hw/intc/arm_gicv5: Implement remaining set-config functions
Implement the GICv5 functions corresponding to the stream protocol SetEnabled, SetPending, SetHandling, and SetTarget commands. These work exactly like SetPriority: the IRS looks up the L2TE and updates the corresponding field in it with the new value. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Message-id: 20260327111700.795099-22-peter.maydell@linaro.org
Peter Maydell committed
Mar 27, 2026 at 11:16 UTC
f2ca526444ca99401f5d89ebc1d2e85c0185a7d7
4 files changed
+239
hw/intc/arm_gicv5.c
+152
@@ -497,6 +497,158 @@ void gicv5_set_priority(GICv5Common *cs, uint32_t id, uint8_t priority,
497
}
498
}
499
500
+void gicv5_set_enabled(GICv5Common *cs, uint32_t id, bool enabled,
501
+ GICv5Domain domain, GICv5IntType type, bool virtual)
502
+{
503
+ GICv5 *s = ARM_GICV5(cs);
504
+
505
+ trace_gicv5_set_enabled(domain_name[domain], inttype_name(type), virtual,
506
+ id, enabled);
507
+ if (virtual) {
508
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_enabled: tried to set "
509
+ "enable state of a virtual interrupt\n");
510
+ return;
511
+ }
512
+
513
+ switch (type) {
514
+ case GICV5_LPI:
515
+ {
516
+ const GICv5ISTConfig *cfg = &s->phys_lpi_config[domain];
517
+ L2_ISTE_Handle h;
518
+ uint32_t *l2_iste_p = get_l2_iste(cs, cfg, id, &h);
519
+
520
+ if (!l2_iste_p) {
521
+ return;
522
+ }
523
+ *l2_iste_p = FIELD_DP32(*l2_iste_p, L2_ISTE, ENABLE, enabled);
524
+ put_l2_iste(cs, cfg, &h);
525
+ break;
526
+ }
527
+ default:
528
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_enabled: tried to set "
529
+ "enable state of bad interrupt type %d\n", type);
530
+ return;
531
+ }
532
+}
533
+
534
+void gicv5_set_pending(GICv5Common *cs, uint32_t id, bool pending,
535
+ GICv5Domain domain, GICv5IntType type, bool virtual)
536
+{
537
+ GICv5 *s = ARM_GICV5(cs);
538
+
539
+ trace_gicv5_set_pending(domain_name[domain], inttype_name(type), virtual,
540
+ id, pending);
541
+ if (virtual) {
542
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_pending: tried to set "
543
+ "pending state of a virtual interrupt\n");
544
+ return;
545
+ }
546
+
547
+ switch (type) {
548
+ case GICV5_LPI:
549
+ {
550
+ const GICv5ISTConfig *cfg = &s->phys_lpi_config[domain];
551
+ L2_ISTE_Handle h;
552
+ uint32_t *l2_iste_p = get_l2_iste(cs, cfg, id, &h);
553
+
554
+ if (!l2_iste_p) {
555
+ return;
556
+ }
557
+ *l2_iste_p = FIELD_DP32(*l2_iste_p, L2_ISTE, PENDING, pending);
558
+ put_l2_iste(cs, cfg, &h);
559
+ break;
560
+ }
561
+ default:
562
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_pending: tried to set "
563
+ "pending state of bad interrupt type %d\n", type);
564
+ return;
565
+ }
566
+}
567
+
568
+void gicv5_set_handling(GICv5Common *cs, uint32_t id,
569
+ GICv5HandlingMode handling, GICv5Domain domain,
570
+ GICv5IntType type, bool virtual)
571
+{
572
+ GICv5 *s = ARM_GICV5(cs);
573
+
574
+ trace_gicv5_set_handling(domain_name[domain], inttype_name(type), virtual,
575
+ id, handling);
576
+ if (virtual) {
577
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_handling: tried to set "
578
+ "handling mode of a virtual interrupt\n");
579
+ return;
580
+ }
581
+
582
+ switch (type) {
583
+ case GICV5_LPI:
584
+ {
585
+ const GICv5ISTConfig *cfg = &s->phys_lpi_config[domain];
586
+ L2_ISTE_Handle h;
587
+ uint32_t *l2_iste_p = get_l2_iste(cs, cfg, id, &h);
588
+
589
+ if (!l2_iste_p) {
590
+ return;
591
+ }
592
+ *l2_iste_p = FIELD_DP32(*l2_iste_p, L2_ISTE, HM, handling);
593
+ put_l2_iste(cs, cfg, &h);
594
+ break;
595
+ }
596
+ default:
597
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_handling: tried to set "
598
+ "handling mode of bad interrupt type %d\n", type);
599
+ return;
600
+ }
601
+}
602
+
603
+void gicv5_set_target(GICv5Common *cs, uint32_t id, uint32_t iaffid,
604
+ GICv5RoutingMode irm, GICv5Domain domain,
605
+ GICv5IntType type, bool virtual)
606
+{
607
+ GICv5 *s = ARM_GICV5(cs);
608
+
609
+ trace_gicv5_set_target(domain_name[domain], inttype_name(type), virtual,
610
+ id, iaffid, irm);
611
+ if (virtual) {
612
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_target: tried to set "
613
+ "target of a virtual interrupt\n");
614
+ return;
615
+ }
616
+ if (irm != GICV5_TARGETED) {
617
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_target: tried to set "
618
+ "1-of-N routing\n");
619
+ /*
620
+ * In the cpuif insn "GIC CDAFF", IRM is RES0 for a GIC which
621
+ * does not support 1-of-N routing. So warn, and fall through
622
+ * to treat IRM=1 the same as IRM=0.
623
+ */
624
+ }
625
+
626
+ switch (type) {
627
+ case GICV5_LPI:
628
+ {
629
+ const GICv5ISTConfig *cfg = &s->phys_lpi_config[domain];
630
+ L2_ISTE_Handle h;
631
+ uint32_t *l2_iste_p = get_l2_iste(cs, cfg, id, &h);
632
+
633
+ if (!l2_iste_p) {
634
+ return;
635
+ }
636
+ /*
637
+ * For QEMU we do not implement 1-of-N routing, and so
638
+ * L2_ISTE.IRM is RES0. We never read it, and we can skip
639
+ * explicitly writing it to zero here.
640
+ */
641
+ *l2_iste_p = FIELD_DP32(*l2_iste_p, L2_ISTE, IAFFID, iaffid);
642
+ put_l2_iste(cs, cfg, &h);
643
+ break;
644
+ }
645
+ default:
646
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_target: tried to set "
647
+ "target of bad interrupt type %d\n", type);
648
+ return;
649
+ }
650
+}
651
+
652
static void irs_map_l2_istr_write(GICv5 *s, GICv5Domain domain, uint64_t value)
653
{
654
GICv5Common *cs = ARM_GICV5_COMMON(s);
hw/intc/trace-events
+4
@@ -236,6 +236,10 @@ gicv5_spi(uint32_t id, int level) "GICv5 SPI ID %u asserted at level %d"
236
gicv5_ist_valid(const char *domain, uint64_t base, uint8_t id_bits, uint8_t l2_idx_bits, uint8_t istsz, bool structure) "GICv5 IRS %s IST now valid: base 0x%" PRIx64 " id_bits %u l2_idx_bits %u IST entry size %u 2-level %d"
237
gicv5_ist_invalid(const char *domain) "GICv5 IRS %s IST no longer valid"
238
gicv5_set_priority(const char *domain, const char *type, bool virtual, uint32_t id, uint8_t priority) "GICv5 IRS SetPriority %s %s virtual:%d ID %u prio %u"
239
+gicv5_set_enabled(const char *domain, const char *type, bool virtual, uint32_t id, bool enabled) "GICv5 IRS SetEnabled %s %s virtual:%d ID %u enabled %d"
240
+gicv5_set_pending(const char *domain, const char *type, bool virtual, uint32_t id, bool pending) "GICv5 IRS SetPending %s %s virtual:%d ID %u pending %d"
241
+gicv5_set_handling(const char *domain, const char *type, bool virtual, uint32_t id, int handling) "GICv5 IRS SetHandling %s %s virtual:%d ID %u handling %d"
242
+gicv5_set_target(const char *domain, const char *type, bool virtual, uint32_t id, uint32_t iaffid, int irm) "GICv5 IRS SetTarget %s %s virtual:%d ID %u IAFFID %u routingmode %d"
243
244
# arm_gicv5_common.c
245
gicv5_common_realize(uint32_t irsid, uint32_t num_cpus, uint32_t spi_base, uint32_t spi_irs_range, uint32_t spi_range) "GICv5 IRS realized: IRS ID %u, %u CPUs, SPI base %u, SPI IRS range %u, SPI range %u"
include/hw/intc/arm_gicv5_stream.h
+68
@@ -58,4 +58,72 @@ void gicv5_set_priority(GICv5Common *cs, uint32_t id,
58
uint8_t priority, GICv5Domain domain,
59
GICv5IntType type, bool virtual);
60
61
+/**
62
+ * gicv5_set_enabled
63
+ * @cs: GIC IRS to send command to
64
+ * @id: interrupt ID
65
+ * @enabled: new enabled state
66
+ * @domain: interrupt Domain to act on
67
+ * @type: interrupt type (LPI or SPI)
68
+ * @virtual: true if this is a virtual interrupt
69
+ *
70
+ * Set enabled state of an interrupt; matches stream interface
71
+ * SetEnabled command from CPUIF to IRS. There is no report back of
72
+ * success/failure to the CPUIF in the protocol.
73
+ */
74
+void gicv5_set_enabled(GICv5Common *cs, uint32_t id,
75
+ bool enabled, GICv5Domain domain,
76
+ GICv5IntType type, bool virtual);
77
+
78
+/**
79
+ * gicv5_set_pending
80
+ * @cs: GIC IRS to send command to
81
+ * @id: interrupt ID
82
+ * @pending: new pending state
83
+ * @domain: interrupt Domain to act on
84
+ * @type: interrupt type (LPI or SPI)
85
+ * @virtual: true if this is a virtual interrupt
86
+ *
87
+ * Set pending state of an interrupt; matches stream interface
88
+ * SetPending command from CPUIF to IRS. There is no report back of
89
+ * success/failure to the CPUIF in the protocol.
90
+ */
91
+void gicv5_set_pending(GICv5Common *cs, uint32_t id,
92
+ bool pending, GICv5Domain domain,
93
+ GICv5IntType type, bool virtual);
94
+
95
+/**
96
+ * gicv5_set_handling
97
+ * @cs: GIC IRS to send command to
98
+ * @id: interrupt ID
99
+ * @handling: new handling mode
100
+ * @domain: interrupt Domain to act on
101
+ * @type: interrupt type (LPI or SPI)
102
+ * @virtual: true if this is a virtual interrupt
103
+ *
104
+ * Set handling mode of an interrupt (edge/level); matches stream
105
+ * interface SetHandling command from CPUIF to IRS. There is no report
106
+ * back of success/failure to the CPUIF in the protocol.
107
+ */
108
+void gicv5_set_handling(GICv5Common *cs, uint32_t id,
109
+ GICv5HandlingMode handling, GICv5Domain domain,
110
+ GICv5IntType type, bool virtual);
111
+
112
+/**
113
+ * gicv5_set_target
114
+ * @cs: GIC IRS to send command to
115
+ * @id: interrupt ID
116
+ * @iaffid: new target PE's interrupt affinity
117
+ * @irm: interrupt routing mode (targeted vs 1-of-N)
118
+ * @domain: interrupt Domain to act on
119
+ * @type: interrupt type (LPI or SPI)
120
+ * @virtual: true if this is a virtual interrupt
121
+ *
122
+ * Set handling mode of an interrupt (edge/level); matches stream
123
+ * interface SetHandling command from CPUIF to IRS. There is no report
124
+ * back of success/failure to the CPUIF in the protocol.
125
+ */
126
+void gicv5_set_target(GICv5Common *cs, uint32_t id, uint32_t iaffid,
127
+ GICv5RoutingMode irm, GICv5Domain domain,
128
+ GICv5IntType type, bool virtual);
129
#endif
include/hw/intc/arm_gicv5_types.h
+15
@@ -55,4 +55,19 @@ typedef enum GICv5IntType {
55
GICV5_SPI = 3,
56
} GICv5IntType;
57
58
+/* Interrupt handling mode (same encoding as L2_ISTE.HM) */
59
+typedef enum GICv5HandlingMode {
60
+ GICV5_EDGE = 0,
61
+ GICV5_LEVEL = 1,
62
+} GICv5HandlingMode;
63
+
64
+/*
65
+ * Interrupt routing mode (same encoding as L2_ISTE.IRM).
66
+ * Note that 1-of-N support is option and QEMU does not implement it.
67
+ */
68
+typedef enum GICv5RoutingMode {
69
+ GICV5_TARGETED = 0,
70
+ GICV5_1OFN = 1,
71
+} GICv5RoutingMode;
72
+
73
#endif