@samitouri / QOSamiQemu / commits / f2ca526444

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