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

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

This version executed successfully the user "init" process on a mono-processor TSAR architecture.

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