Changeset 189 for soft/giet_vm/sys/drivers.c
- Timestamp:
- Aug 7, 2012, 6:37:49 PM (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
soft/giet_vm/sys/drivers.c
r169 r189 5 5 // Copyright (c) UPMC-LIP6 6 6 /////////////////////////////////////////////////////////////////////////////////// 7 // The drivers.c and drivers.h files are part ot the GIET nano kernel.7 // The drivers.c and drivers.h files are part ot the GIET-VM nano kernel. 8 8 // They contains the drivers for the peripherals available in the SoCLib library: 9 9 // - vci_multi_tty … … 11 11 // - vci_multi_dma 12 12 // - vci_multi_icu 13 // - vci_xicu 13 14 // - vci_gcd 14 15 // - vci_frame_buffer … … 16 17 // 17 18 // The following global parameters must be defined in the giet_config.h file: 18 // - NB_CLUSTERS : number of clusters 19 // - NB_PROCS : number of PROCS per cluster 20 // - NB_TIMERS : number of TIMERS per cluster 21 // - NB_DMAS : number of DMA channels 22 // - NB_TTYS : number of TTY terminals 23 // - NB_TIMERS : number of TIMERS per cluster 24 // - CLUSTER_SPAN : address increment between clusters 19 // - NB_CLUSTERS 20 // - NB_PROCS_MAX 21 // - NB_TIMERS_MAX 22 // - NB_DMAS_MAX 23 // - NB_TTYS 25 24 // 26 25 // The following base addresses must be defined in the sys.ld file: … … 43 42 #include <ctx_handler.h> 44 43 45 #if !defined(NB_PROCS)46 # error: You must define NB_PROCS in 'giet_config.h' file!47 #endif48 44 #if !defined(NB_CLUSTERS) 49 # error: You must define NB_CLUSTERS in 'giet_config.h' file! 50 #endif 45 # error: You must define NB_CLUSTERS in 'giet_config.h' file 46 #endif 47 48 #if !defined(NB_PROCS_MAX) 49 # error: You must define NB_PROCS_MAX in 'giet_config.h' file 50 #endif 51 52 #if (NB_PROCS_MAX > 8) 53 # error: NB_PROCS_MAX cannot be larger than 8! 54 #endif 55 51 56 #if !defined(CLUSTER_SPAN) 52 # error: You must define CLUSTER_SPAN in 'giet_config.h' file! 53 #endif 57 # error: You must define CLUSTER_SPAN in 'giet_config.h' file 58 #endif 59 54 60 #if !defined(NB_TTYS) 55 # error: You must define NB_TTYS in 'giet_config.h' file! 56 #endif 57 #if !defined(NB_DMAS) 58 # error: You must define NB_DMAS in 'giet_config.h' file! 59 #endif 60 #if !defined(NB_TIMERS) 61 # error: You must define NB_TIMERS in 'giet_config.h' file! 61 # error: You must define NB_TTYS in 'giet_config.h' file 62 62 #endif 63 63 … … 66 66 #endif 67 67 68 #if (NB_TIMERS < NB_PROCS) 69 # error: NB_TIMERS must be larger or equal to NB_PROCS! 70 #endif 71 72 #if (NB_PROCS > 8) 73 # error: NB_PROCS cannot be larger than 8! 74 #endif 75 76 #if (NB_DMAS < 1) 77 # error: NB_DMAS cannot be 0! 78 #endif 79 80 81 ///////////////////////////////////////////////////////////////////////////// 82 // Global (uncachable) variables 83 ///////////////////////////////////////////////////////////////////////////// 68 #if !defined(NB_DMAS_MAX) 69 # error: You must define NB_DMAS_MAX in 'giet_config.h' file 70 #endif 71 72 #if (NB_DMAS_MAX < 1) 73 # error: NB_DMAS_MAX cannot be 0! 74 #endif 75 76 #if !defined(NB_TIMERS_MAX) 77 # error: You must define NB_TIMERS_MAX in 'giet_config.h' file 78 #endif 79 80 #if ( (NB_TIMERS_MAX + NB_PROCS_MAX) > 32 ) 81 # error: NB_TIMERS_MAX + NB_PROCS_MAX cannot be larger than 32 82 #endif 83 84 #if !defined(NB_IOCS) 85 # error: You must define NB_IOCS in 'giet_config.h' file 86 #endif 87 88 #if ( NB_IOCS > 1 ) 89 # error: NB_IOCS cannot be larger than 1 90 #endif 91 84 92 85 93 #define in_unckdata __attribute__((section (".unckdata"))) 86 94 87 // IOC variables 88 in_unckdata volatile unsigned char _ioc_status = 0; 89 in_unckdata volatile unsigned char _ioc_done = 0; 90 in_unckdata unsigned int _ioc_lock = 0; 91 in_unckdata unsigned int _ioc_iommu_ix1 = 0; 92 in_unckdata unsigned int _ioc_iommu_npages; 93 94 // DMA variables 95 in_unckdata volatile unsigned int _dma_status[NB_DMAS]; 96 in_unckdata volatile unsigned char _dma_busy[NB_DMAS] = { [0 ... NB_DMAS-1] = 0 }; 97 in_unckdata volatile unsigned char _dma_iommu_ix1 = 1; 98 in_unckdata volatile unsigned char _dma_iommu_npages[NB_DMAS]; 95 96 ////////////////////////////////////////////////////////////////////////////// 97 // VciMultiTimer driver 98 ////////////////////////////////////////////////////////////////////////////// 99 // There is one multi_timer (or xicu) component per cluster. 100 // The global index is cluster_id*(NB_PROCS_MAX+NB_TIMERS_MAX) + local_id 101 // There is two types of timers: 102 // - "system" timers : one per processor, used for context switch. 103 // local_id in [0, NB_PROCS_MAX-1], 104 // - "user" timers : requested by the task in the mapping_info data structure. 105 // local_id in [NB_PROC_MAX, NB_PROCS_MAX+NB_TIMERS_MAX-1], 106 // For each user timer, the tty_id is stored in the context of the task 107 // and must be explicitely defined in the boot code. 108 // These timers can be implemented in a vci_multi_timer component 109 // or in a vci_xicu component (depending on the GIET_USE_XICU parameter). 110 ////////////////////////////////////////////////////////////////////////////// 111 112 // User Timer signaling variables 113 114 #if (NB_TIMERS_MAX > 0) 115 in_unckdata volatile unsigned char _user_timer_event[NB_CLUSTERS*NB_TIMERS_MAX] 116 = { [0 ... ((NB_CLUSTERS*NB_TIMERS_MAX)-1)] = 0 }; 117 #endif 118 119 ////////////////////////////////////////////////////////////////////////////// 120 // _timer_access() 121 // This function is the only way to access a timer device. 122 // It can be a multi-timer component or an xicu component. 123 // It can be used by the kernel to initialise a "system" timer, 124 // or by a task (through a system call) to configure an "user" timer. 125 // Returns 0 if success, > 0 if error. 126 ////////////////////////////////////////////////////////////////////////////// 127 unsigned int _timer_access( unsigned int read, 128 unsigned int cluster_id, 129 unsigned int local_id, 130 unsigned int register_id, 131 unsigned int* buffer ) 132 { 133 // parameters checking 134 if ( register_id >= TIMER_SPAN) return 1; 135 if ( cluster_id >= NB_CLUSTERS) return 1; 136 if ( local_id >= NB_TIMERS_MAX + NB_PROCS_MAX ) return 1; 137 138 #if GIET_USE_XICU 139 140 unsigned int* timer_address = //TODO 141 142 #else 143 144 unsigned int* timer_address = (unsigned int*)&seg_timer_base + 145 (cluster_id * CLUSTER_SPAN) + 146 (local_id * TIMER_SPAN); 147 #endif 148 149 if (read) *buffer = timer_address[register_id]; // read word 150 else timer_address[register_id] = *buffer; // write word 151 return 0; 152 } 153 ////////////////////////////////////////////////////////////////////////////// 154 // _timer_write() 155 // This function implements a write access to a "user" timer register. 156 // It gets the cluster_id and local_id from the global index stored in 157 // the task context and use the timer_access() function to make the write. 158 // Returns 0 if success, > 0 if error. 159 ////////////////////////////////////////////////////////////////////////////// 160 unsigned int _timer_write( unsigned int register_id, 161 unsigned int value ) 162 { 163 unsigned int buffer = value; 164 unsigned int timer_id = _get_current_context_slot(CTX_TIMER_ID); 165 unsigned int cluster_id = timer_id / (NB_PROCS_MAX + NB_TIMERS_MAX); 166 unsigned int local_id = timer_id % (NB_PROCS_MAX + NB_TIMERS_MAX); 167 168 // checking user timer 169 if ( local_id < NB_PROCS_MAX ) 170 { 171 return 2; 172 } 173 else 174 { 175 return _timer_access ( 0, // write access 176 cluster_id, 177 local_id, 178 register_id, 179 &buffer ); 180 } 181 } 182 ////////////////////////////////////////////////////////////////////////////// 183 // _timer_read() 184 // This function implements a read access to a "user" timer register. 185 // It gets the cluster_id and local_id from the global index stored in 186 // the task context and use the timer_access() function to make the read. 187 // Returns 0 if success, > 0 if error. 188 ////////////////////////////////////////////////////////////////////////////// 189 unsigned int _timer_read( unsigned int register_id, 190 unsigned int* buffer ) 191 { 192 unsigned int timer_id = _get_current_context_slot(CTX_TIMER_ID); 193 unsigned int cluster_id = timer_id / (NB_PROCS_MAX + NB_TIMERS_MAX); 194 unsigned int local_id = timer_id % (NB_PROCS_MAX + NB_TIMERS_MAX); 195 196 // checking user timer 197 if ( local_id < NB_PROCS_MAX ) 198 { 199 return 2; 200 } 201 else 202 { 203 return _timer_access ( 1, // read access 204 cluster_id, 205 local_id, 206 register_id, 207 buffer ); 208 } 209 } 210 ///////////////////////////////////////////////////////////////////////////////// 211 // _timer_check() 212 ///////////////////////////////////////////////////////////////////////////////// 213 214 ///////////////////////////////////////////////////////////////////////////////// 215 // VciMultiTty driver 216 ///////////////////////////////////////////////////////////////////////////////// 217 // There is only one multi_tty controler in the architecture. 218 // The total number of TTYs is defined by the configuration parameter NB_TTYS. 219 // The "system" terminal is TTY[0]. 220 // The "user" TTYs are allocated to applications by the GIET in the boot phase, 221 // as defined in the mapping_info data structure. The corresponding tty_id must 222 // be stored in the context of the task by the boot code. 223 // The TTY address is : seg_tty_base + tty_id*TTY_SPAN 224 ///////////////////////////////////////////////////////////////////////////////// 99 225 100 226 // TTY variables 101 227 in_unckdata volatile unsigned char _tty_get_buf[NB_TTYS]; 102 228 in_unckdata volatile unsigned char _tty_get_full[NB_TTYS] = { [0 ... NB_TTYS-1] = 0 }; 103 in_unckdata unsigned int _tty_put_lock = 0; 104 105 ////////////////////////////////////////////////////////////////////////////// 106 // VciMultiTimer driver 107 ////////////////////////////////////////////////////////////////////////////// 108 // There is one MULTI-TIMER component per cluster. 109 // The number of timers per cluster must be larger or equal to the number 110 // processors (NB_TIMERS >= NB_PROCS), because each processor uses a private 111 // yimer for context switch. 112 // The total number of timers is NB_CLUSTERS * NB_TIMERS 113 // The global timer index = cluster_id*NB_TIMERS + timer_id 114 ////////////////////////////////////////////////////////////////////////////// 115 116 ////////////////////////////////////////////////////////////////////////////// 117 // _timer_write() 118 // 119 // Write a 32-bit word in a memory mapped register of a timer device, 120 // identified by the cluster index and the local timer index. 121 // Returns 0 if success, > 0 if error. 122 ////////////////////////////////////////////////////////////////////////////// 123 unsigned int _timer_write( unsigned int cluster_index, 124 unsigned int timer_index, 125 unsigned int register_index, 126 unsigned int value ) 127 { 128 unsigned int* timer_address; 129 130 // parameters checking 131 if ( register_index >= TIMER_SPAN) return 1; 132 if ( cluster_index >= NB_CLUSTERS) return 1; 133 if ( timer_index >= NB_TIMERS ) return 1; 134 135 timer_address = (unsigned int*)&seg_timer_base + 136 ( cluster_index * CLUSTER_SPAN ) + 137 ( timer_index * TIMER_SPAN ); 138 139 timer_address[register_index] = value; // write word 140 141 return 0; 142 } 143 144 ////////////////////////////////////////////////////////////////////////////// 145 // _timer_read() 146 // 147 // Read a 32-bit word in a memory mapped register of a timer device, 148 // identified by the cluster index and the local timer index. 149 // Returns 0 if success, > 0 if error. 150 ////////////////////////////////////////////////////////////////////////////// 151 unsigned int _timer_read(unsigned int cluster_index, 152 unsigned int timer_index, 153 unsigned int register_index, 154 unsigned int *buffer) 155 { 156 unsigned int *timer_address; 157 158 // parameters checking 159 if ( register_index >= TIMER_SPAN) return 1; 160 if ( cluster_index >= NB_CLUSTERS) return 1; 161 if ( timer_index >= NB_TIMERS ) return 1; 162 163 timer_address = (unsigned int*)&seg_timer_base + 164 ( cluster_index * CLUSTER_SPAN ) + 165 ( timer_index * TIMER_SPAN ); 166 167 *buffer = timer_address[register_index]; // read word 168 169 return 0; 170 } 171 229 in_unckdata unsigned int _tty_put_lock = 0; // protect kernel TTY[0] 230 231 //////////////////////////////////////////////////////////////////////////////// 232 // _tty_error() 233 //////////////////////////////////////////////////////////////////////////////// 234 void _tty_error() 235 { 236 unsigned int task_id = _get_current_task_id(); 237 unsigned int proc_id = _procid(); 238 239 _get_lock(&_tty_put_lock); 240 _puts("\n[GIET ERROR] TTY index too large for task "); 241 _putw( task_id ); 242 _puts(" on processor "); 243 _putw( proc_id ); 244 _puts("\n"); 245 _release_lock(&_tty_put_lock); 246 } 172 247 ///////////////////////////////////////////////////////////////////////////////// 173 // VciMultiTty driver 174 ///////////////////////////////////////////////////////////////////////////////// 175 // The total number of TTYs is defined by the configuration parameter NB_TTYS. 176 // The system terminal is TTY[0]. 177 // The TTYs are allocated to applications by the GIET in the boot phase. 178 // The nummber of TTYs allocated to each application, and used by each 179 // task can be defined in the mapping_info data structure. 180 // For each user task, the tty_id is stored in the context of the task (slot 34), 181 // and must be explicitely defined in the boot code. 182 // The TTY address is always computed as : seg_tty_base + tty_id*TTY_SPAN 183 /////////////////////////////////////////////////////////////////////////////////// 184 185 ////////////////////////////////////////////////////////////////////////////// 186 // _tty_write() 187 // 248 // _tty_write() 188 249 // Write one or several characters directly from a fixed-length user buffer to 189 250 // the TTY_WRITE register of the TTY controler. … … 192 253 // the transfer as soon as the TTY_STATUS[WRITE] bit is set. 193 254 // The function returns the number of characters that have been written. 194 ////////////////////////////////////////////////////////////////////////////// 255 ///////////////////////////////////////////////////////////////////////////////// 195 256 unsigned int _tty_write( const char *buffer, 196 257 unsigned int length) 197 258 { 198 volatile unsigned int *tty_address; 199 200 unsigned int proc_id; 201 unsigned int task_id; 202 unsigned int tty_id; 203 unsigned int nwritten; 204 205 proc_id = _procid(); 206 207 task_id = _scheduler[proc_id].current; 208 tty_id = _scheduler[proc_id].context[task_id][CTX_TTY_ID]; 209 210 tty_address = (unsigned int*)&seg_tty_base + tty_id*TTY_SPAN; 259 unsigned int nwritten; 260 261 unsigned int tty_id = _get_current_context_slot(CTX_TTY_ID); 262 if ( tty_id >= NB_TTYS ) 263 { 264 _tty_error(); 265 return 0; 266 } 267 268 unsigned int* tty_address = (unsigned int*)&seg_tty_base + tty_id*TTY_SPAN; 211 269 212 270 for (nwritten = 0; nwritten < length; nwritten++) … … 221 279 return nwritten; 222 280 } 223 224 281 ////////////////////////////////////////////////////////////////////////////// 225 // _tty_read_irq() 226 // 282 // _tty_read_irq() 227 283 // This non-blocking function uses the TTY_GET_IRQ[tty_id] interrupt and 228 284 // the associated kernel buffer, that has been written by the ISR. … … 235 291 unsigned int length) 236 292 { 237 unsigned int proc_id; 238 unsigned int task_id; 239 unsigned int tty_id; 240 unsigned int ret; 241 242 proc_id = _procid(); 243 task_id = _scheduler[proc_id].current; 244 tty_id = _scheduler[proc_id].context[task_id][CTX_TTY_ID]; 293 unsigned int tty_id = _get_current_context_slot(CTX_TTY_ID); 294 295 if ( tty_id >= NB_TTYS ) 296 { 297 _tty_error(); 298 return 0; 299 } 245 300 246 301 if (_tty_get_full[tty_id] == 0) 247 302 { 248 ret =0;303 return 0; 249 304 } 250 305 else … … 252 307 *buffer = _tty_get_buf[tty_id]; 253 308 _tty_get_full[tty_id] = 0; 254 ret = 1; 255 } 256 return ret; 257 } 258 259 //////////////////////////////////////////////////////////////////////////////// 260 // _tty_read() 261 // 309 return 1; 310 } 311 } 312 //////////////////////////////////////////////////////////////////////////////// 313 // _tty_read() 262 314 // This non-blocking function fetches one character directly from the TTY_READ 263 315 // register of the TTY controler, and writes this character to the user buffer. … … 268 320 unsigned int length) 269 321 { 270 volatile unsigned int *tty_address; 271 272 unsigned int proc_id; 273 unsigned int task_id; 274 unsigned int tty_id; 275 276 proc_id = _procid(); 277 task_id = _scheduler[proc_id].current; 278 tty_id = _scheduler[proc_id].context[task_id][CTX_TTY_ID]; 279 280 tty_address = (unsigned int*)&seg_tty_base + tty_id*TTY_SPAN; 281 282 if ((tty_address[TTY_STATUS] & 0x1) != 0x1) return 0; 283 284 *buffer = (char)tty_address[TTY_READ]; 285 return 1; 286 } 287 288 //////////////////////////////////////////////////////////////////////////////// 289 // VciMultiIcu driver 290 //////////////////////////////////////////////////////////////////////////////// 291 // There is in principle one MULTI-ICU component per cluster, and the 292 // number of independant ICUs is equal to NB_PROCS, because there is 293 // one ICU per processor. 294 //////////////////////////////////////////////////////////////////////////////// 295 296 //////////////////////////////////////////////////////////////////////////////// 297 // _icu_write() 298 // 322 unsigned int tty_id = _get_current_context_slot(CTX_TTY_ID); 323 if ( tty_id >= NB_TTYS ) 324 { 325 _tty_error(); 326 return 0; 327 } 328 329 unsigned int* tty_address = (unsigned int*)&seg_tty_base + tty_id*TTY_SPAN; 330 331 if ((tty_address[TTY_STATUS] & 0x1) != 0x1) 332 { 333 return 0; 334 } 335 else 336 { 337 *buffer = (char)tty_address[TTY_READ]; 338 return 1; 339 } 340 } 341 342 //////////////////////////////////////////////////////////////////////////////// 343 // VciMultiIcu and VciXicu drivers 344 //////////////////////////////////////////////////////////////////////////////// 345 // There is in principle one vci_multi_icu (or vci_xicu) component per cluster, 346 // and the number of independant ICUs is equal to NB_PROCS_MAX, because there is 347 // one private interrupr controler per processor. 348 //////////////////////////////////////////////////////////////////////////////// 349 350 //////////////////////////////////////////////////////////////////////////////// 351 // _icu_write() 299 352 // Write a 32-bit word in a memory mapped register of the MULTI_ICU device, 300 353 // identified by the cluster index, and a processor local index. … … 306 359 unsigned int value ) 307 360 { 308 unsigned int *icu_address; 361 #if GIET_USE_XICU 362 363 #else 309 364 310 365 // parameters checking 311 366 if ( register_index >= ICU_SPAN) return 1; 312 367 if ( cluster_index >= NB_CLUSTERS) return 1; 313 if ( proc_index >= NB_PROCS )return 1;314 315 icu_address = (unsigned int*)&seg_icu_base +316 ( cluster_index * CLUSTER_SPAN) +317 ( proc_index * ICU_SPAN);368 if ( proc_index >= NB_PROCS_MAX ) return 1; 369 370 unsigned int *icu_address = (unsigned int*)&seg_icu_base + 371 (cluster_index * CLUSTER_SPAN) + 372 (proc_index * ICU_SPAN); 318 373 319 374 icu_address[register_index] = value; // write word 320 375 return 0; 321 } 322 323 //////////////////////////////////////////////////////////////////////////////// 324 // _icu_read()325 // 376 377 #endif 378 } 379 //////////////////////////////////////////////////////////////////////////////// 380 // _icu_read() 326 381 // Read a 32-bit word in a memory mapped register of the MULTI_ICU device, 327 382 // identified by the cluster index and a processor local index. … … 333 388 unsigned int* buffer ) 334 389 { 335 unsigned int *icu_address; 390 #if GIET_USE_XICU 391 392 #else 336 393 337 394 // parameters checking 338 395 if ( register_index >= ICU_SPAN) return 1; 339 396 if ( cluster_index >= NB_CLUSTERS) return 1; 340 if ( proc_index >= NB_PROCS )return 1;341 342 icu_address = (unsigned int*)&seg_icu_base +343 ( cluster_index * CLUSTER_SPAN) +344 ( proc_index * ICU_SPAN);397 if ( proc_index >= NB_PROCS_MAX ) return 1; 398 399 unsigned int *icu_address = (unsigned int*)&seg_icu_base + 400 (cluster_index * CLUSTER_SPAN) + 401 (proc_index * ICU_SPAN); 345 402 346 403 *buffer = icu_address[register_index]; // read word 347 404 return 0; 405 406 #endif 348 407 } 349 408 … … 357 416 358 417 //////////////////////////////////////////////////////////////////////////////// 359 // _gcd_write() 360 // 418 // _gcd_write() 361 419 // Write a 32-bit word in a memory mapped register of the GCD coprocessor. 362 420 // Returns 0 if success, > 0 if error. … … 376 434 return 0; 377 435 } 378 379 //////////////////////////////////////////////////////////////////////////////// 380 // _gcd_read() 381 // 436 //////////////////////////////////////////////////////////////////////////////// 437 // _gcd_read() 382 438 // Read a 32-bit word in a memory mapped register of the GCD coprocessor. 383 439 // Returns 0 if success, > 0 if error. … … 448 504 /////////////////////////////////////////////////////////////////////////////// 449 505 506 // IOC global variables 507 in_unckdata volatile unsigned int _ioc_status = 0; 508 in_unckdata volatile unsigned int _ioc_done = 0; 509 in_unckdata unsigned int _ioc_lock = 0; 510 in_unckdata unsigned int _ioc_iommu_ix1 = 0; 511 in_unckdata unsigned int _ioc_iommu_npages; 512 450 513 /////////////////////////////////////////////////////////////////////////////// 451 // _ioc_get_lock() 452 // 453 // This blocking helper is used by '_ioc_read()' and '_ioc_write()' functions 454 // to get _ioc_lock using atomic LL/SC. 455 /////////////////////////////////////////////////////////////////////////////// 456 static inline void _ioc_get_lock() 457 { 458 register unsigned int delay = (_proctime() & 0xF) << 4; 459 register unsigned int *plock = (unsigned int*)&_ioc_lock; 460 461 asm volatile ( 462 "_ioc_llsc: \n" 463 "ll $2, 0(%0) \n" /* $2 <= _ioc_lock current value */ 464 "bnez $2, _ioc_delay \n" /* delay if _ioc_lock already taken */ 465 "li $3, 1 \n" /* $3 <= argument for sc */ 466 "sc $3, 0(%0) \n" /* try to set _ioc_lock */ 467 "bnez $3, _ioc_ok \n" /* exit if atomic */ 468 "_ioc_delay: \n" 469 "move $4, %1 \n" /* $4 <= delay */ 470 "_ioc_loop: \n" 471 "beqz $4, _ioc_loop \n" /* test end delay */ 472 "addi $4, $4, -1 \n" /* $4 <= $4 - 1 */ 473 "j _ioc_llsc \n" /* retry ll */ 474 "nop \n" 475 "_ioc_ok: \n" 476 : 477 :"r"(plock), "r"(delay) 478 :"$2", "$3", "$4"); 479 } 480 481 /////////////////////////////////////////////////////////////////////////////// 482 // _ioc_access() 514 // _ioc_access() 483 515 // This function transfer data between a memory buffer and the block device. 484 516 // The buffer lentgth is (count*block_size) bytes. 485 //486 517 // Arguments are: 487 518 // - to_mem : from external storage to memory when non 0 … … 503 534 unsigned int ix2; // page index in IOMMU PT1 page table 504 535 unsigned int addr; // buffer address for IOC peripheral 505 unsigned int user_ptp; // page table pointer in user space506 unsigned int ko; // bool returned by _v2p_translate()507 536 unsigned int ppn_first; // first physical page number for user buffer 508 unsigned int ltid; // current task local index509 static_scheduler_t* psched; // pointer on the current task scheduler510 537 511 538 // check buffer alignment … … 517 544 518 545 // get user space page table virtual address 519 psched = &_scheduler[_procid()]; 520 ltid = psched->current; 521 user_ptp = psched->context[ltid][CTX_PTAB_ID]; 546 unsigned int user_pt_vbase = _get_current_context_slot(CTX_PTAB_ID); 522 547 523 548 user_vpn_min = user_vaddr >> 12; … … 529 554 { 530 555 // get ppn and flags for each vpn 531 ko = _v2p_translate( (page_table_t*)user_ptp,532 vpn,533 &ppn,534 &flags );556 unsigned int ko = _v2p_translate( (page_table_t*)user_pt_vbase, 557 vpn, 558 &ppn, 559 &flags ); 535 560 536 561 // check access rights … … 573 598 574 599 // get the lock on ioc device 575 _ ioc_get_lock();600 _get_lock( &_ioc_lock ); 576 601 577 602 // peripheral configuration … … 584 609 return 0; 585 610 } 586 587 611 ///////////////////////////////////////////////////////////////////////////////// 588 612 // _ioc_completed() … … 630 654 return ret; 631 655 } 632 633 656 /////////////////////////////////////////////////////////////////////////////// 634 // _ioc_read()657 // _ioc_read() 635 658 // Transfer data from the block device to a memory buffer in user space. 636 659 // - lba : first block index on the block device … … 643 666 unsigned int count ) 644 667 { 645 return _ioc_access( 1, // read 668 return _ioc_access( 1, // read access 646 669 lba, 647 670 (unsigned int)buffer, 648 671 count ); 649 672 } 650 651 673 /////////////////////////////////////////////////////////////////////////////// 652 // _ioc_write()674 // _ioc_write() 653 675 // Transfer data from a memory buffer in user space to the block device. 654 676 // - lba : first block index on the block device … … 661 683 unsigned int count ) 662 684 { 663 return _ioc_access( 0, // write 685 return _ioc_access( 0, // write access 664 686 lba, 665 687 (unsigned int)buffer, … … 668 690 669 691 ////////////////////////////////////////////////////////////////////////////////// 692 // VciMultiDma driver 693 ////////////////////////////////////////////////////////////////////////////////// 694 // The DMA controllers are physically distributed in the clusters. 695 // There is (NB_CLUSTERS * NB_DMAS_MAX) channels, indexed by a global index: 696 // dma_id = cluster_id * NB_DMA_MAX + loc_id 697 // 698 // As a DMA channel can be used by several tasks, each DMA channel is protected 699 // by a specific lock: _dma_lock[dma_id] 700 // The signalisation between the OS and the DMA uses the _dma_done[dma_id] 701 // synchronisation variables (set by the ISR, and reset by the OS). 702 // The transfer status is copied by the ISR in the _dma_status[dma_id] variables. 703 // 704 // These DMA channels can be used by the FB driver, or by the NIC driver. 705 ////////////////////////////////////////////////////////////////////////////////// 706 707 #if (NB_DMAS_MAX > 0) 708 in_unckdata unsigned int _dma_lock[NB_DMAS_MAX * NB_CLUSTERS] 709 = { [0 ... (NB_DMAS_MAX * NB_CLUSTERS)-1] = 0 }; 710 711 in_unckdata volatile unsigned int _dma_done[NB_DMAS_MAX * NB_CLUSTERS] 712 = { [0 ... (NB_DMAS_MAX * NB_CLUSTERS)-1] = 0 }; 713 714 in_unckdata volatile unsigned int _dma_status[NB_DMAS_MAX * NB_CLUSTERS]; 715 716 in_unckdata unsigned int _dma_iommu_ix1 = 1; 717 718 in_unckdata unsigned int _dma_iommu_npages[NB_DMAS_MAX * NB_CLUSTERS]; 719 #endif 720 721 ////////////////////////////////////////////////////////////////////////////////// 670 722 // VciFrameBuffer driver 671 723 ////////////////////////////////////////////////////////////////////////////////// 724 // The vci_frame_buffer device can be accessed directly by software with memcpy(), 725 // or it can be accessed through a multi-channels DMA component: 726 // 672 727 // The '_fb_sync_write' and '_fb_sync_read' functions use a memcpy strategy to 673 728 // implement the transfer between a data buffer (user space) and the frame … … 675 730 // 676 731 // The '_fb_write()', '_fb_read()' and '_fb_completed()' functions use the DMA 677 // coprocessor to transfer data between the user buffer and the frame buffer. 678 // These functions use a polling policy to test the global variables _dma_busy[i] 679 // and detect the transfer completion. 680 // There is NB_DMA channels, that are indexed by the dma_id stored in the 681 // task context. 682 // The _dma_busy[i] synchronisation variables (one per channel) are set by the OS, 683 // and reset by the DMA ISR. 732 // controlers (distributed in the clusters) to transfer data 733 // between the user buffer and the frame buffer. A DMA channel is 734 // allocated to each task requesting it in the mapping_info data structure. 684 735 ////////////////////////////////////////////////////////////////////////////////// 685 736 … … 697 748 unsigned int length ) 698 749 { 699 volatile unsigned char *fb_address;700 750 701 751 // buffer must be mapped in user space 702 752 if ( ((unsigned int)buffer + length ) >= 0x80000000 ) 753 { 703 754 return 1; 704 705 fb_address = (unsigned char*)&seg_fb_base + offset;706 707 // buffer copy708 memcpy((void*)fb_address, (void*)buffer, length);709 710 return 0;755 } 756 else 757 { 758 unsigned char *fb_address = (unsigned char*)&seg_fb_base + offset; 759 memcpy((void*)fb_address, (void*)buffer, length); 760 return 0; 761 } 711 762 } 712 763 … … 724 775 unsigned int length ) 725 776 { 726 volatile unsigned char *fb_address;727 728 777 // buffer must be mapped in user space 729 778 if ( ((unsigned int)buffer + length ) >= 0x80000000 ) 779 { 730 780 return 1; 731 732 fb_address = (unsigned char*)&seg_fb_base + offset;733 734 // buffer copy735 memcpy((void*)buffer, (void*)fb_address, length);736 737 return 0;738 } 739 740 ////////////////////////////////////////////////////////////////////////////////// 741 // _fb_ access()742 // Transfer data between a memory buffer and the frame_buffer deviceusing DMA.743 // - to_ mem : from frame buffer to memorywhen true.781 } 782 else 783 { 784 unsigned char *fb_address = (unsigned char*)&seg_fb_base + offset; 785 memcpy((void*)buffer, (void*)fb_address, length); 786 return 0; 787 } 788 } 789 790 ////////////////////////////////////////////////////////////////////////////////// 791 // _fb_dma_access() 792 // Transfer data between a user buffer and the frame_buffer using DMA. 793 // - to_user : from frame buffer to user buffer when true. 744 794 // - offset : offset (in bytes) in the frame buffer. 745 795 // - user_vaddr : virtual base address of the memory buffer. … … 747 797 // The memory buffer must be mapped in user address space and word-aligned. 748 798 // The user buffer length must be multiple of 4 bytes. 749 // Returns 0 if success, > 0 if error. 750 ////////////////////////////////////////////////////////////////////////////////// 751 unsigned int _fb_access( unsigned int to_mem, 752 unsigned int offset, 753 unsigned int user_vaddr, 754 unsigned int length ) 755 { 756 static_scheduler_t* psched; // pointer on the current task scheduler 757 unsigned char* fb_base; // frame buffer base address 758 unsigned int* dma_base; // dma component base address 759 unsigned int task_id; // task local index (for scheduler) 760 unsigned int dma_id; // DMA channel index 761 unsigned int vpn; // current virtual page number 762 unsigned int flags; // protection flags 763 unsigned int ppn; // current physical page number 764 unsigned int buf_base; // buffer base address for DMA access 765 unsigned int ppn_first; // first physical page index for user buffer 766 767 fb_base = (unsigned char*)&seg_fb_base + offset; 768 769 psched = &_scheduler[_procid()]; 770 task_id = psched->current; 771 dma_id = psched->context[task_id][CTX_FBDMA_ID]; 772 dma_base = (unsigned int*)&seg_dma_base + (dma_id * DMA_SPAN); 773 774 // check buffer address and ength alignment 775 if ( user_vaddr & 0x3 ) return 1; 776 if ( length & 0x3 ) return 1; 799 // Me must compute the physical base addresses for both the frame buffer 800 // and the user buffer before programming the DMA transfer. 801 // The GIET being fully static, we don't need to split the transfer in 4Kbytes 802 // pages, because the user buffer is contiguous in physical space. 803 // Returns 0 if success, > 0 if error. 804 ////////////////////////////////////////////////////////////////////////////////// 805 unsigned int _fb_dma_access( unsigned int to_user, 806 unsigned int offset, 807 unsigned int user_vaddr, 808 unsigned int length ) 809 { 810 unsigned int ko; // unsuccessfull V2P translation 811 unsigned int flags; // protection flags 812 unsigned int ppn; // physical page number 813 unsigned int user_pbase; // user buffer pbase address 814 unsigned int fb_pbase; // frame buffer pbase address 815 816 // get DMA channel and compute DMA vbase address 817 unsigned int dma_id = _get_current_context_slot(CTX_FBDMA_ID); 818 unsigned int cluster_id = dma_id / NB_DMAS_MAX; 819 unsigned int loc_id = dma_id % NB_DMAS_MAX; 820 unsigned int* dma_base = (unsigned int*)&seg_dma_base + 821 (cluster_id * CLUSTER_SPAN) + 822 (loc_id * DMA_SPAN); 823 824 // check user buffer address and length alignment 825 if ( (user_vaddr & 0x3) || (length & 0x3) ) 826 { 827 _puts("[GIET ERROR] in _fbdma_access() : user buffer not word aligned\n"); 828 return 1; 829 } 777 830 778 831 // get user space page table virtual address 779 unsigned int user_ptp = psched->context[task_id][CTX_PTAB_ID]; 780 832 unsigned int user_ptab = _get_current_context_slot(CTX_PTAB_ID); 833 834 // compute frame buffer pbase address 835 unsigned int fb_vaddr = (unsigned int)&seg_fb_base + offset; 836 837 ko = _v2p_translate( (page_table_t*)user_ptab, 838 (fb_vaddr >> 12), 839 &ppn, 840 &flags ); 841 fb_pbase = (ppn << 12) | (fb_vaddr & 0x00000FFF); 842 843 if ( ko ) 844 { 845 _puts("[GIET ERROR] in _fbdma_access() : frame buffer unmapped\n"); 846 return 2; 847 } 848 849 // Compute user buffer pbase address 850 ko = _v2p_translate( (page_table_t*)user_ptab, 851 (user_vaddr >> 12), 852 &ppn, 853 &flags ); 854 user_pbase = (ppn << 12) | (user_vaddr & 0x00000FFF); 855 856 if ( ko ) 857 { 858 _puts("[GIET ERROR] in _fbdma_access() : user buffer unmapped\n"); 859 return 3; 860 } 861 if ( (flags & PTE_U) == 0 ) 862 { 863 _puts("[GIET ERROR] in _fbdma_access() : user buffer not in user space\n"); 864 return 4; 865 } 866 if ( ( (flags & PTE_W) == 0 ) && to_user ) 867 { 868 _puts("[GIET ERROR] in _fbdma_access() : user buffer not writable\n"); 869 return 5; 870 } 871 872 873 874 /* 875 // loop on all virtual pages covering the user buffer 781 876 unsigned int user_vpn_min = user_vaddr >> 12; 782 877 unsigned int user_vpn_max = (user_vaddr + length - 1) >> 12; 783 878 unsigned int ix2 = 0; 784 879 unsigned int ix1 = _dma_iommu_ix1 + dma_id; 785 unsigned int ko; 786 unsigned int i; 787 788 // loop on all virtual pages covering the user buffer 880 789 881 for ( vpn = user_vpn_min ; vpn <= user_vpn_max ; vpn++ ) 790 882 { 791 883 // get ppn and flags for each vpn 792 ko = _v2p_translate( (page_table_t*)user_ptp,793 vpn,794 &ppn,795 &flags );884 unsigned int ko = _v2p_translate( (page_table_t*)user_pt_vbase, 885 vpn, 886 &ppn, 887 &flags ); 796 888 797 889 // check access rights 798 if ( ko ) return 2; // unmapped799 if ( (flags & PTE_U) == 0 ) return 3; // not in user space800 if ( ( (flags & PTE_W) == 0 ) && to_ mem ) return 4; // not writable890 if ( ko ) return 3; // unmapped 891 if ( (flags & PTE_U) == 0 ) return 4; // not in user space 892 if ( ( (flags & PTE_W) == 0 ) && to_user ) return 5; // not writable 801 893 802 894 // save first ppn value … … 816 908 else // no IOMMU : check that physical pages are contiguous 817 909 { 818 if ( (ppn - ppn_first) != ix2 ) return 5; // split physical buffer910 if ( (ppn - ppn_first) != ix2 ) return 6; // split physical buffer 819 911 } 820 912 … … 823 915 } // end for vpn 824 916 825 // register the number of pages to be unmapped 917 // register the number of pages to be unmapped if iommu activated 826 918 _dma_iommu_npages[dma_id] = (user_vpn_max - user_vpn_min) + 1; 827 919 920 */ 828 921 // invalidate data cache in case of memory write 829 if ( to_mem ) _dcache_buf_invalidate( (void*)user_vaddr, length ); 830 831 // compute buffer base address for DMA depending on IOMMU activation 832 if ( GIET_IOMMU_ACTIVE ) buf_base = ( ix1 ) << 21 | (user_vaddr & 0xFFF); 833 else buf_base = (ppn_first << 12) | (user_vaddr & 0xFFF); 834 835 836 // waiting until DMA device is available 837 while (_dma_busy[dma_id] != 0) 838 { 839 // busy wait with a pseudo random delay between bus access 840 unsigned int delay = (_proctime() & 0xF) << 4; 841 for (i = 0; i < delay; i++) 842 asm volatile("nop"); 843 } 844 845 _dma_busy[dma_id] = 1; 922 if ( to_user ) _dcache_buf_invalidate( (void*)user_vaddr, length ); 923 924 // get the lock 925 _get_lock( &_dma_lock[dma_id] ); 846 926 847 927 // DMA configuration 848 dma_base[DMA_IRQ_DISABLE] = 0; 849 if ( to_mem ) 850 { 851 dma_base[DMA_SRC] = (unsigned int)fb_base; 852 dma_base[DMA_DST] = (unsigned int)buf_base; 928 if ( to_user ) 929 { 930 dma_base[DMA_SRC] = (unsigned int)fb_pbase; 931 dma_base[DMA_DST] = (unsigned int)user_pbase; 853 932 } 854 933 else 855 934 { 856 dma_base[DMA_SRC] = (unsigned int) buf_base;857 dma_base[DMA_DST] = (unsigned int)fb_ base;935 dma_base[DMA_SRC] = (unsigned int)user_pbase; 936 dma_base[DMA_DST] = (unsigned int)fb_pbase; 858 937 } 859 938 dma_base[DMA_LEN] = (unsigned int)length; … … 873 952 unsigned int length ) 874 953 { 875 return _fb_ access( 0, // write to frame buffer876 offset,877 (unsigned int)buffer,878 length );954 return _fb_dma_access( 0, // write to frame buffer 955 offset, 956 (unsigned int)buffer, 957 length ); 879 958 } 880 959 … … 891 970 unsigned int length ) 892 971 { 893 return _fb_ access( 1, // read from frame buffer894 offset,895 (unsigned int)buffer,896 length );972 return _fb_dma_access( 1, // read from frame buffer 973 offset, 974 (unsigned int)buffer, 975 length ); 897 976 } 898 977 … … 906 985 unsigned int _fb_completed() 907 986 { 908 static_scheduler_t* psched = &_scheduler[_procid()]; 909 unsigned int task_id = psched->current; 910 911 volatile unsigned int dma_id = psched->context[task_id][CTX_FBDMA_ID]; 987 unsigned int dma_id = _get_current_context_slot(CTX_FBDMA_ID); 912 988 913 989 // busy waiting with a pseudo random delay between bus access 914 while (_dma_ busy[dma_id] != 0)990 while (_dma_done[dma_id] == 0) 915 991 { 916 992 unsigned int i; 917 unsigned int delay = ( _proctime() & 0xF) << 4;993 unsigned int delay = ( _proctime() ^ _procid()<<4 ) & 0xFF; 918 994 for (i = 0; i < delay; i++) 919 995 asm volatile("nop"); … … 938 1014 } 939 1015 1016 // reset synchronization variables 1017 _dma_lock[dma_id] = 0; 1018 _dma_done[dma_id] = 0; 1019 940 1020 return _dma_status[dma_id]; 941 1021 }
Note: See TracChangeset
for help on using the changeset viewer.