Ignore:
Timestamp:
Aug 7, 2012, 6:37:49 PM (12 years ago)
Author:
alain
Message:

Introducing a new release where all initialisation
is done in the boot code.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • soft/giet_vm/sys/drivers.c

    r169 r189  
    55// Copyright (c) UPMC-LIP6
    66///////////////////////////////////////////////////////////////////////////////////
    7 // The drivers.c and drivers.h files are part ot the GIET nano kernel.
     7// The drivers.c and drivers.h files are part ot the GIET-VM nano kernel.
    88// They contains the drivers for the peripherals available in the SoCLib library:
    99// - vci_multi_tty
     
    1111// - vci_multi_dma
    1212// - vci_multi_icu
     13// - vci_xicu
    1314// - vci_gcd
    1415// - vci_frame_buffer
     
    1617//
    1718// The following global parameters must be defined in the giet_config.h file:
    18 // - NB_CLUSTERS  : number of clusters
    19 // - NB_PROCS     : number of PROCS per cluster
    20 // - NB_TIMERS    : number of TIMERS per cluster
    21 // - NB_DMAS      : number of DMA channels
    22 // - NB_TTYS      : number of TTY terminals
    23 // - NB_TIMERS    : number of TIMERS per cluster
    24 // - CLUSTER_SPAN : address increment between clusters
     19// - NB_CLUSTERS   
     20// - NB_PROCS_MAX 
     21// - NB_TIMERS_MAX   
     22// - NB_DMAS_MAX     
     23// - NB_TTYS   
    2524//
    2625// The following base addresses must be defined in the sys.ld file:
     
    4342#include <ctx_handler.h>
    4443
    45 #if !defined(NB_PROCS)
    46 # error: You must define NB_PROCS in 'giet_config.h' file!
    47 #endif
    4844#if !defined(NB_CLUSTERS)
    49 # error: You must define NB_CLUSTERS in 'giet_config.h' file!
    50 #endif
     45# error: You must define NB_CLUSTERS in 'giet_config.h' file
     46#endif
     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
    5156#if !defined(CLUSTER_SPAN)
    52 # error: You must define CLUSTER_SPAN in 'giet_config.h' file!
    53 #endif
     57# error: You must define CLUSTER_SPAN in 'giet_config.h' file
     58#endif
     59
    5460#if !defined(NB_TTYS)
    55 # error: You must define NB_TTYS in 'giet_config.h' file!
    56 #endif
    57 #if !defined(NB_DMAS)
    58 # error: You must define NB_DMAS in 'giet_config.h' file!
    59 #endif
    60 #if !defined(NB_TIMERS)
    61 # error: You must define NB_TIMERS in 'giet_config.h' file!
     61# error: You must define NB_TTYS in 'giet_config.h' file
    6262#endif
    6363
     
    6666#endif
    6767
    68 #if (NB_TIMERS < NB_PROCS)
    69 # error: NB_TIMERS must be larger or equal to NB_PROCS!
    70 #endif
    71 
    72 #if (NB_PROCS > 8)
    73 # error: NB_PROCS cannot be larger than 8!
    74 #endif
    75 
    76 #if (NB_DMAS < 1)
    77 # error: NB_DMAS cannot be 0!
    78 #endif
    79 
    80 
    81 /////////////////////////////////////////////////////////////////////////////
    82 //      Global (uncachable) variables
    83 /////////////////////////////////////////////////////////////////////////////
     68#if !defined(NB_DMAS_MAX)
     69# error: You must define NB_DMAS_MAX in 'giet_config.h' file
     70#endif
     71
     72#if (NB_DMAS_MAX < 1)
     73# error: NB_DMAS_MAX cannot be 0!
     74#endif
     75
     76#if !defined(NB_TIMERS_MAX)
     77# error: You must define NB_TIMERS_MAX in 'giet_config.h' file
     78#endif
     79
     80#if ( (NB_TIMERS_MAX + NB_PROCS_MAX) > 32 )
     81# error: NB_TIMERS_MAX + NB_PROCS_MAX cannot be larger than 32
     82#endif
     83
     84#if !defined(NB_IOCS)
     85# error: You must define NB_IOCS in 'giet_config.h' file
     86#endif
     87
     88#if ( NB_IOCS > 1 )
     89# error: NB_IOCS cannot be larger than 1
     90#endif
     91
    8492
    8593#define in_unckdata __attribute__((section (".unckdata")))
    8694
    87 // IOC variables
    88 in_unckdata volatile unsigned char _ioc_status       = 0;
    89 in_unckdata volatile unsigned char _ioc_done         = 0;
    90 in_unckdata unsigned int                   _ioc_lock         = 0;
    91 in_unckdata unsigned int                   _ioc_iommu_ix1    = 0;
    92 in_unckdata unsigned int                   _ioc_iommu_npages;
    93 
    94 // DMA variables
    95 in_unckdata volatile unsigned int  _dma_status[NB_DMAS];
    96 in_unckdata volatile unsigned char _dma_busy[NB_DMAS] = { [0 ... NB_DMAS-1] = 0 };
    97 in_unckdata volatile unsigned char _dma_iommu_ix1     = 1;
    98 in_unckdata volatile unsigned char _dma_iommu_npages[NB_DMAS];
     95
     96//////////////////////////////////////////////////////////////////////////////
     97//      VciMultiTimer driver
     98//////////////////////////////////////////////////////////////////////////////
     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).
     110//////////////////////////////////////////////////////////////////////////////
     111
     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
     119//////////////////////////////////////////////////////////////////////////////
     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.
     125// Returns 0 if success, > 0 if error.
     126//////////////////////////////////////////////////////////////////////////////
     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 )
     132{
     133    // parameters checking
     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;
     137
     138#if GIET_USE_XICU
     139
     140    unsigned int* timer_address = //TODO
     141
     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
     151    return 0;
     152}
     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;
     164    unsigned int timer_id   = _get_current_context_slot(CTX_TIMER_ID);
     165    unsigned int cluster_id = timer_id / (NB_PROCS_MAX + NB_TIMERS_MAX);
     166    unsigned int local_id   = timer_id % (NB_PROCS_MAX + NB_TIMERS_MAX);
     167
     168    // checking user timer
     169    if ( local_id < NB_PROCS_MAX )
     170    {
     171        return 2;
     172    }
     173    else
     174    {
     175        return _timer_access ( 0,                               // write access
     176                               cluster_id,
     177                               local_id,
     178                               register_id,
     179                               &buffer );
     180    }
     181}
     182//////////////////////////////////////////////////////////////////////////////
     183//     _timer_read()
     184// This function implements a read access to a "user" timer register.
     185// It gets the cluster_id and local_id from the global index stored in
     186// the task context and use the timer_access() function to make the read.
     187// Returns 0 if success, > 0 if error.
     188//////////////////////////////////////////////////////////////////////////////
     189unsigned int _timer_read( unsigned int  register_id,
     190                          unsigned int* buffer )
     191{
     192    unsigned int timer_id   = _get_current_context_slot(CTX_TIMER_ID);
     193    unsigned int cluster_id = timer_id / (NB_PROCS_MAX + NB_TIMERS_MAX);
     194    unsigned int local_id   = timer_id % (NB_PROCS_MAX + NB_TIMERS_MAX);
     195
     196    // checking user timer
     197    if ( local_id < NB_PROCS_MAX )
     198    {
     199        return 2;
     200    }
     201    else
     202    {
     203        return _timer_access ( 1,                               // read access
     204                               cluster_id,
     205                               local_id,
     206                               register_id,
     207                               buffer );
     208    }
     209}
     210/////////////////////////////////////////////////////////////////////////////////
     211//     _timer_check()
     212/////////////////////////////////////////////////////////////////////////////////
     213
     214/////////////////////////////////////////////////////////////////////////////////
     215//      VciMultiTty driver
     216/////////////////////////////////////////////////////////////////////////////////
     217// There is only one multi_tty controler in the architecture.
     218// The total number of TTYs is defined by the configuration parameter NB_TTYS.
     219// The "system" terminal is TTY[0].
     220// The "user" TTYs are allocated to applications by the GIET in the boot phase,
     221// as defined in the mapping_info data structure. The corresponding tty_id must
     222// be stored in the context of the task by the boot code.
     223// The TTY address is : seg_tty_base + tty_id*TTY_SPAN
     224/////////////////////////////////////////////////////////////////////////////////
    99225
    100226// TTY variables
    101227in_unckdata volatile unsigned char _tty_get_buf[NB_TTYS];
    102228in_unckdata volatile unsigned char _tty_get_full[NB_TTYS] = { [0 ... NB_TTYS-1] = 0 };
    103 in_unckdata unsigned int           _tty_put_lock          = 0;
    104 
    105 //////////////////////////////////////////////////////////////////////////////
    106 //      VciMultiTimer driver
    107 //////////////////////////////////////////////////////////////////////////////
    108 // There is one MULTI-TIMER component per cluster.
    109 // The number of timers per cluster must be larger or equal to the number
    110 // processors (NB_TIMERS >= NB_PROCS), because each processor uses a private
    111 // yimer for context switch.
    112 // The total number of timers is NB_CLUSTERS * NB_TIMERS
    113 // The global timer index = cluster_id*NB_TIMERS + timer_id
    114 //////////////////////////////////////////////////////////////////////////////
    115 
    116 //////////////////////////////////////////////////////////////////////////////
    117 // _timer_write()
    118 //
    119 // Write a 32-bit word in a memory mapped register of a timer device,
    120 // identified by the cluster index and the local timer index.
    121 // Returns 0 if success, > 0 if error.
    122 //////////////////////////////////////////////////////////////////////////////
    123 unsigned int _timer_write( unsigned int cluster_index,
    124                            unsigned int timer_index,
    125                            unsigned int register_index,
    126                            unsigned int value )
    127 {
    128     unsigned int*       timer_address;
    129 
    130     // parameters checking
    131     if ( register_index >= TIMER_SPAN)          return 1;
    132     if ( cluster_index >= NB_CLUSTERS)          return 1;
    133     if ( timer_index >= NB_TIMERS )         return 1;
    134 
    135     timer_address = (unsigned int*)&seg_timer_base +
    136                     ( cluster_index * CLUSTER_SPAN )  +
    137                     ( timer_index * TIMER_SPAN );
    138 
    139     timer_address[register_index] = value; // write word
    140 
    141     return 0;
    142 }
    143 
    144 //////////////////////////////////////////////////////////////////////////////
    145 // _timer_read()
    146 //
    147 // Read a 32-bit word in a memory mapped register of a timer device,
    148 // identified by the cluster index and the local timer index.
    149 // Returns 0 if success, > 0 if error.
    150 //////////////////////////////////////////////////////////////////////////////
    151 unsigned int _timer_read(unsigned int cluster_index,
    152                          unsigned int timer_index,
    153                          unsigned int register_index,
    154                          unsigned int *buffer)
    155 {
    156     unsigned int *timer_address;
    157 
    158     // parameters checking
    159     if ( register_index >= TIMER_SPAN)          return 1;
    160     if ( cluster_index >= NB_CLUSTERS)          return 1;
    161     if ( timer_index >= NB_TIMERS )         return 1;
    162 
    163     timer_address = (unsigned int*)&seg_timer_base +
    164                     ( cluster_index * CLUSTER_SPAN )  +
    165                     ( timer_index * TIMER_SPAN );
    166 
    167     *buffer = timer_address[register_index]; // read word
    168 
    169     return 0;
    170 }
    171 
     229in_unckdata unsigned int           _tty_put_lock = 0;  // protect kernel TTY[0]
     230
     231////////////////////////////////////////////////////////////////////////////////
     232//      _tty_error()
     233////////////////////////////////////////////////////////////////////////////////
     234void _tty_error()
     235{
     236    unsigned int task_id = _get_current_task_id();
     237    unsigned int proc_id = _procid();
     238
     239    _get_lock(&_tty_put_lock);
     240    _puts("\n[GIET ERROR] TTY index too large for task ");
     241    _putw( task_id );
     242    _puts(" on processor ");
     243    _putw( proc_id );
     244    _puts("\n");
     245    _release_lock(&_tty_put_lock);
     246}
    172247/////////////////////////////////////////////////////////////////////////////////
    173 //      VciMultiTty driver
    174 /////////////////////////////////////////////////////////////////////////////////
    175 // The total number of TTYs is defined by the configuration parameter NB_TTYS.
    176 // The system terminal is TTY[0].
    177 // The TTYs are allocated to applications by the GIET in the boot phase.
    178 // The nummber of TTYs allocated to each application, and used by each
    179 // task can be defined in the mapping_info data structure.
    180 // For each user task, the tty_id is stored in the context of the task (slot 34),
    181 // and must be explicitely defined in the boot code.
    182 // The TTY address is always computed as : seg_tty_base + tty_id*TTY_SPAN
    183 ///////////////////////////////////////////////////////////////////////////////////
    184 
    185 //////////////////////////////////////////////////////////////////////////////
    186 // _tty_write()
    187 //
     248//      _tty_write()
    188249// Write one or several characters directly from a fixed-length user buffer to
    189250// the TTY_WRITE register of the TTY controler.
     
    192253// the transfer as soon as the TTY_STATUS[WRITE] bit is set.
    193254// The function returns  the number of characters that have been written.
    194 //////////////////////////////////////////////////////////////////////////////
     255/////////////////////////////////////////////////////////////////////////////////
    195256unsigned int _tty_write( const char             *buffer,
    196257                         unsigned int   length)
    197258{
    198     volatile unsigned int *tty_address;
    199 
    200     unsigned int proc_id;
    201     unsigned int task_id;
    202     unsigned int tty_id;
    203     unsigned int nwritten;
    204 
    205     proc_id = _procid();
    206    
    207     task_id = _scheduler[proc_id].current;
    208     tty_id  = _scheduler[proc_id].context[task_id][CTX_TTY_ID];
    209 
    210     tty_address = (unsigned int*)&seg_tty_base + tty_id*TTY_SPAN;
     259    unsigned int        nwritten;
     260
     261    unsigned int        tty_id = _get_current_context_slot(CTX_TTY_ID);
     262    if ( tty_id >= NB_TTYS )
     263    {
     264        _tty_error();
     265        return 0;
     266    }
     267
     268    unsigned int*       tty_address = (unsigned int*)&seg_tty_base + tty_id*TTY_SPAN;
    211269
    212270    for (nwritten = 0; nwritten < length; nwritten++)
     
    221279    return nwritten;
    222280}
    223 
    224281//////////////////////////////////////////////////////////////////////////////
    225 // _tty_read_irq()
    226 //
     282//      _tty_read_irq()
    227283// This non-blocking function uses the TTY_GET_IRQ[tty_id] interrupt and
    228284// the associated kernel buffer, that has been written by the ISR.
     
    235291                            unsigned int        length)
    236292{
    237     unsigned int proc_id;
    238     unsigned int task_id;
    239     unsigned int tty_id;
    240     unsigned int ret;
    241 
    242     proc_id = _procid();
    243     task_id = _scheduler[proc_id].current;
    244     tty_id  = _scheduler[proc_id].context[task_id][CTX_TTY_ID];
     293    unsigned int        tty_id = _get_current_context_slot(CTX_TTY_ID);
     294
     295    if ( tty_id >= NB_TTYS )
     296    {
     297        _tty_error();
     298        return 0;
     299    }
    245300
    246301    if (_tty_get_full[tty_id] == 0)
    247302    {
    248         ret = 0;
     303        return 0;
    249304    }
    250305    else
     
    252307        *buffer = _tty_get_buf[tty_id];
    253308        _tty_get_full[tty_id] = 0;
    254         ret = 1;
    255     }
    256     return ret;
    257 }
    258 
    259 ////////////////////////////////////////////////////////////////////////////////
    260 // _tty_read()
    261 //
     309        return 1;
     310    }
     311}
     312////////////////////////////////////////////////////////////////////////////////
     313//     _tty_read()
    262314// This non-blocking function fetches one character directly from the TTY_READ
    263315// register of the TTY controler, and writes this character to the user buffer.
     
    268320                        unsigned int    length)
    269321{
    270     volatile unsigned int *tty_address;
    271 
    272     unsigned int proc_id;
    273     unsigned int task_id;
    274     unsigned int tty_id;
    275 
    276     proc_id = _procid();
    277     task_id = _scheduler[proc_id].current;
    278     tty_id  = _scheduler[proc_id].context[task_id][CTX_TTY_ID];
    279 
    280     tty_address = (unsigned int*)&seg_tty_base + tty_id*TTY_SPAN;
    281 
    282     if ((tty_address[TTY_STATUS] & 0x1) != 0x1) return 0;
    283 
    284     *buffer = (char)tty_address[TTY_READ];
    285     return 1;
    286 }
    287 
    288 ////////////////////////////////////////////////////////////////////////////////
    289 //      VciMultiIcu driver
    290 ////////////////////////////////////////////////////////////////////////////////
    291 // There is in principle one MULTI-ICU component per cluster, and the
    292 // number of independant ICUs is equal to NB_PROCS, because there is
    293 // one ICU per processor.
    294 ////////////////////////////////////////////////////////////////////////////////
    295 
    296 ////////////////////////////////////////////////////////////////////////////////
    297 // _icu_write()
    298 //
     322    unsigned int        tty_id = _get_current_context_slot(CTX_TTY_ID);
     323    if ( tty_id >= NB_TTYS )
     324    {
     325        _tty_error();
     326        return 0;
     327    }
     328
     329    unsigned int*       tty_address = (unsigned int*)&seg_tty_base + tty_id*TTY_SPAN;
     330
     331    if ((tty_address[TTY_STATUS] & 0x1) != 0x1)
     332    {
     333        return 0;
     334    }
     335    else
     336    {
     337        *buffer = (char)tty_address[TTY_READ];
     338        return 1;
     339    }
     340}
     341
     342////////////////////////////////////////////////////////////////////////////////
     343//      VciMultiIcu and VciXicu drivers
     344////////////////////////////////////////////////////////////////////////////////
     345// There is in principle one vci_multi_icu (or vci_xicu) component per cluster,
     346// and the number of independant ICUs is equal to NB_PROCS_MAX, because there is
     347// one private interrupr controler per processor.
     348////////////////////////////////////////////////////////////////////////////////
     349
     350////////////////////////////////////////////////////////////////////////////////
     351//     _icu_write()
    299352// Write a 32-bit word in a memory mapped register of the MULTI_ICU device,
    300353// identified by the cluster index, and a processor local index.
     
    306359                         unsigned int value )
    307360{
    308     unsigned int *icu_address;
     361#if GIET_USE_XICU
     362
     363#else
    309364
    310365    // parameters checking
    311366    if ( register_index >= ICU_SPAN)            return 1;
    312367    if ( cluster_index >= NB_CLUSTERS)          return 1;
    313     if ( proc_index >= NB_PROCS )           return 1;
    314 
    315     icu_address = (unsigned int*)&seg_icu_base +
    316                   ( cluster_index * CLUSTER_SPAN )  +
    317                   ( proc_index * ICU_SPAN );
     368    if ( proc_index >= NB_PROCS_MAX )       return 1;
     369
     370    unsigned int *icu_address = (unsigned int*)&seg_icu_base +
     371                                (cluster_index * CLUSTER_SPAN)  +
     372                                (proc_index * ICU_SPAN);
    318373
    319374    icu_address[register_index] = value;   // write word
    320375    return 0;
    321 }
    322 
    323 ////////////////////////////////////////////////////////////////////////////////
    324 // _icu_read()
    325 //
     376
     377#endif
     378}
     379////////////////////////////////////////////////////////////////////////////////
     380//     _icu_read()
    326381// Read a 32-bit word in a memory mapped register of the MULTI_ICU device,
    327382// identified by the cluster index and a processor local index.
     
    333388                         unsigned int* buffer )
    334389{
    335     unsigned int *icu_address;
     390#if GIET_USE_XICU
     391
     392#else
    336393
    337394    // parameters checking
    338395    if ( register_index >= ICU_SPAN)            return 1;
    339396    if ( cluster_index >= NB_CLUSTERS)          return 1;
    340     if ( proc_index >= NB_PROCS )           return 1;
    341 
    342     icu_address = (unsigned int*)&seg_icu_base +
    343                   ( cluster_index * CLUSTER_SPAN )  +
    344                   ( proc_index * ICU_SPAN );
     397    if ( proc_index >= NB_PROCS_MAX )       return 1;
     398
     399    unsigned int *icu_address = (unsigned int*)&seg_icu_base +
     400                                (cluster_index * CLUSTER_SPAN)  +
     401                                (proc_index * ICU_SPAN);
    345402
    346403    *buffer = icu_address[register_index]; // read word
    347404    return 0;
     405
     406#endif
    348407}
    349408
     
    357416
    358417////////////////////////////////////////////////////////////////////////////////
    359 // _gcd_write()
    360 //
     418//     _gcd_write()
    361419// Write a 32-bit word in a memory mapped register of the GCD coprocessor.
    362420// Returns 0 if success, > 0 if error.
     
    376434    return 0;
    377435}
    378 
    379 ////////////////////////////////////////////////////////////////////////////////
    380 // _gcd_read()
    381 //
     436////////////////////////////////////////////////////////////////////////////////
     437//     _gcd_read()
    382438// Read a 32-bit word in a memory mapped register of the GCD coprocessor.
    383439// Returns 0 if success, > 0 if error.
     
    448504///////////////////////////////////////////////////////////////////////////////
    449505
     506// IOC global variables
     507in_unckdata volatile unsigned int       _ioc_status       = 0;
     508in_unckdata volatile unsigned int       _ioc_done         = 0;
     509in_unckdata unsigned int                        _ioc_lock         = 0;
     510in_unckdata unsigned int                        _ioc_iommu_ix1    = 0;
     511in_unckdata unsigned int                        _ioc_iommu_npages;
     512
    450513///////////////////////////////////////////////////////////////////////////////
    451 // _ioc_get_lock()
    452 //
    453 // This blocking helper is used by '_ioc_read()' and '_ioc_write()' functions
    454 // to get _ioc_lock using atomic LL/SC.
    455 ///////////////////////////////////////////////////////////////////////////////
    456 static inline void _ioc_get_lock()
    457 {
    458     register unsigned int delay = (_proctime() & 0xF) << 4;
    459     register unsigned int *plock = (unsigned int*)&_ioc_lock;
    460 
    461     asm volatile (
    462             "_ioc_llsc:             \n"
    463             "ll   $2,    0(%0)      \n" /* $2 <= _ioc_lock current value */
    464             "bnez $2,    _ioc_delay \n" /* delay if _ioc_lock already taken */
    465             "li   $3,    1          \n" /* $3 <= argument for sc */
    466             "sc   $3,    0(%0)      \n" /* try to set _ioc_lock */
    467             "bnez $3,    _ioc_ok    \n" /* exit if atomic */
    468             "_ioc_delay:            \n"
    469             "move $4,    %1         \n" /* $4 <= delay */
    470             "_ioc_loop:             \n"
    471             "beqz $4,    _ioc_loop  \n" /* test end delay */
    472             "addi $4,    $4,    -1  \n" /* $4 <= $4 - 1 */
    473             "j           _ioc_llsc  \n" /* retry ll */
    474             "nop                    \n"
    475             "_ioc_ok:               \n"
    476             :
    477             :"r"(plock), "r"(delay)
    478             :"$2", "$3", "$4");
    479 }
    480 
    481 ///////////////////////////////////////////////////////////////////////////////
    482 //  _ioc_access()
     514//      _ioc_access()
    483515// This function transfer data between a memory buffer and the block device.
    484516// The buffer lentgth is (count*block_size) bytes.
    485 //
    486517// Arguments are:
    487518// - to_mem     : from external storage to memory when non 0
     
    503534    unsigned int                ix2;                    // page index in IOMMU PT1 page table
    504535    unsigned int                addr;                   // buffer address for IOC peripheral
    505     unsigned int                user_ptp;               // page table pointer in user space
    506     unsigned int                ko;                             // bool returned by _v2p_translate()
    507536    unsigned int                ppn_first;              // first physical page number for user buffer
    508     unsigned int                ltid;                   // current task local index
    509     static_scheduler_t* psched;                 // pointer on the current task scheduler
    510537       
    511538    // check buffer alignment
     
    517544
    518545    // get user space page table virtual address
    519     psched   = &_scheduler[_procid()];
    520     ltid     = psched->current;
    521     user_ptp = psched->context[ltid][CTX_PTAB_ID];
     546    unsigned int user_pt_vbase = _get_current_context_slot(CTX_PTAB_ID);
    522547   
    523548    user_vpn_min = user_vaddr >> 12;
     
    529554    {
    530555        // get ppn and flags for each vpn
    531         ko = _v2p_translate( (page_table_t*)user_ptp,
    532                              vpn,
    533                              &ppn,
    534                              &flags );
     556        unsigned int ko = _v2p_translate( (page_table_t*)user_pt_vbase,
     557                                           vpn,
     558                                           &ppn,
     559                                           &flags );
    535560
    536561        // check access rights
     
    573598
    574599    // get the lock on ioc device
    575     _ioc_get_lock();
     600    _get_lock( &_ioc_lock );
    576601
    577602    // peripheral configuration 
     
    584609    return 0;
    585610}
    586 
    587611/////////////////////////////////////////////////////////////////////////////////
    588612// _ioc_completed()
     
    630654    return ret;
    631655}
    632 
    633656///////////////////////////////////////////////////////////////////////////////
    634 // _ioc_read()
     657//     _ioc_read()
    635658// Transfer data from the block device to a memory buffer in user space.
    636659// - lba    : first block index on the block device
     
    643666                        unsigned int    count )
    644667{
    645     return _ioc_access( 1,              // read
     668    return _ioc_access( 1,              // read access
    646669                        lba,
    647670                        (unsigned int)buffer,
    648671                        count );
    649672}
    650 
    651673///////////////////////////////////////////////////////////////////////////////
    652 // _ioc_write()
     674//     _ioc_write()
    653675// Transfer data from a memory buffer in user space to the block device.
    654676// - lba    : first block index on the block device
     
    661683                         unsigned int   count )
    662684{
    663     return _ioc_access( 0,              // write
     685    return _ioc_access( 0,              // write access
    664686                        lba,
    665687                        (unsigned int)buffer,
     
    668690
    669691//////////////////////////////////////////////////////////////////////////////////
     692// VciMultiDma driver
     693//////////////////////////////////////////////////////////////////////////////////
     694// The DMA controllers are physically distributed in the clusters.
     695// There is  (NB_CLUSTERS * NB_DMAS_MAX) channels, indexed by a global index:
     696//        dma_id = cluster_id * NB_DMA_MAX + loc_id
     697//
     698// As a DMA channel can be used by several tasks, each DMA channel is protected
     699// by a specific lock: _dma_lock[dma_id]
     700// The signalisation between the OS and the DMA uses the _dma_done[dma_id]
     701// synchronisation variables  (set by the ISR, and reset by the OS).
     702// The transfer status is copied by the ISR in the _dma_status[dma_id] variables.
     703//
     704// These DMA channels can be used by the FB driver, or by the NIC driver.
     705//////////////////////////////////////////////////////////////////////////////////
     706
     707#if  (NB_DMAS_MAX > 0)
     708in_unckdata unsigned int                        _dma_lock[NB_DMAS_MAX * NB_CLUSTERS]
     709                                       = { [0 ... (NB_DMAS_MAX * NB_CLUSTERS)-1] = 0 };
     710
     711in_unckdata volatile unsigned int       _dma_done[NB_DMAS_MAX * NB_CLUSTERS]
     712                                       = { [0 ... (NB_DMAS_MAX * NB_CLUSTERS)-1] = 0 };
     713
     714in_unckdata volatile unsigned int       _dma_status[NB_DMAS_MAX * NB_CLUSTERS];
     715
     716in_unckdata unsigned int                        _dma_iommu_ix1 = 1;
     717
     718in_unckdata unsigned int            _dma_iommu_npages[NB_DMAS_MAX * NB_CLUSTERS];
     719#endif
     720
     721//////////////////////////////////////////////////////////////////////////////////
    670722//      VciFrameBuffer driver
    671723//////////////////////////////////////////////////////////////////////////////////
     724// The vci_frame_buffer device can be accessed directly by software with memcpy(),
     725// or it can be accessed through a multi-channels DMA component:
     726// 
    672727// The '_fb_sync_write' and '_fb_sync_read' functions use a memcpy strategy to
    673728// implement the transfer between a data buffer (user space) and the frame
     
    675730//
    676731// The '_fb_write()', '_fb_read()' and '_fb_completed()' functions use the DMA
    677 // coprocessor to transfer data between the user buffer and the frame buffer.
    678 // These  functions use a polling policy to test the global variables _dma_busy[i]
    679 // and detect the transfer completion. 
    680 // There is  NB_DMA channels, that are indexed by the dma_id stored in the
    681 // task context.
    682 // The _dma_busy[i] synchronisation variables (one per channel) are set by the OS,
    683 // and reset by the DMA ISR.
     732// controlers (distributed in the clusters) to transfer data
     733// between the user buffer and the frame buffer. A  DMA channel is
     734// allocated to each task requesting it in the mapping_info data structure.
    684735//////////////////////////////////////////////////////////////////////////////////
    685736
     
    697748                             unsigned int       length )
    698749{
    699     volatile unsigned char *fb_address;
    700750
    701751    // buffer must be mapped in user space
    702752    if ( ((unsigned int)buffer + length ) >= 0x80000000 )
     753    {
    703754        return 1;
    704 
    705     fb_address = (unsigned char*)&seg_fb_base + offset;
    706 
    707     // buffer copy
    708     memcpy((void*)fb_address, (void*)buffer, length);
    709 
    710     return 0;
     755    }
     756    else
     757    {
     758        unsigned char *fb_address = (unsigned char*)&seg_fb_base + offset;
     759        memcpy((void*)fb_address, (void*)buffer, length);
     760        return 0;
     761    }
    711762}
    712763
     
    724775                            unsigned int        length )
    725776{
    726     volatile unsigned char *fb_address;
    727 
    728777    // buffer must be mapped in user space
    729778    if ( ((unsigned int)buffer + length ) >= 0x80000000 )
     779    {
    730780        return 1;
    731 
    732     fb_address = (unsigned char*)&seg_fb_base + offset;
    733 
    734     // buffer copy
    735     memcpy((void*)buffer, (void*)fb_address, length);
    736 
    737     return 0;
    738 }
    739 
    740 //////////////////////////////////////////////////////////////////////////////////
    741 // _fb_access()
    742 // Transfer data between a memory buffer and the frame_buffer device using DMA.
    743 // - to_mem     : from frame buffer to memory when true.
     781    }
     782    else
     783    {
     784        unsigned char *fb_address = (unsigned char*)&seg_fb_base + offset;
     785        memcpy((void*)buffer, (void*)fb_address, length);
     786        return 0;
     787    }
     788}
     789
     790//////////////////////////////////////////////////////////////////////////////////
     791// _fb_dma_access()
     792// Transfer data between a user buffer and the frame_buffer using DMA.
     793// - to_user    : from frame buffer to user buffer when true.
    744794// - offset     : offset (in bytes) in the frame buffer.
    745795// - user_vaddr : virtual base address of the memory buffer.
     
    747797// The memory buffer must be mapped in user address space and word-aligned.
    748798// The user buffer length must be multiple of 4 bytes.
    749 // Returns 0 if success, > 0 if error.
    750 //////////////////////////////////////////////////////////////////////////////////
    751 unsigned int _fb_access( unsigned int   to_mem,
    752                          unsigned int   offset,
    753                          unsigned int   user_vaddr,
    754                          unsigned int   length )
    755 {
    756     static_scheduler_t* psched;         // pointer on the current task scheduler
    757     unsigned char*              fb_base;        // frame buffer base address
    758     unsigned int*               dma_base;       // dma component base address
    759     unsigned int                task_id;        // task local index (for scheduler)
    760     unsigned int                dma_id;         // DMA channel index
    761     unsigned int                vpn;            // current virtual page number
    762     unsigned int                flags;          // protection flags
    763     unsigned int                ppn;            // current physical page number
    764     unsigned int                buf_base;       // buffer base address for DMA access
    765     unsigned int                ppn_first;      // first physical page index for user buffer
    766 
    767     fb_base  = (unsigned char*)&seg_fb_base + offset;
    768 
    769     psched   = &_scheduler[_procid()];
    770     task_id  = psched->current;
    771     dma_id   = psched->context[task_id][CTX_FBDMA_ID];
    772     dma_base = (unsigned int*)&seg_dma_base + (dma_id * DMA_SPAN);
    773 
    774     // check buffer address and ength alignment
    775     if ( user_vaddr & 0x3 ) return 1;
    776     if ( length     & 0x3 ) return 1;
     799// Me must compute the physical base addresses for both the frame buffer
     800// and the user buffer before programming the DMA transfer.
     801// The GIET being fully static, we don't need to split the transfer in 4Kbytes
     802// pages, because the user buffer is contiguous in physical space.
     803// Returns 0 if success, > 0 if error.
     804//////////////////////////////////////////////////////////////////////////////////
     805unsigned int _fb_dma_access( unsigned int       to_user,
     806                             unsigned int   offset,
     807                             unsigned int   user_vaddr,
     808                             unsigned int   length )
     809{
     810    unsigned int        ko;                             // unsuccessfull V2P translation
     811    unsigned int        flags;                  // protection flags
     812    unsigned int        ppn;                    // physical page number
     813    unsigned int    user_pbase;         // user buffer pbase address
     814    unsigned int    fb_pbase;           // frame buffer pbase address
     815
     816    // get DMA channel and compute DMA vbase address
     817    unsigned int        dma_id     = _get_current_context_slot(CTX_FBDMA_ID);
     818    unsigned int    cluster_id = dma_id / NB_DMAS_MAX;
     819    unsigned int    loc_id     = dma_id % NB_DMAS_MAX;
     820    unsigned int*       dma_base   = (unsigned int*)&seg_dma_base +
     821                                 (cluster_id * CLUSTER_SPAN) +
     822                                 (loc_id * DMA_SPAN);
     823
     824    // check user buffer address and length alignment
     825    if ( (user_vaddr & 0x3) || (length & 0x3) )
     826    {
     827        _puts("[GIET ERROR] in _fbdma_access() : user buffer not word aligned\n");
     828        return 1;
     829    }
    777830
    778831    // get user space page table virtual address
    779     unsigned int user_ptp = psched->context[task_id][CTX_PTAB_ID];
    780 
     832    unsigned int        user_ptab = _get_current_context_slot(CTX_PTAB_ID);
     833
     834    // compute frame buffer pbase address
     835    unsigned int fb_vaddr = (unsigned int)&seg_fb_base + offset;
     836
     837    ko = _v2p_translate( (page_table_t*)user_ptab,
     838                         (fb_vaddr >> 12),
     839                         &ppn,
     840                         &flags );
     841    fb_pbase = (ppn << 12) | (fb_vaddr & 0x00000FFF);
     842
     843    if ( ko )
     844    {
     845        _puts("[GIET ERROR] in _fbdma_access() : frame buffer unmapped\n");
     846        return 2;
     847    }
     848
     849    // Compute user buffer pbase address
     850    ko = _v2p_translate( (page_table_t*)user_ptab,
     851                         (user_vaddr >> 12),
     852                         &ppn,
     853                         &flags );
     854    user_pbase = (ppn << 12) | (user_vaddr & 0x00000FFF);
     855
     856    if ( ko )
     857    {
     858        _puts("[GIET ERROR] in _fbdma_access() : user buffer unmapped\n");
     859        return 3;
     860    }
     861    if ( (flags & PTE_U) == 0 )
     862    {
     863        _puts("[GIET ERROR] in _fbdma_access() : user buffer not in user space\n");
     864        return 4;
     865    }
     866    if ( ( (flags & PTE_W) == 0 ) && to_user )
     867    {
     868        _puts("[GIET ERROR] in _fbdma_access() : user buffer not writable\n");
     869        return 5;
     870    }
     871
     872
     873
     874/*
     875    // loop on all virtual pages covering the user buffer
    781876    unsigned int user_vpn_min = user_vaddr >> 12;
    782877    unsigned int user_vpn_max = (user_vaddr + length - 1) >> 12;
    783878    unsigned int ix2          = 0;
    784879    unsigned int ix1          = _dma_iommu_ix1 + dma_id;
    785     unsigned int ko;
    786     unsigned int i;
    787 
    788     // loop on all virtual pages covering the user buffer
     880
    789881    for ( vpn = user_vpn_min ; vpn <= user_vpn_max ; vpn++ )
    790882    {
    791883        // get ppn and flags for each vpn
    792         ko = _v2p_translate( (page_table_t*)user_ptp,
    793                              vpn,
    794                              &ppn,
    795                              &flags );
     884        unsigned int ko = _v2p_translate( (page_table_t*)user_pt_vbase,
     885                                          vpn,
     886                                          &ppn,
     887                                          &flags );
    796888
    797889        // check access rights
    798         if ( ko )                                 return 2;     // unmapped
    799         if ( (flags & PTE_U) == 0 )               return 3;     // not in user space
    800         if ( ( (flags & PTE_W) == 0 ) && to_mem ) return 4;     // not writable
     890        if ( ko )                                 return 3;     // unmapped
     891        if ( (flags & PTE_U) == 0 )               return 4;     // not in user space
     892        if ( ( (flags & PTE_W) == 0 ) && to_user ) return 5;     // not writable
    801893
    802894        // save first ppn value
     
    816908        else            // no IOMMU : check that physical pages are contiguous
    817909        {
    818             if ( (ppn - ppn_first) != ix2 )       return 5;     // split physical buffer 
     910            if ( (ppn - ppn_first) != ix2 )       return 6;     // split physical buffer 
    819911        }
    820912
     
    823915    } // end for vpn
    824916
    825     // register the number of pages to be unmapped
     917    // register the number of pages to be unmapped if iommu activated
    826918    _dma_iommu_npages[dma_id] = (user_vpn_max - user_vpn_min) + 1;
    827919
     920*/
    828921    // invalidate data cache in case of memory write
    829     if ( to_mem ) _dcache_buf_invalidate( (void*)user_vaddr, length );
    830 
    831     // compute buffer base address for DMA depending on IOMMU activation
    832     if ( GIET_IOMMU_ACTIVE ) buf_base = ( ix1 ) << 21 | (user_vaddr & 0xFFF);
    833     else                     buf_base = (ppn_first << 12) | (user_vaddr & 0xFFF);
    834 
    835 
    836     // waiting until DMA device is available
    837     while (_dma_busy[dma_id] != 0)
    838     {
    839         // busy wait with a pseudo random delay between bus access
    840         unsigned int delay = (_proctime() & 0xF) << 4;
    841         for (i = 0; i < delay; i++)
    842             asm volatile("nop");
    843     }
    844 
    845     _dma_busy[dma_id] = 1;
     922    if ( to_user ) _dcache_buf_invalidate( (void*)user_vaddr, length );
     923
     924    // get the lock
     925    _get_lock( &_dma_lock[dma_id] );
    846926
    847927    // DMA configuration
    848     dma_base[DMA_IRQ_DISABLE] = 0;
    849     if ( to_mem )
    850     {
    851         dma_base[DMA_SRC] = (unsigned int)fb_base;
    852         dma_base[DMA_DST] = (unsigned int)buf_base;
     928    if ( to_user )
     929    {
     930        dma_base[DMA_SRC] = (unsigned int)fb_pbase;
     931        dma_base[DMA_DST] = (unsigned int)user_pbase;
    853932    }
    854933    else
    855934    {
    856         dma_base[DMA_SRC] = (unsigned int)buf_base;
    857         dma_base[DMA_DST] = (unsigned int)fb_base;
     935        dma_base[DMA_SRC] = (unsigned int)user_pbase;
     936        dma_base[DMA_DST] = (unsigned int)fb_pbase;
    858937    }
    859938    dma_base[DMA_LEN] = (unsigned int)length;
     
    873952                        unsigned int    length )
    874953{
    875     return _fb_access( 0,                                               // write to frame buffer
    876                        offset,
    877                        (unsigned int)buffer,
    878                        length );       
     954    return _fb_dma_access( 0,                                           // write to frame buffer
     955                           offset,
     956                           (unsigned int)buffer,
     957                           length );   
    879958}
    880959
     
    891970                       unsigned int     length )
    892971{
    893     return _fb_access( 1,                                               // read from frame buffer
    894                        offset,
    895                        (unsigned int)buffer,
    896                        length );       
     972    return _fb_dma_access( 1,                                           // read from frame buffer
     973                           offset,
     974                           (unsigned int)buffer,
     975                           length );   
    897976}
    898977
     
    906985unsigned int _fb_completed()
    907986{
    908     static_scheduler_t* psched  = &_scheduler[_procid()];
    909     unsigned int        task_id = psched->current;
    910 
    911     volatile unsigned int   dma_id  = psched->context[task_id][CTX_FBDMA_ID];
     987    unsigned int dma_id = _get_current_context_slot(CTX_FBDMA_ID);
    912988
    913989    // busy waiting with a pseudo random delay between bus access
    914     while (_dma_busy[dma_id] != 0)
     990    while (_dma_done[dma_id] == 0)
    915991    {
    916992            unsigned int i;
    917         unsigned int delay = (_proctime() & 0xF) << 4;
     993        unsigned int delay = ( _proctime() ^ _procid()<<4 ) & 0xFF;
    918994        for (i = 0; i < delay; i++)
    919995            asm volatile("nop");
     
    9381014    }
    9391015
     1016    // reset synchronization variables
     1017    _dma_lock[dma_id] = 0;
     1018    _dma_done[dma_id] = 0;
     1019
    9401020    return _dma_status[dma_id];
    9411021}
Note: See TracChangeset for help on using the changeset viewer.