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

Last change on this file since 478 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
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File      : bdv_driver.c
3// Date      : 23/05/2013
4// Author    : alain greiner
5// Maintainer: cesar fuguet
6// Copyright (c) UPMC-LIP6
7///////////////////////////////////////////////////////////////////////////////////
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.
14///////////////////////////////////////////////////////////////////////////////////
15
16#include <giet_config.h>
17#include <hard_config.h>
18#include <bdv_driver.h>
19#include <xcu_driver.h>
20#include <ioc_driver.h>
21#include <utils.h>
22#include <tty0.h>
23#include <ctx_handler.h>
24
25///////////////////////////////////////////////////////////////////////////////
26// BDV global variables
27///////////////////////////////////////////////////////////////////////////////
28
29spin_lock_t  _bdv_lock __attribute__((aligned(64)));
30unsigned int _bdv_status;
31unsigned int _bdv_gtid;
32
33///////////////////////////////////////////////////////////////////////////////
34// This low_level function returns the value contained in register (index).
35///////////////////////////////////////////////////////////////////////////////
36unsigned int _bdv_get_register( unsigned int index )
37{
38    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index;
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{
48    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index;
49    _io_extended_write( vaddr, value );
50}
51
52///////////////////////////////////////////////////////////////////////////////
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.
57// - mode       : BOOT / KERNEL / USER
58// - lba        : first block index on the external storage.
59// - buf_paddr  : physical base address of the memory buffer.
60// - count      : number of blocks to be transfered.
61// Returns 0 if success, > 0 if error.
62///////////////////////////////////////////////////////////////////////////////
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) 
68{
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);
73
74#if GIET_DEBUG_IOC_DRIVER
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");
94#endif
95
96    unsigned int       error = 0;
97
98    // get the lock protecting BDV
99    _spin_lock_acquire( &_bdv_lock );
100
101#if GIET_DEBUG_IOC_DRIVER
102_puts("\n[BDV DEBUG] _bdv_access() : P[");
103_putd( x );
104_puts(",");
105_putd( y );
106_puts(",");
107_putd( p );
108_puts("] get _bdv_lock at cycle ");
109_putd( _get_proctime() );
110_puts("\n");
111#endif
112
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 );
118
119    // In BOOT mode, we launch transfer, and poll the BDV_STATUS
120    // register because IRQs are masked.
121    if ( mode == IOC_BOOT_MODE ) 
122    {
123        // Launch transfert
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 );
126
127#if GIET_DEBUG_IOC_DRIVER
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");
135#endif
136        unsigned int status;
137        do
138        {
139            status = _bdv_get_register( BLOCK_DEVICE_STATUS );
140
141#if GIET_DEBUG_IOC_DRIVER
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");
149#endif
150        }
151        while( (status != BLOCK_DEVICE_READ_SUCCESS)  &&
152               (status != BLOCK_DEVICE_READ_ERROR)    &&
153               (status != BLOCK_DEVICE_WRITE_SUCCESS) &&
154               (status != BLOCK_DEVICE_WRITE_ERROR)   );      // busy waiting
155
156        // analyse status
157        error = ( (status == BLOCK_DEVICE_READ_ERROR) ||
158                  (status == BLOCK_DEVICE_WRITE_ERROR) );
159
160        // release lock
161        _spin_lock_release( &_bdv_lock );     
162    }
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
170    {
171        unsigned int save_sr;
172        unsigned int ltid = _get_current_task_id();
173
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 ); 
182
183        // set _bdv_gtid and reset runnable
184        _bdv_gtid = (procid<<16) + ltid;
185        _set_task_slot( x, y, p, ltid, CTX_RUN_ID, 0 ); 
186       
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  );
190
191#if GIET_DEBUG_IOC_DRIVER
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");
199#endif
200
201        // deschedule task
202        _ctx_switch();                     
203
204#if GIET_DEBUG_IOC_DRIVER
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");
212#endif
213        // restore SR
214        _it_restore( &save_sr );
215
216        // analyse status
217        error = ( (_bdv_status == BLOCK_DEVICE_READ_ERROR) ||
218                  (_bdv_status == BLOCK_DEVICE_WRITE_ERROR) );
219
220        // reset _bdv_status and release lock
221        _bdv_status = BLOCK_DEVICE_IDLE; 
222        _spin_lock_release( &_bdv_lock );     
223    }
224
225#if GIET_DEBUG_IOC_DRIVER
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 = ");
235_putd( error );
236_puts("\n");
237#endif
238
239    return error;
240} // end _bdv_access()
241
242///////////////////////////////////////////////////////////////////////////////
243//      External functions
244///////////////////////////////////////////////////////////////////////////////
245
246////////////////////////
247unsigned int _bdv_init()
248{
249    if ( _bdv_get_register( BLOCK_DEVICE_BLOCK_SIZE ) != 512 )
250    {
251        _puts("\n[GIET ERROR] in _bdv_init() : block size must be 512 bytes\n");
252        return 1; 
253    }
254
255    _bdv_set_register( BLOCK_DEVICE_IRQ_ENABLE, 0 );
256    return 0;
257}
258
259////////////////////////////////////////////////
260unsigned int _bdv_read( unsigned int       mode, 
261                        unsigned int       lba, 
262                        unsigned long long buffer, 
263                        unsigned int       count) 
264{
265    return _bdv_access( 1,        // read access
266                        mode, 
267                        lba,
268                        buffer,
269                        count );
270}
271
272/////////////////////////////////////////////////
273unsigned int _bdv_write( unsigned int       mode, 
274                         unsigned int       lba, 
275                         unsigned long long buffer, 
276                         unsigned int       count ) 
277{
278    return _bdv_access( 0,        // write access
279                        mode, 
280                        lba,
281                        buffer,
282                        count );
283}
284
285//////////////////////////////
286unsigned int _bdv_get_status()
287{
288    return _bdv_get_register( BLOCK_DEVICE_STATUS );
289}
290
291//////////////////////////////////
292unsigned int _bdv_get_block_size()
293{
294    return _bdv_get_register( BLOCK_DEVICE_BLOCK_SIZE );
295}
296
297/////////////////////////////////////
298void _bdv_isr( unsigned int irq_type,   // HWI / WTI
299               unsigned int irq_id,     // index returned by ICU
300               unsigned int channel )   // unused
301{
302    // get BDV status (and reset IRQ)
303    unsigned int status =  _bdv_get_register( BLOCK_DEVICE_STATUS ); 
304
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; 
311
312    // identify task waiting on BDV
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);
319
320    // re-activates sleeping task
321    _set_task_slot( remote_x,
322                    remote_y,
323                    remote_p,
324                    ltid,       
325                    CTX_RUN_ID,  // CTX_RUN slot
326                    1 );         // running
327
328    // requires a context switch for remote processor running the waiting task
329    _xcu_send_wti( remote_cluster,   
330                   remote_p, 
331                   0 );          // don't force context switch if not idle
332
333#if GIET_DEBUG_IRQS  // we don't take the TTY lock to avoid deadlock
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
339_puts("\n[IRQS DEBUG] Processor[");
340_putd(x );
341_puts(",");
342_putd(y );
343_puts(",");
344_putd(p );
345_puts("] enters _bdv_isr() at cycle ");
346_putd(_get_proctime() );
347_puts("\n  for task ");
348_putd(ltid );
349_puts(" running on processor[");
350_putd(remote_x );
351_puts(",");
352_putd(remore_y );
353_puts(",");
354_putd(remote_p );
355_puts(" / bdv status = ");
356_putx(_bdv_status );
357_puts("\n");
358#endif
359
360}
361
362
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.