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

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

Cosmetic.

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