15ef3166eSFrederic Barrat // SPDX-License-Identifier: GPL-2.0+ 25ef3166eSFrederic Barrat // Copyright 2017 IBM Corp. 35ef3166eSFrederic Barrat #include <linux/fs.h> 45ef3166eSFrederic Barrat #include <linux/poll.h> 55ef3166eSFrederic Barrat #include <linux/sched/signal.h> 65ef3166eSFrederic Barrat #include <linux/uaccess.h> 75ef3166eSFrederic Barrat #include <uapi/misc/ocxl.h> 8e948e06fSAlastair D'Silva #include <asm/reg.h> 9e948e06fSAlastair D'Silva #include <asm/switch_to.h> 105ef3166eSFrederic Barrat #include "ocxl_internal.h" 115ef3166eSFrederic Barrat 125ef3166eSFrederic Barrat 135ef3166eSFrederic Barrat #define OCXL_NUM_MINORS 256 /* Total to reserve */ 145ef3166eSFrederic Barrat 155ef3166eSFrederic Barrat static dev_t ocxl_dev; 165ef3166eSFrederic Barrat static struct class *ocxl_class; 175ef3166eSFrederic Barrat static struct mutex minors_idr_lock; 185ef3166eSFrederic Barrat static struct idr minors_idr; 195ef3166eSFrederic Barrat 205ef3166eSFrederic Barrat static struct ocxl_afu *find_and_get_afu(dev_t devno) 215ef3166eSFrederic Barrat { 225ef3166eSFrederic Barrat struct ocxl_afu *afu; 235ef3166eSFrederic Barrat int afu_minor; 245ef3166eSFrederic Barrat 255ef3166eSFrederic Barrat afu_minor = MINOR(devno); 265ef3166eSFrederic Barrat /* 275ef3166eSFrederic Barrat * We don't declare an RCU critical section here, as our AFU 285ef3166eSFrederic Barrat * is protected by a reference counter on the device. By the time the 295ef3166eSFrederic Barrat * minor number of a device is removed from the idr, the ref count of 305ef3166eSFrederic Barrat * the device is already at 0, so no user API will access that AFU and 315ef3166eSFrederic Barrat * this function can't return it. 325ef3166eSFrederic Barrat */ 335ef3166eSFrederic Barrat afu = idr_find(&minors_idr, afu_minor); 345ef3166eSFrederic Barrat if (afu) 355ef3166eSFrederic Barrat ocxl_afu_get(afu); 365ef3166eSFrederic Barrat return afu; 375ef3166eSFrederic Barrat } 385ef3166eSFrederic Barrat 395ef3166eSFrederic Barrat static int allocate_afu_minor(struct ocxl_afu *afu) 405ef3166eSFrederic Barrat { 415ef3166eSFrederic Barrat int minor; 425ef3166eSFrederic Barrat 435ef3166eSFrederic Barrat mutex_lock(&minors_idr_lock); 445ef3166eSFrederic Barrat minor = idr_alloc(&minors_idr, afu, 0, OCXL_NUM_MINORS, GFP_KERNEL); 455ef3166eSFrederic Barrat mutex_unlock(&minors_idr_lock); 465ef3166eSFrederic Barrat return minor; 475ef3166eSFrederic Barrat } 485ef3166eSFrederic Barrat 495ef3166eSFrederic Barrat static void free_afu_minor(struct ocxl_afu *afu) 505ef3166eSFrederic Barrat { 515ef3166eSFrederic Barrat mutex_lock(&minors_idr_lock); 525ef3166eSFrederic Barrat idr_remove(&minors_idr, MINOR(afu->dev.devt)); 535ef3166eSFrederic Barrat mutex_unlock(&minors_idr_lock); 545ef3166eSFrederic Barrat } 555ef3166eSFrederic Barrat 565ef3166eSFrederic Barrat static int afu_open(struct inode *inode, struct file *file) 575ef3166eSFrederic Barrat { 585ef3166eSFrederic Barrat struct ocxl_afu *afu; 595ef3166eSFrederic Barrat struct ocxl_context *ctx; 605ef3166eSFrederic Barrat int rc; 615ef3166eSFrederic Barrat 625ef3166eSFrederic Barrat pr_debug("%s for device %x\n", __func__, inode->i_rdev); 635ef3166eSFrederic Barrat 645ef3166eSFrederic Barrat afu = find_and_get_afu(inode->i_rdev); 655ef3166eSFrederic Barrat if (!afu) 665ef3166eSFrederic Barrat return -ENODEV; 675ef3166eSFrederic Barrat 685ef3166eSFrederic Barrat ctx = ocxl_context_alloc(); 695ef3166eSFrederic Barrat if (!ctx) { 705ef3166eSFrederic Barrat rc = -ENOMEM; 715ef3166eSFrederic Barrat goto put_afu; 725ef3166eSFrederic Barrat } 735ef3166eSFrederic Barrat 745ef3166eSFrederic Barrat rc = ocxl_context_init(ctx, afu, inode->i_mapping); 755ef3166eSFrederic Barrat if (rc) 765ef3166eSFrederic Barrat goto put_afu; 775ef3166eSFrederic Barrat file->private_data = ctx; 785ef3166eSFrederic Barrat ocxl_afu_put(afu); 795ef3166eSFrederic Barrat return 0; 805ef3166eSFrederic Barrat 815ef3166eSFrederic Barrat put_afu: 825ef3166eSFrederic Barrat ocxl_afu_put(afu); 835ef3166eSFrederic Barrat return rc; 845ef3166eSFrederic Barrat } 855ef3166eSFrederic Barrat 865ef3166eSFrederic Barrat static long afu_ioctl_attach(struct ocxl_context *ctx, 875ef3166eSFrederic Barrat struct ocxl_ioctl_attach __user *uarg) 885ef3166eSFrederic Barrat { 895ef3166eSFrederic Barrat struct ocxl_ioctl_attach arg; 905ef3166eSFrederic Barrat u64 amr = 0; 915ef3166eSFrederic Barrat int rc; 925ef3166eSFrederic Barrat 935ef3166eSFrederic Barrat pr_debug("%s for context %d\n", __func__, ctx->pasid); 945ef3166eSFrederic Barrat 955ef3166eSFrederic Barrat if (copy_from_user(&arg, uarg, sizeof(arg))) 965ef3166eSFrederic Barrat return -EFAULT; 975ef3166eSFrederic Barrat 985ef3166eSFrederic Barrat /* Make sure reserved fields are not set for forward compatibility */ 995ef3166eSFrederic Barrat if (arg.reserved1 || arg.reserved2 || arg.reserved3) 1005ef3166eSFrederic Barrat return -EINVAL; 1015ef3166eSFrederic Barrat 1025ef3166eSFrederic Barrat amr = arg.amr & mfspr(SPRN_UAMOR); 1035ef3166eSFrederic Barrat rc = ocxl_context_attach(ctx, amr); 1045ef3166eSFrederic Barrat return rc; 1055ef3166eSFrederic Barrat } 1065ef3166eSFrederic Barrat 10707c5ccd7SAlastair D'Silva static long afu_ioctl_get_metadata(struct ocxl_context *ctx, 10807c5ccd7SAlastair D'Silva struct ocxl_ioctl_metadata __user *uarg) 10907c5ccd7SAlastair D'Silva { 11007c5ccd7SAlastair D'Silva struct ocxl_ioctl_metadata arg; 11107c5ccd7SAlastair D'Silva 11207c5ccd7SAlastair D'Silva memset(&arg, 0, sizeof(arg)); 11307c5ccd7SAlastair D'Silva 11407c5ccd7SAlastair D'Silva arg.version = 0; 11507c5ccd7SAlastair D'Silva 11607c5ccd7SAlastair D'Silva arg.afu_version_major = ctx->afu->config.version_major; 11707c5ccd7SAlastair D'Silva arg.afu_version_minor = ctx->afu->config.version_minor; 11807c5ccd7SAlastair D'Silva arg.pasid = ctx->pasid; 11907c5ccd7SAlastair D'Silva arg.pp_mmio_size = ctx->afu->config.pp_mmio_stride; 12007c5ccd7SAlastair D'Silva arg.global_mmio_size = ctx->afu->config.global_mmio_size; 12107c5ccd7SAlastair D'Silva 12207c5ccd7SAlastair D'Silva if (copy_to_user(uarg, &arg, sizeof(arg))) 12307c5ccd7SAlastair D'Silva return -EFAULT; 12407c5ccd7SAlastair D'Silva 12507c5ccd7SAlastair D'Silva return 0; 12607c5ccd7SAlastair D'Silva } 12707c5ccd7SAlastair D'Silva 128e948e06fSAlastair D'Silva #ifdef CONFIG_PPC64 129e948e06fSAlastair D'Silva static long afu_ioctl_enable_p9_wait(struct ocxl_context *ctx, 130e948e06fSAlastair D'Silva struct ocxl_ioctl_p9_wait __user *uarg) 131e948e06fSAlastair D'Silva { 132e948e06fSAlastair D'Silva struct ocxl_ioctl_p9_wait arg; 133e948e06fSAlastair D'Silva 134e948e06fSAlastair D'Silva memset(&arg, 0, sizeof(arg)); 135e948e06fSAlastair D'Silva 136e948e06fSAlastair D'Silva if (cpu_has_feature(CPU_FTR_P9_TIDR)) { 137e948e06fSAlastair D'Silva enum ocxl_context_status status; 138e948e06fSAlastair D'Silva 139e948e06fSAlastair D'Silva // Locks both status & tidr 140e948e06fSAlastair D'Silva mutex_lock(&ctx->status_mutex); 141e948e06fSAlastair D'Silva if (!ctx->tidr) { 142e948e06fSAlastair D'Silva if (set_thread_tidr(current)) 143e948e06fSAlastair D'Silva return -ENOENT; 144e948e06fSAlastair D'Silva 145e948e06fSAlastair D'Silva ctx->tidr = current->thread.tidr; 146e948e06fSAlastair D'Silva } 147e948e06fSAlastair D'Silva 148e948e06fSAlastair D'Silva status = ctx->status; 149e948e06fSAlastair D'Silva mutex_unlock(&ctx->status_mutex); 150e948e06fSAlastair D'Silva 151e948e06fSAlastair D'Silva if (status == ATTACHED) { 152e948e06fSAlastair D'Silva int rc; 153e948e06fSAlastair D'Silva struct link *link = ctx->afu->fn->link; 154e948e06fSAlastair D'Silva 155e948e06fSAlastair D'Silva rc = ocxl_link_update_pe(link, ctx->pasid, ctx->tidr); 156e948e06fSAlastair D'Silva if (rc) 157e948e06fSAlastair D'Silva return rc; 158e948e06fSAlastair D'Silva } 159e948e06fSAlastair D'Silva 160e948e06fSAlastair D'Silva arg.thread_id = ctx->tidr; 161e948e06fSAlastair D'Silva } else 162e948e06fSAlastair D'Silva return -ENOENT; 163e948e06fSAlastair D'Silva 164e948e06fSAlastair D'Silva if (copy_to_user(uarg, &arg, sizeof(arg))) 165e948e06fSAlastair D'Silva return -EFAULT; 166e948e06fSAlastair D'Silva 167e948e06fSAlastair D'Silva return 0; 168e948e06fSAlastair D'Silva } 169e948e06fSAlastair D'Silva #endif 170e948e06fSAlastair D'Silva 17102a8e5bcSAlastair D'Silva 17202a8e5bcSAlastair D'Silva static long afu_ioctl_get_features(struct ocxl_context *ctx, 17302a8e5bcSAlastair D'Silva struct ocxl_ioctl_features __user *uarg) 17402a8e5bcSAlastair D'Silva { 17502a8e5bcSAlastair D'Silva struct ocxl_ioctl_features arg; 17602a8e5bcSAlastair D'Silva 17702a8e5bcSAlastair D'Silva memset(&arg, 0, sizeof(arg)); 17802a8e5bcSAlastair D'Silva 17902a8e5bcSAlastair D'Silva #ifdef CONFIG_PPC64 18002a8e5bcSAlastair D'Silva if (cpu_has_feature(CPU_FTR_P9_TIDR)) 18102a8e5bcSAlastair D'Silva arg.flags[0] |= OCXL_IOCTL_FEATURES_FLAGS0_P9_WAIT; 18202a8e5bcSAlastair D'Silva #endif 18302a8e5bcSAlastair D'Silva 18402a8e5bcSAlastair D'Silva if (copy_to_user(uarg, &arg, sizeof(arg))) 18502a8e5bcSAlastair D'Silva return -EFAULT; 18602a8e5bcSAlastair D'Silva 18702a8e5bcSAlastair D'Silva return 0; 18802a8e5bcSAlastair D'Silva } 18902a8e5bcSAlastair D'Silva 1905ef3166eSFrederic Barrat #define CMD_STR(x) (x == OCXL_IOCTL_ATTACH ? "ATTACH" : \ 191aeddad17SFrederic Barrat x == OCXL_IOCTL_IRQ_ALLOC ? "IRQ_ALLOC" : \ 192aeddad17SFrederic Barrat x == OCXL_IOCTL_IRQ_FREE ? "IRQ_FREE" : \ 193aeddad17SFrederic Barrat x == OCXL_IOCTL_IRQ_SET_FD ? "IRQ_SET_FD" : \ 19407c5ccd7SAlastair D'Silva x == OCXL_IOCTL_GET_METADATA ? "GET_METADATA" : \ 195e948e06fSAlastair D'Silva x == OCXL_IOCTL_ENABLE_P9_WAIT ? "ENABLE_P9_WAIT" : \ 19602a8e5bcSAlastair D'Silva x == OCXL_IOCTL_GET_FEATURES ? "GET_FEATURES" : \ 1975ef3166eSFrederic Barrat "UNKNOWN") 1985ef3166eSFrederic Barrat 1995ef3166eSFrederic Barrat static long afu_ioctl(struct file *file, unsigned int cmd, 2005ef3166eSFrederic Barrat unsigned long args) 2015ef3166eSFrederic Barrat { 2025ef3166eSFrederic Barrat struct ocxl_context *ctx = file->private_data; 203aeddad17SFrederic Barrat struct ocxl_ioctl_irq_fd irq_fd; 204aeddad17SFrederic Barrat u64 irq_offset; 2055ef3166eSFrederic Barrat long rc; 2065ef3166eSFrederic Barrat 2075ef3166eSFrederic Barrat pr_debug("%s for context %d, command %s\n", __func__, ctx->pasid, 2085ef3166eSFrederic Barrat CMD_STR(cmd)); 2095ef3166eSFrederic Barrat 2105ef3166eSFrederic Barrat if (ctx->status == CLOSED) 2115ef3166eSFrederic Barrat return -EIO; 2125ef3166eSFrederic Barrat 2135ef3166eSFrederic Barrat switch (cmd) { 2145ef3166eSFrederic Barrat case OCXL_IOCTL_ATTACH: 2155ef3166eSFrederic Barrat rc = afu_ioctl_attach(ctx, 2165ef3166eSFrederic Barrat (struct ocxl_ioctl_attach __user *) args); 2175ef3166eSFrederic Barrat break; 2185ef3166eSFrederic Barrat 219aeddad17SFrederic Barrat case OCXL_IOCTL_IRQ_ALLOC: 220aeddad17SFrederic Barrat rc = ocxl_afu_irq_alloc(ctx, &irq_offset); 221aeddad17SFrederic Barrat if (!rc) { 222aeddad17SFrederic Barrat rc = copy_to_user((u64 __user *) args, &irq_offset, 223aeddad17SFrederic Barrat sizeof(irq_offset)); 224423688abSFrederic Barrat if (rc) { 225aeddad17SFrederic Barrat ocxl_afu_irq_free(ctx, irq_offset); 226423688abSFrederic Barrat return -EFAULT; 227423688abSFrederic Barrat } 228aeddad17SFrederic Barrat } 229aeddad17SFrederic Barrat break; 230aeddad17SFrederic Barrat 231aeddad17SFrederic Barrat case OCXL_IOCTL_IRQ_FREE: 232aeddad17SFrederic Barrat rc = copy_from_user(&irq_offset, (u64 __user *) args, 233aeddad17SFrederic Barrat sizeof(irq_offset)); 234aeddad17SFrederic Barrat if (rc) 235aeddad17SFrederic Barrat return -EFAULT; 236aeddad17SFrederic Barrat rc = ocxl_afu_irq_free(ctx, irq_offset); 237aeddad17SFrederic Barrat break; 238aeddad17SFrederic Barrat 239aeddad17SFrederic Barrat case OCXL_IOCTL_IRQ_SET_FD: 240aeddad17SFrederic Barrat rc = copy_from_user(&irq_fd, (u64 __user *) args, 241aeddad17SFrederic Barrat sizeof(irq_fd)); 242aeddad17SFrederic Barrat if (rc) 243aeddad17SFrederic Barrat return -EFAULT; 244aeddad17SFrederic Barrat if (irq_fd.reserved) 245aeddad17SFrederic Barrat return -EINVAL; 246aeddad17SFrederic Barrat rc = ocxl_afu_irq_set_fd(ctx, irq_fd.irq_offset, 247aeddad17SFrederic Barrat irq_fd.eventfd); 248aeddad17SFrederic Barrat break; 249aeddad17SFrederic Barrat 25007c5ccd7SAlastair D'Silva case OCXL_IOCTL_GET_METADATA: 25107c5ccd7SAlastair D'Silva rc = afu_ioctl_get_metadata(ctx, 25207c5ccd7SAlastair D'Silva (struct ocxl_ioctl_metadata __user *) args); 25307c5ccd7SAlastair D'Silva break; 25407c5ccd7SAlastair D'Silva 255e948e06fSAlastair D'Silva #ifdef CONFIG_PPC64 256e948e06fSAlastair D'Silva case OCXL_IOCTL_ENABLE_P9_WAIT: 257e948e06fSAlastair D'Silva rc = afu_ioctl_enable_p9_wait(ctx, 258e948e06fSAlastair D'Silva (struct ocxl_ioctl_p9_wait __user *) args); 259e948e06fSAlastair D'Silva break; 260e948e06fSAlastair D'Silva #endif 261e948e06fSAlastair D'Silva 26202a8e5bcSAlastair D'Silva case OCXL_IOCTL_GET_FEATURES: 26302a8e5bcSAlastair D'Silva rc = afu_ioctl_get_features(ctx, 26402a8e5bcSAlastair D'Silva (struct ocxl_ioctl_features __user *) args); 26502a8e5bcSAlastair D'Silva break; 26602a8e5bcSAlastair D'Silva 2675ef3166eSFrederic Barrat default: 2685ef3166eSFrederic Barrat rc = -EINVAL; 2695ef3166eSFrederic Barrat } 2705ef3166eSFrederic Barrat return rc; 2715ef3166eSFrederic Barrat } 2725ef3166eSFrederic Barrat 2735ef3166eSFrederic Barrat static long afu_compat_ioctl(struct file *file, unsigned int cmd, 2745ef3166eSFrederic Barrat unsigned long args) 2755ef3166eSFrederic Barrat { 2765ef3166eSFrederic Barrat return afu_ioctl(file, cmd, args); 2775ef3166eSFrederic Barrat } 2785ef3166eSFrederic Barrat 2795ef3166eSFrederic Barrat static int afu_mmap(struct file *file, struct vm_area_struct *vma) 2805ef3166eSFrederic Barrat { 2815ef3166eSFrederic Barrat struct ocxl_context *ctx = file->private_data; 2825ef3166eSFrederic Barrat 2835ef3166eSFrederic Barrat pr_debug("%s for context %d\n", __func__, ctx->pasid); 2845ef3166eSFrederic Barrat return ocxl_context_mmap(ctx, vma); 2855ef3166eSFrederic Barrat } 2865ef3166eSFrederic Barrat 2875ef3166eSFrederic Barrat static bool has_xsl_error(struct ocxl_context *ctx) 2885ef3166eSFrederic Barrat { 2895ef3166eSFrederic Barrat bool ret; 2905ef3166eSFrederic Barrat 2915ef3166eSFrederic Barrat mutex_lock(&ctx->xsl_error_lock); 2925ef3166eSFrederic Barrat ret = !!ctx->xsl_error.addr; 2935ef3166eSFrederic Barrat mutex_unlock(&ctx->xsl_error_lock); 2945ef3166eSFrederic Barrat 2955ef3166eSFrederic Barrat return ret; 2965ef3166eSFrederic Barrat } 2975ef3166eSFrederic Barrat 2985ef3166eSFrederic Barrat /* 2995ef3166eSFrederic Barrat * Are there any events pending on the AFU 3005ef3166eSFrederic Barrat * ctx: The AFU context 3015ef3166eSFrederic Barrat * Returns: true if there are events pending 3025ef3166eSFrederic Barrat */ 3035ef3166eSFrederic Barrat static bool afu_events_pending(struct ocxl_context *ctx) 3045ef3166eSFrederic Barrat { 3055ef3166eSFrederic Barrat if (has_xsl_error(ctx)) 3065ef3166eSFrederic Barrat return true; 3075ef3166eSFrederic Barrat return false; 3085ef3166eSFrederic Barrat } 3095ef3166eSFrederic Barrat 3105ef3166eSFrederic Barrat static unsigned int afu_poll(struct file *file, struct poll_table_struct *wait) 3115ef3166eSFrederic Barrat { 3125ef3166eSFrederic Barrat struct ocxl_context *ctx = file->private_data; 3135ef3166eSFrederic Barrat unsigned int mask = 0; 3145ef3166eSFrederic Barrat bool closed; 3155ef3166eSFrederic Barrat 3165ef3166eSFrederic Barrat pr_debug("%s for context %d\n", __func__, ctx->pasid); 3175ef3166eSFrederic Barrat 3185ef3166eSFrederic Barrat poll_wait(file, &ctx->events_wq, wait); 3195ef3166eSFrederic Barrat 3205ef3166eSFrederic Barrat mutex_lock(&ctx->status_mutex); 3215ef3166eSFrederic Barrat closed = (ctx->status == CLOSED); 3225ef3166eSFrederic Barrat mutex_unlock(&ctx->status_mutex); 3235ef3166eSFrederic Barrat 3245ef3166eSFrederic Barrat if (afu_events_pending(ctx)) 325a9a08845SLinus Torvalds mask = EPOLLIN | EPOLLRDNORM; 3265ef3166eSFrederic Barrat else if (closed) 327a9a08845SLinus Torvalds mask = EPOLLERR; 3285ef3166eSFrederic Barrat 3295ef3166eSFrederic Barrat return mask; 3305ef3166eSFrederic Barrat } 3315ef3166eSFrederic Barrat 3325ef3166eSFrederic Barrat /* 3335ef3166eSFrederic Barrat * Populate the supplied buffer with a single XSL error 3345ef3166eSFrederic Barrat * ctx: The AFU context to report the error from 3355ef3166eSFrederic Barrat * header: the event header to populate 3365ef3166eSFrederic Barrat * buf: The buffer to write the body into (should be at least 3375ef3166eSFrederic Barrat * AFU_EVENT_BODY_XSL_ERROR_SIZE) 3385ef3166eSFrederic Barrat * Return: the amount of buffer that was populated 3395ef3166eSFrederic Barrat */ 3405ef3166eSFrederic Barrat static ssize_t append_xsl_error(struct ocxl_context *ctx, 3415ef3166eSFrederic Barrat struct ocxl_kernel_event_header *header, 3425ef3166eSFrederic Barrat char __user *buf) 3435ef3166eSFrederic Barrat { 3445ef3166eSFrederic Barrat struct ocxl_kernel_event_xsl_fault_error body; 3455ef3166eSFrederic Barrat 3465ef3166eSFrederic Barrat memset(&body, 0, sizeof(body)); 3475ef3166eSFrederic Barrat 3485ef3166eSFrederic Barrat mutex_lock(&ctx->xsl_error_lock); 3495ef3166eSFrederic Barrat if (!ctx->xsl_error.addr) { 3505ef3166eSFrederic Barrat mutex_unlock(&ctx->xsl_error_lock); 3515ef3166eSFrederic Barrat return 0; 3525ef3166eSFrederic Barrat } 3535ef3166eSFrederic Barrat 3545ef3166eSFrederic Barrat body.addr = ctx->xsl_error.addr; 3555ef3166eSFrederic Barrat body.dsisr = ctx->xsl_error.dsisr; 3565ef3166eSFrederic Barrat body.count = ctx->xsl_error.count; 3575ef3166eSFrederic Barrat 3585ef3166eSFrederic Barrat ctx->xsl_error.addr = 0; 3595ef3166eSFrederic Barrat ctx->xsl_error.dsisr = 0; 3605ef3166eSFrederic Barrat ctx->xsl_error.count = 0; 3615ef3166eSFrederic Barrat 3625ef3166eSFrederic Barrat mutex_unlock(&ctx->xsl_error_lock); 3635ef3166eSFrederic Barrat 3645ef3166eSFrederic Barrat header->type = OCXL_AFU_EVENT_XSL_FAULT_ERROR; 3655ef3166eSFrederic Barrat 3665ef3166eSFrederic Barrat if (copy_to_user(buf, &body, sizeof(body))) 3675ef3166eSFrederic Barrat return -EFAULT; 3685ef3166eSFrederic Barrat 3695ef3166eSFrederic Barrat return sizeof(body); 3705ef3166eSFrederic Barrat } 3715ef3166eSFrederic Barrat 3725ef3166eSFrederic Barrat #define AFU_EVENT_BODY_MAX_SIZE sizeof(struct ocxl_kernel_event_xsl_fault_error) 3735ef3166eSFrederic Barrat 3745ef3166eSFrederic Barrat /* 3755ef3166eSFrederic Barrat * Reports events on the AFU 3765ef3166eSFrederic Barrat * Format: 3775ef3166eSFrederic Barrat * Header (struct ocxl_kernel_event_header) 3785ef3166eSFrederic Barrat * Body (struct ocxl_kernel_event_*) 3795ef3166eSFrederic Barrat * Header... 3805ef3166eSFrederic Barrat */ 3815ef3166eSFrederic Barrat static ssize_t afu_read(struct file *file, char __user *buf, size_t count, 3825ef3166eSFrederic Barrat loff_t *off) 3835ef3166eSFrederic Barrat { 3845ef3166eSFrederic Barrat struct ocxl_context *ctx = file->private_data; 3855ef3166eSFrederic Barrat struct ocxl_kernel_event_header header; 3865ef3166eSFrederic Barrat ssize_t rc; 387dedab7f0SColin Ian King ssize_t used = 0; 3885ef3166eSFrederic Barrat DEFINE_WAIT(event_wait); 3895ef3166eSFrederic Barrat 3905ef3166eSFrederic Barrat memset(&header, 0, sizeof(header)); 3915ef3166eSFrederic Barrat 3925ef3166eSFrederic Barrat /* Require offset to be 0 */ 3935ef3166eSFrederic Barrat if (*off != 0) 3945ef3166eSFrederic Barrat return -EINVAL; 3955ef3166eSFrederic Barrat 3965ef3166eSFrederic Barrat if (count < (sizeof(struct ocxl_kernel_event_header) + 3975ef3166eSFrederic Barrat AFU_EVENT_BODY_MAX_SIZE)) 3985ef3166eSFrederic Barrat return -EINVAL; 3995ef3166eSFrederic Barrat 4005ef3166eSFrederic Barrat for (;;) { 4015ef3166eSFrederic Barrat prepare_to_wait(&ctx->events_wq, &event_wait, 4025ef3166eSFrederic Barrat TASK_INTERRUPTIBLE); 4035ef3166eSFrederic Barrat 4045ef3166eSFrederic Barrat if (afu_events_pending(ctx)) 4055ef3166eSFrederic Barrat break; 4065ef3166eSFrederic Barrat 4075ef3166eSFrederic Barrat if (ctx->status == CLOSED) 4085ef3166eSFrederic Barrat break; 4095ef3166eSFrederic Barrat 4105ef3166eSFrederic Barrat if (file->f_flags & O_NONBLOCK) { 4115ef3166eSFrederic Barrat finish_wait(&ctx->events_wq, &event_wait); 4125ef3166eSFrederic Barrat return -EAGAIN; 4135ef3166eSFrederic Barrat } 4145ef3166eSFrederic Barrat 4155ef3166eSFrederic Barrat if (signal_pending(current)) { 4165ef3166eSFrederic Barrat finish_wait(&ctx->events_wq, &event_wait); 4175ef3166eSFrederic Barrat return -ERESTARTSYS; 4185ef3166eSFrederic Barrat } 4195ef3166eSFrederic Barrat 4205ef3166eSFrederic Barrat schedule(); 4215ef3166eSFrederic Barrat } 4225ef3166eSFrederic Barrat 4235ef3166eSFrederic Barrat finish_wait(&ctx->events_wq, &event_wait); 4245ef3166eSFrederic Barrat 4255ef3166eSFrederic Barrat if (has_xsl_error(ctx)) { 4265ef3166eSFrederic Barrat used = append_xsl_error(ctx, &header, buf + sizeof(header)); 4275ef3166eSFrederic Barrat if (used < 0) 4285ef3166eSFrederic Barrat return used; 4295ef3166eSFrederic Barrat } 4305ef3166eSFrederic Barrat 4315ef3166eSFrederic Barrat if (!afu_events_pending(ctx)) 4325ef3166eSFrederic Barrat header.flags |= OCXL_KERNEL_EVENT_FLAG_LAST; 4335ef3166eSFrederic Barrat 4345ef3166eSFrederic Barrat if (copy_to_user(buf, &header, sizeof(header))) 4355ef3166eSFrederic Barrat return -EFAULT; 4365ef3166eSFrederic Barrat 4375ef3166eSFrederic Barrat used += sizeof(header); 4385ef3166eSFrederic Barrat 439423688abSFrederic Barrat rc = used; 4405ef3166eSFrederic Barrat return rc; 4415ef3166eSFrederic Barrat } 4425ef3166eSFrederic Barrat 4435ef3166eSFrederic Barrat static int afu_release(struct inode *inode, struct file *file) 4445ef3166eSFrederic Barrat { 4455ef3166eSFrederic Barrat struct ocxl_context *ctx = file->private_data; 4465ef3166eSFrederic Barrat int rc; 4475ef3166eSFrederic Barrat 4485ef3166eSFrederic Barrat pr_debug("%s for device %x\n", __func__, inode->i_rdev); 4495ef3166eSFrederic Barrat rc = ocxl_context_detach(ctx); 4505ef3166eSFrederic Barrat mutex_lock(&ctx->mapping_lock); 4515ef3166eSFrederic Barrat ctx->mapping = NULL; 4525ef3166eSFrederic Barrat mutex_unlock(&ctx->mapping_lock); 4535ef3166eSFrederic Barrat wake_up_all(&ctx->events_wq); 4545ef3166eSFrederic Barrat if (rc != -EBUSY) 4555ef3166eSFrederic Barrat ocxl_context_free(ctx); 4565ef3166eSFrederic Barrat return 0; 4575ef3166eSFrederic Barrat } 4585ef3166eSFrederic Barrat 4595ef3166eSFrederic Barrat static const struct file_operations ocxl_afu_fops = { 4605ef3166eSFrederic Barrat .owner = THIS_MODULE, 4615ef3166eSFrederic Barrat .open = afu_open, 4625ef3166eSFrederic Barrat .unlocked_ioctl = afu_ioctl, 4635ef3166eSFrederic Barrat .compat_ioctl = afu_compat_ioctl, 4645ef3166eSFrederic Barrat .mmap = afu_mmap, 4655ef3166eSFrederic Barrat .poll = afu_poll, 4665ef3166eSFrederic Barrat .read = afu_read, 4675ef3166eSFrederic Barrat .release = afu_release, 4685ef3166eSFrederic Barrat }; 4695ef3166eSFrederic Barrat 4705ef3166eSFrederic Barrat int ocxl_create_cdev(struct ocxl_afu *afu) 4715ef3166eSFrederic Barrat { 4725ef3166eSFrederic Barrat int rc; 4735ef3166eSFrederic Barrat 4745ef3166eSFrederic Barrat cdev_init(&afu->cdev, &ocxl_afu_fops); 4755ef3166eSFrederic Barrat rc = cdev_add(&afu->cdev, afu->dev.devt, 1); 4765ef3166eSFrederic Barrat if (rc) { 4775ef3166eSFrederic Barrat dev_err(&afu->dev, "Unable to add afu char device: %d\n", rc); 4785ef3166eSFrederic Barrat return rc; 4795ef3166eSFrederic Barrat } 4805ef3166eSFrederic Barrat return 0; 4815ef3166eSFrederic Barrat } 4825ef3166eSFrederic Barrat 4835ef3166eSFrederic Barrat void ocxl_destroy_cdev(struct ocxl_afu *afu) 4845ef3166eSFrederic Barrat { 4855ef3166eSFrederic Barrat cdev_del(&afu->cdev); 4865ef3166eSFrederic Barrat } 4875ef3166eSFrederic Barrat 4885ef3166eSFrederic Barrat int ocxl_register_afu(struct ocxl_afu *afu) 4895ef3166eSFrederic Barrat { 4905ef3166eSFrederic Barrat int minor; 4915ef3166eSFrederic Barrat 4925ef3166eSFrederic Barrat minor = allocate_afu_minor(afu); 4935ef3166eSFrederic Barrat if (minor < 0) 4945ef3166eSFrederic Barrat return minor; 4955ef3166eSFrederic Barrat afu->dev.devt = MKDEV(MAJOR(ocxl_dev), minor); 4965ef3166eSFrederic Barrat afu->dev.class = ocxl_class; 4975ef3166eSFrederic Barrat return device_register(&afu->dev); 4985ef3166eSFrederic Barrat } 4995ef3166eSFrederic Barrat 5005ef3166eSFrederic Barrat void ocxl_unregister_afu(struct ocxl_afu *afu) 5015ef3166eSFrederic Barrat { 5025ef3166eSFrederic Barrat free_afu_minor(afu); 5035ef3166eSFrederic Barrat } 5045ef3166eSFrederic Barrat 5055ef3166eSFrederic Barrat static char *ocxl_devnode(struct device *dev, umode_t *mode) 5065ef3166eSFrederic Barrat { 5075ef3166eSFrederic Barrat return kasprintf(GFP_KERNEL, "ocxl/%s", dev_name(dev)); 5085ef3166eSFrederic Barrat } 5095ef3166eSFrederic Barrat 5105ef3166eSFrederic Barrat int ocxl_file_init(void) 5115ef3166eSFrederic Barrat { 5125ef3166eSFrederic Barrat int rc; 5135ef3166eSFrederic Barrat 5145ef3166eSFrederic Barrat mutex_init(&minors_idr_lock); 5155ef3166eSFrederic Barrat idr_init(&minors_idr); 5165ef3166eSFrederic Barrat 5175ef3166eSFrederic Barrat rc = alloc_chrdev_region(&ocxl_dev, 0, OCXL_NUM_MINORS, "ocxl"); 5185ef3166eSFrederic Barrat if (rc) { 5195ef3166eSFrederic Barrat pr_err("Unable to allocate ocxl major number: %d\n", rc); 5205ef3166eSFrederic Barrat return rc; 5215ef3166eSFrederic Barrat } 5225ef3166eSFrederic Barrat 5235ef3166eSFrederic Barrat ocxl_class = class_create(THIS_MODULE, "ocxl"); 5245ef3166eSFrederic Barrat if (IS_ERR(ocxl_class)) { 5255ef3166eSFrederic Barrat pr_err("Unable to create ocxl class\n"); 5265ef3166eSFrederic Barrat unregister_chrdev_region(ocxl_dev, OCXL_NUM_MINORS); 5275ef3166eSFrederic Barrat return PTR_ERR(ocxl_class); 5285ef3166eSFrederic Barrat } 5295ef3166eSFrederic Barrat 5305ef3166eSFrederic Barrat ocxl_class->devnode = ocxl_devnode; 5315ef3166eSFrederic Barrat return 0; 5325ef3166eSFrederic Barrat } 5335ef3166eSFrederic Barrat 5345ef3166eSFrederic Barrat void ocxl_file_exit(void) 5355ef3166eSFrederic Barrat { 5365ef3166eSFrederic Barrat class_destroy(ocxl_class); 5375ef3166eSFrederic Barrat unregister_chrdev_region(ocxl_dev, OCXL_NUM_MINORS); 5385ef3166eSFrederic Barrat idr_destroy(&minors_idr); 5395ef3166eSFrederic Barrat } 540