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

+40
+7
drivers/misc/cxl/context.c
··· 223 cxl_ops->link_ok(ctx->afu->adapter, ctx->afu)); 224 flush_work(&ctx->fault_work); /* Only needed for dedicated process */ 225 226 /* release the reference to the group leader and mm handling pid */ 227 put_pid(ctx->pid); 228 put_pid(ctx->glpid);
··· 223 cxl_ops->link_ok(ctx->afu->adapter, ctx->afu)); 224 flush_work(&ctx->fault_work); /* Only needed for dedicated process */ 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 + 233 /* release the reference to the group leader and mm handling pid */ 234 put_pid(ctx->pid); 235 put_pid(ctx->glpid);
+2
drivers/misc/cxl/cxl.h
··· 274 #define CXL_PSL_DSISR_An_PE (1ull << (63-4)) /* PSL Error (implementation specific) */ 275 #define CXL_PSL_DSISR_An_AE (1ull << (63-5)) /* AFU Error */ 276 #define CXL_PSL_DSISR_An_OC (1ull << (63-6)) /* OS Context Warning */ 277 /* NOTE: Bits 32:63 are undefined if DSISR[DS] = 1 */ 278 #define CXL_PSL_DSISR_An_M DSISR_NOHPTE /* PTE not found */ 279 #define CXL_PSL_DSISR_An_P DSISR_PROTFAULT /* Storage protection violation */ ··· 856 u64 dsisr, u64 errstat); 857 irqreturn_t (*psl_interrupt)(int irq, void *data); 858 int (*ack_irq)(struct cxl_context *ctx, u64 tfc, u64 psl_reset_mask); 859 int (*attach_process)(struct cxl_context *ctx, bool kernel, 860 u64 wed, u64 amr); 861 int (*detach_process)(struct cxl_context *ctx);
··· 274 #define CXL_PSL_DSISR_An_PE (1ull << (63-4)) /* PSL Error (implementation specific) */ 275 #define CXL_PSL_DSISR_An_AE (1ull << (63-5)) /* AFU Error */ 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) 278 /* NOTE: Bits 32:63 are undefined if DSISR[DS] = 1 */ 279 #define CXL_PSL_DSISR_An_M DSISR_NOHPTE /* PTE not found */ 280 #define CXL_PSL_DSISR_An_P DSISR_PROTFAULT /* Storage protection violation */ ··· 855 u64 dsisr, u64 errstat); 856 irqreturn_t (*psl_interrupt)(int irq, void *data); 857 int (*ack_irq)(struct cxl_context *ctx, u64 tfc, u64 psl_reset_mask); 858 + void (*irq_wait)(struct cxl_context *ctx); 859 int (*attach_process)(struct cxl_context *ctx, bool kernel, 860 u64 wed, u64 amr); 861 int (*detach_process)(struct cxl_context *ctx);
+31
drivers/misc/cxl/native.c
··· 14 #include <linux/mutex.h> 15 #include <linux/mm.h> 16 #include <linux/uaccess.h> 17 #include <asm/synch.h> 18 #include <misc/cxl-base.h> 19 ··· 798 return fail_psl_irq(afu, &irq_info); 799 } 800 801 static irqreturn_t native_slice_irq_err(int irq, void *data) 802 { 803 struct cxl_afu *afu = data; ··· 1106 .handle_psl_slice_error = native_handle_psl_slice_error, 1107 .psl_interrupt = NULL, 1108 .ack_irq = native_ack_irq, 1109 .attach_process = native_attach_process, 1110 .detach_process = native_detach_process, 1111 .support_attributes = native_support_attributes,
··· 14 #include <linux/mutex.h> 15 #include <linux/mm.h> 16 #include <linux/uaccess.h> 17 + #include <linux/delay.h> 18 #include <asm/synch.h> 19 #include <misc/cxl-base.h> 20 ··· 797 return fail_psl_irq(afu, &irq_info); 798 } 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 + 829 static irqreturn_t native_slice_irq_err(int irq, void *data) 830 { 831 struct cxl_afu *afu = data; ··· 1076 .handle_psl_slice_error = native_handle_psl_slice_error, 1077 .psl_interrupt = NULL, 1078 .ack_irq = native_ack_irq, 1079 + .irq_wait = native_irq_wait, 1080 .attach_process = native_attach_process, 1081 .detach_process = native_detach_process, 1082 .support_attributes = native_support_attributes,