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

Last change on this file since 22 was 14, checked in by alain, 8 years ago

Bugs fix.

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