/*
- * Copyright (c) 2019 ARM Limited
+ * Copyright (c) 2019-2020 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
irqGroup(Gicv3::SGI_MAX + Gicv3::PPI_MAX, 0),
irqEnabled(Gicv3::SGI_MAX + Gicv3::PPI_MAX, false),
irqPending(Gicv3::SGI_MAX + Gicv3::PPI_MAX, false),
+ irqPendingIspendr(Gicv3::SGI_MAX + Gicv3::PPI_MAX, false),
irqActive(Gicv3::SGI_MAX + Gicv3::PPI_MAX, false),
irqPriority(Gicv3::SGI_MAX + Gicv3::PPI_MAX, 0),
irqConfig(Gicv3::SGI_MAX + Gicv3::PPI_MAX, Gicv3::INT_EDGE_TRIGGERED),
"(GICR_ISPENDR0): int_id %d (PPI) "
"pending bit set\n", int_id);
irqPending[int_id] = true;
+ irqPendingIspendr[int_id] = true;
}
}
bool clear = data & (1 << int_id) ? 1 : 0;
- if (clear) {
+ if (clear && treatAsEdgeTriggered(int_id)) {
irqPending[int_id] = false;
}
}
assert((int_id >= Gicv3::SGI_MAX) &&
(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX));
irqPending[int_id] = true;
+ irqPendingIspendr[int_id] = false;
DPRINTF(GIC, "Gicv3Redistributor::sendPPInt(): "
"int_id %d (PPI) pending bit set\n", int_id);
updateDistributor();
}
+void
+Gicv3Redistributor::clearPPInt(uint32_t int_id)
+{
+ assert((int_id >= Gicv3::SGI_MAX) &&
+ (int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX));
+
+ if (isLevelSensitive(int_id)) {
+ irqPending[int_id] = false;
+ }
+}
+
void
Gicv3Redistributor::sendSGI(uint32_t int_id, Gicv3::GroupId group, bool ns)
{
if (!forward) return;
irqPending[int_id] = true;
+ irqPendingIspendr[int_id] = false;
DPRINTF(GIC, "Gicv3ReDistributor::sendSGI(): "
"int_id %d (SGI) pending bit set\n", int_id);
updateDistributor();
void
Gicv3Redistributor::activateIRQ(uint32_t int_id)
{
- irqPending[int_id] = false;
+ if (treatAsEdgeTriggered(int_id)) {
+ irqPending[int_id] = false;
+ }
irqActive[int_id] = true;
}
SERIALIZE_CONTAINER(irqGroup);
SERIALIZE_CONTAINER(irqEnabled);
SERIALIZE_CONTAINER(irqPending);
+ SERIALIZE_CONTAINER(irqPendingIspendr);
SERIALIZE_CONTAINER(irqActive);
SERIALIZE_CONTAINER(irqPriority);
SERIALIZE_CONTAINER(irqConfig);
UNSERIALIZE_CONTAINER(irqGroup);
UNSERIALIZE_CONTAINER(irqEnabled);
UNSERIALIZE_CONTAINER(irqPending);
+ UNSERIALIZE_CONTAINER(irqPendingIspendr);
UNSERIALIZE_CONTAINER(irqActive);
UNSERIALIZE_CONTAINER(irqPriority);
UNSERIALIZE_CONTAINER(irqConfig);
/*
- * Copyright (c) 2019 ARM Limited
+ * Copyright (c) 2019-2020 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
std::vector <uint8_t> irqGroup;
std::vector <bool> irqEnabled;
std::vector <bool> irqPending;
+ std::vector <bool> irqPendingIspendr;
std::vector <bool> irqActive;
std::vector <uint8_t> irqPriority;
std::vector <Gicv3::IntTriggerType> irqConfig;
void update();
void updateDistributor();
+ protected:
+
+ bool isLevelSensitive(uint32_t int_id) const
+ {
+ return irqConfig[int_id] == Gicv3::INT_LEVEL_SENSITIVE;
+ }
+
+ /**
+ * This helper is used to check if an interrupt should be treated as
+ * edge triggered in the following scenarios:
+ *
+ * a) While activating the interrupt
+ * b) While clearing an interrupt via ICPENDR
+ *
+ * In fact, in these two situations, a level sensitive interrupt
+ * which had been made pending via a write to ISPENDR, will be
+ * treated as it if was edge triggered.
+ */
+ bool treatAsEdgeTriggered(uint32_t int_id) const
+ {
+ return !isLevelSensitive(int_id) || irqPendingIspendr[int_id];
+ }
+
public:
Gicv3Redistributor(Gicv3 * gic, uint32_t cpu_id);
void init();
uint64_t read(Addr addr, size_t size, bool is_secure_access);
void sendPPInt(uint32_t int_id);
+ void clearPPInt(uint32_t int_id);
void write(Addr addr, uint64_t data, size_t size, bool is_secure_access);
};