Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cxl: Add alternate MMIO error handling

userspace programs using cxl currently have to use two strategies for
dealing with MMIO errors simultaneously. They have to check every read
for a return of all Fs in case the adapter has gone away and the kernel
has not yet noticed, and they have to deal with SIGBUS in case the
kernel has already noticed, invalidated the mapping and marked the
context as failed.

In order to simplify things, this patch adds an alternative approach
where the kernel will return a page filled with Fs instead of delivering
a SIGBUS. This allows userspace to only need to deal with one of these
two error paths, and is intended for use in libraries that use cxl
transparently and may not be able to safely install a signal handler.

This approach will only work if certain constraints are met. Namely, if
the application is both reading and writing to an address in the problem
state area it cannot assume that a non-FF read is OK, as it may just be
reading out a value it has previously written. Further - since only one
page is used per context a write to a given offset would be visible when
reading the same offset from a different page in the mapping (this only
applies within a single context, not between contexts).

An application could deal with this by e.g. making sure it also reads
from a read-only offset after any reads to a read/write offset.

Due to these constraints, this functionality must be explicitly
requested by userspace when starting the context by passing in the
CXL_START_WORK_ERR_FF flag.

Signed-off-by: Ian Munsie <imunsie@au1.ibm.com>
Acked-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by

Ian Munsie and committed by
Michael Ellerman
d9232a3d fc9e9cbf

+23 -3
+14
drivers/misc/cxl/context.c
··· 126 126 if (ctx->status != STARTED) { 127 127 mutex_unlock(&ctx->status_mutex); 128 128 pr_devel("%s: Context not started, failing problem state access\n", __func__); 129 + if (ctx->mmio_err_ff) { 130 + if (!ctx->ff_page) { 131 + ctx->ff_page = alloc_page(GFP_USER); 132 + if (!ctx->ff_page) 133 + return VM_FAULT_OOM; 134 + memset(page_address(ctx->ff_page), 0xff, PAGE_SIZE); 135 + } 136 + get_page(ctx->ff_page); 137 + vmf->page = ctx->ff_page; 138 + vma->vm_page_prot = pgprot_cached(vma->vm_page_prot); 139 + return 0; 140 + } 129 141 return VM_FAULT_SIGBUS; 130 142 } 131 143 ··· 269 257 struct cxl_context *ctx = container_of(rcu, struct cxl_context, rcu); 270 258 271 259 free_page((u64)ctx->sstp); 260 + if (ctx->ff_page) 261 + __free_page(ctx->ff_page); 272 262 ctx->sstp = NULL; 273 263 274 264 kfree(ctx);
+3 -1
drivers/misc/cxl/cxl.h
··· 34 34 * Bump version each time a user API change is made, whether it is 35 35 * backwards compatible ot not. 36 36 */ 37 - #define CXL_API_VERSION 1 37 + #define CXL_API_VERSION 2 38 38 #define CXL_API_VERSION_COMPATIBLE 1 39 39 40 40 /* ··· 418 418 /* Used to unmap any mmaps when force detaching */ 419 419 struct address_space *mapping; 420 420 struct mutex mapping_lock; 421 + struct page *ff_page; 422 + bool mmio_err_ff; 421 423 422 424 spinlock_t sste_lock; /* Protects segment table entries */ 423 425 struct cxl_sste *sstp;
+3 -1
drivers/misc/cxl/file.c
··· 184 184 if (work.flags & CXL_START_WORK_AMR) 185 185 amr = work.amr & mfspr(SPRN_UAMOR); 186 186 187 + ctx->mmio_err_ff = !!(work.flags & CXL_START_WORK_ERR_FF); 188 + 187 189 /* 188 190 * We grab the PID here and not in the file open to allow for the case 189 191 * where a process (master, some daemon, etc) has opened the chardev on ··· 540 538 * If these change we really need to update API. Either change some 541 539 * flags or update API version number CXL_API_VERSION. 542 540 */ 543 - BUILD_BUG_ON(CXL_API_VERSION != 1); 541 + BUILD_BUG_ON(CXL_API_VERSION != 2); 544 542 BUILD_BUG_ON(sizeof(struct cxl_ioctl_start_work) != 64); 545 543 BUILD_BUG_ON(sizeof(struct cxl_event_header) != 8); 546 544 BUILD_BUG_ON(sizeof(struct cxl_event_afu_interrupt) != 8);
+3 -1
include/uapi/misc/cxl.h
··· 29 29 30 30 #define CXL_START_WORK_AMR 0x0000000000000001ULL 31 31 #define CXL_START_WORK_NUM_IRQS 0x0000000000000002ULL 32 + #define CXL_START_WORK_ERR_FF 0x0000000000000004ULL 32 33 #define CXL_START_WORK_ALL (CXL_START_WORK_AMR |\ 33 - CXL_START_WORK_NUM_IRQS) 34 + CXL_START_WORK_NUM_IRQS |\ 35 + CXL_START_WORK_ERR_FF) 34 36 35 37 36 38 /* Possible modes that an afu can be in */