* [RFC PATCH 1/4] ppc/xive: introduce a new XiveRouter end_notify() handler
2023-07-04 13:49 [RFC PATCH 0/4] ppc: Improve multisocket support Cédric Le Goater
@ 2023-07-04 13:49 ` Cédric Le Goater
2023-07-04 13:49 ` [RFC PATCH 2/4] ppc/pnv: handle END triggers between chips with MMIOs Cédric Le Goater
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Cédric Le Goater @ 2023-07-04 13:49 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-ppc, Frédéric Barrat, Nicholas Piggin,
Cédric Le Goater
It will help us model the END triggers on the PowerNV machine, which
can be rerouted from another interrupt controller.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
include/hw/ppc/xive.h | 2 ++
hw/intc/xive.c | 28 ++++++++++++++++++----------
2 files changed, 20 insertions(+), 10 deletions(-)
diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h
index 9f580a2699e9..f120874e0ff1 100644
--- a/include/hw/ppc/xive.h
+++ b/include/hw/ppc/xive.h
@@ -401,6 +401,7 @@ struct XiveRouterClass {
int (*write_nvt)(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
XiveNVT *nvt, uint8_t word_number);
uint8_t (*get_block_id)(XiveRouter *xrtr);
+ void (*end_notify)(XiveRouter *xrtr, XiveEAS *eas);
};
int xive_router_get_eas(XiveRouter *xrtr, uint8_t eas_blk, uint32_t eas_idx,
@@ -414,6 +415,7 @@ int xive_router_get_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
int xive_router_write_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
XiveNVT *nvt, uint8_t word_number);
void xive_router_notify(XiveNotifier *xn, uint32_t lisn, bool pq_checked);
+void xive_router_end_notify(XiveRouter *xrtr, XiveEAS *eas);
/*
* XIVE Presenter
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index f60c8783455f..e36e695a691b 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -1518,6 +1518,13 @@ static void xive_router_realize(DeviceState *dev, Error **errp)
assert(xrtr->xfb);
}
+static void xive_router_end_notify_handler(XiveRouter *xrtr, XiveEAS *eas)
+{
+ XiveRouterClass *xrc = XIVE_ROUTER_GET_CLASS(xrtr);
+
+ return xrc->end_notify(xrtr, eas);
+}
+
/*
* Encode the HW CAM line in the block group mode format :
*
@@ -1664,8 +1671,7 @@ static bool xive_router_end_es_notify(XiveRouter *xrtr, uint8_t end_blk,
* 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)
+void xive_router_end_notify(XiveRouter *xrtr, XiveEAS *eas)
{
XiveEND end;
uint8_t priority;
@@ -1675,6 +1681,10 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk,
XiveNVT nvt;
bool found;
+ uint8_t end_blk = xive_get_field64(EAS_END_BLOCK, eas->w);
+ uint32_t end_idx = xive_get_field64(EAS_END_INDEX, eas->w);
+ uint32_t end_data = xive_get_field64(EAS_END_DATA, eas->w);
+
/* 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,
@@ -1817,10 +1827,7 @@ do_escalation:
/*
* The END trigger becomes an Escalation trigger
*/
- xive_router_end_notify(xrtr,
- xive_get_field32(END_W4_ESC_END_BLOCK, end.w4),
- xive_get_field32(END_W4_ESC_END_INDEX, end.w4),
- xive_get_field32(END_W5_ESC_END_DATA, end.w5));
+ xive_router_end_notify_handler(xrtr, (XiveEAS *) &end.w4);
}
void xive_router_notify(XiveNotifier *xn, uint32_t lisn, bool pq_checked)
@@ -1871,10 +1878,7 @@ void xive_router_notify(XiveNotifier *xn, uint32_t lisn, bool pq_checked)
/*
* The event trigger becomes an END trigger
*/
- xive_router_end_notify(xrtr,
- xive_get_field64(EAS_END_BLOCK, eas.w),
- xive_get_field64(EAS_END_INDEX, eas.w),
- xive_get_field64(EAS_END_DATA, eas.w));
+ xive_router_end_notify_handler(xrtr, &eas);
}
static Property xive_router_properties[] = {
@@ -1887,12 +1891,16 @@ static void xive_router_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
XiveNotifierClass *xnc = XIVE_NOTIFIER_CLASS(klass);
+ XiveRouterClass *xrc = XIVE_ROUTER_CLASS(klass);
dc->desc = "XIVE Router Engine";
device_class_set_props(dc, xive_router_properties);
/* Parent is SysBusDeviceClass. No need to call its realize hook */
dc->realize = xive_router_realize;
xnc->notify = xive_router_notify;
+
+ /* By default, the router handles END triggers locally */
+ xrc->end_notify = xive_router_end_notify;
}
static const TypeInfo xive_router_info = {
--
2.41.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [RFC PATCH 2/4] ppc/pnv: handle END triggers between chips with MMIOs
2023-07-04 13:49 [RFC PATCH 0/4] ppc: Improve multisocket support Cédric Le Goater
2023-07-04 13:49 ` [RFC PATCH 1/4] ppc/xive: introduce a new XiveRouter end_notify() handler Cédric Le Goater
@ 2023-07-04 13:49 ` Cédric Le Goater
2023-07-04 13:49 ` [RFC PATCH 3/4] ppc/pnv: add support for the PC MMIOs Cédric Le Goater
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Cédric Le Goater @ 2023-07-04 13:49 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-ppc, Frédéric Barrat, Nicholas Piggin,
Cédric Le Goater
The notify page of the interrupt controller can either be used to
receive trigger events from the HW controllers (PHB, PSI) or to
reroute interrupts between Interrupt Controller. In which case, the
VSD table is used to determine the address of the notify page of the
remote IC and the store data is forwarded.
Today, our model grabs the remote VSD (EAS, END, NVT) address using
pnv_xive_get_remote() helper but this is incorrect. EAS accesses
should always be local and END triggers should be rerouted using a
store on the remote IC notify page.
We still have a shortcut in the model for the NVT accesses. It will be
addressed later when we model the PC mmio operations.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
hw/intc/pnv_xive_regs.h | 1 +
hw/intc/pnv_xive.c | 68 +++++++++++++++++++++++++++++++++++++++--
2 files changed, 67 insertions(+), 2 deletions(-)
diff --git a/hw/intc/pnv_xive_regs.h b/hw/intc/pnv_xive_regs.h
index c78f030c0260..793847638bce 100644
--- a/hw/intc/pnv_xive_regs.h
+++ b/hw/intc/pnv_xive_regs.h
@@ -228,6 +228,7 @@
* VSD and is only meant to be used in indirect mode !
*/
#define VSD_MODE PPC_BITMASK(0, 1)
+#define VSD_MODE_INVALID 0
#define VSD_MODE_SHARED 1
#define VSD_MODE_EXCLUSIVE 2
#define VSD_MODE_FORWARD 3
diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c
index e536b3ec26e5..b41ab85e01bd 100644
--- a/hw/intc/pnv_xive.c
+++ b/hw/intc/pnv_xive.c
@@ -225,6 +225,11 @@ static uint64_t pnv_xive_vst_addr(PnvXive *xive, uint32_t type, uint8_t blk,
/* Remote VST access */
if (GETFIELD(VSD_MODE, vsd) == VSD_MODE_FORWARD) {
+ if (type != VST_TSEL_VPDT) {
+ xive_error(xive, "VST: invalid access on remote VST %s %x/%x !?",
+ info->name, blk, idx);
+ return 0;
+ }
xive = pnv_xive_get_remote(blk);
return xive ? pnv_xive_vst_addr(xive, type, blk, idx) : 0;
@@ -275,12 +280,26 @@ static int pnv_xive_vst_write(PnvXive *xive, uint32_t type, uint8_t blk,
static int pnv_xive_get_end(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
XiveEND *end)
{
+ PnvXive *xive = PNV_XIVE(xrtr);
+
+ if (pnv_xive_block_id(xive) != blk) {
+ xive_error(xive, "VST: END %x/%x is remote !?", blk, idx);
+ return -1;
+ }
+
return pnv_xive_vst_read(PNV_XIVE(xrtr), VST_TSEL_EQDT, blk, idx, end);
}
static int pnv_xive_write_end(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
XiveEND *end, uint8_t word_number)
{
+ PnvXive *xive = PNV_XIVE(xrtr);
+
+ if (pnv_xive_block_id(xive) != blk) {
+ xive_error(xive, "VST: END %x/%x is remote !?", blk, idx);
+ return -1;
+ }
+
return pnv_xive_vst_write(PNV_XIVE(xrtr), VST_TSEL_EQDT, blk, idx, end,
word_number);
}
@@ -1349,6 +1368,50 @@ static const MemoryRegionOps pnv_xive_ic_reg_ops = {
#define PNV_XIVE_SYNC_PUSH 0xf00 /* Sync push context */
#define PNV_XIVE_SYNC_VPC 0xf80 /* Sync remove VPC store */
+static void pnv_xive_end_notify(XiveRouter *xrtr, XiveEAS *eas)
+{
+ PnvXive *xive = PNV_XIVE(xrtr);
+ uint8_t end_blk = xive_get_field64(EAS_END_BLOCK, eas->w);
+ uint32_t end_idx = xive_get_field64(EAS_END_INDEX, eas->w);
+ uint32_t end_data = xive_get_field64(EAS_END_DATA, eas->w);
+ uint64_t end_vsd = xive->vsds[VST_TSEL_EQDT][end_blk];
+
+ switch (GETFIELD(VSD_MODE, end_vsd)) {
+ case VSD_MODE_EXCLUSIVE:
+ /* Perform the END notification on the local IC. */
+ xive_router_end_notify(xrtr, eas);
+ break;
+
+ case VSD_MODE_FORWARD: {
+ MemTxResult result;
+ uint64_t notif_port = end_vsd & VSD_ADDRESS_MASK;
+ uint64_t data = XIVE_TRIGGER_END | XIVE_TRIGGER_PQ |
+ be64_to_cpu(eas->w);
+
+ /* Forward the store on the remote IC notify page. */
+ address_space_stq_be(&address_space_memory, notif_port, data,
+ MEMTXATTRS_UNSPECIFIED, &result);
+ if (result != MEMTX_OK) {
+ xive_error(xive, "IC: Forward notif END %x/%x [%x] failed @%"
+ HWADDR_PRIx, end_blk, end_idx, end_data, notif_port);
+ return;
+ }
+ break;
+ }
+
+ case VSD_MODE_INVALID:
+ default:
+ /* Set FIR */
+ xive_error(xive, "IC: Invalid END VSD for block %x", end_blk);
+ return;
+ }
+}
+
+/*
+ * The notify page can either be used to receive trigger events from
+ * the HW controllers (PHB, PSI) or to reroute interrupts between
+ * Interrupt controllers.
+ */
static void pnv_xive_ic_hw_trigger(PnvXive *xive, hwaddr addr, uint64_t val)
{
uint8_t blk;
@@ -1357,8 +1420,8 @@ static void pnv_xive_ic_hw_trigger(PnvXive *xive, hwaddr addr, uint64_t val)
trace_pnv_xive_ic_hw_trigger(addr, val);
if (val & XIVE_TRIGGER_END) {
- xive_error(xive, "IC: END trigger at @0x%"HWADDR_PRIx" data 0x%"PRIx64,
- addr, val);
+ val = cpu_to_be64(val);
+ pnv_xive_end_notify(XIVE_ROUTER(xive), (XiveEAS *) &val);
return;
}
@@ -1998,6 +2061,7 @@ static void pnv_xive_class_init(ObjectClass *klass, void *data)
xrc->get_nvt = pnv_xive_get_nvt;
xrc->write_nvt = pnv_xive_write_nvt;
xrc->get_block_id = pnv_xive_get_block_id;
+ xrc->end_notify = pnv_xive_end_notify;
xnc->notify = pnv_xive_notify;
xpc->match_nvt = pnv_xive_match_nvt;
--
2.41.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [RFC PATCH 3/4] ppc/pnv: add support for the PC MMIOs
2023-07-04 13:49 [RFC PATCH 0/4] ppc: Improve multisocket support Cédric Le Goater
2023-07-04 13:49 ` [RFC PATCH 1/4] ppc/xive: introduce a new XiveRouter end_notify() handler Cédric Le Goater
2023-07-04 13:49 ` [RFC PATCH 2/4] ppc/pnv: handle END triggers between chips with MMIOs Cédric Le Goater
@ 2023-07-04 13:49 ` Cédric Le Goater
2023-07-04 13:49 ` [RFC PATCH 4/4] ppc/pnv: Add support for degenerative interrupts (POWER LSI) Cédric Le Goater
2023-07-04 16:20 ` [RFC PATCH 0/4] ppc: Improve multisocket support Frederic Barrat
4 siblings, 0 replies; 7+ messages in thread
From: Cédric Le Goater @ 2023-07-04 13:49 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-ppc, Frédéric Barrat, Nicholas Piggin,
Cédric Le Goater
Associated with each NVT is a CI page address that is intended for use
by privileged interrupt management code to adjust the backlog counts
of a logical server and interrupt pending buffer for a specific
virtual processor. This backlog count adjustment function is valuable
to avoid extraneous physical interrupts when the hardware accumulates
the backlog count per event queue post while the software handles
multiple event queue entries on a single physical interrupt. Likewise
adjusting the Interrupt Pending Buffer allows a virtual processor to
process event queues of other priorities during one physical interrupt
cycle.
The NVT adjustment is initiated by a store byte (stb) or a double word
load instruction.
For the store byte operations that increment/decrement a backlog count
the value of the data byte is the amount added (counter saturates at
maximum value) / subtracted from the backlog counter (the counter does
not go negative).
For the store byte operations that set/reset an IPB priority bit, the
data byte is ignored.
The load double word operations that target a backlog counter
increment/decrement the backlog count by one count (counter saturates
at maximum value / does not go negative).
Load operations to an IPB return the pre-operation value, while load
operations to a backlog counter return the post-operation value, in
both cases right justified in the double word.
Programs may use the load operations if they need to know when the
operation has completed; this may be accomplished by introducing a
data dependency upon the returned load data. Other operation lengths
(other than store byte and load double word) are not supported –
results are boundedly undefined.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
hw/intc/pnv_xive.c | 85 +++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 80 insertions(+), 5 deletions(-)
diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c
index b41ab85e01bd..844965cfe281 100644
--- a/hw/intc/pnv_xive.c
+++ b/hw/intc/pnv_xive.c
@@ -1773,17 +1773,92 @@ static uint64_t pnv_xive_pc_read(void *opaque, hwaddr addr,
unsigned size)
{
PnvXive *xive = PNV_XIVE(opaque);
+ uint32_t offset = (addr & 0x1F0) >> 4;
+ uint8_t nvt_blk;
+ uint32_t nvt_idx;
+ XiveNVT nvt;
+ uint8_t ipb;
+ uint64_t ret = -1;
- xive_error(xive, "PC: invalid read @%"HWADDR_PRIx, addr);
- return -1;
+ if (size != 8) {
+ xive_error(xive, "PC: invalid read size %d @%"HWADDR_PRIx"\n",
+ size, addr);
+ return -1;
+ }
+
+ /* TODO: support multi block */
+ nvt_blk = pnv_xive_block_id(xive);
+ nvt_idx = addr >> TM_SHIFT;
+
+ if (xive_router_get_nvt(XIVE_ROUTER(xive), nvt_blk, nvt_idx, &nvt)) {
+ xive_error(xive, "PC: invalid NVT %x/%x\n", nvt_blk, nvt_idx);
+ return -1;
+ }
+
+ ipb = xive_get_field32(NVT_W4_IPB, nvt.w4);
+
+ switch (offset) {
+ case 0x0 ... 0x7: /* set IBP bit x */
+ ret = ipb;
+ ipb |= 1 << offset;
+ break;
+ case 0x10 ... 0x17: /* reset IBP bit x */
+ ret = ipb;
+ ipb &= ~(1 << (offset - 0x10));
+ break;
+
+ case 0x8 ... 0xF: /* TODO: increment backlog */
+ /* backlog = offset - 0x8; */
+ case 0x18 ... 0x1F: /* TODO: decrement backlog */
+ /* backlog = offset - 0x18; */
+ default:
+ xive_error(xive, "PC: invalid write @%"HWADDR_PRIx"\n", addr);
+ }
+
+ if (ipb != xive_get_field32(NVT_W4_IPB, nvt.w4)) {
+ nvt.w4 = xive_set_field32(NVT_W4_IPB, nvt.w4, ipb);
+ xive_router_write_nvt(XIVE_ROUTER(xive), nvt_blk, nvt_idx, &nvt, 4);
+ }
+
+ return ret;
}
static void pnv_xive_pc_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
PnvXive *xive = PNV_XIVE(opaque);
+ uint32_t offset = (addr & 0x1F0) >> 4;
+ uint8_t nvt_blk;
+ uint32_t nvt_idx;
+ XiveNVT nvt;
+
+ if (size != 1) {
+ xive_error(xive, "PC: invalid write size %d @%"HWADDR_PRIx"\n",
+ size, addr);
+ return;
+ }
+
+ /* TODO: support multi block */
+ nvt_blk = pnv_xive_block_id(xive);
+ nvt_idx = addr >> TM_SHIFT;
+
+ if (xive_router_get_nvt(XIVE_ROUTER(xive), nvt_blk, nvt_idx, &nvt)) {
+ xive_error(xive, "PC: invalid NVT %x/%x\n", nvt_blk, nvt_idx);
+ return;
+ }
- xive_error(xive, "PC: invalid write to VC @%"HWADDR_PRIx, addr);
+ switch (offset) {
+ case 0x0 ... 0x7: /* ignored */
+ case 0x10 ... 0x17: /* ignored */
+ break;
+
+ case 0x8 ... 0xF: /* TODO: Add to backlog */
+ /* backlog = offset - 0x8; */
+ case 0x18 ... 0x1F: /* TODO: substract to backlog */
+ /* backlog = offset - 0x18; */
+ default:
+ xive_error(xive, "PC: invalid write @%"HWADDR_PRIx"\n", addr);
+ }
}
static const MemoryRegionOps pnv_xive_pc_ops = {
@@ -1791,11 +1866,11 @@ static const MemoryRegionOps pnv_xive_pc_ops = {
.write = pnv_xive_pc_write,
.endianness = DEVICE_BIG_ENDIAN,
.valid = {
- .min_access_size = 8,
+ .min_access_size = 1,
.max_access_size = 8,
},
.impl = {
- .min_access_size = 8,
+ .min_access_size = 1,
.max_access_size = 8,
},
};
--
2.41.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [RFC PATCH 4/4] ppc/pnv: Add support for degenerative interrupts (POWER LSI)
2023-07-04 13:49 [RFC PATCH 0/4] ppc: Improve multisocket support Cédric Le Goater
` (2 preceding siblings ...)
2023-07-04 13:49 ` [RFC PATCH 3/4] ppc/pnv: add support for the PC MMIOs Cédric Le Goater
@ 2023-07-04 13:49 ` Cédric Le Goater
2023-07-04 16:20 ` [RFC PATCH 0/4] ppc: Improve multisocket support Frederic Barrat
4 siblings, 0 replies; 7+ messages in thread
From: Cédric Le Goater @ 2023-07-04 13:49 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-ppc, Frédéric Barrat, Nicholas Piggin,
Cédric Le Goater
POWER systems have a degenerative interrupt path used during system
bring up. It doesn't rely on the XIVE routing logic and all thread 0
of each core are notified.
TODO: Need a new OS driver to check modeling.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
include/hw/ppc/pnv_xive.h | 15 ++++++
include/hw/ppc/xive.h | 1 +
hw/intc/pnv_xive.c | 109 +++++++++++++++++++++++++-------------
hw/intc/xive.c | 22 ++++++++
4 files changed, 111 insertions(+), 36 deletions(-)
diff --git a/include/hw/ppc/pnv_xive.h b/include/hw/ppc/pnv_xive.h
index 9c48430ee418..0ab3a8651ec1 100644
--- a/include/hw/ppc/pnv_xive.h
+++ b/include/hw/ppc/pnv_xive.h
@@ -15,6 +15,17 @@
#include "qom/object.h"
#include "hw/ppc/xive2.h"
+struct PnvXive;
+
+#define TYPE_PNV_XIVE_LSI "pnv-xive-lsi"
+#define PNV_XIVE_LSI(obj) OBJECT_CHECK(PnvXiveLsi, (obj), TYPE_PNV_XIVE_LSI)
+
+typedef struct PnvXiveLsi {
+ DeviceState parent_obj;
+
+ struct PnvXive *xive;
+} PnvXiveLsi;
+
#define TYPE_PNV_XIVE "pnv-xive"
OBJECT_DECLARE_TYPE(PnvXive, PnvXiveClass,
PNV_XIVE)
@@ -71,6 +82,10 @@ struct PnvXive {
XiveSource ipi_source;
XiveENDSource end_source;
+ /* Lsi handlers */
+ PnvXiveLsi lsi_xive;
+ XiveSource lsi_source;
+
/* Interrupt controller registers */
uint64_t regs[0x300];
diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h
index f120874e0ff1..983a475dd77c 100644
--- a/include/hw/ppc/xive.h
+++ b/include/hw/ppc/xive.h
@@ -534,6 +534,7 @@ void xive_tctx_reset(XiveTCTX *tctx);
void xive_tctx_destroy(XiveTCTX *tctx);
void xive_tctx_ipb_update(XiveTCTX *tctx, uint8_t ring, uint8_t ipb);
void xive_tctx_reset_os_signal(XiveTCTX *tctx);
+void xive_tctx_lsi_notify(XiveTCTX *tctx);
/*
* KVM XIVE device helpers
diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c
index 844965cfe281..9bf138cdea2c 100644
--- a/hw/intc/pnv_xive.c
+++ b/hw/intc/pnv_xive.c
@@ -991,7 +991,7 @@ static void pnv_xive_ic_reg_write(void *opaque, hwaddr offset,
memory_region_del_subregion(&xive->ic_mmio,
&xive->ic_notify_mmio);
memory_region_del_subregion(&xive->ic_mmio,
- &xive->ic_lsi_mmio);
+ &xive->lsi_source.esb_mmio);
memory_region_del_subregion(&xive->ic_mmio,
&xive->tm_indirect_mmio);
@@ -1010,7 +1010,7 @@ static void pnv_xive_ic_reg_write(void *opaque, hwaddr offset,
&xive->ic_notify_mmio);
memory_region_add_subregion(&xive->ic_mmio,
2ul << xive->ic_shift,
- &xive->ic_lsi_mmio);
+ &xive->lsi_source.esb_mmio);
memory_region_add_subregion(&xive->ic_mmio,
4ull << xive->ic_shift,
&xive->tm_indirect_mmio);
@@ -1503,39 +1503,9 @@ static const MemoryRegionOps pnv_xive_ic_notify_ops = {
};
/*
- * IC - LSI MMIO handlers (not modeled)
+ * IC - LSI MMIO handlers
*/
-static void pnv_xive_ic_lsi_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- PnvXive *xive = PNV_XIVE(opaque);
-
- xive_error(xive, "IC: LSI invalid write @%"HWADDR_PRIx, addr);
-}
-
-static uint64_t pnv_xive_ic_lsi_read(void *opaque, hwaddr addr, unsigned size)
-{
- PnvXive *xive = PNV_XIVE(opaque);
-
- xive_error(xive, "IC: LSI invalid read @%"HWADDR_PRIx, addr);
- return -1;
-}
-
-static const MemoryRegionOps pnv_xive_ic_lsi_ops = {
- .read = pnv_xive_ic_lsi_read,
- .write = pnv_xive_ic_lsi_write,
- .endianness = DEVICE_BIG_ENDIAN,
- .valid = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
-};
-
/*
* IC - Indirect TIMA MMIO handlers
*/
@@ -1975,6 +1945,10 @@ static void pnv_xive_init(Object *obj)
TYPE_XIVE_SOURCE);
object_initialize_child(obj, "end_source", &xive->end_source,
TYPE_XIVE_END_SOURCE);
+ object_initialize_child(obj, "lsi_source", &xive->lsi_source,
+ TYPE_XIVE_SOURCE);
+ object_initialize_child(obj, "xive_lsi", &xive->lsi_xive,
+ TYPE_PNV_XIVE_LSI);
}
/*
@@ -1988,6 +1962,7 @@ static void pnv_xive_realize(DeviceState *dev, Error **errp)
PnvXive *xive = PNV_XIVE(dev);
PnvXiveClass *pxc = PNV_XIVE_GET_CLASS(dev);
XiveSource *xsrc = &xive->ipi_source;
+ XiveSource *lsi_xsrc = &xive->lsi_source;
XiveENDSource *end_xsrc = &xive->end_source;
Error *local_err = NULL;
@@ -2037,9 +2012,20 @@ static void pnv_xive_realize(DeviceState *dev, Error **errp)
&pnv_xive_ic_notify_ops,
xive, "xive-ic-notify", 1 << xive->ic_shift);
- /* The Pervasive LSI trigger and EOI pages (not modeled) */
- memory_region_init_io(&xive->ic_lsi_mmio, OBJECT(dev), &pnv_xive_ic_lsi_ops,
- xive, "xive-ic-lsi", 2 << xive->ic_shift);
+ /* The Pervasive LSI trigger and EOI pages */
+
+ object_property_set_link(OBJECT(&xive->lsi_xive), "xive", OBJECT(xive),
+ &error_abort);
+ if (!qdev_realize(DEVICE(&xive->lsi_xive), NULL, errp)) {
+ return;
+ }
+
+ object_property_set_int(OBJECT(lsi_xsrc), "nr-irqs", 1, &error_fatal);
+ object_property_set_link(OBJECT(lsi_xsrc), "xive", OBJECT(&xive->lsi_xive),
+ &error_abort);
+ if (!qdev_realize(DEVICE(lsi_xsrc), NULL, &local_err)) {
+ return;
+ }
/* Thread Interrupt Management Area (Indirect) */
memory_region_init_io(&xive->tm_indirect_mmio, OBJECT(dev),
@@ -2156,9 +2142,60 @@ static const TypeInfo pnv_xive_info = {
}
};
+/*
+ * Notifier proxy for LSI sources
+ *
+ * Trigger all threads 0
+ */
+static void pnv_xive_lsi_notify(XiveNotifier *xn, uint32_t srcno,
+ bool pq_checked)
+{
+ PnvXive *xive = PNV_XIVE_LSI(xn)->xive;
+ PnvChip *chip = xive->chip;
+ int i;
+
+ for (i = 0; i < chip->nr_cores; i++) {
+ PowerPCCPU *cpu = chip->cores[i]->threads[0];
+
+ if (!pnv_xive_is_cpu_enabled(xive, cpu)) {
+ continue;
+ }
+
+ xive_tctx_lsi_notify(XIVE_TCTX(pnv_cpu_state(cpu)->intc));
+ }
+}
+
+static Property pnv_xive_lsi_properties[] = {
+ DEFINE_PROP_LINK("xive", PnvXiveLsi, xive, TYPE_PNV_XIVE, PnvXive *),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pnv_xive_lsi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ XiveNotifierClass *xnc = XIVE_NOTIFIER_CLASS(klass);
+
+ dc->desc = "PowerNV XIVE LSI proxy";
+ device_class_set_props(dc, pnv_xive_lsi_properties);
+
+ xnc->notify = pnv_xive_lsi_notify;
+};
+
+static const TypeInfo pnv_xive_lsi_info = {
+ .name = TYPE_PNV_XIVE_LSI,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(PnvXiveLsi),
+ .class_init = pnv_xive_lsi_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_XIVE_NOTIFIER },
+ { }
+ }
+};
+
static void pnv_xive_register_types(void)
{
type_register_static(&pnv_xive_info);
+ type_register_static(&pnv_xive_lsi_info);
}
type_init(pnv_xive_register_types)
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index e36e695a691b..d81b7d6ea6b4 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -90,6 +90,8 @@ static uint64_t xive_tctx_accept(XiveTCTX *tctx, uint8_t ring)
regs[TM_CPPR], regs[TM_NSR]);
}
+ /* TODO: drop LP bit when LE is set */
+
return (nsr << 8) | regs[TM_CPPR];
}
@@ -153,6 +155,26 @@ void xive_tctx_ipb_update(XiveTCTX *tctx, uint8_t ring, uint8_t ipb)
xive_tctx_notify(tctx, ring);
}
+void xive_tctx_lsi_notify(XiveTCTX *tctx)
+{
+ uint32_t qw3w2 = xive_tctx_word2(&tctx->regs[TM_QW3_HV_PHYS]);
+ uint8_t *regs = &tctx->regs[TM_QW3_HV_PHYS];
+
+ /*
+ * If the HW context (VT) is enabled and the LSI enabled (LE) bit
+ * is set, raise the LSI pending bit and notify the CPU on the HV
+ * line.
+ */
+ if ((be32_to_cpu(qw3w2) & (TM_QW3W2_VT | TM_QW3W2_LE)) ==
+ (TM_QW3W2_VT | TM_QW3W2_LE)) {
+ qw3w2 = xive_set_field32(TM_QW3W2_LP, qw3w2, 1);
+ memcpy(&tctx->regs[TM_QW3_HV_PHYS + TM_WORD2], &qw3w2, 4);
+
+ regs[TM_NSR] |= (TM_QW3_NSR_HE_LSI << 6);
+ qemu_irq_raise(xive_tctx_output(tctx, TM_QW3_HV_PHYS));
+ }
+}
+
/*
* XIVE Thread Interrupt Management Area (TIMA)
*/
--
2.41.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [RFC PATCH 0/4] ppc: Improve multisocket support
2023-07-04 13:49 [RFC PATCH 0/4] ppc: Improve multisocket support Cédric Le Goater
` (3 preceding siblings ...)
2023-07-04 13:49 ` [RFC PATCH 4/4] ppc/pnv: Add support for degenerative interrupts (POWER LSI) Cédric Le Goater
@ 2023-07-04 16:20 ` Frederic Barrat
2023-07-04 16:57 ` Cédric Le Goater
4 siblings, 1 reply; 7+ messages in thread
From: Frederic Barrat @ 2023-07-04 16:20 UTC (permalink / raw)
To: Cédric Le Goater, qemu-devel; +Cc: qemu-ppc, Nicholas Piggin
On 04/07/2023 15:49, Cédric Le Goater wrote:
> Hello,
>
> Here are changes improving multisocket support of the XIVE models
> (POWER9 only). When a source has an END target on another chip, the
> XIVE IC will use an MMIO store to forward the notification to the
> remote chip. The long term plan is to get rid of pnv_xive_get_remote()
> whic is a modeling shortcut. I have had them for while, they compile,
> they seem to still work but this is not for merge yet. If someone
> could take over, that would be nice.
>
> The best way to test is to start a 2 sockets * 1 cpu system with devices
> attached to the PCI buses of chip 0 and to offline CPU 0. All sources
> should be configured to be served by CPU 1 on socket 1 and trigger
> notifications on chip 0 should be forwarded to chip 1.
>
> Last patch adds support for degenerative interrupts. This is used by
> the lowest level FW of POWER systems. Difficult to test.
>
Thanks for the series! My crystal ball tells me the PC MMIO patch will
come handy soon (to be adapted for P10 and groups). And the remote
routing looks pretty interesting too.
The last patch (LSI) may rot a bit longer though :)
Fred
> Thanks,
>
> C.
>
> Cédric Le Goater (4):
> ppc/xive: introduce a new XiveRouter end_notify() handler
> ppc/pnv: handle END triggers between chips with MMIOs
> ppc/pnv: add support for the PC MMIOs
> ppc/pnv: Add support for degenerative interrupts (POWER LSI)
>
> hw/intc/pnv_xive_regs.h | 1 +
> include/hw/ppc/pnv_xive.h | 15 +++
> include/hw/ppc/xive.h | 3 +
> hw/intc/pnv_xive.c | 262 +++++++++++++++++++++++++++++++-------
> hw/intc/xive.c | 50 ++++++--
> 5 files changed, 278 insertions(+), 53 deletions(-)
>
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [RFC PATCH 0/4] ppc: Improve multisocket support
2023-07-04 16:20 ` [RFC PATCH 0/4] ppc: Improve multisocket support Frederic Barrat
@ 2023-07-04 16:57 ` Cédric Le Goater
0 siblings, 0 replies; 7+ messages in thread
From: Cédric Le Goater @ 2023-07-04 16:57 UTC (permalink / raw)
To: Frederic Barrat, qemu-devel; +Cc: qemu-ppc, Nicholas Piggin
On 7/4/23 18:20, Frederic Barrat wrote:
>
>
> On 04/07/2023 15:49, Cédric Le Goater wrote:
>> Hello,
>>
>> Here are changes improving multisocket support of the XIVE models
>> (POWER9 only). When a source has an END target on another chip, the
>> XIVE IC will use an MMIO store to forward the notification to the
>> remote chip. The long term plan is to get rid of pnv_xive_get_remote()
>> whic is a modeling shortcut. I have had them for while, they compile,
>> they seem to still work but this is not for merge yet. If someone
>> could take over, that would be nice.
>>
>> The best way to test is to start a 2 sockets * 1 cpu system with devices
>> attached to the PCI buses of chip 0 and to offline CPU 0. All sources
>> should be configured to be served by CPU 1 on socket 1 and trigger
>> notifications on chip 0 should be forwarded to chip 1.
>>
>> Last patch adds support for degenerative interrupts. This is used by
>> the lowest level FW of POWER systems. Difficult to test.
>>
>
>
> Thanks for the series! My crystal ball tells me the PC MMIO patch will come handy soon (to be adapted for P10 and groups). And the remote routing looks pretty interesting too.
I am glad !
I think the first 2 patches are a good addition. They remove a
qdev_get_machine() call which is ugly. P10 has the same kind of
shortcut.
C.
^ permalink raw reply [flat|nested] 7+ messages in thread