source: trunk/hal/tsar_mips32/drivers/soclib_pic.c @ 280

Last change on this file since 280 was 279, checked in by alain, 7 years ago

1) Introduce independant command fields for the various devices in the thread descriptor.
2) Introduce a new dev_pic_enable_ipi() function in the generic PIC device
3) Fix two bugs identified by Maxime in the scheduler initialisation, and in the sched_select().
4) fix several bugs in the TSAR hal_kentry.S.
5) Introduce a third kgiet segment (besides kdata and kcode) in the TSAR bootloader.

File size: 18.5 KB
Line 
1/*
2 * soclib_pic.c - soclib PIC driver implementation.
3 *
4 * Author  Alain Greiner (2016,2017)
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 <chdev.h>
26#include <soclib_pic.h>
27#include <errno.h>
28#include <string.h>
29#include <vfs.h>
30#include <cluster.h>
31#include <printk.h>
32#include <core.h>
33#include <thread.h>
34
35//////////////////////////////////////////////////////////////////////////////////////
36//         Extern variables
37//////////////////////////////////////////////////////////////////////////////////////
38
39extern  chdev_directory_t chdev_dir;    // defined in chdev.h / allocated in kerneL-init.c
40
41extern  iopic_input_t  iopic_input;  // defined in dev_pic.h / allocated in kernel_init.c
42extern  lapic_input_t  lapic_input;  // defined in dev_pic.h / allocated in kernel_init.c
43 
44//////////////////////////////////////////////////////////////////////////////////////
45//        SOCLIB PIC private functions
46//////////////////////////////////////////////////////////////////////////////////////
47
48///////////////////////////////
49uint32_t soclib_pic_wti_alloc()
50{
51    uint32_t index;
52
53    // get pointer on cluster extension for SOCLIB PIC (XCU descriptor)
54    soclib_pic_cluster_t * ext_ptr = LOCAL_CLUSTER->pic_extend;
55
56    assert( (ext_ptr->first_free_wti < ext_ptr->wti_nr) , __FUNCTION__ ,
57            "no free WTI found : too much external IRQs\n");
58
59    // update WTI allocator
60    index = ext_ptr->first_free_wti;
61    ext_ptr->first_free_wti++;
62
63    return index;
64
65}  // end soclib_pic_wti_alloc()
66
67///////////////////////////////////////
68inline uint32_t * soclib_pic_xcu_base()
69{
70    return ((soclib_pic_cluster_t *)(LOCAL_CLUSTER->pic_extend))->xcu_base;
71}
72
73/////////////////////////////////////////////////////////
74inline uint32_t * soclib_pic_remote_xcu_base( cxy_t cxy )
75{
76    soclib_pic_cluster_t * extend;
77
78    // get extended pointer on PIC extension in remote cluster
79    extend = hal_remote_lpt( XPTR( cxy , &cluster_manager.pic_extend ) );
80
81        return (uint32_t *)hal_remote_lpt( XPTR( cxy , &extend->xcu_base ) );
82                 
83}
84
85///////////////////////////////////////////
86void soclib_pic_xcu_status( lid_t      lid,
87                            uint32_t * hwi_status,
88                            uint32_t * wti_status,
89                            uint32_t * pti_status )
90{
91    // get local XCU segment base
92        uint32_t * base = soclib_pic_xcu_base();
93
94    // read PRIO register
95        uint32_t prio = base[(XCU_PRIO << 5) | lid];
96
97    *wti_status = (prio & 0x4) ? (((prio >> 24) & 0x1F) + 1) : 0;
98    *hwi_status = (prio & 0x2) ? (((prio >> 16) & 0x1F) + 1) : 0;
99    *pti_status = (prio & 0x1) ? (((prio >>  8) & 0x1F) + 1) : 0;
100
101}
102
103////////////////////////////////////////////////////
104inline uint32_t soclib_pic_xcu_ack( uint32_t * reg )
105{
106    return *reg;
107}
108
109/////////////////////////////
110void soclib_pic_irq_handler()
111{
112    uint32_t   hwi_status;   // HWI index + 1  / no pending HWI if 0
113    uint32_t   wti_status;   // WTI index + 1  / no pending WTI if 0
114    uint32_t   pti_status;   // PTI index + 1  / no pending PTI if 0
115    chdev_t  * src_chdev;    // pointer on source chdev descriptor
116    uint32_t   index;        // WTI / HWI / PTI index
117    uint32_t   ack;          // XCU acknowledge requires a read...
118
119    core_t * core = CURRENT_THREAD->core;
120
121    // get XCU status
122    soclib_pic_xcu_status( core->lid,
123                           &hwi_status,
124                           &wti_status,
125                           &pti_status );
126
127    irq_dmsg("\n[INFO] %s : enter / WTI_STS = %x / HWI_STS = %x / WTI_STS = %x\n",
128             __FUNCTION__ , wti_status , hwi_status , pti_status );
129
130    // analyse status and handle up to 3 pending IRQ (one WTI, one HWI, one PTI)
131
132    if( wti_status )          // pending WTI
133        {
134        index = wti_status - 1;
135
136        if( index < LOCAL_CLUSTER->cores_nr )   // it is an IPI
137        {
138            assert( (index == core->lid) , __FUNCTION__ , "illegal IPI index" );
139
140            // acknowledge WTI
141            uint32_t * base = soclib_pic_xcu_base();
142            ack = base[(XCU_WTI_REG << 5) | core->lid];
143
144            // force scheduling
145            sched_yield();
146        }
147        else                                    // it is an external device
148        {
149            // get pointer on source chdev
150            src_chdev = ((soclib_pic_core_t *)core->pic_extend)->wti_vector[index];
151
152                    if( src_chdev == NULL )        // strange, but not fatal
153                    {
154                printk("\n[WARNING] in %s : no handler for WTI %d on core %d in cluster %x\n",
155                       __FUNCTION__ , index , core->lid , local_cxy );
156
157                    core->spurious_irqs ++;
158
159                // disable WTI in local XCU controller
160                uint32_t * base = soclib_pic_xcu_base();
161                base[(XCU_MSK_WTI_DISABLE << 5) | core->lid] = 1 << core->lid;
162            }
163            else                                 // call relevant ISR
164            {
165                        irq_dmsg("\n[INFO] %s received WTI : index = %d for core %d in cluster %d\n",
166                         __FUNCTION__ , index , core->lid , local_cxy );
167
168                // call ISR
169                    src_chdev->isr( src_chdev );
170            }
171        }
172        }
173
174        if( hwi_status )      // pending HWI
175        {
176        index = hwi_status - 1;
177
178        // get pointer on source chdev
179        src_chdev = ((soclib_pic_core_t *)core->pic_extend)->hwi_vector[index];
180
181                if( src_chdev == NULL )        // strange, but not fatal
182                {
183            printk("\n[WARNING] in %s : no handler for HWI %d on core %d in cluster %x\n",
184                   __FUNCTION__ , index , core->lid , local_cxy );
185
186                core->spurious_irqs ++;
187
188            // disable HWI in local XCU controller
189            uint32_t * base = soclib_pic_xcu_base();
190            base[(XCU_MSK_HWI_DISABLE << 5) | core->lid] = 1 << core->lid;
191                }
192        else                    // call relevant ISR
193        {
194                    irq_dmsg("\n[INFO] %s received HWI : index = %d for core %d in cluster %d\n",
195                     __FUNCTION__ , index , core->lid , local_cxy );
196
197            // call ISR
198                    src_chdev->isr( src_chdev );
199        }
200        }
201
202    if( pti_status )      // pending PTI
203        {
204        index = pti_status - 1;
205
206                irq_dmsg("\n[INFO] %s received PTI : index = %d for cpu %d in cluster %d\n",
207                 __FUNCTION__ , index , core->lid , local_cxy );
208
209        assert( (index == core->lid) , __FUNCTION__ , "unconsistent PTI index\n");
210
211        // acknowledge PTI
212        uint32_t * base = soclib_pic_xcu_base();
213        ack = base[(XCU_PTI_ACK << 5) | core->lid];
214
215        // execute all actions related to TICK event
216        core_clock( core );
217        }
218}  // end soclib_pic_irq_handler()
219
220
221
222
223//////////////////////////////////////////////////////////////////////////////////////
224//         SOCLIC PIC device  generic API
225//////////////////////////////////////////////////////////////////////////////////////
226
227/////////////////////////////////////
228void soclib_pic_init( chdev_t * pic )
229{
230    uint32_t    i;      // for loop on IOPIC inputs
231    uint32_t    x;      // for loop on clusters in a row
232    uint32_t    y;      // for loop on clusters in a column inputs
233    uint32_t    lid;    // for loop on cores in a cluster
234
235    // get target architecture parameters
236    cluster_t * cluster = LOCAL_CLUSTER;
237    uint32_t    x_size  = cluster->x_size;
238    uint32_t    y_size  = cluster->y_size;
239    uint32_t    y_width = cluster->y_width;
240    uint32_t    ncores  = cluster->cores_nr;
241
242    // get IOPIC controller cluster and segment base pointer
243    cxy_t      iopic_seg_cxy = (cxy_t)GET_CXY( pic->base );
244    uint32_t * iopic_seg_ptr = (uint32_t *)GET_PTR( pic->base );
245
246    // reset the IOPIC component registers : mask all input IRQs
247    for( i = 0 ; i < CONFIG_MAX_EXTERNAL_IRQS ; i++ )
248    {
249        xptr_t iopic_seg_xp = XPTR( iopic_seg_cxy,
250                                    iopic_seg_ptr + i*IOPIC_SPAN + IOPIC_MASK ); 
251        hal_remote_sw( iopic_seg_xp , 0 ); 
252    }
253   
254    // GET XCU controller segment base
255    uint32_t * base = soclib_pic_xcu_base();
256
257    // reset the XCU component registers in all clusters:
258    // mask all HWIs, all WTIs, and all PTIs, for all cores   
259    for( x = 0 ; x < x_size ; x++ )
260    {
261        for( y = 0 ; y < y_size ; y++ )
262        {
263            for( lid = 0 ; lid < ncores ; lid++ )
264            {
265                cxy_t cxy = (x<<y_width) + y;
266                xptr_t hwi_mask_xp = XPTR( cxy , base + (XCU_MSK_HWI_DISABLE << 5 | lid) );
267                xptr_t wti_mask_xp = XPTR( cxy , base + (XCU_MSK_WTI_DISABLE << 5 | lid) );
268                xptr_t pti_mask_xp = XPTR( cxy , base + (XCU_MSK_PTI_DISABLE << 5 | lid) );
269                hal_remote_sw( hwi_mask_xp , 0xFFFFFFFF );
270                hal_remote_sw( wti_mask_xp , 0xFFFFFFFF );
271                hal_remote_sw( pti_mask_xp , 0xFFFFFFFF );
272            }
273        }
274    }
275}  // end soclib_pic_init()
276
277//////////////////////////////////////////////////
278void soclib_pic_extend_init( uint32_t * xcu_base )
279{
280    soclib_pic_cluster_t * cluster_ext_ptr;   
281    soclib_pic_core_t    * core_ext_ptr;
282    kmem_req_t             req;
283    uint32_t               lid;
284    uint32_t               idx;
285
286    cluster_t            * cluster = LOCAL_CLUSTER;
287
288    // create core extension for all cores in cluster
289    for( lid = 0 ; lid < cluster->cores_nr ; lid++ )
290    {
291        // allocate memory for core extension
292        req.type     = KMEM_GENERIC;
293        req.size     = sizeof(soclib_pic_core_t);
294        req.flags    = AF_KERNEL;
295        core_ext_ptr = kmem_alloc( &req );
296
297        assert( (core_ext_ptr != NULL) , __FUNCTION__ ,
298                "cannot allocate memory for core extension\n");
299   
300        // reset the HWI / WTI  interrupt vectors
301        for( idx = 0 ; idx < SOCLIB_MAX_HWI ; idx++ ) core_ext_ptr->hwi_vector[idx] = NULL;
302        for( idx = 0 ; idx < SOCLIB_MAX_WTI ; idx++ ) core_ext_ptr->wti_vector[idx] = NULL;
303
304        // register PIC extension in core descriptor
305        cluster->core_tbl[lid].pic_extend = core_ext_ptr;
306    }
307
308    // allocate memory for cluster extension
309    req.type        = KMEM_GENERIC;
310    req.size        = sizeof(soclib_pic_cluster_t);
311    req.flags       = AF_KERNEL;
312    cluster_ext_ptr = kmem_alloc( &req );
313
314    assert( (cluster_ext_ptr != NULL) , __FUNCTION__ ,
315            "cannot allocate memory for cluster extension\n");
316
317    // get XCU characteristics from the XCU config register
318    uint32_t  config = xcu_base[XCU_CONFIG<<5];
319    uint32_t  wti_nr = (config >> 16) & 0xFF; 
320    uint32_t  hwi_nr = (config >> 8 ) & 0xFF; 
321    uint32_t  pti_nr = (config      ) & 0xFF; 
322
323    // initialize the cluster extension
324    // The first WTI slots are for IPIs (one slot per core)
325    cluster_ext_ptr->xcu_base       = xcu_base;
326    cluster_ext_ptr->hwi_nr         = hwi_nr;
327    cluster_ext_ptr->wti_nr         = wti_nr;
328    cluster_ext_ptr->pti_nr         = pti_nr;
329    cluster_ext_ptr->first_free_wti = cluster->cores_nr;
330
331    // register PIC extension in cluster manager
332    cluster->pic_extend = cluster_ext_ptr;
333
334}  // end soclib_pic_extend_init()
335
336////////////////////////////////////////
337void soclib_pic_bind_irq( lid_t     lid,
338                          chdev_t * src_chdev )
339{
340    // get extended & local pointers on PIC chdev descriptor
341    xptr_t     pic_xp  = chdev_dir.pic;
342    cxy_t      pic_cxy = GET_CXY( pic_xp );
343    chdev_t *  pic_ptr = (chdev_t *)GET_PTR( pic_xp );
344
345    // get extended and local pointers on IOPIC  segment base
346    xptr_t     seg_pic_xp  = hal_remote_lwd( XPTR( pic_cxy , &pic_ptr->base ) );
347    cxy_t      seg_pic_cxy = GET_CXY( seg_pic_xp );
348    uint32_t * seg_pic_ptr = (uint32_t *)GET_PTR( seg_pic_xp );
349
350    // get local pointer on XCU segment base
351    uint32_t * seg_xcu_ptr = soclib_pic_xcu_base();
352
353    // get the source chdev functionnal type, channel, and direction
354    uint32_t func    = src_chdev->func;
355    uint32_t channel = src_chdev->channel;
356    bool_t   is_rx   = src_chdev->is_rx;
357
358    if( (func == DEV_FUNC_IOC) || (func == DEV_FUNC_NIC) ||
359        (func == DEV_FUNC_TXT) || (func == DEV_FUNC_IOB) )          // external IRQ => WTI
360    {
361        // get external IRQ index
362        uint32_t  irq_id;   
363        if     (  func == DEV_FUNC_IOC            ) irq_id = iopic_input.ioc[channel];
364        else if(  func == DEV_FUNC_TXT            ) irq_id = iopic_input.txt[channel];
365        else if( (func == DEV_FUNC_NIC) &&  is_rx ) irq_id = iopic_input.nic_rx[channel];
366        else if( (func == DEV_FUNC_NIC) && !is_rx ) irq_id = iopic_input.nic_tx[channel];
367        else if(  func == DEV_FUNC_IOB            ) irq_id = iopic_input.iob;
368        else      assert( false , __FUNCTION__ , "illegal device functionnal type\n");
369
370        // get a WTI mailbox from local XCU descriptor 
371        uint32_t wti_id = soclib_pic_wti_alloc();
372
373        // register IRQ type and index in chdev
374        src_chdev->irq_type = SOCLIB_TYPE_WTI;
375        src_chdev->irq_id   = wti_id;
376
377        // compute extended pointer on WTI mailbox in local XCU
378        xptr_t wti_xp = XPTR( local_cxy , &seg_xcu_ptr[(XCU_WTI_REG << 5) | wti_id] );
379
380            // set the IOPIC_ADDRESS and IOPIC_EXTEND registers in IOPIC
381        uint32_t lsb_wdata = (uint32_t)wti_xp;
382        uint32_t msb_wdata = (uint32_t)(wti_xp >> 32);
383        xptr_t   lsb_xp = XPTR( seg_pic_cxy , seg_pic_ptr+irq_id*IOPIC_SPAN+IOPIC_ADDRESS );
384        xptr_t   msb_xp = XPTR( seg_pic_cxy , seg_pic_ptr+irq_id*IOPIC_SPAN+IOPIC_EXTEND );
385        hal_remote_sw( lsb_xp , lsb_wdata );
386        hal_remote_sw( msb_xp , msb_wdata );
387
388        // unmask IRQ in IOPIC
389        hal_remote_sw( XPTR( seg_pic_cxy , seg_pic_ptr+irq_id*IOPIC_SPAN+IOPIC_MASK ), 1 );
390
391        // update the WTI interrupt vector for core[lid]
392        core_t * core = &LOCAL_CLUSTER->core_tbl[lid];
393        ((soclib_pic_core_t *)core->pic_extend)->wti_vector[wti_id] = src_chdev;
394    }
395    else if( (func == DEV_FUNC_DMA) || (func == DEV_FUNC_MMC) )   // internal IRQ => HWI
396    {
397        // get internal IRQ index
398        uint32_t hwi_id;
399        if( func == DEV_FUNC_DMA ) hwi_id = lapic_input.dma[channel];
400        else                       hwi_id = lapic_input.mmc;
401
402        // register IRQ type and index in chdev
403        src_chdev->irq_type = SOCLIB_TYPE_HWI;
404        src_chdev->irq_id   = hwi_id;
405
406        // update the HWI interrupt vector for core[lid]
407        core_t * core = &LOCAL_CLUSTER->core_tbl[lid];
408        ((soclib_pic_core_t *)core->pic_extend)->wti_vector[hwi_id] = src_chdev;
409    }
410    else
411    {
412        assert( false , __FUNCTION__ , "illegal device functionnal type\n" );
413    } 
414}  // end soclib_pic_bind_irq();
415
416///////////////////////////////////////
417void soclib_pic_enable_irq( lid_t  lid,
418                            xptr_t src_chdev_xp )
419{
420    // get cluster and local pointer on remote src_chdev
421    cxy_t     src_chdev_cxy = GET_CXY( src_chdev_xp );
422    chdev_t * src_chdev_ptr = (chdev_t *)GET_PTR( src_chdev_xp );
423
424    // get local pointer on remote XCU segment base
425    uint32_t * seg_xcu_ptr = soclib_pic_remote_xcu_base( src_chdev_cxy );
426
427    // get the source chdev IRQ type and index
428    uint32_t irq_type = hal_remote_lw( XPTR( src_chdev_cxy , &src_chdev_ptr->irq_type ) );
429    uint32_t irq_id   = hal_remote_lw( XPTR( src_chdev_cxy , &src_chdev_ptr->irq_id ) );
430
431    if( irq_type == SOCLIB_TYPE_HWI )
432    {
433        // enable this HWI in remote XCU controller
434        hal_remote_sw( XPTR( src_chdev_cxy , 
435                       &seg_xcu_ptr[(XCU_MSK_HWI_ENABLE << 5) | lid] ) , (1 << irq_id) );
436    }
437    else if( irq_type == SOCLIB_TYPE_WTI )
438    {
439        // enable this WTI in remote XCU controller
440        hal_remote_sw( XPTR( src_chdev_cxy , 
441                       &seg_xcu_ptr[(XCU_MSK_WTI_ENABLE << 5) | lid] ) , (1 << irq_id) );
442    }
443    else
444    {
445        assert( false , __FUNCTION__ , "illegal IRQ type\n" );
446    }
447} // end soclib_pic_enable_irq()
448
449////////////////////////////////////////
450void soclib_pic_disable_irq( lid_t  lid,
451                             xptr_t src_chdev_xp )
452{
453    // get cluster and local pointer on remote src_chdev
454    cxy_t     src_chdev_cxy = GET_CXY( src_chdev_xp );
455    chdev_t * src_chdev_ptr = (chdev_t *)GET_PTR( src_chdev_xp );
456
457    // get local pointer on remote XCU segment base
458    uint32_t * seg_xcu_ptr = soclib_pic_remote_xcu_base( src_chdev_cxy );
459
460    // get the source chdev IRQ type and index
461    uint32_t irq_type = hal_remote_lw( XPTR( src_chdev_cxy , &src_chdev_ptr->irq_type ) );
462    uint32_t irq_id   = hal_remote_lw( XPTR( src_chdev_cxy , &src_chdev_ptr->irq_id ) );
463
464    if( irq_type == SOCLIB_TYPE_HWI )
465    {
466        // enable this HWI in remote XCU controller
467        hal_remote_sw( XPTR( src_chdev_cxy , 
468                       &seg_xcu_ptr[(XCU_MSK_HWI_DISABLE << 5) | lid] ) , (1 << irq_id) );
469    }
470    else if( irq_type == SOCLIB_TYPE_WTI )
471    {
472        // enable this WTI in remote XCU controller
473        hal_remote_sw( XPTR( src_chdev_cxy , 
474                       &seg_xcu_ptr[(XCU_MSK_WTI_DISABLE << 5) | lid] ) , (1 << irq_id) );
475    }
476    else
477    {
478        assert( false , __FUNCTION__ , "illegal IRQ type\n" );
479    }
480} // end soclib_pic_enable_irq()
481
482///////////////////////////////////////////////
483void soclib_pic_enable_timer( uint32_t period )
484{
485    // calling core local index
486    lid_t  lid = CURRENT_CORE->lid;
487
488    // get XCU segment base
489    uint32_t * base = soclib_pic_xcu_base();
490
491    // set period value in XCU
492    base[(XCU_PTI_PER << 5) | lid] = period;
493
494    // enable PTI in local XCU controller
495    base[(XCU_MSK_PTI_ENABLE << 5) | lid] = 1 << lid;
496}
497
498////////////////////////////
499void soclib_pic_enable_ipi()
500{
501    // calling core local index
502    lid_t  lid = CURRENT_CORE->lid;
503
504    // get XCU segment base
505    uint32_t * base = soclib_pic_xcu_base();
506
507    // enable WTI in local XCU controller
508    base[(XCU_MSK_WTI_ENABLE << 5) | lid] = 1 << lid;
509}
510
511///////////////////////////////////////
512void soclib_pic_send_ipi( cxy_t    cxy,
513                          lid_t    lid )
514{
515    // get pointer on local XCU segment base
516    uint32_t * base = soclib_pic_xcu_base();
517
518    // write to WTI mailbox[cxy][lid]
519    hal_remote_sw( XPTR( cxy , &base[(XCU_WTI_REG << 5) | lid] ) , 0 );
520}
521
522
523
Note: See TracBrowser for help on using the repository browser.