12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
276ebe01fSUma Krishnan /*
376ebe01fSUma Krishnan * CXL Flash Device Driver
476ebe01fSUma Krishnan *
576ebe01fSUma Krishnan * Written by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation
676ebe01fSUma Krishnan * Uma Krishnan <ukrishn@linux.vnet.ibm.com>, IBM Corporation
776ebe01fSUma Krishnan *
876ebe01fSUma Krishnan * Copyright (C) 2018 IBM Corporation
976ebe01fSUma Krishnan */
1076ebe01fSUma Krishnan
11926a62f9SUma Krishnan #include <linux/file.h>
12429ebfa6SUma Krishnan #include <linux/idr.h>
13926a62f9SUma Krishnan #include <linux/module.h>
14926a62f9SUma Krishnan #include <linux/mount.h>
15219e6963SDavid Howells #include <linux/pseudo_fs.h>
1656f1db1aSUma Krishnan #include <linux/poll.h>
1703aa9c51SUma Krishnan #include <linux/sched/signal.h>
181e89da5eSFrederic Barrat #include <linux/interrupt.h>
1961657dcdSChristophe Leroy #include <linux/irqdomain.h>
201e89da5eSFrederic Barrat #include <asm/xive.h>
2176ebe01fSUma Krishnan #include <misc/ocxl.h>
2276ebe01fSUma Krishnan
2303aa9c51SUma Krishnan #include <uapi/misc/cxl.h>
2403aa9c51SUma Krishnan
2576ebe01fSUma Krishnan #include "backend.h"
2648e077dbSUma Krishnan #include "ocxl_hw.h"
2748e077dbSUma Krishnan
28926a62f9SUma Krishnan /*
29926a62f9SUma Krishnan * Pseudo-filesystem to allocate inodes.
30926a62f9SUma Krishnan */
31926a62f9SUma Krishnan
32926a62f9SUma Krishnan #define OCXLFLASH_FS_MAGIC 0x1697698f
33926a62f9SUma Krishnan
34926a62f9SUma Krishnan static int ocxlflash_fs_cnt;
35926a62f9SUma Krishnan static struct vfsmount *ocxlflash_vfs_mount;
36926a62f9SUma Krishnan
ocxlflash_fs_init_fs_context(struct fs_context * fc)37219e6963SDavid Howells static int ocxlflash_fs_init_fs_context(struct fs_context *fc)
38926a62f9SUma Krishnan {
39219e6963SDavid Howells return init_pseudo(fc, OCXLFLASH_FS_MAGIC) ? 0 : -ENOMEM;
40926a62f9SUma Krishnan }
41926a62f9SUma Krishnan
42926a62f9SUma Krishnan static struct file_system_type ocxlflash_fs_type = {
43926a62f9SUma Krishnan .name = "ocxlflash",
44926a62f9SUma Krishnan .owner = THIS_MODULE,
45219e6963SDavid Howells .init_fs_context = ocxlflash_fs_init_fs_context,
46926a62f9SUma Krishnan .kill_sb = kill_anon_super,
47926a62f9SUma Krishnan };
48926a62f9SUma Krishnan
49926a62f9SUma Krishnan /*
50926a62f9SUma Krishnan * ocxlflash_release_mapping() - release the memory mapping
51926a62f9SUma Krishnan * @ctx: Context whose mapping is to be released.
52926a62f9SUma Krishnan */
ocxlflash_release_mapping(struct ocxlflash_context * ctx)53926a62f9SUma Krishnan static void ocxlflash_release_mapping(struct ocxlflash_context *ctx)
54926a62f9SUma Krishnan {
55926a62f9SUma Krishnan if (ctx->mapping)
56926a62f9SUma Krishnan simple_release_fs(&ocxlflash_vfs_mount, &ocxlflash_fs_cnt);
57926a62f9SUma Krishnan ctx->mapping = NULL;
58926a62f9SUma Krishnan }
59926a62f9SUma Krishnan
60926a62f9SUma Krishnan /*
61926a62f9SUma Krishnan * ocxlflash_getfile() - allocate pseudo filesystem, inode, and the file
62926a62f9SUma Krishnan * @dev: Generic device of the host.
63926a62f9SUma Krishnan * @name: Name of the pseudo filesystem.
64926a62f9SUma Krishnan * @fops: File operations.
65926a62f9SUma Krishnan * @priv: Private data.
66926a62f9SUma Krishnan * @flags: Flags for the file.
67926a62f9SUma Krishnan *
68926a62f9SUma Krishnan * Return: pointer to the file on success, ERR_PTR on failure
69926a62f9SUma Krishnan */
ocxlflash_getfile(struct device * dev,const char * name,const struct file_operations * fops,void * priv,int flags)70926a62f9SUma Krishnan static struct file *ocxlflash_getfile(struct device *dev, const char *name,
71926a62f9SUma Krishnan const struct file_operations *fops,
72926a62f9SUma Krishnan void *priv, int flags)
73926a62f9SUma Krishnan {
74926a62f9SUma Krishnan struct file *file;
75118f4868SAl Viro struct inode *inode;
76926a62f9SUma Krishnan int rc;
77926a62f9SUma Krishnan
78926a62f9SUma Krishnan if (fops->owner && !try_module_get(fops->owner)) {
79926a62f9SUma Krishnan dev_err(dev, "%s: Owner does not exist\n", __func__);
80926a62f9SUma Krishnan rc = -ENOENT;
81926a62f9SUma Krishnan goto err1;
82926a62f9SUma Krishnan }
83926a62f9SUma Krishnan
84926a62f9SUma Krishnan rc = simple_pin_fs(&ocxlflash_fs_type, &ocxlflash_vfs_mount,
85926a62f9SUma Krishnan &ocxlflash_fs_cnt);
86926a62f9SUma Krishnan if (unlikely(rc < 0)) {
87926a62f9SUma Krishnan dev_err(dev, "%s: Cannot mount ocxlflash pseudofs rc=%d\n",
88926a62f9SUma Krishnan __func__, rc);
89926a62f9SUma Krishnan goto err2;
90926a62f9SUma Krishnan }
91926a62f9SUma Krishnan
92926a62f9SUma Krishnan inode = alloc_anon_inode(ocxlflash_vfs_mount->mnt_sb);
93926a62f9SUma Krishnan if (IS_ERR(inode)) {
94926a62f9SUma Krishnan rc = PTR_ERR(inode);
95926a62f9SUma Krishnan dev_err(dev, "%s: alloc_anon_inode failed rc=%d\n",
96926a62f9SUma Krishnan __func__, rc);
97926a62f9SUma Krishnan goto err3;
98926a62f9SUma Krishnan }
99926a62f9SUma Krishnan
100118f4868SAl Viro file = alloc_file_pseudo(inode, ocxlflash_vfs_mount, name,
101118f4868SAl Viro flags & (O_ACCMODE | O_NONBLOCK), fops);
102926a62f9SUma Krishnan if (IS_ERR(file)) {
103926a62f9SUma Krishnan rc = PTR_ERR(file);
104926a62f9SUma Krishnan dev_err(dev, "%s: alloc_file failed rc=%d\n",
105926a62f9SUma Krishnan __func__, rc);
106118f4868SAl Viro goto err4;
107926a62f9SUma Krishnan }
108926a62f9SUma Krishnan
109926a62f9SUma Krishnan file->private_data = priv;
110926a62f9SUma Krishnan out:
111926a62f9SUma Krishnan return file;
112926a62f9SUma Krishnan err4:
113926a62f9SUma Krishnan iput(inode);
114926a62f9SUma Krishnan err3:
115926a62f9SUma Krishnan simple_release_fs(&ocxlflash_vfs_mount, &ocxlflash_fs_cnt);
116926a62f9SUma Krishnan err2:
117926a62f9SUma Krishnan module_put(fops->owner);
118926a62f9SUma Krishnan err1:
119926a62f9SUma Krishnan file = ERR_PTR(rc);
120926a62f9SUma Krishnan goto out;
121926a62f9SUma Krishnan }
122926a62f9SUma Krishnan
12348e077dbSUma Krishnan /**
124012f394cSUma Krishnan * ocxlflash_psa_map() - map the process specific MMIO space
125012f394cSUma Krishnan * @ctx_cookie: Adapter context for which the mapping needs to be done.
126012f394cSUma Krishnan *
127012f394cSUma Krishnan * Return: MMIO pointer of the mapped region
128012f394cSUma Krishnan */
ocxlflash_psa_map(void * ctx_cookie)129012f394cSUma Krishnan static void __iomem *ocxlflash_psa_map(void *ctx_cookie)
130012f394cSUma Krishnan {
131012f394cSUma Krishnan struct ocxlflash_context *ctx = ctx_cookie;
132f81face7SUma Krishnan struct device *dev = ctx->hw_afu->dev;
133f81face7SUma Krishnan
134f81face7SUma Krishnan mutex_lock(&ctx->state_mutex);
135f81face7SUma Krishnan if (ctx->state != STARTED) {
136f81face7SUma Krishnan dev_err(dev, "%s: Context not started, state=%d\n", __func__,
137f81face7SUma Krishnan ctx->state);
138f81face7SUma Krishnan mutex_unlock(&ctx->state_mutex);
139f81face7SUma Krishnan return NULL;
140f81face7SUma Krishnan }
141f81face7SUma Krishnan mutex_unlock(&ctx->state_mutex);
142012f394cSUma Krishnan
143012f394cSUma Krishnan return ioremap(ctx->psn_phys, ctx->psn_size);
144012f394cSUma Krishnan }
145012f394cSUma Krishnan
146012f394cSUma Krishnan /**
147012f394cSUma Krishnan * ocxlflash_psa_unmap() - unmap the process specific MMIO space
148012f394cSUma Krishnan * @addr: MMIO pointer to unmap.
149012f394cSUma Krishnan */
ocxlflash_psa_unmap(void __iomem * addr)150012f394cSUma Krishnan static void ocxlflash_psa_unmap(void __iomem *addr)
151012f394cSUma Krishnan {
152012f394cSUma Krishnan iounmap(addr);
153012f394cSUma Krishnan }
154012f394cSUma Krishnan
155012f394cSUma Krishnan /**
156b18718c6SUma Krishnan * ocxlflash_process_element() - get process element of the adapter context
157b18718c6SUma Krishnan * @ctx_cookie: Adapter context associated with the process element.
158b18718c6SUma Krishnan *
159b18718c6SUma Krishnan * Return: process element of the adapter context
160b18718c6SUma Krishnan */
ocxlflash_process_element(void * ctx_cookie)161b18718c6SUma Krishnan static int ocxlflash_process_element(void *ctx_cookie)
162b18718c6SUma Krishnan {
163b18718c6SUma Krishnan struct ocxlflash_context *ctx = ctx_cookie;
164b18718c6SUma Krishnan
165b18718c6SUma Krishnan return ctx->pe;
166b18718c6SUma Krishnan }
167b18718c6SUma Krishnan
168b18718c6SUma Krishnan /**
169a06b1cfcSUma Krishnan * afu_map_irq() - map the interrupt of the adapter context
170a06b1cfcSUma Krishnan * @flags: Flags.
171a06b1cfcSUma Krishnan * @ctx: Adapter context.
172a06b1cfcSUma Krishnan * @num: Per-context AFU interrupt number.
173a06b1cfcSUma Krishnan * @handler: Interrupt handler to register.
174a06b1cfcSUma Krishnan * @cookie: Interrupt handler private data.
175a06b1cfcSUma Krishnan * @name: Name of the interrupt.
176a06b1cfcSUma Krishnan *
177a06b1cfcSUma Krishnan * Return: 0 on success, -errno on failure
178a06b1cfcSUma Krishnan */
afu_map_irq(u64 flags,struct ocxlflash_context * ctx,int num,irq_handler_t handler,void * cookie,char * name)179a06b1cfcSUma Krishnan static int afu_map_irq(u64 flags, struct ocxlflash_context *ctx, int num,
180a06b1cfcSUma Krishnan irq_handler_t handler, void *cookie, char *name)
181a06b1cfcSUma Krishnan {
182a06b1cfcSUma Krishnan struct ocxl_hw_afu *afu = ctx->hw_afu;
183a06b1cfcSUma Krishnan struct device *dev = afu->dev;
184a06b1cfcSUma Krishnan struct ocxlflash_irqs *irq;
1851e89da5eSFrederic Barrat struct xive_irq_data *xd;
186a06b1cfcSUma Krishnan u32 virq;
187a06b1cfcSUma Krishnan int rc = 0;
188a06b1cfcSUma Krishnan
189a06b1cfcSUma Krishnan if (num < 0 || num >= ctx->num_irqs) {
190a06b1cfcSUma Krishnan dev_err(dev, "%s: Interrupt %d not allocated\n", __func__, num);
191a06b1cfcSUma Krishnan rc = -ENOENT;
192a06b1cfcSUma Krishnan goto out;
193a06b1cfcSUma Krishnan }
194a06b1cfcSUma Krishnan
195a06b1cfcSUma Krishnan irq = &ctx->irqs[num];
196a06b1cfcSUma Krishnan virq = irq_create_mapping(NULL, irq->hwirq);
197a06b1cfcSUma Krishnan if (unlikely(!virq)) {
198a06b1cfcSUma Krishnan dev_err(dev, "%s: irq_create_mapping failed\n", __func__);
199a06b1cfcSUma Krishnan rc = -ENOMEM;
200a06b1cfcSUma Krishnan goto out;
201a06b1cfcSUma Krishnan }
202a06b1cfcSUma Krishnan
203a06b1cfcSUma Krishnan rc = request_irq(virq, handler, 0, name, cookie);
204a06b1cfcSUma Krishnan if (unlikely(rc)) {
205a06b1cfcSUma Krishnan dev_err(dev, "%s: request_irq failed rc=%d\n", __func__, rc);
206a06b1cfcSUma Krishnan goto err1;
207a06b1cfcSUma Krishnan }
208a06b1cfcSUma Krishnan
2091e89da5eSFrederic Barrat xd = irq_get_handler_data(virq);
2101e89da5eSFrederic Barrat if (unlikely(!xd)) {
2111e89da5eSFrederic Barrat dev_err(dev, "%s: Can't get interrupt data\n", __func__);
2121e89da5eSFrederic Barrat rc = -ENXIO;
213a06b1cfcSUma Krishnan goto err2;
214a06b1cfcSUma Krishnan }
215a06b1cfcSUma Krishnan
216a06b1cfcSUma Krishnan irq->virq = virq;
2171e89da5eSFrederic Barrat irq->vtrig = xd->trig_mmio;
218a06b1cfcSUma Krishnan out:
219a06b1cfcSUma Krishnan return rc;
220a06b1cfcSUma Krishnan err2:
221a06b1cfcSUma Krishnan free_irq(virq, cookie);
222a06b1cfcSUma Krishnan err1:
223a06b1cfcSUma Krishnan irq_dispose_mapping(virq);
224a06b1cfcSUma Krishnan goto out;
225a06b1cfcSUma Krishnan }
226a06b1cfcSUma Krishnan
227a06b1cfcSUma Krishnan /**
228a06b1cfcSUma Krishnan * ocxlflash_map_afu_irq() - map the interrupt of the adapter context
229a06b1cfcSUma Krishnan * @ctx_cookie: Adapter context.
230a06b1cfcSUma Krishnan * @num: Per-context AFU interrupt number.
231a06b1cfcSUma Krishnan * @handler: Interrupt handler to register.
232a06b1cfcSUma Krishnan * @cookie: Interrupt handler private data.
233a06b1cfcSUma Krishnan * @name: Name of the interrupt.
234a06b1cfcSUma Krishnan *
235a06b1cfcSUma Krishnan * Return: 0 on success, -errno on failure
236a06b1cfcSUma Krishnan */
ocxlflash_map_afu_irq(void * ctx_cookie,int num,irq_handler_t handler,void * cookie,char * name)237a06b1cfcSUma Krishnan static int ocxlflash_map_afu_irq(void *ctx_cookie, int num,
238a06b1cfcSUma Krishnan irq_handler_t handler, void *cookie,
239a06b1cfcSUma Krishnan char *name)
240a06b1cfcSUma Krishnan {
241a06b1cfcSUma Krishnan return afu_map_irq(0, ctx_cookie, num, handler, cookie, name);
242a06b1cfcSUma Krishnan }
243a06b1cfcSUma Krishnan
244a06b1cfcSUma Krishnan /**
245a06b1cfcSUma Krishnan * afu_unmap_irq() - unmap the interrupt
246a06b1cfcSUma Krishnan * @flags: Flags.
247a06b1cfcSUma Krishnan * @ctx: Adapter context.
248a06b1cfcSUma Krishnan * @num: Per-context AFU interrupt number.
249a06b1cfcSUma Krishnan * @cookie: Interrupt handler private data.
250a06b1cfcSUma Krishnan */
afu_unmap_irq(u64 flags,struct ocxlflash_context * ctx,int num,void * cookie)251a06b1cfcSUma Krishnan static void afu_unmap_irq(u64 flags, struct ocxlflash_context *ctx, int num,
252a06b1cfcSUma Krishnan void *cookie)
253a06b1cfcSUma Krishnan {
254a06b1cfcSUma Krishnan struct ocxl_hw_afu *afu = ctx->hw_afu;
255a06b1cfcSUma Krishnan struct device *dev = afu->dev;
256a06b1cfcSUma Krishnan struct ocxlflash_irqs *irq;
257a06b1cfcSUma Krishnan
258a06b1cfcSUma Krishnan if (num < 0 || num >= ctx->num_irqs) {
259a06b1cfcSUma Krishnan dev_err(dev, "%s: Interrupt %d not allocated\n", __func__, num);
260a06b1cfcSUma Krishnan return;
261a06b1cfcSUma Krishnan }
262a06b1cfcSUma Krishnan
263a06b1cfcSUma Krishnan irq = &ctx->irqs[num];
264a06b1cfcSUma Krishnan
265a06b1cfcSUma Krishnan if (irq_find_mapping(NULL, irq->hwirq)) {
266a06b1cfcSUma Krishnan free_irq(irq->virq, cookie);
267a06b1cfcSUma Krishnan irq_dispose_mapping(irq->virq);
268a06b1cfcSUma Krishnan }
269a06b1cfcSUma Krishnan
270a06b1cfcSUma Krishnan memset(irq, 0, sizeof(*irq));
271a06b1cfcSUma Krishnan }
272a06b1cfcSUma Krishnan
273a06b1cfcSUma Krishnan /**
274a06b1cfcSUma Krishnan * ocxlflash_unmap_afu_irq() - unmap the interrupt
275a06b1cfcSUma Krishnan * @ctx_cookie: Adapter context.
276a06b1cfcSUma Krishnan * @num: Per-context AFU interrupt number.
277a06b1cfcSUma Krishnan * @cookie: Interrupt handler private data.
278a06b1cfcSUma Krishnan */
ocxlflash_unmap_afu_irq(void * ctx_cookie,int num,void * cookie)279a06b1cfcSUma Krishnan static void ocxlflash_unmap_afu_irq(void *ctx_cookie, int num, void *cookie)
280a06b1cfcSUma Krishnan {
281a06b1cfcSUma Krishnan return afu_unmap_irq(0, ctx_cookie, num, cookie);
282a06b1cfcSUma Krishnan }
283a06b1cfcSUma Krishnan
284a06b1cfcSUma Krishnan /**
285402a55eaSUma Krishnan * ocxlflash_get_irq_objhndl() - get the object handle for an interrupt
286402a55eaSUma Krishnan * @ctx_cookie: Context associated with the interrupt.
287402a55eaSUma Krishnan * @irq: Interrupt number.
288402a55eaSUma Krishnan *
289402a55eaSUma Krishnan * Return: effective address of the mapped region
290402a55eaSUma Krishnan */
ocxlflash_get_irq_objhndl(void * ctx_cookie,int irq)291402a55eaSUma Krishnan static u64 ocxlflash_get_irq_objhndl(void *ctx_cookie, int irq)
292402a55eaSUma Krishnan {
293402a55eaSUma Krishnan struct ocxlflash_context *ctx = ctx_cookie;
294402a55eaSUma Krishnan
295402a55eaSUma Krishnan if (irq < 0 || irq >= ctx->num_irqs)
296402a55eaSUma Krishnan return 0;
297402a55eaSUma Krishnan
298402a55eaSUma Krishnan return (__force u64)ctx->irqs[irq].vtrig;
299402a55eaSUma Krishnan }
300402a55eaSUma Krishnan
301402a55eaSUma Krishnan /**
30266ae644bSUma Krishnan * ocxlflash_xsl_fault() - callback when translation error is triggered
30366ae644bSUma Krishnan * @data: Private data provided at callback registration, the context.
30466ae644bSUma Krishnan * @addr: Address that triggered the error.
30566ae644bSUma Krishnan * @dsisr: Value of dsisr register.
30666ae644bSUma Krishnan */
ocxlflash_xsl_fault(void * data,u64 addr,u64 dsisr)30766ae644bSUma Krishnan static void ocxlflash_xsl_fault(void *data, u64 addr, u64 dsisr)
30866ae644bSUma Krishnan {
30966ae644bSUma Krishnan struct ocxlflash_context *ctx = data;
31066ae644bSUma Krishnan
31166ae644bSUma Krishnan spin_lock(&ctx->slock);
31266ae644bSUma Krishnan ctx->fault_addr = addr;
31366ae644bSUma Krishnan ctx->fault_dsisr = dsisr;
31466ae644bSUma Krishnan ctx->pending_fault = true;
31566ae644bSUma Krishnan spin_unlock(&ctx->slock);
31666ae644bSUma Krishnan
31766ae644bSUma Krishnan wake_up_all(&ctx->wq);
31866ae644bSUma Krishnan }
31966ae644bSUma Krishnan
32066ae644bSUma Krishnan /**
3216b938ac9SUma Krishnan * start_context() - local routine to start a context
3226b938ac9SUma Krishnan * @ctx: Adapter context to be started.
3236b938ac9SUma Krishnan *
324c207b571SUma Krishnan * Assign the context specific MMIO space, add and enable the PE.
3256b938ac9SUma Krishnan *
3266b938ac9SUma Krishnan * Return: 0 on success, -errno on failure
3276b938ac9SUma Krishnan */
start_context(struct ocxlflash_context * ctx)3286b938ac9SUma Krishnan static int start_context(struct ocxlflash_context *ctx)
3296b938ac9SUma Krishnan {
3306b938ac9SUma Krishnan struct ocxl_hw_afu *afu = ctx->hw_afu;
3316b938ac9SUma Krishnan struct ocxl_afu_config *acfg = &afu->acfg;
332c207b571SUma Krishnan void *link_token = afu->link_token;
333d731feeaSChristophe Lombard struct pci_dev *pdev = afu->pdev;
334c207b571SUma Krishnan struct device *dev = afu->dev;
3356b938ac9SUma Krishnan bool master = ctx->master;
336762c7e93SUma Krishnan struct mm_struct *mm;
337c207b571SUma Krishnan int rc = 0;
338762c7e93SUma Krishnan u32 pid;
3396b938ac9SUma Krishnan
340f81face7SUma Krishnan mutex_lock(&ctx->state_mutex);
341f81face7SUma Krishnan if (ctx->state != OPENED) {
342f81face7SUma Krishnan dev_err(dev, "%s: Context state invalid, state=%d\n",
343f81face7SUma Krishnan __func__, ctx->state);
344f81face7SUma Krishnan rc = -EINVAL;
345f81face7SUma Krishnan goto out;
346f81face7SUma Krishnan }
347f81face7SUma Krishnan
3486b938ac9SUma Krishnan if (master) {
3496b938ac9SUma Krishnan ctx->psn_size = acfg->global_mmio_size;
3506b938ac9SUma Krishnan ctx->psn_phys = afu->gmmio_phys;
3516b938ac9SUma Krishnan } else {
3526b938ac9SUma Krishnan ctx->psn_size = acfg->pp_mmio_stride;
3536b938ac9SUma Krishnan ctx->psn_phys = afu->ppmmio_phys + (ctx->pe * ctx->psn_size);
3546b938ac9SUma Krishnan }
3556b938ac9SUma Krishnan
356762c7e93SUma Krishnan /* pid and mm not set for master contexts */
357762c7e93SUma Krishnan if (master) {
358762c7e93SUma Krishnan pid = 0;
359762c7e93SUma Krishnan mm = NULL;
360762c7e93SUma Krishnan } else {
361762c7e93SUma Krishnan pid = current->mm->context.id;
362762c7e93SUma Krishnan mm = current->mm;
363762c7e93SUma Krishnan }
364c207b571SUma Krishnan
365d731feeaSChristophe Lombard rc = ocxl_link_add_pe(link_token, ctx->pe, pid, 0, 0,
366d731feeaSChristophe Lombard pci_dev_id(pdev), mm, ocxlflash_xsl_fault,
367d731feeaSChristophe Lombard ctx);
368c207b571SUma Krishnan if (unlikely(rc)) {
369c207b571SUma Krishnan dev_err(dev, "%s: ocxl_link_add_pe failed rc=%d\n",
370c207b571SUma Krishnan __func__, rc);
371c207b571SUma Krishnan goto out;
372c207b571SUma Krishnan }
373f81face7SUma Krishnan
374f81face7SUma Krishnan ctx->state = STARTED;
375c207b571SUma Krishnan out:
376f81face7SUma Krishnan mutex_unlock(&ctx->state_mutex);
377c207b571SUma Krishnan return rc;
3786b938ac9SUma Krishnan }
3796b938ac9SUma Krishnan
3806b938ac9SUma Krishnan /**
3816b938ac9SUma Krishnan * ocxlflash_start_context() - start a kernel context
3826b938ac9SUma Krishnan * @ctx_cookie: Adapter context to be started.
3836b938ac9SUma Krishnan *
3846b938ac9SUma Krishnan * Return: 0 on success, -errno on failure
3856b938ac9SUma Krishnan */
ocxlflash_start_context(void * ctx_cookie)3866b938ac9SUma Krishnan static int ocxlflash_start_context(void *ctx_cookie)
3876b938ac9SUma Krishnan {
3886b938ac9SUma Krishnan struct ocxlflash_context *ctx = ctx_cookie;
3896b938ac9SUma Krishnan
3906b938ac9SUma Krishnan return start_context(ctx);
3916b938ac9SUma Krishnan }
3926b938ac9SUma Krishnan
3936b938ac9SUma Krishnan /**
394c207b571SUma Krishnan * ocxlflash_stop_context() - stop a context
395c207b571SUma Krishnan * @ctx_cookie: Adapter context to be stopped.
396c207b571SUma Krishnan *
397c207b571SUma Krishnan * Return: 0 on success, -errno on failure
398c207b571SUma Krishnan */
ocxlflash_stop_context(void * ctx_cookie)399c207b571SUma Krishnan static int ocxlflash_stop_context(void *ctx_cookie)
400c207b571SUma Krishnan {
401c207b571SUma Krishnan struct ocxlflash_context *ctx = ctx_cookie;
402c207b571SUma Krishnan struct ocxl_hw_afu *afu = ctx->hw_afu;
403c207b571SUma Krishnan struct ocxl_afu_config *acfg = &afu->acfg;
404c207b571SUma Krishnan struct pci_dev *pdev = afu->pdev;
405c207b571SUma Krishnan struct device *dev = afu->dev;
406f81face7SUma Krishnan enum ocxlflash_ctx_state state;
407f81face7SUma Krishnan int rc = 0;
408f81face7SUma Krishnan
409f81face7SUma Krishnan mutex_lock(&ctx->state_mutex);
410f81face7SUma Krishnan state = ctx->state;
411f81face7SUma Krishnan ctx->state = CLOSED;
412f81face7SUma Krishnan mutex_unlock(&ctx->state_mutex);
413f81face7SUma Krishnan if (state != STARTED)
414f81face7SUma Krishnan goto out;
415c207b571SUma Krishnan
416c207b571SUma Krishnan rc = ocxl_config_terminate_pasid(pdev, acfg->dvsec_afu_control_pos,
417c207b571SUma Krishnan ctx->pe);
418c207b571SUma Krishnan if (unlikely(rc)) {
419c207b571SUma Krishnan dev_err(dev, "%s: ocxl_config_terminate_pasid failed rc=%d\n",
420c207b571SUma Krishnan __func__, rc);
421c207b571SUma Krishnan /* If EBUSY, PE could be referenced in future by the AFU */
422c207b571SUma Krishnan if (rc == -EBUSY)
423c207b571SUma Krishnan goto out;
424c207b571SUma Krishnan }
425c207b571SUma Krishnan
426c207b571SUma Krishnan rc = ocxl_link_remove_pe(afu->link_token, ctx->pe);
427c207b571SUma Krishnan if (unlikely(rc)) {
428c207b571SUma Krishnan dev_err(dev, "%s: ocxl_link_remove_pe failed rc=%d\n",
429c207b571SUma Krishnan __func__, rc);
430c207b571SUma Krishnan goto out;
431c207b571SUma Krishnan }
432c207b571SUma Krishnan out:
433c207b571SUma Krishnan return rc;
434c207b571SUma Krishnan }
435c207b571SUma Krishnan
436c207b571SUma Krishnan /**
4379433fb32SUma Krishnan * ocxlflash_afu_reset() - reset the AFU
4389433fb32SUma Krishnan * @ctx_cookie: Adapter context.
4399433fb32SUma Krishnan */
ocxlflash_afu_reset(void * ctx_cookie)4409433fb32SUma Krishnan static int ocxlflash_afu_reset(void *ctx_cookie)
4419433fb32SUma Krishnan {
4429433fb32SUma Krishnan struct ocxlflash_context *ctx = ctx_cookie;
4439433fb32SUma Krishnan struct device *dev = ctx->hw_afu->dev;
4449433fb32SUma Krishnan
4459433fb32SUma Krishnan /* Pending implementation from OCXL transport services */
4469433fb32SUma Krishnan dev_err_once(dev, "%s: afu_reset() fop not supported\n", __func__);
4479433fb32SUma Krishnan
4489433fb32SUma Krishnan /* Silently return success until it is implemented */
4499433fb32SUma Krishnan return 0;
4509433fb32SUma Krishnan }
4519433fb32SUma Krishnan
4529433fb32SUma Krishnan /**
453f6b4557cSUma Krishnan * ocxlflash_set_master() - sets the context as master
454f6b4557cSUma Krishnan * @ctx_cookie: Adapter context to set as master.
455f6b4557cSUma Krishnan */
ocxlflash_set_master(void * ctx_cookie)456f6b4557cSUma Krishnan static void ocxlflash_set_master(void *ctx_cookie)
457f6b4557cSUma Krishnan {
458f6b4557cSUma Krishnan struct ocxlflash_context *ctx = ctx_cookie;
459f6b4557cSUma Krishnan
460f6b4557cSUma Krishnan ctx->master = true;
461f6b4557cSUma Krishnan }
462f6b4557cSUma Krishnan
463f6b4557cSUma Krishnan /**
464f6b4557cSUma Krishnan * ocxlflash_get_context() - obtains the context associated with the host
465f6b4557cSUma Krishnan * @pdev: PCI device associated with the host.
466f6b4557cSUma Krishnan * @afu_cookie: Hardware AFU associated with the host.
467f6b4557cSUma Krishnan *
468f6b4557cSUma Krishnan * Return: returns the pointer to host adapter context
469f6b4557cSUma Krishnan */
ocxlflash_get_context(struct pci_dev * pdev,void * afu_cookie)470f6b4557cSUma Krishnan static void *ocxlflash_get_context(struct pci_dev *pdev, void *afu_cookie)
471f6b4557cSUma Krishnan {
472f6b4557cSUma Krishnan struct ocxl_hw_afu *afu = afu_cookie;
473f6b4557cSUma Krishnan
474f6b4557cSUma Krishnan return afu->ocxl_ctx;
475f6b4557cSUma Krishnan }
476f6b4557cSUma Krishnan
477f6b4557cSUma Krishnan /**
478f6b4557cSUma Krishnan * ocxlflash_dev_context_init() - allocate and initialize an adapter context
479f6b4557cSUma Krishnan * @pdev: PCI device associated with the host.
480f6b4557cSUma Krishnan * @afu_cookie: Hardware AFU associated with the host.
481f6b4557cSUma Krishnan *
482f6b4557cSUma Krishnan * Return: returns the adapter context on success, ERR_PTR on failure
483f6b4557cSUma Krishnan */
ocxlflash_dev_context_init(struct pci_dev * pdev,void * afu_cookie)484f6b4557cSUma Krishnan static void *ocxlflash_dev_context_init(struct pci_dev *pdev, void *afu_cookie)
485f6b4557cSUma Krishnan {
486f6b4557cSUma Krishnan struct ocxl_hw_afu *afu = afu_cookie;
487f6b4557cSUma Krishnan struct device *dev = afu->dev;
488f6b4557cSUma Krishnan struct ocxlflash_context *ctx;
489f6b4557cSUma Krishnan int rc;
490f6b4557cSUma Krishnan
491f6b4557cSUma Krishnan ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
492f6b4557cSUma Krishnan if (unlikely(!ctx)) {
493f6b4557cSUma Krishnan dev_err(dev, "%s: Context allocation failed\n", __func__);
494f6b4557cSUma Krishnan rc = -ENOMEM;
495429ebfa6SUma Krishnan goto err1;
496f6b4557cSUma Krishnan }
497f6b4557cSUma Krishnan
498429ebfa6SUma Krishnan idr_preload(GFP_KERNEL);
499429ebfa6SUma Krishnan rc = idr_alloc(&afu->idr, ctx, 0, afu->max_pasid, GFP_NOWAIT);
500429ebfa6SUma Krishnan idr_preload_end();
501429ebfa6SUma Krishnan if (unlikely(rc < 0)) {
502429ebfa6SUma Krishnan dev_err(dev, "%s: idr_alloc failed rc=%d\n", __func__, rc);
503429ebfa6SUma Krishnan goto err2;
504429ebfa6SUma Krishnan }
505429ebfa6SUma Krishnan
506762c7e93SUma Krishnan spin_lock_init(&ctx->slock);
50756f1db1aSUma Krishnan init_waitqueue_head(&ctx->wq);
508f81face7SUma Krishnan mutex_init(&ctx->state_mutex);
509762c7e93SUma Krishnan
510f81face7SUma Krishnan ctx->state = OPENED;
511429ebfa6SUma Krishnan ctx->pe = rc;
512f6b4557cSUma Krishnan ctx->master = false;
513926a62f9SUma Krishnan ctx->mapping = NULL;
514f6b4557cSUma Krishnan ctx->hw_afu = afu;
515762c7e93SUma Krishnan ctx->irq_bitmap = 0;
516762c7e93SUma Krishnan ctx->pending_irq = false;
51766ae644bSUma Krishnan ctx->pending_fault = false;
518f6b4557cSUma Krishnan out:
519f6b4557cSUma Krishnan return ctx;
520429ebfa6SUma Krishnan err2:
521429ebfa6SUma Krishnan kfree(ctx);
522429ebfa6SUma Krishnan err1:
523f6b4557cSUma Krishnan ctx = ERR_PTR(rc);
524f6b4557cSUma Krishnan goto out;
525f6b4557cSUma Krishnan }
526f6b4557cSUma Krishnan
527f6b4557cSUma Krishnan /**
528f6b4557cSUma Krishnan * ocxlflash_release_context() - releases an adapter context
529f6b4557cSUma Krishnan * @ctx_cookie: Adapter context to be released.
530f6b4557cSUma Krishnan *
531f6b4557cSUma Krishnan * Return: 0 on success, -errno on failure
532f6b4557cSUma Krishnan */
ocxlflash_release_context(void * ctx_cookie)533f6b4557cSUma Krishnan static int ocxlflash_release_context(void *ctx_cookie)
534f6b4557cSUma Krishnan {
535f6b4557cSUma Krishnan struct ocxlflash_context *ctx = ctx_cookie;
536f81face7SUma Krishnan struct device *dev;
537f6b4557cSUma Krishnan int rc = 0;
538f6b4557cSUma Krishnan
539f6b4557cSUma Krishnan if (!ctx)
540f6b4557cSUma Krishnan goto out;
541f6b4557cSUma Krishnan
542f81face7SUma Krishnan dev = ctx->hw_afu->dev;
543f81face7SUma Krishnan mutex_lock(&ctx->state_mutex);
544f81face7SUma Krishnan if (ctx->state >= STARTED) {
545f81face7SUma Krishnan dev_err(dev, "%s: Context in use, state=%d\n", __func__,
546f81face7SUma Krishnan ctx->state);
547f81face7SUma Krishnan mutex_unlock(&ctx->state_mutex);
548f81face7SUma Krishnan rc = -EBUSY;
549f81face7SUma Krishnan goto out;
550f81face7SUma Krishnan }
551f81face7SUma Krishnan mutex_unlock(&ctx->state_mutex);
552f81face7SUma Krishnan
553429ebfa6SUma Krishnan idr_remove(&ctx->hw_afu->idr, ctx->pe);
554926a62f9SUma Krishnan ocxlflash_release_mapping(ctx);
555f6b4557cSUma Krishnan kfree(ctx);
556f6b4557cSUma Krishnan out:
557f6b4557cSUma Krishnan return rc;
558f6b4557cSUma Krishnan }
559f6b4557cSUma Krishnan
560f6b4557cSUma Krishnan /**
5618b7a5521SUma Krishnan * ocxlflash_perst_reloads_same_image() - sets the image reload policy
5628b7a5521SUma Krishnan * @afu_cookie: Hardware AFU associated with the host.
5638b7a5521SUma Krishnan * @image: Whether to load the same image on PERST.
5648b7a5521SUma Krishnan */
ocxlflash_perst_reloads_same_image(void * afu_cookie,bool image)5658b7a5521SUma Krishnan static void ocxlflash_perst_reloads_same_image(void *afu_cookie, bool image)
5668b7a5521SUma Krishnan {
5678b7a5521SUma Krishnan struct ocxl_hw_afu *afu = afu_cookie;
5688b7a5521SUma Krishnan
5698b7a5521SUma Krishnan afu->perst_same_image = image;
5708b7a5521SUma Krishnan }
5718b7a5521SUma Krishnan
5728b7a5521SUma Krishnan /**
573119c9200SUma Krishnan * ocxlflash_read_adapter_vpd() - reads the adapter VPD
574119c9200SUma Krishnan * @pdev: PCI device associated with the host.
575119c9200SUma Krishnan * @buf: Buffer to get the VPD data.
576119c9200SUma Krishnan * @count: Size of buffer (maximum bytes that can be read).
577119c9200SUma Krishnan *
578119c9200SUma Krishnan * Return: size of VPD on success, -errno on failure
579119c9200SUma Krishnan */
ocxlflash_read_adapter_vpd(struct pci_dev * pdev,void * buf,size_t count)580119c9200SUma Krishnan static ssize_t ocxlflash_read_adapter_vpd(struct pci_dev *pdev, void *buf,
581119c9200SUma Krishnan size_t count)
582119c9200SUma Krishnan {
583119c9200SUma Krishnan return pci_read_vpd(pdev, 0, count, buf);
584119c9200SUma Krishnan }
585119c9200SUma Krishnan
586119c9200SUma Krishnan /**
587bc65c1c7SUma Krishnan * free_afu_irqs() - internal service to free interrupts
588bc65c1c7SUma Krishnan * @ctx: Adapter context.
589bc65c1c7SUma Krishnan */
free_afu_irqs(struct ocxlflash_context * ctx)590bc65c1c7SUma Krishnan static void free_afu_irqs(struct ocxlflash_context *ctx)
591bc65c1c7SUma Krishnan {
592bc65c1c7SUma Krishnan struct ocxl_hw_afu *afu = ctx->hw_afu;
593bc65c1c7SUma Krishnan struct device *dev = afu->dev;
594bc65c1c7SUma Krishnan int i;
595bc65c1c7SUma Krishnan
596bc65c1c7SUma Krishnan if (!ctx->irqs) {
597bc65c1c7SUma Krishnan dev_err(dev, "%s: Interrupts not allocated\n", __func__);
598bc65c1c7SUma Krishnan return;
599bc65c1c7SUma Krishnan }
600bc65c1c7SUma Krishnan
601bc65c1c7SUma Krishnan for (i = ctx->num_irqs; i >= 0; i--)
602bc65c1c7SUma Krishnan ocxl_link_free_irq(afu->link_token, ctx->irqs[i].hwirq);
603bc65c1c7SUma Krishnan
604bc65c1c7SUma Krishnan kfree(ctx->irqs);
605bc65c1c7SUma Krishnan ctx->irqs = NULL;
606bc65c1c7SUma Krishnan }
607bc65c1c7SUma Krishnan
608bc65c1c7SUma Krishnan /**
609bc65c1c7SUma Krishnan * alloc_afu_irqs() - internal service to allocate interrupts
610bc65c1c7SUma Krishnan * @ctx: Context associated with the request.
611bc65c1c7SUma Krishnan * @num: Number of interrupts requested.
612bc65c1c7SUma Krishnan *
613bc65c1c7SUma Krishnan * Return: 0 on success, -errno on failure
614bc65c1c7SUma Krishnan */
alloc_afu_irqs(struct ocxlflash_context * ctx,int num)615bc65c1c7SUma Krishnan static int alloc_afu_irqs(struct ocxlflash_context *ctx, int num)
616bc65c1c7SUma Krishnan {
617bc65c1c7SUma Krishnan struct ocxl_hw_afu *afu = ctx->hw_afu;
618bc65c1c7SUma Krishnan struct device *dev = afu->dev;
619bc65c1c7SUma Krishnan struct ocxlflash_irqs *irqs;
620bc65c1c7SUma Krishnan int rc = 0;
621bc65c1c7SUma Krishnan int hwirq;
622bc65c1c7SUma Krishnan int i;
623bc65c1c7SUma Krishnan
624bc65c1c7SUma Krishnan if (ctx->irqs) {
625bc65c1c7SUma Krishnan dev_err(dev, "%s: Interrupts already allocated\n", __func__);
626bc65c1c7SUma Krishnan rc = -EEXIST;
627bc65c1c7SUma Krishnan goto out;
628bc65c1c7SUma Krishnan }
629bc65c1c7SUma Krishnan
630bc65c1c7SUma Krishnan if (num > OCXL_MAX_IRQS) {
631bc65c1c7SUma Krishnan dev_err(dev, "%s: Too many interrupts num=%d\n", __func__, num);
632bc65c1c7SUma Krishnan rc = -EINVAL;
633bc65c1c7SUma Krishnan goto out;
634bc65c1c7SUma Krishnan }
635bc65c1c7SUma Krishnan
636bc65c1c7SUma Krishnan irqs = kcalloc(num, sizeof(*irqs), GFP_KERNEL);
637bc65c1c7SUma Krishnan if (unlikely(!irqs)) {
638bc65c1c7SUma Krishnan dev_err(dev, "%s: Context irqs allocation failed\n", __func__);
639bc65c1c7SUma Krishnan rc = -ENOMEM;
640bc65c1c7SUma Krishnan goto out;
641bc65c1c7SUma Krishnan }
642bc65c1c7SUma Krishnan
643bc65c1c7SUma Krishnan for (i = 0; i < num; i++) {
644dde6f18aSFrederic Barrat rc = ocxl_link_irq_alloc(afu->link_token, &hwirq);
645bc65c1c7SUma Krishnan if (unlikely(rc)) {
646bc65c1c7SUma Krishnan dev_err(dev, "%s: ocxl_link_irq_alloc failed rc=%d\n",
647bc65c1c7SUma Krishnan __func__, rc);
648bc65c1c7SUma Krishnan goto err;
649bc65c1c7SUma Krishnan }
650bc65c1c7SUma Krishnan
651bc65c1c7SUma Krishnan irqs[i].hwirq = hwirq;
652bc65c1c7SUma Krishnan }
653bc65c1c7SUma Krishnan
654bc65c1c7SUma Krishnan ctx->irqs = irqs;
655bc65c1c7SUma Krishnan ctx->num_irqs = num;
656bc65c1c7SUma Krishnan out:
657bc65c1c7SUma Krishnan return rc;
658bc65c1c7SUma Krishnan err:
659bc65c1c7SUma Krishnan for (i = i-1; i >= 0; i--)
660bc65c1c7SUma Krishnan ocxl_link_free_irq(afu->link_token, irqs[i].hwirq);
661bc65c1c7SUma Krishnan kfree(irqs);
662bc65c1c7SUma Krishnan goto out;
663bc65c1c7SUma Krishnan }
664bc65c1c7SUma Krishnan
665bc65c1c7SUma Krishnan /**
666bc65c1c7SUma Krishnan * ocxlflash_allocate_afu_irqs() - allocates the requested number of interrupts
667bc65c1c7SUma Krishnan * @ctx_cookie: Context associated with the request.
668bc65c1c7SUma Krishnan * @num: Number of interrupts requested.
669bc65c1c7SUma Krishnan *
670bc65c1c7SUma Krishnan * Return: 0 on success, -errno on failure
671bc65c1c7SUma Krishnan */
ocxlflash_allocate_afu_irqs(void * ctx_cookie,int num)672bc65c1c7SUma Krishnan static int ocxlflash_allocate_afu_irqs(void *ctx_cookie, int num)
673bc65c1c7SUma Krishnan {
674bc65c1c7SUma Krishnan return alloc_afu_irqs(ctx_cookie, num);
675bc65c1c7SUma Krishnan }
676bc65c1c7SUma Krishnan
677bc65c1c7SUma Krishnan /**
678bc65c1c7SUma Krishnan * ocxlflash_free_afu_irqs() - frees the interrupts of an adapter context
679bc65c1c7SUma Krishnan * @ctx_cookie: Adapter context.
680bc65c1c7SUma Krishnan */
ocxlflash_free_afu_irqs(void * ctx_cookie)681bc65c1c7SUma Krishnan static void ocxlflash_free_afu_irqs(void *ctx_cookie)
682bc65c1c7SUma Krishnan {
683bc65c1c7SUma Krishnan free_afu_irqs(ctx_cookie);
684bc65c1c7SUma Krishnan }
685bc65c1c7SUma Krishnan
686bc65c1c7SUma Krishnan /**
68754370503SUma Krishnan * ocxlflash_unconfig_afu() - unconfigure the AFU
68854370503SUma Krishnan * @afu: AFU associated with the host.
68954370503SUma Krishnan */
ocxlflash_unconfig_afu(struct ocxl_hw_afu * afu)69054370503SUma Krishnan static void ocxlflash_unconfig_afu(struct ocxl_hw_afu *afu)
69154370503SUma Krishnan {
69254370503SUma Krishnan if (afu->gmmio_virt) {
69354370503SUma Krishnan iounmap(afu->gmmio_virt);
69454370503SUma Krishnan afu->gmmio_virt = NULL;
69554370503SUma Krishnan }
69654370503SUma Krishnan }
69754370503SUma Krishnan
69854370503SUma Krishnan /**
69948e077dbSUma Krishnan * ocxlflash_destroy_afu() - destroy the AFU structure
70048e077dbSUma Krishnan * @afu_cookie: AFU to be freed.
70148e077dbSUma Krishnan */
ocxlflash_destroy_afu(void * afu_cookie)70248e077dbSUma Krishnan static void ocxlflash_destroy_afu(void *afu_cookie)
70348e077dbSUma Krishnan {
70448e077dbSUma Krishnan struct ocxl_hw_afu *afu = afu_cookie;
7053351e4f0SUma Krishnan int pos;
70648e077dbSUma Krishnan
70748e077dbSUma Krishnan if (!afu)
70848e077dbSUma Krishnan return;
70948e077dbSUma Krishnan
710f6b4557cSUma Krishnan ocxlflash_release_context(afu->ocxl_ctx);
711429ebfa6SUma Krishnan idr_destroy(&afu->idr);
7123351e4f0SUma Krishnan
7133351e4f0SUma Krishnan /* Disable the AFU */
7143351e4f0SUma Krishnan pos = afu->acfg.dvsec_afu_control_pos;
7153351e4f0SUma Krishnan ocxl_config_set_afu_state(afu->pdev, pos, 0);
7163351e4f0SUma Krishnan
71754370503SUma Krishnan ocxlflash_unconfig_afu(afu);
71848e077dbSUma Krishnan kfree(afu);
71948e077dbSUma Krishnan }
72048e077dbSUma Krishnan
72148e077dbSUma Krishnan /**
722e9dfcedaSUma Krishnan * ocxlflash_config_fn() - configure the host function
723e9dfcedaSUma Krishnan * @pdev: PCI device associated with the host.
724e9dfcedaSUma Krishnan * @afu: AFU associated with the host.
725e9dfcedaSUma Krishnan *
726e9dfcedaSUma Krishnan * Return: 0 on success, -errno on failure
727e9dfcedaSUma Krishnan */
ocxlflash_config_fn(struct pci_dev * pdev,struct ocxl_hw_afu * afu)728e9dfcedaSUma Krishnan static int ocxlflash_config_fn(struct pci_dev *pdev, struct ocxl_hw_afu *afu)
729e9dfcedaSUma Krishnan {
730e9dfcedaSUma Krishnan struct ocxl_fn_config *fcfg = &afu->fcfg;
731e9dfcedaSUma Krishnan struct device *dev = &pdev->dev;
7322e222779SUma Krishnan u16 base, enabled, supported;
733e9dfcedaSUma Krishnan int rc = 0;
734e9dfcedaSUma Krishnan
735e9dfcedaSUma Krishnan /* Read DVSEC config of the function */
736e9dfcedaSUma Krishnan rc = ocxl_config_read_function(pdev, fcfg);
737e9dfcedaSUma Krishnan if (unlikely(rc)) {
738e9dfcedaSUma Krishnan dev_err(dev, "%s: ocxl_config_read_function failed rc=%d\n",
739e9dfcedaSUma Krishnan __func__, rc);
740e9dfcedaSUma Krishnan goto out;
741e9dfcedaSUma Krishnan }
742e9dfcedaSUma Krishnan
743e9dfcedaSUma Krishnan /* Check if function has AFUs defined, only 1 per function supported */
744e9dfcedaSUma Krishnan if (fcfg->max_afu_index >= 0) {
745e9dfcedaSUma Krishnan afu->is_present = true;
746e9dfcedaSUma Krishnan if (fcfg->max_afu_index != 0)
747e9dfcedaSUma Krishnan dev_warn(dev, "%s: Unexpected AFU index value %d\n",
748e9dfcedaSUma Krishnan __func__, fcfg->max_afu_index);
749e9dfcedaSUma Krishnan }
7502e222779SUma Krishnan
7512e222779SUma Krishnan rc = ocxl_config_get_actag_info(pdev, &base, &enabled, &supported);
7522e222779SUma Krishnan if (unlikely(rc)) {
7532e222779SUma Krishnan dev_err(dev, "%s: ocxl_config_get_actag_info failed rc=%d\n",
7542e222779SUma Krishnan __func__, rc);
7552e222779SUma Krishnan goto out;
7562e222779SUma Krishnan }
7572e222779SUma Krishnan
7582e222779SUma Krishnan afu->fn_actag_base = base;
7592e222779SUma Krishnan afu->fn_actag_enabled = enabled;
7602e222779SUma Krishnan
7612e222779SUma Krishnan ocxl_config_set_actag(pdev, fcfg->dvsec_function_pos, base, enabled);
7622e222779SUma Krishnan dev_dbg(dev, "%s: Function acTag range base=%u enabled=%u\n",
7632e222779SUma Krishnan __func__, base, enabled);
76473904823SUma Krishnan
76573904823SUma Krishnan rc = ocxl_link_setup(pdev, 0, &afu->link_token);
76673904823SUma Krishnan if (unlikely(rc)) {
76773904823SUma Krishnan dev_err(dev, "%s: ocxl_link_setup failed rc=%d\n",
76873904823SUma Krishnan __func__, rc);
76973904823SUma Krishnan goto out;
77073904823SUma Krishnan }
771c52bf5b3SUma Krishnan
772c52bf5b3SUma Krishnan rc = ocxl_config_set_TL(pdev, fcfg->dvsec_tl_pos);
773c52bf5b3SUma Krishnan if (unlikely(rc)) {
774c52bf5b3SUma Krishnan dev_err(dev, "%s: ocxl_config_set_TL failed rc=%d\n",
775c52bf5b3SUma Krishnan __func__, rc);
776c52bf5b3SUma Krishnan goto err;
777c52bf5b3SUma Krishnan }
778e9dfcedaSUma Krishnan out:
779e9dfcedaSUma Krishnan return rc;
780c52bf5b3SUma Krishnan err:
781c52bf5b3SUma Krishnan ocxl_link_release(pdev, afu->link_token);
782c52bf5b3SUma Krishnan goto out;
783e9dfcedaSUma Krishnan }
784e9dfcedaSUma Krishnan
785e9dfcedaSUma Krishnan /**
78673904823SUma Krishnan * ocxlflash_unconfig_fn() - unconfigure the host function
78773904823SUma Krishnan * @pdev: PCI device associated with the host.
78873904823SUma Krishnan * @afu: AFU associated with the host.
78973904823SUma Krishnan */
ocxlflash_unconfig_fn(struct pci_dev * pdev,struct ocxl_hw_afu * afu)79073904823SUma Krishnan static void ocxlflash_unconfig_fn(struct pci_dev *pdev, struct ocxl_hw_afu *afu)
79173904823SUma Krishnan {
79273904823SUma Krishnan ocxl_link_release(pdev, afu->link_token);
79373904823SUma Krishnan }
79473904823SUma Krishnan
79573904823SUma Krishnan /**
79654370503SUma Krishnan * ocxlflash_map_mmio() - map the AFU MMIO space
79754370503SUma Krishnan * @afu: AFU associated with the host.
79854370503SUma Krishnan *
79954370503SUma Krishnan * Return: 0 on success, -errno on failure
80054370503SUma Krishnan */
ocxlflash_map_mmio(struct ocxl_hw_afu * afu)80154370503SUma Krishnan static int ocxlflash_map_mmio(struct ocxl_hw_afu *afu)
80254370503SUma Krishnan {
80354370503SUma Krishnan struct ocxl_afu_config *acfg = &afu->acfg;
80454370503SUma Krishnan struct pci_dev *pdev = afu->pdev;
80554370503SUma Krishnan struct device *dev = afu->dev;
80654370503SUma Krishnan phys_addr_t gmmio, ppmmio;
80754370503SUma Krishnan int rc = 0;
80854370503SUma Krishnan
80954370503SUma Krishnan rc = pci_request_region(pdev, acfg->global_mmio_bar, "ocxlflash");
81054370503SUma Krishnan if (unlikely(rc)) {
81154370503SUma Krishnan dev_err(dev, "%s: pci_request_region for global failed rc=%d\n",
81254370503SUma Krishnan __func__, rc);
81354370503SUma Krishnan goto out;
81454370503SUma Krishnan }
81554370503SUma Krishnan gmmio = pci_resource_start(pdev, acfg->global_mmio_bar);
81654370503SUma Krishnan gmmio += acfg->global_mmio_offset;
81754370503SUma Krishnan
81854370503SUma Krishnan rc = pci_request_region(pdev, acfg->pp_mmio_bar, "ocxlflash");
81954370503SUma Krishnan if (unlikely(rc)) {
82054370503SUma Krishnan dev_err(dev, "%s: pci_request_region for pp bar failed rc=%d\n",
82154370503SUma Krishnan __func__, rc);
82254370503SUma Krishnan goto err1;
82354370503SUma Krishnan }
82454370503SUma Krishnan ppmmio = pci_resource_start(pdev, acfg->pp_mmio_bar);
82554370503SUma Krishnan ppmmio += acfg->pp_mmio_offset;
82654370503SUma Krishnan
82754370503SUma Krishnan afu->gmmio_virt = ioremap(gmmio, acfg->global_mmio_size);
82854370503SUma Krishnan if (unlikely(!afu->gmmio_virt)) {
82954370503SUma Krishnan dev_err(dev, "%s: MMIO mapping failed\n", __func__);
83054370503SUma Krishnan rc = -ENOMEM;
83154370503SUma Krishnan goto err2;
83254370503SUma Krishnan }
83354370503SUma Krishnan
83454370503SUma Krishnan afu->gmmio_phys = gmmio;
83554370503SUma Krishnan afu->ppmmio_phys = ppmmio;
83654370503SUma Krishnan out:
83754370503SUma Krishnan return rc;
83854370503SUma Krishnan err2:
83954370503SUma Krishnan pci_release_region(pdev, acfg->pp_mmio_bar);
84054370503SUma Krishnan err1:
84154370503SUma Krishnan pci_release_region(pdev, acfg->global_mmio_bar);
84254370503SUma Krishnan goto out;
84354370503SUma Krishnan }
84454370503SUma Krishnan
84554370503SUma Krishnan /**
8469cc84291SUma Krishnan * ocxlflash_config_afu() - configure the host AFU
8479cc84291SUma Krishnan * @pdev: PCI device associated with the host.
8489cc84291SUma Krishnan * @afu: AFU associated with the host.
8499cc84291SUma Krishnan *
8509cc84291SUma Krishnan * Must be called _after_ host function configuration.
8519cc84291SUma Krishnan *
8529cc84291SUma Krishnan * Return: 0 on success, -errno on failure
8539cc84291SUma Krishnan */
ocxlflash_config_afu(struct pci_dev * pdev,struct ocxl_hw_afu * afu)8549cc84291SUma Krishnan static int ocxlflash_config_afu(struct pci_dev *pdev, struct ocxl_hw_afu *afu)
8559cc84291SUma Krishnan {
8569cc84291SUma Krishnan struct ocxl_afu_config *acfg = &afu->acfg;
8579cc84291SUma Krishnan struct ocxl_fn_config *fcfg = &afu->fcfg;
8589cc84291SUma Krishnan struct device *dev = &pdev->dev;
859d926519eSUma Krishnan int count;
860d926519eSUma Krishnan int base;
861d926519eSUma Krishnan int pos;
8629cc84291SUma Krishnan int rc = 0;
8639cc84291SUma Krishnan
8649cc84291SUma Krishnan /* This HW AFU function does not have any AFUs defined */
8659cc84291SUma Krishnan if (!afu->is_present)
8669cc84291SUma Krishnan goto out;
8679cc84291SUma Krishnan
8689cc84291SUma Krishnan /* Read AFU config at index 0 */
8699cc84291SUma Krishnan rc = ocxl_config_read_afu(pdev, fcfg, acfg, 0);
8709cc84291SUma Krishnan if (unlikely(rc)) {
8719cc84291SUma Krishnan dev_err(dev, "%s: ocxl_config_read_afu failed rc=%d\n",
8729cc84291SUma Krishnan __func__, rc);
8739cc84291SUma Krishnan goto out;
8749cc84291SUma Krishnan }
875d926519eSUma Krishnan
876d926519eSUma Krishnan /* Only one AFU per function is supported, so actag_base is same */
877d926519eSUma Krishnan base = afu->fn_actag_base;
878d926519eSUma Krishnan count = min_t(int, acfg->actag_supported, afu->fn_actag_enabled);
879d926519eSUma Krishnan pos = acfg->dvsec_afu_control_pos;
880d926519eSUma Krishnan
881d926519eSUma Krishnan ocxl_config_set_afu_actag(pdev, pos, base, count);
882d926519eSUma Krishnan dev_dbg(dev, "%s: acTag base=%d enabled=%d\n", __func__, base, count);
883d926519eSUma Krishnan afu->afu_actag_base = base;
884d926519eSUma Krishnan afu->afu_actag_enabled = count;
88541df40d8SUma Krishnan afu->max_pasid = 1 << acfg->pasid_supported_log;
88641df40d8SUma Krishnan
88741df40d8SUma Krishnan ocxl_config_set_afu_pasid(pdev, pos, 0, acfg->pasid_supported_log);
88854370503SUma Krishnan
88954370503SUma Krishnan rc = ocxlflash_map_mmio(afu);
89054370503SUma Krishnan if (unlikely(rc)) {
89154370503SUma Krishnan dev_err(dev, "%s: ocxlflash_map_mmio failed rc=%d\n",
89254370503SUma Krishnan __func__, rc);
89354370503SUma Krishnan goto out;
89454370503SUma Krishnan }
8953351e4f0SUma Krishnan
8963351e4f0SUma Krishnan /* Enable the AFU */
8973351e4f0SUma Krishnan ocxl_config_set_afu_state(pdev, acfg->dvsec_afu_control_pos, 1);
8989cc84291SUma Krishnan out:
8999cc84291SUma Krishnan return rc;
9009cc84291SUma Krishnan }
9019cc84291SUma Krishnan
9029cc84291SUma Krishnan /**
90348e077dbSUma Krishnan * ocxlflash_create_afu() - create the AFU for OCXL
90448e077dbSUma Krishnan * @pdev: PCI device associated with the host.
90548e077dbSUma Krishnan *
90648e077dbSUma Krishnan * Return: AFU on success, NULL on failure
90748e077dbSUma Krishnan */
ocxlflash_create_afu(struct pci_dev * pdev)90848e077dbSUma Krishnan static void *ocxlflash_create_afu(struct pci_dev *pdev)
90948e077dbSUma Krishnan {
91048e077dbSUma Krishnan struct device *dev = &pdev->dev;
911f6b4557cSUma Krishnan struct ocxlflash_context *ctx;
91248e077dbSUma Krishnan struct ocxl_hw_afu *afu;
913e9dfcedaSUma Krishnan int rc;
91448e077dbSUma Krishnan
91548e077dbSUma Krishnan afu = kzalloc(sizeof(*afu), GFP_KERNEL);
91648e077dbSUma Krishnan if (unlikely(!afu)) {
91748e077dbSUma Krishnan dev_err(dev, "%s: HW AFU allocation failed\n", __func__);
91848e077dbSUma Krishnan goto out;
91948e077dbSUma Krishnan }
92048e077dbSUma Krishnan
92148e077dbSUma Krishnan afu->pdev = pdev;
92248e077dbSUma Krishnan afu->dev = dev;
923429ebfa6SUma Krishnan idr_init(&afu->idr);
924e9dfcedaSUma Krishnan
925e9dfcedaSUma Krishnan rc = ocxlflash_config_fn(pdev, afu);
926e9dfcedaSUma Krishnan if (unlikely(rc)) {
927e9dfcedaSUma Krishnan dev_err(dev, "%s: Function configuration failed rc=%d\n",
928e9dfcedaSUma Krishnan __func__, rc);
929e9dfcedaSUma Krishnan goto err1;
930e9dfcedaSUma Krishnan }
9319cc84291SUma Krishnan
9329cc84291SUma Krishnan rc = ocxlflash_config_afu(pdev, afu);
9339cc84291SUma Krishnan if (unlikely(rc)) {
9349cc84291SUma Krishnan dev_err(dev, "%s: AFU configuration failed rc=%d\n",
9359cc84291SUma Krishnan __func__, rc);
93673904823SUma Krishnan goto err2;
9379cc84291SUma Krishnan }
938f6b4557cSUma Krishnan
939f6b4557cSUma Krishnan ctx = ocxlflash_dev_context_init(pdev, afu);
940f6b4557cSUma Krishnan if (IS_ERR(ctx)) {
941f6b4557cSUma Krishnan rc = PTR_ERR(ctx);
942f6b4557cSUma Krishnan dev_err(dev, "%s: ocxlflash_dev_context_init failed rc=%d\n",
943f6b4557cSUma Krishnan __func__, rc);
94473904823SUma Krishnan goto err3;
945f6b4557cSUma Krishnan }
946f6b4557cSUma Krishnan
947f6b4557cSUma Krishnan afu->ocxl_ctx = ctx;
94848e077dbSUma Krishnan out:
94948e077dbSUma Krishnan return afu;
95073904823SUma Krishnan err3:
95154370503SUma Krishnan ocxlflash_unconfig_afu(afu);
95273904823SUma Krishnan err2:
95373904823SUma Krishnan ocxlflash_unconfig_fn(pdev, afu);
954e9dfcedaSUma Krishnan err1:
955429ebfa6SUma Krishnan idr_destroy(&afu->idr);
956e9dfcedaSUma Krishnan kfree(afu);
957e9dfcedaSUma Krishnan afu = NULL;
958e9dfcedaSUma Krishnan goto out;
95948e077dbSUma Krishnan }
96076ebe01fSUma Krishnan
96156f1db1aSUma Krishnan /**
96256f1db1aSUma Krishnan * ctx_event_pending() - check for any event pending on the context
96356f1db1aSUma Krishnan * @ctx: Context to be checked.
96456f1db1aSUma Krishnan *
96556f1db1aSUma Krishnan * Return: true if there is an event pending, false if none pending
96656f1db1aSUma Krishnan */
ctx_event_pending(struct ocxlflash_context * ctx)96756f1db1aSUma Krishnan static inline bool ctx_event_pending(struct ocxlflash_context *ctx)
96856f1db1aSUma Krishnan {
96966ae644bSUma Krishnan if (ctx->pending_irq || ctx->pending_fault)
97056f1db1aSUma Krishnan return true;
97156f1db1aSUma Krishnan
97256f1db1aSUma Krishnan return false;
97356f1db1aSUma Krishnan }
97456f1db1aSUma Krishnan
97556f1db1aSUma Krishnan /**
97656f1db1aSUma Krishnan * afu_poll() - poll the AFU for events on the context
97756f1db1aSUma Krishnan * @file: File associated with the adapter context.
97856f1db1aSUma Krishnan * @poll: Poll structure from the user.
97956f1db1aSUma Krishnan *
98056f1db1aSUma Krishnan * Return: poll mask
98156f1db1aSUma Krishnan */
afu_poll(struct file * file,struct poll_table_struct * poll)98256f1db1aSUma Krishnan static unsigned int afu_poll(struct file *file, struct poll_table_struct *poll)
98356f1db1aSUma Krishnan {
98456f1db1aSUma Krishnan struct ocxlflash_context *ctx = file->private_data;
98556f1db1aSUma Krishnan struct device *dev = ctx->hw_afu->dev;
98656f1db1aSUma Krishnan ulong lock_flags;
98756f1db1aSUma Krishnan int mask = 0;
98856f1db1aSUma Krishnan
98956f1db1aSUma Krishnan poll_wait(file, &ctx->wq, poll);
99056f1db1aSUma Krishnan
99156f1db1aSUma Krishnan spin_lock_irqsave(&ctx->slock, lock_flags);
99256f1db1aSUma Krishnan if (ctx_event_pending(ctx))
99356f1db1aSUma Krishnan mask |= POLLIN | POLLRDNORM;
994f81face7SUma Krishnan else if (ctx->state == CLOSED)
99556f1db1aSUma Krishnan mask |= POLLERR;
99656f1db1aSUma Krishnan spin_unlock_irqrestore(&ctx->slock, lock_flags);
99756f1db1aSUma Krishnan
99856f1db1aSUma Krishnan dev_dbg(dev, "%s: Poll wait completed for pe %i mask %i\n",
99956f1db1aSUma Krishnan __func__, ctx->pe, mask);
100056f1db1aSUma Krishnan
100156f1db1aSUma Krishnan return mask;
100256f1db1aSUma Krishnan }
100356f1db1aSUma Krishnan
100403aa9c51SUma Krishnan /**
100503aa9c51SUma Krishnan * afu_read() - perform a read on the context for any event
100603aa9c51SUma Krishnan * @file: File associated with the adapter context.
100703aa9c51SUma Krishnan * @buf: Buffer to receive the data.
100803aa9c51SUma Krishnan * @count: Size of buffer (maximum bytes that can be read).
100903aa9c51SUma Krishnan * @off: Offset.
101003aa9c51SUma Krishnan *
101103aa9c51SUma Krishnan * Return: size of the data read on success, -errno on failure
101203aa9c51SUma Krishnan */
afu_read(struct file * file,char __user * buf,size_t count,loff_t * off)101303aa9c51SUma Krishnan static ssize_t afu_read(struct file *file, char __user *buf, size_t count,
101403aa9c51SUma Krishnan loff_t *off)
101503aa9c51SUma Krishnan {
101603aa9c51SUma Krishnan struct ocxlflash_context *ctx = file->private_data;
101703aa9c51SUma Krishnan struct device *dev = ctx->hw_afu->dev;
101803aa9c51SUma Krishnan struct cxl_event event;
101903aa9c51SUma Krishnan ulong lock_flags;
102003aa9c51SUma Krishnan ssize_t esize;
102103aa9c51SUma Krishnan ssize_t rc;
102203aa9c51SUma Krishnan int bit;
102303aa9c51SUma Krishnan DEFINE_WAIT(event_wait);
102403aa9c51SUma Krishnan
102503aa9c51SUma Krishnan if (*off != 0) {
102603aa9c51SUma Krishnan dev_err(dev, "%s: Non-zero offset not supported, off=%lld\n",
102703aa9c51SUma Krishnan __func__, *off);
102803aa9c51SUma Krishnan rc = -EINVAL;
102903aa9c51SUma Krishnan goto out;
103003aa9c51SUma Krishnan }
103103aa9c51SUma Krishnan
103203aa9c51SUma Krishnan spin_lock_irqsave(&ctx->slock, lock_flags);
103303aa9c51SUma Krishnan
103403aa9c51SUma Krishnan for (;;) {
103503aa9c51SUma Krishnan prepare_to_wait(&ctx->wq, &event_wait, TASK_INTERRUPTIBLE);
103603aa9c51SUma Krishnan
1037f81face7SUma Krishnan if (ctx_event_pending(ctx) || (ctx->state == CLOSED))
103803aa9c51SUma Krishnan break;
103903aa9c51SUma Krishnan
104003aa9c51SUma Krishnan if (file->f_flags & O_NONBLOCK) {
104103aa9c51SUma Krishnan dev_err(dev, "%s: File cannot be blocked on I/O\n",
104203aa9c51SUma Krishnan __func__);
104303aa9c51SUma Krishnan rc = -EAGAIN;
104403aa9c51SUma Krishnan goto err;
104503aa9c51SUma Krishnan }
104603aa9c51SUma Krishnan
104703aa9c51SUma Krishnan if (signal_pending(current)) {
104803aa9c51SUma Krishnan dev_err(dev, "%s: Signal pending on the process\n",
104903aa9c51SUma Krishnan __func__);
105003aa9c51SUma Krishnan rc = -ERESTARTSYS;
105103aa9c51SUma Krishnan goto err;
105203aa9c51SUma Krishnan }
105303aa9c51SUma Krishnan
105403aa9c51SUma Krishnan spin_unlock_irqrestore(&ctx->slock, lock_flags);
105503aa9c51SUma Krishnan schedule();
105603aa9c51SUma Krishnan spin_lock_irqsave(&ctx->slock, lock_flags);
105703aa9c51SUma Krishnan }
105803aa9c51SUma Krishnan
105903aa9c51SUma Krishnan finish_wait(&ctx->wq, &event_wait);
106003aa9c51SUma Krishnan
106103aa9c51SUma Krishnan memset(&event, 0, sizeof(event));
106203aa9c51SUma Krishnan event.header.process_element = ctx->pe;
106303aa9c51SUma Krishnan event.header.size = sizeof(struct cxl_event_header);
106403aa9c51SUma Krishnan if (ctx->pending_irq) {
106503aa9c51SUma Krishnan esize = sizeof(struct cxl_event_afu_interrupt);
106603aa9c51SUma Krishnan event.header.size += esize;
106703aa9c51SUma Krishnan event.header.type = CXL_EVENT_AFU_INTERRUPT;
106803aa9c51SUma Krishnan
106903aa9c51SUma Krishnan bit = find_first_bit(&ctx->irq_bitmap, ctx->num_irqs);
107003aa9c51SUma Krishnan clear_bit(bit, &ctx->irq_bitmap);
107103aa9c51SUma Krishnan event.irq.irq = bit + 1;
107203aa9c51SUma Krishnan if (bitmap_empty(&ctx->irq_bitmap, ctx->num_irqs))
107303aa9c51SUma Krishnan ctx->pending_irq = false;
107466ae644bSUma Krishnan } else if (ctx->pending_fault) {
107566ae644bSUma Krishnan event.header.size += sizeof(struct cxl_event_data_storage);
107666ae644bSUma Krishnan event.header.type = CXL_EVENT_DATA_STORAGE;
107766ae644bSUma Krishnan event.fault.addr = ctx->fault_addr;
107866ae644bSUma Krishnan event.fault.dsisr = ctx->fault_dsisr;
107966ae644bSUma Krishnan ctx->pending_fault = false;
108003aa9c51SUma Krishnan }
108103aa9c51SUma Krishnan
108203aa9c51SUma Krishnan spin_unlock_irqrestore(&ctx->slock, lock_flags);
108303aa9c51SUma Krishnan
108403aa9c51SUma Krishnan if (copy_to_user(buf, &event, event.header.size)) {
108503aa9c51SUma Krishnan dev_err(dev, "%s: copy_to_user failed\n", __func__);
108603aa9c51SUma Krishnan rc = -EFAULT;
108703aa9c51SUma Krishnan goto out;
108803aa9c51SUma Krishnan }
108903aa9c51SUma Krishnan
109003aa9c51SUma Krishnan rc = event.header.size;
109103aa9c51SUma Krishnan out:
109203aa9c51SUma Krishnan return rc;
109303aa9c51SUma Krishnan err:
109403aa9c51SUma Krishnan finish_wait(&ctx->wq, &event_wait);
109503aa9c51SUma Krishnan spin_unlock_irqrestore(&ctx->slock, lock_flags);
109603aa9c51SUma Krishnan goto out;
109703aa9c51SUma Krishnan }
109803aa9c51SUma Krishnan
109993b8f8dfSUma Krishnan /**
110093b8f8dfSUma Krishnan * afu_release() - release and free the context
110193b8f8dfSUma Krishnan * @inode: File inode pointer.
110293b8f8dfSUma Krishnan * @file: File associated with the context.
110393b8f8dfSUma Krishnan *
110493b8f8dfSUma Krishnan * Return: 0 on success, -errno on failure
110593b8f8dfSUma Krishnan */
afu_release(struct inode * inode,struct file * file)110693b8f8dfSUma Krishnan static int afu_release(struct inode *inode, struct file *file)
110793b8f8dfSUma Krishnan {
110893b8f8dfSUma Krishnan struct ocxlflash_context *ctx = file->private_data;
110993b8f8dfSUma Krishnan int i;
111093b8f8dfSUma Krishnan
111193b8f8dfSUma Krishnan /* Unmap and free the interrupts associated with the context */
111293b8f8dfSUma Krishnan for (i = ctx->num_irqs; i >= 0; i--)
111393b8f8dfSUma Krishnan afu_unmap_irq(0, ctx, i, ctx);
111493b8f8dfSUma Krishnan free_afu_irqs(ctx);
111593b8f8dfSUma Krishnan
111693b8f8dfSUma Krishnan return ocxlflash_release_context(ctx);
111793b8f8dfSUma Krishnan }
111893b8f8dfSUma Krishnan
111993b8f8dfSUma Krishnan /**
112093b8f8dfSUma Krishnan * ocxlflash_mmap_fault() - mmap fault handler
112193b8f8dfSUma Krishnan * @vmf: VM fault associated with current fault.
112293b8f8dfSUma Krishnan *
112393b8f8dfSUma Krishnan * Return: 0 on success, -errno on failure
112493b8f8dfSUma Krishnan */
ocxlflash_mmap_fault(struct vm_fault * vmf)1125a38b80c5SSouptick Joarder static vm_fault_t ocxlflash_mmap_fault(struct vm_fault *vmf)
112693b8f8dfSUma Krishnan {
112793b8f8dfSUma Krishnan struct vm_area_struct *vma = vmf->vma;
112893b8f8dfSUma Krishnan struct ocxlflash_context *ctx = vma->vm_file->private_data;
1129f81face7SUma Krishnan struct device *dev = ctx->hw_afu->dev;
113093b8f8dfSUma Krishnan u64 mmio_area, offset;
113193b8f8dfSUma Krishnan
113293b8f8dfSUma Krishnan offset = vmf->pgoff << PAGE_SHIFT;
113393b8f8dfSUma Krishnan if (offset >= ctx->psn_size)
113493b8f8dfSUma Krishnan return VM_FAULT_SIGBUS;
113593b8f8dfSUma Krishnan
1136f81face7SUma Krishnan mutex_lock(&ctx->state_mutex);
1137f81face7SUma Krishnan if (ctx->state != STARTED) {
1138f81face7SUma Krishnan dev_err(dev, "%s: Context not started, state=%d\n",
1139f81face7SUma Krishnan __func__, ctx->state);
1140f81face7SUma Krishnan mutex_unlock(&ctx->state_mutex);
1141f81face7SUma Krishnan return VM_FAULT_SIGBUS;
1142f81face7SUma Krishnan }
1143f81face7SUma Krishnan mutex_unlock(&ctx->state_mutex);
1144f81face7SUma Krishnan
114593b8f8dfSUma Krishnan mmio_area = ctx->psn_phys;
114693b8f8dfSUma Krishnan mmio_area += offset;
114793b8f8dfSUma Krishnan
1148a38b80c5SSouptick Joarder return vmf_insert_pfn(vma, vmf->address, mmio_area >> PAGE_SHIFT);
114993b8f8dfSUma Krishnan }
115093b8f8dfSUma Krishnan
115193b8f8dfSUma Krishnan static const struct vm_operations_struct ocxlflash_vmops = {
115293b8f8dfSUma Krishnan .fault = ocxlflash_mmap_fault,
115393b8f8dfSUma Krishnan };
115493b8f8dfSUma Krishnan
115593b8f8dfSUma Krishnan /**
115693b8f8dfSUma Krishnan * afu_mmap() - map the fault handler operations
115793b8f8dfSUma Krishnan * @file: File associated with the context.
115893b8f8dfSUma Krishnan * @vma: VM area associated with mapping.
115993b8f8dfSUma Krishnan *
116093b8f8dfSUma Krishnan * Return: 0 on success, -errno on failure
116193b8f8dfSUma Krishnan */
afu_mmap(struct file * file,struct vm_area_struct * vma)116293b8f8dfSUma Krishnan static int afu_mmap(struct file *file, struct vm_area_struct *vma)
116393b8f8dfSUma Krishnan {
116493b8f8dfSUma Krishnan struct ocxlflash_context *ctx = file->private_data;
116593b8f8dfSUma Krishnan
116693b8f8dfSUma Krishnan if ((vma_pages(vma) + vma->vm_pgoff) >
116793b8f8dfSUma Krishnan (ctx->psn_size >> PAGE_SHIFT))
116893b8f8dfSUma Krishnan return -EINVAL;
116993b8f8dfSUma Krishnan
1170*1c71222eSSuren Baghdasaryan vm_flags_set(vma, VM_IO | VM_PFNMAP);
117193b8f8dfSUma Krishnan vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
117293b8f8dfSUma Krishnan vma->vm_ops = &ocxlflash_vmops;
117393b8f8dfSUma Krishnan return 0;
117493b8f8dfSUma Krishnan }
117593b8f8dfSUma Krishnan
1176926a62f9SUma Krishnan static const struct file_operations ocxl_afu_fops = {
1177926a62f9SUma Krishnan .owner = THIS_MODULE,
117856f1db1aSUma Krishnan .poll = afu_poll,
117903aa9c51SUma Krishnan .read = afu_read,
118093b8f8dfSUma Krishnan .release = afu_release,
118193b8f8dfSUma Krishnan .mmap = afu_mmap,
1182926a62f9SUma Krishnan };
1183926a62f9SUma Krishnan
118456f1db1aSUma Krishnan #define PATCH_FOPS(NAME) \
118556f1db1aSUma Krishnan do { if (!fops->NAME) fops->NAME = ocxl_afu_fops.NAME; } while (0)
118656f1db1aSUma Krishnan
1187926a62f9SUma Krishnan /**
1188926a62f9SUma Krishnan * ocxlflash_get_fd() - get file descriptor for an adapter context
1189926a62f9SUma Krishnan * @ctx_cookie: Adapter context.
1190926a62f9SUma Krishnan * @fops: File operations to be associated.
1191926a62f9SUma Krishnan * @fd: File descriptor to be returned back.
1192926a62f9SUma Krishnan *
1193926a62f9SUma Krishnan * Return: pointer to the file on success, ERR_PTR on failure
1194926a62f9SUma Krishnan */
ocxlflash_get_fd(void * ctx_cookie,struct file_operations * fops,int * fd)1195926a62f9SUma Krishnan static struct file *ocxlflash_get_fd(void *ctx_cookie,
1196926a62f9SUma Krishnan struct file_operations *fops, int *fd)
1197926a62f9SUma Krishnan {
1198926a62f9SUma Krishnan struct ocxlflash_context *ctx = ctx_cookie;
1199926a62f9SUma Krishnan struct device *dev = ctx->hw_afu->dev;
1200926a62f9SUma Krishnan struct file *file;
1201926a62f9SUma Krishnan int flags, fdtmp;
1202926a62f9SUma Krishnan int rc = 0;
1203926a62f9SUma Krishnan char *name = NULL;
1204926a62f9SUma Krishnan
1205926a62f9SUma Krishnan /* Only allow one fd per context */
1206926a62f9SUma Krishnan if (ctx->mapping) {
1207926a62f9SUma Krishnan dev_err(dev, "%s: Context is already mapped to an fd\n",
1208926a62f9SUma Krishnan __func__);
1209926a62f9SUma Krishnan rc = -EEXIST;
1210926a62f9SUma Krishnan goto err1;
1211926a62f9SUma Krishnan }
1212926a62f9SUma Krishnan
1213926a62f9SUma Krishnan flags = O_RDWR | O_CLOEXEC;
1214926a62f9SUma Krishnan
1215926a62f9SUma Krishnan /* This code is similar to anon_inode_getfd() */
1216926a62f9SUma Krishnan rc = get_unused_fd_flags(flags);
1217926a62f9SUma Krishnan if (unlikely(rc < 0)) {
1218926a62f9SUma Krishnan dev_err(dev, "%s: get_unused_fd_flags failed rc=%d\n",
1219926a62f9SUma Krishnan __func__, rc);
1220926a62f9SUma Krishnan goto err1;
1221926a62f9SUma Krishnan }
1222926a62f9SUma Krishnan fdtmp = rc;
1223926a62f9SUma Krishnan
122456f1db1aSUma Krishnan /* Patch the file ops that are not defined */
122556f1db1aSUma Krishnan if (fops) {
122656f1db1aSUma Krishnan PATCH_FOPS(poll);
122703aa9c51SUma Krishnan PATCH_FOPS(read);
122893b8f8dfSUma Krishnan PATCH_FOPS(release);
122993b8f8dfSUma Krishnan PATCH_FOPS(mmap);
123056f1db1aSUma Krishnan } else /* Use default ops */
1231926a62f9SUma Krishnan fops = (struct file_operations *)&ocxl_afu_fops;
1232926a62f9SUma Krishnan
1233926a62f9SUma Krishnan name = kasprintf(GFP_KERNEL, "ocxlflash:%d", ctx->pe);
1234926a62f9SUma Krishnan file = ocxlflash_getfile(dev, name, fops, ctx, flags);
1235926a62f9SUma Krishnan kfree(name);
1236926a62f9SUma Krishnan if (IS_ERR(file)) {
1237926a62f9SUma Krishnan rc = PTR_ERR(file);
1238926a62f9SUma Krishnan dev_err(dev, "%s: ocxlflash_getfile failed rc=%d\n",
1239926a62f9SUma Krishnan __func__, rc);
1240926a62f9SUma Krishnan goto err2;
1241926a62f9SUma Krishnan }
1242926a62f9SUma Krishnan
1243926a62f9SUma Krishnan ctx->mapping = file->f_mapping;
1244926a62f9SUma Krishnan *fd = fdtmp;
1245926a62f9SUma Krishnan out:
1246926a62f9SUma Krishnan return file;
1247926a62f9SUma Krishnan err2:
1248926a62f9SUma Krishnan put_unused_fd(fdtmp);
1249926a62f9SUma Krishnan err1:
1250926a62f9SUma Krishnan file = ERR_PTR(rc);
1251926a62f9SUma Krishnan goto out;
1252926a62f9SUma Krishnan }
1253926a62f9SUma Krishnan
1254b18718c6SUma Krishnan /**
1255b18718c6SUma Krishnan * ocxlflash_fops_get_context() - get the context associated with the file
1256b18718c6SUma Krishnan * @file: File associated with the adapter context.
1257b18718c6SUma Krishnan *
1258b18718c6SUma Krishnan * Return: pointer to the context
1259b18718c6SUma Krishnan */
ocxlflash_fops_get_context(struct file * file)1260b18718c6SUma Krishnan static void *ocxlflash_fops_get_context(struct file *file)
1261b18718c6SUma Krishnan {
1262b18718c6SUma Krishnan return file->private_data;
1263b18718c6SUma Krishnan }
1264b18718c6SUma Krishnan
1265762c7e93SUma Krishnan /**
1266762c7e93SUma Krishnan * ocxlflash_afu_irq() - interrupt handler for user contexts
1267762c7e93SUma Krishnan * @irq: Interrupt number.
1268762c7e93SUma Krishnan * @data: Private data provided at interrupt registration, the context.
1269762c7e93SUma Krishnan *
1270762c7e93SUma Krishnan * Return: Always return IRQ_HANDLED.
1271762c7e93SUma Krishnan */
ocxlflash_afu_irq(int irq,void * data)1272762c7e93SUma Krishnan static irqreturn_t ocxlflash_afu_irq(int irq, void *data)
1273762c7e93SUma Krishnan {
1274762c7e93SUma Krishnan struct ocxlflash_context *ctx = data;
1275762c7e93SUma Krishnan struct device *dev = ctx->hw_afu->dev;
1276762c7e93SUma Krishnan int i;
1277762c7e93SUma Krishnan
1278762c7e93SUma Krishnan dev_dbg(dev, "%s: Interrupt raised for pe %i virq %i\n",
1279762c7e93SUma Krishnan __func__, ctx->pe, irq);
1280762c7e93SUma Krishnan
1281762c7e93SUma Krishnan for (i = 0; i < ctx->num_irqs; i++) {
1282762c7e93SUma Krishnan if (ctx->irqs[i].virq == irq)
1283762c7e93SUma Krishnan break;
1284762c7e93SUma Krishnan }
1285762c7e93SUma Krishnan if (unlikely(i >= ctx->num_irqs)) {
1286762c7e93SUma Krishnan dev_err(dev, "%s: Received AFU IRQ out of range\n", __func__);
1287762c7e93SUma Krishnan goto out;
1288762c7e93SUma Krishnan }
1289762c7e93SUma Krishnan
1290762c7e93SUma Krishnan spin_lock(&ctx->slock);
1291762c7e93SUma Krishnan set_bit(i - 1, &ctx->irq_bitmap);
1292762c7e93SUma Krishnan ctx->pending_irq = true;
1293762c7e93SUma Krishnan spin_unlock(&ctx->slock);
129456f1db1aSUma Krishnan
129556f1db1aSUma Krishnan wake_up_all(&ctx->wq);
1296762c7e93SUma Krishnan out:
1297762c7e93SUma Krishnan return IRQ_HANDLED;
1298762c7e93SUma Krishnan }
1299762c7e93SUma Krishnan
1300762c7e93SUma Krishnan /**
1301762c7e93SUma Krishnan * ocxlflash_start_work() - start a user context
1302762c7e93SUma Krishnan * @ctx_cookie: Context to be started.
1303762c7e93SUma Krishnan * @num_irqs: Number of interrupts requested.
1304762c7e93SUma Krishnan *
1305762c7e93SUma Krishnan * Return: 0 on success, -errno on failure
1306762c7e93SUma Krishnan */
ocxlflash_start_work(void * ctx_cookie,u64 num_irqs)1307762c7e93SUma Krishnan static int ocxlflash_start_work(void *ctx_cookie, u64 num_irqs)
1308762c7e93SUma Krishnan {
1309762c7e93SUma Krishnan struct ocxlflash_context *ctx = ctx_cookie;
1310762c7e93SUma Krishnan struct ocxl_hw_afu *afu = ctx->hw_afu;
1311762c7e93SUma Krishnan struct device *dev = afu->dev;
1312762c7e93SUma Krishnan char *name;
1313762c7e93SUma Krishnan int rc = 0;
1314762c7e93SUma Krishnan int i;
1315762c7e93SUma Krishnan
1316762c7e93SUma Krishnan rc = alloc_afu_irqs(ctx, num_irqs);
1317762c7e93SUma Krishnan if (unlikely(rc < 0)) {
1318762c7e93SUma Krishnan dev_err(dev, "%s: alloc_afu_irqs failed rc=%d\n", __func__, rc);
1319762c7e93SUma Krishnan goto out;
1320762c7e93SUma Krishnan }
1321762c7e93SUma Krishnan
1322762c7e93SUma Krishnan for (i = 0; i < num_irqs; i++) {
1323762c7e93SUma Krishnan name = kasprintf(GFP_KERNEL, "ocxlflash-%s-pe%i-%i",
1324762c7e93SUma Krishnan dev_name(dev), ctx->pe, i);
1325762c7e93SUma Krishnan rc = afu_map_irq(0, ctx, i, ocxlflash_afu_irq, ctx, name);
1326762c7e93SUma Krishnan kfree(name);
1327762c7e93SUma Krishnan if (unlikely(rc < 0)) {
1328762c7e93SUma Krishnan dev_err(dev, "%s: afu_map_irq failed rc=%d\n",
1329762c7e93SUma Krishnan __func__, rc);
1330762c7e93SUma Krishnan goto err;
1331762c7e93SUma Krishnan }
1332762c7e93SUma Krishnan }
1333762c7e93SUma Krishnan
1334762c7e93SUma Krishnan rc = start_context(ctx);
1335762c7e93SUma Krishnan if (unlikely(rc)) {
1336762c7e93SUma Krishnan dev_err(dev, "%s: start_context failed rc=%d\n", __func__, rc);
1337762c7e93SUma Krishnan goto err;
1338762c7e93SUma Krishnan }
1339762c7e93SUma Krishnan out:
1340762c7e93SUma Krishnan return rc;
1341762c7e93SUma Krishnan err:
1342762c7e93SUma Krishnan for (i = i-1; i >= 0; i--)
1343762c7e93SUma Krishnan afu_unmap_irq(0, ctx, i, ctx);
1344762c7e93SUma Krishnan free_afu_irqs(ctx);
1345762c7e93SUma Krishnan goto out;
1346e117c3c7SUma Krishnan };
1347e117c3c7SUma Krishnan
1348e117c3c7SUma Krishnan /**
1349e117c3c7SUma Krishnan * ocxlflash_fd_mmap() - mmap handler for adapter file descriptor
1350e117c3c7SUma Krishnan * @file: File installed with adapter file descriptor.
1351e117c3c7SUma Krishnan * @vma: VM area associated with mapping.
1352e117c3c7SUma Krishnan *
1353e117c3c7SUma Krishnan * Return: 0 on success, -errno on failure
1354e117c3c7SUma Krishnan */
ocxlflash_fd_mmap(struct file * file,struct vm_area_struct * vma)1355e117c3c7SUma Krishnan static int ocxlflash_fd_mmap(struct file *file, struct vm_area_struct *vma)
1356e117c3c7SUma Krishnan {
1357e117c3c7SUma Krishnan return afu_mmap(file, vma);
1358e117c3c7SUma Krishnan }
1359e117c3c7SUma Krishnan
1360e117c3c7SUma Krishnan /**
1361e117c3c7SUma Krishnan * ocxlflash_fd_release() - release the context associated with the file
1362e117c3c7SUma Krishnan * @inode: File inode pointer.
1363e117c3c7SUma Krishnan * @file: File associated with the adapter context.
1364e117c3c7SUma Krishnan *
1365e117c3c7SUma Krishnan * Return: 0 on success, -errno on failure
1366e117c3c7SUma Krishnan */
ocxlflash_fd_release(struct inode * inode,struct file * file)1367e117c3c7SUma Krishnan static int ocxlflash_fd_release(struct inode *inode, struct file *file)
1368e117c3c7SUma Krishnan {
1369e117c3c7SUma Krishnan return afu_release(inode, file);
1370762c7e93SUma Krishnan }
1371762c7e93SUma Krishnan
137276ebe01fSUma Krishnan /* Backend ops to ocxlflash services */
137376ebe01fSUma Krishnan const struct cxlflash_backend_ops cxlflash_ocxl_ops = {
137476ebe01fSUma Krishnan .module = THIS_MODULE,
1375012f394cSUma Krishnan .psa_map = ocxlflash_psa_map,
1376012f394cSUma Krishnan .psa_unmap = ocxlflash_psa_unmap,
1377b18718c6SUma Krishnan .process_element = ocxlflash_process_element,
1378a06b1cfcSUma Krishnan .map_afu_irq = ocxlflash_map_afu_irq,
1379a06b1cfcSUma Krishnan .unmap_afu_irq = ocxlflash_unmap_afu_irq,
1380402a55eaSUma Krishnan .get_irq_objhndl = ocxlflash_get_irq_objhndl,
13816b938ac9SUma Krishnan .start_context = ocxlflash_start_context,
1382c207b571SUma Krishnan .stop_context = ocxlflash_stop_context,
13839433fb32SUma Krishnan .afu_reset = ocxlflash_afu_reset,
1384f6b4557cSUma Krishnan .set_master = ocxlflash_set_master,
1385f6b4557cSUma Krishnan .get_context = ocxlflash_get_context,
1386f6b4557cSUma Krishnan .dev_context_init = ocxlflash_dev_context_init,
1387f6b4557cSUma Krishnan .release_context = ocxlflash_release_context,
13888b7a5521SUma Krishnan .perst_reloads_same_image = ocxlflash_perst_reloads_same_image,
1389119c9200SUma Krishnan .read_adapter_vpd = ocxlflash_read_adapter_vpd,
1390bc65c1c7SUma Krishnan .allocate_afu_irqs = ocxlflash_allocate_afu_irqs,
1391bc65c1c7SUma Krishnan .free_afu_irqs = ocxlflash_free_afu_irqs,
139248e077dbSUma Krishnan .create_afu = ocxlflash_create_afu,
139348e077dbSUma Krishnan .destroy_afu = ocxlflash_destroy_afu,
1394926a62f9SUma Krishnan .get_fd = ocxlflash_get_fd,
1395b18718c6SUma Krishnan .fops_get_context = ocxlflash_fops_get_context,
1396762c7e93SUma Krishnan .start_work = ocxlflash_start_work,
1397e117c3c7SUma Krishnan .fd_mmap = ocxlflash_fd_mmap,
1398e117c3c7SUma Krishnan .fd_release = ocxlflash_fd_release,
139976ebe01fSUma Krishnan };
1400