source: soft/giet_vm/giet_drivers/sdc_driver.c

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

Major release: Change the task model to implement the POSIX threads API.

  • The shell "exec" and "kill" commands can be used to activate/de-activate the applications.
  • The "pause", "resume", and "context" commands can be used to stop, restart, a single thtead or to display the thread context.

This version has been tested on the following multi-threaded applications,
that have been modified to use the POSIX threads:

  • classif
  • convol
  • transpose
  • gameoflife
  • raycast
File size: 17.6 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : sdc_driver.c
3// Date     : 31/04/2015
4// Author   : Alain Greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7
8#include "hard_config.h"
9#include "giet_config.h"
10#include "sdc_driver.h"
11#include "tty0.h"
12#include "utils.h"
13#include "vmem.h"
14#include "kernel_locks.h"
15#include "mmc_driver.h"
16#include "xcu_driver.h"
17#include "ctx_handler.h"
18
19#define  SDC_RSP_TIMEOUT      100       // number of retries for a config RSP
20
21#define  SDC_POLLING_TIMEOUT  1000000   // number of retries for polling PXCI
22
23//////////////////////////////////////////////////////////////////////////////////
24//      Extern variables
25//////////////////////////////////////////////////////////////////////////////////
26
27// allocated in the boot.c or kernel_init.c files
28extern static_scheduler_t* _schedulers[X_SIZE][Y_SIZE][NB_PROCS_MAX]; 
29
30///////////////////////////////////////////////////////////////////////////////////
31//          AHCI related global variables
32///////////////////////////////////////////////////////////////////////////////////
33
34// global index ot the thread, for each entry in the command list
35__attribute__((section(".kdata")))
36unsigned int     _ahci_trdid[32];
37
38// status of the command, for each entry in the command list
39__attribute__((section(".kdata")))
40unsigned int     _ahci_status[32];
41
42// command list : up to 32 commands
43__attribute__((section(".kdata")))
44ahci_cmd_desc_t  _ahci_cmd_list[32] __attribute__((aligned(0x40)));   
45
46// command tables array : one command table per entry in command list
47__attribute__((section(".kdata")))
48ahci_cmd_table_t _ahci_cmd_table[32] __attribute__((aligned(0x40))); 
49
50// command list write index : next slot to register a command
51__attribute__((section(".kdata")))
52unsigned int     _ahci_cmd_ptw;
53
54// command list read index : next slot to poll a completed command
55__attribute__((section(".kdata")))
56unsigned int     _ahci_cmd_ptr;
57
58
59///////////////////////////////////////////////////////////////////////////////////
60//          SD Card related global variables
61///////////////////////////////////////////////////////////////////////////////////
62
63// SD card relative address
64__attribute__((section(".kdata")))
65unsigned int     _sdc_rca;
66
67// SD Card Hih Capacity Support when non zero
68__attribute__((section(".kdata")))
69unsigned int     _sdc_sdhc;
70
71
72///////////////////////////////////////////////////////////////////////////////
73// This low_level function returns the value contained in register (index).
74///////////////////////////////////////////////////////////////////////////////
75static unsigned int _sdc_get_register( unsigned int index )
76{
77    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index;
78    return _io_extended_read( vaddr );
79}
80
81///////////////////////////////////////////////////////////////////////////////
82// This low-level function set a new value in register (index).
83///////////////////////////////////////////////////////////////////////////////
84static void _sdc_set_register( unsigned int index,
85                               unsigned int value ) 
86{
87    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index;
88    _io_extended_write( vaddr, value );
89}
90
91///////////////////////////////////////////////////////////////////////////////
92// This function sends a command to the SD card and returns the response.
93// - index      : CMD index
94// - arg        : CMD argument
95// - return Card response
96///////////////////////////////////////////////////////////////////////////////
97static unsigned int _sdc_send_cmd ( unsigned int   index,
98                                    unsigned int   arg )
99{
100    unsigned int  sdc_rsp;
101    register int  iter = 0;
102
103    // load argument
104    _sdc_set_register( SDC_CMD_ARG, arg );
105
106    // lauch command
107    _sdc_set_register( SDC_CMD_ID , index );
108
109    // get response
110    do
111    {
112        sdc_rsp = _sdc_get_register( SDC_RSP_STS );
113        iter++;
114    }
115    while ( (sdc_rsp == 0xFFFFFFFF) && (iter < SDC_RSP_TIMEOUT) ); 
116
117    return sdc_rsp;
118}
119
120/////////////////////////////////////////////////////////////////////////////////
121//           Extern functions
122/////////////////////////////////////////////////////////////////////////////////
123
124////////////////////////
125unsigned int _sdc_init()
126{
127    //////////// SD Card initialisation //////////
128 
129    unsigned int rsp;
130
131    // define the SD card clock period
132    _sdc_set_register( SDC_PERIOD , GIET_SDC_PERIOD );
133
134    // send CMD0 (soft reset / no argument)
135    rsp = _sdc_send_cmd( SDC_CMD0 , 0 );
136    if ( rsp == 0xFFFFFFFF )
137    {
138        _printf("\n[SDC ERROR] in _sdc_init() : no acknowledge to CMD0\n");
139        return 1;
140    }
141
142#if GIET_DEBUG_IOC
143if (_get_proctime() > GIET_DEBUG_IOC)
144_printf("\n[DEBUG SDC] _sdc_init() : SDC_CMD0 done at cycle %d\n", _get_proctime() );
145#endif
146
147    // send CMD8 command
148    rsp = _sdc_send_cmd( SDC_CMD8 , SDC_CMD8_ARGUMENT );
149    if ( rsp == 0xFFFFFFFF )
150    {
151        _printf("\n[SDC ERROR] in _sdc_init() : no response to CMD8\n");
152        return 1;
153    }
154    else if ( rsp != SDC_CMD8_ARGUMENT )
155    {
156        _printf("\n[SDC ERROR] in _sdc_init() : response to CMD8 = %x / expected = %x\n",
157                rsp , SDC_CMD8_ARGUMENT );
158        return 1;
159    }
160
161#if GIET_DEBUG_IOC
162if (_get_proctime() > GIET_DEBUG_IOC)
163_printf("\n[DEBUG SDC] _sdc_init() : SDC_CMD8 done at cycle %d\n", _get_proctime() );
164#endif
165
166    // send CMD41 to get SDHC
167    if ( rsp == 0xFFFFFFFF )
168    {
169        _printf("\n[SDC ERROR] in _sdc_init() : no response to CMD41\n");
170        return 1;
171    }
172    _sdc_sdhc = ( (rsp & SDC_CMD41_RSP_CCS) != 0 );
173
174#if GIET_DEBUG_IOC
175if (_get_proctime() > GIET_DEBUG_IOC)
176_printf("\n[DEBUG SDC] _sdc_init() : SDC_CMD41 done at cycle %d\n", _get_proctime() );
177#endif
178
179    // send CMD3 to get RCA
180    rsp = _sdc_send_cmd( SDC_CMD3 , 0 );
181    if ( rsp == 0xFFFFFFFF )
182    {
183        _printf("\n[SDC ERROR] in _sdc_init() : no response to CMD3\n");
184        return 1;
185    }
186    _sdc_rca = rsp;
187
188#if GIET_DEBUG_IOC
189if (_get_proctime() > GIET_DEBUG_IOC)
190_printf("\n[DEBUG SDC] _sdc_init() : SDC_CMD3 done at cycle %d\n", _get_proctime() );
191#endif
192
193    // send CMD7
194    rsp = _sdc_send_cmd( SDC_CMD7 , _sdc_rca );
195    if ( rsp == 0xFFFFFFFF )
196    {
197        _printf("\n[SDC ERROR] in _sdc_init() : no response to CMD7\n");
198        return 1;
199    }
200
201#if GIET_DEBUG_IOC
202if (_get_proctime() > GIET_DEBUG_IOC)
203_printf("\n[DEBUG SDC] _sdc_init() : SDC_CMD7 done at cycle %d\n", _get_proctime() );
204#endif
205
206    //////////// AHCI interface initialisation  ///////
207
208    unsigned int       cmd_list_vaddr;
209    unsigned int       cmd_table_vaddr;
210    unsigned long long cmd_list_paddr;
211    unsigned long long cmd_table_paddr;
212    unsigned int       flags;                 // unused
213
214    // compute Command list & command table physical addresses
215    cmd_list_vaddr  = (unsigned int)(&_ahci_cmd_list[0]);
216    cmd_table_vaddr = (unsigned int)(&_ahci_cmd_table[0]);
217    if ( _get_mmu_mode() & 0x4 )
218    {
219        cmd_list_paddr  = _v2p_translate( cmd_list_vaddr  , &flags );
220        cmd_table_paddr = _v2p_translate( cmd_table_vaddr , &flags );
221    }
222    else
223    {
224        cmd_list_paddr  = (unsigned long long)cmd_list_vaddr;
225        cmd_table_paddr = (unsigned long long)cmd_table_vaddr;
226    }
227
228    // initialise Command List pointers
229    _ahci_cmd_ptw = 0;
230    _ahci_cmd_ptr = 0;
231
232    // initialise Command Descriptors in Command List
233    unsigned int         c;     
234    unsigned long long   paddr;
235    for( c=0 ; c<32 ; c++ )
236    {
237        paddr = cmd_table_paddr + c * sizeof(ahci_cmd_table_t);
238        _ahci_cmd_list[c].ctba  = (unsigned int)(paddr);
239        _ahci_cmd_list[c].ctbau = (unsigned int)(paddr>>32);
240    }
241
242    // initialise AHCI registers
243    _sdc_set_register( AHCI_PXCLB  , (unsigned int)(cmd_list_paddr) );
244    _sdc_set_register( AHCI_PXCLBU , (unsigned int)(cmd_list_paddr>>32) );
245    _sdc_set_register( AHCI_PXIE   , 0 );
246    _sdc_set_register( AHCI_PXIS   , 0 );
247    _sdc_set_register( AHCI_PXCI   , 0 );
248    _sdc_set_register( AHCI_PXCMD  , 1 );
249
250#if GIET_DEBUG_IOC
251if (_get_proctime() > GIET_DEBUG_IOC)
252_printf("\n[DEBUG SDC] _sdc_init() : AHCI init done at cycle %d\n", _get_proctime() );
253#endif
254
255    return 0;
256} // end _sdc_init()
257
258
259/////////////////////////////////////////////////////
260unsigned int _sdc_access( unsigned int       use_irq, 
261                          unsigned int       to_mem,
262                          unsigned int       lba,
263                          unsigned long long buf_paddr,
264                          unsigned int       count )
265{
266    unsigned int procid  = _get_procid();
267    unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
268    unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH) - 1);
269    unsigned int p       = procid & ((1<<P_WIDTH)-1);
270    unsigned int iter;
271
272#if GIET_DEBUG_IOC
273if (_get_proctime() > GIET_DEBUG_IOC)
274_printf("\n[DEBUG SDC] _sdc_access() : P[%d,%d,%d] enters at cycle %d\n"
275        "  use_irq = %d / to_mem = %d / lba = %x / paddr = %l / count = %d\n",
276        x , y , p , _get_proctime() , use_irq , to_mem , lba , buf_paddr, count );
277#endif
278
279    unsigned int       pxci;              // AHCI_PXCI register value
280    unsigned int       ptw;               // command list write pointer
281    unsigned int       pxis;              // AHCI_PXIS register value
282    ahci_cmd_desc_t*   cmd_desc;          // command descriptor pointer   
283    ahci_cmd_table_t*  cmd_table;         // command table pointer
284
285    // check buffer alignment
286    if( buf_paddr & 0x3F )
287    {
288        _printf("\n[SDC ERROR] in _sdc_access() : buffer not 64 bytes aligned\n");
289        return 1;
290    }
291
292    // get one entry in Command List, using an
293    // atomic increment on the _ahci_cmd_ptw allocator
294    // only the 5 LSB bits are used to index the Command List
295    ptw = _atomic_increment( &_ahci_cmd_ptw , 1 ) & 0x1F;
296
297    // blocked until allocated entry in Command List is empty
298    iter = SDC_POLLING_TIMEOUT;
299    do
300    {
301        // get PXCI register
302        pxci = _sdc_get_register( AHCI_PXCI );
303
304        // check livelock
305        iter--;
306        if ( iter == 0 )
307        {
308            _printf("\n[SDC ERROR] in _sdc_access() : cannot get PXCI slot\n");
309            return 1;
310        }
311    } 
312    while ( pxci & (1<<ptw) );
313
314    // compute pointers on command descriptor and command table   
315    cmd_desc  = &_ahci_cmd_list[ptw];
316    cmd_table = &_ahci_cmd_table[ptw];
317
318    // set  buffer descriptor in command table
319    cmd_table->buffer.dba  = (unsigned int)(buf_paddr);
320    cmd_table->buffer.dbau = (unsigned int)(buf_paddr >> 32);
321    cmd_table->buffer.dbc  = count * 512;
322
323    // initialize command table header
324    cmd_table->header.lba0 = (char)lba;
325    cmd_table->header.lba1 = (char)(lba>>8);
326    cmd_table->header.lba2 = (char)(lba>>16);
327    cmd_table->header.lba3 = (char)(lba>>24);
328    cmd_table->header.lba4 = 0;
329    cmd_table->header.lba5 = 0;
330
331    // initialise command descriptor
332    cmd_desc->prdtl[0] = 1;
333    cmd_desc->prdtl[1] = 0;
334    if( to_mem ) cmd_desc->flag[0] = 0x00;
335    else         cmd_desc->flag[0] = 0x40;     
336
337#if USE_IOB    // software L2/L3 cache coherence
338
339    // compute physical addresses
340    unsigned long long cmd_desc_paddr;    // command descriptor physical address
341    unsigned long long cmd_table_paddr;   // command table header physical address
342    unsigned int       flags;             // unused
343
344    if ( _get_mmu_mode() & 0x4 )
345    {
346        cmd_desc_paddr  = _v2p_translate( (unsigned int)cmd_desc  , &flags );
347        cmd_table_paddr = _v2p_translate( (unsigned int)cmd_table , &flags );
348    }
349    else
350    {
351        cmd_desc_paddr  = (unsigned int)cmd_desc;
352        cmd_table_paddr = (unsigned int)cmd_table;
353    }
354
355    // update external memory for command table
356    _mmc_sync( cmd_table_paddr & (~0x3F) , sizeof(ahci_cmd_table_t) );
357
358    // update external memory for command descriptor
359    _mmc_sync( cmd_desc_paddr & (~0x3F) , sizeof(ahci_cmd_desc_t) );
360
361    // inval or synchronize memory buffer
362    if ( to_mem )  _mmc_inval( buf_paddr, count<<9 );
363    else           _mmc_sync( buf_paddr, count<<9 );
364
365#endif     // end software L2/L3 cache coherence
366
367    /////////////////////////////////////////////////////////////////////
368    // In synchronous mode, we poll the PXCI register until completion
369    /////////////////////////////////////////////////////////////////////
370    if ( use_irq == 0 ) 
371    {
372        // start transfer
373        _sdc_set_register( AHCI_PXCI, (1<<ptw) );
374
375#if GIET_DEBUG_IOC
376if (_get_proctime() > GIET_DEBUG_IOC)
377_printf("\n[DEBUG SDC] _sdc_access() : command %d for P[%d,%d,%d]"
378        " at cycle %d / polling\n",
379        ptw , x , y , p , _get_proctime() );
380#endif
381        // disable IRQs in PXIE register
382        _sdc_set_register( AHCI_PXIE , 0 );
383
384        // poll PXCI[ptw] until command completed
385        iter = SDC_POLLING_TIMEOUT;
386        do
387        {
388            pxci = _sdc_get_register( AHCI_PXCI );
389
390            // check livelock
391            iter--;
392            if ( iter == 0 )
393            {
394                _printf("\n[SDC ERROR] in _sdc_access() : polling PXCI timeout\n");
395                return 1;
396            }
397        }
398        while( pxci & (1<<ptw) ); 
399             
400        // get PXIS register
401        pxis = _sdc_get_register( AHCI_PXIS );
402
403        // reset PXIS register
404        _sdc_set_register( AHCI_PXIS , 0 );
405    }
406
407    /////////////////////////////////////////////////////////////////
408    // in descheduling mode, we deschedule the thread
409    // and use an interrupt to reschedule the thread.
410    // We need a critical section, because we must set the NORUN bit
411        // before to launch the transfer, and we don't want to be
412    // descheduled between these two operations.
413    /////////////////////////////////////////////////////////////////
414    else
415    {
416
417#if GIET_DEBUG_IOC
418if (_get_proctime() > GIET_DEBUG_IOC)
419_printf("\n[DEBUG SDC] _sdc_access() : command %d for P[%d,%d,%d] "
420        "at cycle %d / descheduling\n",
421        ptw , x , y , p , _get_proctime() );
422#endif
423        unsigned int save_sr;
424        unsigned int ltid = _get_thread_ltid();
425
426        // activates interrupt
427        _sdc_set_register( AHCI_PXIE , 0x00000001 ); 
428
429        // set _ahci_trdid[ptw]
430        _ahci_trdid[ptw] = (x<<24) + (y<<16) + (p<<8) + ltid;
431
432        // enters critical section
433        _it_disable( &save_sr ); 
434
435        // Set NORUN_MASK_IOC bit
436        static_scheduler_t* psched  = (static_scheduler_t*)_schedulers[x][y][p];
437        unsigned int*       ptr     = &psched->context[ltid].slot[CTX_NORUN_ID];
438        _atomic_or( ptr , NORUN_MASK_IOC );
439       
440        // start transfer
441        _sdc_set_register( AHCI_PXCI, (1<<ptw) );
442
443        // deschedule thread
444        _ctx_switch();                     
445
446#if GIET_DEBUG_IOC
447if (_get_proctime() > GIET_DEBUG_IOC)
448_printf("\n[DEBUG SDC] _sdc_access() : thread %d on P[%d,%d,%d] resume at cycle %d\n",
449        ltid , x , y , p , _get_proctime() );
450#endif
451
452        // restore SR
453        _it_restore( &save_sr );
454
455        // get command status
456        pxis = _ahci_status[ptw];
457    }   
458
459#if GIET_DEBUG_IOC
460if (_get_proctime() > GIET_DEBUG_IOC)
461_printf("\n[DEBUG SDC] _sdc_access() : P[%d,%d,%d] exit at cycle %d\n",
462        x , y , p , _get_proctime() );
463#endif
464
465    if ( pxis & 0x40000000 ) return pxis;
466    else                     return 0;
467
468} // end _sdc_access()
469
470
471///////////////////////////////////////////////////////////////////////////////
472// This ISR handles the IRQ generated by the AHCI_SDC controler
473///////////////////////////////////////////////////////////////////////////////
474void _sdc_isr( unsigned int irq_type,
475               unsigned int irq_id,
476               unsigned int channel )
477{
478    // get AHCI_PXCI containing commands status
479    unsigned int pxci = _sdc_get_register( AHCI_PXCI );
480
481    // we must handle all completed commands
482    // active commands are between  (_ahci_cmd_ptr) and (_ahci_cmd_ptw-1)
483    unsigned int current;
484    for ( current = _ahci_cmd_ptr ; current != _ahci_cmd_ptw ; current++ )
485    {
486        unsigned int cmd_id = current & 0x1F;
487       
488        if ( (pxci & (1<<cmd_id)) == 0 )    // command completed
489        {
490            // increment the 32 bits variable _ahci_cmd_ptr
491            _ahci_cmd_ptr++;
492
493            // save AHCI_PXIS register
494            _ahci_status[cmd_id] = _sdc_get_register( AHCI_PXIS );
495
496            // reset AHCI_PXIS register
497            _sdc_set_register( AHCI_PXIS , 0 );
498 
499            // identify waiting thread
500            unsigned int x       = (_ahci_trdid[cmd_id]>>24) & 0xFF;
501            unsigned int y       = (_ahci_trdid[cmd_id]>>16) & 0xFF;
502            unsigned int p       = (_ahci_trdid[cmd_id]>> 8) & 0xFF;
503            unsigned int ltid    = (_ahci_trdid[cmd_id]    ) & 0xFF;
504
505            // Reset NORUN_MASK_IOC bit
506            static_scheduler_t* psched  = (static_scheduler_t*)_schedulers[x][y][p];
507            _atomic_and( &psched->context[ltid].slot[CTX_NORUN_ID] , ~NORUN_MASK_IOC );
508
509            // send a WAKUP WTI to processor running the waiting thread
510            _xcu_send_wti( (x<<Y_WIDTH) + y,
511                           p , 
512                           0 );          // don't force context switch
513
514#if GIET_DEBUG_IOC 
515if (_get_proctime() > GIET_DEBUG_IOC)
516_printf("\n[DEBUG SDC] _sdc_isr() : command %d completed at cycle %d\n"
517        "  resume thread %d running on P[%d,%d,%d] / status = %x\n",
518        cmd_id , _get_proctime() ,
519        ltid , x , y , p , _ahci_status[cmd_id] );
520#endif
521        }
522        else                         // command non completed
523        {
524            break;
525        }
526    }  // end for completed commands
527}  // end _sdc_isr()
528
529// Local Variables:
530// tab-width: 4
531// c-basic-offset: 4
532// c-file-offsets:((innamespace . 0)(inline-open . 0))
533// indent-tabs-mode: nil
534// End:
535// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
Note: See TracBrowser for help on using the repository browser.