Changeset 295 for soft/giet_vm/giet_drivers/bdv_driver.c
- Timestamp:
- Mar 26, 2014, 6:44:44 PM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
soft/giet_vm/giet_drivers/bdv_driver.c
r289 r295 10 10 // a single channel, block oriented, external storage contrÃŽler. 11 11 // 12 // It can exist only one block-device controler in the architecture. 13 // 14 // The _bdv_read() and _bdv_write() functions use the _bdv_access() function, 15 // that is always blocking, but can be called in 4 modes: 16 // 17 // - In BOOT_PA mode, the _bdv_access() function uses a polling policy on the 18 // IOC_STATUS register to detect transfer completion, as hardware interrupts 19 // are not activated. This mode is used by the boot code to load the map.bin 20 // file into memory. 21 // 22 // - In BOOT_VA mode, the _bdv_access() function uses a polling policy on 23 // IOC_STATUS register to detect transfer completion. This mode is used by 24 // the boot code to load the various .elf files into memory. 25 // 26 // - In KERNEL mode, the _bdv_access() function uses a descheduling strategy: 12 // The _bdv_read() and _bdv_write() functions are always blocking. 13 // They can be called in 3 modes: 14 // 15 // - In BOOT mode, these functions use a polling policy on the BDV STATUS 16 // register to detect transfer completion, as interrupts are not activated. 17 // This mode is used by the boot code to load the map.bin file into memory 18 // (before MMU activation), or to load the .elf files (after MMU activation). 19 // 20 // - In KERNEL mode, these functions use a descheduling strategy: 27 21 // The ISR executed when transfer completes should restart the calling task. 28 // There is no checking of user access right to the memory buffer. This mode29 // must be used to access IOC, for an "open" system call.30 // 31 // - In USER mode, the _bdv_access() function usesa descheduling strategy:22 // There is no checking of user access right to the memory buffer. 23 // This mode must be used, for an "open" system call. 24 // 25 // - In USER mode, these functions use a descheduling strategy: 32 26 // The ISR executed when transfer completes should restart the calling task, 33 27 // The user access right to the memory buffer must be checked. 34 // This mode must be used to access IOC,for a "read/write" system call.28 // This mode must be used for a "read/write" system call. 35 29 // 36 30 // As the BDV component can be used by several programs running in parallel, 37 // the _ ioc_lock variable guaranties exclusive access to the device. The31 // the _bdv_lock variable guaranties exclusive access to the device. The 38 32 // _bdv_read() and _bdv_write() functions use atomic LL/SC to get the lock. 39 33 // … … 47 41 // if the IOMMU is not activated. 48 42 // An error code is returned if these conditions are not verified. 49 /////////////////////////////////////////////////////////////////////////////////// 50 // The seg_ioc_base virtual base addresses must be defined in giet_vsegs.ld file. 43 // 44 // The "seg_ioc_base" must be defined in giet_vsegs.ld file. 45 /////////////////////////////////////////////////////////////////////////////////// 46 // Implementation notes: 47 // 48 // 1. In order to share code, the two _bdv_read() and _bdv_write() functions 49 // call the same _bdv_access() function. 50 // 51 // 2. All accesses to BDV registers are done by the two 52 // _bdv_set_register() and _bdv_get_register() low-level functions, 53 // that are handling virtual / physical extended addressing. 51 54 /////////////////////////////////////////////////////////////////////////////////// 52 55 53 56 #include <giet_config.h> 57 #include <bdv_driver.h> 58 #include <xcu_driver.h> 54 59 #include <ioc_driver.h> 55 #include <bdv_driver.h>56 60 #include <utils.h> 57 61 #include <tty_driver.h> … … 59 63 60 64 /////////////////////////////////////////////////////////////////////////////// 61 // _bdv_access() 65 // BDV global variables 66 /////////////////////////////////////////////////////////////////////////////// 67 68 #define in_unckdata __attribute__((section (".unckdata"))) 69 70 in_unckdata unsigned int _bdv_lock = 0; 71 in_unckdata volatile unsigned int _bdv_status = 0; 72 in_unckdata volatile unsigned int _bdv_gtid; 73 74 /////////////////////////////////////////////////////////////////////////////// 75 // This low_level function returns the value contained in register (index). 76 /////////////////////////////////////////////////////////////////////////////// 77 unsigned int _bdv_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 /////////////////////////////////////////////////////////////////////////////// 86 void _bdv_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 /////////////////////////////////////////////////////////////////////////////// 62 94 // This function transfer data between a memory buffer and the block device. 63 95 // The buffer lentgth is (count*block_size) bytes. … … 70 102 // Returns 0 if success, > 0 if error. 71 103 /////////////////////////////////////////////////////////////////////////////// 72 static unsigned int _bdv_access( unsigned int to_mem, 73 unsigned int mode, 74 unsigned int lba, 75 paddr_t buf_paddr, 76 unsigned int count) 77 { 78 79 #if GIET_DEBUG_IOC_DRIVER 80 _tty_get_lock( 0 ); 81 _puts("\n[IOC DEBUG] Enter _bdv_access() at cycle "); 82 _putd( _get_proctime() ); 83 _puts(" for processor "); 84 _putd( _get_procid() ); 85 _puts("\n - mode = "); 86 _putd( mode ); 87 _puts("\n - paddr = "); 88 _putx( buf_paddr ); 89 _puts("\n - sectors = "); 90 _putd( count ); 91 _puts("\n - lba = "); 92 _putx( lba ); 93 _puts("\n"); 94 _tty_release_lock( 0 ); 104 static unsigned int _bdv_access( unsigned int to_mem, 105 unsigned int mode, 106 unsigned int lba, 107 unsigned long long buf_paddr, 108 unsigned int count) 109 { 110 111 #if GIET_DEBUG_BDV_DRIVER 112 unsigned int procid = _get_procid(); 113 unsigned int cxy = procid / NB_PROCS_MAX; 114 unsigned int lpid = procid % NB_PROCS_MAX; 115 unsigned int x = cxy >> Y_WIDTH; 116 unsigned int y = cxy & ((1<<Y_WIDTH) - 1); 117 118 _printf("\n[BDV DEBUG] Processor[%d,%d,%d] enters _bdv_access() at cycle %d\n" 119 " - mode = %d\n" 120 " - paddr = %l\n" 121 " - sectors = %x\n" 122 " - lba = %x\n", 123 x, y, lpid, _get_proctime(), mode, buf_paddr, count, lba ); 95 124 #endif 96 125 97 volatile unsigned int * ioc_address = (unsigned int *) &seg_ioc_base ; 98 unsigned int error = 0; 99 100 // get the lock protecting IOC 101 _get_lock(&_ioc_lock); 102 103 // set the _ioc_status polling variable 104 _ioc_status = BLOCK_DEVICE_BUSY; 105 106 ioc_address[BLOCK_DEVICE_BUFFER] = (unsigned int)buf_paddr; 107 ioc_address[BLOCK_DEVICE_BUFFER_EXT] = (unsigned int)(buf_paddr>>32); 108 ioc_address[BLOCK_DEVICE_COUNT] = count; 109 ioc_address[BLOCK_DEVICE_LBA] = lba; 110 111 // There are two policies for transfer completion 112 // detection, depending on the mode argument: 113 114 if ( (mode == IOC_BOOT_PA_MODE) || // We poll directly the IOC_STATUS register 115 (mode == IOC_BOOT_VA_MODE) ) // as IRQs are masked. 126 unsigned int error = 0; 127 128 // get the lock protecting BDV 129 _get_lock(&_bdv_lock); 130 131 // set device registers 132 _bdv_set_register( BLOCK_DEVICE_BUFFER , (unsigned int)buf_paddr ); 133 _bdv_set_register( BLOCK_DEVICE_BUFFER_EXT, (unsigned int)(buf_paddr>>32) ); 134 _bdv_set_register( BLOCK_DEVICE_COUNT , count ); 135 _bdv_set_register( BLOCK_DEVICE_LBA , lba ); 136 137 // In BOOT mode, we launch transfer, and poll the BDV_STATUS 138 // register because IRQs are masked. 139 if ( mode == IOC_BOOT_MODE ) 116 140 { 117 141 // Launch transfert 118 if (to_mem == 0) ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_WRITE;119 else ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_READ;142 if (to_mem == 0) _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_WRITE ); 143 else _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_READ ); 120 144 121 145 unsigned int status; 122 146 do 123 147 { 124 if ( _bdv_get_status( 0, &status ) ) return 1; 125 126 #if GIET_DEBUG_IOC_DRIVER 127 _tty_get_lock( 0 ); 128 _puts("\n[IOC DEBUG] _bdv_access() : ... waiting on IOC_STATUS register ...\n"); 129 _tty_release_lock( 0 ); 148 status = _bdv_get_register( BLOCK_DEVICE_STATUS ); 149 150 #if GIET_DEBUG_BDV_DRIVER 151 _printf("\n[BDV DEBUG] _bdv_access() : ... waiting on BDV_STATUS register ...\n"); 130 152 #endif 131 153 } … … 133 155 (status != BLOCK_DEVICE_READ_ERROR) && 134 156 (status != BLOCK_DEVICE_WRITE_SUCCESS) && 135 (status != BLOCK_DEVICE_WRITE_ERROR) ); 157 (status != BLOCK_DEVICE_WRITE_ERROR) ); // busy waiting 136 158 137 159 // analyse status … … 140 162 141 163 // release lock 142 _release_lock(&_ ioc_lock);164 _release_lock(&_bdv_lock); 143 165 } 144 else // in USER or KERNEL mode, we deschedule the task. 145 // When the task is rescheduled by the ISR, we reset 146 // the _ioc_status variable, and release the lock 166 // in USER or KERNEL mode, we deschedule the task. 167 // When the task is rescheduled, we check the _bdv_status variable, 168 // and release the lock. 169 // We need a critical section, because we must reset the RUN bit 170 // before to launch the transfer, and we don't want to be descheduled 171 // between these two operations. 172 else 147 173 { 148 // We need a critical section, because we must reset the RUN bit 149 // before to launch the transfer, and we want to avoid to be descheduled 150 // between these two operations. 151 152 // Enter critical section 153 _it_disable(); 174 unsigned int save_sr; 175 unsigned int ltid = _get_current_task_id(); 176 unsigned int gpid = _get_procid(); 177 178 // activates BDV interrupts 179 _bdv_set_register( BLOCK_DEVICE_IRQ_ENABLE, 1 ); 180 181 // set the _bdv_status variable 182 _bdv_status = BLOCK_DEVICE_BUSY; 183 184 // enters critical section 185 _it_disable( &save_sr ); 154 186 155 // set _ioc_gtid and reset runnable 156 unsigned int ltid = _get_proc_task_id(); 157 unsigned int pid = _get_procid(); 158 _ioc_gtid = (pid<<16) + ltid; 159 _set_task_slot( pid, ltid, CTX_RUN_ID, 0 ); 187 // set _bdv_gtid and reset runnable 188 _bdv_gtid = (gpid<<16) + ltid; 189 _set_task_slot( gpid, ltid, CTX_RUN_ID, 0 ); 160 190 161 // Launch transfert162 if (to_mem == 0) ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_WRITE;163 else ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_READ;191 // launch transfer 192 if (to_mem == 0) _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_WRITE ); 193 else _bdv_set_register( BLOCK_DEVICE_OP, BLOCK_DEVICE_READ ); 164 194 165 195 // deschedule task 166 196 _ctx_switch(); 167 197 198 // restore SR 199 _it_restore( &save_sr ); 200 168 201 // analyse status 169 error = ( (_ ioc_status == BLOCK_DEVICE_READ_ERROR) ||170 (_ ioc_status == BLOCK_DEVICE_WRITE_ERROR) );171 172 // reset _ ioc_status and release lock173 _ ioc_status = BLOCK_DEVICE_IDLE;174 _release_lock(&_ ioc_lock);202 error = ( (_bdv_status == BLOCK_DEVICE_READ_ERROR) || 203 (_bdv_status == BLOCK_DEVICE_WRITE_ERROR) ); 204 205 // reset _bdv_status and release lock 206 _bdv_status = BLOCK_DEVICE_IDLE; 207 _release_lock(&_bdv_lock); 175 208 } 176 209 177 #if GIET_DEBUG_IOC_DRIVER 178 _tty_get_lock( 0 ); 179 _puts("\n[IOC DEBUG] _bdv_access completed at cycle "); 180 _putd( _get_proctime() ); 181 _puts(" for processor "); 182 _putd( _get_procid() ); 183 _puts(" : error = "); 184 _putd( (unsigned int)error ); 185 _puts("\n"); 186 _tty_release_lock( 0 ); 210 #if GIET_DEBUG_BDV_DRIVER 211 _printf("\n[BDV DEBUG] Processor[%d,%d,%d] exit _bdv_access() at cycle %d\n", 212 x, y, lpid, _get_proctime() ); 187 213 #endif 188 214 … … 191 217 192 218 /////////////////////////////////////////////////////////////////////////////// 193 // _bdv_init() 194 // This function cheks block size, and activates the IOC interrupts. 219 // This function cheks block size, and desactivates the interrupts. 195 220 // Return 0 for success, > 0 if error 196 221 /////////////////////////////////////////////////////////////////////////////// 197 unsigned int _bdv_init( unsigned int channel ) 198 { 199 volatile unsigned int * ioc_address = (unsigned int *) &seg_ioc_base ; 200 201 if ( ioc_address[BLOCK_DEVICE_BLOCK_SIZE] != 512 ) 222 unsigned int _bdv_init() 223 { 224 if ( _bdv_get_register( BLOCK_DEVICE_BLOCK_SIZE ) != 512 ) 202 225 { 203 _tty_get_lock( 0 ); 204 _puts("\n[GIET ERROR] in _bdv_init() : block size must be 512 bytes\n"); 205 _tty_release_lock( 0 ); 226 _printf("\n[GIET ERROR] in _bdv_init() : block size must be 512 bytes\n"); 206 227 return 1; 207 228 } 208 229 209 if ( channel != 0 ) 210 { 211 _tty_get_lock( 0 ); 212 _puts("\n[GIET ERROR] in _bdv_init() : illegal channel\n"); 213 _tty_release_lock( 0 ); 214 215 return 1; 216 } 217 218 ioc_address[BLOCK_DEVICE_IRQ_ENABLE] = 1; 230 _bdv_set_register( BLOCK_DEVICE_IRQ_ENABLE, 0 ); 219 231 return 0; 220 232 } 221 233 222 234 /////////////////////////////////////////////////////////////////////////////// 223 // _bdv_read()224 235 // Transfer data from the block device to a memory buffer. 225 236 // - mode : BOOT / KERNEL / USER … … 229 240 // Returns 0 if success, > 0 if error. 230 241 /////////////////////////////////////////////////////////////////////////////// 231 unsigned int _bdv_read( unsigned int mode,232 unsigned int lba,233 paddr_tbuffer,234 unsigned int count)242 unsigned int _bdv_read( unsigned int mode, 243 unsigned int lba, 244 unsigned long long buffer, 245 unsigned int count) 235 246 { 236 247 return _bdv_access( 1, // read access … … 242 253 243 254 /////////////////////////////////////////////////////////////////////////////// 244 // _bdv_write()245 255 // Transfer data from a memory buffer to the block device. 246 256 // - mode : BOOT / KERNEL / USER … … 250 260 // Returns 0 if success, > 0 if error. 251 261 /////////////////////////////////////////////////////////////////////////////// 252 unsigned int _bdv_write( unsigned int mode,253 unsigned int lba,254 paddr_tbuffer,255 unsigned int count )262 unsigned int _bdv_write( unsigned int mode, 263 unsigned int lba, 264 unsigned long long buffer, 265 unsigned int count ) 256 266 { 257 267 return _bdv_access( 0, // write access … … 263 273 264 274 /////////////////////////////////////////////////////////////////////////////// 265 // _bdv_get_status() 266 // This function returns in the status variable, the transfert status, and 267 // acknowledge the IRQ if the IOC controler is not busy. 268 // Returns 0 if success, > 0 if error 269 /////////////////////////////////////////////////////////////////////////////// 270 unsigned int _bdv_get_status( unsigned int channel, 271 unsigned int* status ) 272 { 273 if ( channel != 0 ) 274 { 275 _tty_get_lock( 0 ); 276 _puts("\n[GIET ERROR] in _bdv_get_status() : illegal channel\n"); 277 _tty_release_lock( 0 ); 278 279 return 1; 280 } 281 282 // get IOC base address 283 volatile unsigned int * ioc_address = (unsigned int *) &seg_ioc_base; 284 *status = ioc_address[BLOCK_DEVICE_STATUS]; 285 286 return 0; 287 } 288 289 /////////////////////////////////////////////////////////////////////////////// 290 // _bdv_get_block_size() 291 // This function returns the block_size with which the IOC has been configured. 292 /////////////////////////////////////////////////////////////////////////////// 293 unsigned int _bdv_get_block_size() 294 { 295 // get IOC base address 296 volatile unsigned int * ioc_address = (unsigned int *) &seg_ioc_base; 297 298 return ioc_address[BLOCK_DEVICE_BLOCK_SIZE]; 275 // Returns device status. 276 /////////////////////////////////////////////////////////////////////////////// 277 unsigned int _bdv_get_status() 278 { 279 return _bdv_get_register( BLOCK_DEVICE_STATUS ); 280 } 281 282 /////////////////////////////////////////////////////////////////////////////// 283 // Returns block size. 284 /////////////////////////////////////////////////////////////////////////////// 285 unsigned int _bdv_get_block_size() 286 { 287 return _bdv_get_register( BLOCK_DEVICE_BLOCK_SIZE ); 288 } 289 290 /////////////////////////////////////////////////////////////////////////////////// 291 // This ISR save the status, acknowledge the IRQ, 292 // and activates the task waiting on IO transfer. 293 // It can be an HWI or a SWI. 294 // 295 // TODO the _set_task_slot access should be replaced by an atomic LL/SC 296 // when the CTX_RUN bool will be replaced by a bit_vector. 297 /////////////////////////////////////////////////////////////////////////////////// 298 void _bdv_isr( unsigned int irq_type, // HWI / WTI 299 unsigned int irq_id, // index returned by ICU 300 unsigned int channel ) // unused 301 { 302 unsigned int procid = _get_procid(); 303 unsigned int cluster_xy = procid / NB_PROCS_MAX; 304 unsigned int lpid = procid % NB_PROCS_MAX; 305 306 // acknowledge WTI in local XCU if required 307 unsigned int value; 308 if ( irq_type == IRQ_TYPE_WTI ) _xcu_get_wti_value( cluster_xy, irq_id, &value ); 309 310 // save status in _bdv_status variable and reset IRQ 311 _bdv_status = _bdv_get_register( BLOCK_DEVICE_STATUS ); 312 313 // identify task waiting on BDV 314 unsigned int rprocid = _bdv_gtid>>16; 315 unsigned int ltid = _bdv_gtid & 0xFFFF; 316 unsigned int remote_xy = rprocid / NB_PROCS_MAX; 317 318 #if GIET_DEBUG_IRQS // we don't take the TTY lock to avoid deadlock 319 unsigned int x = cluster_xy >> Y_WIDTH; 320 unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1); 321 unsigned int rx = remote_xy >> Y_WIDTH; 322 unsigned int ry = remote_xy & ((1<<Y_WIDTH)-1); 323 unsigned int rlpid = rprocid % NB_PROCS_MAX; 324 _puts("\n[IRQS DEBUG] Processor["); 325 _putd(x ); 326 _puts(","); 327 _putd(y ); 328 _puts(","); 329 _putd(lpid ); 330 _puts("] enters _bdv_isr() at cycle "); 331 _putd(_get_proctime() ); 332 _puts("\n for task "); 333 _putd(ltid ); 334 _puts(" running on processor["); 335 _putd(rx ); 336 _puts(","); 337 _putd(ry ); 338 _puts(","); 339 _putd(rlpid ); 340 _puts(" / bdv status = "); 341 _putx(_bdv_status ); 342 _puts("\n"); 343 #endif 344 345 // re-activates sleeping task 346 _set_task_slot( rprocid, // global processor index 347 ltid, // local task index on processor 348 CTX_RUN_ID, // CTX_RUN slot 349 1 ); // running 350 351 // requires a context switch for remote processor running the waiting task 352 _xcu_send_wti( remote_xy, // cluster index 353 lpid, // local processor index 354 0 ); // don't force context switch if not idle 299 355 } 300 356
Note: See TracChangeset
for help on using the changeset viewer.