diff options
author | Cédric Le Goater <clg@kaod.org> | 2017-08-30 15:46:15 -0400 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2017-09-02 07:02:37 -0400 |
commit | bed81ee181dd6b21171cffbb80472cc5b774c24d (patch) | |
tree | 9f157198f03b7afa7ace7aa3066439055b23d79d | |
parent | c58a14a9ccf0a79bbdafc106a95c080340c00f49 (diff) |
powerpc/xive: introduce H_INT_ESB hcall
The H_INT_ESB hcall() is used to issue a load or store to the ESB page
instead of using the MMIO pages. This can be used as a workaround on
some HW issues. The OS knows that this hcall should be used on an
interrupt source when the ESB hcall flag is set to 1 in the hcall
H_INT_GET_SOURCE_INFO.
To maintain the frontier between the xive frontend and backend, we
introduce a new xive operation 'esb_rw' to be used in the routines
doing memory accesses on the ESBs.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r-- | arch/powerpc/include/asm/xive.h | 1 | ||||
-rw-r--r-- | arch/powerpc/sysdev/xive/common.c | 10 | ||||
-rw-r--r-- | arch/powerpc/sysdev/xive/spapr.c | 44 | ||||
-rw-r--r-- | arch/powerpc/sysdev/xive/xive-internal.h | 1 |
4 files changed, 53 insertions, 3 deletions
diff --git a/arch/powerpc/include/asm/xive.h b/arch/powerpc/include/asm/xive.h index 64ec9bbcf03e..371fbebf1ec9 100644 --- a/arch/powerpc/include/asm/xive.h +++ b/arch/powerpc/include/asm/xive.h | |||
@@ -56,6 +56,7 @@ struct xive_irq_data { | |||
56 | #define XIVE_IRQ_FLAG_SHIFT_BUG 0x04 | 56 | #define XIVE_IRQ_FLAG_SHIFT_BUG 0x04 |
57 | #define XIVE_IRQ_FLAG_MASK_FW 0x08 | 57 | #define XIVE_IRQ_FLAG_MASK_FW 0x08 |
58 | #define XIVE_IRQ_FLAG_EOI_FW 0x10 | 58 | #define XIVE_IRQ_FLAG_EOI_FW 0x10 |
59 | #define XIVE_IRQ_FLAG_H_INT_ESB 0x20 | ||
59 | 60 | ||
60 | #define XIVE_INVALID_CHIP_ID -1 | 61 | #define XIVE_INVALID_CHIP_ID -1 |
61 | 62 | ||
diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c index 9ac9626c0fa6..7014ca6da4f6 100644 --- a/arch/powerpc/sysdev/xive/common.c +++ b/arch/powerpc/sysdev/xive/common.c | |||
@@ -198,7 +198,10 @@ static notrace u8 xive_esb_read(struct xive_irq_data *xd, u32 offset) | |||
198 | if (xd->flags & XIVE_IRQ_FLAG_SHIFT_BUG) | 198 | if (xd->flags & XIVE_IRQ_FLAG_SHIFT_BUG) |
199 | offset |= offset << 4; | 199 | offset |= offset << 4; |
200 | 200 | ||
201 | val = in_be64(xd->eoi_mmio + offset); | 201 | if ((xd->flags & XIVE_IRQ_FLAG_H_INT_ESB) && xive_ops->esb_rw) |
202 | val = xive_ops->esb_rw(xd->hw_irq, offset, 0, 0); | ||
203 | else | ||
204 | val = in_be64(xd->eoi_mmio + offset); | ||
202 | 205 | ||
203 | return (u8)val; | 206 | return (u8)val; |
204 | } | 207 | } |
@@ -209,7 +212,10 @@ static void xive_esb_write(struct xive_irq_data *xd, u32 offset, u64 data) | |||
209 | if (xd->flags & XIVE_IRQ_FLAG_SHIFT_BUG) | 212 | if (xd->flags & XIVE_IRQ_FLAG_SHIFT_BUG) |
210 | offset |= offset << 4; | 213 | offset |= offset << 4; |
211 | 214 | ||
212 | out_be64(xd->eoi_mmio + offset, data); | 215 | if ((xd->flags & XIVE_IRQ_FLAG_H_INT_ESB) && xive_ops->esb_rw) |
216 | xive_ops->esb_rw(xd->hw_irq, offset, data, 1); | ||
217 | else | ||
218 | out_be64(xd->eoi_mmio + offset, data); | ||
213 | } | 219 | } |
214 | 220 | ||
215 | #ifdef CONFIG_XMON | 221 | #ifdef CONFIG_XMON |
diff --git a/arch/powerpc/sysdev/xive/spapr.c b/arch/powerpc/sysdev/xive/spapr.c index 0fcae7504353..43e9eeb0d39f 100644 --- a/arch/powerpc/sysdev/xive/spapr.c +++ b/arch/powerpc/sysdev/xive/spapr.c | |||
@@ -224,7 +224,46 @@ static long plpar_int_sync(unsigned long flags, unsigned long lisn) | |||
224 | return 0; | 224 | return 0; |
225 | } | 225 | } |
226 | 226 | ||
227 | #define XIVE_SRC_H_INT_ESB (1ull << (63 - 60)) /* TODO */ | 227 | #define XIVE_ESB_FLAG_STORE (1ull << (63 - 63)) |
228 | |||
229 | static long plpar_int_esb(unsigned long flags, | ||
230 | unsigned long lisn, | ||
231 | unsigned long offset, | ||
232 | unsigned long in_data, | ||
233 | unsigned long *out_data) | ||
234 | { | ||
235 | unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; | ||
236 | long rc; | ||
237 | |||
238 | pr_devel("H_INT_ESB flags=%lx lisn=%lx offset=%lx in=%lx\n", | ||
239 | flags, lisn, offset, in_data); | ||
240 | |||
241 | rc = plpar_hcall(H_INT_ESB, retbuf, flags, lisn, offset, in_data); | ||
242 | if (rc) { | ||
243 | pr_err("H_INT_ESB lisn=%ld offset=%ld returned %ld\n", | ||
244 | lisn, offset, rc); | ||
245 | return rc; | ||
246 | } | ||
247 | |||
248 | *out_data = retbuf[0]; | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static u64 xive_spapr_esb_rw(u32 lisn, u32 offset, u64 data, bool write) | ||
254 | { | ||
255 | unsigned long read_data; | ||
256 | long rc; | ||
257 | |||
258 | rc = plpar_int_esb(write ? XIVE_ESB_FLAG_STORE : 0, | ||
259 | lisn, offset, data, &read_data); | ||
260 | if (rc) | ||
261 | return -1; | ||
262 | |||
263 | return write ? 0 : read_data; | ||
264 | } | ||
265 | |||
266 | #define XIVE_SRC_H_INT_ESB (1ull << (63 - 60)) | ||
228 | #define XIVE_SRC_LSI (1ull << (63 - 61)) | 267 | #define XIVE_SRC_LSI (1ull << (63 - 61)) |
229 | #define XIVE_SRC_TRIGGER (1ull << (63 - 62)) | 268 | #define XIVE_SRC_TRIGGER (1ull << (63 - 62)) |
230 | #define XIVE_SRC_STORE_EOI (1ull << (63 - 63)) | 269 | #define XIVE_SRC_STORE_EOI (1ull << (63 - 63)) |
@@ -244,6 +283,8 @@ static int xive_spapr_populate_irq_data(u32 hw_irq, struct xive_irq_data *data) | |||
244 | if (rc) | 283 | if (rc) |
245 | return -EINVAL; | 284 | return -EINVAL; |
246 | 285 | ||
286 | if (flags & XIVE_SRC_H_INT_ESB) | ||
287 | data->flags |= XIVE_IRQ_FLAG_H_INT_ESB; | ||
247 | if (flags & XIVE_SRC_STORE_EOI) | 288 | if (flags & XIVE_SRC_STORE_EOI) |
248 | data->flags |= XIVE_IRQ_FLAG_STORE_EOI; | 289 | data->flags |= XIVE_IRQ_FLAG_STORE_EOI; |
249 | if (flags & XIVE_SRC_LSI) | 290 | if (flags & XIVE_SRC_LSI) |
@@ -487,6 +528,7 @@ static const struct xive_ops xive_spapr_ops = { | |||
487 | .setup_cpu = xive_spapr_setup_cpu, | 528 | .setup_cpu = xive_spapr_setup_cpu, |
488 | .teardown_cpu = xive_spapr_teardown_cpu, | 529 | .teardown_cpu = xive_spapr_teardown_cpu, |
489 | .sync_source = xive_spapr_sync_source, | 530 | .sync_source = xive_spapr_sync_source, |
531 | .esb_rw = xive_spapr_esb_rw, | ||
490 | #ifdef CONFIG_SMP | 532 | #ifdef CONFIG_SMP |
491 | .get_ipi = xive_spapr_get_ipi, | 533 | .get_ipi = xive_spapr_get_ipi, |
492 | .put_ipi = xive_spapr_put_ipi, | 534 | .put_ipi = xive_spapr_put_ipi, |
diff --git a/arch/powerpc/sysdev/xive/xive-internal.h b/arch/powerpc/sysdev/xive/xive-internal.h index dd1e2022cce4..f34abed0c05f 100644 --- a/arch/powerpc/sysdev/xive/xive-internal.h +++ b/arch/powerpc/sysdev/xive/xive-internal.h | |||
@@ -47,6 +47,7 @@ struct xive_ops { | |||
47 | void (*update_pending)(struct xive_cpu *xc); | 47 | void (*update_pending)(struct xive_cpu *xc); |
48 | void (*eoi)(u32 hw_irq); | 48 | void (*eoi)(u32 hw_irq); |
49 | void (*sync_source)(u32 hw_irq); | 49 | void (*sync_source)(u32 hw_irq); |
50 | u64 (*esb_rw)(u32 hw_irq, u32 offset, u64 data, bool write); | ||
50 | #ifdef CONFIG_SMP | 51 | #ifdef CONFIG_SMP |
51 | int (*get_ipi)(unsigned int cpu, struct xive_cpu *xc); | 52 | int (*get_ipi)(unsigned int cpu, struct xive_cpu *xc); |
52 | void (*put_ipi)(unsigned int cpu, struct xive_cpu *xc); | 53 | void (*put_ipi)(unsigned int cpu, struct xive_cpu *xc); |