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

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

Fix several bugs to use the vci_block_device with MMU activated

File size: 32.1 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{
[167]493    unsigned int                user_vpn_min;   // first virtuel page index in user space
494    unsigned int                user_vpn_max;   // last virtual page index in user space
495    unsigned int                vpn;                    // current virtual page index in user space
496    unsigned int                ppn;                    // physical page number
497    unsigned int                flags;                  // page protection flags
498    unsigned int                ix2;                    // page index in IOMMU PT1 page table
499    unsigned int                addr;                   // buffer address for IOC peripheral
500    unsigned int                user_ptp;               // page table pointer in user space
501    unsigned int                ko;                             // bool returned by _v2p_translate()
502    unsigned int                ppn_first;              // first physical page number for user buffer
503    unsigned int                ltid;                   // current task local index
504    static_scheduler_t* psched;                 // pointer on the current task scheduler
[166]505       
506    // check buffer alignment
507    if ( (unsigned int)user_vaddr & 0x3 ) return 1;
[158]508
[166]509    unsigned int*       ioc_address = (unsigned int*)&seg_ioc_base;
510    unsigned int        block_size   = ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
511    unsigned int        length       = count*block_size;
[158]512
[167]513    // get user space page table virtual address
514    psched   = &_scheduler[_procid()];
515    ltid     = psched->current;
516    user_ptp = psched->context[ltid][CTX_PTAB_ID];
[166]517   
518    user_vpn_min = user_vaddr >> 12;
519    user_vpn_max = (user_vaddr + length - 1) >> 12;
520    ix2          = 0;
[158]521
[166]522    // loop on all virtual pages covering the user buffer
523    for ( vpn = user_vpn_min ; vpn <= user_vpn_max ; vpn++ )
524    {
525        // get ppn and flags for each vpn
[167]526        ko = _v2p_translate( (page_table_t*)user_ptp,
527                             vpn,
528                             &ppn,
529                             &flags );
[158]530
[166]531        // check access rights
532        if ( ko )                                                                 return 2;             // unmapped
533        if ( (flags & PTE_U) == 0 )                               return 3;             // not in user space
534        if ( ( (flags & PTE_W) == 0 ) && to_mem ) return 4;             // not writable
[158]535
[166]536        // save first ppn value
537        if ( ix2 == 0 ) ppn_first = ppn;
[158]538
[166]539        if ( GIET_IOMMU_ACTIVE )    // the user buffer must be remapped in the I/0 space
540        {
541            // check buffer length < 2 Mbytes
542            if ( ix2 > 511 ) return 2;
[158]543
[166]544            // map the physical page in IOMMU page table
545            _iommu_add_pte2( _ioc_iommu_ix1,    // PT1 index
546                             ix2,                               // PT2 index
547                                                 ppn,                           // Physical page number
548                             flags );                   // Protection flags
549        }
550        else                    // no IOMMU : check that physical pages are contiguous
551        {
552            if ( (ppn - ppn_first) != ix2 )           return 5;         // split physical buffer 
553        }
554       
555        // increment page index
556        ix2++;
557    } // end for vpn
[158]558
[166]559    // register the number of pages to be unmapped
560    _ioc_iommu_npages = (user_vpn_max - user_vpn_min) + 1;
[158]561
[166]562    // invalidate data cache in case of memory write
563    if ( to_mem ) _dcache_buf_invalidate( (void*)user_vaddr, length );
[158]564
[166]565    // compute buffer base address for IOC depending on IOMMU activation
566    if ( GIET_IOMMU_ACTIVE ) addr = (_ioc_iommu_ix1) << 21 | (user_vaddr & 0xFFF);
[167]567    else                     addr = (ppn_first << 12) | (user_vaddr & 0xFFF);
[166]568
569    // get the lock on ioc device
[158]570    _ioc_get_lock();
571
[166]572    // peripheral configuration 
573    ioc_address[BLOCK_DEVICE_BUFFER]     = addr;
574    ioc_address[BLOCK_DEVICE_COUNT]      = count;
575    ioc_address[BLOCK_DEVICE_LBA]        = lba;
576    if ( to_mem == 0 ) ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_WRITE;
577    else               ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_READ;
[158]578
579    return 0;
580}
581
582/////////////////////////////////////////////////////////////////////////////////
583// _ioc_completed()
584//
585// This function checks completion of an I/O transfer and reports errors.
[166]586// As it is a blocking call, the processor is stalled.
587// If the virtual memory is activated, the pages mapped in the I/O virtual
588// space are unmapped, and the IOB TLB is cleared.
[158]589// Returns 0 if success, > 0 if error.
590/////////////////////////////////////////////////////////////////////////////////
591unsigned int _ioc_completed()
592{
[166]593    unsigned int        ret;
594    unsigned int        ix2;
[158]595
[166]596    // busy waiting
[158]597    while (_ioc_done == 0)
598        asm volatile("nop");
599
[166]600    // unmap the buffer from IOMMU page table if IOMMU is activated
601    if ( GIET_IOMMU_ACTIVE )
602    {
603        unsigned int* iob_address = (unsigned int*)&seg_iob_base;
604
605        for ( ix2 = 0 ; ix2 < _ioc_iommu_npages ; ix2++ )
606        {
607            // unmap the page in IOMMU page table
608            _iommu_inval_pte2( _ioc_iommu_ix1,  // PT1 index
609                              ix2 );                    // PT2 index
610
611            // clear IOMMU TLB
612            iob_address[IOB_INVAL_PTE] = (_ioc_iommu_ix1 << 21) | (ix2) << 12; 
613        }
614    }
615
616    // test IOC status
[158]617    if ((_ioc_status != BLOCK_DEVICE_READ_SUCCESS)
[166]618            && (_ioc_status != BLOCK_DEVICE_WRITE_SUCCESS)) ret = 1;    // error
619    else                                                    ret = 0;    // success
[158]620
[166]621    // reset synchronization variables
[158]622    _ioc_lock =0;
623    _ioc_done =0;
624
625    return ret;
626}
627
[166]628///////////////////////////////////////////////////////////////////////////////
629// _ioc_read()
630// Transfer data from the block device to a memory buffer in user space.
631// - lba    : first block index on the block device
632// - buffer : base address of the memory buffer (must be word aligned)
633// - count  : number of blocks to be transfered.
634// Returns 0 if success, > 0 if error.
635///////////////////////////////////////////////////////////////////////////////
636unsigned int _ioc_read( unsigned int    lba, 
637                        void*               buffer, 
638                        unsigned int    count )
639{
640    return _ioc_access( 1,              // read
641                        lba,
642                        (unsigned int)buffer,
643                        count );
644}
645
646///////////////////////////////////////////////////////////////////////////////
647// _ioc_write()
648// Transfer data from a memory buffer in user space to the block device.
649// - lba    : first block index on the block device
650// - buffer : base address of the memory buffer (must be word aligned)
651// - count  : number of blocks to be transfered.
652// Returns 0 if success, > 0 if error.
653///////////////////////////////////////////////////////////////////////////////
654unsigned int _ioc_write( unsigned int   lba, 
655                         const void*    buffer, 
656                         unsigned int   count )
657{
658    return _ioc_access( 0,              // write
659                        lba,
660                        (unsigned int)buffer,
661                        count );
662}
663
[158]664//////////////////////////////////////////////////////////////////////////////////
665//      VciFrameBuffer driver
666//////////////////////////////////////////////////////////////////////////////////
667// The '_fb_sync_write' and '_fb_sync_read' functions use a memcpy strategy to
668// implement the transfer between a data buffer (user space) and the frame
669// buffer (kernel space). They are blocking until completion of the transfer.
670// The '_fb_write()', '_fb_read()' and '_fb_completed()' functions use the DMA
671// coprocessor to transfer data between the user buffer and the frame buffer.
672// These  functions use a polling policy to test the global variables _dma_busy[i]
673// and detect the transfer completion. 
674// There is  NB_PROCS DMA channels, that are indexed by the proc_id.
675// The _dma_busy[i] synchronisation variables (one per channel) are set by the OS,
676// and reset by the ISR.
677//////////////////////////////////////////////////////////////////////////////////
678
679//////////////////////////////////////////////////////////////////////////////////
680// _fb_sync_write()
681// Transfer data from an memory buffer to the frame_buffer device using
682// a memcpy. The source memory buffer must be in user address space.
683// - offset : offset (in bytes) in the frame buffer.
684// - buffer : base address of the memory buffer.
685// - length : number of bytes to be transfered.
686// Returns 0 if success, > 0 if error.
687//////////////////////////////////////////////////////////////////////////////////
688unsigned int _fb_sync_write( unsigned int       offset, 
689                             const void*        buffer, 
690                             unsigned int       length )
691{
692    volatile unsigned char *fb_address;
693
694    /* buffer must be in user space */
695    if (((unsigned int)buffer >= 0x80000000)
696            || (((unsigned int)buffer + length ) >= 0x80000000 ))
697        return 1;
698
699    fb_address = (unsigned char*)&seg_fb_base + offset;
700
701    /* buffer copy */
702    memcpy((void*)fb_address, (void*)buffer, length);
703
704    return 0;
705}
706
707//////////////////////////////////////////////////////////////////////////////////
708// _fb_sync_read()
709// Transfer data from the frame_buffer device to a memory buffer using
710// a memcpy. The destination memory buffer must be in user address space.
711// - offset : offset (in bytes) in the frame buffer.
712// - buffer : base address of the memory buffer.
713// - length : number of bytes to be transfered.
714// Returns 0 if success, > 0 if error.
715//////////////////////////////////////////////////////////////////////////////////
716unsigned int _fb_sync_read( unsigned int        offset, 
717                            const void*         buffer, 
718                            unsigned int        length )
719{
720    volatile unsigned char *fb_address;
721
722    /* parameters checking */
723    /* buffer must be in user space */
724    if (((unsigned int)buffer >= 0x80000000)
725            || (((unsigned int)buffer + length ) >= 0x80000000 ))
726        return 1;
727
728    fb_address = (unsigned char*)&seg_fb_base + offset;
729
730    /* buffer copy */
731    memcpy((void*)buffer, (void*)fb_address, length);
732
733    return 0;
734}
735
736//////////////////////////////////////////////////////////////////////////////////
737// _fb_write()
738// Transfer data from an memory buffer to the frame_buffer device using a DMA.
739// The source memory buffer must be in user address space.
740// - offset : offset (in bytes) in the frame buffer.
741// - buffer : base address of the memory buffer.
742// - length : number of bytes to be transfered.
743// Returns 0 if success, > 0 if error.
744//////////////////////////////////////////////////////////////////////////////////
745unsigned int _fb_write( unsigned int    offset, 
746                        const void*     buffer, 
747                        unsigned int    length )
748{
749    volatile unsigned char *fb_address;
750    volatile unsigned int *dma;
751
752    unsigned int proc_id;
753    unsigned int delay;
754    unsigned int i;
755
756    /* buffer must be in user space */
757    if (((unsigned int)buffer >= 0x80000000)
758            || (((unsigned int)buffer + length ) >= 0x80000000 ))
759        return 1;
760
761    proc_id = _procid();
762    fb_address = (unsigned char*)&seg_fb_base + offset;
763    dma = (unsigned int*)&seg_dma_base + (proc_id * DMA_SPAN);
764
765    /* waiting until DMA device is available */
766    while (_dma_busy[proc_id] != 0)
767    {
768        /* if the lock failed, busy wait with a pseudo random delay between bus
769         * accesses */
770        delay = (_proctime() & 0xF) << 4;
771        for (i = 0; i < delay; i++)
772            asm volatile("nop");
773    }
774    _dma_busy[proc_id] = 1;
775
776    /* DMA configuration for write transfer */
777    dma[DMA_IRQ_DISABLE] = 0;
778    dma[DMA_SRC] = (unsigned int)buffer;
779    dma[DMA_DST] = (unsigned int)fb_address;
780    dma[DMA_LEN] = (unsigned int)length;
781    return 0;
782}
783
784//////////////////////////////////////////////////////////////////////////////////
785// _fb_read()
786// Transfer data from the frame_buffer device to an memory buffer using a DMA.
787// The destination memory buffer must be in user address space.
788// - offset : offset (in bytes) in the frame buffer.
789// - buffer : base address of the memory buffer.
790// - length : number of bytes to be transfered.
791// All cache lines corresponding to the the target buffer are invalidated
792// for cache coherence.
793// Returns 0 if success, > 0 if error.
794//////////////////////////////////////////////////////////////////////////////////
795unsigned int _fb_read( unsigned int     offset, 
796                       const void*      buffer, 
797                       unsigned int     length )
798{
799    volatile unsigned char *fb_address;
800    volatile unsigned int *dma;
801
802    unsigned int proc_id;
803    unsigned int delay;
804    unsigned int i;
805
806    /* buffer must be in user space */
807    if (((unsigned int)buffer >= 0x80000000)
808            || (((unsigned int)buffer + length ) >= 0x80000000 ))
809        return 1;
810
811    proc_id = _procid();
812    fb_address = (unsigned char*)&seg_fb_base + offset;
813    dma = (unsigned int*)&seg_dma_base + (proc_id * DMA_SPAN);
814
815    /* waiting until DMA device is available */
816    while (_dma_busy[proc_id] != 0)
817    {
818        /* if the lock failed, busy wait with a pseudo random delay between bus
819         * accesses */
820        delay = (_proctime() & 0xF) << 4;
821        for (i = 0; i < delay; i++)
822            asm volatile("nop");
823    }
824    _dma_busy[proc_id] = 1;
825
826    /* DMA configuration for write transfer */
827    dma[DMA_IRQ_DISABLE] = 0;
828    dma[DMA_SRC] = (unsigned int)fb_address;
829    dma[DMA_DST] = (unsigned int)buffer;
830    dma[DMA_LEN] = (unsigned int)length;
831
832    /* invalidation of data cache */
833    _dcache_buf_invalidate(buffer, length);
834
835    return 0;
836}
837
838//////////////////////////////////////////////////////////////////////////////////
839// _fb_completed()
840// This function checks completion of a DMA transfer to or fom the frame buffer.
841// As it is a blocking call, the processor is stalled until the next interrupt.
842// Returns 0 if success, > 0 if error.
843//////////////////////////////////////////////////////////////////////////////////
844unsigned int _fb_completed()
845{
846    unsigned int proc_id;
847
848    proc_id = _procid();
849
850    while (_dma_busy[proc_id] != 0)
851        asm volatile("nop");
852
853    if (_dma_status[proc_id] != 0)
854        return 1;
855
856    return 0;
857}
858
Note: See TracBrowser for help on using the repository browser.