[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 17/27] ppc/xive: introduce the XIVE Event Notificatio
From: |
David Gibson |
Subject: |
[Qemu-devel] [PULL 17/27] ppc/xive: introduce the XIVE Event Notification Descriptors |
Date: |
Thu, 13 Dec 2018 15:01:16 +1100 |
From: Cédric Le Goater <address@hidden>
To complete the event routing, the IVRE sub-engine uses a second table
containing Event Notification Descriptor (END) structures.
An END specifies on which Event Queue (EQ) the event notification
data, defined in the associated EAS, should be posted when an
exception occurs. It also defines which Notification Virtual Target
(NVT) should be notified.
The Event Queue is a memory page provided by the O/S defining a
circular buffer, one per server and priority couple, containing Event
Queue entries. These are 4 bytes long, the first bit being a
'generation' bit and the 31 following bits the END Data field. They
are pulled by the O/S when the exception occurs.
The END Data field is a way to set an invariant logical event source
number for an IRQ. On sPAPR machines, it is set with the
H_INT_SET_SOURCE_CONFIG hcall when the EISN flag is used.
Signed-off-by: Cédric Le Goater <address@hidden>
Signed-off-by: David Gibson <address@hidden>
---
hw/intc/xive.c | 174 +++++++++++++++++++++++++++++++++++++
include/hw/ppc/xive.h | 18 ++++
include/hw/ppc/xive_regs.h | 57 ++++++++++++
3 files changed, 249 insertions(+)
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index d21df6674d..41d8ba1540 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -443,6 +443,95 @@ static const TypeInfo xive_source_info = {
.class_init = xive_source_class_init,
};
+/*
+ * XiveEND helpers
+ */
+
+void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon)
+{
+ uint64_t qaddr_base = (uint64_t) be32_to_cpu(end->w2 & 0x0fffffff) << 32
+ | be32_to_cpu(end->w3);
+ uint32_t qsize = GETFIELD_BE32(END_W0_QSIZE, end->w0);
+ uint32_t qindex = GETFIELD_BE32(END_W1_PAGE_OFF, end->w1);
+ uint32_t qentries = 1 << (qsize + 10);
+ int i;
+
+ /*
+ * print out the [ (qindex - (width - 1)) .. (qindex + 1)] window
+ */
+ monitor_printf(mon, " [ ");
+ qindex = (qindex - (width - 1)) & (qentries - 1);
+ for (i = 0; i < width; i++) {
+ uint64_t qaddr = qaddr_base + (qindex << 2);
+ uint32_t qdata = -1;
+
+ if (dma_memory_read(&address_space_memory, qaddr, &qdata,
+ sizeof(qdata))) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: failed to read EQ @0x%"
+ HWADDR_PRIx "\n", qaddr);
+ return;
+ }
+ monitor_printf(mon, "%s%08x ", i == width - 1 ? "^" : "",
+ be32_to_cpu(qdata));
+ qindex = (qindex + 1) & (qentries - 1);
+ }
+}
+
+void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon)
+{
+ uint64_t qaddr_base = (uint64_t) be32_to_cpu(end->w2 & 0x0fffffff) << 32
+ | be32_to_cpu(end->w3);
+ uint32_t qindex = GETFIELD_BE32(END_W1_PAGE_OFF, end->w1);
+ uint32_t qgen = GETFIELD_BE32(END_W1_GENERATION, end->w1);
+ uint32_t qsize = GETFIELD_BE32(END_W0_QSIZE, end->w0);
+ uint32_t qentries = 1 << (qsize + 10);
+
+ uint32_t nvt = GETFIELD_BE32(END_W6_NVT_INDEX, end->w6);
+ uint8_t priority = GETFIELD_BE32(END_W7_F0_PRIORITY, end->w7);
+
+ if (!xive_end_is_valid(end)) {
+ return;
+ }
+
+ monitor_printf(mon, " %08x %c%c%c%c%c prio:%d nvt:%04x eq:@%08"PRIx64
+ "% 6d/%5d ^%d", end_idx,
+ xive_end_is_valid(end) ? 'v' : '-',
+ xive_end_is_enqueue(end) ? 'q' : '-',
+ xive_end_is_notify(end) ? 'n' : '-',
+ xive_end_is_backlog(end) ? 'b' : '-',
+ xive_end_is_escalate(end) ? 'e' : '-',
+ priority, nvt, qaddr_base, qindex, qentries, qgen);
+
+ xive_end_queue_pic_print_info(end, 6, mon);
+ monitor_printf(mon, "]\n");
+}
+
+static void xive_end_enqueue(XiveEND *end, uint32_t data)
+{
+ uint64_t qaddr_base = (uint64_t) be32_to_cpu(end->w2 & 0x0fffffff) << 32
+ | be32_to_cpu(end->w3);
+ uint32_t qsize = GETFIELD_BE32(END_W0_QSIZE, end->w0);
+ uint32_t qindex = GETFIELD_BE32(END_W1_PAGE_OFF, end->w1);
+ uint32_t qgen = GETFIELD_BE32(END_W1_GENERATION, end->w1);
+
+ uint64_t qaddr = qaddr_base + (qindex << 2);
+ uint32_t qdata = cpu_to_be32((qgen << 31) | (data & 0x7fffffff));
+ uint32_t qentries = 1 << (qsize + 10);
+
+ if (dma_memory_write(&address_space_memory, qaddr, &qdata, sizeof(qdata)))
{
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: failed to write END data @0x%"
+ HWADDR_PRIx "\n", qaddr);
+ return;
+ }
+
+ qindex = (qindex + 1) & (qentries - 1);
+ if (qindex == 0) {
+ qgen ^= 1;
+ end->w1 = SETFIELD_BE32(END_W1_GENERATION, end->w1, qgen);
+ }
+ end->w1 = SETFIELD_BE32(END_W1_PAGE_OFF, end->w1, qindex);
+}
+
/*
* XIVE Router (aka. Virtualization Controller or IVRE)
*/
@@ -455,6 +544,83 @@ int xive_router_get_eas(XiveRouter *xrtr, uint8_t eas_blk,
uint32_t eas_idx,
return xrc->get_eas(xrtr, eas_blk, eas_idx, eas);
}
+int xive_router_get_end(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
+ XiveEND *end)
+{
+ XiveRouterClass *xrc = XIVE_ROUTER_GET_CLASS(xrtr);
+
+ return xrc->get_end(xrtr, end_blk, end_idx, end);
+}
+
+int xive_router_write_end(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
+ XiveEND *end, uint8_t word_number)
+{
+ XiveRouterClass *xrc = XIVE_ROUTER_GET_CLASS(xrtr);
+
+ return xrc->write_end(xrtr, end_blk, end_idx, end, word_number);
+}
+
+/*
+ * An END trigger can come from an event trigger (IPI or HW) or from
+ * another chip. We don't model the PowerBus but the END trigger
+ * message has the same parameters than in the function below.
+ */
+static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk,
+ uint32_t end_idx, uint32_t end_data)
+{
+ XiveEND end;
+ uint8_t priority;
+ uint8_t format;
+
+ /* END cache lookup */
+ if (xive_router_get_end(xrtr, end_blk, end_idx, &end)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No END %x/%x\n", end_blk,
+ end_idx);
+ return;
+ }
+
+ if (!xive_end_is_valid(&end)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: END %x/%x is invalid\n",
+ end_blk, end_idx);
+ return;
+ }
+
+ if (xive_end_is_enqueue(&end)) {
+ xive_end_enqueue(&end, end_data);
+ /* Enqueuing event data modifies the EQ toggle and index */
+ xive_router_write_end(xrtr, end_blk, end_idx, &end, 1);
+ }
+
+ /*
+ * The W7 format depends on the F bit in W6. It defines the type
+ * of the notification :
+ *
+ * F=0 : single or multiple NVT notification
+ * F=1 : User level Event-Based Branch (EBB) notification, no
+ * priority
+ */
+ format = GETFIELD_BE32(END_W6_FORMAT_BIT, end.w6);
+ priority = GETFIELD_BE32(END_W7_F0_PRIORITY, end.w7);
+
+ /* The END is masked */
+ if (format == 0 && priority == 0xff) {
+ return;
+ }
+
+ /*
+ * Check the END ESn (Event State Buffer for notification) for
+ * even futher coalescing in the Router
+ */
+ if (!xive_end_is_notify(&end)) {
+ qemu_log_mask(LOG_UNIMP, "XIVE: !UCOND_NOTIFY not implemented\n");
+ return;
+ }
+
+ /*
+ * Follows IVPE notification
+ */
+}
+
static void xive_router_notify(XiveNotifier *xn, uint32_t lisn)
{
XiveRouter *xrtr = XIVE_ROUTER(xn);
@@ -482,6 +648,14 @@ static void xive_router_notify(XiveNotifier *xn, uint32_t
lisn)
/* Notification completed */
return;
}
+
+ /*
+ * The event trigger becomes an END trigger
+ */
+ xive_router_end_notify(xrtr,
+ GETFIELD_BE64(EAS_END_BLOCK, eas.w),
+ GETFIELD_BE64(EAS_END_INDEX, eas.w),
+ GETFIELD_BE64(EAS_END_DATA, eas.w));
}
static void xive_router_class_init(ObjectClass *klass, void *data)
diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h
index 527aa73366..4851d3b3a4 100644
--- a/include/hw/ppc/xive.h
+++ b/include/hw/ppc/xive.h
@@ -321,11 +321,29 @@ typedef struct XiveRouterClass {
/* XIVE table accessors */
int (*get_eas)(XiveRouter *xrtr, uint8_t eas_blk, uint32_t eas_idx,
XiveEAS *eas);
+ int (*get_end)(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
+ XiveEND *end);
+ int (*write_end)(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
+ XiveEND *end, uint8_t word_number);
} XiveRouterClass;
void xive_eas_pic_print_info(XiveEAS *eas, uint32_t lisn, Monitor *mon);
int xive_router_get_eas(XiveRouter *xrtr, uint8_t eas_blk, uint32_t eas_idx,
XiveEAS *eas);
+int xive_router_get_end(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
+ XiveEND *end);
+int xive_router_write_end(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
+ XiveEND *end, uint8_t word_number);
+
+/*
+ * For legacy compatibility, the exceptions define up to 256 different
+ * priorities. P9 implements only 9 levels : 8 active levels [0 - 7]
+ * and the least favored level 0xFF.
+ */
+#define XIVE_PRIORITY_MAX 7
+
+void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon);
+void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon);
#endif /* PPC_XIVE_H */
diff --git a/include/hw/ppc/xive_regs.h b/include/hw/ppc/xive_regs.h
index 15f2470ed9..3c0ebad18b 100644
--- a/include/hw/ppc/xive_regs.h
+++ b/include/hw/ppc/xive_regs.h
@@ -47,4 +47,61 @@ typedef struct XiveEAS {
#define GETFIELD_BE64(m, v) GETFIELD(m, be64_to_cpu(v))
#define SETFIELD_BE64(m, v, val) cpu_to_be64(SETFIELD(m, be64_to_cpu(v), val))
+/* Event Notification Descriptor (END) */
+typedef struct XiveEND {
+ uint32_t w0;
+#define END_W0_VALID PPC_BIT32(0) /* "v" bit */
+#define END_W0_ENQUEUE PPC_BIT32(1) /* "q" bit */
+#define END_W0_UCOND_NOTIFY PPC_BIT32(2) /* "n" bit */
+#define END_W0_BACKLOG PPC_BIT32(3) /* "b" bit */
+#define END_W0_PRECL_ESC_CTL PPC_BIT32(4) /* "p" bit */
+#define END_W0_ESCALATE_CTL PPC_BIT32(5) /* "e" bit */
+#define END_W0_UNCOND_ESCALATE PPC_BIT32(6) /* "u" bit - DD2.0 */
+#define END_W0_SILENT_ESCALATE PPC_BIT32(7) /* "s" bit - DD2.0 */
+#define END_W0_QSIZE PPC_BITMASK32(12, 15)
+#define END_W0_SW0 PPC_BIT32(16)
+#define END_W0_FIRMWARE END_W0_SW0 /* Owned by FW */
+#define END_QSIZE_4K 0
+#define END_QSIZE_64K 4
+#define END_W0_HWDEP PPC_BITMASK32(24, 31)
+ uint32_t w1;
+#define END_W1_ESn PPC_BITMASK32(0, 1)
+#define END_W1_ESn_P PPC_BIT32(0)
+#define END_W1_ESn_Q PPC_BIT32(1)
+#define END_W1_ESe PPC_BITMASK32(2, 3)
+#define END_W1_ESe_P PPC_BIT32(2)
+#define END_W1_ESe_Q PPC_BIT32(3)
+#define END_W1_GENERATION PPC_BIT32(9)
+#define END_W1_PAGE_OFF PPC_BITMASK32(10, 31)
+ uint32_t w2;
+#define END_W2_MIGRATION_REG PPC_BITMASK32(0, 3)
+#define END_W2_OP_DESC_HI PPC_BITMASK32(4, 31)
+ uint32_t w3;
+#define END_W3_OP_DESC_LO PPC_BITMASK32(0, 31)
+ uint32_t w4;
+#define END_W4_ESC_END_BLOCK PPC_BITMASK32(4, 7)
+#define END_W4_ESC_END_INDEX PPC_BITMASK32(8, 31)
+ uint32_t w5;
+#define END_W5_ESC_END_DATA PPC_BITMASK32(1, 31)
+ uint32_t w6;
+#define END_W6_FORMAT_BIT PPC_BIT32(8)
+#define END_W6_NVT_BLOCK PPC_BITMASK32(9, 12)
+#define END_W6_NVT_INDEX PPC_BITMASK32(13, 31)
+ uint32_t w7;
+#define END_W7_F0_IGNORE PPC_BIT32(0)
+#define END_W7_F0_BLK_GROUPING PPC_BIT32(1)
+#define END_W7_F0_PRIORITY PPC_BITMASK32(8, 15)
+#define END_W7_F1_WAKEZ PPC_BIT32(0)
+#define END_W7_F1_LOG_SERVER_ID PPC_BITMASK32(1, 31)
+} XiveEND;
+
+#define xive_end_is_valid(end) (be32_to_cpu((end)->w0) & END_W0_VALID)
+#define xive_end_is_enqueue(end) (be32_to_cpu((end)->w0) & END_W0_ENQUEUE)
+#define xive_end_is_notify(end) (be32_to_cpu((end)->w0) &
END_W0_UCOND_NOTIFY)
+#define xive_end_is_backlog(end) (be32_to_cpu((end)->w0) & END_W0_BACKLOG)
+#define xive_end_is_escalate(end) (be32_to_cpu((end)->w0) &
END_W0_ESCALATE_CTL)
+
+#define GETFIELD_BE32(m, v) GETFIELD(m, be32_to_cpu(v))
+#define SETFIELD_BE32(m, v, val) cpu_to_be32(SETFIELD(m, be32_to_cpu(v), val))
+
#endif /* PPC_XIVE_REGS_H */
--
2.19.2
- [Qemu-devel] [PULL 05/27] spapr: use g_new(T, n) instead of g_malloc(sizeof(T) * n), (continued)
- [Qemu-devel] [PULL 05/27] spapr: use g_new(T, n) instead of g_malloc(sizeof(T) * n), David Gibson, 2018/12/12
- [Qemu-devel] [PULL 08/27] ppc440_bamboo: use g_new(T, n) instead of g_malloc(sizeof(T) * n), David Gibson, 2018/12/12
- [Qemu-devel] [PULL 06/27] ppc405_boards: use g_new(T, n) instead of g_malloc(sizeof(T) * n), David Gibson, 2018/12/12
- [Qemu-devel] [PULL 12/27] e500: simplify IRQ wiring, David Gibson, 2018/12/12
- [Qemu-devel] [PULL 09/27] sam460ex: use g_new(T, n) instead of g_malloc(sizeof(T) * n), David Gibson, 2018/12/12
- [Qemu-devel] [PULL 07/27] ppc405_uc: use g_new(T, n) instead of g_malloc(sizeof(T) * n), David Gibson, 2018/12/12
- [Qemu-devel] [PULL 10/27] virtex_ml507: use g_new(T, n) instead of g_malloc(sizeof(T) * n), David Gibson, 2018/12/12
- [Qemu-devel] [PULL 19/27] spapr: introduce a spapr_irq_init() routine, David Gibson, 2018/12/12
- [Qemu-devel] [PULL 15/27] ppc/xive: introduce the XiveNotifier interface, David Gibson, 2018/12/12
- [Qemu-devel] [PULL 16/27] ppc/xive: introduce the XiveRouter model, David Gibson, 2018/12/12
- [Qemu-devel] [PULL 17/27] ppc/xive: introduce the XIVE Event Notification Descriptors,
David Gibson <=
- [Qemu-devel] [PULL 18/27] spapr: initialize VSMT before initializing the IRQ backend, David Gibson, 2018/12/12
- [Qemu-devel] [PULL 14/27] ppc/xive: add support for the LSI interrupt sources, David Gibson, 2018/12/12
- [Qemu-devel] [PULL 13/27] ppc/xive: introduce a XIVE interrupt source model, David Gibson, 2018/12/12
- [Qemu-devel] [PULL 25/27] ppc/xive: notify the CPU when the interrupt priority is more privileged, David Gibson, 2018/12/12
- [Qemu-devel] [PULL 23/27] ppc/xive: introduce the XIVE interrupt thread context, David Gibson, 2018/12/12
- [Qemu-devel] [PULL 11/27] mac_newworld: simplify IRQ wiring, David Gibson, 2018/12/12
- [Qemu-devel] [PULL 20/27] spapr: export and rename the xics_max_server_number() routine, David Gibson, 2018/12/12
- [Qemu-devel] [PULL 21/27] Changes requirement for "vsubsbs" instruction, David Gibson, 2018/12/12
- [Qemu-devel] [PULL 24/27] ppc/xive: introduce a simplified XIVE presenter, David Gibson, 2018/12/12
- [Qemu-devel] [PULL 27/27] spapr/xive: use the VCPU id as a NVT identifier, David Gibson, 2018/12/12