| From c7870159cd46c4dfb80576e28d3f128d5792eda6 Mon Sep 17 00:00:00 2001 |
| From: Frederic Barrat <fbarrat@linux.ibm.com> |
| Date: Mon, 13 Jan 2020 14:01:18 +0100 |
| Subject: [PATCH] powerpc/xive: Discard ESB load value when interrupt is |
| invalid |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| commit 17328f218fb760c9c6accc5b52494889243a6b98 upstream. |
| |
| A load on an ESB page returning all 1's means that the underlying |
| device has invalidated the access to the PQ state of the interrupt |
| through mmio. It may happen, for example when querying a PHB interrupt |
| while the PHB is in an error state. |
| |
| In that case, we should consider the interrupt to be invalid when |
| checking its state in the irq_get_irqchip_state() handler. |
| |
| Fixes: da15c03b047d ("powerpc/xive: Implement get_irqchip_state method for XIVE to fix shutdown race") |
| Cc: stable@vger.kernel.org # v5.4+ |
| Signed-off-by: Frederic Barrat <fbarrat@linux.ibm.com> |
| [clg: wrote a commit log, introduced XIVE_ESB_INVALID ] |
| Signed-off-by: Cédric Le Goater <clg@kaod.org> |
| Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> |
| Link: https://lore.kernel.org/r/20200113130118.27969-1-clg@kaod.org |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/arch/powerpc/include/asm/xive-regs.h b/arch/powerpc/include/asm/xive-regs.h |
| index f2dfcd50a2d3..33aee7490cbb 100644 |
| --- a/arch/powerpc/include/asm/xive-regs.h |
| +++ b/arch/powerpc/include/asm/xive-regs.h |
| @@ -39,6 +39,7 @@ |
| |
| #define XIVE_ESB_VAL_P 0x2 |
| #define XIVE_ESB_VAL_Q 0x1 |
| +#define XIVE_ESB_INVALID 0xFF |
| |
| /* |
| * Thread Management (aka "TM") registers |
| diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c |
| index 723db3ceeaa8..c1d871d50a23 100644 |
| --- a/arch/powerpc/sysdev/xive/common.c |
| +++ b/arch/powerpc/sysdev/xive/common.c |
| @@ -937,12 +937,21 @@ static int xive_get_irqchip_state(struct irq_data *data, |
| enum irqchip_irq_state which, bool *state) |
| { |
| struct xive_irq_data *xd = irq_data_get_irq_handler_data(data); |
| + u8 pq; |
| |
| switch (which) { |
| case IRQCHIP_STATE_ACTIVE: |
| - *state = !xd->stale_p && |
| - (xd->saved_p || |
| - !!(xive_esb_read(xd, XIVE_ESB_GET) & XIVE_ESB_VAL_P)); |
| + pq = xive_esb_read(xd, XIVE_ESB_GET); |
| + |
| + /* |
| + * The esb value being all 1's means we couldn't get |
| + * the PQ state of the interrupt through mmio. It may |
| + * happen, for example when querying a PHB interrupt |
| + * while the PHB is in an error state. We consider the |
| + * interrupt to be inactive in that case. |
| + */ |
| + *state = (pq != XIVE_ESB_INVALID) && !xd->stale_p && |
| + (xd->saved_p || !!(pq & XIVE_ESB_VAL_P)); |
| return 0; |
| default: |
| return -EINVAL; |
| -- |
| 2.7.4 |
| |