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

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

Introduce syscalls.

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