| [1] | 1 | /* | 
|---|
|  | 2 | * dev_icu.c - ICU (Interrupt Controler Unit) generic device API implementation. | 
|---|
|  | 3 | * | 
|---|
|  | 4 | * Authors   Alain Greiner  (2016) | 
|---|
|  | 5 | * | 
|---|
|  | 6 | * Copyright (c) UPMC Sorbonne Universites | 
|---|
|  | 7 | * | 
|---|
|  | 8 | * This file is part of ALMOS-MKH. | 
|---|
|  | 9 | * | 
|---|
|  | 10 | * ALMOS-MKH is free software; you can redistribute it and/or modify it | 
|---|
|  | 11 | * under the terms of the GNU General Public License as published by | 
|---|
|  | 12 | * the Free Software Foundation; version 2.0 of the License. | 
|---|
|  | 13 | * | 
|---|
|  | 14 | * ALMOS-MKH is distributed in the hope that it will be useful, but | 
|---|
|  | 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
|  | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|---|
|  | 17 | * General Public License for more details. | 
|---|
|  | 18 | * | 
|---|
|  | 19 | * You should have received a copy of the GNU General Public License | 
|---|
|  | 20 | * along with ALMOS-MKH; if not, write to the Free Software Foundation, | 
|---|
|  | 21 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 
|---|
|  | 22 | */ | 
|---|
|  | 23 |  | 
|---|
|  | 24 | #include <hal_types.h> | 
|---|
|  | 25 | #include <hal_special.h> | 
|---|
| [3] | 26 | #include <chdev.h> | 
|---|
| [1] | 27 | #include <thread.h> | 
|---|
|  | 28 | #include <cluster.h> | 
|---|
|  | 29 | #include <printk.h> | 
|---|
|  | 30 | #include <memcpy.h> | 
|---|
|  | 31 | #include <spinlock.h> | 
|---|
|  | 32 | #include <soclib_xcu.h> | 
|---|
|  | 33 | #include <dev_icu.h> | 
|---|
|  | 34 |  | 
|---|
|  | 35 | ///////////////////////////////////////////////////////////////////////////////////////// | 
|---|
|  | 36 | // Extern global variables | 
|---|
|  | 37 | ///////////////////////////////////////////////////////////////////////////////////////// | 
|---|
|  | 38 |  | 
|---|
| [3] | 39 | extern chdev_directory_t  chdev_dir;         // allocated in kernel_init.c | 
|---|
| [1] | 40 |  | 
|---|
| [3] | 41 | extern chdev_pic_input_t  chdev_pic_input;   // allocated in kernel_init.c | 
|---|
| [1] | 42 |  | 
|---|
| [3] | 43 | ///////////////////////////////// | 
|---|
|  | 44 | void dev_icu_init( chdev_t * icu, | 
|---|
|  | 45 | uint32_t  hwi_nr, | 
|---|
|  | 46 | uint32_t  wti_nr, | 
|---|
|  | 47 | uint32_t  pti_nr ) | 
|---|
| [1] | 48 | { | 
|---|
| [3] | 49 | // set ICU chdev extension fields | 
|---|
|  | 50 | icu->ext.icu.hwi_nr     = hwi_nr; | 
|---|
|  | 51 | icu->ext.icu.wti_nr     = wti_nr; | 
|---|
|  | 52 | icu->ext.icu.pti_nr     = pti_nr; | 
|---|
|  | 53 | icu->ext.icu.wti_bitmap = 0; | 
|---|
|  | 54 | spinlock_init( &icu->ext.icu.wti_lock ); | 
|---|
| [1] | 55 |  | 
|---|
| [3] | 56 | // get implementation | 
|---|
|  | 57 | uint32_t impl = icu->impl; | 
|---|
| [1] | 58 |  | 
|---|
| [3] | 59 | // call the relevant driver init function | 
|---|
| [1] | 60 | if( impl == IMPL_ICU_XCU ) | 
|---|
|  | 61 | { | 
|---|
| [3] | 62 | uint32_t  lid; | 
|---|
|  | 63 | for( lid = 0 ; lid < LOCAL_CLUSTER->cores_nr ; lid++ ) | 
|---|
| [1] | 64 | { | 
|---|
| [3] | 65 | soclib_xcu_init( icu , lid ); | 
|---|
| [1] | 66 | } | 
|---|
|  | 67 | } | 
|---|
|  | 68 | else | 
|---|
|  | 69 | { | 
|---|
| [3] | 70 | assert( false , __FUNCTION__ , "undefined ICU implementation" ); | 
|---|
| [1] | 71 | } | 
|---|
|  | 72 | } // end dev_icu_init() | 
|---|
|  | 73 |  | 
|---|
|  | 74 | ///////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [3] | 75 | // This static function check the irq_type / irq_index arguments. | 
|---|
| [1] | 76 | // It is called by the dev_icu_enable_irq() & dev_icu_disable_irq() functions. | 
|---|
|  | 77 | ///////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [3] | 78 | static inline void dev_icu_check_irq( chdev_t  * icu, | 
|---|
| [1] | 79 | uint32_t   irq_type, | 
|---|
|  | 80 | uint32_t   irq_index ) | 
|---|
|  | 81 | { | 
|---|
|  | 82 | if( irq_type == HWI_TYPE ) | 
|---|
|  | 83 | { | 
|---|
| [3] | 84 | assert( (irq_index < icu->ext.icu.hwi_nr) , __FUNCTION__ , "illegal HWI" ); | 
|---|
| [1] | 85 | } | 
|---|
|  | 86 | if( irq_type == WTI_TYPE ) | 
|---|
|  | 87 | { | 
|---|
| [3] | 88 | assert( (irq_index < icu->ext.icu.wti_nr) , __FUNCTION__ , "illegal WTI" ); | 
|---|
| [1] | 89 | } | 
|---|
|  | 90 | if( irq_type == PTI_TYPE ) | 
|---|
|  | 91 | { | 
|---|
| [3] | 92 | assert( (irq_index < icu->ext.icu.pti_nr) , __FUNCTION__ , "illegal PTI" ); | 
|---|
| [1] | 93 | } | 
|---|
| [3] | 94 | }  // end dev_icu_check_irq() | 
|---|
| [1] | 95 |  | 
|---|
| [3] | 96 | //////////////////////////////////////// | 
|---|
|  | 97 | void dev_icu_enable_irq( lid_t      lid, | 
|---|
| [1] | 98 | uint32_t   irq_type, | 
|---|
|  | 99 | uint32_t   irq_index, | 
|---|
| [3] | 100 | chdev_t  * src_chdev ) | 
|---|
| [1] | 101 | { | 
|---|
| [3] | 102 | // get local pointer on local ICU chdev | 
|---|
|  | 103 | xptr_t    icu_xp = chdev_dir.icu[local_cxy]; | 
|---|
|  | 104 | chdev_t * icu    = (chdev_t *)GET_PTR( icu_xp ); | 
|---|
| [1] | 105 |  | 
|---|
|  | 106 | // check IRQ type and index | 
|---|
| [3] | 107 | dev_icu_check_irq( icu , irq_type , irq_index ); | 
|---|
| [1] | 108 |  | 
|---|
|  | 109 | // (1) call implementation specific ICU driver to enable IRQ | 
|---|
| [3] | 110 | if( icu->impl == IMPL_ICU_XCU ) | 
|---|
| [1] | 111 | { | 
|---|
| [3] | 112 | soclib_xcu_enable_irq( icu , 1<<irq_index , irq_type , lid ); | 
|---|
| [1] | 113 | } | 
|---|
|  | 114 |  | 
|---|
| [3] | 115 | // (2) get selected core local pointer, and register | 
|---|
|  | 116 | // source chdev pointer in relevant interrupt vector | 
|---|
|  | 117 | core_t * core = &LOCAL_CLUSTER->core_tbl[lid]; | 
|---|
|  | 118 | core_set_irq_vector_entry( core , irq_type , irq_index , src_chdev ); | 
|---|
| [1] | 119 |  | 
|---|
| [3] | 120 | // (3) register IRQ type and index in source chdev descriptor | 
|---|
|  | 121 | src_chdev->irq_type = irq_type; | 
|---|
|  | 122 | src_chdev->irq_id   = irq_index; | 
|---|
| [1] | 123 |  | 
|---|
|  | 124 | }  // end dev_icu_enable_irq() | 
|---|
|  | 125 |  | 
|---|
| [3] | 126 | ///////////////////////////////////////// | 
|---|
|  | 127 | void dev_icu_disable_irq( lid_t      lid, | 
|---|
| [1] | 128 | uint32_t   irq_type, | 
|---|
|  | 129 | uint32_t   irq_index ) | 
|---|
|  | 130 | { | 
|---|
| [3] | 131 | // get local pointer on local ICU chdev | 
|---|
|  | 132 | xptr_t    icu_xp = chdev_dir.icu[local_cxy]; | 
|---|
|  | 133 | chdev_t * icu    = (chdev_t *)GET_PTR( icu_xp ); | 
|---|
| [1] | 134 |  | 
|---|
|  | 135 | // check IRQ type and index | 
|---|
| [3] | 136 | dev_icu_check_irq( icu , irq_type , irq_index ); | 
|---|
| [1] | 137 |  | 
|---|
|  | 138 | // (1) call the implementation specific ICU driver to disable IRQ | 
|---|
| [3] | 139 | if( icu->impl == IMPL_ICU_XCU ) | 
|---|
| [1] | 140 | { | 
|---|
| [3] | 141 | soclib_xcu_disable_irq( icu , 1<<irq_index , irq_type , lid ); | 
|---|
| [1] | 142 | } | 
|---|
|  | 143 |  | 
|---|
|  | 144 | // (2) get selected remote core local pointer, and remove | 
|---|
| [3] | 145 | // the source chdev xptr from relevant interrupt vector | 
|---|
| [1] | 146 |  | 
|---|
| [3] | 147 | core_t * core = &LOCAL_CLUSTER->core_tbl[lid]; | 
|---|
|  | 148 | core_set_irq_vector_entry( core , irq_type , irq_index , NULL ); | 
|---|
| [1] | 149 |  | 
|---|
|  | 150 | } // end dev_icu_disable_irq() | 
|---|
|  | 151 |  | 
|---|
|  | 152 | ////////////////////////////////////////////// | 
|---|
|  | 153 | void dev_icu_set_period( uint32_t   pti_index, | 
|---|
|  | 154 | uint32_t   period ) | 
|---|
|  | 155 | { | 
|---|
| [3] | 156 | // get local pointer on local ICU chdev | 
|---|
|  | 157 | xptr_t    icu_xp = chdev_dir.icu[local_cxy]; | 
|---|
|  | 158 | chdev_t * icu    = (chdev_t *)GET_PTR( icu_xp ); | 
|---|
| [1] | 159 |  | 
|---|
|  | 160 | // check PTI index | 
|---|
| [3] | 161 | assert( (pti_index < icu->ext.icu.pti_nr) , __FUNCTION__ , "illegal PTI index" ); | 
|---|
| [1] | 162 |  | 
|---|
|  | 163 | // call the implementation specific driver ICU to set period | 
|---|
|  | 164 | if( icu->impl == IMPL_ICU_XCU ) | 
|---|
|  | 165 | { | 
|---|
|  | 166 | soclib_xcu_set_period( icu , pti_index , period ); | 
|---|
|  | 167 | } | 
|---|
|  | 168 | }  // end dev_icu_set_period() | 
|---|
|  | 169 |  | 
|---|
|  | 170 | //////////////////////////////////////////// | 
|---|
|  | 171 | void dev_icu_ack_timer( uint32_t pti_index ) | 
|---|
|  | 172 | { | 
|---|
| [3] | 173 | // get local pointer on local ICU chdev | 
|---|
|  | 174 | xptr_t    icu_xp = chdev_dir.icu[local_cxy]; | 
|---|
|  | 175 | chdev_t * icu    = (chdev_t *)GET_PTR( icu_xp ); | 
|---|
| [1] | 176 |  | 
|---|
|  | 177 | // check PTI index | 
|---|
| [3] | 178 | assert( (pti_index < icu->ext.icu.pti_nr) , __FUNCTION__ , "illegal PTI index" ); | 
|---|
| [1] | 179 |  | 
|---|
|  | 180 | // call the implementation specific driver ICU to acknowledge PTI IRQ | 
|---|
|  | 181 | if( icu->impl == IMPL_ICU_XCU ) | 
|---|
|  | 182 | { | 
|---|
|  | 183 | soclib_xcu_ack_timer( icu , pti_index ); | 
|---|
|  | 184 | } | 
|---|
|  | 185 | }  // end dev_icu_ack_timer() | 
|---|
|  | 186 |  | 
|---|
|  | 187 | //////////////////////////////////// | 
|---|
|  | 188 | void dev_icu_send_ipi( cxy_t    cxy, | 
|---|
|  | 189 | lid_t    lid ) | 
|---|
|  | 190 | { | 
|---|
|  | 191 | // check arguments | 
|---|
|  | 192 | cluster_t * cluster  = LOCAL_CLUSTER; | 
|---|
|  | 193 | uint32_t    y_width  = cluster->y_width; | 
|---|
|  | 194 | uint32_t    x_size   = cluster->x_size; | 
|---|
|  | 195 | uint32_t    y_size   = cluster->y_size; | 
|---|
|  | 196 | uint32_t    cores_nr = cluster->cores_nr; | 
|---|
|  | 197 | uint32_t    x = cxy >> y_width; | 
|---|
|  | 198 | uint32_t    y = cxy & ((1<<y_width)-1); | 
|---|
|  | 199 |  | 
|---|
| [3] | 200 | assert( ((x < x_size) && (y < y_size)) , __FUNCTION__ , "illegal cluster identifier" ); | 
|---|
| [1] | 201 |  | 
|---|
| [3] | 202 | assert( (lid < cores_nr) , __FUNCTION__ , "illegal core local index" ); | 
|---|
| [1] | 203 |  | 
|---|
| [3] | 204 | // get extended pointer on target ICU chdev | 
|---|
|  | 205 | xptr_t icu_xp = chdev_dir.icu[cxy]; | 
|---|
|  | 206 |  | 
|---|
| [1] | 207 | // get target ICU cluster and local pointer | 
|---|
| [3] | 208 | cxy_t     icu_cxy = GET_CXY( icu_xp ); | 
|---|
|  | 209 | chdev_t * icu_ptr = (chdev_t *)GET_PTR( icu_xp ); | 
|---|
| [1] | 210 |  | 
|---|
| [3] | 211 | // get implementation from remote ICU chdev | 
|---|
|  | 212 | uint32_t impl = hal_remote_lw( XPTR( icu_cxy , &icu_ptr->impl ) ); | 
|---|
| [1] | 213 |  | 
|---|
|  | 214 | // call the implementation specific ICU driver to send IPI | 
|---|
|  | 215 | if( impl == IMPL_ICU_XCU ) | 
|---|
|  | 216 | { | 
|---|
|  | 217 | soclib_xcu_send_ipi( icu_xp , lid ); | 
|---|
|  | 218 | } | 
|---|
|  | 219 | }  // end dev_icu_send_ipi() | 
|---|
|  | 220 |  | 
|---|
|  | 221 | ////////////////////////// | 
|---|
|  | 222 | void dev_icu_irq_handler() | 
|---|
|  | 223 | { | 
|---|
|  | 224 | uint32_t   hwi_status;   // HWI index + 1  / no pending HWI if 0 | 
|---|
|  | 225 | uint32_t   wti_status;   // WTI index + 1  / no pending WTI if 0 | 
|---|
|  | 226 | uint32_t   pti_status;   // PTI index + 1  / no pending PTI if 0 | 
|---|
| [3] | 227 | chdev_t  * src_chdev;    // pointer on source chdev descriptor | 
|---|
| [1] | 228 | uint32_t   index;        // IRQ index | 
|---|
|  | 229 |  | 
|---|
|  | 230 | core_t   * core = CURRENT_CORE; | 
|---|
|  | 231 |  | 
|---|
| [3] | 232 | // get local pointer on local ICU chdev | 
|---|
|  | 233 | xptr_t    icu_xp = chdev_dir.icu[local_cxy]; | 
|---|
|  | 234 | chdev_t * icu    = (chdev_t *)GET_PTR( icu_xp ); | 
|---|
|  | 235 |  | 
|---|
| [1] | 236 | // call the implementation specific ICU driver | 
|---|
|  | 237 | // to return highest priority pending IRQ of each type | 
|---|
|  | 238 | if( icu->impl == IMPL_ICU_XCU ) | 
|---|
|  | 239 | { | 
|---|
|  | 240 | soclib_xcu_get_status( icu , core->lid , &hwi_status , &wti_status , &pti_status ); | 
|---|
|  | 241 | } | 
|---|
|  | 242 |  | 
|---|
|  | 243 | // analyse ICU status and handle up to 3 pending IRQ (one WTI, one HWI, one PTI) | 
|---|
|  | 244 |  | 
|---|
| [3] | 245 | if( wti_status )          // pending WTI | 
|---|
| [1] | 246 | { | 
|---|
|  | 247 | index = wti_status - 1; | 
|---|
|  | 248 |  | 
|---|
| [3] | 249 | if( index < LOCAL_CLUSTER->cores_nr )   // it is an IPI | 
|---|
|  | 250 | { | 
|---|
|  | 251 | assert( (index == core->lid) , __FUNCTION__ , "illegal IPI index" ); | 
|---|
| [1] | 252 |  | 
|---|
| [3] | 253 | // TODO acknowledge WTI [AG] | 
|---|
|  | 254 |  | 
|---|
|  | 255 | // TODO force scheduling [AG] | 
|---|
| [1] | 256 | } | 
|---|
| [3] | 257 | else                                    // it is an external device | 
|---|
| [1] | 258 | { | 
|---|
| [3] | 259 | // get pointer on IRQ source chdev | 
|---|
|  | 260 | src_chdev = core->wti_vector[index]; | 
|---|
| [1] | 261 |  | 
|---|
| [3] | 262 | if( src_chdev == NULL )        // strange, but not fatal => disable IRQ | 
|---|
|  | 263 | { | 
|---|
|  | 264 | printk("\n[WARNING] in %s : no handler for WTI %d on core %d in cluster %x\n", | 
|---|
|  | 265 | __FUNCTION__ , index , core->lid , local_cxy ); | 
|---|
|  | 266 | core->spurious_irqs ++; | 
|---|
|  | 267 | dev_icu_disable_irq( core->lid , WTI_TYPE , index ); | 
|---|
|  | 268 | } | 
|---|
|  | 269 | else                                 // call relevant ISR | 
|---|
|  | 270 | { | 
|---|
|  | 271 | icu_dmsg("\n[INFO] %s received WTI : index = %d for cpu %d in cluster %d\n", | 
|---|
|  | 272 | __FUNCTION__ , index , core->lid , local_cxy ); | 
|---|
|  | 273 |  | 
|---|
|  | 274 | // call ISR | 
|---|
|  | 275 | src_chdev->isr( src_chdev ); | 
|---|
|  | 276 | } | 
|---|
| [1] | 277 | } | 
|---|
|  | 278 | } | 
|---|
|  | 279 |  | 
|---|
|  | 280 | if( hwi_status )      // pending HWI | 
|---|
|  | 281 | { | 
|---|
|  | 282 | index = hwi_status - 1; | 
|---|
|  | 283 |  | 
|---|
| [3] | 284 | // get pointer on IRQ source chdev | 
|---|
|  | 285 | src_chdev = core->hwi_vector[index]; | 
|---|
| [1] | 286 |  | 
|---|
| [3] | 287 | if( src_chdev == NULL )        // strange, but not fatal => disable IRQ | 
|---|
| [1] | 288 | { | 
|---|
|  | 289 | printk("\n[WARNING] in %s : no handler for HWI %d on core %d in cluster %x\n", | 
|---|
|  | 290 | __FUNCTION__ , index , core->lid , local_cxy ); | 
|---|
|  | 291 | core->spurious_irqs ++; | 
|---|
| [3] | 292 | dev_icu_disable_irq( core->lid , HWI_TYPE , index ); | 
|---|
| [1] | 293 | } | 
|---|
|  | 294 | else                    // call relevant ISR | 
|---|
|  | 295 | { | 
|---|
|  | 296 | icu_dmsg("\n[INFO] %s received HWI : index = %d for cpu %d in cluster %d\n", | 
|---|
|  | 297 | __FUNCTION__ , index , core->lid , local_cxy ); | 
|---|
|  | 298 |  | 
|---|
| [3] | 299 | // call ISR | 
|---|
|  | 300 | src_chdev->isr( src_chdev ); | 
|---|
| [1] | 301 | } | 
|---|
|  | 302 | } | 
|---|
|  | 303 |  | 
|---|
|  | 304 | if( pti_status )      // pending PTI | 
|---|
|  | 305 | { | 
|---|
|  | 306 | index = pti_status - 1; | 
|---|
|  | 307 |  | 
|---|
|  | 308 | icu_dmsg("\n[INFO] %s received PTI : index = %d for cpu %d in cluster %d\n", | 
|---|
|  | 309 | __FUNCTION__ , index , core->lid , local_cxy ); | 
|---|
|  | 310 |  | 
|---|
|  | 311 | // acknowledge PTI | 
|---|
|  | 312 | dev_icu_ack_timer( index ); | 
|---|
|  | 313 |  | 
|---|
| [3] | 314 | // TODO execute all actions related to TICK event | 
|---|
| [1] | 315 | core_clock( core ); | 
|---|
|  | 316 | } | 
|---|
|  | 317 | }  // end dev_icu_irq_handler() | 
|---|
|  | 318 |  | 
|---|
|  | 319 | //////////////////////////// | 
|---|
|  | 320 | uint32_t dev_icu_wti_alloc() | 
|---|
|  | 321 | { | 
|---|
| [3] | 322 | // get local pointer on local ICU chdev | 
|---|
|  | 323 | xptr_t    icu_xp = chdev_dir.icu[local_cxy]; | 
|---|
|  | 324 | chdev_t * icu    = (chdev_t *)GET_PTR( icu_xp ); | 
|---|
| [1] | 325 |  | 
|---|
| [3] | 326 | // get bitmap pointer, lock pointer, and size | 
|---|
|  | 327 | uint32_t   * bitmap = &icu->ext.icu.wti_bitmap; | 
|---|
| [1] | 328 | spinlock_t * lock   = &icu->ext.icu.wti_lock; | 
|---|
|  | 329 | uint32_t     size   =  icu->ext.icu.wti_nr; | 
|---|
|  | 330 |  | 
|---|
|  | 331 | // get lock protecting WTI allocator | 
|---|
|  | 332 | spinlock_lock( lock ); | 
|---|
|  | 333 |  | 
|---|
|  | 334 | // get first free mailbox index | 
|---|
|  | 335 | uint32_t index = (uint32_t)bitmap_ffc( bitmap , size ); | 
|---|
|  | 336 |  | 
|---|
|  | 337 | // set bitmap entry if found | 
|---|
|  | 338 | if( index < size ) bitmap_set( bitmap , index ); | 
|---|
|  | 339 |  | 
|---|
|  | 340 | // release lock | 
|---|
|  | 341 | spinlock_unlock( lock ); | 
|---|
|  | 342 |  | 
|---|
|  | 343 | return index; | 
|---|
|  | 344 | }  // end dev_icu_wti_alloc() | 
|---|
|  | 345 |  | 
|---|
|  | 346 | ////////////////////////////////////////// | 
|---|
|  | 347 | void dev_icu_wti_release( uint32_t index ) | 
|---|
|  | 348 | { | 
|---|
| [3] | 349 | // get pointer on local ICU chdev descriptor | 
|---|
|  | 350 | xptr_t    icu_xp  = chdev_dir.icu[local_cxy]; | 
|---|
|  | 351 | chdev_t * icu_ptr = (chdev_t *)GET_PTR( icu_xp ); | 
|---|
| [1] | 352 |  | 
|---|
|  | 353 | // get bitmap pointer, lock, and size | 
|---|
| [3] | 354 | bitmap_t   * bitmap = &icu_ptr->ext.icu.wti_bitmap; | 
|---|
|  | 355 | spinlock_t * lock   = &icu_ptr->ext.icu.wti_lock; | 
|---|
|  | 356 | uint32_t     size   =  icu_ptr->ext.icu.wti_nr; | 
|---|
| [1] | 357 |  | 
|---|
|  | 358 | // check index | 
|---|
| [3] | 359 | assert( (index < size) , __FUNCTION__ , "illegal WTI index" ); | 
|---|
| [1] | 360 |  | 
|---|
|  | 361 | // get lock protecting WTI allocator | 
|---|
|  | 362 | spinlock_lock( lock ); | 
|---|
|  | 363 |  | 
|---|
|  | 364 | // clear bitmap entry | 
|---|
|  | 365 | bitmap_clear( bitmap , index ); | 
|---|
|  | 366 |  | 
|---|
|  | 367 | // release lock | 
|---|
|  | 368 | spinlock_unlock( lock ); | 
|---|
| [3] | 369 |  | 
|---|
| [1] | 370 | }  // end dev_icu_wti_release() | 
|---|
|  | 371 |  | 
|---|
| [3] | 372 | ////////////////////////////////////////////// | 
|---|
|  | 373 | uint32_t * dev_icu_wti_ptr( uint32_t  wti_id ) | 
|---|
| [1] | 374 | { | 
|---|
| [3] | 375 | uint32_t *  wti_ptr = NULL; | 
|---|
| [1] | 376 |  | 
|---|
| [3] | 377 | // get pointer on local ICU chdev descriptor | 
|---|
|  | 378 | xptr_t    icu_xp  = chdev_dir.icu[local_cxy]; | 
|---|
|  | 379 | chdev_t * icu     = (chdev_t *)GET_PTR( icu_xp ); | 
|---|
|  | 380 |  | 
|---|
| [1] | 381 | // call implementation specific ICU driver | 
|---|
|  | 382 | if( icu->impl == IMPL_ICU_XCU ) | 
|---|
|  | 383 | { | 
|---|
| [3] | 384 | wti_ptr = soclib_xcu_wti_ptr( icu , wti_id ); | 
|---|
| [1] | 385 | } | 
|---|
|  | 386 |  | 
|---|
| [3] | 387 | return wti_ptr; | 
|---|
| [1] | 388 | }   // end dev_icu_wti_xptr() | 
|---|
|  | 389 |  | 
|---|
|  | 390 |  | 
|---|