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

Last change on this file since 539 was 529, checked in by alain, 10 years ago

1) Removing the IOC driver (integrated in the FAT library).
2) Simplifying the BDV, HBA, SDC, RDK drivers: they support
only two modes (synchronous => polling / descheduling => IRQ),
and only one access function (for both read/write).

File size: 11.9 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>
17#include <kernel_locks.h>
[258]18#include <utils.h>
[456]19#include <tty0.h>
[258]20#include <ctx_handler.h>
[529]21#include <irq_handler.h>
[258]22#include <vmem.h>
23
[529]24///////////////////////////////////////////////////////////////////////////////////
25//               Global variables
26///////////////////////////////////////////////////////////////////////////////////
[258]27
[529]28// global index ot the task, for each entry in the command list
29__attribute__((section(".kdata")))
30unsigned int _hba_gtid[32];
[258]31
[529]32// status of the command, for each entry in the command list
33__attribute__((section(".kdata")))
34unsigned int _hba_status[32];
[258]35
[529]36// command list : up to 32 commands
37__attribute__((section(".kdata")))
38hba_cmd_desc_t  _hba_cmd_list[32] __attribute__((aligned(0x1000)));   
[258]39
[529]40// command tables array : one command table per entry in command list
41__attribute__((section(".kdata")))
42hba_cmd_table_t _hba_cmd_table[32] __attribute__((aligned(0x1000))); 
[258]43
[529]44// command list write index : next slot to register a command
45__attribute__((section(".kdata")))
46unsigned int     _hba_cmd_ptw;
[258]47
[529]48// command list read index : next slot to poll a completed command
49__attribute__((section(".kdata")))
50unsigned int     _hba_cmd_ptr;
[258]51
[295]52//////////////////////////////////////////////////////////////////////////////
[529]53// This low level function returns the value of register (index)
[295]54//////////////////////////////////////////////////////////////////////////////
[529]55unsigned int _hba_get_register( unsigned int index )
[258]56{
[529]57    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index;
[295]58    return _io_extended_read( vaddr );
59}
[258]60
[295]61//////////////////////////////////////////////////////////////////////////////
[529]62// This low level function set a new value in register (index) 
[295]63//////////////////////////////////////////////////////////////////////////////
[529]64void _hba_set_register( unsigned int index,
[295]65                        unsigned int value )
66{
[529]67    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index;
[295]68    _io_extended_write( vaddr, value );
[258]69}
70
[529]71///////////////////////////////////////////////////////////////////////////////
72//      Extern functions
73///////////////////////////////////////////////////////////////////////////////
[295]74
[258]75///////////////////////////////////////////////////////////////////////////////
76// This function register a command in both the command list
77// and the command table, and updates the HBA_PXCI register.
[437]78// return 0 if success, -1 if error
[258]79///////////////////////////////////////////////////////////////////////////////
[529]80unsigned int _hba_access( unsigned int       use_irq,
81                          unsigned int       to_mem,
82                          unsigned int       lba, 
83                          unsigned long long buf_paddr,
84                          unsigned int       count )   
[258]85{
[529]86    unsigned int procid  = _get_procid();
87    unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
88    unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH) - 1);
89    unsigned int p       = procid & ((1<<P_WIDTH)-1);
[295]90
[529]91#if GIET_DEBUG_IOC_DRIVER
92_printf("\n[HBA DEBUG] P[%d,%d,%d] enters _hba_access at cycle %d\n"
93        "  use_irq = %d / to_mem = %d / lba = %x / paddr = %l / count = %d\n",
94        x , y , p , _get_proctime() , use_irq , to_mem , lba , buf_paddr, count );
95#endif
96
97    unsigned int       pxci;           // HBA_PXCI register value
98    unsigned int       ptw;            // command list write pointer
99    unsigned int       pxis;           // HBA_PXIS register value
[258]100    hba_cmd_desc_t*    cmd_desc;       // command descriptor pointer   
101    hba_cmd_table_t*   cmd_table;      // command table pointer
102
103    // check buffer alignment
[529]104    if( buf_paddr & 0x1FF )
[258]105    {
[529]106        _printf("\n[HBA ERROR] in _hba_access() : buffer not block aligned\n");
[437]107        return -1;
[258]108    }
109
[529]110    // get pointer on the next possible entry in command list
111    ptw = _atomic_increment( &_hba_cmd_ptw , 1 );
[258]112
[529]113    // poll PXCI register until pointed entry empty
114    do
[258]115    {
[529]116        // get PXCI register
117        pxci = _hba_get_register( HBA_PXCI );
118    } 
119    while ( pxci & (1<<ptw) );
120   
[258]121    // compute pointers on command descriptor and command table   
[529]122    cmd_desc  = &_hba_cmd_list[ptw];
123    cmd_table = &_hba_cmd_table[ptw];
[258]124
[295]125    // set  buffer descriptor in command table
[529]126    cmd_table->entry[0].dba  = (unsigned int)(buf_paddr);
127    cmd_table->entry[0].dbau = (unsigned int)(buf_paddr >> 32);
128    cmd_table->entry[0].dbc  = count * 512;
[295]129
130    // initialize command table header
131    cmd_table->header.lba0 = (char)lba;
132    cmd_table->header.lba1 = (char)(lba>>8);
133    cmd_table->header.lba2 = (char)(lba>>16);
134    cmd_table->header.lba3 = (char)(lba>>24);
135    cmd_table->header.lba4 = 0;
136    cmd_table->header.lba5 = 0;
137
138    // initialise command descriptor
139    cmd_desc->prdtl[0] = 1;
140    cmd_desc->prdtl[1] = 0;
[529]141    if( to_mem ) cmd_desc->flag[0] = 0x00;
142    else         cmd_desc->flag[0] = 0x40;     
[295]143   
[529]144    // set command in PXCI[ptw]
145    _hba_set_register( HBA_PXCI, pxci + (1<<ptw) );
[295]146
147
[529]148    /////////////////////////////////////////////////////////////////////
149    // In synchronous mode, we poll the PXCI register until completion
150    /////////////////////////////////////////////////////////////////////
151    if ( use_irq == 0 ) 
152    {
[295]153
[529]154#if GIET_DEBUG_IOC_DRIVER
155_printf("\n[HBA DEBUG] _hba_access() : P[%d,%d,%d] launch transfer"
156        " in polling mode at cycle %d\n",
157        x , y , p , _get_proctime() );
158#endif
159        // disable IRQs in PXIE register
160        _hba_set_register( HBA_PXIE , 0 );
[295]161
[529]162        // poll PXCI[ptw] until command completed by HBA
163        do
164        {
165            pxci = _hba_get_register( HBA_PXCI ) & (1<<ptw);
[258]166
[529]167#if GIET_DEBUG_IOC_DRIVER
168_printf("\n[HBA DEBUG] _hba_access() : P[%d,%d,%d] wait on HBA_STATUS ...\n",
169        x , y , p );
170#endif
171        }
172        while( pxci & (1<<ptw) ); 
173             
174        // get PXIS register
175        pxis = _hba_get_register( HBA_PXIS );
176
177        // reset PXIS register
178        _hba_set_register( HBA_PXIS , 0 );
179    }
180
181    /////////////////////////////////////////////////////////////////
182    // in descheduling mode, we deschedule the task
183    // and use an interrupt to reschedule the task.
184    // We need a critical section, because we must reset the RUN bit
185        // before to launch the transfer, and we don't want to be
186    // descheduled between these two operations.
187    /////////////////////////////////////////////////////////////////
188    else
[258]189    {
190
[529]191#if GIET_DEBUG_IOC_DRIVER
192_printf("\n[HBA DEBUG] _hba_access() : P[%d,%d,%d] launch transfer"
193        " in descheduling mode at cycle %d\n",
194        x , y , p , _get_proctime() );
195#endif
196        unsigned int save_sr;
197        unsigned int ltid = _get_current_task_id();
[258]198
[529]199        // activates HBA interrupts
200        _hba_set_register( HBA_PXIE , 0x00000001 ); 
[258]201
[529]202        // set _hba_gtid[ptw]
203        _hba_gtid[ptw] = (procid<<16) + ltid;
[258]204
[529]205        // enters critical section
206        _it_disable( &save_sr ); 
[258]207
[529]208        // reset runnable
209        _set_task_slot( x, y, p, ltid, CTX_RUN_ID, 0 ); 
[258]210
[529]211        // deschedule task
212        _ctx_switch();                     
[258]213
[529]214#if GIET_DEBUG_IOC_DRIVER
215_printf("\n[HBA DEBUG] _hba_access() : P[%d,%d,%d] resume execution at cycle %d\n",
216        x , y , p , _get_proctime() );
217#endif
[258]218
[529]219        // restore SR
220        _it_restore( &save_sr );
[258]221
[529]222        // get command status
223        pxis = _hba_status[ptw];
224    }   
[258]225
[529]226#if GIET_DEBUG_IOC_DRIVER
227_printf("\n[HBA DEBUG] _hba_access() : P[%d,%d,%d] exit at cycle %d\n",
228        x , y , p , _get_proctime() );
229#endif
[258]230
[529]231    if ( pxis & 0x40000000 ) return pxis;
232    else                     return 0;
[258]233
[529]234} // end _hba_access()
[258]235
236
[529]237////////////////////////
238unsigned int _hba_init()
239{
240    unsigned int       flags;
241    unsigned int       vaddr;
242    unsigned long long paddr;
243    unsigned int       c;     
244    unsigned int       pxclb;
245    unsigned int       pxclbu;
[258]246
[529]247    // command list pointers
248    _hba_cmd_ptw = 0;
249    _hba_cmd_ptr = 0;
[258]250
251    // Command list physical addresse
[529]252    vaddr  = (unsigned int)(_hba_cmd_list);
253    paddr  = _v2p_translate( vaddr , &flags );
254    pxclb  = (unsigned int)paddr;
255    pxclbu = (unsigned int)(paddr>>32);
[258]256
257    // Command tables physical addresses
258    for( c=0 ; c<32 ; c++ )
259    {
[529]260        // compute command table physical address
261        // for one entry in the command list
262        vaddr = (unsigned int)(&_hba_cmd_table[c]);
263        paddr = _v2p_translate( vaddr , &flags );
264
265        // initialise the corresponding command descriptor
266        _hba_cmd_list[c].ctba  = (unsigned int)paddr;
267        _hba_cmd_list[c].ctbau = (unsigned int)(paddr>>32);
[258]268    }
[289]269
[529]270    // set HBA registers
271    _hba_set_register( HBA_PXCLB , pxclb  );
272    _hba_set_register( HBA_PXCLBU, pxclbu );
273    _hba_set_register( HBA_PXIE  , 0      );
274    _hba_set_register( HBA_PXIS  , 0      );
275    _hba_set_register( HBA_PXCI  , 0      );
276    _hba_set_register( HBA_PXCMD , 1      );
277
[289]278    return 0;
[258]279}
280
[437]281
[529]282/////////////////////////////////////
283void _hba_isr( unsigned int irq_type,   // HWI / WTI
284               unsigned int irq_id,     // index returned by ICU
285               unsigned int channel )   // unused
[437]286{
[529]287    // get HBA_PXCI containing commands status
288    unsigned int pxci = _hba_get_register( HBA_PXCI );
[437]289
[529]290    // scan active commands from (_hba_cmd_ptr) to (_hba_cmd_ptw-1)
291    unsigned int c;
292    for ( c = _hba_cmd_ptr ; 
293          c != _hba_cmd_ptw ; 
294          c = (c + 1) % 32 )
295    {
296        if ( (pxci & (1<<c)) == 0 )    // command completed
297        {
298            // increment read pointer;
299            _hba_cmd_ptr++;
[258]300
[529]301            // save PXIS register
302            _hba_status[c] = _hba_get_register( HBA_PXIS );
[258]303
[529]304            // reset PXIS register
305            _hba_set_register( HBA_PXIS , 0 );
306 
307            // identify waiting task
308            unsigned int remote_procid  = _hba_gtid[c]>>16;
309            unsigned int ltid           = _hba_gtid[c] & 0xFFFF;
310            unsigned int remote_cluster = remote_procid >> P_WIDTH;
311            unsigned int remote_x       = remote_cluster >> Y_WIDTH;
312            unsigned int remote_y       = remote_cluster & ((1<<Y_WIDTH)-1);
313            unsigned int remote_p       = remote_procid & ((1<<P_WIDTH)-1);
314 
315            // re-activates waiting task
316            _set_task_slot( remote_x,
317                            remote_y,
318                            remote_p,
319                            ltid,
320                            CTX_RUN_ID,
321                            1 );
[295]322
[529]323            // send a WAKUP WTI to processor running the waiting task
324            _xcu_send_wti( remote_cluster , 
325                           remote_p , 
326                           0 );          // don't force context switch
[295]327
[529]328#if GIET_DEBUG_IOC_DRIVER 
329unsigned int procid  = _get_procid();
330unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
331unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
332unsigned int p       = procid & ((1<<P_WIDTH)-1);
333_printf("\n[HBA DEBUG] Processor[%d,%d,%d] executes _hba_isr() :\n"
334        "  resume task %d running on P[%d,%d,%d] / status = %x at cyle %d\n",
335        x , y , p , 
336        ltid , remote_x , remote_y , remote_p , _hba_status[c] , _get_proctime() );
337#endif
338        }
339        else                         // command non completed
340        {
341            break;
342        }
343    }
344} // end _hba_isr()
[295]345
[258]346// Local Variables:
347// tab-width: 4
348// c-basic-offset: 4
349// c-file-offsets:((innamespace . 0)(inline-open . 0))
350// indent-tabs-mode: nil
351// End:
352// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
353
Note: See TracBrowser for help on using the repository browser.