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

Last change on this file since 593 was 576, checked in by bellefin, 10 years ago

Improve hba driver : introduce the tables _hba_active_cmd and _hba_allocated_cmd, and a cmd allocator function which uses a lock (in descheduling mode) to get a free cmd index between 0 and 31

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