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

Last change on this file since 223 was 223, checked in by meunier, 12 years ago

Correction d'un bug dans drivers.c (fonctions _ioc_completed et _dma_completed) :
on relâche le lock après avoir remis à 0 les variables de synchro _ioc_done et _dma_done (+ pour le dma, lecture du status avant de relâcher le lock)
(+ ajout d'un sync dans les 2 cas avant relâchement du lock pour tsar)

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