source: trunk/kernel/devices/dev_icu.c@ 128

Last change on this file since 128 was 128, checked in by max@…, 9 years ago

style

File size: 13.9 KB
Line 
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>
26#include <chdev.h>
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
39extern chdev_directory_t chdev_dir; // allocated in kernel_init.c
40
41extern chdev_pic_input_t chdev_pic_input; // allocated in kernel_init.c
42
43/////////////////////////////////
44void dev_icu_init( chdev_t * icu,
45 uint32_t hwi_nr,
46 uint32_t wti_nr,
47 uint32_t pti_nr )
48{
49 // set chdev name
50 snprintf( icu->name , 16 , "icu_%x" , local_cxy );
51
52 // set ICU chdev extension fields
53 icu->ext.icu.hwi_nr = hwi_nr;
54 icu->ext.icu.wti_nr = wti_nr;
55 icu->ext.icu.pti_nr = pti_nr;
56 icu->ext.icu.wti_bitmap = 0;
57 spinlock_init( &icu->ext.icu.wti_lock );
58
59 // get implementation
60 uint32_t impl = icu->impl;
61
62 // call the relevant driver init function
63 if( impl == IMPL_ICU_XCU )
64 {
65 uint32_t lid;
66 for( lid = 0 ; lid < LOCAL_CLUSTER->cores_nr ; lid++ )
67 {
68 soclib_xcu_init( icu , lid );
69 }
70 }
71 else
72 {
73 assert( false , __FUNCTION__ , "undefined ICU implementation" );
74 }
75}
76
77/////////////////////////////////////////////////////////////////////////////////////
78// This static function check the irq_type / irq_index arguments.
79// It is called by the dev_icu_enable_irq() & dev_icu_disable_irq() functions.
80/////////////////////////////////////////////////////////////////////////////////////
81static inline void dev_icu_check_irq( chdev_t * icu,
82 uint32_t irq_type,
83 uint32_t irq_index )
84{
85 if( irq_type == HWI_TYPE )
86 {
87 if( irq_index >= icu->ext.icu.hwi_nr )
88 {
89 printk("\n[PANIC] in %s : illegal HWI index = %d / max = %d\n",
90 __FUNCTION__ , irq_index , icu->ext.icu.hwi_nr );
91 hal_core_sleep();
92 }
93 }
94 else if( irq_type == WTI_TYPE )
95 {
96 if( irq_index >= icu->ext.icu.wti_nr )
97 {
98 printk("\n[PANIC] in %s : illegal WTI index = %d / max = %d\n",
99 __FUNCTION__ , irq_index , icu->ext.icu.wti_nr );
100 hal_core_sleep();
101 }
102 }
103 else // irq_type == PTI_TYPE
104 {
105 if( irq_index >= icu->ext.icu.pti_nr )
106 {
107 printk("\n[PANIC] in %s : illegal PTI index = %d / max = %d\n",
108 __FUNCTION__ , irq_index , icu->ext.icu.pti_nr );
109 hal_core_sleep();
110 }
111 }
112}
113
114////////////////////////////////////////
115void dev_icu_enable_irq( lid_t lid,
116 uint32_t irq_type,
117 uint32_t irq_index,
118 chdev_t * src_chdev )
119{
120 // get local pointer on local ICU chdev
121 xptr_t icu_xp = chdev_dir.icu[local_cxy];
122 chdev_t * icu = (chdev_t *)GET_PTR( icu_xp );
123
124 // check IRQ type and index
125 dev_icu_check_irq( icu , irq_type , irq_index );
126
127 // call implementation specific ICU driver to enable IRQ
128 if( icu->impl == IMPL_ICU_XCU )
129 {
130 soclib_xcu_enable_irq( icu , 1<<irq_index , irq_type , lid );
131 }
132
133 // This is only done for an HWI, or for a WTI that is not an IPI
134 if( (irq_type != PTI_TYPE) && (src_chdev != NULL) )
135 {
136 // get selected core local pointer, and register
137 // source chdev pointer in relevant interrupt vector
138 core_t * core = &LOCAL_CLUSTER->core_tbl[lid];
139 core_set_irq_vector_entry( core , irq_type , irq_index , src_chdev );
140
141 // (3) register IRQ type and index in source chdev descriptor
142 src_chdev->irq_type = irq_type;
143 src_chdev->irq_id = irq_index;
144 }
145}
146
147/////////////////////////////////////////
148void dev_icu_disable_irq( lid_t lid,
149 uint32_t irq_type,
150 uint32_t irq_index )
151{
152 // get local pointer on local ICU chdev
153 xptr_t icu_xp = chdev_dir.icu[local_cxy];
154 chdev_t * icu = (chdev_t *)GET_PTR( icu_xp );
155
156 // check IRQ type and index
157 dev_icu_check_irq( icu , irq_type , irq_index );
158
159 // call the implementation specific ICU driver to disable IRQ
160 if( icu->impl == IMPL_ICU_XCU )
161 {
162 soclib_xcu_disable_irq( icu , 1<<irq_index , irq_type , lid );
163 }
164
165 // This is only done for HWI or WTI that are not IPI
166 if( irq_type != PTI_TYPE )
167 {
168 // get selected remote core local pointer, and remove
169 // the source chdev xptr from relevant interrupt vector
170 core_t * core = &LOCAL_CLUSTER->core_tbl[lid];
171 core_set_irq_vector_entry( core , irq_type , irq_index , NULL );
172 }
173}
174
175///////////////////////////////////////
176void dev_icu_get_masks( lid_t lid,
177 uint32_t * hwi_mask,
178 uint32_t * wti_mask,
179 uint32_t * pti_mask )
180{
181 // get local pointer on local ICU chdev
182 xptr_t icu_xp = chdev_dir.icu[local_cxy];
183 chdev_t * icu = (chdev_t *)GET_PTR( icu_xp );
184
185 if( icu->impl == IMPL_ICU_XCU )
186 {
187 soclib_xcu_get_masks( icu , lid , hwi_mask , wti_mask , pti_mask );
188 }
189}
190
191//////////////////////////////////////////////
192void dev_icu_set_period( uint32_t pti_index,
193 uint32_t period )
194{
195 // get local pointer on local ICU chdev
196 xptr_t icu_xp = chdev_dir.icu[local_cxy];
197 chdev_t * icu = (chdev_t *)GET_PTR( icu_xp );
198
199 // check PTI index
200 assert( (pti_index < icu->ext.icu.pti_nr) , __FUNCTION__ , "illegal PTI index" );
201
202 // call the implementation specific driver ICU to set period
203 if( icu->impl == IMPL_ICU_XCU )
204 {
205 soclib_xcu_set_period( icu , pti_index , period );
206 }
207}
208
209////////////////////////////////////////////
210void dev_icu_ack_timer( uint32_t pti_index )
211{
212 // get local pointer on local ICU chdev
213 xptr_t icu_xp = chdev_dir.icu[local_cxy];
214 chdev_t * icu = (chdev_t *)GET_PTR( icu_xp );
215
216 // check PTI index
217 assert( (pti_index < icu->ext.icu.pti_nr) , __FUNCTION__ , "illegal PTI index" );
218
219 // call the implementation specific driver ICU to acknowledge PTI IRQ
220 if( icu->impl == IMPL_ICU_XCU )
221 {
222 soclib_xcu_ack_timer( icu , pti_index );
223 }
224}
225
226////////////////////////////////////
227void dev_icu_send_ipi( cxy_t cxy,
228 lid_t lid )
229{
230 // check arguments
231 cluster_t * cluster = LOCAL_CLUSTER;
232 uint32_t y_width = cluster->y_width;
233 uint32_t x_size = cluster->x_size;
234 uint32_t y_size = cluster->y_size;
235 uint32_t cores_nr = cluster->cores_nr;
236 uint32_t x = cxy >> y_width;
237 uint32_t y = cxy & ((1<<y_width)-1);
238
239 assert( ((x < x_size) && (y < y_size)) , __FUNCTION__ , "illegal cluster identifier" );
240
241 assert( (lid < cores_nr) , __FUNCTION__ , "illegal core local index" );
242
243 // get extended pointer on target ICU chdev
244 xptr_t icu_xp = chdev_dir.icu[cxy];
245
246 // get target ICU cluster and local pointer
247 cxy_t icu_cxy = GET_CXY( icu_xp );
248 chdev_t * icu_ptr = (chdev_t *)GET_PTR( icu_xp );
249
250 // get implementation from remote ICU chdev
251 uint32_t impl = hal_remote_lw( XPTR( icu_cxy , &icu_ptr->impl ) );
252
253 // call the implementation specific ICU driver to send IPI
254 if( impl == IMPL_ICU_XCU )
255 {
256 soclib_xcu_send_ipi( icu_xp , lid );
257 }
258}
259
260//////////////////////////
261void dev_icu_irq_handler()
262{
263 uint32_t hwi_status; // HWI index + 1 / no pending HWI if 0
264 uint32_t wti_status; // WTI index + 1 / no pending WTI if 0
265 uint32_t pti_status; // PTI index + 1 / no pending PTI if 0
266 chdev_t * src_chdev; // pointer on source chdev descriptor
267 uint32_t index; // IRQ index
268
269 core_t * core = CURRENT_CORE;
270
271 // get local pointer on local ICU chdev
272 xptr_t icu_xp = chdev_dir.icu[local_cxy];
273 chdev_t * icu = (chdev_t *)GET_PTR( icu_xp );
274
275 // call the implementation specific ICU driver
276 // to return highest priority pending IRQ of each type
277 if( icu->impl == IMPL_ICU_XCU )
278 {
279 soclib_xcu_get_status( icu , core->lid , &hwi_status , &wti_status , &pti_status );
280 }
281
282 // analyse ICU status and handle up to 3 pending IRQ (one WTI, one HWI, one PTI)
283
284 if( wti_status ) // pending WTI
285 {
286 index = wti_status - 1;
287
288 if( index < LOCAL_CLUSTER->cores_nr ) // it is an IPI
289 {
290 assert( (index == core->lid) , __FUNCTION__ , "illegal IPI index" );
291
292 // TODO acknowledge WTI [AG]
293
294 // TODO force scheduling [AG]
295 }
296 else // it is an external device
297 {
298 // get pointer on IRQ source chdev
299 src_chdev = core->wti_vector[index];
300
301 if( src_chdev == NULL ) // strange, but not fatal => disable IRQ
302 {
303 printk("\n[WARNING] in %s : no handler for WTI %d on core %d in cluster %x\n",
304 __FUNCTION__ , index , core->lid , local_cxy );
305 core->spurious_irqs ++;
306 dev_icu_disable_irq( core->lid , WTI_TYPE , index );
307 }
308 else // call relevant ISR
309 {
310 icu_dmsg("\n[INFO] %s received WTI : index = %d for cpu %d in cluster %d\n",
311 __FUNCTION__ , index , core->lid , local_cxy );
312
313 // call ISR
314 src_chdev->isr( src_chdev );
315 }
316 }
317 }
318
319 if( hwi_status ) // pending HWI
320 {
321 index = hwi_status - 1;
322
323 // get pointer on IRQ source chdev
324 src_chdev = core->hwi_vector[index];
325
326 if( src_chdev == NULL ) // strange, but not fatal => disable IRQ
327 {
328 printk("\n[WARNING] in %s : no handler for HWI %d on core %d in cluster %x\n",
329 __FUNCTION__ , index , core->lid , local_cxy );
330 core->spurious_irqs ++;
331 dev_icu_disable_irq( core->lid , HWI_TYPE , index );
332 }
333 else // call relevant ISR
334 {
335 icu_dmsg("\n[INFO] %s received HWI : index = %d for cpu %d in cluster %d\n",
336 __FUNCTION__ , index , core->lid , local_cxy );
337
338 // call ISR
339 src_chdev->isr( src_chdev );
340 }
341 }
342
343 if( pti_status ) // pending PTI
344 {
345 index = pti_status - 1;
346
347 icu_dmsg("\n[INFO] %s received PTI : index = %d for cpu %d in cluster %d\n",
348 __FUNCTION__ , index , core->lid , local_cxy );
349
350 // acknowledge PTI
351 dev_icu_ack_timer( index );
352
353 if( index < LOCAL_CLUSTER->cores_nr ) // its a TICK event
354 {
355 // TODO execute all actions related to TICK event
356 core_clock( core );
357 }
358 else
359 {
360 printk("\n[WARNING] in %s : no handler for PTI %d on core %d in cluster %x\n",
361 __FUNCTION__ , index , core->lid , local_cxy );
362 core->spurious_irqs ++;
363 dev_icu_disable_irq( core->lid , PTI_TYPE , index );
364 }
365 }
366}
367
368////////////////////////////
369uint32_t dev_icu_wti_alloc()
370{
371 // get local pointer on local ICU chdev
372 xptr_t icu_xp = chdev_dir.icu[local_cxy];
373 chdev_t * icu = (chdev_t *)GET_PTR( icu_xp );
374
375 // get bitmap pointer, lock pointer, and size
376 uint32_t * bitmap = &icu->ext.icu.wti_bitmap;
377 spinlock_t * lock = &icu->ext.icu.wti_lock;
378 uint32_t size = icu->ext.icu.wti_nr;
379
380 // get lock protecting WTI allocator
381 spinlock_lock( lock );
382
383 // get first free mailbox index
384 uint32_t index = (uint32_t)bitmap_ffc( bitmap , size );
385
386 // set bitmap entry if found
387 if( index < size ) bitmap_set( bitmap , index );
388
389 // release lock
390 spinlock_unlock( lock );
391
392 return index;
393}
394
395//////////////////////////////////////////
396void dev_icu_wti_release( uint32_t index )
397{
398 // get pointer on local ICU chdev descriptor
399 xptr_t icu_xp = chdev_dir.icu[local_cxy];
400 chdev_t * icu_ptr = (chdev_t *)GET_PTR( icu_xp );
401
402 // get bitmap pointer, lock, and size
403 bitmap_t * bitmap = &icu_ptr->ext.icu.wti_bitmap;
404 spinlock_t * lock = &icu_ptr->ext.icu.wti_lock;
405 uint32_t size = icu_ptr->ext.icu.wti_nr;
406
407 // check index
408 assert( (index < size) , __FUNCTION__ , "illegal WTI index" );
409
410 // get lock protecting WTI allocator
411 spinlock_lock( lock );
412
413 // clear bitmap entry
414 bitmap_clear( bitmap , index );
415
416 // release lock
417 spinlock_unlock( lock );
418}
419
420//////////////////////////////////////////////
421uint32_t * dev_icu_wti_ptr( uint32_t wti_id )
422{
423 uint32_t * wti_ptr = NULL;
424
425 // get pointer on local ICU chdev descriptor
426 xptr_t icu_xp = chdev_dir.icu[local_cxy];
427 chdev_t * icu = (chdev_t *)GET_PTR( icu_xp );
428
429 // call implementation specific ICU driver
430 if( icu->impl == IMPL_ICU_XCU )
431 {
432 wti_ptr = soclib_xcu_wti_ptr( icu , wti_id );
433 }
434
435 return wti_ptr;
436}
437
Note: See TracBrowser for help on using the repository browser.