From patchwork Tue Sep 3 17:04:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?C=C3=A9dric_Le_Goater?= X-Patchwork-Id: 1157193 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46NDpb4ZBxz9sDB for ; Wed, 4 Sep 2019 03:44:07 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=kaod.org Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 46NDpb3C2ZzDqlc for ; Wed, 4 Sep 2019 03:44:07 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=kaod.org (client-ip=87.98.172.162; helo=18.mo3.mail-out.ovh.net; envelope-from=clg@kaod.org; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=kaod.org Received: from 18.mo3.mail-out.ovh.net (18.mo3.mail-out.ovh.net [87.98.172.162]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 46NDpQ2rfwzDqm6 for ; Wed, 4 Sep 2019 03:43:55 +1000 (AEST) Received: from player779.ha.ovh.net (unknown [10.108.57.43]) by mo3.mail-out.ovh.net (Postfix) with ESMTP id 679AA225BDE for ; Tue, 3 Sep 2019 19:05:30 +0200 (CEST) Received: from kaod.org (lfbn-1-2240-157.w90-76.abo.wanadoo.fr [90.76.60.157]) (Authenticated sender: clg@kaod.org) by player779.ha.ovh.net (Postfix) with ESMTPSA id 7DC4E94D0246; Tue, 3 Sep 2019 17:05:26 +0000 (UTC) From: =?utf-8?q?C=C3=A9dric_Le_Goater?= To: skiboot@lists.ozlabs.org Date: Tue, 3 Sep 2019 19:04:10 +0200 Message-Id: <20190903170413.4373-20-clg@kaod.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190903170413.4373-1-clg@kaod.org> References: <20190903170413.4373-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 11338375012823108569 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgeduvddrudejfedgjeelucetufdoteggodetrfdotffvucfrrhhofhhilhgvmecuqfggjfdpvefjgfevmfevgfenuceurghilhhouhhtmecuhedttdenucesvcftvggtihhpihgvnhhtshculddquddttddm Subject: [Skiboot] [PATCH 19/22] xive/p9: remove XICS emulation X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" This emulation was required to run pre-POWER9 linux kernels. Signed-off-by: Cédric Le Goater --- 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 #include -/* 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, " \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);