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

Last change on this file since 476 was 469, checked in by alain, 10 years ago

The global variables associated to TTY channels are not anymore
defined in the tty_driver.c file, but in the boot.c and kernel_init.c files.

File size: 11.2 KB
RevLine 
[283]1///////////////////////////////////////////////////////////////////////////////////
[284]2// File      : bdv_driver.c
3// Date      : 23/05/2013
4// Author    : alain greiner
5// Maintainer: cesar fuguet
[283]6// Copyright (c) UPMC-LIP6
7///////////////////////////////////////////////////////////////////////////////////
[295]8// Implementation notes:
9// 1. In order to share code, the two _bdv_read() and _bdv_write() functions
10//    call the same _bdv_access() function.
11// 2. All accesses to BDV registers are done by the two
12//    _bdv_set_register() and _bdv_get_register() low-level functions,
13//    that are handling virtual / physical extended addressing.
[283]14///////////////////////////////////////////////////////////////////////////////////
15
16#include <giet_config.h>
[320]17#include <hard_config.h>
[295]18#include <bdv_driver.h>
19#include <xcu_driver.h>
[283]20#include <ioc_driver.h>
21#include <utils.h>
[456]22#include <tty0.h>
[283]23#include <ctx_handler.h>
24
25///////////////////////////////////////////////////////////////////////////////
[295]26// BDV global variables
27///////////////////////////////////////////////////////////////////////////////
28
[456]29spin_lock_t  _bdv_lock __attribute__((aligned(64)));
30unsigned int _bdv_status;
31unsigned int _bdv_gtid;
[295]32
33///////////////////////////////////////////////////////////////////////////////
34// This low_level function returns the value contained in register (index).
35///////////////////////////////////////////////////////////////////////////////
36unsigned int _bdv_get_register( unsigned int index )
37{
[320]38    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index;
[295]39    return _io_extended_read( vaddr );
40}
41
42///////////////////////////////////////////////////////////////////////////////
43// This low-level function set a new value in register (index).
44///////////////////////////////////////////////////////////////////////////////
45void _bdv_set_register( unsigned int index,
46                        unsigned int value ) 
47{
[320]48    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index;
[295]49    _io_extended_write( vaddr, value );
50}
51
52///////////////////////////////////////////////////////////////////////////////
[283]53// This function transfer data between a memory buffer and the block device.
54// The buffer lentgth is (count*block_size) bytes.
55// Arguments are:
56// - to_mem     : from external storage to memory when non 0.
[289]57// - mode       : BOOT / KERNEL / USER
[283]58// - lba        : first block index on the external storage.
[289]59// - buf_paddr  : physical base address of the memory buffer.
[283]60// - count      : number of blocks to be transfered.
61// Returns 0 if success, > 0 if error.
62///////////////////////////////////////////////////////////////////////////////
[295]63static unsigned int _bdv_access( unsigned int       to_mem,
64                                 unsigned int       mode,
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
[437]75_puts("\n[BDV DEBUG] _bdv_access() : P[");
76_putd( x );
77_puts(",");
78_putd( y );
79_puts(",");
80_putd( p );
81_puts("] enters at cycle ");
82_putd( _get_proctime() );
83_puts("\n - to_mem  = ");
84_putd( to_mem );
85_puts("\n - mode    = ");
86_putd( mode );
87_puts("\n - paddr   = ");
88_putl( buf_paddr );
89_puts("\n - sectors = ");
90_putd( count );
91_puts("\n - lba     = ");
92_putx( lba );
93_puts("\n");
[283]94#endif
95
[295]96    unsigned int       error = 0;
[283]97
[295]98    // get the lock protecting BDV
[469]99    _spin_lock_acquire( &_bdv_lock );
[283]100
[426]101#if GIET_DEBUG_IOC_DRIVER
[437]102_puts("\n[BDV DEBUG] _bdv_access() : P[");
103_putd( x );
104_puts(",");
105_putd( y );
106_puts(",");
107_putd( p );
[456]108_puts("] get _bdv_lock at cycle ");
109_putd( _get_proctime() );
[437]110_puts("\n");
[426]111#endif
112
[295]113    // set device registers
114    _bdv_set_register( BLOCK_DEVICE_BUFFER    , (unsigned int)buf_paddr );
115    _bdv_set_register( BLOCK_DEVICE_BUFFER_EXT, (unsigned int)(buf_paddr>>32) );
116    _bdv_set_register( BLOCK_DEVICE_COUNT     , count );
117    _bdv_set_register( BLOCK_DEVICE_LBA       , lba );
[283]118
[295]119    // In BOOT mode, we launch transfer, and poll the BDV_STATUS
120    // register because IRQs are masked.
121    if ( mode == IOC_BOOT_MODE ) 
[283]122    {
123        // Launch transfert
[295]124        if (to_mem == 0) _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_WRITE );
125        else             _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_READ );
[283]126
[333]127#if GIET_DEBUG_IOC_DRIVER
[437]128_puts("\n[BDV DEBUG] _bdv_access() : P[");
129_putd( x );
130_puts(",");
131_putd( y );
132_puts(",");
133_putd( p );
134_puts("] launch transfer in polling mode\n");
[333]135#endif
[283]136        unsigned int status;
[289]137        do
[283]138        {
[295]139            status = _bdv_get_register( BLOCK_DEVICE_STATUS );
[283]140
[313]141#if GIET_DEBUG_IOC_DRIVER
[437]142_puts("\n[BDV DEBUG] _bdv_access() : P[");
143_putd( x );
144_puts(",");
145_putd( y );
146_puts(",");
147_putd( p );
148_puts("] wait on BDV_STATUS register ...\n");
[283]149#endif
[289]150        }
151        while( (status != BLOCK_DEVICE_READ_SUCCESS)  &&
152               (status != BLOCK_DEVICE_READ_ERROR)    &&
153               (status != BLOCK_DEVICE_WRITE_SUCCESS) &&
[295]154               (status != BLOCK_DEVICE_WRITE_ERROR)   );      // busy waiting
[283]155
156        // analyse status
157        error = ( (status == BLOCK_DEVICE_READ_ERROR) ||
158                  (status == BLOCK_DEVICE_WRITE_ERROR) );
159
160        // release lock
[469]161        _spin_lock_release( &_bdv_lock );     
[283]162    }
[295]163    // in USER or KERNEL mode, we deschedule the task.
164    // When the task is rescheduled, we check the _bdv_status variable,
165    // and release the lock.
166    // We need a critical section, because we must reset the RUN bit
167        // before to launch the transfer, and we don't want to be descheduled
168        // between these two operations.
169    else
[283]170    {
[295]171        unsigned int save_sr;
172        unsigned int ltid = _get_current_task_id();
[283]173
[295]174        // activates BDV interrupts
175        _bdv_set_register( BLOCK_DEVICE_IRQ_ENABLE, 1 );
176
177        // set the _bdv_status variable
178        _bdv_status = BLOCK_DEVICE_BUSY;
179
180        // enters critical section
181        _it_disable( &save_sr ); 
[320]182
[295]183        // set _bdv_gtid and reset runnable
[426]184        _bdv_gtid = (procid<<16) + ltid;
185        _set_task_slot( x, y, p, ltid, CTX_RUN_ID, 0 ); 
[283]186       
[295]187        // launch transfer
188        if (to_mem == 0) _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_WRITE );
189        else             _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_READ  );
[283]190
[333]191#if GIET_DEBUG_IOC_DRIVER
[437]192_puts("\n[BDV DEBUG] _bdv_access() : P[");
193_putd( x );
194_puts(",");
195_putd( y );
196_puts(",");
197_putd( p );
198_puts("] launch transfer in nterrupt mode\n");
[333]199#endif
[437]200
[283]201        // deschedule task
202        _ctx_switch();                     
203
[426]204#if GIET_DEBUG_IOC_DRIVER
[437]205_puts("\n[BDV DEBUG] _bdv_access() : P[");
206_putd( x );
207_puts(",");
208_putd( y );
209_puts(",");
210_putd( p );
211_puts("] resume execution after descheduling\n");
[426]212#endif
[295]213        // restore SR
214        _it_restore( &save_sr );
215
[283]216        // analyse status
[295]217        error = ( (_bdv_status == BLOCK_DEVICE_READ_ERROR) ||
218                  (_bdv_status == BLOCK_DEVICE_WRITE_ERROR) );
[283]219
[295]220        // reset _bdv_status and release lock
221        _bdv_status = BLOCK_DEVICE_IDLE; 
[469]222        _spin_lock_release( &_bdv_lock );     
[283]223    }
224
[313]225#if GIET_DEBUG_IOC_DRIVER
[437]226_puts("\n[BDV DEBUG] _bdv_access() : P[");
227_putd( x );
228_puts(",");
229_putd( y );
230_puts(",");
231_putd( p );
232_puts("] exit at cycle ");
233_putd( _get_proctime() );
234_puts(" / error = ");
[456]235_putd( error );
[437]236_puts("\n");
[283]237#endif
238
239    return error;
240} // end _bdv_access()
241
242///////////////////////////////////////////////////////////////////////////////
[437]243//      External functions
[283]244///////////////////////////////////////////////////////////////////////////////
[437]245
246////////////////////////
[295]247unsigned int _bdv_init()
[283]248{
[295]249    if ( _bdv_get_register( BLOCK_DEVICE_BLOCK_SIZE ) != 512 )
[283]250    {
[437]251        _puts("\n[GIET ERROR] in _bdv_init() : block size must be 512 bytes\n");
[283]252        return 1; 
253    }
254
[295]255    _bdv_set_register( BLOCK_DEVICE_IRQ_ENABLE, 0 );
[283]256    return 0;
257}
258
[437]259////////////////////////////////////////////////
[295]260unsigned int _bdv_read( unsigned int       mode, 
261                        unsigned int       lba, 
262                        unsigned long long buffer, 
263                        unsigned int       count) 
[283]264{
265    return _bdv_access( 1,        // read access
266                        mode, 
267                        lba,
268                        buffer,
269                        count );
270}
271
[437]272/////////////////////////////////////////////////
[295]273unsigned int _bdv_write( unsigned int       mode, 
274                         unsigned int       lba, 
275                         unsigned long long buffer, 
276                         unsigned int       count ) 
[283]277{
278    return _bdv_access( 0,        // write access
279                        mode, 
280                        lba,
281                        buffer,
282                        count );
283}
284
[437]285//////////////////////////////
[295]286unsigned int _bdv_get_status()
[283]287{
[295]288    return _bdv_get_register( BLOCK_DEVICE_STATUS );
[283]289}
290
[437]291//////////////////////////////////
[295]292unsigned int _bdv_get_block_size()
[283]293{
[295]294    return _bdv_get_register( BLOCK_DEVICE_BLOCK_SIZE );
[283]295}
296
[437]297/////////////////////////////////////
[295]298void _bdv_isr( unsigned int irq_type,   // HWI / WTI
299               unsigned int irq_id,     // index returned by ICU
300               unsigned int channel )   // unused
301{
[297]302    // get BDV status (and reset IRQ)
303    unsigned int status =  _bdv_get_register( BLOCK_DEVICE_STATUS ); 
[295]304
[297]305    // check status: does nothing if IDLE or BUSY
306    if ( (status == BLOCK_DEVICE_IDLE) ||
307         (status == BLOCK_DEVICE_BUSY) )   return;
308 
309    // save status in kernel buffer _bdv_status
310    _bdv_status = status; 
[295]311
312    // identify task waiting on BDV
[426]313    unsigned int remote_procid  = _bdv_gtid>>16;
314    unsigned int ltid           = _bdv_gtid & 0xFFFF;
315    unsigned int remote_cluster = remote_procid >> P_WIDTH;
316    unsigned int remote_x       = remote_cluster >> Y_WIDTH;
317    unsigned int remote_y       = remote_cluster & ((1<<Y_WIDTH)-1);
318    unsigned int remote_p       = remote_procid & ((1<<P_WIDTH)-1);
[295]319
[297]320    // re-activates sleeping task
[426]321    _set_task_slot( remote_x,
322                    remote_y,
323                    remote_p,
324                    ltid,       
[297]325                    CTX_RUN_ID,  // CTX_RUN slot
326                    1 );         // running
327
328    // requires a context switch for remote processor running the waiting task
[426]329    _xcu_send_wti( remote_cluster,   
330                   remote_p, 
[297]331                   0 );          // don't force context switch if not idle
332
[295]333#if GIET_DEBUG_IRQS  // we don't take the TTY lock to avoid deadlock
[426]334unsigned int procid  = _get_procid();
335unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
336unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
337unsigned int p       = procid & ((1<<P_WIDTH)-1);
338
[295]339_puts("\n[IRQS DEBUG] Processor[");
340_putd(x );
341_puts(",");
342_putd(y );
343_puts(",");
[426]344_putd(p );
[295]345_puts("] enters _bdv_isr() at cycle ");
346_putd(_get_proctime() );
347_puts("\n  for task ");
348_putd(ltid );
349_puts(" running on processor[");
[426]350_putd(remote_x );
[295]351_puts(",");
[426]352_putd(remore_y );
[295]353_puts(",");
[426]354_putd(remote_p );
[295]355_puts(" / bdv status = ");
356_putx(_bdv_status );
357_puts("\n");
358#endif
359
360}
361
362
[283]363// Local Variables:
364// tab-width: 4
365// c-basic-offset: 4
366// c-file-offsets:((innamespace . 0)(inline-open . 0))
367// indent-tabs-mode: nil
368// End:
369// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
370
Note: See TracBrowser for help on using the repository browser.