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

Last change on this file since 168 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
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : drivers.c
3// Date     : 01/04/2012
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7// The drivers.c and drivers.h files are part ot the GIET nano kernel.
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:
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
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
36#include <vm_handler.h>
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
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
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
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;
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 };
98in_unckdata unsigned int           _tty_put_lock;
99
100//////////////////////////////////////////////////////////////////////////////
101//      VciMultiTimer driver
102//////////////////////////////////////////////////////////////////////////////
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.
107// The total number of timers is NB_CLUSTERS * NB_TIMERS
108// The global timer index = cluster_id*NB_TIMERS + timer_id
109//////////////////////////////////////////////////////////////////////////////
110
111//////////////////////////////////////////////////////////////////////////////
112// _timer_write()
113//
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.
116// Returns 0 if success, > 0 if error.
117//////////////////////////////////////////////////////////////////////////////
118unsigned int _timer_write( unsigned int cluster_index,
119                           unsigned int timer_index,
120                           unsigned int register_index, 
121                           unsigned int value )
122{
123    unsigned int*       timer_address;
124
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;
129
130    timer_address = (unsigned int*)&seg_timer_base + 
131                    ( cluster_index * CLUSTER_SPAN )  +
132                    ( timer_index * TIMER_SPAN );
133
134    timer_address[register_index] = value; // write word
135
136    return 0;
137}
138
139//////////////////////////////////////////////////////////////////////////////
140// _timer_read()
141//
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.
144// Returns 0 if success, > 0 if error.
145//////////////////////////////////////////////////////////////////////////////
146unsigned int _timer_read(unsigned int cluster_index,
147                         unsigned int timer_index, 
148                         unsigned int register_index, 
149                         unsigned int *buffer)
150{
151    unsigned int *timer_address;
152
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;
157
158    timer_address = (unsigned int*)&seg_timer_base + 
159                    ( cluster_index * CLUSTER_SPAN )  +
160                    ( timer_index * TIMER_SPAN );
161
162    *buffer = timer_address[register_index]; // read word
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.
173// The nummber of TTYs allocated to each application, and used by each
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//////////////////////////////////////////////////////////////////////////////
190unsigned int _tty_write( const char             *buffer, 
191                         unsigned int   length)
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();
201   
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    {
209        // check tty's status
210        if ((tty_address[TTY_STATUS] & 0x2) == 0x2)
211            break;
212        else
213            // write character
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
223// the associated kernel buffer, that has been written by the ISR.
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//////////////////////////////////////////////////////////////////////////////
229unsigned int _tty_read_irq( char                        *buffer, 
230                            unsigned int        length)
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////////////////////////////////////////////////////////////////////////////////
262unsigned int _tty_read( char                    *buffer, 
263                        unsigned int    length)
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//
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.
296// Returns 0 if success, > 0 if error.
297////////////////////////////////////////////////////////////////////////////////
298unsigned int _icu_write( unsigned int cluster_index,
299                         unsigned int proc_index,
300                         unsigned int register_index, 
301                         unsigned int value )
302{
303    unsigned int *icu_address;
304
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;
309
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
315    return 0;
316}
317
318////////////////////////////////////////////////////////////////////////////////
319// _icu_read()
320//
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.
323// Returns 0 if success, > 0 if error.
324////////////////////////////////////////////////////////////////////////////////
325unsigned int _icu_read(  unsigned int cluster_index,
326                         unsigned int proc_index,
327                         unsigned int register_index, 
328                         unsigned int* buffer )
329{
330    unsigned int *icu_address;
331
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;
336
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
342    return 0;
343}
344
345////////////////////////////////////////////////////////////////////////////////
346//      VciGcd driver
347////////////////////////////////////////////////////////////////////////////////
348// The Greater Dommon Divider is a -very- simple hardware coprocessor
349// performing the computation of the GCD of two 32 bits integers.
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////////////////////////////////////////////////////////////////////////////////
359unsigned int _gcd_write( unsigned int register_index, 
360                         unsigned int value)
361{
362    volatile unsigned int *gcd_address;
363
364    // parameters checking
365    if (register_index >= GCD_END)
366        return 1;
367
368    gcd_address = (unsigned int*)&seg_gcd_base;
369
370    gcd_address[register_index] = value; // write word
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////////////////////////////////////////////////////////////////////////////////
380unsigned int _gcd_read( unsigned int register_index, 
381                        unsigned int *buffer)
382{
383    volatile unsigned int *gcd_address;
384
385    // parameters checking
386    if (register_index >= GCD_END)
387        return 1;
388
389    gcd_address = (unsigned int*)&seg_gcd_base;
390
391    *buffer = gcd_address[register_index]; // read word
392    return 0;
393}
394
395////////////////////////////////////////////////////////////////////////////////
396// VciBlockDevice driver
397////////////////////////////////////////////////////////////////////////////////
398// The VciBlockDevice is a single channel external storage contrÃŽler.
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//
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
437// transfer completion. When the completion is signaled, the _ioc_completed()
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"
466            "beqz $4,    _ioc_loop  \n" /* test end delay */
467            "addi $4,    $4,    -1  \n" /* $4 <= $4 - 1 */
468            "j           _ioc_llsc  \n" /* retry ll */
469            "nop                    \n"
470            "_ioc_ok:               \n"
471            :
472            :"r"(plock), "r"(delay)
473            :"$2", "$3", "$4");
474}
475
476///////////////////////////////////////////////////////////////////////////////
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.
480//
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.
486// Returns 0 if success, > 0 if error.
487///////////////////////////////////////////////////////////////////////////////
488unsigned int _ioc_access( unsigned int  to_mem,
489                          unsigned int  lba,
490                          unsigned int  user_vaddr,
491                          unsigned int  count )
492{
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
505       
506    // check buffer alignment
507    if ( (unsigned int)user_vaddr & 0x3 ) return 1;
508
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;
512
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];
517   
518    user_vpn_min = user_vaddr >> 12;
519    user_vpn_max = (user_vaddr + length - 1) >> 12;
520    ix2          = 0;
521
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
526        ko = _v2p_translate( (page_table_t*)user_ptp,
527                             vpn,
528                             &ppn,
529                             &flags );
530
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
535
536        // save first ppn value
537        if ( ix2 == 0 ) ppn_first = ppn;
538
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;
543
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
558
559    // register the number of pages to be unmapped
560    _ioc_iommu_npages = (user_vpn_max - user_vpn_min) + 1;
561
562    // invalidate data cache in case of memory write
563    if ( to_mem ) _dcache_buf_invalidate( (void*)user_vaddr, length );
564
565    // compute buffer base address for IOC depending on IOMMU activation
566    if ( GIET_IOMMU_ACTIVE ) addr = (_ioc_iommu_ix1) << 21 | (user_vaddr & 0xFFF);
567    else                     addr = (ppn_first << 12) | (user_vaddr & 0xFFF);
568
569    // get the lock on ioc device
570    _ioc_get_lock();
571
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;
578
579    return 0;
580}
581
582/////////////////////////////////////////////////////////////////////////////////
583// _ioc_completed()
584//
585// This function checks completion of an I/O transfer and reports errors.
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.
589// Returns 0 if success, > 0 if error.
590/////////////////////////////////////////////////////////////////////////////////
591unsigned int _ioc_completed()
592{
593    unsigned int        ret;
594    unsigned int        ix2;
595
596    // busy waiting
597    while (_ioc_done == 0)
598        asm volatile("nop");
599
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
617    if ((_ioc_status != BLOCK_DEVICE_READ_SUCCESS)
618            && (_ioc_status != BLOCK_DEVICE_WRITE_SUCCESS)) ret = 1;    // error
619    else                                                    ret = 0;    // success
620
621    // reset synchronization variables
622    _ioc_lock =0;
623    _ioc_done =0;
624
625    return ret;
626}
627
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
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.