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

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

Introducing support for IOMMU

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