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

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

Introducing support for FBDMA (Frame Buffer using DMA)

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