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

Last change on this file since 539 was 529, checked in by alain, 10 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.