////////////////////////////////////////////////////////////////////////////////// // File : hba_driver.c // Date : 23/11/2013 // Author : alain greiner // Copyright (c) UPMC-LIP6 /////////////////////////////////////////////////////////////////////////////////// // Implementation notes: // All accesses to HBA registers are done by the two // _hba_set_register() and _hba_get_register() low-level functions, // that are handling virtual / physical extended addressing. /////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #include /////////////////////////////////////////////////////////////////////////////////// // Global variables /////////////////////////////////////////////////////////////////////////////////// // global index ot the task, for each entry in the command list __attribute__((section(".kdata"))) unsigned int _hba_gtid[32]; // status of the command, for each entry in the command list __attribute__((section(".kdata"))) unsigned int _hba_status[32]; // command list : up to 32 commands __attribute__((section(".kdata"))) hba_cmd_desc_t _hba_cmd_list[32] __attribute__((aligned(0x40))); // command tables array : one command table per entry in command list __attribute__((section(".kdata"))) hba_cmd_table_t _hba_cmd_table[32] __attribute__((aligned(0x40))); // command list write index : next slot to register a command __attribute__((section(".kdata"))) unsigned int _hba_cmd_ptw; // command list read index : next slot to poll a completed command __attribute__((section(".kdata"))) unsigned int _hba_cmd_ptr; ////////////////////////////////////////////////////////////////////////////// // This low level function returns the value of register (index) ////////////////////////////////////////////////////////////////////////////// unsigned int _hba_get_register( unsigned int index ) { unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index; return _io_extended_read( vaddr ); } ////////////////////////////////////////////////////////////////////////////// // This low level function set a new value in register (index) ////////////////////////////////////////////////////////////////////////////// void _hba_set_register( unsigned int index, unsigned int value ) { unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index; _io_extended_write( vaddr, value ); } /////////////////////////////////////////////////////////////////////////////// // Extern functions /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // This function register a command in both the command list // and the command table, and updates the HBA_PXCI register. // return 0 if success, -1 if error /////////////////////////////////////////////////////////////////////////////// unsigned int _hba_access( unsigned int use_irq, unsigned int to_mem, unsigned int lba, unsigned long long buf_paddr, unsigned int count ) { unsigned int procid = _get_procid(); unsigned int x = procid >> (Y_WIDTH + P_WIDTH); unsigned int y = (procid >> P_WIDTH) & ((1<buffer.dba = (unsigned int)(buf_paddr); cmd_table->buffer.dbau = (unsigned int)(buf_paddr >> 32); cmd_table->buffer.dbc = count * 512; // initialize command table header cmd_table->header.lba0 = (char)lba; cmd_table->header.lba1 = (char)(lba>>8); cmd_table->header.lba2 = (char)(lba>>16); cmd_table->header.lba3 = (char)(lba>>24); cmd_table->header.lba4 = 0; cmd_table->header.lba5 = 0; // initialise command descriptor cmd_desc->prdtl[0] = 1; cmd_desc->prdtl[1] = 0; if( to_mem ) cmd_desc->flag[0] = 0x00; else cmd_desc->flag[0] = 0x40; #if USE_IOB // software L2/L3 cache coherence // compute physical addresses unsigned long long cmd_desc_paddr; // command descriptor physical address unsigned long long cmd_table_paddr; // command table header physical address unsigned int flags; // unused if ( _get_mmu_mode() & 0x4 ) { cmd_desc_paddr = _v2p_translate( (unsigned int)cmd_desc , &flags ); cmd_table_paddr = _v2p_translate( (unsigned int)cmd_table , &flags ); } else { cmd_desc_paddr = (unsigned int)cmd_desc; cmd_table_paddr = (unsigned int)cmd_table; } // update external memory for command table _mmc_sync( cmd_table_paddr & (~0x3F) , sizeof(hba_cmd_table_t) ); // update external memory for command descriptor _mmc_sync( cmd_desc_paddr & (~0x3F) , sizeof(hba_cmd_desc_t) ); // inval or synchronize memory buffer if ( to_mem ) _mmc_inval( buf_paddr, count<<9 ); else _mmc_sync( buf_paddr, count<<9 ); #endif // end software L2/L3 cache coherence ///////////////////////////////////////////////////////////////////// // In synchronous mode, we poll the PXCI register until completion ///////////////////////////////////////////////////////////////////// if ( use_irq == 0 ) { // start HBA transfer _hba_set_register( HBA_PXCI, (1<>32); } // initialise HBA registers _hba_set_register( HBA_PXCLB , (unsigned int)(cmd_list_paddr) ); _hba_set_register( HBA_PXCLBU , (unsigned int)(cmd_list_paddr>>32) ); _hba_set_register( HBA_PXIE , 0 ); _hba_set_register( HBA_PXIS , 0 ); _hba_set_register( HBA_PXCI , 0 ); _hba_set_register( HBA_PXCMD , 1 ); return 0; } ///////////////////////////////////////////////////// void _hba_isr( unsigned int irq_type, // HWI / WTI unsigned int irq_id, // index returned by ICU unsigned int channel ) // unused { // get HBA_PXCI containing commands status unsigned int pxci = _hba_get_register( HBA_PXCI ); // we must handle all completed commands // active commands are between (_hba_cmd_ptr) and (_hba_cmd_ptw-1) unsigned int current; for ( current = _hba_cmd_ptr ; current != _hba_cmd_ptw ; current++ ) { unsigned int ptr = current & 0x1F; if ( (pxci & (1<>16; unsigned int ltid = _hba_gtid[ptr] & 0xFFFF; unsigned int remote_cluster = remote_procid >> P_WIDTH; unsigned int remote_x = remote_cluster >> Y_WIDTH; unsigned int remote_y = remote_cluster & ((1<