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

Last change on this file since 188 was 136, checked in by max@…, 7 years ago

Hide a few soclib_xcu_ functions

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