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

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