source: soft/giet_vm/giet_drivers/bdv_driver.c @ 726

Last change on this file since 726 was 715, checked in by alain, 9 years ago

Cosmetic.

File size: 10.1 KB
RevLine 
[283]1///////////////////////////////////////////////////////////////////////////////////
[284]2// File      : bdv_driver.c
3// Date      : 23/05/2013
[529]4// Author    : alain greiner cesar fuguet
[283]5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
[295]7// Implementation notes:
[529]8// All accesses to BDV registers are done by the two
9// _bdv_set_register() and _bdv_get_register() low-level functions,
10// that are handling virtual / physical extended addressing.
[283]11///////////////////////////////////////////////////////////////////////////////////
12
13#include <giet_config.h>
[320]14#include <hard_config.h>
[295]15#include <bdv_driver.h>
16#include <xcu_driver.h>
[545]17#include <mmc_driver.h>
[529]18#include <kernel_locks.h>
[283]19#include <utils.h>
[456]20#include <tty0.h>
[283]21#include <ctx_handler.h>
[529]22#include <irq_handler.h>
[283]23
24///////////////////////////////////////////////////////////////////////////////
[630]25//      Extern variables
26///////////////////////////////////////////////////////////////////////////////
27
28// allocated in the boot.c or kernel_init.c files
29extern static_scheduler_t* _schedulers[X_SIZE][Y_SIZE][NB_PROCS_MAX]; 
30 
31///////////////////////////////////////////////////////////////////////////////
[529]32//      Global variables
[295]33///////////////////////////////////////////////////////////////////////////////
34
[715]35// lock protecting exclusive access
[496]36__attribute__((section(".kdata")))
[715]37spin_lock_t      _bdv_lock __attribute__((aligned(64)));
[496]38
[715]39// owner thread (only used in descheduling mode)
[496]40__attribute__((section(".kdata")))
[715]41unsigned int     _bdv_trdid;
[496]42
[715]43// transfer status (only used in descheduling mode)
[496]44__attribute__((section(".kdata")))
[715]45unsigned int     _bdv_status;
[295]46
47///////////////////////////////////////////////////////////////////////////////
[715]48// This low_level function returns the value contained in register(index).
[295]49///////////////////////////////////////////////////////////////////////////////
50unsigned int _bdv_get_register( unsigned int index )
51{
[320]52    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index;
[295]53    return _io_extended_read( vaddr );
54}
55
56///////////////////////////////////////////////////////////////////////////////
[715]57// This low-level function set a new value in register(index).
[295]58///////////////////////////////////////////////////////////////////////////////
59void _bdv_set_register( unsigned int index,
60                        unsigned int value ) 
61{
[320]62    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index;
[295]63    _io_extended_write( vaddr, value );
64}
65
66///////////////////////////////////////////////////////////////////////////////
[529]67//      Extern functions
[283]68///////////////////////////////////////////////////////////////////////////////
[529]69
70/////////////////////////////////////////////////////
71unsigned int _bdv_access( unsigned int       use_irq,
72                          unsigned int       to_mem,
73                          unsigned int       lba,
74                          unsigned long long buf_paddr,
75                          unsigned int       count) 
[283]76{
77
[593]78#if GIET_DEBUG_IOC
[709]79unsigned int procid  = _get_procid();
80unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
81unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH) - 1);
82unsigned int p       = procid & ((1<<P_WIDTH)-1);
[593]83if ( _get_proctime() > GIET_DEBUG_IOC )
[529]84_printf("\n[BDV DEBUG] P[%d,%d,%d] enters _bdv_access at cycle %d\n"
85        "  use_irq = %d / to_mem = %d / lba = %x / paddr = %l / count = %d\n",
86        x , y , p , _get_proctime() , use_irq , to_mem , lba , buf_paddr, count );
[283]87#endif
88
[529]89    // check buffer alignment
[593]90    if( buf_paddr & 0x3F )
[529]91    {
[593]92        _printf("\n[BDV ERROR] in _bdv_access() : buffer not cache ligne aligned\n");
[529]93        return -1;
94    }
[283]95
[529]96    unsigned int error;
97    unsigned int status;
98
[709]99    // get the BDV lock and register it in task context
100    static_scheduler_t*  psched = _get_sched();
101    unsigned int         ltid   = _get_thread_ltid();
[469]102    _spin_lock_acquire( &_bdv_lock );
[709]103    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_BDV ); 
[283]104
[295]105    // set device registers
106    _bdv_set_register( BLOCK_DEVICE_BUFFER    , (unsigned int)buf_paddr );
107    _bdv_set_register( BLOCK_DEVICE_BUFFER_EXT, (unsigned int)(buf_paddr>>32) );
108    _bdv_set_register( BLOCK_DEVICE_COUNT     , count );
109    _bdv_set_register( BLOCK_DEVICE_LBA       , lba );
[283]110
[545]111#if USE_IOB    // software L2/L3 cache coherence
112    if ( to_mem )  _mmc_inval( buf_paddr, count<<9 );
113    else           _mmc_sync( buf_paddr, count<<9 );
114#endif     // end software L2/L3 cache coherence
115
[529]116    /////////////////////////////////////////////////////////////////////
117    // In synchronous mode, we launch transfer,
118    // and poll the BDV_STATUS register until completion.
119    /////////////////////////////////////////////////////////////////////
120    if ( use_irq == 0 ) 
[283]121    {
122        // Launch transfert
[295]123        if (to_mem == 0) _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_WRITE );
124        else             _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_READ );
[283]125
[593]126#if GIET_DEBUG_IOC
127if ( _get_proctime() > GIET_DEBUG_IOC )
[529]128_printf("\n[BDV DEBUG] _bdv_access() : P[%d,%d,%d] launch transfer"
129        " in polling mode at cycle %d\n",
130        x , y , p , _get_proctime() );
[333]131#endif
[529]132
[289]133        do
[283]134        {
[295]135            status = _bdv_get_register( BLOCK_DEVICE_STATUS );
[283]136
[593]137#if GIET_DEBUG_IOC
138if ( _get_proctime() > GIET_DEBUG_IOC )
[529]139_printf("\n[BDV DEBUG] _bdv_access() : P[%d,%d,%d] wait on BDV_STATUS ...\n",
140        x , y , p );
[283]141#endif
[289]142        }
143        while( (status != BLOCK_DEVICE_READ_SUCCESS)  &&
144               (status != BLOCK_DEVICE_READ_ERROR)    &&
145               (status != BLOCK_DEVICE_WRITE_SUCCESS) &&
[295]146               (status != BLOCK_DEVICE_WRITE_ERROR)   );      // busy waiting
[283]147
148        // analyse status
149        error = ( (status == BLOCK_DEVICE_READ_ERROR) ||
150                  (status == BLOCK_DEVICE_WRITE_ERROR) );
[529]151    }
[283]152
[529]153    /////////////////////////////////////////////////////////////////
[709]154    // in descheduling mode, we deschedule the thread
155    // and use an interrupt to reschedule the thread.
[295]156    // We need a critical section, because we must reset the RUN bit
[529]157        // before to launch the transfer, and we don't want to be
158    // descheduled between these two operations.
159    /////////////////////////////////////////////////////////////////
[295]160    else
[283]161    {
[295]162        unsigned int save_sr;
[283]163
[529]164        // activates BDV interrupt
[295]165        _bdv_set_register( BLOCK_DEVICE_IRQ_ENABLE, 1 );
166
[709]167        // set _bdv_trdid
168        _bdv_trdid = _get_thread_trdid();
[545]169
[295]170        // enters critical section
171        _it_disable( &save_sr ); 
[320]172
[630]173        // Set NORUN_MASK_IOC bit
[709]174        static_scheduler_t* psched  = (static_scheduler_t*)_get_sched();
175        unsigned int ltid = psched->current;
176        _atomic_or( &psched->context[ltid].slot[CTX_NORUN_ID] , NORUN_MASK_IOC );
[283]177       
[295]178        // launch transfer
179        if (to_mem == 0) _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_WRITE );
180        else             _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_READ  );
[283]181
[593]182#if GIET_DEBUG_IOC
183if ( _get_proctime() > GIET_DEBUG_IOC )
[529]184_printf("\n[BDV DEBUG] _bdv_access() : P[%d,%d,%d] launch transfer"
185        " in descheduling mode at cycle %d\n",
186        x , y , p , _get_proctime() );
[333]187#endif
[437]188
[709]189        // deschedule thread
[283]190        _ctx_switch();                     
191
[593]192#if GIET_DEBUG_IOC
193if ( _get_proctime() > GIET_DEBUG_IOC )
[529]194_printf("\n[BDV DEBUG] _bdv_access() : P[%d,%d,%d] resume execution at cycle %d\n",
195        x , y , p , _get_proctime() );
[426]196#endif
[529]197
[295]198        // restore SR
199        _it_restore( &save_sr );
200
[283]201        // analyse status
[295]202        error = ( (_bdv_status == BLOCK_DEVICE_READ_ERROR) ||
203                  (_bdv_status == BLOCK_DEVICE_WRITE_ERROR) );
[283]204    }
205
[709]206    // release BDV lock and clear task context
[529]207    _spin_lock_release( &_bdv_lock );     
[709]208    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_BDV ); 
[529]209
[593]210#if GIET_DEBUG_IOC
211if ( _get_proctime() > GIET_DEBUG_IOC )
[529]212_printf("\n[BDV DEBUG] _bdv_access() : P[%d,%d,%d] exit at cycle %d\n",
213        x , y , p , _get_proctime() );
[283]214#endif
215
216    return error;
217} // end _bdv_access()
218
[437]219////////////////////////
[295]220unsigned int _bdv_init()
[283]221{
[295]222    if ( _bdv_get_register( BLOCK_DEVICE_BLOCK_SIZE ) != 512 )
[283]223    {
[437]224        _puts("\n[GIET ERROR] in _bdv_init() : block size must be 512 bytes\n");
[283]225        return 1; 
226    }
227
[295]228    _bdv_set_register( BLOCK_DEVICE_IRQ_ENABLE, 0 );
[283]229    return 0;
230}
231
[437]232/////////////////////////////////////
[295]233void _bdv_isr( unsigned int irq_type,   // HWI / WTI
234               unsigned int irq_id,     // index returned by ICU
235               unsigned int channel )   // unused
236{
[529]237    // get BDV status and reset BDV_IRQ
[297]238    unsigned int status =  _bdv_get_register( BLOCK_DEVICE_STATUS ); 
[295]239
[297]240    // check status: does nothing if IDLE or BUSY
241    if ( (status == BLOCK_DEVICE_IDLE) ||
242         (status == BLOCK_DEVICE_BUSY) )   return;
243 
[529]244    // register status in global variable
245    _bdv_status = status;
[295]246
[709]247    // identify thread waiting on BDV
248    unsigned int x       = (_bdv_trdid >> 24) & 0xFF;
249    unsigned int y       = (_bdv_trdid >> 16) & 0xFF;
250    unsigned int p       = (_bdv_trdid >>  8) & 0xFF;
251    unsigned int ltid    = (_bdv_trdid      ) & 0xFF;
[295]252
[630]253    // Reset NORUN_MASK_IOC bit
254    static_scheduler_t* psched  = (static_scheduler_t*)_schedulers[x][y][p];
[709]255    unsigned int*       ptr     = &psched->context[ltid].slot[CTX_NORUN_ID];
[630]256    _atomic_and( ptr , ~NORUN_MASK_IOC );
[297]257
[709]258    // send a WAKUP WTI to processor running the sleeping thread
259    _xcu_send_wti( (x<<Y_WIDTH) + y,
[630]260                   p, 
[529]261                   0 );          // don't force context switch
[297]262
[593]263#if GIET_DEBUG_IOC 
[630]264unsigned int pid  = _get_procid();
265unsigned int c_x  = pid >> (Y_WIDTH + P_WIDTH);
266unsigned int c_y  = (pid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
267unsigned int c_p  = pid & ((1<<P_WIDTH)-1);
[593]268if ( _get_proctime() > GIET_DEBUG_IOC )
[563]269_printf("\n[BDV DEBUG] Processor[%d,%d,%d] enters _bdv_isr() at cycle %d\n"
[709]270        "  for thread %d running on P[%d,%d,%d] / bdv_status = %x\n",
[630]271        c_x , c_y , c_p , _get_proctime() ,
272        ltid , x , y , p , status );
[295]273#endif
274
[529]275} // end bdv_isr()
[295]276
277
[283]278// Local Variables:
279// tab-width: 4
280// c-basic-offset: 4
281// c-file-offsets:((innamespace . 0)(inline-open . 0))
282// indent-tabs-mode: nil
283// End:
284// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
285
Note: See TracBrowser for help on using the repository browser.