Changeset 289 for soft/giet_vm/giet_drivers/ioc_driver.c
- Timestamp:
- Feb 4, 2014, 2:16:37 AM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
soft/giet_vm/giet_drivers/ioc_driver.c
r279 r289 1 1 /////////////////////////////////////////////////////////////////////////////////// 2 // File : ioc_driver.c 3 // Date : 23/05/2013 4 // Author : alain greiner 2 // File : ioc_driver.c 3 // Date : 23/05/2013 4 // Author : alain greiner 5 // Maintainer : cesar fuguet 5 6 // Copyright (c) UPMC-LIP6 6 7 /////////////////////////////////////////////////////////////////////////////////// … … 12 13 // 13 14 // The _ioc_read() and _ioc_write() functions use the _ioc_access() function, 14 // that is always blocking , but can be called in 4 modes:15 // 16 // - In BOOT_PA mode, the _ioc_access() function use the buffer virtual address17 // as a physical address (as the page tables are not build) and use a polling18 // policy on the IOC_STATUS register to detect transfer completion, as19 // hardware interrupts are not activated. This mode is used by the20 // boot code to load the map.bin file into memory.15 // that is always blocking. The _ioc_access function will call the read or 16 // write function in the driver of the choosen IOC peripheral, which can be for 17 // now: BDV, HBA and SPI. This function can be called in 4 modes: 18 // 19 // - In BOOT_PA mode, the _ioc_access() function use the buffer virtual address 20 // as a physical address (as the page tables are not build). This mode is 21 // used by the boot code to load the map.bin file into memory. 21 22 // 22 23 // - In BOOT_VA mode, the _ioc_access() function makes a V2P translation to 23 // compute the buffer physical address, and use a polling policy on IOC_STATUS 24 // register to detect transfer completion. This mode is used by the boot code 25 // to load the various .elf files into memory. 24 // compute the buffer physical address. This mode is used by the boot code to 25 // load the various .elf files into memory. 26 26 // 27 27 // - In KERNEL mode, the _ioc_access() function makes a V2P translation to 28 // compute the buffer physical address, and use a descheduling strategy: 29 // The ISR executed when transfer completes should restart the calling task. 30 // There is no checking of user access right to the memory buffer. 31 // This mode must be used to access IOC, for an "open" system call. 28 // compute the buffer physical address. There is no checking of user access 29 // right to the memory buffer. This mode must be used to access IOC, for an 30 // "open" system call. 32 31 // 33 32 // - In USER mode, the _ioc_access() function makes a V2P translation to 34 // compute the buffer physical address, and use a descheduling strategy: 35 // The ISR executed when transfer completes should restart the calling task, 36 // The user access right to the memory buffer must be checked. 37 // This mode must be used to access IOC, for a "read/write" system call. 38 // 39 // As the IOC component can be used by several programs running in parallel, 40 // the _ioc_lock variable guaranties exclusive access to the device. The 41 // _ioc_read() and _ioc_write() functions use atomic LL/SC to get the lock. 33 // compute the buffer physical address. The user access right to the memory 34 // buffer must be checked. This mode must be used to access IOC, for a 35 // "read/write" system call. 42 36 // 43 37 // The IOMMU can be activated or not: … … 87 81 #endif 88 82 83 #if (USE_BDV + USE_SPI + USE_HBA) != 1 84 # error: You must use only one IOC controller (BDV or SPI or HBA) 85 #endif 86 87 #if USE_BDV 88 # include <bdv_driver.h> 89 #endif 90 91 #if USE_SPI 92 # include <sdc_driver.h> 93 #endif 94 95 #if USE_HBA 96 # include <hba_driver.h> 97 #endif 98 99 89 100 #define in_unckdata __attribute__((section (".unckdata"))) 90 101 91 102 ///////////////////// IOC global variables 92 103 93 in_unckdata unsigned int 94 in_unckdata volatileunsigned int _ioc_status = 0;104 in_unckdata unsigned int _ioc_lock = 0; 105 in_unckdata unsigned int _ioc_status = 0; 95 106 in_unckdata volatile unsigned int _ioc_gtid; 96 107 in_unckdata volatile unsigned int _ioc_iommu_ix1 = 0; … … 155 166 } 156 167 157 volatile unsigned int * ioc_address = (unsigned int *) &seg_ioc_base ;158 159 168 unsigned int length = count << 9; // count * 512 bytes 160 169 … … 269 278 } 270 279 271 // get the lock protecting IOC 272 _get_lock(&_ioc_lock); 273 274 // set the _ioc_status polling variable 275 _ioc_status = BLOCK_DEVICE_BUSY; 276 277 #if GIET_DEBUG_IOC_DRIVER 278 _tty_get_lock( 0 ); 279 _puts("\n[IOC DEBUG] _ioc_access() : configure IOC\n"); 280 _puts(" - buf_paddr = "); 281 _putl( buf_paddr ); 282 _puts("\n"); 283 _puts(" - count = "); 284 _putd( count ); 285 _puts("\n"); 286 _puts(" - lba = "); 287 _putx( lba ); 288 _puts("\n"); 289 _tty_release_lock( 0 ); 290 #endif 291 292 // send command to IOC 293 if ( GIET_USE_IOMMU ) 294 { 295 ioc_address[BLOCK_DEVICE_BUFFER] = buf_xaddr; 296 ioc_address[BLOCK_DEVICE_COUNT] = count; 297 ioc_address[BLOCK_DEVICE_LBA] = lba; 298 } 299 else 300 { 301 ioc_address[BLOCK_DEVICE_BUFFER] = (unsigned int)buf_paddr; 302 ioc_address[BLOCK_DEVICE_BUFFER_EXT] = (unsigned int)(buf_paddr>>32); 303 ioc_address[BLOCK_DEVICE_COUNT] = count; 304 ioc_address[BLOCK_DEVICE_LBA] = lba; 305 } 306 307 // There is two policies for transfer completion 308 // detection, depending on the mode argument: 309 310 if ( (mode == IOC_BOOT_PA_MODE) || // We poll directly the IOC_STATUS register 311 (mode == IOC_BOOT_VA_MODE) ) // as IRQs are masked. 312 { 313 // Launch transfert 314 if (to_mem == 0) ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_WRITE; 315 else ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_READ; 316 317 unsigned int status; 318 if ( _ioc_get_status(0, &status) ) return 1; 319 320 while( (status != BLOCK_DEVICE_READ_SUCCESS) && 321 (status != BLOCK_DEVICE_READ_ERROR) && 322 (status != BLOCK_DEVICE_WRITE_SUCCESS) && 323 (status != BLOCK_DEVICE_WRITE_ERROR) ) 324 { 325 if ( _ioc_get_status(0, &status) ) return 1; 326 327 #if GIET_DEBUG_IOC_DRIVER 328 _tty_get_lock( 0 ); 329 _puts("\n[IOC DEBUG] _ioc_access() : ... waiting on IOC_STATUS register ...\n"); 330 _tty_release_lock( 0 ); 331 #endif 332 333 } 334 // analyse status 335 error = ( (status == BLOCK_DEVICE_READ_ERROR) || 336 (status == BLOCK_DEVICE_WRITE_ERROR) ); 337 338 // release lock 339 _release_lock(&_ioc_lock); 340 } 341 else // in USER or KERNEL mode, we deschedule the task. 342 // When the task is rescheduled by the ISR, we reset 343 // the _ioc_status variable, and release the lock 344 { 345 // We need a critical section, because we must reset the RUN bit 346 // before to launch the transfer, and we want to avoid to be descheduled 347 // between these two operations. 348 349 // Enter critical section 350 _it_disable(); 351 352 // set _ioc_gtid and reset runnable 353 unsigned int ltid = _get_proc_task_id(); 354 unsigned int pid = _get_procid(); 355 _ioc_gtid = (pid<<16) + ltid; 356 _set_task_slot( pid, ltid, CTX_RUN_ID, 0 ); 357 358 // Launch transfert 359 if (to_mem == 0) ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_WRITE; 360 else ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_READ; 361 362 // deschedule task 363 _ctx_switch(); 364 365 // analyse status 366 error = ( (_ioc_status == BLOCK_DEVICE_READ_ERROR) || 367 (_ioc_status == BLOCK_DEVICE_WRITE_ERROR) ); 368 369 // reset _ioc_status and release lock 370 _ioc_status = BLOCK_DEVICE_IDLE; 371 _release_lock(&_ioc_lock); 372 } 373 374 #if GIET_DEBUG_IOC_DRIVER 375 _tty_get_lock( 0 ); 376 _puts("\n[IOC DEBUG] _ioc_access completed at cycle "); 377 _putd( _get_proctime() ); 378 _puts(" for processor "); 379 _putd( _get_procid() ); 380 _puts(" : error = "); 381 _putd( (unsigned int)error ); 382 _puts("\n"); 383 _tty_release_lock( 0 ); 280 if ( GIET_USE_IOMMU ) buf_paddr = (paddr_t) buf_xaddr; 281 282 #if USE_BDV 283 if (to_mem) error = _bdv_read (mode, lba, buf_paddr, count); 284 else error = _bdv_write(mode, lba, buf_paddr, count); 285 #elif USE_SPI 286 if (to_mem) error = _sdc_read (mode, lba, buf_paddr, count); 287 else error = _sdc_write(mode, lba, buf_paddr, count); 288 #elif USE_HBA 289 if (to_mem) error = _hba_read (mode, lba, buf_paddr, count); 290 else error = _hba_write(mode, lba, buf_paddr, count); 384 291 #endif 385 292 … … 392 299 // Return 0 for success. 393 300 /////////////////////////////////////////////////////////////////////////////// 394 unsigned int _ioc_init() 395 { 396 volatile unsigned int * ioc_address = (unsigned int *) &seg_ioc_base ; 397 398 if ( ioc_address[BLOCK_DEVICE_BLOCK_SIZE] != 512 ) 399 { 400 _puts("\n[GIET ERROR] in _ioc_init() : block size must be 512 bytes\n"); 401 _exit(); 402 } 403 404 ioc_address[BLOCK_DEVICE_IRQ_ENABLE] = 1; 405 return 0; 301 unsigned int _ioc_init( unsigned int channel ) 302 { 303 #if USE_BDV 304 return _bdv_init( channel ); 305 #elif USE_SPI 306 return _sdc_init( channel ); 307 #elif USE_HBA 308 return _hba_init( channel ); 309 #endif 406 310 } 407 311 … … 457 361 unsigned int* status ) 458 362 { 459 if ( channel != 0 ) 460 { 461 _tty_get_lock( 0 ); 462 _puts("\n[GIET ERROR] in _ioc_get_status : illegal channel\n"); 463 _tty_release_lock( 0 ); 464 465 return 1; 466 } 467 468 // get IOC base address 469 volatile unsigned int * ioc_address = (unsigned int *) &seg_ioc_base; 470 *status = ioc_address[BLOCK_DEVICE_STATUS]; 471 472 return 0; 363 #if USE_BDV 364 return _bdv_get_status(channel, status); 365 #elif USE_SPI 366 return _sdc_get_status(channel, status); 367 #elif USE_HBA 368 return _hba_get_status(channel, status); 369 #endif 473 370 } 474 371 … … 479 376 unsigned int _ioc_get_block_size() 480 377 { 481 // get IOC base address 482 volatile unsigned int * ioc_address = (unsigned int *) &seg_ioc_base; 483 484 return ioc_address[BLOCK_DEVICE_BLOCK_SIZE]; 378 #if USE_BDV 379 return _bdv_get_block_size(); 380 #elif USE_SPI 381 return _sdc_get_block_size(); 382 #elif USE_HBA 383 return _hba_get_block_size(); 384 #endif 485 385 } 486 386
Note: See TracChangeset
for help on using the changeset viewer.