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

Last change on this file since 538 was 529, checked in by alain, 9 years ago

1) Removing the IOC driver (integrated in the FAT library).
2) Simplifying the BDV, HBA, SDC, RDK drivers: they support
only two modes (synchronous => polling / descheduling => IRQ),
and only one access function (for both read/write).

File size: 9.4 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>
[529]17#include <kernel_locks.h>
[283]18#include <utils.h>
[456]19#include <tty0.h>
[283]20#include <ctx_handler.h>
[529]21#include <irq_handler.h>
[283]22
23///////////////////////////////////////////////////////////////////////////////
[529]24//      Global variables
[295]25///////////////////////////////////////////////////////////////////////////////
26
[529]27// lock protecting single channel BDV peripheral
[496]28__attribute__((section(".kdata")))
[456]29spin_lock_t  _bdv_lock __attribute__((aligned(64)));
[496]30
[529]31// global index of the waiting task (only used in descheduling mode)
[496]32__attribute__((section(".kdata")))
[529]33unsigned int _bdv_gtid;
[496]34
[529]35// BDV peripheral status (only used in descheduling mode)
[496]36__attribute__((section(".kdata")))
[529]37unsigned int _bdv_status;
[295]38
39///////////////////////////////////////////////////////////////////////////////
40// This low_level function returns the value contained in register (index).
41///////////////////////////////////////////////////////////////////////////////
42unsigned int _bdv_get_register( unsigned int index )
43{
[320]44    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index;
[295]45    return _io_extended_read( vaddr );
46}
47
48///////////////////////////////////////////////////////////////////////////////
49// This low-level function set a new value in register (index).
50///////////////////////////////////////////////////////////////////////////////
51void _bdv_set_register( unsigned int index,
52                        unsigned int value ) 
53{
[320]54    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index;
[295]55    _io_extended_write( vaddr, value );
56}
57
58///////////////////////////////////////////////////////////////////////////////
[529]59//      Extern functions
[283]60///////////////////////////////////////////////////////////////////////////////
[529]61
62/////////////////////////////////////////////////////
63unsigned int _bdv_access( unsigned int       use_irq,
64                          unsigned int       to_mem,
65                          unsigned int       lba,
66                          unsigned long long buf_paddr,
67                          unsigned int       count) 
[283]68{
[426]69    unsigned int procid  = _get_procid();
70    unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
71    unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH) - 1);
72    unsigned int p       = procid & ((1<<P_WIDTH)-1);
[283]73
[313]74#if GIET_DEBUG_IOC_DRIVER
[529]75_printf("\n[BDV DEBUG] P[%d,%d,%d] enters _bdv_access at cycle %d\n"
76        "  use_irq = %d / to_mem = %d / lba = %x / paddr = %l / count = %d\n",
77        x , y , p , _get_proctime() , use_irq , to_mem , lba , buf_paddr, count );
[283]78#endif
79
[529]80    // check buffer alignment
81    if( buf_paddr & 0x1FF )
82    {
83        _printf("\n[BDV ERROR] in _bdv_access() : buffer not block aligned\n");
84        return -1;
85    }
[283]86
[529]87    unsigned int error;
88    unsigned int status;
89
[295]90    // get the lock protecting BDV
[469]91    _spin_lock_acquire( &_bdv_lock );
[283]92
[295]93    // set device registers
94    _bdv_set_register( BLOCK_DEVICE_BUFFER    , (unsigned int)buf_paddr );
95    _bdv_set_register( BLOCK_DEVICE_BUFFER_EXT, (unsigned int)(buf_paddr>>32) );
96    _bdv_set_register( BLOCK_DEVICE_COUNT     , count );
97    _bdv_set_register( BLOCK_DEVICE_LBA       , lba );
[283]98
[529]99    /////////////////////////////////////////////////////////////////////
100    // In synchronous mode, we launch transfer,
101    // and poll the BDV_STATUS register until completion.
102    /////////////////////////////////////////////////////////////////////
103    if ( use_irq == 0 ) 
[283]104    {
105        // Launch transfert
[295]106        if (to_mem == 0) _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_WRITE );
107        else             _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_READ );
[283]108
[333]109#if GIET_DEBUG_IOC_DRIVER
[529]110_printf("\n[BDV DEBUG] _bdv_access() : P[%d,%d,%d] launch transfer"
111        " in polling mode at cycle %d\n",
112        x , y , p , _get_proctime() );
[333]113#endif
[529]114
[289]115        do
[283]116        {
[295]117            status = _bdv_get_register( BLOCK_DEVICE_STATUS );
[283]118
[313]119#if GIET_DEBUG_IOC_DRIVER
[529]120_printf("\n[BDV DEBUG] _bdv_access() : P[%d,%d,%d] wait on BDV_STATUS ...\n",
121        x , y , p );
[283]122#endif
[289]123        }
124        while( (status != BLOCK_DEVICE_READ_SUCCESS)  &&
125               (status != BLOCK_DEVICE_READ_ERROR)    &&
126               (status != BLOCK_DEVICE_WRITE_SUCCESS) &&
[295]127               (status != BLOCK_DEVICE_WRITE_ERROR)   );      // busy waiting
[283]128
129        // analyse status
130        error = ( (status == BLOCK_DEVICE_READ_ERROR) ||
131                  (status == BLOCK_DEVICE_WRITE_ERROR) );
[529]132    }
[283]133
[529]134    /////////////////////////////////////////////////////////////////
135    // in descheduling mode, we deschedule the task
136    // and use an interrupt to reschedule the task.
[295]137    // We need a critical section, because we must reset the RUN bit
[529]138        // before to launch the transfer, and we don't want to be
139    // descheduled between these two operations.
140    /////////////////////////////////////////////////////////////////
[295]141    else
[283]142    {
[295]143        unsigned int save_sr;
[529]144        unsigned int wti_index;
[295]145        unsigned int ltid = _get_current_task_id();
[283]146
[529]147        // activates BDV interrupt
[295]148        _bdv_set_register( BLOCK_DEVICE_IRQ_ENABLE, 1 );
149
[529]150        // allocate a WTI mailbox to the calling proc if external IRQ
151        if ( USE_PIC ) _ext_irq_alloc( ISR_BDV , 0 , &wti_index );
[295]152
153        // enters critical section
154        _it_disable( &save_sr ); 
[320]155
[295]156        // set _bdv_gtid and reset runnable
[426]157        _bdv_gtid = (procid<<16) + ltid;
158        _set_task_slot( x, y, p, ltid, CTX_RUN_ID, 0 ); 
[283]159       
[295]160        // launch transfer
161        if (to_mem == 0) _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_WRITE );
162        else             _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_READ  );
[283]163
[333]164#if GIET_DEBUG_IOC_DRIVER
[529]165_printf("\n[BDV DEBUG] _bdv_access() : P[%d,%d,%d] launch transfer"
166        " in descheduling mode at cycle %d\n",
167        x , y , p , _get_proctime() );
[333]168#endif
[437]169
[283]170        // deschedule task
171        _ctx_switch();                     
172
[426]173#if GIET_DEBUG_IOC_DRIVER
[529]174_printf("\n[BDV DEBUG] _bdv_access() : P[%d,%d,%d] resume execution at cycle %d\n",
175        x , y , p , _get_proctime() );
[426]176#endif
[529]177
178        // release WTI mailbox if external IRQ
179        if ( USE_PIC ) _ext_irq_release( ISR_BDV , 0 , wti_index );
180
[295]181        // restore SR
182        _it_restore( &save_sr );
183
[283]184        // analyse status
[295]185        error = ( (_bdv_status == BLOCK_DEVICE_READ_ERROR) ||
186                  (_bdv_status == BLOCK_DEVICE_WRITE_ERROR) );
[283]187    }
188
[529]189    // release lock
190    _spin_lock_release( &_bdv_lock );     
191
[313]192#if GIET_DEBUG_IOC_DRIVER
[529]193_printf("\n[BDV DEBUG] _bdv_access() : P[%d,%d,%d] exit at cycle %d\n",
194        x , y , p , _get_proctime() );
[283]195#endif
196
197    return error;
198} // end _bdv_access()
199
[437]200////////////////////////
[295]201unsigned int _bdv_init()
[283]202{
[295]203    if ( _bdv_get_register( BLOCK_DEVICE_BLOCK_SIZE ) != 512 )
[283]204    {
[437]205        _puts("\n[GIET ERROR] in _bdv_init() : block size must be 512 bytes\n");
[283]206        return 1; 
207    }
208
[295]209    _bdv_set_register( BLOCK_DEVICE_IRQ_ENABLE, 0 );
[283]210    return 0;
211}
212
[437]213/////////////////////////////////////
[295]214void _bdv_isr( unsigned int irq_type,   // HWI / WTI
215               unsigned int irq_id,     // index returned by ICU
216               unsigned int channel )   // unused
217{
[529]218    // get BDV status and reset BDV_IRQ
[297]219    unsigned int status =  _bdv_get_register( BLOCK_DEVICE_STATUS ); 
[295]220
[297]221    // check status: does nothing if IDLE or BUSY
222    if ( (status == BLOCK_DEVICE_IDLE) ||
223         (status == BLOCK_DEVICE_BUSY) )   return;
224 
[529]225    // register status in global variable
226    _bdv_status = status;
[295]227
228    // identify task waiting on BDV
[426]229    unsigned int remote_procid  = _bdv_gtid>>16;
230    unsigned int ltid           = _bdv_gtid & 0xFFFF;
231    unsigned int remote_cluster = remote_procid >> P_WIDTH;
232    unsigned int remote_x       = remote_cluster >> Y_WIDTH;
233    unsigned int remote_y       = remote_cluster & ((1<<Y_WIDTH)-1);
234    unsigned int remote_p       = remote_procid & ((1<<P_WIDTH)-1);
[295]235
[297]236    // re-activates sleeping task
[426]237    _set_task_slot( remote_x,
238                    remote_y,
239                    remote_p,
240                    ltid,       
[297]241                    CTX_RUN_ID,  // CTX_RUN slot
[529]242                    1 );         // running value
[297]243
[529]244    // send a WAKUP WTI to processor running the sleeping task
[426]245    _xcu_send_wti( remote_cluster,   
246                   remote_p, 
[529]247                   0 );          // don't force context switch
[297]248
[529]249#if GIET_DEBUG_IOC_DRIVER 
[426]250unsigned int procid  = _get_procid();
251unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
252unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
253unsigned int p       = procid & ((1<<P_WIDTH)-1);
[529]254_printf("\n[IOC DEBUG] Processor[%d,%d,%d] enters _bdv_isr() at cycle %d\n"
255        "  for task %d running on P[%d,%d,%d] / bdv_status = %x\n",
256        x , y , p , _get_proctime() ,
257        ltid , remote_x , remote_y , remote_p , status );
[295]258#endif
259
[529]260} // end bdv_isr()
[295]261
262
[283]263// Local Variables:
264// tab-width: 4
265// c-basic-offset: 4
266// c-file-offsets:((innamespace . 0)(inline-open . 0))
267// indent-tabs-mode: nil
268// End:
269// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
270
Note: See TracBrowser for help on using the repository browser.