[Skiboot] [PATCH 19/22] xive/p9: remove XICS emulation
Cédric Le Goater
clg at kaod.org
Wed Sep 4 03:04:10 AEST 2019
This emulation was required to run pre-POWER9 linux kernels.
Signed-off-by: Cédric Le Goater <clg at kaod.org>
---
hw/xive-p9.c | 925 +--------------------------------------------------
1 file changed, 5 insertions(+), 920 deletions(-)
diff --git a/hw/xive-p9.c b/hw/xive-p9.c
index cdc44a123b08..320ec65ebe1f 100644
--- a/hw/xive-p9.c
+++ b/hw/xive-p9.c
@@ -27,28 +27,15 @@
#include <phys-map.h>
#include <p9_stop_api.H>
-/* Always notify from EQ to VP (no EOI on EQs). Will speed up
- * EOIs at the expense of potentially higher powerbus traffic.
- */
-#define EQ_ALWAYS_NOTIFY
-
/* Verbose debug */
#undef XIVE_VERBOSE_DEBUG
/* Extra debug options used in debug builds */
#ifdef DEBUG
-#define XIVE_DEBUG_DUPLICATES
#define XIVE_PERCPU_LOG
-#define XIVE_DEBUG_INIT_CACHE_UPDATES
-#define XIVE_EXTRA_CHECK_INIT_CACHE
-#undef XIVE_CHECK_MISROUTED_IPI
#define XIVE_CHECK_LOCKS
#else
-#undef XIVE_DEBUG_DUPLICATES
#undef XIVE_PERCPU_LOG
-#undef XIVE_DEBUG_INIT_CACHE_UPDATES
-#undef XIVE_EXTRA_CHECK_INIT_CACHE
-#undef XIVE_CHECK_MISROUTED_IPI
#undef XIVE_CHECK_LOCKS
#endif
@@ -178,9 +165,6 @@
/* Number of priorities (and thus EQDs) we allocate for each VP */
#define NUM_INT_PRIORITIES 8
-/* Priority used for the one queue in XICS emulation */
-#define XIVE_EMULATION_PRIO 7
-
/* Max number of VPs. We allocate an indirect table big enough so
* that when fully populated we can have that many VPs.
*
@@ -214,7 +198,6 @@
* to the "mode" parameter of the opal_xive_reset() call
*/
static enum {
- XIVE_MODE_EMU = OPAL_XIVE_MODE_EMU,
XIVE_MODE_EXPL = OPAL_XIVE_MODE_EXPL,
XIVE_MODE_NONE,
} xive_mode = XIVE_MODE_NONE;
@@ -261,23 +244,8 @@ struct xive_cpu_state {
uint32_t vp_idx;
uint32_t eq_blk;
uint32_t eq_idx; /* Base eq index of a block of 8 */
- void *eq_page;
- /* Pre-allocated IPI */
- uint32_t ipi_irq;
-
- /* Use for XICS emulation */
struct lock lock;
- uint8_t cppr;
- uint8_t mfrr;
- uint8_t pending;
- uint8_t prev_cppr;
- uint32_t *eqbuf;
- uint32_t eqptr;
- uint32_t eqmsk;
- uint8_t eqgen;
- void *eqmmio;
- uint64_t total_irqs;
};
#ifdef XIVE_PERCPU_LOG
@@ -801,41 +769,6 @@ static void xive_init_default_vp(struct xive_vp *vp,
vp->w0 = VP_W0_VALID;
}
-static void xive_init_emu_eq(uint32_t vp_blk, uint32_t vp_idx,
- struct xive_eq *eq, void *backing_page,
- uint8_t prio)
-{
- memset(eq, 0, sizeof(struct xive_eq));
-
- eq->w1 = EQ_W1_GENERATION;
- eq->w3 = ((uint64_t)backing_page) & 0xffffffff;
- eq->w2 = (((uint64_t)backing_page)) >> 32 & 0x0fffffff;
- eq->w6 = SETFIELD(EQ_W6_NVT_BLOCK, 0ul, vp_blk) |
- SETFIELD(EQ_W6_NVT_INDEX, 0ul, vp_idx);
- eq->w7 = SETFIELD(EQ_W7_F0_PRIORITY, 0ul, prio);
- eq->w0 = EQ_W0_VALID | EQ_W0_ENQUEUE |
- SETFIELD(EQ_W0_QSIZE, 0ul, EQ_QSIZE_64K) |
- EQ_W0_FIRMWARE;
-#ifdef EQ_ALWAYS_NOTIFY
- eq->w0 |= EQ_W0_UCOND_NOTIFY;
-#endif
-}
-
-static uint32_t *xive_get_eq_buf(uint32_t eq_blk, uint32_t eq_idx)
-{
- struct xive *x = xive_from_vc_blk(eq_blk);
- struct xive_eq *eq;
- uint64_t addr;
-
- assert(x);
- eq = xive_get_eq(x, eq_idx);
- assert(eq);
- assert(eq->w0 & EQ_W0_VALID);
- addr = (((uint64_t)eq->w2) & 0x0fffffff) << 32 | eq->w3;
-
- return (uint32_t *)addr;
-}
-
static void *xive_get_donated_page(struct xive *x)
{
return (void *)list_pop_(&x->donated_pages, 0);
@@ -2149,10 +2082,6 @@ static int64_t xive_set_irq_targetting(uint32_t isn, uint32_t target,
lock(&x->lock);
- /* If using emulation mode, fixup prio to the only supported one */
- if (xive_mode == XIVE_MODE_EMU && prio != 0xff)
- prio = XIVE_EMULATION_PRIO;
-
/* Read existing IVE */
new_ive = ive->w;
@@ -2663,47 +2592,6 @@ static struct xive *init_one_xive(struct dt_node *np)
return NULL;
}
-/*
- * XICS emulation
- */
-static void xive_ipi_init(struct xive *x, struct cpu_thread *cpu)
-{
- struct xive_cpu_state *xs = cpu->xstate;
-
- assert(xs);
-
- __xive_set_irq_config(&x->ipis.is, xs->ipi_irq, cpu->pir,
- XIVE_EMULATION_PRIO, xs->ipi_irq,
- true, true);
-}
-
-static void xive_ipi_eoi(struct xive *x, uint32_t idx)
-{
- uint8_t *mm = x->esb_mmio + idx * 0x20000;
- uint8_t eoi_val;
-
- /* For EOI, we use the special MMIO that does a clear of both
- * P and Q and returns the old Q.
- *
- * This allows us to then do a re-trigger if Q was set rather
- * than synthetizing an interrupt in software
- */
- eoi_val = in_8(mm + 0x10c00);
- if (eoi_val & 1) {
- out_8(mm, 0);
- }
-}
-
-static void xive_ipi_trigger(struct xive *x, uint32_t idx)
-{
- uint8_t *mm = x->esb_mmio + idx * 0x20000;
-
- xive_vdbg(x, "Trigger IPI 0x%x\n", idx);
-
- out_8(mm, 0);
-}
-
-
static void xive_reset_enable_thread(struct cpu_thread *c)
{
struct proc_chip *chip = get_chip(c->chip_id);
@@ -2748,166 +2636,6 @@ static void xive_p9_cpu_callin(struct cpu_thread *cpu)
old_w2, w2);
}
-#ifdef XIVE_DEBUG_INIT_CACHE_UPDATES
-static bool xive_check_eq_update(struct xive *x, uint32_t idx, struct xive_eq *eq)
-{
- struct xive_eq *eq_p = xive_get_eq(x, idx);
- struct xive_eq eq2;
-
- assert(eq_p);
- eq2 = *eq_p;
- if (memcmp(eq, &eq2, sizeof(eq)) != 0) {
- xive_err(x, "EQ update mismatch idx %d\n", idx);
- xive_err(x, "want: %08x %08x %08x %08x\n",
- eq->w0, eq->w1, eq->w2, eq->w3);
- xive_err(x, " %08x %08x %08x %08x\n",
- eq->w4, eq->w5, eq->w6, eq->w7);
- xive_err(x, "got : %08x %08x %08x %08x\n",
- eq2.w0, eq2.w1, eq2.w2, eq2.w3);
- xive_err(x, " %08x %08x %08x %08x\n",
- eq2.w4, eq2.w5, eq2.w6, eq2.w7);
- return false;
- }
- return true;
-}
-
-static bool xive_check_vpc_update(struct xive *x, uint32_t idx, struct xive_vp *vp)
-{
- struct xive_vp *vp_p = xive_get_vp(x, idx);
- struct xive_vp vp2;
-
- assert(vp_p);
- vp2 = *vp_p;
- if (memcmp(vp, &vp2, sizeof(vp)) != 0) {
- xive_err(x, "VP update mismatch idx %d\n", idx);
- xive_err(x, "want: %08x %08x %08x %08x\n",
- vp->w0, vp->w1, vp->w2, vp->w3);
- xive_err(x, " %08x %08x %08x %08x\n",
- vp->w4, vp->w5, vp->w6, vp->w7);
- xive_err(x, "got : %08x %08x %08x %08x\n",
- vp2.w0, vp2.w1, vp2.w2, vp2.w3);
- xive_err(x, " %08x %08x %08x %08x\n",
- vp2.w4, vp2.w5, vp2.w6, vp2.w7);
- return false;
- }
- return true;
-}
-#else
-static inline bool xive_check_eq_update(struct xive *x __unused,
- uint32_t idx __unused,
- struct xive_eq *eq __unused)
-{
- return true;
-}
-
-static inline bool xive_check_vpc_update(struct xive *x __unused,
- uint32_t idx __unused,
- struct xive_vp *vp __unused)
-{
- return true;
-}
-#endif
-
-#ifdef XIVE_EXTRA_CHECK_INIT_CACHE
-static void xive_special_cache_check(struct xive *x, uint32_t blk, uint32_t idx)
-{
- struct xive_vp vp = {0};
- uint32_t i;
-
- for (i = 0; i < 1000; i++) {
- struct xive_vp *vp_m = xive_get_vp(x, idx);
-
- memset(vp_m, (~i) & 0xff, sizeof(*vp_m));
- sync();
- vp.w1 = (i << 16) | i;
- xive_vpc_cache_update(x, blk, idx,
- 0, 8, &vp, false, true);
- if (!xive_check_vpc_update(x, idx, &vp)) {
- xive_dbg(x, "Test failed at %d iterations\n", i);
- return;
- }
- }
- xive_dbg(x, "1000 iterations test success at %d/0x%x\n", blk, idx);
-}
-#else
-static inline void xive_special_cache_check(struct xive *x __unused,
- uint32_t blk __unused,
- uint32_t idx __unused)
-{
-}
-#endif
-
-static void xive_setup_hw_for_emu(struct xive_cpu_state *xs)
-{
- struct xive_eq eq;
- struct xive_vp vp;
- struct xive *x_eq, *x_vp;
-
- /* Grab the XIVE where the VP resides. It could be different from
- * the local chip XIVE if not using block group mode
- */
- x_vp = xive_from_pc_blk(xs->vp_blk);
- assert(x_vp);
-
- /* Grab the XIVE where the EQ resides. It will be the same as the
- * VP one with the current provisioning but I prefer not making
- * this code depend on it.
- */
- x_eq = xive_from_vc_blk(xs->eq_blk);
- assert(x_eq);
-
- /* Initialize the structure */
- xive_init_emu_eq(xs->vp_blk, xs->vp_idx, &eq,
- xs->eq_page, XIVE_EMULATION_PRIO);
-
- /* Use the cache watch to write it out */
- lock(&x_eq->lock);
- xive_eqc_cache_update(x_eq, xs->eq_blk,
- xs->eq_idx + XIVE_EMULATION_PRIO,
- 0, 4, &eq, false, true);
- xive_check_eq_update(x_eq, xs->eq_idx + XIVE_EMULATION_PRIO, &eq);
-
- /* Extra testing of cache watch & scrub facilities */
- xive_special_cache_check(x_vp, xs->vp_blk, xs->vp_idx);
- unlock(&x_eq->lock);
-
- /* Initialize/enable the VP */
- xive_init_default_vp(&vp, xs->eq_blk, xs->eq_idx);
-
- /* Use the cache watch to write it out */
- lock(&x_vp->lock);
- xive_vpc_cache_update(x_vp, xs->vp_blk, xs->vp_idx,
- 0, 8, &vp, false, true);
- xive_check_vpc_update(x_vp, xs->vp_idx, &vp);
- unlock(&x_vp->lock);
-}
-
-static void xive_init_cpu_emulation(struct xive_cpu_state *xs,
- struct cpu_thread *cpu)
-{
- struct xive *x;
-
- /* Setup HW EQ and VP */
- xive_setup_hw_for_emu(xs);
-
- /* Setup and unmask the IPI */
- xive_ipi_init(xs->xive, cpu);
-
- /* Initialize remaining state */
- xs->cppr = 0;
- xs->mfrr = 0xff;
- xs->eqbuf = xive_get_eq_buf(xs->vp_blk,
- xs->eq_idx + XIVE_EMULATION_PRIO);
- assert(xs->eqbuf);
- memset(xs->eqbuf, 0, 0x10000);
-
- xs->eqptr = 0;
- xs->eqmsk = (0x10000/4) - 1;
- xs->eqgen = 0;
- x = xive_from_vc_blk(xs->eq_blk);
- assert(x);
- xs->eqmmio = x->eq_mmio + (xs->eq_idx + XIVE_EMULATION_PRIO) * 0x20000;
-}
static void xive_init_cpu_exploitation(struct xive_cpu_state *xs)
{
@@ -2928,15 +2656,6 @@ static void xive_init_cpu_exploitation(struct xive_cpu_state *xs)
xive_vpc_cache_update(x_vp, xs->vp_blk, xs->vp_idx,
0, 8, &vp, false, true);
unlock(&x_vp->lock);
-
- /* Clenaup remaining state */
- xs->cppr = 0;
- xs->mfrr = 0xff;
- xs->eqbuf = NULL;
- xs->eqptr = 0;
- xs->eqmsk = 0;
- xs->eqgen = 0;
- xs->eqmmio = NULL;
}
static void xive_configure_ex_special_bar(struct xive *x, struct cpu_thread *c)
@@ -2989,7 +2708,6 @@ static void xive_p9_late_init(void)
static void xive_provision_cpu(struct xive_cpu_state *xs, struct cpu_thread *c)
{
struct xive *x;
- void *p;
/* Physical VPs are pre-allocated */
xs->vp_blk = PIR2VP_BLK(c->pir);
@@ -3009,16 +2727,6 @@ static void xive_provision_cpu(struct xive_cpu_state *xs, struct cpu_thread *c)
/* Allocate a set of EQs for that VP */
xs->eq_idx = xive_alloc_eq_set(x, true);
assert(!XIVE_ALLOC_IS_ERR(xs->eq_idx));
-
- /* Provision one of the queues. Allocate the memory on the
- * chip where the CPU resides
- */
- p = local_alloc(c->chip_id, 0x10000, 0x10000);
- if (!p) {
- xive_err(x, "Failed to allocate EQ backing store\n");
- assert(false);
- }
- xs->eq_page = p;
}
static void xive_init_cpu(struct cpu_thread *c)
@@ -3053,549 +2761,8 @@ static void xive_init_cpu(struct cpu_thread *c)
/* Shortcut to TM HV ring */
xs->tm_ring1 = x->tm_base + (1u << x->tm_shift);
- /* Allocate an IPI */
- xs->ipi_irq = xive_alloc_ipi_irqs(c->chip_id, 1, 1);
-
- xive_cpu_vdbg(c, "CPU IPI is irq %08x\n", xs->ipi_irq);
-
/* Provision a VP and some EQDs for a physical CPU */
xive_provision_cpu(xs, c);
-
- /* Initialize the XICS emulation related fields */
- xive_init_cpu_emulation(xs, c);
-}
-
-static void xive_init_cpu_properties(struct cpu_thread *cpu)
-{
- struct cpu_thread *t;
- uint32_t iprop[8][2] = { };
- uint32_t i;
-
- assert(cpu_thread_count <= 8);
-
- if (!cpu->node)
- return;
- for (i = 0; i < cpu_thread_count; i++) {
- t = (i == 0) ? cpu : find_cpu_by_pir(cpu->pir + i);
- if (!t)
- continue;
- iprop[i][0] = t->xstate->ipi_irq;
- iprop[i][1] = 0; /* Edge */
- }
- dt_add_property(cpu->node, "interrupts", iprop, cpu_thread_count * 8);
- dt_add_property_cells(cpu->node, "interrupt-parent", get_ics_phandle());
-}
-
-#ifdef XIVE_DEBUG_DUPLICATES
-static uint32_t xive_count_irq_copies(struct xive_cpu_state *xs, uint32_t ref)
-{
- uint32_t i, irq;
- uint32_t cnt = 0;
- uint32_t pos = xs->eqptr;
- uint32_t gen = xs->eqgen;
-
- for (i = 0; i < 0x3fff; i++) {
- irq = xs->eqbuf[pos];
- if ((irq >> 31) == gen)
- break;
- if (irq == ref)
- cnt++;
- pos = (pos + 1) & xs->eqmsk;
- if (!pos)
- gen ^= 1;
- }
- return cnt;
-}
-#else
-static inline uint32_t xive_count_irq_copies(struct xive_cpu_state *xs __unused,
- uint32_t ref __unused)
-{
- return 1;
-}
-#endif
-
-static uint32_t xive_read_eq(struct xive_cpu_state *xs, bool just_peek)
-{
- uint32_t cur, copies;
-
- xive_cpu_vdbg(this_cpu(), " EQ %s... IDX=%x MSK=%x G=%d\n",
- just_peek ? "peek" : "read",
- xs->eqptr, xs->eqmsk, xs->eqgen);
- cur = xs->eqbuf[xs->eqptr];
- xive_cpu_vdbg(this_cpu(), " cur: %08x [%08x %08x %08x ...]\n", cur,
- xs->eqbuf[(xs->eqptr + 1) & xs->eqmsk],
- xs->eqbuf[(xs->eqptr + 2) & xs->eqmsk],
- xs->eqbuf[(xs->eqptr + 3) & xs->eqmsk]);
- if ((cur >> 31) == xs->eqgen)
- return 0;
-
- /* Debug: check for duplicate interrupts in the queue */
- copies = xive_count_irq_copies(xs, cur);
- if (copies > 1) {
- struct xive_eq *eq;
-
- prerror("Wow ! Dups of irq %x, found %d copies !\n",
- cur & 0x7fffffff, copies);
- prerror("[%08x > %08x %08x %08x %08x ...] eqgen=%x eqptr=%x jp=%d\n",
- xs->eqbuf[(xs->eqptr - 1) & xs->eqmsk],
- xs->eqbuf[(xs->eqptr + 0) & xs->eqmsk],
- xs->eqbuf[(xs->eqptr + 1) & xs->eqmsk],
- xs->eqbuf[(xs->eqptr + 2) & xs->eqmsk],
- xs->eqbuf[(xs->eqptr + 3) & xs->eqmsk],
- xs->eqgen, xs->eqptr, just_peek);
- lock(&xs->xive->lock);
- __xive_cache_scrub(xs->xive, xive_cache_eqc, xs->eq_blk,
- xs->eq_idx + XIVE_EMULATION_PRIO,
- false, false);
- unlock(&xs->xive->lock);
- eq = xive_get_eq(xs->xive, xs->eq_idx + XIVE_EMULATION_PRIO);
- prerror("EQ @%p W0=%08x W1=%08x qbuf @%p\n",
- eq, eq->w0, eq->w1, xs->eqbuf);
- }
- log_add(xs, LOG_TYPE_POPQ, 7, cur,
- xs->eqbuf[(xs->eqptr + 1) & xs->eqmsk],
- xs->eqbuf[(xs->eqptr + 2) & xs->eqmsk],
- copies,
- xs->eqptr, xs->eqgen, just_peek);
- if (!just_peek) {
- xs->eqptr = (xs->eqptr + 1) & xs->eqmsk;
- if (xs->eqptr == 0)
- xs->eqgen ^= 1;
- xs->total_irqs++;
- }
- return cur & 0x00ffffff;
-}
-
-static uint8_t xive_sanitize_cppr(uint8_t cppr)
-{
- if (cppr == 0xff || cppr == 0)
- return cppr;
- else
- return XIVE_EMULATION_PRIO;
-}
-
-static inline uint8_t opal_xive_check_pending(struct xive_cpu_state *xs,
- uint8_t cppr)
-{
- uint8_t mask = (cppr > 7) ? 0xff : ~((0x100 >> cppr) - 1);
-
- return xs->pending & mask;
-}
-
-static void opal_xive_update_cppr(struct xive_cpu_state *xs, u8 cppr)
-{
- /* Peform the update */
- xs->cppr = cppr;
- out_8(xs->tm_ring1 + TM_QW3_HV_PHYS + TM_CPPR, cppr);
-
- /* Trigger the IPI if it's still more favored than the CPPR
- *
- * This can lead to a bunch of spurrious retriggers if the
- * IPI is queued up behind other interrupts but that's not
- * a big deal and keeps the code simpler
- */
- if (xs->mfrr < cppr)
- xive_ipi_trigger(xs->xive, GIRQ_TO_IDX(xs->ipi_irq));
-}
-
-static int64_t opal_xive_eoi(uint32_t xirr)
-{
- struct cpu_thread *c = this_cpu();
- struct xive_cpu_state *xs = c->xstate;
- uint32_t isn = xirr & 0x00ffffff;
- struct xive *src_x;
- bool special_ipi = false;
- uint8_t cppr;
-
- /*
- * In exploitation mode, this is supported as a way to perform
- * an EOI via a FW calls. This can be needed to workaround HW
- * implementation bugs for example. In this case interrupts will
- * have the OPAL_XIVE_IRQ_EOI_VIA_FW flag set.
- *
- * In that mode the entire "xirr" argument is interpreterd as
- * a global IRQ number (including the escalation bit), ther is
- * no split between the top 8 bits for CPPR and bottom 24 for
- * the interrupt number.
- */
- if (xive_mode != XIVE_MODE_EMU)
- return irq_source_eoi(xirr) ? OPAL_SUCCESS : OPAL_PARAMETER;
-
- if (!xs)
- return OPAL_INTERNAL_ERROR;
-
- xive_cpu_vdbg(c, "EOI xirr=%08x cur_cppr=%d\n", xirr, xs->cppr);
-
- /* Limit supported CPPR values from OS */
- cppr = xive_sanitize_cppr(xirr >> 24);
-
- lock(&xs->lock);
-
- log_add(xs, LOG_TYPE_EOI, 3, isn, xs->eqptr, xs->eqgen);
-
- /* If this was our magic IPI, convert to IRQ number */
- if (isn == 2) {
- isn = xs->ipi_irq;
- special_ipi = true;
- xive_cpu_vdbg(c, "User EOI for IPI !\n");
- }
-
- /* First check if we have stuff in that queue. If we do, don't bother with
- * doing an EOI on the EQ. Just mark that priority pending, we'll come
- * back later.
- *
- * If/when supporting multiple queues we would have to check them all
- * in ascending prio order up to the passed-in CPPR value (exclusive).
- */
- if (xive_read_eq(xs, true)) {
- xive_cpu_vdbg(c, " isn %08x, skip, queue non empty\n", xirr);
- xs->pending |= 1 << XIVE_EMULATION_PRIO;
- }
-#ifndef EQ_ALWAYS_NOTIFY
- else {
- uint8_t eoi_val;
-
- /* Perform EQ level EOI. Only one EQ for now ...
- *
- * Note: We aren't doing an actual EOI. Instead we are clearing
- * both P and Q and will re-check the queue if Q was set.
- */
- eoi_val = in_8(xs->eqmmio + XIVE_ESB_SET_PQ_00);
- xive_cpu_vdbg(c, " isn %08x, eoi_val=%02x\n", xirr, eoi_val);
-
- /* Q was set ? Check EQ again after doing a sync to ensure
- * ordering.
- */
- if (eoi_val & 1) {
- sync();
- if (xive_read_eq(xs, true))
- xs->pending |= 1 << XIVE_EMULATION_PRIO;
- }
- }
-#endif
-
- /* Perform source level EOI if it's not our emulated MFRR IPI
- * otherwise EOI ourselves
- */
- src_x = xive_from_isn(isn);
- if (src_x) {
- uint32_t idx = GIRQ_TO_IDX(isn);
-
- /* Is it an IPI ? */
- if (special_ipi) {
- xive_ipi_eoi(src_x, idx);
- } else {
- /* Otherwise go through the source mechanism */
- xive_vdbg(src_x, "EOI of IDX %x in EXT range\n", idx);
- irq_source_eoi(isn);
- }
- } else {
- xive_cpu_err(c, " EOI unknown ISN %08x\n", isn);
- }
-
- /* Finally restore CPPR */
- opal_xive_update_cppr(xs, cppr);
-
- xive_cpu_vdbg(c, " pending=0x%x cppr=%d\n", xs->pending, cppr);
-
- unlock(&xs->lock);
-
- /* Return whether something is pending that is suitable for
- * delivery considering the new CPPR value. This can be done
- * without lock as these fields are per-cpu.
- */
- return opal_xive_check_pending(xs, cppr) ? 1 : 0;
-}
-
-#ifdef XIVE_CHECK_MISROUTED_IPI
-static void xive_dump_eq(uint32_t eq_blk, uint32_t eq_idx)
-{
- struct cpu_thread *me = this_cpu();
- struct xive *x;
- struct xive_eq *eq;
-
- x = xive_from_vc_blk(eq_blk);
- if (!x)
- return;
- eq = xive_get_eq(x, eq_idx);
- if (!eq)
- return;
- xive_cpu_err(me, "EQ: %08x %08x %08x %08x (@%p)\n",
- eq->w0, eq->w1, eq->w2, eq->w3, eq);
- xive_cpu_err(me, " %08x %08x %08x %08x\n",
- eq->w4, eq->w5, eq->w6, eq->w7);
-}
-static int64_t __opal_xive_dump_emu(struct xive_cpu_state *xs, uint32_t pir);
-
-static bool check_misrouted_ipi(struct cpu_thread *me, uint32_t irq)
-{
- struct cpu_thread *c;
-
- for_each_present_cpu(c) {
- struct xive_cpu_state *xs = c->xstate;
- struct xive_ive *ive;
- uint32_t ipi_target, i, eq_blk, eq_idx;
- struct proc_chip *chip;
- struct xive *x;
-
- if (!xs)
- continue;
- if (irq == xs->ipi_irq) {
- xive_cpu_err(me, "misrouted IPI 0x%x, should"
- " be aimed at CPU 0x%x\n",
- irq, c->pir);
- xive_cpu_err(me, " my eq_page=%p eqbuff=%p eq=0x%x/%x\n",
- me->xstate->eq_page, me->xstate->eqbuf,
- me->xstate->eq_blk, me->xstate->eq_idx + XIVE_EMULATION_PRIO);
- xive_cpu_err(me, "tgt eq_page=%p eqbuff=%p eq=0x%x/%x\n",
- c->xstate->eq_page, c->xstate->eqbuf,
- c->xstate->eq_blk, c->xstate->eq_idx + XIVE_EMULATION_PRIO);
- __opal_xive_dump_emu(me->xstate, me->pir);
- __opal_xive_dump_emu(c->xstate, c->pir);
- if (xive_get_irq_targetting(xs->ipi_irq, &ipi_target, NULL, NULL))
- xive_cpu_err(me, "target=%08x\n", ipi_target);
- else
- xive_cpu_err(me, "target=???\n");
- /* Find XIVE on which the IVE resides */
- x = xive_from_isn(irq);
- if (!x) {
- xive_cpu_err(me, "no xive attached\n");
- return true;
- }
- ive = xive_get_ive(x, irq);
- if (!ive) {
- xive_cpu_err(me, "no ive attached\n");
- return true;
- }
- xive_cpu_err(me, "ive=%016llx\n", ive->w);
- for_each_chip(chip) {
- x = chip->xive;
- if (!x)
- continue;
- ive = x->ivt_base;
- for (i = 0; i < MAX_INT_ENTRIES; i++) {
- if ((ive[i].w & IVE_EQ_DATA) == irq) {
- eq_blk = GETFIELD(IVE_EQ_BLOCK, ive[i].w);
- eq_idx = GETFIELD(IVE_EQ_INDEX, ive[i].w);
- xive_cpu_err(me, "Found source: 0x%x ive=%016llx\n"
- " eq 0x%x/%x",
- BLKIDX_TO_GIRQ(x->block_id, i),
- ive[i].w, eq_blk, eq_idx);
- xive_dump_eq(eq_blk, eq_idx);
- }
- }
- }
- return true;
- }
- }
- return false;
-}
-#else
-static inline bool check_misrouted_ipi(struct cpu_thread *c __unused,
- uint32_t irq __unused)
-{
- return false;
-}
-#endif
-
-static int64_t opal_xive_get_xirr(uint32_t *out_xirr, bool just_poll)
-{
- struct cpu_thread *c = this_cpu();
- struct xive_cpu_state *xs = c->xstate;
- uint16_t ack;
- uint8_t active, old_cppr;
-
- if (xive_mode != XIVE_MODE_EMU)
- return OPAL_WRONG_STATE;
- if (!xs)
- return OPAL_INTERNAL_ERROR;
- if (!out_xirr)
- return OPAL_PARAMETER;
-
- *out_xirr = 0;
-
- lock(&xs->lock);
-
- /*
- * Due to the need to fetch multiple interrupts from the EQ, we
- * need to play some tricks.
- *
- * The "pending" byte in "xs" keeps track of the priorities that
- * are known to have stuff to read (currently we only use one).
- *
- * It is set in EOI and cleared when consumed here. We don't bother
- * looking ahead here, EOI will do it.
- *
- * We do need to still do an ACK every time in case a higher prio
- * exception occurred (though we don't do prio yet... right ? still
- * let's get the basic design right !).
- *
- * Note that if we haven't found anything via ack, but did find
- * something in the queue, we must also raise CPPR back.
- */
-
- xive_cpu_vdbg(c, "get_xirr W01=%016llx W2=%08x\n",
- __in_be64(xs->tm_ring1 + TM_QW3_HV_PHYS),
- __in_be32(xs->tm_ring1 + TM_QW3_HV_PHYS + 8));
-
- /* Perform the HV Ack cycle */
- if (just_poll)
- ack = __in_be64(xs->tm_ring1 + TM_QW3_HV_PHYS) >> 48;
- else
- ack = __in_be16(xs->tm_ring1 + TM_SPC_ACK_HV_REG);
- sync();
- xive_cpu_vdbg(c, "get_xirr,%s=%04x\n", just_poll ? "POLL" : "ACK", ack);
-
- /* Capture the old CPPR which we will return with the interrupt */
- old_cppr = xs->cppr;
-
- switch(GETFIELD(TM_QW3_NSR_HE, (ack >> 8))) {
- case TM_QW3_NSR_HE_NONE:
- break;
- case TM_QW3_NSR_HE_POOL:
- break;
- case TM_QW3_NSR_HE_PHYS:
- /* Mark pending and keep track of the CPPR update */
- if (!just_poll && (ack & 0xff) != 0xff) {
- xs->cppr = ack & 0xff;
- xs->pending |= 1 << xs->cppr;
- }
- break;
- case TM_QW3_NSR_HE_LSI:
- break;
- }
-
- /* Calculate "active" lines as being the pending interrupts
- * masked by the "old" CPPR
- */
- active = opal_xive_check_pending(xs, old_cppr);
-
- log_add(xs, LOG_TYPE_XIRR, 6, old_cppr, xs->cppr, xs->pending, active,
- xs->eqptr, xs->eqgen);
-
-#ifdef XIVE_PERCPU_LOG
- {
- struct xive_eq *eq;
- lock(&xs->xive->lock);
- __xive_cache_scrub(xs->xive, xive_cache_eqc, xs->eq_blk,
- xs->eq_idx + XIVE_EMULATION_PRIO,
- false, false);
- unlock(&xs->xive->lock);
- eq = xive_get_eq(xs->xive, xs->eq_idx + XIVE_EMULATION_PRIO);
- log_add(xs, LOG_TYPE_EQD, 2, eq->w0, eq->w1);
- }
-#endif /* XIVE_PERCPU_LOG */
-
- xive_cpu_vdbg(c, " cppr=%d->%d pending=0x%x active=%x\n",
- old_cppr, xs->cppr, xs->pending, active);
- if (active) {
- /* Find highest pending */
- uint8_t prio = ffs(active) - 1;
- uint32_t val;
-
- /* XXX Use "p" to select queue */
- val = xive_read_eq(xs, just_poll);
-
- if (val && val < XIVE_INT_FIRST)
- xive_cpu_err(c, "Bogus interrupt 0x%x received !\n", val);
-
- /* Convert to magic IPI if needed */
- if (val == xs->ipi_irq)
- val = 2;
- if (check_misrouted_ipi(c, val))
- val = 2;
-
- *out_xirr = (old_cppr << 24) | val;
-
- /* If we are polling, that's it */
- if (just_poll)
- goto skip;
-
- /* Clear the pending bit. EOI will set it again if needed. We
- * could check the queue but that's not really critical here.
- */
- xs->pending &= ~(1 << prio);
-
- /* Spurrious IPB bit, nothing to fetch, bring CPPR back */
- if (!val)
- prio = old_cppr;
-
- /* We could have fetched a pending interrupt left over
- * by a previous EOI, so the CPPR might need adjusting
- * Also if we had a spurrious one as well.
- */
- if (xs->cppr != prio) {
- xs->cppr = prio;
- out_8(xs->tm_ring1 + TM_QW3_HV_PHYS + TM_CPPR, prio);
- xive_cpu_vdbg(c, " adjusted CPPR to %d\n", prio);
- }
-
- if (val)
- xive_cpu_vdbg(c, " found irq, prio=%d\n", prio);
-
- } else {
- /* Nothing was active, this is a fluke, restore CPPR */
- opal_xive_update_cppr(xs, old_cppr);
- xive_cpu_vdbg(c, " nothing active, restored CPPR to %d\n",
- old_cppr);
- }
- skip:
-
- log_add(xs, LOG_TYPE_XIRR2, 5, xs->cppr, xs->pending,
- *out_xirr, xs->eqptr, xs->eqgen);
- xive_cpu_vdbg(c, " returning XIRR=%08x, pending=0x%x\n",
- *out_xirr, xs->pending);
-
- unlock(&xs->lock);
-
- return OPAL_SUCCESS;
-}
-
-static int64_t opal_xive_set_cppr(uint8_t cppr)
-{
- struct cpu_thread *c = this_cpu();
- struct xive_cpu_state *xs = c->xstate;
-
- if (xive_mode != XIVE_MODE_EMU)
- return OPAL_WRONG_STATE;
-
- /* Limit supported CPPR values */
- cppr = xive_sanitize_cppr(cppr);
-
- if (!xs)
- return OPAL_INTERNAL_ERROR;
- xive_cpu_vdbg(c, "CPPR setting to %d\n", cppr);
-
- lock(&xs->lock);
- opal_xive_update_cppr(xs, cppr);
- unlock(&xs->lock);
-
- return OPAL_SUCCESS;
-}
-
-static int64_t opal_xive_set_mfrr(uint32_t cpu, uint8_t mfrr)
-{
- struct cpu_thread *c = find_cpu_by_server(cpu);
- struct xive_cpu_state *xs;
- uint8_t old_mfrr;
-
- if (xive_mode != XIVE_MODE_EMU)
- return OPAL_WRONG_STATE;
- if (!c)
- return OPAL_PARAMETER;
- xs = c->xstate;
- if (!xs)
- return OPAL_INTERNAL_ERROR;
-
- lock(&xs->lock);
- old_mfrr = xs->mfrr;
- xive_cpu_vdbg(c, " Setting MFRR to %x, old is %x\n", mfrr, old_mfrr);
- xs->mfrr = mfrr;
- if (old_mfrr > mfrr && mfrr < xs->cppr)
- xive_ipi_trigger(xs->xive, GIRQ_TO_IDX(xs->ipi_irq));
- unlock(&xs->lock);
-
- return OPAL_SUCCESS;
}
static uint64_t xive_convert_irq_flags(uint64_t iflags)
@@ -4474,17 +3641,14 @@ static void xive_reset_one(struct xive *x)
/* The rest must not be called with the lock held */
unlock(&x->lock);
- /* Re-configure VPs and emulation */
+ /* Re-configure VPs */
for_each_present_cpu(c) {
struct xive_cpu_state *xs = c->xstate;
if (c->chip_id != x->chip_id || !xs)
continue;
- if (xive_mode == XIVE_MODE_EMU)
- xive_init_cpu_emulation(xs, c);
- else
- xive_init_cpu_exploitation(xs);
+ xive_init_cpu_exploitation(xs);
}
}
@@ -4521,7 +3685,6 @@ static void xive_p9_cpu_reset(void)
struct cpu_thread *c = this_cpu();
struct xive_cpu_state *xs = c->xstate;
- xs->cppr = 0;
out_8(xs->tm_ring1 + TM_QW3_HV_PHYS + TM_CPPR, 0);
in_be64(xs->tm_ring1 + TM_SPC_PULL_POOL_CTX);
@@ -4568,7 +3731,7 @@ static int64_t xive_p9_reset(void)
{
if (xive_mode == XIVE_MODE_NONE)
return OPAL_SUCCESS;
- return __xive_reset(XIVE_MODE_EMU);
+ return __xive_reset(XIVE_MODE_EXPL);
}
static int64_t opal_xive_reset(uint64_t version)
@@ -4941,71 +4104,6 @@ static int64_t opal_xive_dump_vp(uint32_t vp_id)
return OPAL_SUCCESS;
}
-static int64_t __opal_xive_dump_emu(struct xive_cpu_state *xs, uint32_t pir)
-{
- struct xive_eq *eq;
- uint32_t ipi_target;
- uint8_t *mm, pq;
-
- prlog(PR_INFO, "CPU[%04x]: XIVE emulation state\n", pir);
-
- prlog(PR_INFO, "CPU[%04x]: cppr=%02x mfrr=%02x pend=%02x"
- " prev_cppr=%02x total_irqs=%llx\n", pir,
- xs->cppr, xs->mfrr, xs->pending, xs->prev_cppr, xs->total_irqs);
-
- prlog(PR_INFO, "CPU[%04x]: EQ IDX=%x MSK=%x G=%d [%08x %08x %08x > %08x %08x %08x %08x ...]\n",
- pir, xs->eqptr, xs->eqmsk, xs->eqgen,
- xs->eqbuf[(xs->eqptr - 3) & xs->eqmsk],
- xs->eqbuf[(xs->eqptr - 2) & xs->eqmsk],
- xs->eqbuf[(xs->eqptr - 1) & xs->eqmsk],
- xs->eqbuf[(xs->eqptr + 0) & xs->eqmsk],
- xs->eqbuf[(xs->eqptr + 1) & xs->eqmsk],
- xs->eqbuf[(xs->eqptr + 2) & xs->eqmsk],
- xs->eqbuf[(xs->eqptr + 3) & xs->eqmsk]);
-
- mm = xs->xive->esb_mmio + GIRQ_TO_IDX(xs->ipi_irq) * 0x20000;
- pq = in_8(mm + 0x10800);
- if (xive_get_irq_targetting(xs->ipi_irq, &ipi_target, NULL, NULL))
- prlog(PR_INFO, "CPU[%04x]: IPI #%08x PQ=%x target=%08x\n",
- pir, xs->ipi_irq, pq, ipi_target);
- else
- prlog(PR_INFO, "CPU[%04x]: IPI #%08x PQ=%x target=??\n",
- pir, xs->ipi_irq, pq);
-
-
-
- __xive_cache_scrub(xs->xive, xive_cache_eqc, xs->eq_blk,
- xs->eq_idx + XIVE_EMULATION_PRIO,
- false, false);
- eq = xive_get_eq(xs->xive, xs->eq_idx + XIVE_EMULATION_PRIO);
- prlog(PR_INFO, "CPU[%04x]: EQ @%p W0=%08x W1=%08x qbuf @%p\n",
- pir, eq, eq->w0, eq->w1, xs->eqbuf);
-
- return OPAL_SUCCESS;
-}
-
-static int64_t opal_xive_dump_emu(uint32_t pir)
-{
- struct cpu_thread *c = find_cpu_by_pir(pir);
- struct xive_cpu_state *xs;
- int64_t rc;
-
- if (!c)
- return OPAL_PARAMETER;
-
- xs = c->xstate;
- if (!xs) {
- prlog(PR_INFO, " <none>\n");
- return OPAL_SUCCESS;
- }
- lock(&xs->lock);
- rc = __opal_xive_dump_emu(xs, pir);
- log_print(xs);
- unlock(&xs->lock);
-
- return rc;
-}
-
static int64_t opal_xive_sync_irq_src(uint32_t girq)
{
struct xive *x = xive_from_isn(girq);
@@ -5061,8 +4159,6 @@ static int64_t opal_xive_dump(uint32_t type, uint32_t id)
return opal_xive_dump_tm(TM_QW0_USER, "USER", id);
case XIVE_DUMP_VP:
return opal_xive_dump_vp(id);
- case XIVE_DUMP_EMU_STATE:
- return opal_xive_dump_emu(id);
default:
return OPAL_PARAMETER;
}
@@ -5101,7 +4197,7 @@ static void xive_p9_init(const char *compat)
if (first)
return;
- xive_mode = XIVE_MODE_EMU;
+ xive_mode = XIVE_MODE_EXPL;
/* Init VP allocator */
xive_init_vp_allocator();
@@ -5117,25 +4213,14 @@ static void xive_p9_init(const char *compat)
late_init_one_xive(chip->xive);
}
- /* Initialize XICS emulation per-cpu structures */
+ /* Initialize per-cpu structures */
for_each_present_cpu(cpu) {
xive_init_cpu(cpu);
}
- /* Add interrupts propertie to each CPU node */
- for_each_present_cpu(cpu) {
- if (cpu_is_thread0(cpu))
- xive_init_cpu_properties(cpu);
- }
/* Calling boot CPU */
xive_cpu_callin(this_cpu());
- /* Register XICS emulation calls */
- opal_register(OPAL_INT_GET_XIRR, opal_xive_get_xirr, 2);
- opal_register(OPAL_INT_SET_CPPR, opal_xive_set_cppr, 1);
- opal_register(OPAL_INT_EOI, opal_xive_eoi, 1);
- opal_register(OPAL_INT_SET_MFRR, opal_xive_set_mfrr, 2);
-
/* Register XIVE exploitation calls */
opal_register(OPAL_XIVE_RESET, opal_xive_reset, 1);
opal_register(OPAL_XIVE_GET_IRQ_INFO, opal_xive_get_irq_info, 6);
--
2.21.0
More information about the Skiboot
mailing list