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

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

cosmetic

File size: 16.4 KB
RevLine 
[529]1//////////////////////////////////////////////////////////////////////////////////
[258]2// File     : hba_driver.c
3// Date     : 23/11/2013
[295]4// Author   : alain greiner
[258]5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
[295]7// Implementation notes:
[529]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.
[258]11///////////////////////////////////////////////////////////////////////////////////
12
13#include <giet_config.h>
[529]14#include <hard_config.h>
15#include <hba_driver.h>
16#include <xcu_driver.h>
[545]17#include <mmc_driver.h>
[529]18#include <kernel_locks.h>
[258]19#include <utils.h>
[456]20#include <tty0.h>
[258]21#include <ctx_handler.h>
[529]22#include <irq_handler.h>
[258]23#include <vmem.h>
24
[529]25///////////////////////////////////////////////////////////////////////////////////
26//               Global variables
27///////////////////////////////////////////////////////////////////////////////////
[258]28
[576]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
[529]40__attribute__((section(".kdata")))
[576]41sqt_lock_t          _hba_allocator_lock  __attribute__((aligned(64)));
[258]42
[576]43// state of each slot (allocated to a task or not)
44// access must be protected by the allocator_lock in descheduling mode
[529]45__attribute__((section(".kdata")))
[576]46unsigned int        _hba_allocated_cmd[32];
[258]47
[576]48// state of the command (active or not), for each possible slot
49// used only in descheduling mode
[529]50__attribute__((section(".kdata")))
[576]51unsigned int        _hba_active_cmd[32]; 
[258]52
[576]53// global index of the task, for each entry in the command list
[529]54__attribute__((section(".kdata")))
[576]55unsigned int        _hba_gtid[32];
[258]56
[576]57// status of HBA commands
[529]58__attribute__((section(".kdata")))
[576]59unsigned int        _hba_status;
[258]60
[576]61// command list : up to 32 commands
[529]62__attribute__((section(".kdata")))
[576]63hba_cmd_desc_t      _hba_cmd_list[32] __attribute__((aligned(0x40)));   
[258]64
[576]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
[295]70//////////////////////////////////////////////////////////////////////////////
[529]71// This low level function returns the value of register (index)
[295]72//////////////////////////////////////////////////////////////////////////////
[529]73unsigned int _hba_get_register( unsigned int index )
[258]74{
[529]75    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index;
[295]76    return _io_extended_read( vaddr );
77}
[258]78
[295]79//////////////////////////////////////////////////////////////////////////////
[529]80// This low level function set a new value in register (index) 
[295]81//////////////////////////////////////////////////////////////////////////////
[529]82void _hba_set_register( unsigned int index,
[295]83                        unsigned int value )
84{
[529]85    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index;
[295]86    _io_extended_write( vaddr, value );
[258]87}
88
[529]89///////////////////////////////////////////////////////////////////////////////
90//      Extern functions
91///////////////////////////////////////////////////////////////////////////////
[295]92
[258]93///////////////////////////////////////////////////////////////////////////////
[576]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.
[437]131// return 0 if success, -1 if error
[258]132///////////////////////////////////////////////////////////////////////////////
[576]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///////////////////////////////////////////////////////////////////////////////
[529]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 )   
[258]158{
[529]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);
[295]163
[603]164#if GIET_DEBUG_IOC
165if (_get_proctime() > GIET_DEBUG_IOC)
[545]166_printf("\n[DEBUG HBA] _hba_access() : P[%d,%d,%d] enters at cycle %d\n"
[529]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
[576]171    unsigned int       cmd_id;            // command index
[545]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
[258]176
177    // check buffer alignment
[545]178    if( buf_paddr & 0x3F )
[258]179    {
[545]180        _printf("\n[HBA ERROR] in _hba_access() : buffer not 64 bytes aligned\n");
[437]181        return -1;
[258]182    }
183
[545]184    // get one entry in Command List
[576]185    cmd_id = _hba_cmd_alloc();
[258]186
187    // compute pointers on command descriptor and command table   
[576]188    cmd_desc  = &_hba_cmd_list[cmd_id];
189    cmd_table = &_hba_cmd_table[cmd_id];
[258]190
[295]191    // set  buffer descriptor in command table
[540]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;
[295]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;
[529]207    if( to_mem ) cmd_desc->flag[0] = 0x00;
208    else         cmd_desc->flag[0] = 0x40;     
[295]209
[545]210#if USE_IOB    // software L2/L3 cache coherence
[295]211
[545]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
[529]240    /////////////////////////////////////////////////////////////////////
241    // In synchronous mode, we poll the PXCI register until completion
242    /////////////////////////////////////////////////////////////////////
243    if ( use_irq == 0 ) 
244    {
[545]245        // start HBA transfer
[576]246        _hba_set_register( HBA_PXCI, (1<<cmd_id) );
[295]247
[603]248#if GIET_DEBUG_IOC
249if (_get_proctime() > GIET_DEBUG_IOC)
[563]250_printf("\n[DEBUG HBA] _hba_access() : P[%d,%d,%d] get slot %d in Cmd List "
[545]251        " at cycle %d / polling\n",
[576]252        x , y , p , cmd_id, _get_proctime() );
[529]253#endif
254        // disable IRQs in PXIE register
255        _hba_set_register( HBA_PXIE , 0 );
[295]256
[576]257        // poll PXCI[cmd_id] until command completed by HBA
[529]258        do
259        {
[545]260            pxci = _hba_get_register( HBA_PXCI );
[258]261
[603]262#if GIET_DEBUG_IOC
263if (_get_proctime() > GIET_DEBUG_IOC)
[545]264_printf("\n[DEBUG HBA] _hba_access() : P[%d,%d,%d] wait on HBA_PXCI / pxci = %x\n",
265        x , y , p , pxci );
[529]266#endif
267        }
[576]268        while( pxci & (1<<cmd_id) ); 
[529]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
[258]285    {
286
[603]287#if GIET_DEBUG_IOC
288if (_get_proctime() > GIET_DEBUG_IOC)
[563]289_printf("\n[DEBUG HBA] _hba_access() : P[%d,%d,%d] get slot %d in Cmd List "
[545]290        "at cycle %d / descheduling\n",
[576]291        x , y , p , cmd_id, _get_proctime() );
[529]292#endif
293        unsigned int save_sr;
294        unsigned int ltid = _get_current_task_id();
[258]295
[529]296        // activates HBA interrupts
297        _hba_set_register( HBA_PXIE , 0x00000001 ); 
[258]298
[576]299        // set _hba_gtid[cmd_id]
300        _hba_gtid[cmd_id] = (procid<<16) + ltid;
[258]301
[529]302        // enters critical section
303        _it_disable( &save_sr ); 
[258]304
[529]305        // reset runnable
306        _set_task_slot( x, y, p, ltid, CTX_RUN_ID, 0 ); 
[258]307
[545]308        // start HBA transfer
[576]309        _hba_set_register( HBA_PXCI, (1<<cmd_id) );
[545]310
[576]311        // set _hba_active_cmd[cmd_id]
312        _hba_active_cmd[cmd_id] = 1;
313
[529]314        // deschedule task
315        _ctx_switch();                     
[258]316
[603]317#if GIET_DEBUG_IOC
318if (_get_proctime() > GIET_DEBUG_IOC)
[545]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() );
[529]321#endif
[258]322
[529]323        // restore SR
324        _it_restore( &save_sr );
[258]325
[529]326        // get command status
[576]327        pxis = _hba_status;
328    }
329   
330    // release the cmd index
331    unsigned int release_success;
332    release_success = _hba_cmd_release(cmd_id);
[258]333
[603]334#if GIET_DEBUG_IOC
335if (_get_proctime() > GIET_DEBUG_IOC)
[576]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() );
[529]340#endif
[258]341
[576]342    if ( release_success != 0 )   return -1;
343    else if ( pxis & 0x40000000 ) return pxis;
344    else                          return 0;
[258]345
[529]346} // end _hba_access()
[258]347
348
[529]349////////////////////////
350unsigned int _hba_init()
351{
[545]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
[258]357
[545]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
[576]372    // initialise allocator lock if not in boot mode
373    if ( !_hba_boot_mode )
374        _sqt_lock_init(&_hba_allocator_lock);
[258]375
[576]376    // initialise Command Descriptors in Command List, allocated command table
377    // and active command table
[545]378    unsigned int         c;     
379    unsigned long long   paddr;
[258]380    for( c=0 ; c<32 ; c++ )
381    {
[545]382        paddr = cmd_table_paddr + c * sizeof(hba_cmd_table_t);
383        _hba_cmd_list[c].ctba  = (unsigned int)(paddr);
[529]384        _hba_cmd_list[c].ctbau = (unsigned int)(paddr>>32);
[576]385        _hba_allocated_cmd[c] = 0;
386        _hba_active_cmd[c] = 0;
[258]387    }
[289]388
[545]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 );
[529]396
[289]397    return 0;
[258]398}
399
[437]400
[545]401/////////////////////////////////////////////////////
[529]402void _hba_isr( unsigned int irq_type,   // HWI / WTI
403               unsigned int irq_id,     // index returned by ICU
404               unsigned int channel )   // unused
[437]405{
[576]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   
[529]422    // get HBA_PXCI containing commands status
[576]423    unsigned int current_pxci = _hba_get_register( HBA_PXCI );
[437]424
[576]425    for ( cmd_id = 0 ; cmd_id < 32 ; cmd_id ++ )
[529]426    {
[576]427        if ( ( (current_active_cmd & (1<<cmd_id)) != 0) && // active command
428             ( (current_pxci & (1<<cmd_id)) == 0 ) )       // completed command
[529]429        {
[576]430            // desactivate the command
431            _hba_active_cmd[cmd_id] = 0;
[258]432
[529]433            // identify waiting task
[576]434            unsigned int remote_procid  = _hba_gtid[cmd_id]>>16;
435            unsigned int ltid           = _hba_gtid[cmd_id] & 0xFFFF;
[529]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 );
[295]448
[529]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
[295]453
[603]454#if GIET_DEBUG_IOC 
455if (_get_proctime() > GIET_DEBUG_IOC)
[545]456_printf("\n[DEBUG HBA] _hba_isr() : command %d completed at cycle %d\n"
[576]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
[529]461        }
462    }
463} // end _hba_isr()
[295]464
[258]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.