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

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

Introducing the "idle" to improve the exit mechanism.

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