@@ -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,
},
};
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(-)