source: soft/giet_vm/sys/drivers.c @ 204

Last change on this file since 204 was 204, checked in by alain, 12 years ago

mproving support for multi-clusters architectures (CLUSTER_SIZE & CLUSTER_IO_ID parameters)

File size: 42.4 KB
RevLine 
[158]1///////////////////////////////////////////////////////////////////////////////////
2// File     : drivers.c
3// Date     : 01/04/2012
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
[189]7// The drivers.c and drivers.h files are part ot the GIET-VM nano kernel.
[158]8// They contains the drivers for the peripherals available in the SoCLib library:
9// - vci_multi_tty
10// - vci_multi_timer
11// - vci_multi_dma
12// - vci_multi_icu
[203]13// - vci_xicu & vci_multi_icu
[158]14// - vci_gcd
15// - vci_frame_buffer
16// - vci_block_device
17//
18// The following global parameters must be defined in the giet_config.h file:
[204]19// - CLUSTER_IO_ID
20// - CLUSTER_SIZE
[189]21// - NB_CLUSTERS   
22// - NB_PROCS_MAX 
23// - NB_TIMERS_MAX   
24// - NB_DMAS_MAX     
25// - NB_TTYS   
[158]26//
[204]27// The following virtual base addresses must be defined in the giet.ld file:
[158]28// - seg_icu_base
[203]29// - seg_tim_base
[158]30// - seg_tty_base
31// - seg_gcd_base
32// - seg_dma_base
[203]33// - seg_fbf_base
[158]34// - seg_ioc_base
[204]35// As some peripherals can be replicated in the clusters (ICU, TIMER, DMA)
36// These addresses must be completed by an offset depending on the cluster index
37//    full_base_address = seg_***_base + cluster_id * CLUSTER_SIZE
[158]38///////////////////////////////////////////////////////////////////////////////////
39
[166]40#include <vm_handler.h>
[158]41#include <sys_handler.h>
42#include <giet_config.h>
43#include <drivers.h>
44#include <common.h>
45#include <hwr_mapping.h>
46#include <mips32_registers.h>
47#include <ctx_handler.h>
48
49#if !defined(NB_CLUSTERS)
[189]50# error: You must define NB_CLUSTERS in 'giet_config.h' file
[158]51#endif
[189]52
53#if !defined(NB_PROCS_MAX)
54# error: You must define NB_PROCS_MAX in 'giet_config.h' file
55#endif
56
57#if (NB_PROCS_MAX > 8)
58# error: NB_PROCS_MAX cannot be larger than 8!
59#endif
60
[204]61#if !defined(CLUSTER_SIZE)
62# error: You must define CLUSTER_SIZE in 'giet_config.h' file
[158]63#endif
[189]64
[158]65#if !defined(NB_TTYS)
[189]66# error: You must define NB_TTYS in 'giet_config.h' file
[158]67#endif
68
[165]69#if (NB_TTYS < 1)
70# error: NB_TTYS cannot be smaller than 1!
71#endif
72
[189]73#if !defined(NB_DMAS_MAX)
74# error: You must define NB_DMAS_MAX in 'giet_config.h' file
[165]75#endif
76
[189]77#if (NB_DMAS_MAX < 1)
78# error: NB_DMAS_MAX cannot be 0!
[165]79#endif
80
[189]81#if !defined(NB_TIMERS_MAX)
82# error: You must define NB_TIMERS_MAX in 'giet_config.h' file
[165]83#endif
84
[189]85#if ( (NB_TIMERS_MAX + NB_PROCS_MAX) > 32 )
86# error: NB_TIMERS_MAX + NB_PROCS_MAX cannot be larger than 32
87#endif
[165]88
[189]89#if !defined(NB_IOCS)
90# error: You must define NB_IOCS in 'giet_config.h' file
91#endif
[158]92
[189]93#if ( NB_IOCS > 1 )
94# error: NB_IOCS cannot be larger than 1
95#endif
[158]96
97
[189]98#define in_unckdata __attribute__((section (".unckdata")))
[169]99
[158]100//////////////////////////////////////////////////////////////////////////////
[203]101//      Timers driver
[158]102//////////////////////////////////////////////////////////////////////////////
[203]103// The timers can be implemented in a vci_timer component or in a vci_xicu
104// component (depending on the GIET_USE_XICU parameter).
105// There is one timer (or xicu) component per cluster.
[189]106// There is two types of timers:
107// - "system" timers : one per processor, used for context switch.
108//   local_id in [0, NB_PROCS_MAX-1],
109// - "user" timers : requested by the task in the mapping_info data structure.
[203]110//   local_id in [NB_PROC_MAX, NB_PROCS_MAX + NB_TIMERS_MAX - 1]
111//   For each user timer, the timer_id is stored in the context of the task.
112// The global index is cluster_id * (NB_PROCS_MAX+NB_TIMERS_MAX) + local_id
[158]113//////////////////////////////////////////////////////////////////////////////
114
[189]115// User Timer signaling variables
116
117#if (NB_TIMERS_MAX > 0)
118in_unckdata volatile unsigned char _user_timer_event[NB_CLUSTERS*NB_TIMERS_MAX] 
119         = { [0 ... ((NB_CLUSTERS*NB_TIMERS_MAX)-1)] = 0 };
120#endif
121
[158]122//////////////////////////////////////////////////////////////////////////////
[203]123//     _timer_start()
124// This function activates a timer in the vci_timer (or vci_xicu) component
125// by writing in the proper register the period value.
126// It can be used by both the kernel to initialise a "system" timer,
[189]127// or by a task (through a system call) to configure an "user" timer.
[158]128// Returns 0 if success, > 0 if error.
129//////////////////////////////////////////////////////////////////////////////
[203]130unsigned int _timer_start( unsigned int cluster_id,
131                           unsigned int local_id,
132                           unsigned int period )
[158]133{
[165]134    // parameters checking
[189]135    if ( cluster_id >= NB_CLUSTERS)                                     return 1;
136    if ( local_id >= NB_TIMERS_MAX + NB_PROCS_MAX ) return 1;
[158]137
[189]138#if GIET_USE_XICU
[204]139    unsigned int* timer_address = (unsigned int*)((char*)&seg_icu_base +
140                                  (cluster_id * CLUSTER_SIZE) );
[158]141
[203]142    timer_address[XICU_REG(XICU_PTI_PER, local_id)] = period;
[189]143#else
[204]144    unsigned int* timer_address = (unsigned int*)((char*)&seg_tim_base + 
145                                  (cluster_id * CLUSTER_SIZE) );
[189]146
[203]147    timer_address[local_id * TIMER_SPAN + TIMER_PERIOD] = period;
148    timer_address[local_id * TIMER_SPAN + TIMER_MODE]   = 0x3;
[189]149#endif
150
[158]151    return 0;
152}
[189]153//////////////////////////////////////////////////////////////////////////////
[203]154//     _timer_stop()
155// This function desactivates a timer in the vci_timer (or vci_xicu) component
156// by writing in the proper register.
[189]157// Returns 0 if success, > 0 if error.
158//////////////////////////////////////////////////////////////////////////////
[203]159unsigned int _timer_stop( unsigned int  cluster_id,
160                          unsigned int  local_id )
[189]161{
[203]162    // parameters checking
163    if ( cluster_id >= NB_CLUSTERS)                                     return 1;
164    if ( local_id >= NB_TIMERS_MAX + NB_PROCS_MAX ) return 1;
[158]165
[203]166#if GIET_USE_XICU
[204]167    unsigned int* timer_address = (unsigned int*)((char*)&seg_icu_base +
168                                  (cluster_id * CLUSTER_SIZE) );
[203]169
170    timer_address[XICU_REG(XICU_PTI_PER, local_id)] = 0;
171#else
[204]172    unsigned int* timer_address = (unsigned int*)((char*)&seg_tim_base + 
173                                  (cluster_id * CLUSTER_SIZE) );
[203]174
175    timer_address[local_id * TIMER_SPAN + TIMER_MODE] = 0;
176#endif
177
178    return 0;
[189]179}
[158]180//////////////////////////////////////////////////////////////////////////////
[203]181//     _timer_reset_irq()
182// This function acknowlegge a timer interrupt in the vci_timer (or vci_xicu)
[204]183// component by reading/writing in the proper register.
[203]184// It can be used by both the isr_switch() for a "system" timer,
185// or by the _isr_timer() for an "user" timer.
[158]186// Returns 0 if success, > 0 if error.
187//////////////////////////////////////////////////////////////////////////////
[203]188unsigned int _timer_reset_irq( unsigned int     cluster_id,
189                               unsigned int     local_id )
[158]190{
[203]191    // parameters checking
192    if ( cluster_id >= NB_CLUSTERS)                                     return 1;
193    if ( local_id >= NB_TIMERS_MAX + NB_PROCS_MAX ) return 1;
[158]194
[203]195#if GIET_USE_XICU
[204]196    unsigned int* timer_address = (unsigned int*)((char*)&seg_icu_base +
197                                  (cluster_id * (unsigned)CLUSTER_SIZE) );
[203]198
199    unsigned int bloup = timer_address[XICU_REG(XICU_PTI_ACK, local_id)];
[204]200    bloup++;    // to avoid a warning
[203]201#else
[204]202    unsigned int* timer_address = (unsigned int*)((char*)&seg_tim_base + 
203                                  (cluster_id * CLUSTER_SIZE) );
[203]204
205    timer_address[local_id * TIMER_SPAN + TIMER_RESETIRQ] = 0;
206#endif
207
208    return 0;
[158]209}
210
211/////////////////////////////////////////////////////////////////////////////////
212//      VciMultiTty driver
213/////////////////////////////////////////////////////////////////////////////////
[189]214// There is only one multi_tty controler in the architecture.
[158]215// The total number of TTYs is defined by the configuration parameter NB_TTYS.
[189]216// The "system" terminal is TTY[0].
217// The "user" TTYs are allocated to applications by the GIET in the boot phase,
218// as defined in the mapping_info data structure. The corresponding tty_id must
219// be stored in the context of the task by the boot code.
220// The TTY address is : seg_tty_base + tty_id*TTY_SPAN
221/////////////////////////////////////////////////////////////////////////////////
[158]222
[189]223// TTY variables
224in_unckdata volatile unsigned char _tty_get_buf[NB_TTYS];
225in_unckdata volatile unsigned char _tty_get_full[NB_TTYS] = { [0 ... NB_TTYS-1] = 0 };
226in_unckdata unsigned int           _tty_put_lock = 0;  // protect kernel TTY[0]
227
228////////////////////////////////////////////////////////////////////////////////
229//      _tty_error()
230////////////////////////////////////////////////////////////////////////////////
[199]231void _tty_error( unsigned int task_id )
[189]232{
233    unsigned int proc_id = _procid();
234
235    _get_lock(&_tty_put_lock);
236    _puts("\n[GIET ERROR] TTY index too large for task ");
237    _putw( task_id );
238    _puts(" on processor ");
239    _putw( proc_id );
240    _puts("\n");
241    _release_lock(&_tty_put_lock);
242}
243/////////////////////////////////////////////////////////////////////////////////
244//      _tty_write()
[158]245// Write one or several characters directly from a fixed-length user buffer to
246// the TTY_WRITE register of the TTY controler.
247// It doesn't use the TTY_PUT_IRQ interrupt and the associated kernel buffer.
248// This is a non blocking call: it tests the TTY_STATUS register, and stops
249// the transfer as soon as the TTY_STATUS[WRITE] bit is set.
250// The function returns  the number of characters that have been written.
[189]251/////////////////////////////////////////////////////////////////////////////////
[165]252unsigned int _tty_write( const char             *buffer, 
253                         unsigned int   length)
[158]254{
[189]255    unsigned int        nwritten;
[158]256
[199]257    unsigned int task_id  = _get_current_task_id();
258    unsigned int tty_id   = _get_context_slot(task_id, CTX_TTY_ID);
259
[189]260    if ( tty_id >= NB_TTYS )
261    {
[199]262        _tty_error( task_id );
[189]263        return 0;
264    }
[158]265
[204]266    unsigned int*       tty_address = (unsigned int*)( (char*)&seg_tty_base + 
267                                  (CLUSTER_IO_ID * (unsigned)CLUSTER_SIZE) ); 
[158]268
269    for (nwritten = 0; nwritten < length; nwritten++)
270    {
[165]271        // check tty's status
[204]272        if ((tty_address[tty_id*TTY_SPAN + TTY_STATUS] & 0x2) == 0x2)
[158]273            break;
274        else
[165]275            // write character
[204]276            tty_address[tty_id*TTY_SPAN + TTY_WRITE] = (unsigned int)buffer[nwritten];
[158]277    }
278    return nwritten;
279}
280//////////////////////////////////////////////////////////////////////////////
[204]281//      _tty_read()
[158]282// This non-blocking function uses the TTY_GET_IRQ[tty_id] interrupt and
[165]283// the associated kernel buffer, that has been written by the ISR.
[204]284// It get the TTY terminal index from the context of the current task.
[158]285// It fetches one single character from the _tty_get_buf[tty_id] kernel
286// buffer, writes this character to the user buffer, and resets the
287// _tty_get_full[tty_id] buffer.
[204]288// The length argument is not used.
[158]289// Returns 0 if the kernel buffer is empty, 1 if the buffer is full.
290//////////////////////////////////////////////////////////////////////////////
[204]291unsigned int _tty_read( char                    *buffer, 
292                        unsigned int    length)
[158]293{
[199]294    unsigned int task_id  = _get_current_task_id();
295    unsigned int tty_id   = _get_context_slot(task_id, CTX_TTY_ID);
[158]296
[189]297    if ( tty_id >= NB_TTYS )
298    {
[199]299        _tty_error( task_id );
[189]300        return 0;
301    }
[158]302
303    if (_tty_get_full[tty_id] == 0) 
304    {
[189]305        return 0;
[158]306    }
307    else
308    {
309        *buffer = _tty_get_buf[tty_id];
310        _tty_get_full[tty_id] = 0;
[189]311        return 1;
[158]312    }
[189]313} 
[158]314////////////////////////////////////////////////////////////////////////////////
[204]315//     _tty_get_char()
316// This function is used by the _isr_tty to read a character in the TTY
317// terminal defined by the tty_id argument. The character is stored
318// in requested buffer, and the IRQ is acknowledged.
319// Returns 0 if success, 1 if tty_id too large.
[158]320////////////////////////////////////////////////////////////////////////////////
[204]321unsigned int _tty_get_char( unsigned int        tty_id,
322                            char*           buffer )
[158]323{
[204]324    // checking argument
325    if ( tty_id >= NB_TTYS ) return 1;
[199]326
[204]327    // compute terminal base address
328    unsigned int *tty_address = (unsigned int*)( (char*)&seg_tty_base + 
329                                (CLUSTER_IO_ID * (unsigned)CLUSTER_SIZE) );
[158]330
[204]331    *buffer = (unsigned char)tty_address[tty_id*TTY_SPAN + TTY_READ];
332    return 0;
[158]333}
334
335////////////////////////////////////////////////////////////////////////////////
[189]336//      VciMultiIcu and VciXicu drivers
[158]337////////////////////////////////////////////////////////////////////////////////
[203]338// There is one vci_multi_icu (or vci_xicu) component per cluster,
339// and the number of independant ICUs is equal to NB_PROCS_MAX,
340// because there is one private interrupr controler per processor.
[158]341////////////////////////////////////////////////////////////////////////////////
342
343////////////////////////////////////////////////////////////////////////////////
[203]344//     _icu_set_mask()
345// This function can be used with both the vci_xicu & vci_multi_icu components.
346// It set the mask register for the ICU channel identified by the cluster index
347// and the processor index: all '1' bits are set / all '0' bits are not modified.
[158]348// Returns 0 if success, > 0 if error.
349////////////////////////////////////////////////////////////////////////////////
[203]350unsigned int _icu_set_mask( unsigned int cluster_id,
351                            unsigned int proc_id,
352                            unsigned int value,
353                            unsigned int is_timer )
[158]354{
[203]355    // parameters checking
356    if ( cluster_id >= NB_CLUSTERS)             return 1;
357    if ( proc_id    >= NB_PROCS_MAX )   return 1;
358
[204]359    unsigned int* icu_address = (unsigned int*)( (char*)&seg_icu_base + 
360                                (cluster_id * (unsigned)CLUSTER_SIZE) );
[189]361#if GIET_USE_XICU
[203]362    if ( is_timer ) icu_address[XICU_REG(XICU_MSK_PTI_ENABLE, proc_id)] = value;
363    else            icu_address[XICU_REG(XICU_MSK_HWI_ENABLE, proc_id)] = value;
[189]364#else
[203]365    icu_address[proc_id * ICU_SPAN + ICU_MASK_SET] = value; 
366#endif
[189]367
[158]368    return 0;
369}
370////////////////////////////////////////////////////////////////////////////////
[203]371//     _icu_get_index()
372// This function can be used with both the vci_xicu & vci_multi_icu components.
373// It returns the index of the highest priority (smaller index) active HWI.
374// The ICU channel is identified by the cluster index and the processor index.
[158]375// Returns 0 if success, > 0 if error.
376////////////////////////////////////////////////////////////////////////////////
[203]377unsigned int _icu_get_index(  unsigned int cluster_id,
378                              unsigned int proc_id,
379                              unsigned int* buffer )
[158]380{
[203]381    // parameters checking
382    if ( cluster_id >= NB_CLUSTERS)             return 1;
383    if ( proc_id    >= NB_PROCS_MAX )   return 1;
384
[204]385    unsigned int* icu_address = (unsigned int*)( (char*)&seg_icu_base + 
386                                (cluster_id * (unsigned)CLUSTER_SIZE) );
[189]387#if GIET_USE_XICU
[203]388    unsigned int prio   = icu_address[XICU_REG(XICU_PRIO, proc_id)];
389    unsigned int pti_ok = (prio & 0x00000001);
390    unsigned int hwi_ok = (prio & 0x00000002);
391    unsigned int swi_ok = (prio & 0x00000004);
392    unsigned int pti_id = (prio & 0x00001F00) >> 8;
393    unsigned int hwi_id = (prio & 0x001F0000) >> 16;
394    unsigned int swi_id = (prio & 0x1F000000) >> 24;
395    if      (pti_ok)    *buffer = pti_id;
396    else if (hwi_ok)    *buffer = hwi_id;
397    else if (swi_ok)    *buffer = swi_id;
398    else                *buffer = 32;
[189]399#else
[203]400    *buffer = icu_address[proc_id * ICU_SPAN + ICU_IT_VECTOR]; 
401#endif
[189]402
[158]403    return 0;
404}
405
406////////////////////////////////////////////////////////////////////////////////
407//      VciGcd driver
408////////////////////////////////////////////////////////////////////////////////
409// The Greater Dommon Divider is a -very- simple hardware coprocessor
[165]410// performing the computation of the GCD of two 32 bits integers.
[158]411// It has no DMA capability.
412////////////////////////////////////////////////////////////////////////////////
413
414////////////////////////////////////////////////////////////////////////////////
[189]415//     _gcd_write()
[158]416// Write a 32-bit word in a memory mapped register of the GCD coprocessor.
417// Returns 0 if success, > 0 if error.
418////////////////////////////////////////////////////////////////////////////////
[165]419unsigned int _gcd_write( unsigned int register_index, 
420                         unsigned int value)
[158]421{
[165]422    // parameters checking
[158]423    if (register_index >= GCD_END)
424        return 1;
425
[204]426    unsigned int* gcd_address = (unsigned int*)( (char*)&seg_gcd_base +
427                                (CLUSTER_IO_ID * (unsigned)CLUSTER_SIZE) );
[165]428
429    gcd_address[register_index] = value; // write word
[158]430    return 0;
431}
432////////////////////////////////////////////////////////////////////////////////
[189]433//     _gcd_read()
[158]434// Read a 32-bit word in a memory mapped register of the GCD coprocessor.
435// Returns 0 if success, > 0 if error.
436////////////////////////////////////////////////////////////////////////////////
[165]437unsigned int _gcd_read( unsigned int register_index, 
438                        unsigned int *buffer)
[158]439{
[165]440    // parameters checking
[158]441    if (register_index >= GCD_END)
442        return 1;
443
[204]444    unsigned int* gcd_address = (unsigned int*)( (char*)&seg_gcd_base +
445                                (CLUSTER_IO_ID * (unsigned)CLUSTER_SIZE) );
[165]446
447    *buffer = gcd_address[register_index]; // read word
[158]448    return 0;
449}
450
451////////////////////////////////////////////////////////////////////////////////
452// VciBlockDevice driver
453////////////////////////////////////////////////////////////////////////////////
[165]454// The VciBlockDevice is a single channel external storage contrÃŽler.
[166]455//
456// The IOMMU can be activated or not:
457//
458// 1) When the IOMMU is used, a fixed size 2Mbytes vseg is allocated to
459// the IOC peripheral, in the I/O virtual space, and the user buffer is
460// dynamically remapped in the IOMMU page table. The corresponding entry
461// in the IOMMU PT1 is defined by the kernel _ioc_iommu_ix1 variable.
462// The number of pages to be unmapped is stored in the _ioc_npages variable.
463// The number of PT2 entries is dynamically computed and stored in the
464// kernel _ioc_iommu_npages variable. It cannot be larger than 512.
465// The user buffer is unmapped by the _ioc_completed() function when
466// the transfer is completed.
467//
468// 2/ If the IOMMU is not used, we check that  the user buffer is mapped to a
469// contiguous physical buffer (this is generally true because the user space
470// page tables are statically constructed to use contiguous physical memory).
471//
472// Finally, the memory buffer must fulfill the following conditions:
473// - The user buffer must be word aligned,
474// - The user buffer must be mapped in user address space,
475// - The user buffer must be writable in case of (to_mem) access,
476// - The total number of physical pages occupied by the user buffer cannot
477//   be larger than 512 pages if the IOMMU is activated,
478// - All physical pages occupied by the user buffer must be contiguous
479//   if the IOMMU is not activated.
480// An error code is returned if these conditions are not verified.
481//
[158]482// As the IOC component can be used by several programs running in parallel,
483// the _ioc_lock variable guaranties exclusive access to the device.  The
484// _ioc_read() and _ioc_write() functions use atomic LL/SC to get the lock.
485// and set _ioc_lock to a non zero value.  The _ioc_write() and _ioc_read()
486// functions are blocking, polling the _ioc_lock variable until the device is
487// available.
488// When the tranfer is completed, the ISR routine activated by the IOC IRQ
489// set the _ioc_done variable to a non-zero value. Possible address errors
490// detected by the IOC peripheral are reported by the ISR in the _ioc_status
491// variable.
492// The _ioc_completed() function is polling the _ioc_done variable, waiting for
[166]493// transfer completion. When the completion is signaled, the _ioc_completed()
[158]494// function reset the _ioc_done variable to zero, and releases the _ioc_lock
495// variable.
496//
497// In a multi-processing environment, this polling policy should be replaced by
498// a descheduling policy for the requesting process.
499///////////////////////////////////////////////////////////////////////////////
500
[189]501// IOC global variables
502in_unckdata volatile unsigned int       _ioc_status       = 0;
503in_unckdata volatile unsigned int       _ioc_done         = 0;
504in_unckdata unsigned int                        _ioc_lock         = 0;
505in_unckdata unsigned int                        _ioc_iommu_ix1    = 0;
506in_unckdata unsigned int                        _ioc_iommu_npages; 
[158]507
508///////////////////////////////////////////////////////////////////////////////
[189]509//      _ioc_access()
[166]510// This function transfer data between a memory buffer and the block device.
511// The buffer lentgth is (count*block_size) bytes.
512// Arguments are:
513// - to_mem     : from external storage to memory when non 0
514// - lba        : first block index on the external storage.
515// - user_vaddr : virtual base address of the memory buffer.
516// - count      : number of blocks to be transfered.
[158]517// Returns 0 if success, > 0 if error.
518///////////////////////////////////////////////////////////////////////////////
[166]519unsigned int _ioc_access( unsigned int  to_mem,
520                          unsigned int  lba,
521                          unsigned int  user_vaddr,
522                          unsigned int  count )
[158]523{
[167]524    unsigned int                user_vpn_min;   // first virtuel page index in user space
525    unsigned int                user_vpn_max;   // last virtual page index in user space
526    unsigned int                vpn;                    // current virtual page index in user space
527    unsigned int                ppn;                    // physical page number
528    unsigned int                flags;                  // page protection flags
529    unsigned int                ix2;                    // page index in IOMMU PT1 page table
530    unsigned int                addr;                   // buffer address for IOC peripheral
531    unsigned int                ppn_first;              // first physical page number for user buffer
[166]532       
533    // check buffer alignment
534    if ( (unsigned int)user_vaddr & 0x3 ) return 1;
[158]535
[204]536    unsigned int*       ioc_address = (unsigned int*)( (char*)&seg_ioc_base +
537                                  (CLUSTER_IO_ID * (unsigned)CLUSTER_SIZE) );
538
[166]539    unsigned int        block_size   = ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
540    unsigned int        length       = count*block_size;
[158]541
[167]542    // get user space page table virtual address
[199]543    unsigned int task_id       = _get_current_task_id();
544    unsigned int user_pt_vbase = _get_context_slot( task_id, CTX_PTAB_ID );
[166]545   
546    user_vpn_min = user_vaddr >> 12;
547    user_vpn_max = (user_vaddr + length - 1) >> 12;
548    ix2          = 0;
[158]549
[166]550    // loop on all virtual pages covering the user buffer
551    for ( vpn = user_vpn_min ; vpn <= user_vpn_max ; vpn++ )
552    {
553        // get ppn and flags for each vpn
[189]554        unsigned int ko = _v2p_translate( (page_table_t*)user_pt_vbase,
555                                           vpn,
556                                           &ppn,
557                                           &flags );
[158]558
[166]559        // check access rights
560        if ( ko )                                                                 return 2;             // unmapped
561        if ( (flags & PTE_U) == 0 )                               return 3;             // not in user space
562        if ( ( (flags & PTE_W) == 0 ) && to_mem ) return 4;             // not writable
[158]563
[166]564        // save first ppn value
565        if ( ix2 == 0 ) ppn_first = ppn;
[158]566
[166]567        if ( GIET_IOMMU_ACTIVE )    // the user buffer must be remapped in the I/0 space
568        {
569            // check buffer length < 2 Mbytes
570            if ( ix2 > 511 ) return 2;
[158]571
[166]572            // map the physical page in IOMMU page table
573            _iommu_add_pte2( _ioc_iommu_ix1,    // PT1 index
574                             ix2,                               // PT2 index
575                                                 ppn,                           // Physical page number
576                             flags );                   // Protection flags
577        }
578        else                    // no IOMMU : check that physical pages are contiguous
579        {
580            if ( (ppn - ppn_first) != ix2 )           return 5;         // split physical buffer 
581        }
582       
583        // increment page index
584        ix2++;
585    } // end for vpn
[158]586
[166]587    // register the number of pages to be unmapped
588    _ioc_iommu_npages = (user_vpn_max - user_vpn_min) + 1;
[158]589
[166]590    // invalidate data cache in case of memory write
591    if ( to_mem ) _dcache_buf_invalidate( (void*)user_vaddr, length );
[158]592
[166]593    // compute buffer base address for IOC depending on IOMMU activation
594    if ( GIET_IOMMU_ACTIVE ) addr = (_ioc_iommu_ix1) << 21 | (user_vaddr & 0xFFF);
[167]595    else                     addr = (ppn_first << 12) | (user_vaddr & 0xFFF);
[166]596
597    // get the lock on ioc device
[189]598    _get_lock( &_ioc_lock );
[158]599
[166]600    // peripheral configuration 
601    ioc_address[BLOCK_DEVICE_BUFFER]     = addr;
602    ioc_address[BLOCK_DEVICE_COUNT]      = count;
603    ioc_address[BLOCK_DEVICE_LBA]        = lba;
604    if ( to_mem == 0 ) ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_WRITE;
605    else               ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_READ;
[158]606
607    return 0;
608}
609/////////////////////////////////////////////////////////////////////////////////
610// _ioc_completed()
611//
612// This function checks completion of an I/O transfer and reports errors.
[166]613// As it is a blocking call, the processor is stalled.
614// If the virtual memory is activated, the pages mapped in the I/O virtual
615// space are unmapped, and the IOB TLB is cleared.
[158]616// Returns 0 if success, > 0 if error.
617/////////////////////////////////////////////////////////////////////////////////
618unsigned int _ioc_completed()
619{
[166]620    unsigned int        ret;
621    unsigned int        ix2;
[158]622
[166]623    // busy waiting
[158]624    while (_ioc_done == 0)
625        asm volatile("nop");
626
[166]627    // unmap the buffer from IOMMU page table if IOMMU is activated
628    if ( GIET_IOMMU_ACTIVE )
629    {
[204]630        unsigned int* iob_address = (unsigned int*)( (char*)&seg_iob_base +
631                                    (CLUSTER_IO_ID * (unsigned)CLUSTER_SIZE) );
[166]632
633        for ( ix2 = 0 ; ix2 < _ioc_iommu_npages ; ix2++ )
634        {
635            // unmap the page in IOMMU page table
636            _iommu_inval_pte2( _ioc_iommu_ix1,  // PT1 index
637                              ix2 );                    // PT2 index
638
639            // clear IOMMU TLB
[169]640            iob_address[IOB_INVAL_PTE] = (_ioc_iommu_ix1 << 21) | (ix2 << 12); 
[166]641        }
642    }
643
644    // test IOC status
[158]645    if ((_ioc_status != BLOCK_DEVICE_READ_SUCCESS)
[166]646            && (_ioc_status != BLOCK_DEVICE_WRITE_SUCCESS)) ret = 1;    // error
647    else                                                    ret = 0;    // success
[158]648
[166]649    // reset synchronization variables
[158]650    _ioc_lock =0;
651    _ioc_done =0;
652
653    return ret;
654}
[166]655///////////////////////////////////////////////////////////////////////////////
[189]656//     _ioc_read()
[166]657// Transfer data from the block device to a memory buffer in user space.
658// - lba    : first block index on the block device
659// - buffer : base address of the memory buffer (must be word aligned)
660// - count  : number of blocks to be transfered.
661// Returns 0 if success, > 0 if error.
662///////////////////////////////////////////////////////////////////////////////
663unsigned int _ioc_read( unsigned int    lba, 
664                        void*               buffer, 
665                        unsigned int    count )
666{
[189]667    return _ioc_access( 1,              // read access
[166]668                        lba,
669                        (unsigned int)buffer,
670                        count );
671}
672///////////////////////////////////////////////////////////////////////////////
[189]673//     _ioc_write()
[166]674// Transfer data from a memory buffer in user space to the block device.
675// - lba    : first block index on the block device
676// - buffer : base address of the memory buffer (must be word aligned)
677// - count  : number of blocks to be transfered.
678// Returns 0 if success, > 0 if error.
679///////////////////////////////////////////////////////////////////////////////
680unsigned int _ioc_write( unsigned int   lba, 
681                         const void*    buffer, 
682                         unsigned int   count )
683{
[189]684    return _ioc_access( 0,              // write access
[166]685                        lba,
686                        (unsigned int)buffer,
687                        count );
688}
[204]689///////////////////////////////////////////////////////////////////////////////
690//     _ioc_get_status()
691// This function returns the transfert status, and acknowledge the IRQ.
692// Returns 0 if success, > 0 if error.
693///////////////////////////////////////////////////////////////////////////////
694unsigned int _ioc_get_status(unsigned int* status)
695{
696    // get IOC base address
697    unsigned int* ioc_address = (unsigned int*)( (char*)&seg_ioc_base +
698                                (CLUSTER_IO_ID * (unsigned)CLUSTER_SIZE) );
[166]699
[204]700    *status = ioc_address[BLOCK_DEVICE_STATUS]; // read status & reset IRQ
701    return 0;
702}
703
[158]704//////////////////////////////////////////////////////////////////////////////////
[189]705// VciMultiDma driver
706//////////////////////////////////////////////////////////////////////////////////
707// The DMA controllers are physically distributed in the clusters.
708// There is  (NB_CLUSTERS * NB_DMAS_MAX) channels, indexed by a global index:
709//        dma_id = cluster_id * NB_DMA_MAX + loc_id
710//
711// As a DMA channel can be used by several tasks, each DMA channel is protected
712// by a specific lock: _dma_lock[dma_id]
713// The signalisation between the OS and the DMA uses the _dma_done[dma_id]
714// synchronisation variables  (set by the ISR, and reset by the OS).
715// The transfer status is copied by the ISR in the _dma_status[dma_id] variables.
716//
717// These DMA channels can be used by the FB driver, or by the NIC driver.
718//////////////////////////////////////////////////////////////////////////////////
719
720#if  (NB_DMAS_MAX > 0)
721in_unckdata unsigned int                        _dma_lock[NB_DMAS_MAX * NB_CLUSTERS]
722                                       = { [0 ... (NB_DMAS_MAX * NB_CLUSTERS)-1] = 0 };
723
724in_unckdata volatile unsigned int       _dma_done[NB_DMAS_MAX * NB_CLUSTERS]
725                                       = { [0 ... (NB_DMAS_MAX * NB_CLUSTERS)-1] = 0 };
726
727in_unckdata volatile unsigned int       _dma_status[NB_DMAS_MAX * NB_CLUSTERS];
728
729in_unckdata unsigned int                        _dma_iommu_ix1 = 1;
730
731in_unckdata unsigned int            _dma_iommu_npages[NB_DMAS_MAX * NB_CLUSTERS];
732#endif
733
734//////////////////////////////////////////////////////////////////////////////////
[204]735// _dma_reset_irq()
736//////////////////////////////////////////////////////////////////////////////////
737unsigned int _dma_reset_irq( unsigned int       cluster_id,
738                             unsigned int       local_id )
739{
740    // parameters checking
741    if ( cluster_id >= NB_CLUSTERS ) return 1;
742    if ( local_id >= NB_DMAS_MAX )   return 1;
743
744    // compute DMA base address
745    unsigned int*       dma_address = (unsigned int*)( (char*)&seg_dma_base + 
746                                  (cluster_id * (unsigned)CLUSTER_SIZE) );
747
748    dma_address[local_id*DMA_SPAN + DMA_RESET] = 0;                     
749    return 0;
750}
751//////////////////////////////////////////////////////////////////////////////////
752// _dma_get_status()
753//////////////////////////////////////////////////////////////////////////////////
754unsigned int _dma_get_status( unsigned int      cluster_id,
755                              unsigned int      local_id,
756                              unsigned int* status )
757{
758    // parameters checking
759    if ( cluster_id >= NB_CLUSTERS ) return 1;
760    if ( local_id >= NB_DMAS_MAX )   return 1;
761
762    // compute DMA base address
763    unsigned int*       dma_address = (unsigned int*)( (char*)&seg_dma_base + 
764                                  (cluster_id * (unsigned)CLUSTER_SIZE) );
765   
766    *status = dma_address[local_id*DMA_SPAN + DMA_LEN];
767    return 0;
768}
769
770//////////////////////////////////////////////////////////////////////////////////
[158]771//      VciFrameBuffer driver
772//////////////////////////////////////////////////////////////////////////////////
[189]773// The vci_frame_buffer device can be accessed directly by software with memcpy(),
774// or it can be accessed through a multi-channels DMA component:
775// 
[158]776// The '_fb_sync_write' and '_fb_sync_read' functions use a memcpy strategy to
777// implement the transfer between a data buffer (user space) and the frame
778// buffer (kernel space). They are blocking until completion of the transfer.
[169]779//
[158]780// The '_fb_write()', '_fb_read()' and '_fb_completed()' functions use the DMA
[189]781// controlers (distributed in the clusters) to transfer data
782// between the user buffer and the frame buffer. A  DMA channel is
783// allocated to each task requesting it in the mapping_info data structure.
[158]784//////////////////////////////////////////////////////////////////////////////////
785
786//////////////////////////////////////////////////////////////////////////////////
787// _fb_sync_write()
788// Transfer data from an memory buffer to the frame_buffer device using
789// a memcpy. The source memory buffer must be in user address space.
790// - offset : offset (in bytes) in the frame buffer.
791// - buffer : base address of the memory buffer.
792// - length : number of bytes to be transfered.
793// Returns 0 if success, > 0 if error.
794//////////////////////////////////////////////////////////////////////////////////
795unsigned int _fb_sync_write( unsigned int       offset, 
796                             const void*        buffer, 
797                             unsigned int       length )
798{
799
[169]800    // buffer must be mapped in user space
801    if ( ((unsigned int)buffer + length ) >= 0x80000000 )
[189]802    {
[158]803        return 1;
[189]804    }
805    else
806    {
[203]807        unsigned char *fb_address = (unsigned char*)&seg_fbf_base + offset;
[189]808        memcpy((void*)fb_address, (void*)buffer, length);
809        return 0;
810    }
[158]811}
812
813//////////////////////////////////////////////////////////////////////////////////
814// _fb_sync_read()
815// Transfer data from the frame_buffer device to a memory buffer using
816// a memcpy. The destination memory buffer must be in user address space.
817// - offset : offset (in bytes) in the frame buffer.
818// - buffer : base address of the memory buffer.
819// - length : number of bytes to be transfered.
820// Returns 0 if success, > 0 if error.
821//////////////////////////////////////////////////////////////////////////////////
822unsigned int _fb_sync_read( unsigned int        offset, 
823                            const void*         buffer, 
824                            unsigned int        length )
825{
[169]826    // buffer must be mapped in user space
827    if ( ((unsigned int)buffer + length ) >= 0x80000000 )
[189]828    {
[158]829        return 1;
[189]830    }
831    else
832    {
[203]833        unsigned char *fb_address = (unsigned char*)&seg_fbf_base + offset;
[189]834        memcpy((void*)buffer, (void*)fb_address, length);
835        return 0;
836    }
[158]837}
838
839//////////////////////////////////////////////////////////////////////////////////
[189]840// _fb_dma_access()
841// Transfer data between a user buffer and the frame_buffer using DMA.
842// - to_user    : from frame buffer to user buffer when true.
[169]843// - offset     : offset (in bytes) in the frame buffer.
844// - user_vaddr : virtual base address of the memory buffer.
845// - length     : number of bytes to be transfered.
846// The memory buffer must be mapped in user address space and word-aligned.
847// The user buffer length must be multiple of 4 bytes.
[189]848// Me must compute the physical base addresses for both the frame buffer
849// and the user buffer before programming the DMA transfer.
850// The GIET being fully static, we don't need to split the transfer in 4Kbytes
851// pages, because the user buffer is contiguous in physical space.
[158]852// Returns 0 if success, > 0 if error.
853//////////////////////////////////////////////////////////////////////////////////
[189]854unsigned int _fb_dma_access( unsigned int       to_user,
855                             unsigned int   offset,
856                             unsigned int   user_vaddr,
857                             unsigned int   length )
[158]858{
[189]859    unsigned int        ko;                             // unsuccessfull V2P translation
860    unsigned int        flags;                  // protection flags
861    unsigned int        ppn;                    // physical page number
862    unsigned int    user_pbase;         // user buffer pbase address
863    unsigned int    fb_pbase;           // frame buffer pbase address
[158]864
[189]865    // get DMA channel and compute DMA vbase address
[199]866    unsigned int        task_id    = _get_current_task_id();
867    unsigned int        dma_id     = _get_context_slot( task_id, CTX_FBDMA_ID );
[189]868    unsigned int    cluster_id = dma_id / NB_DMAS_MAX;
869    unsigned int    loc_id     = dma_id % NB_DMAS_MAX;
[169]870
[204]871    unsigned int*       dma_base   = (unsigned int*)( (char*)&seg_dma_base +
872                                 (cluster_id * (unsigned)CLUSTER_SIZE) );
873 
[189]874    // check user buffer address and length alignment
875    if ( (user_vaddr & 0x3) || (length & 0x3) )
876    {
[203]877        _get_lock(&_tty_put_lock);
[189]878        _puts("[GIET ERROR] in _fbdma_access() : user buffer not word aligned\n");
[203]879        _release_lock(&_tty_put_lock);
[189]880        return 1;
881    }
[169]882
883    // get user space page table virtual address
[199]884    unsigned int        user_ptab = _get_context_slot( task_id, CTX_PTAB_ID );
[169]885
[189]886    // compute frame buffer pbase address
[203]887    unsigned int fb_vaddr = (unsigned int)&seg_fbf_base + offset;
[189]888
889    ko = _v2p_translate( (page_table_t*)user_ptab,
890                         (fb_vaddr >> 12),
891                         &ppn,
892                         &flags );
893    fb_pbase = (ppn << 12) | (fb_vaddr & 0x00000FFF);
894
895    if ( ko )
896    {
[203]897        _get_lock(&_tty_put_lock);
[189]898        _puts("[GIET ERROR] in _fbdma_access() : frame buffer unmapped\n");
[203]899        _release_lock(&_tty_put_lock);
[189]900        return 2;
901    }
902
903    // Compute user buffer pbase address
904    ko = _v2p_translate( (page_table_t*)user_ptab,
905                         (user_vaddr >> 12),
906                         &ppn,
907                         &flags );
908    user_pbase = (ppn << 12) | (user_vaddr & 0x00000FFF);
909
910    if ( ko )
911    {
[203]912        _get_lock(&_tty_put_lock);
[189]913        _puts("[GIET ERROR] in _fbdma_access() : user buffer unmapped\n");
[203]914        _release_lock(&_tty_put_lock);
[189]915        return 3;
916    } 
917    if ( (flags & PTE_U) == 0 )
918    {
[203]919        _get_lock(&_tty_put_lock);
[189]920        _puts("[GIET ERROR] in _fbdma_access() : user buffer not in user space\n");
[203]921        _release_lock(&_tty_put_lock);
[189]922        return 4; 
923    }
924    if ( ( (flags & PTE_W) == 0 ) && to_user ) 
925    {
[203]926        _get_lock(&_tty_put_lock);
[189]927        _puts("[GIET ERROR] in _fbdma_access() : user buffer not writable\n");
[203]928        _release_lock(&_tty_put_lock);
[189]929        return 5;
930    }
931
932
933
934/*
935    // loop on all virtual pages covering the user buffer
[169]936    unsigned int user_vpn_min = user_vaddr >> 12;
937    unsigned int user_vpn_max = (user_vaddr + length - 1) >> 12;
938    unsigned int ix2          = 0;
939    unsigned int ix1          = _dma_iommu_ix1 + dma_id;
[158]940
[169]941    for ( vpn = user_vpn_min ; vpn <= user_vpn_max ; vpn++ )
942    {
943        // get ppn and flags for each vpn
[189]944        unsigned int ko = _v2p_translate( (page_table_t*)user_pt_vbase,
945                                          vpn,
946                                          &ppn,
947                                          &flags );
[158]948
[169]949        // check access rights
[189]950        if ( ko )                                 return 3;     // unmapped
951        if ( (flags & PTE_U) == 0 )               return 4;     // not in user space
952        if ( ( (flags & PTE_W) == 0 ) && to_user ) return 5;     // not writable
[158]953
[169]954        // save first ppn value
955        if ( ix2 == 0 ) ppn_first = ppn;
956
957        if ( GIET_IOMMU_ACTIVE )    // the user buffer must be remapped in the I/0 space
958        {
959            // check buffer length < 2 Mbytes
960            if ( ix2 > 511 ) return 2;
961
962            // map the physical page in IOMMU page table
963            _iommu_add_pte2( ix1,               // PT1 index
964                             ix2,               // PT2 index
965                             ppn,               // physical page number
966                             flags );   // protection flags
967        }
968        else            // no IOMMU : check that physical pages are contiguous
969        {
[189]970            if ( (ppn - ppn_first) != ix2 )       return 6;     // split physical buffer 
[169]971        }
972
973        // increment page index
974        ix2++;
975    } // end for vpn
976
[189]977    // register the number of pages to be unmapped if iommu activated
[169]978    _dma_iommu_npages[dma_id] = (user_vpn_max - user_vpn_min) + 1;
979
[189]980*/
[204]981
[169]982    // invalidate data cache in case of memory write
[189]983    if ( to_user ) _dcache_buf_invalidate( (void*)user_vaddr, length );
[169]984
[189]985    // get the lock
986    _get_lock( &_dma_lock[dma_id] );
[169]987
988    // DMA configuration
[189]989    if ( to_user )
[169]990    {
[204]991        dma_base[loc_id*DMA_SPAN + DMA_SRC] = (unsigned int)fb_pbase;
992        dma_base[loc_id*DMA_SPAN + DMA_DST] = (unsigned int)user_pbase;
[169]993    }
994    else
995    {
[204]996        dma_base[loc_id*DMA_SPAN + DMA_SRC] = (unsigned int)user_pbase;
997        dma_base[loc_id*DMA_SPAN + DMA_DST] = (unsigned int)fb_pbase;
[169]998    }
[204]999    dma_base[loc_id*DMA_SPAN + DMA_LEN] = (unsigned int)length;
[169]1000   
[158]1001    return 0;
[169]1002} 
1003//////////////////////////////////////////////////////////////////////////////////
1004// _fb_write()
1005// Transfer data from a memory buffer to the frame_buffer device using  DMA.
1006// - offset : offset (in bytes) in the frame buffer.
1007// - buffer : base address of the memory buffer.
1008// - length : number of bytes to be transfered.
1009// Returns 0 if success, > 0 if error.
1010//////////////////////////////////////////////////////////////////////////////////
1011unsigned int _fb_write( unsigned int    offset, 
1012                        const void*             buffer, 
1013                        unsigned int    length )
1014{
[189]1015    return _fb_dma_access( 0,                                           // write to frame buffer
1016                           offset,
1017                           (unsigned int)buffer,
1018                           length );   
[158]1019}
1020
1021//////////////////////////////////////////////////////////////////////////////////
1022// _fb_read()
[169]1023// Transfer data from the frame_buffer device to a memory buffer using  DMA.
[158]1024// - offset : offset (in bytes) in the frame buffer.
1025// - buffer : base address of the memory buffer.
1026// - length : number of bytes to be transfered.
1027// Returns 0 if success, > 0 if error.
1028//////////////////////////////////////////////////////////////////////////////////
1029unsigned int _fb_read( unsigned int     offset, 
[169]1030                       const void*              buffer, 
[158]1031                       unsigned int     length )
1032{
[189]1033    return _fb_dma_access( 1,                                           // read from frame buffer
1034                           offset,
1035                           (unsigned int)buffer,
1036                           length );   
[158]1037}
1038
1039//////////////////////////////////////////////////////////////////////////////////
1040// _fb_completed()
1041// This function checks completion of a DMA transfer to or fom the frame buffer.
[169]1042// As it is a blocking call, the processor is busy waiting.
1043// Returns 0 if success, > 0 if error
1044// (1 == read error / 2 == DMA idle error / 3 == write error)
[158]1045//////////////////////////////////////////////////////////////////////////////////
1046unsigned int _fb_completed()
1047{
[199]1048    unsigned int task_id = _get_current_task_id();
1049    unsigned int dma_id  = _get_context_slot( task_id, CTX_FBDMA_ID );
[158]1050
[169]1051    // busy waiting with a pseudo random delay between bus access
[189]1052    while (_dma_done[dma_id] == 0)
[169]1053    {
1054            unsigned int i;
[189]1055        unsigned int delay = ( _proctime() ^ _procid()<<4 ) & 0xFF;
[169]1056        for (i = 0; i < delay; i++)
1057            asm volatile("nop");
1058    }
1059   
1060    // unmap the buffer from IOMMU page table if IOMMU is activated
1061    if ( GIET_IOMMU_ACTIVE )
1062    {
[204]1063        unsigned int* iob_address = (unsigned int*)( (char*)&seg_iob_base +
1064                                    (CLUSTER_IO_ID * (unsigned)CLUSTER_SIZE) );
1065
[169]1066        unsigned int  ix1         = _dma_iommu_ix1 + dma_id;
1067        unsigned int  ix2;
[158]1068
[169]1069        for ( ix2 = 0 ; ix2 < _dma_iommu_npages[dma_id] ; ix2++ )
1070        {
1071            // unmap the page in IOMMU page table
1072            _iommu_inval_pte2( ix1,             // PT1 index
1073                               ix2 );   // PT2 index
[158]1074
[169]1075            // clear IOMMU TLB
1076            iob_address[IOB_INVAL_PTE] = (ix1 << 21) | (ix2 << 12);
1077        }
1078    }
1079
[189]1080    // reset synchronization variables
1081    _dma_lock[dma_id] = 0;
1082    _dma_done[dma_id] = 0;
1083
[169]1084    return _dma_status[dma_id];
[158]1085}
1086
Note: See TracBrowser for help on using the repository browser.