11
11
#define gic_debug (x , ...)
12
12
#endif
13
13
14
- #define GIC_ICID 0 /* a single interrupt collection is being used */
14
+ #define GIC_ICID ( cpuid ) (cpuid) /* mapping between target CPU and interrupt collection */
15
15
16
16
/* The physical address of the command queue must be aligned to 64 KB. */
17
17
#define GIC_CMD_QUEUE_SIZE (64 * KB)
@@ -22,14 +22,16 @@ static struct {
22
22
u64 dist_base ;
23
23
struct {
24
24
u64 base ;
25
- u64 rdbase ;
26
- } redist ; /* redistributor associated to CPU 0 */
25
+ u64 propbase ;
26
+ u64 pendbase ;
27
+ } redist ;
27
28
u64 its_base ;
28
29
u8 * lpi_cfg_table ;
29
30
u64 its_typer ;
30
31
u32 dev_id_limit ;
31
32
void * its_cmd_queue ;
32
33
struct list devices ;
34
+ table its_irq_map ; /* maps interrupt vectors to target CPUs */
33
35
} gic ;
34
36
35
37
typedef struct its_dev {
@@ -40,6 +42,7 @@ typedef struct its_dev {
40
42
41
43
#define gicd_read_32 (reg ) mmio_read_32(gic.dist_base + GICD_ ## reg)
42
44
#define gicd_write_32 (reg , value ) mmio_write_32(gic.dist_base + GICD_ ## reg, value)
45
+ #define gicd_write_64 (reg , value ) mmio_write_64(gic.dist_base + GICD_ ## reg, value)
43
46
44
47
#define gicr_base (current_cpu()->m.gic_rdist_base)
45
48
#define gicr_read_32 (reg ) mmio_read_32(gicr_base + GICR_ ## reg)
@@ -149,6 +152,25 @@ void gic_clear_pending_int(int irq)
149
152
GIC_SET_INTFIELD (priority , IPRIORITY )
150
153
GIC_SET_INTFIELD (config , ICFG )
151
154
155
+ void gic_set_int_target (int irq , u32 target_cpu )
156
+ {
157
+ gic_debug ("irq %d, target %d\n" , irq , target_cpu );
158
+ if ((irq < GIC_SPI_INTS_START ) || (irq >= GIC_SPI_INTS_END ))
159
+ return ;
160
+ if (gic .v3_iface ) { /* use affinity routing */
161
+ u64 mpid = mpid_from_cpuid (target_cpu );
162
+ gicd_write_64 (IROUTER (irq ), mpid );
163
+ } else {
164
+ int reg_num = irq / GICD_INTS_PER_ITARGETS_REG ;
165
+ u32 itargets = gicd_read_32 (ITARGETSR (reg_num ));
166
+ int width = 32 / GICD_INTS_PER_ITARGETS_REG ;
167
+ int reg_offset = (irq - reg_num * GICD_INTS_PER_ITARGETS_REG ) * width ;
168
+ itargets &= ~(MASK32 (width ) << reg_offset );
169
+ itargets |= U32_FROM_BIT (target_cpu ) << reg_offset ;
170
+ gicd_write_32 (ITARGETSR (reg_num ), itargets );
171
+ }
172
+ }
173
+
152
174
boolean gic_int_is_pending (int irq )
153
175
{
154
176
int w = irq / GICD_INTS_PER_IPEND_REG ;
@@ -226,19 +248,14 @@ static void init_gicd(void)
226
248
i < GIC_SPI_INTS_END / GICD_INTS_PER_IGROUP_REG ; i ++ )
227
249
gicd_write_32 (IGROUPR (i ), MASK (32 ));
228
250
229
- /* shared periph target cpu0 */
230
- for (int i = GIC_SPI_INTS_START / GICD_INTS_PER_ITARGETS_REG ;
231
- i < GIC_SPI_INTS_END / GICD_INTS_PER_ITARGETS_REG ; i ++ )
232
- gicd_write_32 (ITARGETSR (i ), 0x01010101 );
233
-
234
- /* enable
235
- XXX - turn on affinity routing (ARE)? */
236
-
237
251
/* Kludge: We seem to have one gicv2 variant (qemu w/ noaccel) that honors
238
252
bit 1 as GRP1 enable, and another (qemu w/ kvm on bcm2711) which
239
253
doesn't, so set both for now until the variants can be sorted
240
254
out. (This may be due to the presence of GIC Security Extensions. */
241
- gicd_write_32 (CTLR , GICD_CTLR_ENABLEGRP1 | GICD_CTLR_ENABLEGRP0 );
255
+ u32 ctrl = GICD_CTLR_ENABLEGRP1 | GICD_CTLR_ENABLEGRP0 ;
256
+ if (gic .v3_iface )
257
+ ctrl |= GICD_CTLR_ARE_NS ; /* enable affinity routing */
258
+ gicd_write_32 (CTLR , ctrl );
242
259
}
243
260
244
261
/* aliases for macro use */
@@ -265,7 +282,7 @@ void gic_eoi(int irq)
265
282
gicc_write (EOIR1 , irq );
266
283
}
267
284
268
- boolean dev_irq_enable (u32 dev_id , int vector )
285
+ boolean dev_irq_enable (u32 dev_id , int vector , u32 target_cpu )
269
286
{
270
287
gic_debug ("dev 0x%x, irq %d\n" , dev_id , vector );
271
288
if ((vector >= gic_msi_vector_base ) && gic .its_base ) {
@@ -304,9 +321,13 @@ boolean dev_irq_enable(u32 dev_id, int vector)
304
321
}
305
322
u32 event_id = vector - gic_msi_vector_base ;
306
323
gic_its_cmd (((u64 )dev_id << 32 ) | ITS_CMD_MAPTI , ((u64 )vector << 32 ) | event_id ,
307
- GIC_ICID , 0 );
324
+ GIC_ICID ( target_cpu ) , 0 );
308
325
gic_its_cmd (((u64 )dev_id << 32 ) | ITS_CMD_INV , event_id , 0 , 0 );
309
- gic_its_cmd (ITS_CMD_SYNC , 0 , gic .redist .rdbase << 16 , 0 );
326
+ cpuinfo ci = cpuinfo_from_id (target_cpu );
327
+ gic_its_cmd (ITS_CMD_SYNC , 0 , ci -> m .gic_rdist_rdbase << 16 , 0 );
328
+ table_set (gic .its_irq_map , pointer_from_u64 ((u64 )vector ), ci );
329
+ } else {
330
+ gic_set_int_target (vector , target_cpu );
310
331
}
311
332
return true;
312
333
}
@@ -318,11 +339,13 @@ void dev_irq_disable(u32 dev_id, int vector)
318
339
u32 event_id = vector - gic_msi_vector_base ;
319
340
gic_its_cmd (((u64 )dev_id << 32 ) | ITS_CMD_DISCARD , event_id , 0 , 0 );
320
341
gic_its_cmd (((u64 )dev_id << 32 ) | ITS_CMD_INV , event_id , 0 , 0 );
321
- gic_its_cmd (ITS_CMD_SYNC , 0 , gic .redist .rdbase << 16 , 0 );
342
+ cpuinfo ci = table_remove (gic .its_irq_map , pointer_from_u64 ((u64 )vector ));
343
+ if (ci )
344
+ gic_its_cmd (ITS_CMD_SYNC , 0 , ci -> m .gic_rdist_rdbase << 16 , 0 );
322
345
}
323
346
}
324
347
325
- void msi_format (u32 * address , u32 * data , int vector )
348
+ void msi_format (u32 * address , u32 * data , int vector , u32 target_cpu )
326
349
{
327
350
if (gic .its_base ) {
328
351
* address = gic .its_base + GITS_TRANSLATER - DEVICE_BASE ;
@@ -333,12 +356,18 @@ void msi_format(u32 *address, u32 *data, int vector)
333
356
}
334
357
}
335
358
336
- int msi_get_vector (u32 data )
337
- {
338
- if (gic .its_base )
339
- return (data + gic_msi_vector_base );
340
- else
341
- return data ;
359
+ void msi_get_config (u32 address , u32 data , int * vector , u32 * target_cpu ) {
360
+ if (gic .its_base ) {
361
+ * vector = data + gic_msi_vector_base ;
362
+ cpuinfo ci = table_find (gic .its_irq_map , pointer_from_u64 ((u64 )* vector ));
363
+ if (ci )
364
+ * target_cpu = ci -> id ;
365
+ else
366
+ * target_cpu = 0 ;
367
+ } else {
368
+ * vector = data ;
369
+ * target_cpu = 0 ; /* retrieval of target CPU not supported */
370
+ }
342
371
}
343
372
344
373
static void init_gicc (void )
@@ -376,14 +405,26 @@ static void init_gicc(void)
376
405
}
377
406
}
378
407
408
+ static void gits_percpu_init (void )
409
+ {
410
+ cpuinfo ci = current_cpu ();
411
+ u64 rdbase ;
412
+ if (gic .its_typer & GITS_TYPER_PTA )
413
+ rdbase = ci -> m .gic_rdist_base >> 16 ;
414
+ else
415
+ rdbase = GICR_TYPER_PROC_NUM (gicr_read_64 (TYPER ));
416
+ gic_debug ("cpu %d, rdbase 0x%lx\n" , ci -> id , rdbase );
417
+ ci -> m .gic_rdist_rdbase = rdbase ;
418
+
419
+ /* map an interrupt collection to the redistributor associated to this CPU */
420
+ gic_its_cmd (ITS_CMD_MAPC , 0 , ITS_MAPC_V | (rdbase << 16 ) | GIC_ICID (ci -> id ), 0 );
421
+ }
422
+
379
423
static void init_gits (kernel_heaps kh )
380
424
{
381
425
gic .its_typer = gits_read_64 (TYPER );
382
426
gic_debug ("typer 0x%lx\n" , gic .its_typer );
383
- if (gic .its_typer & GITS_TYPER_PTA )
384
- gic .redist .rdbase = gic .redist .base >> 16 ;
385
- else
386
- gic .redist .rdbase = GICR_TYPER_PROC_NUM (gicr_read_64 (TYPER ));
427
+ heap h = heap_locked (kh );
387
428
backed_heap backed = heap_linear_backed (kh );
388
429
u64 pa ;
389
430
for (int n = 0 ; n < 8 ; n ++ ) {
@@ -419,6 +460,8 @@ static void init_gits(kernel_heaps kh)
419
460
break ;
420
461
}
421
462
}
463
+ gic .its_irq_map = allocate_table (h , identity_key , pointer_equal );
464
+ assert (gic .its_irq_map != INVALID_ADDRESS );
422
465
list_init (& gic .devices );
423
466
424
467
/* Set up the command queue. */
@@ -429,8 +472,7 @@ static void init_gits(kernel_heaps kh)
429
472
430
473
gits_write_32 (CTLR , GITS_CTRL_ENABLED ); /* Enable the ITS. */
431
474
432
- /* Map an interrupt collection to the redistributor associated to CPU 0. */
433
- gic_its_cmd (ITS_CMD_MAPC , 0 , ITS_MAPC_V | (gic .redist .rdbase << 16 ) | GIC_ICID , 0 );
475
+ gits_percpu_init ();
434
476
}
435
477
436
478
BSS_RO_AFTER_INIT u16 gic_msi_vector_base ;
@@ -496,13 +538,15 @@ int init_gic(void)
496
538
assert (gic .lpi_cfg_table != INVALID_ADDRESS );
497
539
zero (gic .lpi_cfg_table , PAGESIZE );
498
540
u64 id_bits = find_order (gic_msi_vector_base + gic_msi_vector_num ) - 1 ;
499
- gicr_write_64 (PROPBASER , pa | id_bits );
541
+ gic .redist .propbase = pa | id_bits ;
542
+ gicr_write_64 (PROPBASER , gic .redist .propbase );
500
543
501
544
/* Set up LPI pending table, which must be aligned to 64 KB. */
502
545
void * lpi_pending_table = alloc_map (backed , 64 * KB , & pa );
503
546
assert (lpi_pending_table != INVALID_ADDRESS );
504
547
zero (lpi_pending_table , 64 * KB );
505
- gicr_write_64 (PENDBASER , GICR_PENDBASER_PTZ | pa );
548
+ gic .redist .pendbase = GICR_PENDBASER_PTZ | pa ;
549
+ gicr_write_64 (PENDBASER , gic .redist .pendbase );
506
550
507
551
gicr_write_32 (CTLR , GICR_CTLR_EnableLPIs );
508
552
if (gic .its_base )
@@ -525,8 +569,14 @@ int init_gic(void)
525
569
526
570
void gic_percpu_init (void )
527
571
{
528
- if (gic .v3_iface )
572
+ if (gic .v3_iface ) {
529
573
gicr_get_base ();
574
+ gicr_write_64 (PROPBASER , gic .redist .propbase );
575
+ gicr_write_64 (PENDBASER , gic .redist .pendbase );
576
+ gicr_write_32 (CTLR , GICR_CTLR_EnableLPIs );
577
+ if (gic .its_base )
578
+ gits_percpu_init ();
579
+ }
530
580
init_gicd_percpu ();
531
581
init_gicc ();
532
582
}
0 commit comments