cxl: Poll for outstanding IRQs when detaching a context

When detaching contexts, we may still have interrupts in the system
which are yet to be delivered to any CPU and be acked in the PSL.
This can result in a subsequent unrelated process getting an spurious
IRQ or an interrupt for a non-existent context.

This polls the PSL to ensure that the PSL is clear of IRQs for the
detached context, before removing the context from the idr.

Signed-off-by: Michael Neuling <mikey@neuling.org>
Tested-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com>
Acked-by: Ian Munsie <imunsie@au1.ibm.com>
Tested-by: Vaibhav Jain <vaibhav@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by Michael Neuling and committed by Michael Ellerman 2bc79ffc d6776bba

Changed files
+40
drivers
+7
drivers/misc/cxl/context.c
··· 223 223 cxl_ops->link_ok(ctx->afu->adapter, ctx->afu)); 224 224 flush_work(&ctx->fault_work); /* Only needed for dedicated process */ 225 225 226 + /* 227 + * Wait until no further interrupts are presented by the PSL 228 + * for this context. 229 + */ 230 + if (cxl_ops->irq_wait) 231 + cxl_ops->irq_wait(ctx); 232 + 226 233 /* release the reference to the group leader and mm handling pid */ 227 234 put_pid(ctx->pid); 228 235 put_pid(ctx->glpid);
+2
drivers/misc/cxl/cxl.h
··· 274 274 #define CXL_PSL_DSISR_An_PE (1ull << (63-4)) /* PSL Error (implementation specific) */ 275 275 #define CXL_PSL_DSISR_An_AE (1ull << (63-5)) /* AFU Error */ 276 276 #define CXL_PSL_DSISR_An_OC (1ull << (63-6)) /* OS Context Warning */ 277 + #define CXL_PSL_DSISR_PENDING (CXL_PSL_DSISR_TRANS | CXL_PSL_DSISR_An_PE | CXL_PSL_DSISR_An_AE | CXL_PSL_DSISR_An_OC) 277 278 /* NOTE: Bits 32:63 are undefined if DSISR[DS] = 1 */ 278 279 #define CXL_PSL_DSISR_An_M DSISR_NOHPTE /* PTE not found */ 279 280 #define CXL_PSL_DSISR_An_P DSISR_PROTFAULT /* Storage protection violation */ ··· 856 855 u64 dsisr, u64 errstat); 857 856 irqreturn_t (*psl_interrupt)(int irq, void *data); 858 857 int (*ack_irq)(struct cxl_context *ctx, u64 tfc, u64 psl_reset_mask); 858 + void (*irq_wait)(struct cxl_context *ctx); 859 859 int (*attach_process)(struct cxl_context *ctx, bool kernel, 860 860 u64 wed, u64 amr); 861 861 int (*detach_process)(struct cxl_context *ctx);
+31
drivers/misc/cxl/native.c
··· 14 14 #include <linux/mutex.h> 15 15 #include <linux/mm.h> 16 16 #include <linux/uaccess.h> 17 + #include <linux/delay.h> 17 18 #include <asm/synch.h> 18 19 #include <misc/cxl-base.h> 19 20 ··· 798 797 return fail_psl_irq(afu, &irq_info); 799 798 } 800 799 800 + void native_irq_wait(struct cxl_context *ctx) 801 + { 802 + u64 dsisr; 803 + int timeout = 1000; 804 + int ph; 805 + 806 + /* 807 + * Wait until no further interrupts are presented by the PSL 808 + * for this context. 809 + */ 810 + while (timeout--) { 811 + ph = cxl_p2n_read(ctx->afu, CXL_PSL_PEHandle_An) & 0xffff; 812 + if (ph != ctx->pe) 813 + return; 814 + dsisr = cxl_p2n_read(ctx->afu, CXL_PSL_DSISR_An); 815 + if ((dsisr & CXL_PSL_DSISR_PENDING) == 0) 816 + return; 817 + /* 818 + * We are waiting for the workqueue to process our 819 + * irq, so need to let that run here. 820 + */ 821 + msleep(1); 822 + } 823 + 824 + dev_warn(&ctx->afu->dev, "WARNING: waiting on DSI for PE %i" 825 + " DSISR %016llx!\n", ph, dsisr); 826 + return; 827 + } 828 + 801 829 static irqreturn_t native_slice_irq_err(int irq, void *data) 802 830 { 803 831 struct cxl_afu *afu = data; ··· 1106 1076 .handle_psl_slice_error = native_handle_psl_slice_error, 1107 1077 .psl_interrupt = NULL, 1108 1078 .ack_irq = native_ack_irq, 1079 + .irq_wait = native_irq_wait, 1109 1080 .attach_process = native_attach_process, 1110 1081 .detach_process = native_detach_process, 1111 1082 .support_attributes = native_support_attributes,