Changeset 3 for trunk/kernel/devices/dev_ioc.c
- Timestamp:
- Apr 26, 2017, 2:08:13 PM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/kernel/devices/dev_ioc.c
r1 r3 32 32 #include <thread.h> 33 33 #include <printk.h> 34 #include <chdev.h> 34 35 #include <dev_ioc.h> 35 36 … … 38 39 ///////////////////////////////////////////////////////////////////////////////////////// 39 40 40 extern devices_directory_t devices_dir; // allocated in kernel_init.c41 extern chdev_directory_t chdev_dir; // allocated in kernel_init.c 41 42 42 extern devices_input_irq_t devices_input_irq; // allocated in kernel_init.c43 extern chdev_pic_input_t chdev_pic_input; // allocated in kernel_init.c 43 44 44 ////////////////////////////////// 45 void dev_ioc_init( xptr_t dev_xp)45 //////////////////////////////////// 46 void dev_ioc_init( chdev_t * chdev ) 46 47 { 47 // get IOC device descriptor cluster and local pointer 48 cxy_t dev_cxy = GET_CXY( dev_xp ); 49 device_t * dev_ptr = (device_t *)GET_PTR( dev_xp ); 48 // the local ICU chdev must be initialized before the IOC chdev, because 49 // the IOC chdev initialisation requires allocation of a WTI from local ICU 50 xptr_t icu_xp = chdev_dir.icu[local_cxy]; 51 assert( (icu_xp != XPTR_NULL) , __FUNCTION__ , "ICU not initialised before IOC" ); 50 52 51 // get implementation from device descriptor 52 uint32_t impl = hal_remote_lw( XPTR( dev_cxy , &dev_ptr->impl ) ); 53 // get implementation and channel from chdev descriptor 54 uint32_t impl = chdev->impl; 55 uint32_t channel = chdev->channel; 53 56 54 // set driver specific fields in device descriptor 55 // and call driver init function 57 // set driver specific fields in chdev descriptor and call driver init function 56 58 if( impl == IMPL_IOC_BDV ) 57 59 { 58 hal_remote_spt( XPTR( dev_cxy , &dev_ptr->cmd ) , &soclib_bdv_command ); 59 hal_remote_spt( XPTR( dev_cxy , &dev_ptr->isr ) , &soclib_bdv_isr ); 60 hal_remote_memcpy( XPTR( dev_cxy , &dev_ptr->name ), 61 XPTR( local_cxy , "IOC_BDV" ) , 16 ); 62 soclib_bdv_init( dev_xp ); 60 chdev->cmd = &soclib_bdv_cmd; 61 chdev->isr = &soclib_bdv_isr; 62 soclib_bdv_init( chdev ); 63 63 } 64 64 else if( impl == IMPL_IOC_HBA ) 65 65 { 66 hal_remote_spt( XPTR( dev_cxy , &dev_ptr->cmd ) , &soclib_hba_command ); 67 hal_remote_spt( XPTR( dev_cxy , &dev_ptr->isr ) , &soclib_hba_isr ); 68 hal_remote_memcpy( XPTR( dev_cxy , &dev_ptr->name ), 69 XPTR( local_cxy , "IOC_HBA" ) , 16 ); 70 soclib_hba_init( dev_xp ); 66 chdev->cmd = &soclib_hba_command; 67 chdev->isr = &soclib_hba_isr; 68 soclib_hba_init( chdev ); 71 69 } 72 // else if( impl == IMPL_IOC_SDC )73 // {74 // hal_remote_spt( XPTR( dev_cxy , &dev_ptr->cmd ) , &soclib_sdc_command );75 // hal_remote_spt( XPTR( dev_cxy , &dev_ptr->isr ) , &soclib_sdc_isr );76 // hal_remote_memcpy( XPTR( dev_cxy , &dev_ptr->name ),77 // XPTR( local_cxy , "IOC_SDC" ) , 16 );78 // soclib_sdc_init( dev_xp );79 // }80 // else if( impl == IMPL_IOC_SPI )81 // {82 // hal_remote_spt( XPTR( dev_cxy , &dev_ptr->cmd ) , &soclib_spi_command );83 // hal_remote_spt( XPTR( dev_cxy , &dev_ptr->isr ) , &soclib_spi_isr );84 // hal_remote_memcpy( XPTR( dev_cxy , &dev_ptr->name ),85 // XPTR( local_cxy , "IOC_SPI" ) , 16 );86 // soclib_spi_init( dev_xp );87 // }88 // else if( impl == IMPL_IOC_RDK )89 // {90 // hal_remote_spt( XPTR( dev_cxy , &dev_ptr->cmd ) , &soclib_rdk_command );91 // hal_remote_spt( XPTR( dev_cxy , &dev_ptr->isr ) , &soclib_rdk_isr );92 // hal_remote_memcpy( XPTR( dev_cxy , &dev_ptr->name ),93 // XPTR( local_cxy , "IOC_RDK" ) , 16 );94 // soclib_rdk_init( dev_xp );95 // }96 70 else 97 71 { 98 printk("\n[PANIC] in %s: undefined IOC device implementation\n", __FUNCTION__ ); 99 hal_core_sleep(); 72 assert( false , __FUNCTION__ , "undefined IOC device implementation" ); 100 73 } 101 74 75 // get a WTI mailbox from local ICU 76 uint32_t wti_id = dev_icu_wti_alloc(); 77 78 assert( (wti_id != -1) , __FUNCTION__ , "cannot allocate WTI mailbox" ); 79 80 // select a core 81 lid_t lid = cluster_select_local_core(); 82 83 // enable WTI IRQ and update WTI interrupt vector 84 dev_icu_enable_irq( lid , WTI_TYPE , wti_id , chdev ); 85 86 // link IOC IRQ to WTI mailbox in PIC component 87 uint32_t irq_id = chdev_pic_input.ioc[channel]; 88 dev_pic_bind_irq( irq_id , local_cxy , wti_id ); 89 102 90 // create server thread 103 thread_t * new_thread_ptr; 104 xptr_t new_thread_xp; 91 thread_t * new_thread; 105 92 error_t error; 106 93 107 if( dev_cxy == local_cxy ) // device cluster is local 108 { 109 error = thread_kernel_create( &new_thread_ptr, 110 THREAD_DEV, 111 &dev_ioc_server, 112 dev_ptr, 113 cluster_select_local_core() ); 94 error = thread_kernel_create( &new_thread, 95 THREAD_DEV, 96 &chdev_sequencial_server, 97 chdev, 98 lid ); 99 assert( (error == 0) , __FUNCTION__ , "cannot create server thread" ); 114 100 115 new_thread_xp = XPTR( local_cxy , new_thread_ptr ); 116 } 117 else // device cluster is remote 118 { 119 rpc_thread_kernel_create_client( dev_cxy, 120 THREAD_DEV, 121 &dev_ioc_server, 122 dev_ptr, 123 &new_thread_xp, 124 &error ); 125 126 new_thread_ptr = (thread_t *)GET_PTR( new_thread_xp ); 127 } 128 if( error ) 129 { 130 printk("\n[PANIC] in %s : cannot create server thread\n", __FUNCTION__ ); 131 hal_core_sleep(); 132 } 133 134 // set "server" field in device descriptor 135 hal_remote_spt( XPTR( dev_cxy , &dev_ptr->server ) , new_thread_ptr ); 101 // set "server" field in chdev descriptor 102 chdev->server = new_thread; 136 103 137 104 // start server thread 138 thread_unblock( new_thread_xp, THREAD_BLOCKED_GLOBAL );105 thread_unblock( XPTR( local_cxy , new_thread ) , THREAD_BLOCKED_GLOBAL ); 139 106 140 107 } // end dev_ioc_init() … … 144 111 // It builds and registers the command in the calling thread descriptor, after 145 112 // translation of buffer virtual address to physical address. 146 // Then, it registers the calling thead in devicewaiting queue.113 // Then, it registers the calling thead in chdev waiting queue. 147 114 // Finally it blocks on the THREAD_BLOCKED_DEV condition and deschedule. 148 115 ////////////////////////////////////i///////////////////////////////////////////// … … 152 119 uint32_t count ) 153 120 { 154 thread_t * this = CURRENT_THREAD; // pointer on client thread 155 cxy_t local_cxy = local_cxy; // client thread cluster 121 thread_t * this = CURRENT_THREAD; // pointer on client thread 156 122 157 123 error_t error; 158 124 paddr_t buf_paddr; 159 bool_t ident = CONFIG_KERNEL_IDENTITY;160 125 161 126 // Get buffer physical address 162 error = vmm_v2p_translate( ident, buffer , &buf_paddr );127 error = vmm_v2p_translate( CONFIG_KERNEL_IDENTITY , buffer , &buf_paddr ); 163 128 164 129 if( error ) return EINVAL; 165 130 166 131 ioc_dmsg("\n[INFO] in %s : thread %x in process %x" 167 " for lba = %x / vaddr = %x / paddr = %l lx\n",132 " for lba = %x / vaddr = %x / paddr = %l / at cycle %d\n", 168 133 __FUNCTION__ , this->trdid , this->process->pid , 169 lba , (uint32_t)buffer , buf_paddr );134 lba , (uint32_t)buffer , buf_paddr , hal_time_stamp() ); 170 135 171 136 #if USE_IOB // software L2/L3 cache coherence for memory buffer … … 176 141 #endif // end software L2/L3 cache coherence 177 142 178 // get extended pointer on IOC devicedescriptor179 xptr_t dev_xp = devices_dir.ioc;143 // get extended pointer on IOC chdev descriptor 144 xptr_t dev_xp = chdev_dir.ioc[0]; 180 145 181 if ( dev_xp == XPTR_NULL ) 182 { 183 printk("\n[PANIC] in %s : undefined IOC device descriptor\n", __FUNCTION__ ); 184 hal_core_sleep(); 185 } 146 assert( (dev_xp != XPTR_NULL) , __FUNCTION__ , "undefined IOC chdev descriptor" ); 186 147 187 // get a free WTI mailbox 188 uint32_t wti_id; 189 while( 1 ) 190 { 191 wti_id = dev_icu_wti_alloc(); 192 if( wti_id == -1 ) sched_yield(); 193 else break; 194 } 148 // register command in calling thread descriptor 149 this->command.ioc.dev_xp = dev_xp; 150 this->command.ioc.to_mem = to_mem; 151 this->command.ioc.buf_xp = XPTR( local_cxy , buffer ); 152 this->command.ioc.lba = lba; 153 this->command.ioc.count = count; 195 154 196 // enable WTI IRQ in local ICU and update WTI interrupt vector 197 dev_icu_enable_irq( local_cxy, CURRENT_CORE->lid , WTI_TYPE , wti_id , dev_xp ); 198 199 // link IOC IRQ to WTI mailbox in PIC component 200 uint32_t irq_id = devices_input_irq.ioc; 201 dev_pic_bind_irq( irq_id , local_cxy , wti_id ); 202 203 // store command in thread descriptor 204 this->dev.ioc.dev_xp = dev_xp; 205 this->dev.ioc.to_mem = to_mem; 206 this->dev.ioc.buf_xp = XPTR( local_cxy , buffer ); 207 this->dev.ioc.lba = lba; 208 this->dev.ioc.count = count; 209 210 // register client thread in waiting queue, activate server thread, 155 // register client thread in IOC chdev waiting queue, activate server thread, 211 156 // block client thread on THREAD_BLOCKED_IO and deschedule. 212 157 // it is re-activated by the ISR signaling IO operation completion. 213 device_register_command( dev_xp , this );158 chdev_register_command( dev_xp , this ); 214 159 215 // access PIC to unlink the IOC IRQ 216 dev_pic_unbind_irq( irq_id ); 217 218 // disable WTI IRQ in ICU and update interrupt vector 219 dev_icu_disable_irq( local_cxy , CURRENT_CORE->lid , WTI_TYPE , wti_id ); 220 221 // release WTI mailbox 222 dev_icu_wti_release( wti_id ); 223 224 ioc_dmsg("\n[INFO] in %s : thread %x in process %x completes / error = %d\n", 225 __FUNCTION__ , this->trdid , this->process->pid , this->dev.ioc.error ); 160 ioc_dmsg("\n[INFO] in %s : thread %x in process %x" 161 " completes / error = %d / at cycle %d\n", 162 __FUNCTION__ , this->trdid , this->process->pid , 163 this->dev.ioc.error , hal_time_stamp() ); 226 164 227 165 // return I/O operation status 228 return this-> dev.ioc.error;166 return this->command.ioc.error; 229 167 230 168 } // end dev_ioc_access() … … 245 183 return dev_ioc_access( false , buffer , lba , count ); 246 184 } 247 248 /////////////////////////////////////249 void dev_ioc_server( device_t * dev )250 {251 xptr_t client_xp; // extended pointer on waiting thread252 cxy_t client_cxy; // cluster of client thread253 thread_t * client_ptr; // local pointer on client thread254 thread_t * server; // local pointer on server thread255 xptr_t root_xp; // extended pointer on device waiting queue root256 257 server = CURRENT_THREAD;258 259 root_xp = XPTR( local_cxy , &dev->wait_root );260 261 // infinite loop handling commands registered in the IOC waiting queue262 // TODO If we want to implement an "elevator" mecanism (i.e. sort all263 // pending command on the LBA to optimize physical device accesses),264 // it should be done in this loop...265 266 while( 1 )267 {268 // get lock protecting queue269 remote_spinlock_lock( XPTR( local_cxy , &dev->wait_lock ) );270 271 // block and deschedule server thread if waiting queue empty272 if( xlist_is_empty( root_xp ) )273 {274 thread_block( server , THREAD_BLOCKED_DEV_QUEUE );275 remote_spinlock_unlock( XPTR( local_cxy , &dev->wait_lock ) );276 sched_yield();277 }278 else279 {280 remote_spinlock_unlock( XPTR( local_cxy , &dev->wait_lock ) );281 }282 283 // get extended pointer on first client thread284 client_xp = XLIST_FIRST_ELEMENT( root_xp , thread_t , wait_list );285 286 // call driver command function to start I/O operation287 dev->cmd( client_xp );288 289 // get client thread cluster and local pointer290 client_cxy = GET_CXY( client_xp );291 client_ptr = (thread_t *)GET_PTR( client_xp );292 293 // remove the client thread from waiting queue294 remote_spinlock_lock( XPTR( local_cxy , &dev->wait_lock ) );295 xlist_unlink( XPTR( client_cxy , &client_ptr->wait_list ) );296 remote_spinlock_unlock( XPTR( local_cxy , &dev->wait_lock ) );297 298 } // end while299 300 } // end dev_ioc_server()
Note: See TracChangeset
for help on using the changeset viewer.