aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/xive.c100
-rw-r--r--include/xive.h3
2 files changed, 68 insertions, 35 deletions
diff --git a/hw/xive.c b/hw/xive.c
index a8cc2fc..66b9539 100644
--- a/hw/xive.c
+++ b/hw/xive.c
@@ -338,18 +338,23 @@ struct xive {
/* Conversion between GIRQ and block/index.
*
* ------------------------------------
- * |00000000|BLOC| INDEX|
+ * |0000000E|BLOC| INDEX|
* ------------------------------------
* 8 4 20
*
- * The global interrupt number is thus limited to 24 bits which is
- * necessary for our XICS emulation since the top 8 bits are
- * reserved for the CPPR value.
+ * the E bit indicates that this is an escalation interrupt, in
+ * that case, the BLOC/INDEX represents the EQ containig the
+ * corresponding escalation descriptor.
+ *
+ * Global interrupt numbers for non-escalation interrupts are thus
+ * limited to 24 bits which is necessary for our XICS emulation since
+ * the top 8 bits are reserved for the CPPR value.
*
*/
#define GIRQ_TO_BLK(__g) (((__g) >> 20) & 0xf)
#define GIRQ_TO_IDX(__g) ((__g) & 0x000fffff)
#define BLKIDX_TO_GIRQ(__b,__i) (((uint32_t)(__b)) << 20 | (__i))
+#define GIRQ_IS_ESCALATION(__g) ((__g) & 0x01000000)
/* VP IDs are just the concatenation of the BLK and index as found
* in an EQ target field for example
@@ -476,27 +481,6 @@ static struct xive *xive_from_vc_blk(uint32_t blk)
return c->xive;
}
-static struct xive_ive *xive_get_ive(struct xive *x, unsigned int isn)
-{
- struct xive_ive *ivt;
- uint32_t idx = GIRQ_TO_IDX(isn);
-
- /* Check the block matches */
- if (isn < x->int_base || isn >= x->int_max) {
- xive_err(x, "xive_get_ive, ISN 0x%x not on chip\n", idx);
- return NULL;
- }
- assert (idx < MAX_INT_ENTRIES);
-
- /* If we support >1 block per chip, this should still work as
- * we are likely to make the table contiguous anyway
- */
- ivt = x->ivt_base;
- assert(ivt);
-
- return ivt + idx;
-}
-
static struct xive_eq *xive_get_eq(struct xive *x, unsigned int idx)
{
struct xive_eq *p;
@@ -525,6 +509,45 @@ static struct xive_eq *xive_get_eq(struct xive *x, unsigned int idx)
#endif
}
+static struct xive_ive *xive_get_ive(struct xive *x, unsigned int isn)
+{
+ struct xive_ive *ivt;
+ uint32_t idx = GIRQ_TO_IDX(isn);
+
+ if (GIRQ_IS_ESCALATION(isn)) {
+ /* Allright, an escalation IVE is buried inside an EQ, let's
+ * try to find it
+ */
+ struct xive_eq *eq;
+
+ if (x->chip_id != VC_BLK_TO_CHIP(GIRQ_TO_BLK(isn))) {
+ xive_err(x, "xive_get_ive, ESC ISN 0x%x not on right chip\n", isn);
+ return NULL;
+ }
+ eq = xive_get_eq(x, idx);
+ if (!eq) {
+ xive_err(x, "xive_get_ive, ESC ISN 0x%x EQ not found\n", isn);
+ return NULL;
+ }
+ return (struct xive_ive *)(char *)&eq->w4;
+ } else {
+ /* Check the block matches */
+ if (isn < x->int_base || isn >= x->int_max) {
+ xive_err(x, "xive_get_ive, ISN 0x%x not on right chip\n", isn);
+ return NULL;
+ }
+ assert (idx < MAX_INT_ENTRIES);
+
+ /* If we support >1 block per chip, this should still work as
+ * we are likely to make the table contiguous anyway
+ */
+ ivt = x->ivt_base;
+ assert(ivt);
+
+ return ivt + idx;
+ }
+}
+
static struct xive_vp *xive_get_vp(struct xive *x, unsigned int idx)
{
struct xive_vp *p;
@@ -1295,21 +1318,25 @@ uint32_t xive_alloc_ipi_irqs(uint32_t chip_id, uint32_t count, uint32_t align)
void *xive_get_trigger_port(uint32_t girq)
{
+ uint32_t idx = GIRQ_TO_IDX(girq);
struct xive *x;
- uint32_t idx;
/* Find XIVE on which the IVE resides */
x = xive_from_isn(girq);
if (!x)
return NULL;
- /* Make sure it's an IPI on that chip */
- if (girq < x->int_base ||
- girq >= x->int_ipi_top)
- return NULL;
+ if (GIRQ_IS_ESCALATION(girq)) {
+ /* Page 2 of the EQ MMIO space is the escalate irq */
+ return x->eq_mmio + idx * 0x20000 + 0x10000;
+ } else {
+ /* Make sure it's an IPI on that chip */
+ if (girq < x->int_base ||
+ girq >= x->int_ipi_top)
+ return NULL;
- idx = girq - x->int_base;
- return x->esb_mmio + idx * 0x20000;
+ return x->esb_mmio + idx * 0x20000;
+ }
}
uint64_t xive_get_notify_port(uint32_t chip_id, uint32_t ent)
@@ -1406,6 +1433,7 @@ static bool xive_get_eq_info(uint32_t isn, uint32_t *out_target,
uint32_t eq_blk, eq_idx;
uint32_t vp_blk, vp_idx;
uint32_t prio, server;
+ bool is_escalation = GIRQ_IS_ESCALATION(isn);
/* Find XIVE on which the IVE resides */
x = xive_from_isn(isn);
@@ -1415,7 +1443,7 @@ static bool xive_get_eq_info(uint32_t isn, uint32_t *out_target,
ive = xive_get_ive(x, isn);
if (!ive)
return false;
- if (!(ive->w & IVE_VALID)) {
+ if (!(ive->w & IVE_VALID) && !is_escalation) {
xive_err(x, "ISN %x lead to invalid IVE !\n", isn);
return false;
}
@@ -1471,6 +1499,7 @@ static bool xive_set_eq_info(uint32_t isn, uint32_t target, uint8_t prio)
struct xive *x;
struct xive_ive *ive;
uint32_t eq_blk, eq_idx;
+ bool is_escalation = GIRQ_IS_ESCALATION(isn);
/* Find XIVE on which the IVE resides */
x = xive_from_isn(isn);
@@ -1480,7 +1509,7 @@ static bool xive_set_eq_info(uint32_t isn, uint32_t target, uint8_t prio)
ive = xive_get_ive(x, isn);
if (!ive)
return false;
- if (!(ive->w & IVE_VALID)) {
+ if (!(ive->w & IVE_VALID) && !is_escalation) {
xive_err(x, "ISN %x lead to invalid IVE !\n", isn);
return false;
}
@@ -1488,7 +1517,8 @@ static bool xive_set_eq_info(uint32_t isn, uint32_t target, uint8_t prio)
/* Are we masking ? */
if (prio == 0xff) {
/* Masking, just set the M bit */
- ive->w |= IVE_MASKED;
+ if (!is_escalation)
+ ive->w |= IVE_MASKED;
xive_vdbg(x, "ISN %x masked !\n", isn);
} else {
diff --git a/include/xive.h b/include/xive.h
index 065aa69..e35da6d 100644
--- a/include/xive.h
+++ b/include/xive.h
@@ -276,6 +276,9 @@
*
* One per interrupt source. Targets that interrupt to a given EQ
* and provides the corresponding logical interrupt number (EQ data)
+ *
+ * We also map this structure to the escalation descriptor inside
+ * an EQ, though in that case the valid and masked bits are not used.
*/
struct xive_ive {
/* Use a single 64-bit definition to make it easier to