source: soft/giet_vm/giet_drivers/bdv_driver.c

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