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

Last change on this file since 226 was 226, checked in by karaoui, 12 years ago

2 modifications:
Better debug info for the tty number used,
Adding the O_TRUNC flag when opening/creating the map.bin.

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