| [283] | 1 | /////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [284] | 2 | // File      : bdv_driver.c | 
|---|
 | 3 | // Date      : 23/05/2013 | 
|---|
| [529] | 4 | // Author    : alain greiner cesar fuguet | 
|---|
| [283] | 5 | // Copyright (c) UPMC-LIP6 | 
|---|
 | 6 | /////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [295] | 7 | // Implementation notes: | 
|---|
| [529] | 8 | // All accesses to BDV registers are done by the two | 
|---|
 | 9 | // _bdv_set_register() and _bdv_get_register() low-level functions, | 
|---|
 | 10 | // that are handling virtual / physical extended addressing. | 
|---|
| [283] | 11 | /////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 12 |  | 
|---|
 | 13 | #include <giet_config.h> | 
|---|
| [320] | 14 | #include <hard_config.h> | 
|---|
| [295] | 15 | #include <bdv_driver.h> | 
|---|
 | 16 | #include <xcu_driver.h> | 
|---|
| [545] | 17 | #include <mmc_driver.h> | 
|---|
| [529] | 18 | #include <kernel_locks.h> | 
|---|
| [283] | 19 | #include <utils.h> | 
|---|
| [456] | 20 | #include <tty0.h> | 
|---|
| [283] | 21 | #include <ctx_handler.h> | 
|---|
| [529] | 22 | #include <irq_handler.h> | 
|---|
| [283] | 23 |  | 
|---|
 | 24 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| [529] | 25 | //      Global variables | 
|---|
| [295] | 26 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 27 |  | 
|---|
| [529] | 28 | // lock protecting single channel BDV peripheral | 
|---|
| [496] | 29 | __attribute__((section(".kdata"))) | 
|---|
| [456] | 30 | spin_lock_t  _bdv_lock __attribute__((aligned(64))); | 
|---|
| [496] | 31 |  | 
|---|
| [529] | 32 | // global index of the waiting task (only used in descheduling mode) | 
|---|
| [496] | 33 | __attribute__((section(".kdata"))) | 
|---|
| [529] | 34 | unsigned int _bdv_gtid; | 
|---|
| [496] | 35 |  | 
|---|
| [529] | 36 | // BDV peripheral status (only used in descheduling mode) | 
|---|
| [496] | 37 | __attribute__((section(".kdata"))) | 
|---|
| [529] | 38 | unsigned int _bdv_status; | 
|---|
| [295] | 39 |  | 
|---|
 | 40 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 41 | // This low_level function returns the value contained in register (index). | 
|---|
 | 42 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 43 | unsigned int _bdv_get_register( unsigned int index ) | 
|---|
 | 44 | { | 
|---|
| [320] | 45 |     unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index; | 
|---|
| [295] | 46 |     return _io_extended_read( vaddr ); | 
|---|
 | 47 | } | 
|---|
 | 48 |  | 
|---|
 | 49 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 50 | // This low-level function set a new value in register (index). | 
|---|
 | 51 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 52 | void _bdv_set_register( unsigned int index, | 
|---|
 | 53 |                         unsigned int value )  | 
|---|
 | 54 | { | 
|---|
| [320] | 55 |     unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + index; | 
|---|
| [295] | 56 |     _io_extended_write( vaddr, value ); | 
|---|
 | 57 | } | 
|---|
 | 58 |  | 
|---|
 | 59 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| [529] | 60 | //      Extern functions | 
|---|
| [283] | 61 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| [529] | 62 |  | 
|---|
 | 63 | ///////////////////////////////////////////////////// | 
|---|
 | 64 | unsigned int _bdv_access( unsigned int       use_irq, | 
|---|
 | 65 |                           unsigned int       to_mem, | 
|---|
 | 66 |                           unsigned int       lba, | 
|---|
 | 67 |                           unsigned long long buf_paddr, | 
|---|
 | 68 |                           unsigned int       count)  | 
|---|
| [283] | 69 | { | 
|---|
| [426] | 70 |     unsigned int procid  = _get_procid(); | 
|---|
 | 71 |     unsigned int x       = procid >> (Y_WIDTH + P_WIDTH); | 
|---|
 | 72 |     unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH) - 1); | 
|---|
 | 73 |     unsigned int p       = procid & ((1<<P_WIDTH)-1); | 
|---|
| [283] | 74 |  | 
|---|
| [313] | 75 | #if GIET_DEBUG_IOC_DRIVER | 
|---|
| [529] | 76 | _printf("\n[BDV DEBUG] P[%d,%d,%d] enters _bdv_access at cycle %d\n" | 
|---|
 | 77 |         "  use_irq = %d / to_mem = %d / lba = %x / paddr = %l / count = %d\n", | 
|---|
 | 78 |         x , y , p , _get_proctime() , use_irq , to_mem , lba , buf_paddr, count ); | 
|---|
| [283] | 79 | #endif | 
|---|
 | 80 |  | 
|---|
| [529] | 81 |     // check buffer alignment | 
|---|
 | 82 |     if( buf_paddr & 0x1FF ) | 
|---|
 | 83 |     { | 
|---|
 | 84 |         _printf("\n[BDV ERROR] in _bdv_access() : buffer not block aligned\n"); | 
|---|
 | 85 |         return -1; | 
|---|
 | 86 |     } | 
|---|
| [283] | 87 |  | 
|---|
| [529] | 88 |     unsigned int error; | 
|---|
 | 89 |     unsigned int status; | 
|---|
 | 90 |  | 
|---|
| [295] | 91 |     // get the lock protecting BDV | 
|---|
| [469] | 92 |     _spin_lock_acquire( &_bdv_lock ); | 
|---|
| [283] | 93 |  | 
|---|
| [295] | 94 |     // set device registers | 
|---|
 | 95 |     _bdv_set_register( BLOCK_DEVICE_BUFFER    , (unsigned int)buf_paddr ); | 
|---|
 | 96 |     _bdv_set_register( BLOCK_DEVICE_BUFFER_EXT, (unsigned int)(buf_paddr>>32) ); | 
|---|
 | 97 |     _bdv_set_register( BLOCK_DEVICE_COUNT     , count ); | 
|---|
 | 98 |     _bdv_set_register( BLOCK_DEVICE_LBA       , lba ); | 
|---|
| [283] | 99 |  | 
|---|
| [545] | 100 | #if USE_IOB    // software L2/L3 cache coherence | 
|---|
 | 101 |     if ( to_mem )  _mmc_inval( buf_paddr, count<<9 ); | 
|---|
 | 102 |     else           _mmc_sync( buf_paddr, count<<9 ); | 
|---|
 | 103 | #endif     // end software L2/L3 cache coherence | 
|---|
 | 104 |  | 
|---|
| [529] | 105 |     ///////////////////////////////////////////////////////////////////// | 
|---|
 | 106 |     // In synchronous mode, we launch transfer,  | 
|---|
 | 107 |     // and poll the BDV_STATUS register until completion. | 
|---|
 | 108 |     ///////////////////////////////////////////////////////////////////// | 
|---|
 | 109 |     if ( use_irq == 0 )  | 
|---|
| [283] | 110 |     { | 
|---|
 | 111 |         // Launch transfert | 
|---|
| [295] | 112 |         if (to_mem == 0) _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_WRITE ); | 
|---|
 | 113 |         else             _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_READ ); | 
|---|
| [283] | 114 |  | 
|---|
| [333] | 115 | #if GIET_DEBUG_IOC_DRIVER | 
|---|
| [529] | 116 | _printf("\n[BDV DEBUG] _bdv_access() : P[%d,%d,%d] launch transfer" | 
|---|
 | 117 |         " in polling mode at cycle %d\n", | 
|---|
 | 118 |         x , y , p , _get_proctime() ); | 
|---|
| [333] | 119 | #endif | 
|---|
| [529] | 120 |  | 
|---|
| [289] | 121 |         do | 
|---|
| [283] | 122 |         { | 
|---|
| [295] | 123 |             status = _bdv_get_register( BLOCK_DEVICE_STATUS ); | 
|---|
| [283] | 124 |  | 
|---|
| [313] | 125 | #if GIET_DEBUG_IOC_DRIVER | 
|---|
| [529] | 126 | _printf("\n[BDV DEBUG] _bdv_access() : P[%d,%d,%d] wait on BDV_STATUS ...\n", | 
|---|
 | 127 |         x , y , p ); | 
|---|
| [283] | 128 | #endif | 
|---|
| [289] | 129 |         } | 
|---|
 | 130 |         while( (status != BLOCK_DEVICE_READ_SUCCESS)  && | 
|---|
 | 131 |                (status != BLOCK_DEVICE_READ_ERROR)    && | 
|---|
 | 132 |                (status != BLOCK_DEVICE_WRITE_SUCCESS) && | 
|---|
| [295] | 133 |                (status != BLOCK_DEVICE_WRITE_ERROR)   );      // busy waiting | 
|---|
| [283] | 134 |  | 
|---|
 | 135 |         // analyse status | 
|---|
 | 136 |         error = ( (status == BLOCK_DEVICE_READ_ERROR) || | 
|---|
 | 137 |                   (status == BLOCK_DEVICE_WRITE_ERROR) ); | 
|---|
| [529] | 138 |     } | 
|---|
| [283] | 139 |  | 
|---|
| [529] | 140 |     ///////////////////////////////////////////////////////////////// | 
|---|
 | 141 |     // in descheduling mode, we deschedule the task | 
|---|
 | 142 |     // and use an interrupt to reschedule the task. | 
|---|
| [295] | 143 |     // We need a critical section, because we must reset the RUN bit | 
|---|
| [529] | 144 |         // before to launch the transfer, and we don't want to be  | 
|---|
 | 145 |     // descheduled between these two operations.  | 
|---|
 | 146 |     ///////////////////////////////////////////////////////////////// | 
|---|
| [295] | 147 |     else | 
|---|
| [283] | 148 |     { | 
|---|
| [295] | 149 |         unsigned int save_sr; | 
|---|
| [529] | 150 |         unsigned int wti_index; | 
|---|
| [295] | 151 |         unsigned int ltid = _get_current_task_id(); | 
|---|
| [283] | 152 |  | 
|---|
| [529] | 153 |         // activates BDV interrupt | 
|---|
| [295] | 154 |         _bdv_set_register( BLOCK_DEVICE_IRQ_ENABLE, 1 ); | 
|---|
 | 155 |  | 
|---|
| [529] | 156 |         // allocate a WTI mailbox to the calling proc if external IRQ | 
|---|
 | 157 |         if ( USE_PIC ) _ext_irq_alloc( ISR_BDV , 0 , &wti_index ); | 
|---|
| [295] | 158 |  | 
|---|
| [545] | 159 |         // set _bdv_gtid  | 
|---|
 | 160 |         _bdv_gtid = (procid<<16) + ltid; | 
|---|
 | 161 |  | 
|---|
| [295] | 162 |         // enters critical section | 
|---|
 | 163 |         _it_disable( &save_sr );  | 
|---|
| [320] | 164 |  | 
|---|
| [545] | 165 |         // reset runnable  | 
|---|
| [426] | 166 |         _set_task_slot( x, y, p, ltid, CTX_RUN_ID, 0 );   | 
|---|
| [283] | 167 |          | 
|---|
| [295] | 168 |         // launch transfer | 
|---|
 | 169 |         if (to_mem == 0) _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_WRITE ); | 
|---|
 | 170 |         else             _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_READ  ); | 
|---|
| [283] | 171 |  | 
|---|
| [333] | 172 | #if GIET_DEBUG_IOC_DRIVER | 
|---|
| [529] | 173 | _printf("\n[BDV DEBUG] _bdv_access() : P[%d,%d,%d] launch transfer" | 
|---|
 | 174 |         " in descheduling mode at cycle %d\n", | 
|---|
 | 175 |         x , y , p , _get_proctime() ); | 
|---|
| [333] | 176 | #endif | 
|---|
| [437] | 177 |  | 
|---|
| [283] | 178 |         // deschedule task | 
|---|
 | 179 |         _ctx_switch();                       | 
|---|
 | 180 |  | 
|---|
| [426] | 181 | #if GIET_DEBUG_IOC_DRIVER | 
|---|
| [529] | 182 | _printf("\n[BDV DEBUG] _bdv_access() : P[%d,%d,%d] resume execution at cycle %d\n", | 
|---|
 | 183 |         x , y , p , _get_proctime() ); | 
|---|
| [426] | 184 | #endif | 
|---|
| [529] | 185 |  | 
|---|
 | 186 |         // release WTI mailbox if external IRQ | 
|---|
 | 187 |         if ( USE_PIC ) _ext_irq_release( ISR_BDV , 0 , wti_index ); | 
|---|
 | 188 |  | 
|---|
| [295] | 189 |         // restore SR | 
|---|
 | 190 |         _it_restore( &save_sr ); | 
|---|
 | 191 |  | 
|---|
| [283] | 192 |         // analyse status | 
|---|
| [295] | 193 |         error = ( (_bdv_status == BLOCK_DEVICE_READ_ERROR) || | 
|---|
 | 194 |                   (_bdv_status == BLOCK_DEVICE_WRITE_ERROR) ); | 
|---|
| [283] | 195 |     } | 
|---|
 | 196 |  | 
|---|
| [529] | 197 |     // release lock | 
|---|
 | 198 |     _spin_lock_release( &_bdv_lock );       | 
|---|
 | 199 |  | 
|---|
| [313] | 200 | #if GIET_DEBUG_IOC_DRIVER | 
|---|
| [529] | 201 | _printf("\n[BDV DEBUG] _bdv_access() : P[%d,%d,%d] exit at cycle %d\n", | 
|---|
 | 202 |         x , y , p , _get_proctime() ); | 
|---|
| [283] | 203 | #endif | 
|---|
 | 204 |  | 
|---|
 | 205 |     return error; | 
|---|
 | 206 | } // end _bdv_access() | 
|---|
 | 207 |  | 
|---|
| [437] | 208 | //////////////////////// | 
|---|
| [295] | 209 | unsigned int _bdv_init() | 
|---|
| [283] | 210 | { | 
|---|
| [295] | 211 |     if ( _bdv_get_register( BLOCK_DEVICE_BLOCK_SIZE ) != 512 ) | 
|---|
| [283] | 212 |     { | 
|---|
| [437] | 213 |         _puts("\n[GIET ERROR] in _bdv_init() : block size must be 512 bytes\n"); | 
|---|
| [283] | 214 |         return 1;  | 
|---|
 | 215 |     } | 
|---|
 | 216 |  | 
|---|
| [295] | 217 |     _bdv_set_register( BLOCK_DEVICE_IRQ_ENABLE, 0 ); | 
|---|
| [283] | 218 |     return 0; | 
|---|
 | 219 | } | 
|---|
 | 220 |  | 
|---|
| [437] | 221 | ///////////////////////////////////// | 
|---|
| [295] | 222 | void _bdv_isr( unsigned int irq_type,   // HWI / WTI | 
|---|
 | 223 |                unsigned int irq_id,     // index returned by ICU | 
|---|
 | 224 |                unsigned int channel )   // unused  | 
|---|
 | 225 | { | 
|---|
| [529] | 226 |     // get BDV status and reset BDV_IRQ | 
|---|
| [297] | 227 |     unsigned int status =  _bdv_get_register( BLOCK_DEVICE_STATUS );  | 
|---|
| [295] | 228 |  | 
|---|
| [297] | 229 |     // check status: does nothing if IDLE or BUSY | 
|---|
 | 230 |     if ( (status == BLOCK_DEVICE_IDLE) || | 
|---|
 | 231 |          (status == BLOCK_DEVICE_BUSY) )   return; | 
|---|
 | 232 |   | 
|---|
| [529] | 233 |     // register status in global variable | 
|---|
 | 234 |     _bdv_status = status; | 
|---|
| [295] | 235 |  | 
|---|
 | 236 |     // identify task waiting on BDV | 
|---|
| [426] | 237 |     unsigned int remote_procid  = _bdv_gtid>>16; | 
|---|
 | 238 |     unsigned int ltid           = _bdv_gtid & 0xFFFF; | 
|---|
 | 239 |     unsigned int remote_cluster = remote_procid >> P_WIDTH; | 
|---|
 | 240 |     unsigned int remote_x       = remote_cluster >> Y_WIDTH; | 
|---|
 | 241 |     unsigned int remote_y       = remote_cluster & ((1<<Y_WIDTH)-1); | 
|---|
 | 242 |     unsigned int remote_p       = remote_procid & ((1<<P_WIDTH)-1); | 
|---|
| [295] | 243 |  | 
|---|
| [297] | 244 |     // re-activates sleeping task | 
|---|
| [426] | 245 |     _set_task_slot( remote_x, | 
|---|
 | 246 |                     remote_y, | 
|---|
 | 247 |                     remote_p, | 
|---|
 | 248 |                     ltid,         | 
|---|
| [297] | 249 |                     CTX_RUN_ID,  // CTX_RUN slot  | 
|---|
| [529] | 250 |                     1 );         // running value | 
|---|
| [297] | 251 |  | 
|---|
| [529] | 252 |     // send a WAKUP WTI to processor running the sleeping task  | 
|---|
| [426] | 253 |     _xcu_send_wti( remote_cluster,    | 
|---|
 | 254 |                    remote_p,  | 
|---|
| [529] | 255 |                    0 );          // don't force context switch  | 
|---|
| [297] | 256 |  | 
|---|
| [529] | 257 | #if GIET_DEBUG_IOC_DRIVER   | 
|---|
| [426] | 258 | unsigned int procid  = _get_procid(); | 
|---|
 | 259 | unsigned int x       = procid >> (Y_WIDTH + P_WIDTH); | 
|---|
 | 260 | unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1); | 
|---|
 | 261 | unsigned int p       = procid & ((1<<P_WIDTH)-1); | 
|---|
| [529] | 262 | _printf("\n[IOC DEBUG] Processor[%d,%d,%d] enters _bdv_isr() at cycle %d\n" | 
|---|
 | 263 |         "  for task %d running on P[%d,%d,%d] / bdv_status = %x\n", | 
|---|
 | 264 |         x , y , p , _get_proctime() , | 
|---|
 | 265 |         ltid , remote_x , remote_y , remote_p , status ); | 
|---|
| [295] | 266 | #endif | 
|---|
 | 267 |  | 
|---|
| [529] | 268 | } // end bdv_isr() | 
|---|
| [295] | 269 |  | 
|---|
 | 270 |  | 
|---|
| [283] | 271 | // Local Variables: | 
|---|
 | 272 | // tab-width: 4 | 
|---|
 | 273 | // c-basic-offset: 4 | 
|---|
 | 274 | // c-file-offsets:((innamespace . 0)(inline-open . 0)) | 
|---|
 | 275 | // indent-tabs-mode: nil | 
|---|
 | 276 | // End: | 
|---|
 | 277 | // vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4 | 
|---|
 | 278 |  | 
|---|