source: soft/giet_vm/giet_drivers/sdc_driver.c @ 739

Last change on this file since 739 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
RevLine 
[284]1///////////////////////////////////////////////////////////////////////////////////
2// File     : sdc_driver.c
[563]3// Date     : 31/04/2015
4// Author   : Alain Greiner
[284]5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
[295]7
[563]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"
[283]18
[563]19#define  SDC_RSP_TIMEOUT      100       // number of retries for a config RSP
[283]20
[563]21#define  SDC_POLLING_TIMEOUT  1000000   // number of retries for polling PXCI
[545]22
[630]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
[563]30///////////////////////////////////////////////////////////////////////////////////
31//          AHCI related global variables
32///////////////////////////////////////////////////////////////////////////////////
33
[709]34// global index ot the thread, for each entry in the command list
[545]35__attribute__((section(".kdata")))
[709]36unsigned int     _ahci_trdid[32];
[545]37
[563]38// status of the command, for each entry in the command list
[545]39__attribute__((section(".kdata")))
[563]40unsigned int     _ahci_status[32];
[283]41
[563]42// command list : up to 32 commands
43__attribute__((section(".kdata")))
44ahci_cmd_desc_t  _ahci_cmd_list[32] __attribute__((aligned(0x40)));   
[283]45
[563]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))); 
[283]49
[563]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
[284]72///////////////////////////////////////////////////////////////////////////////
[563]73// This low_level function returns the value contained in register (index).
[284]74///////////////////////////////////////////////////////////////////////////////
[563]75static unsigned int _sdc_get_register( unsigned int index )
[283]76{
[563]77    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index;
78    return _io_extended_read( vaddr );
[283]79}
80
[284]81///////////////////////////////////////////////////////////////////////////////
[563]82// This low-level function set a new value in register (index).
[284]83///////////////////////////////////////////////////////////////////////////////
[563]84static void _sdc_set_register( unsigned int index,
85                               unsigned int value ) 
[283]86{
[563]87    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index;
88    _io_extended_write( vaddr, value );
[283]89}
90
[284]91///////////////////////////////////////////////////////////////////////////////
[563]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
[284]96///////////////////////////////////////////////////////////////////////////////
[563]97static unsigned int _sdc_send_cmd ( unsigned int   index,
98                                    unsigned int   arg )
[283]99{
[563]100    unsigned int  sdc_rsp;
101    register int  iter = 0;
[283]102
[563]103    // load argument
104    _sdc_set_register( SDC_CMD_ARG, arg );
[283]105
[563]106    // lauch command
107    _sdc_set_register( SDC_CMD_ID , index );
[283]108
[563]109    // get response
110    do
[283]111    {
[563]112        sdc_rsp = _sdc_get_register( SDC_RSP_STS );
[283]113        iter++;
114    }
[563]115    while ( (sdc_rsp == 0xFFFFFFFF) && (iter < SDC_RSP_TIMEOUT) ); 
[283]116
[563]117    return sdc_rsp;
[283]118}
119
[563]120/////////////////////////////////////////////////////////////////////////////////
121//           Extern functions
122/////////////////////////////////////////////////////////////////////////////////
[283]123
[563]124////////////////////////
125unsigned int _sdc_init()
[283]126{
[563]127    //////////// SD Card initialisation //////////
128 
129    unsigned int rsp;
[283]130
[563]131    // define the SD card clock period
132    _sdc_set_register( SDC_PERIOD , GIET_SDC_PERIOD );
[283]133
[563]134    // send CMD0 (soft reset / no argument)
135    rsp = _sdc_send_cmd( SDC_CMD0 , 0 );
136    if ( rsp == 0xFFFFFFFF )
[283]137    {
[563]138        _printf("\n[SDC ERROR] in _sdc_init() : no acknowledge to CMD0\n");
139        return 1;
140    }
[283]141
[603]142#if GIET_DEBUG_IOC
143if (_get_proctime() > GIET_DEBUG_IOC)
[563]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;
[283]153    }
[563]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    }
[283]160
[603]161#if GIET_DEBUG_IOC
162if (_get_proctime() > GIET_DEBUG_IOC)
[563]163_printf("\n[DEBUG SDC] _sdc_init() : SDC_CMD8 done at cycle %d\n", _get_proctime() );
164#endif
[283]165
[563]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 );
[283]173
[603]174#if GIET_DEBUG_IOC
175if (_get_proctime() > GIET_DEBUG_IOC)
[563]176_printf("\n[DEBUG SDC] _sdc_init() : SDC_CMD41 done at cycle %d\n", _get_proctime() );
177#endif
[283]178
[563]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;
[283]187
[603]188#if GIET_DEBUG_IOC
189if (_get_proctime() > GIET_DEBUG_IOC)
[563]190_printf("\n[DEBUG SDC] _sdc_init() : SDC_CMD3 done at cycle %d\n", _get_proctime() );
191#endif
[283]192
[563]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    }
[283]200
[603]201#if GIET_DEBUG_IOC
202if (_get_proctime() > GIET_DEBUG_IOC)
[563]203_printf("\n[DEBUG SDC] _sdc_init() : SDC_CMD7 done at cycle %d\n", _get_proctime() );
204#endif
[283]205
[563]206    //////////// AHCI interface initialisation  ///////
[283]207
[563]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
[283]213
[563]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 )
[284]218    {
[563]219        cmd_list_paddr  = _v2p_translate( cmd_list_vaddr  , &flags );
220        cmd_table_paddr = _v2p_translate( cmd_table_vaddr , &flags );
221    }
[284]222    else
223    {
[563]224        cmd_list_paddr  = (unsigned long long)cmd_list_vaddr;
225        cmd_table_paddr = (unsigned long long)cmd_table_vaddr;
226    }
[284]227
[563]228    // initialise Command List pointers
229    _ahci_cmd_ptw = 0;
230    _ahci_cmd_ptr = 0;
[283]231
[563]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    }
[283]241
[563]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 );
[283]249
[603]250#if GIET_DEBUG_IOC
251if (_get_proctime() > GIET_DEBUG_IOC)
[563]252_printf("\n[DEBUG SDC] _sdc_init() : AHCI init done at cycle %d\n", _get_proctime() );
253#endif
[283]254
[593]255    return 0;
[563]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 )
[283]265{
[563]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;
[283]271
[603]272#if GIET_DEBUG_IOC
273if (_get_proctime() > GIET_DEBUG_IOC)
[563]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
[283]278
[563]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
[283]284
[563]285    // check buffer alignment
286    if( buf_paddr & 0x3F )
[283]287    {
[563]288        _printf("\n[SDC ERROR] in _sdc_access() : buffer not 64 bytes aligned\n");
289        return 1;
[283]290    }
291
[563]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;
[283]296
[563]297    // blocked until allocated entry in Command List is empty
298    iter = SDC_POLLING_TIMEOUT;
299    do
[283]300    {
[563]301        // get PXCI register
302        pxci = _sdc_get_register( AHCI_PXCI );
[283]303
[563]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) );
[283]313
[563]314    // compute pointers on command descriptor and command table   
315    cmd_desc  = &_ahci_cmd_list[ptw];
316    cmd_table = &_ahci_cmd_table[ptw];
[283]317
[563]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;
[283]322
[563]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;
[437]330
[563]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;     
[283]336
[563]337#if USE_IOB    // software L2/L3 cache coherence
[283]338
[563]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
[283]343
[563]344    if ( _get_mmu_mode() & 0x4 )
[283]345    {
[563]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    }
[283]354
[563]355    // update external memory for command table
356    _mmc_sync( cmd_table_paddr & (~0x3F) , sizeof(ahci_cmd_table_t) );
[283]357
[563]358    // update external memory for command descriptor
359    _mmc_sync( cmd_desc_paddr & (~0x3F) , sizeof(ahci_cmd_desc_t) );
[283]360
[563]361    // inval or synchronize memory buffer
362    if ( to_mem )  _mmc_inval( buf_paddr, count<<9 );
363    else           _mmc_sync( buf_paddr, count<<9 );
[283]364
[563]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
[603]375#if GIET_DEBUG_IOC
376if (_get_proctime() > GIET_DEBUG_IOC)
[563]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
[283]387        {
[563]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            }
[283]397        }
[563]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 );
[283]405    }
406
[563]407    /////////////////////////////////////////////////////////////////
[709]408    // in descheduling mode, we deschedule the thread
409    // and use an interrupt to reschedule the thread.
[630]410    // We need a critical section, because we must set the NORUN bit
[563]411        // before to launch the transfer, and we don't want to be
412    // descheduled between these two operations.
413    /////////////////////////////////////////////////////////////////
414    else
[283]415    {
416
[603]417#if GIET_DEBUG_IOC
418if (_get_proctime() > GIET_DEBUG_IOC)
[563]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;
[709]424        unsigned int ltid = _get_thread_ltid();
[283]425
[563]426        // activates interrupt
427        _sdc_set_register( AHCI_PXIE , 0x00000001 ); 
[283]428
[709]429        // set _ahci_trdid[ptw]
430        _ahci_trdid[ptw] = (x<<24) + (y<<16) + (p<<8) + ltid;
[283]431
[563]432        // enters critical section
433        _it_disable( &save_sr ); 
[283]434
[630]435        // Set NORUN_MASK_IOC bit
436        static_scheduler_t* psched  = (static_scheduler_t*)_schedulers[x][y][p];
[709]437        unsigned int*       ptr     = &psched->context[ltid].slot[CTX_NORUN_ID];
[630]438        _atomic_or( ptr , NORUN_MASK_IOC );
439       
[563]440        // start transfer
441        _sdc_set_register( AHCI_PXCI, (1<<ptw) );
[283]442
[709]443        // deschedule thread
[563]444        _ctx_switch();                     
[283]445
[603]446#if GIET_DEBUG_IOC
447if (_get_proctime() > GIET_DEBUG_IOC)
[709]448_printf("\n[DEBUG SDC] _sdc_access() : thread %d on P[%d,%d,%d] resume at cycle %d\n",
[563]449        ltid , x , y , p , _get_proctime() );
450#endif
[283]451
[563]452        // restore SR
453        _it_restore( &save_sr );
[283]454
[563]455        // get command status
456        pxis = _ahci_status[ptw];
457    }   
[283]458
[603]459#if GIET_DEBUG_IOC
460if (_get_proctime() > GIET_DEBUG_IOC)
[563]461_printf("\n[DEBUG SDC] _sdc_access() : P[%d,%d,%d] exit at cycle %d\n",
462        x , y , p , _get_proctime() );
463#endif
[283]464
[563]465    if ( pxis & 0x40000000 ) return pxis;
466    else                     return 0;
[283]467
[563]468} // end _sdc_access()
[529]469
[283]470
[545]471///////////////////////////////////////////////////////////////////////////////
[563]472// This ISR handles the IRQ generated by the AHCI_SDC controler
[545]473///////////////////////////////////////////////////////////////////////////////
474void _sdc_isr( unsigned int irq_type,
475               unsigned int irq_id,
476               unsigned int channel )
477{
[563]478    // get AHCI_PXCI containing commands status
479    unsigned int pxci = _sdc_get_register( AHCI_PXCI );
[545]480
[563]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    {
[657]486        unsigned int cmd_id = current & 0x1F;
[563]487       
[657]488        if ( (pxci & (1<<cmd_id)) == 0 )    // command completed
[563]489        {
490            // increment the 32 bits variable _ahci_cmd_ptr
491            _ahci_cmd_ptr++;
492
493            // save AHCI_PXIS register
[657]494            _ahci_status[cmd_id] = _sdc_get_register( AHCI_PXIS );
[563]495
496            // reset AHCI_PXIS register
497            _sdc_set_register( AHCI_PXIS , 0 );
498 
[709]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
[630]505            // Reset NORUN_MASK_IOC bit
506            static_scheduler_t* psched  = (static_scheduler_t*)_schedulers[x][y][p];
[709]507            _atomic_and( &psched->context[ltid].slot[CTX_NORUN_ID] , ~NORUN_MASK_IOC );
[563]508
[709]509            // send a WAKUP WTI to processor running the waiting thread
510            _xcu_send_wti( (x<<Y_WIDTH) + y,
[630]511                           p , 
[563]512                           0 );          // don't force context switch
513
[603]514#if GIET_DEBUG_IOC 
515if (_get_proctime() > GIET_DEBUG_IOC)
[563]516_printf("\n[DEBUG SDC] _sdc_isr() : command %d completed at cycle %d\n"
[709]517        "  resume thread %d running on P[%d,%d,%d] / status = %x\n",
[657]518        cmd_id , _get_proctime() ,
519        ltid , x , y , p , _ahci_status[cmd_id] );
[563]520#endif
521        }
522        else                         // command non completed
523        {
524            break;
525        }
[630]526    }  // end for completed commands
[563]527}  // end _sdc_isr()
528
[284]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.