From 3093d65ad37a820681ea88cbb70c2e70c4b1957c Mon Sep 17 00:00:00 2001 From: Giacomo Travaglini Date: Tue, 27 Aug 2019 11:38:55 +0100 Subject: [PATCH] dev-arm: Rewrite GICv3 update The GICv3 update methods are method which are invoked anytime the model needs to evaluate a change in its state, which most of the time means managing the state of an interrupt (forwarding it to a PE, deasserting it, etc). The way it is currently done is a little bit obscure and doesn't handle correctly IRQ prioritization. Example: An IRQ which is handled by the redistributor (PPI or LPI) was not competing with any pending interrupts coming from the distributor (SPIs) once raised by a peripheral. Also the way the pending state of an interrupt was removed at the cpu interface level wasn't happening in place where this was actually happening (E.g. when activating it), but happened with a weird fullUpdate semantic, where if there was a pending interrupt in a cpu interface, all cpu interfaces had their pending interrupt (if any) been disabled. With this patch, state update always starts at the distributor, and it goes down until the cpu interface where a Gicv3CPUInterface::update method selects the winning interrupt coming from distributor/redistributor to be forwarded to the PE. Change-Id: I1c517cbc4bf107cc2d7ae7beb2692e3cf5187a40 Signed-off-by: Giacomo Travaglini Reviewed-by: Andreas Sandberg Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/20614 Maintainer: Andreas Sandberg Tested-by: kokoro --- src/dev/arm/gic_v3_cpu_interface.cc | 21 +++-- src/dev/arm/gic_v3_cpu_interface.hh | 1 + src/dev/arm/gic_v3_distributor.cc | 118 ++++++++++++---------------- src/dev/arm/gic_v3_distributor.hh | 3 +- src/dev/arm/gic_v3_its.cc | 2 +- src/dev/arm/gic_v3_redistributor.cc | 31 +++----- src/dev/arm/gic_v3_redistributor.hh | 2 +- 7 files changed, 80 insertions(+), 98 deletions(-) diff --git a/src/dev/arm/gic_v3_cpu_interface.cc b/src/dev/arm/gic_v3_cpu_interface.cc index 97d914568..b4c271d4a 100644 --- a/src/dev/arm/gic_v3_cpu_interface.cc +++ b/src/dev/arm/gic_v3_cpu_interface.cc @@ -1819,15 +1819,19 @@ Gicv3CPUInterface::activateIRQ(uint32_t int_id, Gicv3::GroupId group) if (int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX) { // SGI or PPI, redistributor redistributor->activateIRQ(int_id); - redistributor->updateAndInformCPUInterface(); } else if (int_id < Gicv3::INTID_SECURE) { // SPI, distributor distributor->activateIRQ(int_id); - distributor->updateAndInformCPUInterfaces(); } else if (int_id >= Gicv3Redistributor::SMALLEST_LPI_ID) { // LPI, Redistributor redistributor->setClrLPI(int_id, false); } + + // By setting the priority to 0xff we are effectively + // making the int_id not pending anymore at the cpu + // interface. + hppi.prio = 0xff; + updateDistributor(); } void @@ -1857,15 +1861,12 @@ Gicv3CPUInterface::deactivateIRQ(uint32_t int_id, Gicv3::GroupId group) if (int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX) { // SGI or PPI, redistributor redistributor->deactivateIRQ(int_id); - redistributor->updateAndInformCPUInterface(); } else if (int_id < Gicv3::INTID_SECURE) { // SPI, distributor distributor->deactivateIRQ(int_id); - distributor->updateAndInformCPUInterfaces(); - } else { - // LPI, redistributor, shouldn't deactivate - redistributor->updateAndInformCPUInterface(); } + + updateDistributor(); } void @@ -1991,6 +1992,12 @@ Gicv3CPUInterface::highestActiveGroup() const return -1; } +void +Gicv3CPUInterface::updateDistributor() +{ + distributor->update(); +} + void Gicv3CPUInterface::update() { diff --git a/src/dev/arm/gic_v3_cpu_interface.hh b/src/dev/arm/gic_v3_cpu_interface.hh index 5c66fd75f..ed432bce5 100644 --- a/src/dev/arm/gic_v3_cpu_interface.hh +++ b/src/dev/arm/gic_v3_cpu_interface.hh @@ -326,6 +326,7 @@ class Gicv3CPUInterface : public ArmISA::BaseISADevice, public Serializable void serialize(CheckpointOut & cp) const override; void unserialize(CheckpointIn & cp) override; void update(); + void updateDistributor(); void virtualActivateIRQ(uint32_t lrIdx); void virtualDeactivateIRQ(int lrIdx); uint8_t virtualDropPriority(); diff --git a/src/dev/arm/gic_v3_distributor.cc b/src/dev/arm/gic_v3_distributor.cc index f85474c9c..0211bec56 100644 --- a/src/dev/arm/gic_v3_distributor.cc +++ b/src/dev/arm/gic_v3_distributor.cc @@ -638,7 +638,7 @@ Gicv3Distributor::write(Addr addr, uint64_t data, size_t size, } } - updateAndInformCPUInterfaces(); + update(); return; } else if (GICD_ICPENDR.contains(addr)) { // Interrupt Clear-Pending Registers @@ -663,10 +663,11 @@ Gicv3Distributor::write(Addr addr, uint64_t data, size_t size, if (clear) { irqPending[int_id] = false; + clearIrqCpuInterface(int_id); } } - updateAndInformCPUInterfaces(); + update(); return; } else if (GICD_ISACTIVER.contains(addr)) { // Interrupt Set-Active Registers @@ -947,7 +948,7 @@ Gicv3Distributor::sendInt(uint32_t int_id) irqPending[int_id] = true; DPRINTF(GIC, "Gicv3Distributor::sendInt(): " "int_id %d (SPI) pending bit set\n", int_id); - updateAndInformCPUInterfaces(); + update(); } void @@ -956,40 +957,59 @@ Gicv3Distributor::deassertSPI(uint32_t int_id) panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!"); panic_if(int_id > itLines, "Invalid SPI!"); irqPending[int_id] = false; - updateAndInformCPUInterfaces(); + clearIrqCpuInterface(int_id); + + update(); } -void -Gicv3Distributor::updateAndInformCPUInterfaces() +Gicv3CPUInterface* +Gicv3Distributor::route(uint32_t int_id) { - update(); + IROUTER affinity_routing = irqAffinityRouting[int_id]; + Gicv3Redistributor * target_redistributor = nullptr; - for (int i = 0; i < gic->getSystem()->numContexts(); i++) { - gic->getCPUInterface(i)->update(); + const Gicv3::GroupId int_group = getIntGroup(int_id); + + if (affinity_routing.IRM) { + // Interrupts routed to any PE defined as a participating node + for (int i = 0; i < gic->getSystem()->numContexts(); i++) { + Gicv3Redistributor * redistributor_i = + gic->getRedistributor(i); + + if (redistributor_i-> + canBeSelectedFor1toNInterrupt(int_group)) { + target_redistributor = redistributor_i; + break; + } + } + } else { + uint32_t affinity = (affinity_routing.Aff3 << 24) | + (affinity_routing.Aff2 << 16) | + (affinity_routing.Aff1 << 8) | + (affinity_routing.Aff0 << 0); + target_redistributor = + gic->getRedistributorByAffinity(affinity); + } + + if (!target_redistributor) { + // Interrrupts targeting not present cpus must remain pending + return nullptr; + } else { + return target_redistributor->getCPUInterface(); } } void -Gicv3Distributor::fullUpdate() +Gicv3Distributor::clearIrqCpuInterface(uint32_t int_id) { - for (int i = 0; i < gic->getSystem()->numContexts(); i++) { - Gicv3CPUInterface * cpu_interface_i = gic->getCPUInterface(i); - cpu_interface_i->hppi.prio = 0xff; - } - - update(); - - for (int i = 0; i < gic->getSystem()->numContexts(); i++) { - Gicv3Redistributor * redistributor_i = gic->getRedistributor(i); - redistributor_i->update(); - } + auto cpu_interface = route(int_id); + if (cpu_interface) + cpu_interface->hppi.prio = 0xff; } void Gicv3Distributor::update() { - std::vector new_hppi(gic->getSystem()->numContexts(), false); - // Find the highest priority pending SPI for (int int_id = Gicv3::SGI_MAX + Gicv3::PPI_MAX; int_id < itLines; int_id++) { @@ -998,65 +1018,27 @@ Gicv3Distributor::update() if (irqPending[int_id] && irqEnabled[int_id] && !irqActive[int_id] && group_enabled) { - IROUTER affinity_routing = irqAffinityRouting[int_id]; - Gicv3Redistributor * target_redistributor = nullptr; - - if (affinity_routing.IRM) { - // Interrupts routed to any PE defined as a participating node - for (int i = 0; i < gic->getSystem()->numContexts(); i++) { - Gicv3Redistributor * redistributor_i = - gic->getRedistributor(i); - - if (redistributor_i-> - canBeSelectedFor1toNInterrupt(int_group)) { - target_redistributor = redistributor_i; - break; - } - } - } else { - uint32_t affinity = (affinity_routing.Aff3 << 24) | - (affinity_routing.Aff3 << 16) | - (affinity_routing.Aff1 << 8) | - (affinity_routing.Aff0 << 0); - target_redistributor = - gic->getRedistributorByAffinity(affinity); - } - if (!target_redistributor) { - // Interrrupts targeting not present cpus must remain pending - return; - } + // Find the cpu interface where to route the interrupt + Gicv3CPUInterface *target_cpu_interface = route(int_id); - Gicv3CPUInterface * target_cpu_interface = - target_redistributor->getCPUInterface(); - uint32_t target_cpu = target_redistributor->cpuId; + // Invalid routing + if (!target_cpu_interface) continue; if ((irqPriority[int_id] < target_cpu_interface->hppi.prio) || - /* - * Multiple pending ints with same priority. - * Implementation choice which one to signal. - * Our implementation selects the one with the lower id. - */ (irqPriority[int_id] == target_cpu_interface->hppi.prio && int_id < target_cpu_interface->hppi.intid)) { + target_cpu_interface->hppi.intid = int_id; target_cpu_interface->hppi.prio = irqPriority[int_id]; target_cpu_interface->hppi.group = int_group; - new_hppi[target_cpu] = true; } } } + // Update all redistributors for (int i = 0; i < gic->getSystem()->numContexts(); i++) { - Gicv3Redistributor * redistributor_i = gic->getRedistributor(i); - Gicv3CPUInterface * cpu_interface_i = - redistributor_i->getCPUInterface(); - - if (!new_hppi[i] && cpu_interface_i->hppi.prio != 0xff && - cpu_interface_i->hppi.intid >= (Gicv3::SGI_MAX + Gicv3::PPI_MAX) && - cpu_interface_i->hppi.intid < Gicv3::INTID_SECURE) { - fullUpdate(); - } + gic->getRedistributor(i)->update(); } } diff --git a/src/dev/arm/gic_v3_distributor.hh b/src/dev/arm/gic_v3_distributor.hh index 0cf8d378c..76ab6dd02 100644 --- a/src/dev/arm/gic_v3_distributor.hh +++ b/src/dev/arm/gic_v3_distributor.hh @@ -222,13 +222,14 @@ class Gicv3Distributor : public Serializable void serialize(CheckpointOut & cp) const override; void unserialize(CheckpointIn & cp) override; void update(); - void updateAndInformCPUInterfaces(); + Gicv3CPUInterface* route(uint32_t int_id); public: Gicv3Distributor(Gicv3 * gic, uint32_t it_lines); void deassertSPI(uint32_t int_id); + void clearIrqCpuInterface(uint32_t int_id); void init(); void initState(); uint64_t read(Addr addr, size_t size, bool is_secure_access); diff --git a/src/dev/arm/gic_v3_its.cc b/src/dev/arm/gic_v3_its.cc index f822042ce..4108cc744 100644 --- a/src/dev/arm/gic_v3_its.cc +++ b/src/dev/arm/gic_v3_its.cc @@ -1271,7 +1271,7 @@ Gicv3Its::moveAllPendingState( rd1->lpiPendingTablePtr, 0, sizeof(lpi_pending_table)); - rd2->updateAndInformCPUInterface(); + rd2->updateDistributor(); } Gicv3Its * diff --git a/src/dev/arm/gic_v3_redistributor.cc b/src/dev/arm/gic_v3_redistributor.cc index 71e74bfb8..e22ea7080 100644 --- a/src/dev/arm/gic_v3_redistributor.cc +++ b/src/dev/arm/gic_v3_redistributor.cc @@ -536,7 +536,7 @@ Gicv3Redistributor::write(Addr addr, uint64_t data, size_t size, } } - updateAndInformCPUInterface(); + updateDistributor(); break; case GICR_ICPENDR0:// Interrupt Clear-Pending Register 0 @@ -733,7 +733,7 @@ Gicv3Redistributor::sendPPInt(uint32_t int_id) irqPending[int_id] = true; DPRINTF(GIC, "Gicv3Redistributor::sendPPInt(): " "int_id %d (PPI) pending bit set\n", int_id); - updateAndInformCPUInterface(); + updateDistributor(); } void @@ -770,7 +770,7 @@ Gicv3Redistributor::sendSGI(uint32_t int_id, Gicv3::GroupId group, bool ns) irqPending[int_id] = true; DPRINTF(GIC, "Gicv3ReDistributor::sendSGI(): " "int_id %d (SGI) pending bit set\n", int_id); - updateAndInformCPUInterface(); + updateDistributor(); } Gicv3::IntStatus @@ -791,6 +791,12 @@ Gicv3Redistributor::intStatus(uint32_t int_id) const } } +void +Gicv3Redistributor::updateDistributor() +{ + distributor->update(); +} + /* * Recalculate the highest priority pending interrupt after a * change to redistributor state. @@ -798,8 +804,6 @@ Gicv3Redistributor::intStatus(uint32_t int_id) const void Gicv3Redistributor::update() { - bool new_hppi = false; - for (int int_id = 0; int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX; int_id++) { Gicv3::GroupId int_group = getIntGroup(int_id); bool group_enabled = distributor->groupEnabled(int_group); @@ -817,7 +821,6 @@ Gicv3Redistributor::update() cpuInterface->hppi.intid = int_id; cpuInterface->hppi.prio = irqPriority[int_id]; cpuInterface->hppi.group = int_group; - new_hppi = true; } } } @@ -866,17 +869,12 @@ Gicv3Redistributor::update() cpuInterface->hppi.intid = lpi_id; cpuInterface->hppi.prio = lpi_priority; cpuInterface->hppi.group = lpi_group; - new_hppi = true; } } } } - if (!new_hppi && cpuInterface->hppi.prio != 0xff && - (cpuInterface->hppi.intid < Gicv3::SGI_MAX + Gicv3::PPI_MAX || - cpuInterface->hppi.intid > SMALLEST_LPI_ID)) { - distributor->fullUpdate(); - } + cpuInterface->update(); } uint8_t @@ -958,14 +956,7 @@ Gicv3Redistributor::setClrLPI(uint64_t data, bool set) writeEntryLPI(lpi_id, lpi_pending_entry); - updateAndInformCPUInterface(); -} - -void -Gicv3Redistributor::updateAndInformCPUInterface() -{ - update(); - cpuInterface->update(); + updateDistributor(); } Gicv3::GroupId diff --git a/src/dev/arm/gic_v3_redistributor.hh b/src/dev/arm/gic_v3_redistributor.hh index 29ff8672d..c59c3411f 100644 --- a/src/dev/arm/gic_v3_redistributor.hh +++ b/src/dev/arm/gic_v3_redistributor.hh @@ -210,7 +210,7 @@ class Gicv3Redistributor : public Serializable void serialize(CheckpointOut & cp) const override; void unserialize(CheckpointIn & cp) override; void update(); - void updateAndInformCPUInterface(); + void updateDistributor(); public: -- 2.30.2