source: soft/giet_vm/giet_drivers/hba_driver.c @ 630

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

Update the peripheral drivers using descheduling,
to comply with the modified NORUN bit-vector in task context.

File size: 16.6 KB
Line 
1//////////////////////////////////////////////////////////////////////////////////
2// File     : hba_driver.c
3// Date     : 23/11/2013
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7// Implementation notes:
8// All accesses to HBA registers are done by the two
9// _hba_set_register() and _hba_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 <hba_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#include <vmem.h>
24
25//////////////////////////////////////////////////////////////////////////////////
26//      Extern variables
27//////////////////////////////////////////////////////////////////////////////////
28
29// allocated in the boot.c or kernel_init.c files
30extern static_scheduler_t* _schedulers[X_SIZE][Y_SIZE][NB_PROCS_MAX]; 
31
32//////////////////////////////////////////////////////////////////////////////////
33//               Global variables
34//////////////////////////////////////////////////////////////////////////////////
35// The global variable hba_boot_mode defines the way the HBA component is used
36// and must be defined in both kernel_init.c and boot.c files.
37// - during the boot phase, only one processor access the HBA in synchronous
38//   mode. There is no need for the allocator to use a lock.
39// - after the boot phase, the HBA device can be used by several processors. The
40//   allocator is protected by a sqt_lock.
41//////////////////////////////////////////////////////////////////////////////////
42       
43extern unsigned int _hba_boot_mode;
44
45__attribute__((section(".kdata")))
46sqt_lock_t          _hba_allocator_lock  __attribute__((aligned(64)));
47
48// state of each slot (allocated to a task or not)
49// access must be protected by the allocator_lock in descheduling mode
50__attribute__((section(".kdata")))
51unsigned int        _hba_allocated_cmd[32];
52
53// state of the command (active or not), for each possible slot
54// used only in descheduling mode
55__attribute__((section(".kdata")))
56unsigned int        _hba_active_cmd[32]; 
57
58// global index of the task, for each entry in the command list
59__attribute__((section(".kdata")))
60unsigned int        _hba_gtid[32];
61
62// status of HBA commands
63__attribute__((section(".kdata")))
64unsigned int        _hba_status;
65
66// command list : up to 32 commands
67__attribute__((section(".kdata")))
68hba_cmd_desc_t      _hba_cmd_list[32] __attribute__((aligned(0x40)));   
69
70// command tables array : one command table per entry in command list
71__attribute__((section(".kdata")))
72hba_cmd_table_t     _hba_cmd_table[32] __attribute__((aligned(0x40))); 
73
74
75//////////////////////////////////////////////////////////////////////////////
76// This low level function returns the value of register (index)
77//////////////////////////////////////////////////////////////////////////////
78unsigned int _hba_get_register( unsigned int index )
79{
80    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index;
81    return _io_extended_read( vaddr );
82}
83
84//////////////////////////////////////////////////////////////////////////////
85// This low level function set a new value in register (index) 
86//////////////////////////////////////////////////////////////////////////////
87void _hba_set_register( unsigned int index,
88                        unsigned int value )
89{
90    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index;
91    _io_extended_write( vaddr, value );
92}
93
94///////////////////////////////////////////////////////////////////////////////
95//      Extern functions
96///////////////////////////////////////////////////////////////////////////////
97
98///////////////////////////////////////////////////////////////////////////////
99// This blocking fonction allocates a free command index to the task.
100// The hba_allocator_lock is used except in boot mode.
101// It returns the allocated command index (between 0 and 31)
102///////////////////////////////////////////////////////////////////////////////
103unsigned int _hba_cmd_alloc()
104{
105    unsigned int found = 0;
106    unsigned int c;           // command index for the loop
107    unsigned int cmd_id = -1; // allocated command index when found
108
109    while ( found == 0)
110    {
111        if ( !_hba_boot_mode )
112            _sqt_lock_acquire(&_hba_allocator_lock);
113
114        for ( c = 0; c < 32 ; c++ )
115        {
116            if (_hba_allocated_cmd[c] == 0)
117            {
118                found = 1;
119                cmd_id = c;
120                _hba_allocated_cmd[c] = 1;
121                break;
122            }
123        }
124
125        if ( !_hba_boot_mode )
126            _sqt_lock_release(&_hba_allocator_lock);
127    }
128
129    return cmd_id;
130}
131
132///////////////////////////////////////////////////////////////////////////////
133// This function releases the command index in the hba_allocated_cmd table.
134// There is no need to take the lock because only the task which owns the
135// command can release it.
136// return 0 if success, -1 if error
137///////////////////////////////////////////////////////////////////////////////
138unsigned int _hba_cmd_release(unsigned int cmd_id)
139{
140    if ( _hba_allocated_cmd[cmd_id] == 0 )
141    {
142        _printf("\n[HBA ERROR] in _hba_access() : ask to release a command which is not allocated\n");
143        return -1;
144    }
145   
146    _hba_allocated_cmd[cmd_id] = 0;
147    return 0;
148}
149
150
151///////////////////////////////////////////////////////////////////////////////
152// This function gets a command index with the hba_cmd_alloc function. Then it
153// registers a command in both the command list and the command table. It
154// updates the HBA_PXCI register and the hba_active_cmd in descheduling mode.
155// At the end the command slot is released.
156// return 0 if success, -1 if error
157///////////////////////////////////////////////////////////////////////////////
158unsigned int _hba_access( unsigned int       use_irq,
159                          unsigned int       to_mem,
160                          unsigned int       lba, 
161                          unsigned long long buf_paddr,
162                          unsigned int       count )   
163{
164    unsigned int procid  = _get_procid();
165    unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
166    unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH) - 1);
167    unsigned int p       = procid & ((1<<P_WIDTH)-1);
168
169#if GIET_DEBUG_IOC
170if (_get_proctime() > GIET_DEBUG_IOC)
171_printf("\n[DEBUG HBA] _hba_access() : P[%d,%d,%d] enters at cycle %d\n"
172        "  use_irq = %d / to_mem = %d / lba = %x / paddr = %l / count = %d\n",
173        x , y , p , _get_proctime() , use_irq , to_mem , lba , buf_paddr, count );
174#endif
175
176    unsigned int       cmd_id;            // command index
177    unsigned int       pxci;              // HBA_PXCI register value
178    unsigned int       pxis;              // HBA_PXIS register value
179    hba_cmd_desc_t*    cmd_desc;          // command descriptor pointer   
180    hba_cmd_table_t*   cmd_table;         // command table pointer
181
182    // check buffer alignment
183    if( buf_paddr & 0x3F )
184    {
185        _printf("\n[HBA ERROR] in _hba_access() : buffer not 64 bytes aligned\n");
186        return -1;
187    }
188
189    // get one entry in Command List
190    cmd_id = _hba_cmd_alloc();
191
192    // compute pointers on command descriptor and command table   
193    cmd_desc  = &_hba_cmd_list[cmd_id];
194    cmd_table = &_hba_cmd_table[cmd_id];
195
196    // set  buffer descriptor in command table
197    cmd_table->buffer.dba  = (unsigned int)(buf_paddr);
198    cmd_table->buffer.dbau = (unsigned int)(buf_paddr >> 32);
199    cmd_table->buffer.dbc  = count * 512;
200
201    // initialize command table header
202    cmd_table->header.lba0 = (char)lba;
203    cmd_table->header.lba1 = (char)(lba>>8);
204    cmd_table->header.lba2 = (char)(lba>>16);
205    cmd_table->header.lba3 = (char)(lba>>24);
206    cmd_table->header.lba4 = 0;
207    cmd_table->header.lba5 = 0;
208
209    // initialise command descriptor
210    cmd_desc->prdtl[0] = 1;
211    cmd_desc->prdtl[1] = 0;
212    if( to_mem ) cmd_desc->flag[0] = 0x00;
213    else         cmd_desc->flag[0] = 0x40;     
214
215#if USE_IOB    // software L2/L3 cache coherence
216
217    // compute physical addresses
218    unsigned long long cmd_desc_paddr;    // command descriptor physical address
219    unsigned long long cmd_table_paddr;   // command table header physical address
220    unsigned int       flags;             // unused
221
222    if ( _get_mmu_mode() & 0x4 )
223    {
224        cmd_desc_paddr  = _v2p_translate( (unsigned int)cmd_desc  , &flags );
225        cmd_table_paddr = _v2p_translate( (unsigned int)cmd_table , &flags );
226    }
227    else
228    {
229        cmd_desc_paddr  = (unsigned int)cmd_desc;
230        cmd_table_paddr = (unsigned int)cmd_table;
231    }
232
233    // update external memory for command table
234    _mmc_sync( cmd_table_paddr & (~0x3F) , sizeof(hba_cmd_table_t) );
235
236    // update external memory for command descriptor
237    _mmc_sync( cmd_desc_paddr & (~0x3F) , sizeof(hba_cmd_desc_t) );
238
239    // inval or synchronize memory buffer
240    if ( to_mem )  _mmc_inval( buf_paddr, count<<9 );
241    else           _mmc_sync( buf_paddr, count<<9 );
242
243#endif     // end software L2/L3 cache coherence
244
245    /////////////////////////////////////////////////////////////////////
246    // In synchronous mode, we poll the PXCI register until completion
247    /////////////////////////////////////////////////////////////////////
248    if ( use_irq == 0 ) 
249    {
250        // start HBA transfer
251        _hba_set_register( HBA_PXCI, (1<<cmd_id) );
252
253#if GIET_DEBUG_IOC
254if (_get_proctime() > GIET_DEBUG_IOC)
255_printf("\n[DEBUG HBA] _hba_access() : P[%d,%d,%d] get slot %d in Cmd List "
256        " at cycle %d / polling\n",
257        x , y , p , cmd_id, _get_proctime() );
258#endif
259        // disable IRQs in PXIE register
260        _hba_set_register( HBA_PXIE , 0 );
261
262        // poll PXCI[cmd_id] until command completed by HBA
263        do
264        {
265            pxci = _hba_get_register( HBA_PXCI );
266
267#if GIET_DEBUG_IOC
268if (_get_proctime() > GIET_DEBUG_IOC)
269_printf("\n[DEBUG HBA] _hba_access() : P[%d,%d,%d] wait on HBA_PXCI / pxci = %x\n",
270        x , y , p , pxci );
271#endif
272        }
273        while( pxci & (1<<cmd_id) ); 
274             
275        // get PXIS register
276        pxis = _hba_get_register( HBA_PXIS );
277
278        // reset PXIS register
279        _hba_set_register( HBA_PXIS , 0 );
280    }
281
282    /////////////////////////////////////////////////////////////////
283    // in descheduling mode, we deschedule the task
284    // and use an interrupt to reschedule the task.
285    // We need a critical section, because we must set the NORUN bit
286        // before to launch the transfer, and we don't want to be
287    // descheduled between these two operations.
288    /////////////////////////////////////////////////////////////////
289    else
290    {
291
292#if GIET_DEBUG_IOC
293if (_get_proctime() > GIET_DEBUG_IOC)
294_printf("\n[DEBUG HBA] _hba_access() : P[%d,%d,%d] get slot %d in Cmd List "
295        "at cycle %d / descheduling\n",
296        x , y , p , cmd_id, _get_proctime() );
297#endif
298        unsigned int save_sr;
299        unsigned int ltid = _get_current_task_id();
300
301        // activates HBA interrupts
302        _hba_set_register( HBA_PXIE , 0x00000001 ); 
303
304        // set _hba_gtid[cmd_id]
305        _hba_gtid[cmd_id] = (procid<<16) + ltid;
306
307        // enters critical section
308        _it_disable( &save_sr ); 
309
310        // Set NORUN_MASK_IOC bit
311        static_scheduler_t* psched  = (static_scheduler_t*)_schedulers[x][y][p];
312        unsigned int*       ptr     = &psched->context[ltid][CTX_NORUN_ID];
313        _atomic_or( ptr , NORUN_MASK_IOC );
314     
315        // start HBA transfer
316        _hba_set_register( HBA_PXCI, (1<<cmd_id) );
317
318        // set _hba_active_cmd[cmd_id]
319        _hba_active_cmd[cmd_id] = 1;
320
321        // deschedule task
322        _ctx_switch();                     
323
324#if GIET_DEBUG_IOC
325if (_get_proctime() > GIET_DEBUG_IOC)
326_printf("\n[DEBUG HBA] _hba_access() : task %d on P[%d,%d,%d] resume at cycle %d\n",
327        ltid , x , y , p , _get_proctime() );
328#endif
329
330        // restore SR
331        _it_restore( &save_sr );
332
333        // get command status
334        pxis = _hba_status;
335    }
336   
337    // release the cmd index
338    unsigned int release_success;
339    release_success = _hba_cmd_release(cmd_id);
340
341#if GIET_DEBUG_IOC
342if (_get_proctime() > GIET_DEBUG_IOC)
343_printf("\n[DEBUG HBA] _hba_access() : P[%d,%d,%d] release slot %d in Cmd List "
344        "and exit at cycle %d\n",
345        x , y , p, cmd_id,
346        _get_proctime() );
347#endif
348
349    if ( release_success != 0 )   return -1;
350    else if ( pxis & 0x40000000 ) return pxis;
351    else                          return 0;
352
353} // end _hba_access()
354
355
356////////////////////////
357unsigned int _hba_init()
358{
359    unsigned int       cmd_list_vaddr;
360    unsigned int       cmd_table_vaddr;
361    unsigned long long cmd_list_paddr;
362    unsigned long long cmd_table_paddr;
363    unsigned int       flags;            // unused
364
365    // compute Command list & command table physical addresses
366    cmd_list_vaddr  = (unsigned int)(&_hba_cmd_list[0]);
367    cmd_table_vaddr = (unsigned int)(&_hba_cmd_table[0]);
368    if ( _get_mmu_mode() & 0x4 )
369    {
370        cmd_list_paddr  = _v2p_translate( cmd_list_vaddr  , &flags );
371        cmd_table_paddr = _v2p_translate( cmd_table_vaddr , &flags );
372    }
373    else
374    {
375        cmd_list_paddr  = (unsigned long long)cmd_list_vaddr;
376        cmd_table_paddr = (unsigned long long)cmd_table_vaddr;
377    }
378
379    // initialise allocator lock if not in boot mode
380    if ( !_hba_boot_mode )
381        _sqt_lock_init(&_hba_allocator_lock);
382
383    // initialise Command Descriptors in Command List, allocated command table
384    // and active command table
385    unsigned int         c;     
386    unsigned long long   paddr;
387    for( c=0 ; c<32 ; c++ )
388    {
389        paddr = cmd_table_paddr + c * sizeof(hba_cmd_table_t);
390        _hba_cmd_list[c].ctba  = (unsigned int)(paddr);
391        _hba_cmd_list[c].ctbau = (unsigned int)(paddr>>32);
392        _hba_allocated_cmd[c] = 0;
393        _hba_active_cmd[c] = 0;
394    }
395
396    // initialise HBA registers
397    _hba_set_register( HBA_PXCLB  , (unsigned int)(cmd_list_paddr) );
398    _hba_set_register( HBA_PXCLBU , (unsigned int)(cmd_list_paddr>>32) );
399    _hba_set_register( HBA_PXIE   , 0 );
400    _hba_set_register( HBA_PXIS   , 0 );
401    _hba_set_register( HBA_PXCI   , 0 );
402    _hba_set_register( HBA_PXCMD  , 1 );
403
404    return 0;
405}
406
407
408/////////////////////////////////////////////////////
409void _hba_isr( unsigned int irq_type,   // HWI / WTI
410               unsigned int irq_id,     // index returned by ICU
411               unsigned int channel )   // unused
412{
413    // save PXIS register if there is no previous error
414    if ( !(_hba_status & 0x40000000))
415        _hba_status = _hba_get_register( HBA_PXIS );
416
417    // reset PXIS register
418    _hba_set_register( HBA_PXIS , 0 );
419
420    unsigned int cmd_id;  // cmd index for the loops
421   
422    // save the current list of active cmd in a 32 bits word
423    unsigned int current_active_cmd = 0;
424    for ( cmd_id = 0 ; cmd_id < 32 ; cmd_id ++ )
425    {
426        if ( _hba_active_cmd[cmd_id] == 1 ) current_active_cmd += (1 << cmd_id);
427    }
428   
429    // get HBA_PXCI containing commands status
430    unsigned int current_pxci = _hba_get_register( HBA_PXCI );
431
432    for ( cmd_id = 0 ; cmd_id < 32 ; cmd_id ++ )
433    {
434        if ( ( (current_active_cmd & (1<<cmd_id)) != 0) && // active command
435             ( (current_pxci & (1<<cmd_id)) == 0 ) )       // completed command
436        {
437            // desactivate the command
438            _hba_active_cmd[cmd_id] = 0;
439
440            // identify waiting task
441            unsigned int procid  = _hba_gtid[cmd_id]>>16;
442            unsigned int ltid    = _hba_gtid[cmd_id] & 0xFFFF;
443            unsigned int cluster = procid >> P_WIDTH;
444            unsigned int x       = cluster >> Y_WIDTH;
445            unsigned int y       = cluster & ((1<<Y_WIDTH)-1);
446            unsigned int p       = procid & ((1<<P_WIDTH)-1);
447 
448            // Reset NORUN_MASK_IOC bit
449            static_scheduler_t* psched  = (static_scheduler_t*)_schedulers[x][y][p];
450            unsigned int*       ptr     = &psched->context[ltid][CTX_NORUN_ID];
451            _atomic_and( ptr , ~NORUN_MASK_IOC );
452
453            // send a WAKUP WTI to processor running the waiting task
454            _xcu_send_wti( cluster , 
455                           p , 
456                           0 );          // don't force context switch
457
458#if GIET_DEBUG_IOC 
459if (_get_proctime() > GIET_DEBUG_IOC)
460_printf("\n[DEBUG HBA] _hba_isr() : command %d completed at cycle %d\n"
461        "  resume task %d running on P[%d,%d,%d]\n",
462        cmd_id , _get_proctime() ,
463        ltid , x , y , p );
464#endif
465        }
466    }
467} // end _hba_isr()
468
469// Local Variables:
470// tab-width: 4
471// c-basic-offset: 4
472// c-file-offsets:((innamespace . 0)(inline-open . 0))
473// indent-tabs-mode: nil
474// End:
475// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
476
Note: See TracBrowser for help on using the repository browser.