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
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
return -1;
}
+void
+Gicv3CPUInterface::updateDistributor()
+{
+ distributor->update();
+}
+
void
Gicv3CPUInterface::update()
{
}
}
- updateAndInformCPUInterfaces();
+ update();
return;
} else if (GICD_ICPENDR.contains(addr)) {
// Interrupt Clear-Pending Registers
if (clear) {
irqPending[int_id] = false;
+ clearIrqCpuInterface(int_id);
}
}
- updateAndInformCPUInterfaces();
+ update();
return;
} else if (GICD_ISACTIVER.contains(addr)) {
// Interrupt Set-Active Registers
irqPending[int_id] = true;
DPRINTF(GIC, "Gicv3Distributor::sendInt(): "
"int_id %d (SPI) pending bit set\n", int_id);
- updateAndInformCPUInterfaces();
+ update();
}
void
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<bool> 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++) {
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();
}
}
}
}
- updateAndInformCPUInterface();
+ updateDistributor();
break;
case GICR_ICPENDR0:// Interrupt Clear-Pending Register 0
irqPending[int_id] = true;
DPRINTF(GIC, "Gicv3Redistributor::sendPPInt(): "
"int_id %d (PPI) pending bit set\n", int_id);
- updateAndInformCPUInterface();
+ updateDistributor();
}
void
irqPending[int_id] = true;
DPRINTF(GIC, "Gicv3ReDistributor::sendSGI(): "
"int_id %d (SGI) pending bit set\n", int_id);
- updateAndInformCPUInterface();
+ updateDistributor();
}
Gicv3::IntStatus
}
}
+void
+Gicv3Redistributor::updateDistributor()
+{
+ distributor->update();
+}
+
/*
* Recalculate the highest priority pending interrupt after a
* change to redistributor state.
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);
cpuInterface->hppi.intid = int_id;
cpuInterface->hppi.prio = irqPriority[int_id];
cpuInterface->hppi.group = int_group;
- new_hppi = true;
}
}
}
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
writeEntryLPI(lpi_id, lpi_pending_entry);
- updateAndInformCPUInterface();
-}
-
-void
-Gicv3Redistributor::updateAndInformCPUInterface()
-{
- update();
- cpuInterface->update();
+ updateDistributor();
}
Gicv3::GroupId