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

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

Introduce dev_fbf, dev dma, dev_iob

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