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

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

Introducing support for XICU

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