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

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

use hal_drivers_xcu_init

File size: 13.9 KB
RevLine 
[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>
[131]33#include <hal_drivers.h>
[1]34#include <dev_icu.h>
35
36/////////////////////////////////////////////////////////////////////////////////////////
37// Extern global variables
38/////////////////////////////////////////////////////////////////////////////////////////
39
[3]40extern chdev_directory_t  chdev_dir;         // allocated in kernel_init.c
[1]41
[3]42extern chdev_pic_input_t  chdev_pic_input;   // allocated in kernel_init.c
[1]43
[3]44/////////////////////////////////
45void dev_icu_init( chdev_t * icu,
46                   uint32_t  hwi_nr,
47                   uint32_t  wti_nr,
48                   uint32_t  pti_nr )
[1]49{
[23]50    // set chdev name
51    snprintf( icu->name , 16 , "icu_%x" , local_cxy );
52
[3]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 );
[128]59
[3]60    // get implementation
61    uint32_t impl = icu->impl;
[1]62
[3]63    // call the relevant driver init function
[1]64    if( impl == IMPL_ICU_XCU )
65    {
[3]66        uint32_t  lid;
67        for( lid = 0 ; lid < LOCAL_CLUSTER->cores_nr ; lid++ )
[1]68        {
[131]69            hal_drivers_xcu_init( icu , lid );
[1]70        }
71    }
72    else
73    {
[3]74        assert( false , __FUNCTION__ , "undefined ICU implementation" );
[1]75    }
[128]76}
[1]77
78/////////////////////////////////////////////////////////////////////////////////////
[3]79// This static function check the irq_type / irq_index arguments.
[1]80// It is called by the dev_icu_enable_irq() & dev_icu_disable_irq() functions.
81/////////////////////////////////////////////////////////////////////////////////////
[3]82static inline void dev_icu_check_irq( chdev_t  * icu,
[1]83                                      uint32_t   irq_type,
84                                      uint32_t   irq_index )
85{
[128]86    if( irq_type == HWI_TYPE )
[1]87    {
[14]88        if( irq_index >= icu->ext.icu.hwi_nr )
89        {
[128]90            printk("\n[PANIC] in %s : illegal HWI index = %d / max = %d\n",
[14]91                   __FUNCTION__ , irq_index , icu->ext.icu.hwi_nr );
92            hal_core_sleep();
93        }
[1]94    }
[14]95    else if( irq_type == WTI_TYPE )
[1]96    {
[14]97        if( irq_index >= icu->ext.icu.wti_nr )
98        {
[128]99            printk("\n[PANIC] in %s : illegal WTI index = %d / max = %d\n",
[14]100                   __FUNCTION__ , irq_index , icu->ext.icu.wti_nr );
101            hal_core_sleep();
102        }
[1]103    }
[128]104    else  //  irq_type == PTI_TYPE
[1]105    {
[14]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        }
[1]112    }
[128]113}
[1]114
[3]115////////////////////////////////////////
116void dev_icu_enable_irq( lid_t      lid,
[1]117                         uint32_t   irq_type,
118                         uint32_t   irq_index,
[3]119                         chdev_t  * src_chdev )
[1]120{
[3]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 );
[1]124
125    // check IRQ type and index
[3]126    dev_icu_check_irq( icu , irq_type , irq_index );
[1]127
[14]128    // call implementation specific ICU driver to enable IRQ
[128]129    if( icu->impl == IMPL_ICU_XCU )
[1]130    {
[14]131         soclib_xcu_enable_irq( icu , 1<<irq_index , irq_type , lid );
[1]132    }
133
[14]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];
[128]140        core_set_irq_vector_entry( core , irq_type , irq_index , src_chdev );
[1]141
[14]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    }
[128]146}
[1]147
[3]148/////////////////////////////////////////
149void dev_icu_disable_irq( lid_t      lid,
[1]150                          uint32_t   irq_type,
151                          uint32_t   irq_index )
152{
[3]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 );
[1]156
157    // check IRQ type and index
[3]158    dev_icu_check_irq( icu , irq_type , irq_index );
[1]159
[128]160    // call the implementation specific ICU driver to disable IRQ
161    if( icu->impl == IMPL_ICU_XCU )
[1]162    {
[3]163        soclib_xcu_disable_irq( icu , 1<<irq_index , irq_type , lid );
[1]164    }
165
[14]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];
[128]172        core_set_irq_vector_entry( core , irq_type , irq_index , NULL );
[14]173    }
[128]174}
[1]175
[14]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 );
[1]185
[14]186    if( icu->impl == IMPL_ICU_XCU )
187    {
188        soclib_xcu_get_masks( icu , lid , hwi_mask , wti_mask , pti_mask );
189    }
190}
[1]191
192//////////////////////////////////////////////
193void dev_icu_set_period( uint32_t   pti_index,
194                         uint32_t   period )
195{
[3]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 );
[1]199
200    // check PTI index
[128]201    assert( (pti_index < icu->ext.icu.pti_nr) , __FUNCTION__ , "illegal PTI index" );
[1]202
[128]203    // call the implementation specific driver ICU to set period
204    if( icu->impl == IMPL_ICU_XCU )
[1]205    {
206        soclib_xcu_set_period( icu , pti_index , period );
207    }
[128]208}
[1]209
210////////////////////////////////////////////
211void dev_icu_ack_timer( uint32_t pti_index )
212{
[3]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 );
[1]216
217    // check PTI index
[128]218    assert( (pti_index < icu->ext.icu.pti_nr) , __FUNCTION__ , "illegal PTI index" );
[1]219
220    // call the implementation specific driver ICU to acknowledge PTI IRQ
[128]221    if( icu->impl == IMPL_ICU_XCU )
[1]222    {
223        soclib_xcu_ack_timer( icu , pti_index );
224    }
[128]225}
[1]226
227////////////////////////////////////
228void dev_icu_send_ipi( cxy_t    cxy,
229                       lid_t    lid )
230{
[128]231    // check arguments
[1]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
[3]240    assert( ((x < x_size) && (y < y_size)) , __FUNCTION__ , "illegal cluster identifier" );
[1]241
[3]242    assert( (lid < cores_nr) , __FUNCTION__ , "illegal core local index" );
[1]243
[3]244    // get extended pointer on target ICU chdev
245    xptr_t icu_xp = chdev_dir.icu[cxy];
246
[1]247     // get target ICU cluster and local pointer
[3]248    cxy_t     icu_cxy = GET_CXY( icu_xp );
249    chdev_t * icu_ptr = (chdev_t *)GET_PTR( icu_xp );
[1]250
[3]251    // get implementation from remote ICU chdev
[128]252    uint32_t impl = hal_remote_lw( XPTR( icu_cxy , &icu_ptr->impl ) );
[1]253
254    // call the implementation specific ICU driver to send IPI
[128]255    if( impl == IMPL_ICU_XCU )
[1]256    {
257        soclib_xcu_send_ipi( icu_xp , lid );
258    }
[128]259}
[1]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
[3]267    chdev_t  * src_chdev;    // pointer on source chdev descriptor
[1]268    uint32_t   index;        // IRQ index
269
270    core_t   * core = CURRENT_CORE;
271
[3]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
[128]276    // call the implementation specific ICU driver
[1]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
[128]285    if( wti_status )          // pending WTI
286    {
[1]287        index = wti_status - 1;
288
[3]289        if( index < LOCAL_CLUSTER->cores_nr )   // it is an IPI
290        {
291            assert( (index == core->lid) , __FUNCTION__ , "illegal IPI index" );
[1]292
[3]293            // TODO acknowledge WTI [AG]
294
295            // TODO force scheduling [AG]
[1]296        }
[3]297        else                                    // it is an external device
[1]298        {
[3]299            // get pointer on IRQ source chdev
[128]300            src_chdev = core->wti_vector[index];
[1]301
[128]302            if( src_chdev == NULL )        // strange, but not fatal => disable IRQ
303            {
[3]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 );
[128]306                core->spurious_irqs ++;
307                dev_icu_disable_irq( core->lid , WTI_TYPE , index );
[3]308            }
309            else                                 // call relevant ISR
310            {
[128]311                icu_dmsg("\n[INFO] %s received WTI : index = %d for cpu %d in cluster %d\n",
[3]312                         __FUNCTION__ , index , core->lid , local_cxy );
313
314                // call ISR
[128]315                src_chdev->isr( src_chdev );
[3]316            }
[1]317        }
[128]318    }
[1]319
[128]320    if( hwi_status )      // pending HWI
321    {
[1]322        index = hwi_status - 1;
323
[3]324        // get pointer on IRQ source chdev
[128]325        src_chdev = core->hwi_vector[index];
[1]326
[128]327        if( src_chdev == NULL )        // strange, but not fatal => disable IRQ
328        {
[1]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 );
[128]331            core->spurious_irqs ++;
332            dev_icu_disable_irq( core->lid , HWI_TYPE , index );
333        }
[1]334        else                    // call relevant ISR
335        {
[128]336            icu_dmsg("\n[INFO] %s received HWI : index = %d for cpu %d in cluster %d\n",
[1]337                     __FUNCTION__ , index , core->lid , local_cxy );
338
[3]339            // call ISR
[128]340            src_chdev->isr( src_chdev );
[1]341        }
[128]342    }
[1]343
344    if( pti_status )      // pending PTI
[128]345    {
[1]346        index = pti_status - 1;
347
[128]348        icu_dmsg("\n[INFO] %s received PTI : index = %d for cpu %d in cluster %d\n",
[1]349                 __FUNCTION__ , index , core->lid , local_cxy );
350
351        // acknowledge PTI
352        dev_icu_ack_timer( index );
353
[14]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 );
[128]363            core->spurious_irqs ++;
364            dev_icu_disable_irq( core->lid , PTI_TYPE , index );
[14]365        }
[128]366    }
367}
[1]368
369////////////////////////////
370uint32_t dev_icu_wti_alloc()
371{
[3]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 );
[1]375
[3]376    // get bitmap pointer, lock pointer, and size
377    uint32_t   * bitmap = &icu->ext.icu.wti_bitmap;
[1]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 );
[128]386
[1]387    // set bitmap entry if found
388    if( index < size ) bitmap_set( bitmap , index );
389
390    // release lock
391    spinlock_unlock( lock );
[128]392
[1]393    return index;
[128]394}
[1]395
396//////////////////////////////////////////
397void dev_icu_wti_release( uint32_t index )
398{
[3]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 );
[1]402
403    // get bitmap pointer, lock, and size
[3]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;
[1]407
408    // check index
[3]409    assert( (index < size) , __FUNCTION__ , "illegal WTI index" );
[1]410
411    // get lock protecting WTI allocator
412    spinlock_lock( lock );
413
[128]414    // clear bitmap entry
[1]415    bitmap_clear( bitmap , index );
416
417    // release lock
418    spinlock_unlock( lock );
[128]419}
[3]420
421//////////////////////////////////////////////
422uint32_t * dev_icu_wti_ptr( uint32_t  wti_id )
[1]423{
[3]424    uint32_t *  wti_ptr = NULL;
[1]425
[3]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
[1]430    // call implementation specific ICU driver
431    if( icu->impl == IMPL_ICU_XCU )
432    {
[128]433        wti_ptr = soclib_xcu_wti_ptr( icu , wti_id );
[1]434    }
435
[3]436    return wti_ptr;
[128]437}
[1]438
Note: See TracBrowser for help on using the repository browser.