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

Last change on this file since 1 was 1, checked in by alain, 5 years ago

First import

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