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

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

style

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