diff options
Diffstat (limited to 'drivers/misc/cxl')
-rw-r--r-- | drivers/misc/cxl/api.c | 147 | ||||
-rw-r--r-- | drivers/misc/cxl/context.c | 17 | ||||
-rw-r--r-- | drivers/misc/cxl/cxl.h | 6 | ||||
-rw-r--r-- | drivers/misc/cxl/debugfs.c | 6 | ||||
-rw-r--r-- | drivers/misc/cxl/file.c | 5 | ||||
-rw-r--r-- | drivers/misc/cxl/guest.c | 2 | ||||
-rw-r--r-- | drivers/misc/cxl/irq.c | 2 | ||||
-rw-r--r-- | drivers/misc/cxl/native.c | 20 | ||||
-rw-r--r-- | drivers/misc/cxl/pci.c | 2 | ||||
-rw-r--r-- | drivers/misc/cxl/phb.c | 2 |
10 files changed, 160 insertions, 49 deletions
diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c index 2e5233b60971..1b35e33d2434 100644 --- a/drivers/misc/cxl/api.c +++ b/drivers/misc/cxl/api.c @@ -9,18 +9,119 @@ #include <linux/pci.h> #include <linux/slab.h> -#include <linux/anon_inodes.h> #include <linux/file.h> #include <misc/cxl.h> -#include <linux/fs.h> #include <asm/pnv-pci.h> #include <linux/msi.h> +#include <linux/module.h> +#include <linux/mount.h> #include "cxl.h" +/* + * Since we want to track memory mappings to be able to force-unmap + * when the AFU is no longer reachable, we need an inode. For devices + * opened through the cxl user API, this is not a problem, but a + * userland process can also get a cxl fd through the cxl_get_fd() + * API, which is used by the cxlflash driver. + * + * Therefore we implement our own simple pseudo-filesystem and inode + * allocator. We don't use the anonymous inode, as we need the + * meta-data associated with it (address_space) and it is shared by + * other drivers/processes, so it could lead to cxl unmapping VMAs + * from random processes. + */ + +#define CXL_PSEUDO_FS_MAGIC 0x1697697f + +static int cxl_fs_cnt; +static struct vfsmount *cxl_vfs_mount; + +static const struct dentry_operations cxl_fs_dops = { + .d_dname = simple_dname, +}; + +static struct dentry *cxl_fs_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) +{ + return mount_pseudo(fs_type, "cxl:", NULL, &cxl_fs_dops, + CXL_PSEUDO_FS_MAGIC); +} + +static struct file_system_type cxl_fs_type = { + .name = "cxl", + .owner = THIS_MODULE, + .mount = cxl_fs_mount, + .kill_sb = kill_anon_super, +}; + + +void cxl_release_mapping(struct cxl_context *ctx) +{ + if (ctx->kernelapi && ctx->mapping) + simple_release_fs(&cxl_vfs_mount, &cxl_fs_cnt); +} + +static struct file *cxl_getfile(const char *name, + const struct file_operations *fops, + void *priv, int flags) +{ + struct qstr this; + struct path path; + struct file *file; + struct inode *inode = NULL; + int rc; + + /* strongly inspired by anon_inode_getfile() */ + + if (fops->owner && !try_module_get(fops->owner)) + return ERR_PTR(-ENOENT); + + rc = simple_pin_fs(&cxl_fs_type, &cxl_vfs_mount, &cxl_fs_cnt); + if (rc < 0) { + pr_err("Cannot mount cxl pseudo filesystem: %d\n", rc); + file = ERR_PTR(rc); + goto err_module; + } + + inode = alloc_anon_inode(cxl_vfs_mount->mnt_sb); + if (IS_ERR(inode)) { + file = ERR_CAST(inode); + goto err_fs; + } + + file = ERR_PTR(-ENOMEM); + this.name = name; + this.len = strlen(name); + this.hash = 0; + path.dentry = d_alloc_pseudo(cxl_vfs_mount->mnt_sb, &this); + if (!path.dentry) + goto err_inode; + + path.mnt = mntget(cxl_vfs_mount); + d_instantiate(path.dentry, inode); + + file = alloc_file(&path, OPEN_FMODE(flags), fops); + if (IS_ERR(file)) + goto err_dput; + file->f_flags = flags & (O_ACCMODE | O_NONBLOCK); + file->private_data = priv; + + return file; + +err_dput: + path_put(&path); +err_inode: + iput(inode); +err_fs: + simple_release_fs(&cxl_vfs_mount, &cxl_fs_cnt); +err_module: + module_put(fops->owner); + return file; +} + struct cxl_context *cxl_dev_context_init(struct pci_dev *dev) { - struct address_space *mapping; struct cxl_afu *afu; struct cxl_context *ctx; int rc; @@ -30,38 +131,20 @@ struct cxl_context *cxl_dev_context_init(struct pci_dev *dev) return ERR_CAST(afu); ctx = cxl_context_alloc(); - if (IS_ERR(ctx)) { - rc = PTR_ERR(ctx); - goto err_dev; - } + if (!ctx) + return ERR_PTR(-ENOMEM); ctx->kernelapi = true; - /* - * Make our own address space since we won't have one from the - * filesystem like the user api has, and even if we do associate a file - * with this context we don't want to use the global anonymous inode's - * address space as that can invalidate unrelated users: - */ - mapping = kmalloc(sizeof(struct address_space), GFP_KERNEL); - if (!mapping) { - rc = -ENOMEM; - goto err_ctx; - } - address_space_init_once(mapping); - /* Make it a slave context. We can promote it later? */ - rc = cxl_context_init(ctx, afu, false, mapping); + rc = cxl_context_init(ctx, afu, false); if (rc) - goto err_mapping; + goto err_ctx; return ctx; -err_mapping: - kfree(mapping); err_ctx: kfree(ctx); -err_dev: return ERR_PTR(rc); } EXPORT_SYMBOL_GPL(cxl_dev_context_init); @@ -340,6 +423,11 @@ struct file *cxl_get_fd(struct cxl_context *ctx, struct file_operations *fops, { struct file *file; int rc, flags, fdtmp; + char *name = NULL; + + /* only allow one per context */ + if (ctx->mapping) + return ERR_PTR(-EEXIST); flags = O_RDWR | O_CLOEXEC; @@ -363,12 +451,13 @@ struct file *cxl_get_fd(struct cxl_context *ctx, struct file_operations *fops, } else /* use default ops */ fops = (struct file_operations *)&afu_fops; - file = anon_inode_getfile("cxl", fops, ctx, flags); + name = kasprintf(GFP_KERNEL, "cxl:%d", ctx->pe); + file = cxl_getfile(name, fops, ctx, flags); + kfree(name); if (IS_ERR(file)) goto err_fd; - file->f_mapping = ctx->mapping; - + cxl_context_set_mapping(ctx, file->f_mapping); *fd = fdtmp; return file; @@ -541,7 +630,7 @@ int _cxl_cx4_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) if (remaining > 0) { new_ctx = cxl_dev_context_init(pdev); - if (!new_ctx) { + if (IS_ERR(new_ctx)) { pr_warn("%s: Failed to allocate enough contexts for MSIs\n", pci_name(pdev)); return -ENOSPC; } diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c index 5d36dcc7f47e..3907387b6d15 100644 --- a/drivers/misc/cxl/context.c +++ b/drivers/misc/cxl/context.c @@ -34,8 +34,7 @@ struct cxl_context *cxl_context_alloc(void) /* * Initialises a CXL context. */ -int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master, - struct address_space *mapping) +int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master) { int i; @@ -44,7 +43,7 @@ int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master, ctx->master = master; ctx->pid = ctx->glpid = NULL; /* Set in start work ioctl */ mutex_init(&ctx->mapping_lock); - ctx->mapping = mapping; + ctx->mapping = NULL; /* * Allocate the segment table before we put it in the IDR so that we @@ -114,6 +113,14 @@ int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master, return 0; } +void cxl_context_set_mapping(struct cxl_context *ctx, + struct address_space *mapping) +{ + mutex_lock(&ctx->mapping_lock); + ctx->mapping = mapping; + mutex_unlock(&ctx->mapping_lock); +} + static int cxl_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct cxl_context *ctx = vma->vm_file->private_data; @@ -299,8 +306,6 @@ static void reclaim_ctx(struct rcu_head *rcu) if (ctx->ff_page) __free_page(ctx->ff_page); ctx->sstp = NULL; - if (ctx->kernelapi) - kfree(ctx->mapping); kfree(ctx->irq_bitmap); @@ -312,6 +317,8 @@ static void reclaim_ctx(struct rcu_head *rcu) void cxl_context_free(struct cxl_context *ctx) { + if (ctx->kernelapi && ctx->mapping) + cxl_release_mapping(ctx); mutex_lock(&ctx->afu->contexts_lock); idr_remove(&ctx->afu->contexts_idr, ctx->pe); mutex_unlock(&ctx->afu->contexts_lock); diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index a144073593fa..b24d76723fb0 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -817,8 +817,9 @@ void cxl_dump_debug_buffer(void *addr, size_t size); void init_cxl_native(void); struct cxl_context *cxl_context_alloc(void); -int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master, - struct address_space *mapping); +int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master); +void cxl_context_set_mapping(struct cxl_context *ctx, + struct address_space *mapping); void cxl_context_free(struct cxl_context *ctx); int cxl_context_iomap(struct cxl_context *ctx, struct vm_area_struct *vma); unsigned int cxl_map_irq(struct cxl *adapter, irq_hw_number_t hwirq, @@ -877,6 +878,7 @@ void cxl_native_err_irq_dump_regs(struct cxl *adapter); void cxl_stop_trace(struct cxl *cxl); int cxl_pci_vphb_add(struct cxl_afu *afu); void cxl_pci_vphb_remove(struct cxl_afu *afu); +void cxl_release_mapping(struct cxl_context *ctx); extern struct pci_driver cxl_pci_driver; extern struct platform_driver cxl_of_driver; diff --git a/drivers/misc/cxl/debugfs.c b/drivers/misc/cxl/debugfs.c index ec7b8a017439..9c06ac8fa5ac 100644 --- a/drivers/misc/cxl/debugfs.c +++ b/drivers/misc/cxl/debugfs.c @@ -43,12 +43,14 @@ static int debugfs_io_u64_set(void *data, u64 val) out_be64((u64 __iomem *)data, val); return 0; } -DEFINE_SIMPLE_ATTRIBUTE(fops_io_x64, debugfs_io_u64_get, debugfs_io_u64_set, "0x%016llx\n"); +DEFINE_DEBUGFS_ATTRIBUTE(fops_io_x64, debugfs_io_u64_get, debugfs_io_u64_set, + "0x%016llx\n"); static struct dentry *debugfs_create_io_x64(const char *name, umode_t mode, struct dentry *parent, u64 __iomem *value) { - return debugfs_create_file(name, mode, parent, (void __force *)value, &fops_io_x64); + return debugfs_create_file_unsafe(name, mode, parent, + (void __force *)value, &fops_io_x64); } void cxl_debugfs_add_adapter_psl_regs(struct cxl *adapter, struct dentry *dir) diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c index 77080cc5fa0a..859959f19f10 100644 --- a/drivers/misc/cxl/file.c +++ b/drivers/misc/cxl/file.c @@ -86,9 +86,12 @@ static int __afu_open(struct inode *inode, struct file *file, bool master) goto err_put_afu; } - if ((rc = cxl_context_init(ctx, afu, master, inode->i_mapping))) + rc = cxl_context_init(ctx, afu, master); + if (rc) goto err_put_afu; + cxl_context_set_mapping(ctx, inode->i_mapping); + pr_devel("afu_open pe: %i\n", ctx->pe); file->private_data = ctx; cxl_ctx_get(); diff --git a/drivers/misc/cxl/guest.c b/drivers/misc/cxl/guest.c index 3e102cd6ed91..e04bc4ddfd74 100644 --- a/drivers/misc/cxl/guest.c +++ b/drivers/misc/cxl/guest.c @@ -887,7 +887,7 @@ static void afu_handle_errstate(struct work_struct *work) afu_guest->previous_state == H_STATE_PERM_UNAVAILABLE) return; - if (afu_guest->handle_err == true) + if (afu_guest->handle_err) schedule_delayed_work(&afu_guest->work_err, msecs_to_jiffies(3000)); } diff --git a/drivers/misc/cxl/irq.c b/drivers/misc/cxl/irq.c index dec60f58a767..1a402bbed687 100644 --- a/drivers/misc/cxl/irq.c +++ b/drivers/misc/cxl/irq.c @@ -104,7 +104,7 @@ irqreturn_t cxl_irq(int irq, struct cxl_context *ctx, struct cxl_irq_info *irq_i } else { spin_lock(&ctx->lock); ctx->afu_err = irq_info->afu_err; - ctx->pending_afu_err = 1; + ctx->pending_afu_err = true; spin_unlock(&ctx->lock); wake_up_all(&ctx->wq); diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index a217a74ccc98..09505f432eda 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c @@ -10,7 +10,6 @@ #include <linux/spinlock.h> #include <linux/sched.h> #include <linux/slab.h> -#include <linux/sched.h> #include <linux/mutex.h> #include <linux/mm.h> #include <linux/uaccess.h> @@ -54,7 +53,7 @@ static int afu_control(struct cxl_afu *afu, u64 command, u64 clear, AFU_Cntl | command); cpu_relax(); AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An); - }; + } if (AFU_Cntl & CXL_AFU_Cntl_An_RA) { /* @@ -167,7 +166,7 @@ int cxl_psl_purge(struct cxl_afu *afu) cpu_relax(); } PSL_CNTL = cxl_p1n_read(afu, CXL_PSL_SCNTL_An); - }; + } end = local_clock(); pr_devel("PSL purged in %lld ns\n", end - start); @@ -931,9 +930,18 @@ static irqreturn_t native_irq_multiplexed(int irq, void *data) struct cxl_afu *afu = data; struct cxl_context *ctx; struct cxl_irq_info irq_info; - int ph = cxl_p2n_read(afu, CXL_PSL_PEHandle_An) & 0xffff; - int ret; - + u64 phreg = cxl_p2n_read(afu, CXL_PSL_PEHandle_An); + int ph, ret; + + /* check if eeh kicked in while the interrupt was in flight */ + if (unlikely(phreg == ~0ULL)) { + dev_warn(&afu->dev, + "Ignoring slice interrupt(%d) due to fenced card", + irq); + return IRQ_HANDLED; + } + /* Mask the pe-handle from register value */ + ph = phreg & 0xffff; if ((ret = native_get_irq_info(afu, &irq_info))) { WARN(1, "Unable to get CXL IRQ Info: %i\n", ret); return fail_psl_irq(afu, &irq_info); diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index e96be9ca4e60..80a87ab25b83 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -1921,7 +1921,7 @@ static pci_ers_result_t cxl_pci_slot_reset(struct pci_dev *pdev) goto err; ctx = cxl_dev_context_init(afu_dev); - if (!ctx) + if (IS_ERR(ctx)) goto err; afu_dev->dev.archdata.cxl_ctx = ctx; diff --git a/drivers/misc/cxl/phb.c b/drivers/misc/cxl/phb.c index 0935d44c1770..6ec69ada19f4 100644 --- a/drivers/misc/cxl/phb.c +++ b/drivers/misc/cxl/phb.c @@ -20,7 +20,7 @@ bool _cxl_pci_associate_default_context(struct pci_dev *dev, struct cxl_afu *afu * in the virtual phb, we'll need a default context to attach them to. */ ctx = cxl_dev_context_init(dev); - if (!ctx) + if (IS_ERR(ctx)) return false; dev->dev.archdata.cxl_ctx = ctx; |