xref: /openbmc/linux/drivers/misc/cxl/api.c (revision b810253b)
16f7f0b3dSMichael Neuling /*
26f7f0b3dSMichael Neuling  * Copyright 2014 IBM Corp.
36f7f0b3dSMichael Neuling  *
46f7f0b3dSMichael Neuling  * This program is free software; you can redistribute it and/or
56f7f0b3dSMichael Neuling  * modify it under the terms of the GNU General Public License
66f7f0b3dSMichael Neuling  * as published by the Free Software Foundation; either version
76f7f0b3dSMichael Neuling  * 2 of the License, or (at your option) any later version.
86f7f0b3dSMichael Neuling  */
96f7f0b3dSMichael Neuling 
106f7f0b3dSMichael Neuling #include <linux/pci.h>
116f7f0b3dSMichael Neuling #include <linux/slab.h>
126f7f0b3dSMichael Neuling #include <linux/anon_inodes.h>
136f7f0b3dSMichael Neuling #include <linux/file.h>
146f7f0b3dSMichael Neuling #include <misc/cxl.h>
1555e07668SIan Munsie #include <linux/fs.h>
166f7f0b3dSMichael Neuling 
176f7f0b3dSMichael Neuling #include "cxl.h"
186f7f0b3dSMichael Neuling 
196f7f0b3dSMichael Neuling struct cxl_context *cxl_dev_context_init(struct pci_dev *dev)
206f7f0b3dSMichael Neuling {
2155e07668SIan Munsie 	struct address_space *mapping;
226f7f0b3dSMichael Neuling 	struct cxl_afu *afu;
236f7f0b3dSMichael Neuling 	struct cxl_context  *ctx;
246f7f0b3dSMichael Neuling 	int rc;
256f7f0b3dSMichael Neuling 
266f7f0b3dSMichael Neuling 	afu = cxl_pci_to_afu(dev);
276f7f0b3dSMichael Neuling 
286f7f0b3dSMichael Neuling 	ctx = cxl_context_alloc();
29af2a50bbSIan Munsie 	if (IS_ERR(ctx)) {
30af2a50bbSIan Munsie 		rc = PTR_ERR(ctx);
31af2a50bbSIan Munsie 		goto err_dev;
32af2a50bbSIan Munsie 	}
336f7f0b3dSMichael Neuling 
3455e07668SIan Munsie 	ctx->kernelapi = true;
3555e07668SIan Munsie 
3655e07668SIan Munsie 	/*
3755e07668SIan Munsie 	 * Make our own address space since we won't have one from the
3855e07668SIan Munsie 	 * filesystem like the user api has, and even if we do associate a file
3955e07668SIan Munsie 	 * with this context we don't want to use the global anonymous inode's
4055e07668SIan Munsie 	 * address space as that can invalidate unrelated users:
4155e07668SIan Munsie 	 */
4255e07668SIan Munsie 	mapping = kmalloc(sizeof(struct address_space), GFP_KERNEL);
4355e07668SIan Munsie 	if (!mapping) {
4455e07668SIan Munsie 		rc = -ENOMEM;
45af2a50bbSIan Munsie 		goto err_ctx;
4655e07668SIan Munsie 	}
4755e07668SIan Munsie 	address_space_init_once(mapping);
4855e07668SIan Munsie 
4955e07668SIan Munsie 	/* Make it a slave context.  We can promote it later? */
5055e07668SIan Munsie 	rc = cxl_context_init(ctx, afu, false, mapping);
5155e07668SIan Munsie 	if (rc)
5255e07668SIan Munsie 		goto err_mapping;
5355e07668SIan Munsie 
546f7f0b3dSMichael Neuling 	return ctx;
55af2a50bbSIan Munsie 
5655e07668SIan Munsie err_mapping:
5755e07668SIan Munsie 	kfree(mapping);
58af2a50bbSIan Munsie err_ctx:
59af2a50bbSIan Munsie 	kfree(ctx);
60af2a50bbSIan Munsie err_dev:
61af2a50bbSIan Munsie 	return ERR_PTR(rc);
626f7f0b3dSMichael Neuling }
636f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_dev_context_init);
646f7f0b3dSMichael Neuling 
656f7f0b3dSMichael Neuling struct cxl_context *cxl_get_context(struct pci_dev *dev)
666f7f0b3dSMichael Neuling {
676f7f0b3dSMichael Neuling 	return dev->dev.archdata.cxl_ctx;
686f7f0b3dSMichael Neuling }
696f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_get_context);
706f7f0b3dSMichael Neuling 
716f7f0b3dSMichael Neuling int cxl_release_context(struct cxl_context *ctx)
726f7f0b3dSMichael Neuling {
737c26b9cfSAndrew Donnellan 	if (ctx->status >= STARTED)
746f7f0b3dSMichael Neuling 		return -EBUSY;
756f7f0b3dSMichael Neuling 
766f7f0b3dSMichael Neuling 	cxl_context_free(ctx);
776f7f0b3dSMichael Neuling 
786f7f0b3dSMichael Neuling 	return 0;
796f7f0b3dSMichael Neuling }
806f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_release_context);
816f7f0b3dSMichael Neuling 
826f7f0b3dSMichael Neuling static irq_hw_number_t cxl_find_afu_irq(struct cxl_context *ctx, int num)
836f7f0b3dSMichael Neuling {
846f7f0b3dSMichael Neuling 	__u16 range;
856f7f0b3dSMichael Neuling 	int r;
866f7f0b3dSMichael Neuling 
876f7f0b3dSMichael Neuling 	for (r = 0; r < CXL_IRQ_RANGES; r++) {
886f7f0b3dSMichael Neuling 		range = ctx->irqs.range[r];
896f7f0b3dSMichael Neuling 		if (num < range) {
906f7f0b3dSMichael Neuling 			return ctx->irqs.offset[r] + num;
916f7f0b3dSMichael Neuling 		}
926f7f0b3dSMichael Neuling 		num -= range;
936f7f0b3dSMichael Neuling 	}
946f7f0b3dSMichael Neuling 	return 0;
956f7f0b3dSMichael Neuling }
966f7f0b3dSMichael Neuling 
97d601ea91SFrederic Barrat int cxl_allocate_afu_irqs(struct cxl_context *ctx, int num)
98d601ea91SFrederic Barrat {
99d601ea91SFrederic Barrat 	int res;
100d601ea91SFrederic Barrat 	irq_hw_number_t hwirq;
101d601ea91SFrederic Barrat 
102d601ea91SFrederic Barrat 	if (num == 0)
103d601ea91SFrederic Barrat 		num = ctx->afu->pp_irqs;
104d601ea91SFrederic Barrat 	res = afu_allocate_irqs(ctx, num);
105292841b0SIan Munsie 	if (res)
106292841b0SIan Munsie 		return res;
107292841b0SIan Munsie 
108292841b0SIan Munsie 	if (!cpu_has_feature(CPU_FTR_HVMODE)) {
109d601ea91SFrederic Barrat 		/* In a guest, the PSL interrupt is not multiplexed. It was
110d601ea91SFrederic Barrat 		 * allocated above, and we need to set its handler
111d601ea91SFrederic Barrat 		 */
112d601ea91SFrederic Barrat 		hwirq = cxl_find_afu_irq(ctx, 0);
113d601ea91SFrederic Barrat 		if (hwirq)
114d601ea91SFrederic Barrat 			cxl_map_irq(ctx->afu->adapter, hwirq, cxl_ops->psl_interrupt, ctx, "psl");
115d601ea91SFrederic Barrat 	}
116292841b0SIan Munsie 
117292841b0SIan Munsie 	if (ctx->status == STARTED) {
118292841b0SIan Munsie 		if (cxl_ops->update_ivtes)
119292841b0SIan Munsie 			cxl_ops->update_ivtes(ctx);
120292841b0SIan Munsie 		else WARN(1, "BUG: cxl_allocate_afu_irqs must be called prior to starting the context on this platform\n");
121292841b0SIan Munsie 	}
122292841b0SIan Munsie 
123d601ea91SFrederic Barrat 	return res;
124d601ea91SFrederic Barrat }
125d601ea91SFrederic Barrat EXPORT_SYMBOL_GPL(cxl_allocate_afu_irqs);
126d601ea91SFrederic Barrat 
127d601ea91SFrederic Barrat void cxl_free_afu_irqs(struct cxl_context *ctx)
128d601ea91SFrederic Barrat {
129d601ea91SFrederic Barrat 	irq_hw_number_t hwirq;
130d601ea91SFrederic Barrat 	unsigned int virq;
131d601ea91SFrederic Barrat 
132d601ea91SFrederic Barrat 	if (!cpu_has_feature(CPU_FTR_HVMODE)) {
133d601ea91SFrederic Barrat 		hwirq = cxl_find_afu_irq(ctx, 0);
134d601ea91SFrederic Barrat 		if (hwirq) {
135d601ea91SFrederic Barrat 			virq = irq_find_mapping(NULL, hwirq);
136d601ea91SFrederic Barrat 			if (virq)
137d601ea91SFrederic Barrat 				cxl_unmap_irq(virq, ctx);
138d601ea91SFrederic Barrat 		}
139d601ea91SFrederic Barrat 	}
140d601ea91SFrederic Barrat 	afu_irq_name_free(ctx);
141d601ea91SFrederic Barrat 	cxl_ops->release_irq_ranges(&ctx->irqs, ctx->afu->adapter);
142d601ea91SFrederic Barrat }
143d601ea91SFrederic Barrat EXPORT_SYMBOL_GPL(cxl_free_afu_irqs);
144d601ea91SFrederic Barrat 
1456f7f0b3dSMichael Neuling int cxl_map_afu_irq(struct cxl_context *ctx, int num,
1466f7f0b3dSMichael Neuling 		    irq_handler_t handler, void *cookie, char *name)
1476f7f0b3dSMichael Neuling {
1486f7f0b3dSMichael Neuling 	irq_hw_number_t hwirq;
1496f7f0b3dSMichael Neuling 
1506f7f0b3dSMichael Neuling 	/*
1516f7f0b3dSMichael Neuling 	 * Find interrupt we are to register.
1526f7f0b3dSMichael Neuling 	 */
1536f7f0b3dSMichael Neuling 	hwirq = cxl_find_afu_irq(ctx, num);
1546f7f0b3dSMichael Neuling 	if (!hwirq)
1556f7f0b3dSMichael Neuling 		return -ENOENT;
1566f7f0b3dSMichael Neuling 
1576f7f0b3dSMichael Neuling 	return cxl_map_irq(ctx->afu->adapter, hwirq, handler, cookie, name);
1586f7f0b3dSMichael Neuling }
1596f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_map_afu_irq);
1606f7f0b3dSMichael Neuling 
1616f7f0b3dSMichael Neuling void cxl_unmap_afu_irq(struct cxl_context *ctx, int num, void *cookie)
1626f7f0b3dSMichael Neuling {
1636f7f0b3dSMichael Neuling 	irq_hw_number_t hwirq;
1646f7f0b3dSMichael Neuling 	unsigned int virq;
1656f7f0b3dSMichael Neuling 
1666f7f0b3dSMichael Neuling 	hwirq = cxl_find_afu_irq(ctx, num);
1676f7f0b3dSMichael Neuling 	if (!hwirq)
1686f7f0b3dSMichael Neuling 		return;
1696f7f0b3dSMichael Neuling 
1706f7f0b3dSMichael Neuling 	virq = irq_find_mapping(NULL, hwirq);
1716f7f0b3dSMichael Neuling 	if (virq)
1726f7f0b3dSMichael Neuling 		cxl_unmap_irq(virq, cookie);
1736f7f0b3dSMichael Neuling }
1746f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_unmap_afu_irq);
1756f7f0b3dSMichael Neuling 
1766f7f0b3dSMichael Neuling /*
1776f7f0b3dSMichael Neuling  * Start a context
1786f7f0b3dSMichael Neuling  * Code here similar to afu_ioctl_start_work().
1796f7f0b3dSMichael Neuling  */
1806f7f0b3dSMichael Neuling int cxl_start_context(struct cxl_context *ctx, u64 wed,
1816f7f0b3dSMichael Neuling 		      struct task_struct *task)
1826f7f0b3dSMichael Neuling {
1836f7f0b3dSMichael Neuling 	int rc = 0;
1846f7f0b3dSMichael Neuling 	bool kernel = true;
1856f7f0b3dSMichael Neuling 
1866f7f0b3dSMichael Neuling 	pr_devel("%s: pe: %i\n", __func__, ctx->pe);
1876f7f0b3dSMichael Neuling 
1886f7f0b3dSMichael Neuling 	mutex_lock(&ctx->status_mutex);
1896f7f0b3dSMichael Neuling 	if (ctx->status == STARTED)
1906f7f0b3dSMichael Neuling 		goto out; /* already started */
1916f7f0b3dSMichael Neuling 
1926f7f0b3dSMichael Neuling 	if (task) {
1936f7f0b3dSMichael Neuling 		ctx->pid = get_task_pid(task, PIDTYPE_PID);
1947b8ad495SVaibhav Jain 		ctx->glpid = get_task_pid(task->group_leader, PIDTYPE_PID);
1956f7f0b3dSMichael Neuling 		kernel = false;
1967a0d85d3SIan Munsie 		ctx->real_mode = false;
1976f7f0b3dSMichael Neuling 	}
1986f7f0b3dSMichael Neuling 
1996f7f0b3dSMichael Neuling 	cxl_ctx_get();
2006f7f0b3dSMichael Neuling 
2015be587b1SFrederic Barrat 	if ((rc = cxl_ops->attach_process(ctx, kernel, wed, 0))) {
2026f7f0b3dSMichael Neuling 		put_pid(ctx->pid);
2036f7f0b3dSMichael Neuling 		cxl_ctx_put();
2046f7f0b3dSMichael Neuling 		goto out;
2056f7f0b3dSMichael Neuling 	}
2066f7f0b3dSMichael Neuling 
2076f7f0b3dSMichael Neuling 	ctx->status = STARTED;
2086f7f0b3dSMichael Neuling out:
2096f7f0b3dSMichael Neuling 	mutex_unlock(&ctx->status_mutex);
2106f7f0b3dSMichael Neuling 	return rc;
2116f7f0b3dSMichael Neuling }
2126f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_start_context);
2136f7f0b3dSMichael Neuling 
2146f7f0b3dSMichael Neuling int cxl_process_element(struct cxl_context *ctx)
2156f7f0b3dSMichael Neuling {
21614baf4d9SChristophe Lombard 	return ctx->external_pe;
2176f7f0b3dSMichael Neuling }
2186f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_process_element);
2196f7f0b3dSMichael Neuling 
2206f7f0b3dSMichael Neuling /* Stop a context.  Returns 0 on success, otherwise -Errno */
2216f7f0b3dSMichael Neuling int cxl_stop_context(struct cxl_context *ctx)
2226f7f0b3dSMichael Neuling {
2233f8dc44dSMichael Neuling 	return __detach_context(ctx);
2246f7f0b3dSMichael Neuling }
2256f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_stop_context);
2266f7f0b3dSMichael Neuling 
2276f7f0b3dSMichael Neuling void cxl_set_master(struct cxl_context *ctx)
2286f7f0b3dSMichael Neuling {
2296f7f0b3dSMichael Neuling 	ctx->master = true;
2306f7f0b3dSMichael Neuling }
2316f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_set_master);
2326f7f0b3dSMichael Neuling 
2337a0d85d3SIan Munsie int cxl_set_translation_mode(struct cxl_context *ctx, bool real_mode)
2347a0d85d3SIan Munsie {
2357a0d85d3SIan Munsie 	if (ctx->status == STARTED) {
2367a0d85d3SIan Munsie 		/*
2377a0d85d3SIan Munsie 		 * We could potentially update the PE and issue an update LLCMD
2387a0d85d3SIan Munsie 		 * to support this, but it doesn't seem to have a good use case
2397a0d85d3SIan Munsie 		 * since it's trivial to just create a second kernel context
2407a0d85d3SIan Munsie 		 * with different translation modes, so until someone convinces
2417a0d85d3SIan Munsie 		 * me otherwise:
2427a0d85d3SIan Munsie 		 */
2437a0d85d3SIan Munsie 		return -EBUSY;
2447a0d85d3SIan Munsie 	}
2457a0d85d3SIan Munsie 
2467a0d85d3SIan Munsie 	ctx->real_mode = real_mode;
2477a0d85d3SIan Munsie 	return 0;
2487a0d85d3SIan Munsie }
2497a0d85d3SIan Munsie EXPORT_SYMBOL_GPL(cxl_set_translation_mode);
2507a0d85d3SIan Munsie 
2516f7f0b3dSMichael Neuling /* wrappers around afu_* file ops which are EXPORTED */
2526f7f0b3dSMichael Neuling int cxl_fd_open(struct inode *inode, struct file *file)
2536f7f0b3dSMichael Neuling {
2546f7f0b3dSMichael Neuling 	return afu_open(inode, file);
2556f7f0b3dSMichael Neuling }
2566f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_fd_open);
2576f7f0b3dSMichael Neuling int cxl_fd_release(struct inode *inode, struct file *file)
2586f7f0b3dSMichael Neuling {
2596f7f0b3dSMichael Neuling 	return afu_release(inode, file);
2606f7f0b3dSMichael Neuling }
2616f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_fd_release);
2626f7f0b3dSMichael Neuling long cxl_fd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
2636f7f0b3dSMichael Neuling {
2646f7f0b3dSMichael Neuling 	return afu_ioctl(file, cmd, arg);
2656f7f0b3dSMichael Neuling }
2666f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_fd_ioctl);
2676f7f0b3dSMichael Neuling int cxl_fd_mmap(struct file *file, struct vm_area_struct *vm)
2686f7f0b3dSMichael Neuling {
2696f7f0b3dSMichael Neuling 	return afu_mmap(file, vm);
2706f7f0b3dSMichael Neuling }
2716f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_fd_mmap);
2726f7f0b3dSMichael Neuling unsigned int cxl_fd_poll(struct file *file, struct poll_table_struct *poll)
2736f7f0b3dSMichael Neuling {
2746f7f0b3dSMichael Neuling 	return afu_poll(file, poll);
2756f7f0b3dSMichael Neuling }
2766f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_fd_poll);
2776f7f0b3dSMichael Neuling ssize_t cxl_fd_read(struct file *file, char __user *buf, size_t count,
2786f7f0b3dSMichael Neuling 			loff_t *off)
2796f7f0b3dSMichael Neuling {
2806f7f0b3dSMichael Neuling 	return afu_read(file, buf, count, off);
2816f7f0b3dSMichael Neuling }
2826f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_fd_read);
2836f7f0b3dSMichael Neuling 
2846f7f0b3dSMichael Neuling #define PATCH_FOPS(NAME) if (!fops->NAME) fops->NAME = afu_fops.NAME
2856f7f0b3dSMichael Neuling 
2866f7f0b3dSMichael Neuling /* Get a struct file and fd for a context and attach the ops */
2876f7f0b3dSMichael Neuling struct file *cxl_get_fd(struct cxl_context *ctx, struct file_operations *fops,
2886f7f0b3dSMichael Neuling 			int *fd)
2896f7f0b3dSMichael Neuling {
2906f7f0b3dSMichael Neuling 	struct file *file;
2916f7f0b3dSMichael Neuling 	int rc, flags, fdtmp;
2926f7f0b3dSMichael Neuling 
2936f7f0b3dSMichael Neuling 	flags = O_RDWR | O_CLOEXEC;
2946f7f0b3dSMichael Neuling 
2956f7f0b3dSMichael Neuling 	/* This code is similar to anon_inode_getfd() */
2966f7f0b3dSMichael Neuling 	rc = get_unused_fd_flags(flags);
2976f7f0b3dSMichael Neuling 	if (rc < 0)
2986f7f0b3dSMichael Neuling 		return ERR_PTR(rc);
2996f7f0b3dSMichael Neuling 	fdtmp = rc;
3006f7f0b3dSMichael Neuling 
3016f7f0b3dSMichael Neuling 	/*
3026f7f0b3dSMichael Neuling 	 * Patch the file ops.  Needs to be careful that this is rentrant safe.
3036f7f0b3dSMichael Neuling 	 */
3046f7f0b3dSMichael Neuling 	if (fops) {
3056f7f0b3dSMichael Neuling 		PATCH_FOPS(open);
3066f7f0b3dSMichael Neuling 		PATCH_FOPS(poll);
3076f7f0b3dSMichael Neuling 		PATCH_FOPS(read);
3086f7f0b3dSMichael Neuling 		PATCH_FOPS(release);
3096f7f0b3dSMichael Neuling 		PATCH_FOPS(unlocked_ioctl);
3106f7f0b3dSMichael Neuling 		PATCH_FOPS(compat_ioctl);
3116f7f0b3dSMichael Neuling 		PATCH_FOPS(mmap);
3126f7f0b3dSMichael Neuling 	} else /* use default ops */
3136f7f0b3dSMichael Neuling 		fops = (struct file_operations *)&afu_fops;
3146f7f0b3dSMichael Neuling 
3156f7f0b3dSMichael Neuling 	file = anon_inode_getfile("cxl", fops, ctx, flags);
3166f7f0b3dSMichael Neuling 	if (IS_ERR(file))
31755e07668SIan Munsie 		goto err_fd;
31855e07668SIan Munsie 
31955e07668SIan Munsie 	file->f_mapping = ctx->mapping;
32055e07668SIan Munsie 
3216f7f0b3dSMichael Neuling 	*fd = fdtmp;
3226f7f0b3dSMichael Neuling 	return file;
32355e07668SIan Munsie 
32455e07668SIan Munsie err_fd:
32555e07668SIan Munsie 	put_unused_fd(fdtmp);
32655e07668SIan Munsie 	return NULL;
3276f7f0b3dSMichael Neuling }
3286f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_get_fd);
3296f7f0b3dSMichael Neuling 
3306f7f0b3dSMichael Neuling struct cxl_context *cxl_fops_get_context(struct file *file)
3316f7f0b3dSMichael Neuling {
3326f7f0b3dSMichael Neuling 	return file->private_data;
3336f7f0b3dSMichael Neuling }
3346f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_fops_get_context);
3356f7f0b3dSMichael Neuling 
336b810253bSPhilippe Bergheaud void cxl_set_driver_ops(struct cxl_context *ctx,
337b810253bSPhilippe Bergheaud 			struct cxl_afu_driver_ops *ops)
338b810253bSPhilippe Bergheaud {
339b810253bSPhilippe Bergheaud 	WARN_ON(!ops->fetch_event || !ops->event_delivered);
340b810253bSPhilippe Bergheaud 	atomic_set(&ctx->afu_driver_events, 0);
341b810253bSPhilippe Bergheaud 	ctx->afu_driver_ops = ops;
342b810253bSPhilippe Bergheaud }
343b810253bSPhilippe Bergheaud EXPORT_SYMBOL_GPL(cxl_set_driver_ops);
344b810253bSPhilippe Bergheaud 
345b810253bSPhilippe Bergheaud void cxl_context_events_pending(struct cxl_context *ctx,
346b810253bSPhilippe Bergheaud 				unsigned int new_events)
347b810253bSPhilippe Bergheaud {
348b810253bSPhilippe Bergheaud 	atomic_add(new_events, &ctx->afu_driver_events);
349b810253bSPhilippe Bergheaud 	wake_up_all(&ctx->wq);
350b810253bSPhilippe Bergheaud }
351b810253bSPhilippe Bergheaud EXPORT_SYMBOL_GPL(cxl_context_events_pending);
352b810253bSPhilippe Bergheaud 
3536f7f0b3dSMichael Neuling int cxl_start_work(struct cxl_context *ctx,
3546f7f0b3dSMichael Neuling 		   struct cxl_ioctl_start_work *work)
3556f7f0b3dSMichael Neuling {
3566f7f0b3dSMichael Neuling 	int rc;
3576f7f0b3dSMichael Neuling 
3586f7f0b3dSMichael Neuling 	/* code taken from afu_ioctl_start_work */
3596f7f0b3dSMichael Neuling 	if (!(work->flags & CXL_START_WORK_NUM_IRQS))
3606f7f0b3dSMichael Neuling 		work->num_interrupts = ctx->afu->pp_irqs;
3616f7f0b3dSMichael Neuling 	else if ((work->num_interrupts < ctx->afu->pp_irqs) ||
3626f7f0b3dSMichael Neuling 		 (work->num_interrupts > ctx->afu->irqs_max)) {
3636f7f0b3dSMichael Neuling 		return -EINVAL;
3646f7f0b3dSMichael Neuling 	}
3656f7f0b3dSMichael Neuling 
3666f7f0b3dSMichael Neuling 	rc = afu_register_irqs(ctx, work->num_interrupts);
3676f7f0b3dSMichael Neuling 	if (rc)
3686f7f0b3dSMichael Neuling 		return rc;
3696f7f0b3dSMichael Neuling 
3706f7f0b3dSMichael Neuling 	rc = cxl_start_context(ctx, work->work_element_descriptor, current);
3716f7f0b3dSMichael Neuling 	if (rc < 0) {
3726f7f0b3dSMichael Neuling 		afu_release_irqs(ctx, ctx);
3736f7f0b3dSMichael Neuling 		return rc;
3746f7f0b3dSMichael Neuling 	}
3756f7f0b3dSMichael Neuling 
3766f7f0b3dSMichael Neuling 	return 0;
3776f7f0b3dSMichael Neuling }
3786f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_start_work);
3796f7f0b3dSMichael Neuling 
3806f7f0b3dSMichael Neuling void __iomem *cxl_psa_map(struct cxl_context *ctx)
3816f7f0b3dSMichael Neuling {
382cca44c01SFrederic Barrat 	if (ctx->status != STARTED)
3836f7f0b3dSMichael Neuling 		return NULL;
3846f7f0b3dSMichael Neuling 
3856f7f0b3dSMichael Neuling 	pr_devel("%s: psn_phys%llx size:%llx\n",
386cca44c01SFrederic Barrat 		__func__, ctx->psn_phys, ctx->psn_size);
3876f7f0b3dSMichael Neuling 	return ioremap(ctx->psn_phys, ctx->psn_size);
3886f7f0b3dSMichael Neuling }
3896f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_psa_map);
3906f7f0b3dSMichael Neuling 
3916f7f0b3dSMichael Neuling void cxl_psa_unmap(void __iomem *addr)
3926f7f0b3dSMichael Neuling {
3936f7f0b3dSMichael Neuling 	iounmap(addr);
3946f7f0b3dSMichael Neuling }
3956f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_psa_unmap);
3966f7f0b3dSMichael Neuling 
3976f7f0b3dSMichael Neuling int cxl_afu_reset(struct cxl_context *ctx)
3986f7f0b3dSMichael Neuling {
3996f7f0b3dSMichael Neuling 	struct cxl_afu *afu = ctx->afu;
4006f7f0b3dSMichael Neuling 	int rc;
4016f7f0b3dSMichael Neuling 
4025be587b1SFrederic Barrat 	rc = cxl_ops->afu_reset(afu);
4036f7f0b3dSMichael Neuling 	if (rc)
4046f7f0b3dSMichael Neuling 		return rc;
4056f7f0b3dSMichael Neuling 
4065be587b1SFrederic Barrat 	return cxl_ops->afu_check_and_enable(afu);
4076f7f0b3dSMichael Neuling }
4086f7f0b3dSMichael Neuling EXPORT_SYMBOL_GPL(cxl_afu_reset);
40913e68d8bSDaniel Axtens 
41013e68d8bSDaniel Axtens void cxl_perst_reloads_same_image(struct cxl_afu *afu,
41113e68d8bSDaniel Axtens 				  bool perst_reloads_same_image)
41213e68d8bSDaniel Axtens {
41313e68d8bSDaniel Axtens 	afu->adapter->perst_same_image = perst_reloads_same_image;
41413e68d8bSDaniel Axtens }
41513e68d8bSDaniel Axtens EXPORT_SYMBOL_GPL(cxl_perst_reloads_same_image);
416d601ea91SFrederic Barrat 
417d601ea91SFrederic Barrat ssize_t cxl_read_adapter_vpd(struct pci_dev *dev, void *buf, size_t count)
418d601ea91SFrederic Barrat {
419d601ea91SFrederic Barrat 	struct cxl_afu *afu = cxl_pci_to_afu(dev);
420d601ea91SFrederic Barrat 
421d601ea91SFrederic Barrat 	return cxl_ops->read_adapter_vpd(afu->adapter, buf, count);
422d601ea91SFrederic Barrat }
423d601ea91SFrederic Barrat EXPORT_SYMBOL_GPL(cxl_read_adapter_vpd);
424