xref: /openbmc/linux/drivers/misc/cxl/guest.c (revision 14baf4d9c739e6e69150512d2eb23c71fffcc192)
1*14baf4d9SChristophe Lombard /*
2*14baf4d9SChristophe Lombard  * Copyright 2015 IBM Corp.
3*14baf4d9SChristophe Lombard  *
4*14baf4d9SChristophe Lombard  * This program is free software; you can redistribute it and/or
5*14baf4d9SChristophe Lombard  * modify it under the terms of the GNU General Public License
6*14baf4d9SChristophe Lombard  * as published by the Free Software Foundation; either version
7*14baf4d9SChristophe Lombard  * 2 of the License, or (at your option) any later version.
8*14baf4d9SChristophe Lombard  */
9*14baf4d9SChristophe Lombard 
10*14baf4d9SChristophe Lombard #include <linux/spinlock.h>
11*14baf4d9SChristophe Lombard #include <linux/uaccess.h>
12*14baf4d9SChristophe Lombard #include <linux/delay.h>
13*14baf4d9SChristophe Lombard 
14*14baf4d9SChristophe Lombard #include "cxl.h"
15*14baf4d9SChristophe Lombard #include "hcalls.h"
16*14baf4d9SChristophe Lombard #include "trace.h"
17*14baf4d9SChristophe Lombard 
18*14baf4d9SChristophe Lombard 
19*14baf4d9SChristophe Lombard static irqreturn_t guest_handle_psl_slice_error(struct cxl_context *ctx, u64 dsisr,
20*14baf4d9SChristophe Lombard 					u64 errstat)
21*14baf4d9SChristophe Lombard {
22*14baf4d9SChristophe Lombard 	pr_devel("in %s\n", __func__);
23*14baf4d9SChristophe Lombard 	dev_crit(&ctx->afu->dev, "PSL ERROR STATUS: 0x%.16llx\n", errstat);
24*14baf4d9SChristophe Lombard 
25*14baf4d9SChristophe Lombard 	return cxl_ops->ack_irq(ctx, 0, errstat);
26*14baf4d9SChristophe Lombard }
27*14baf4d9SChristophe Lombard 
28*14baf4d9SChristophe Lombard static ssize_t guest_collect_vpd(struct cxl *adapter, struct cxl_afu *afu,
29*14baf4d9SChristophe Lombard 			void *buf, size_t len)
30*14baf4d9SChristophe Lombard {
31*14baf4d9SChristophe Lombard 	unsigned int entries, mod;
32*14baf4d9SChristophe Lombard 	unsigned long **vpd_buf = NULL;
33*14baf4d9SChristophe Lombard 	struct sg_list *le;
34*14baf4d9SChristophe Lombard 	int rc = 0, i, tocopy;
35*14baf4d9SChristophe Lombard 	u64 out = 0;
36*14baf4d9SChristophe Lombard 
37*14baf4d9SChristophe Lombard 	if (buf == NULL)
38*14baf4d9SChristophe Lombard 		return -EINVAL;
39*14baf4d9SChristophe Lombard 
40*14baf4d9SChristophe Lombard 	/* number of entries in the list */
41*14baf4d9SChristophe Lombard 	entries = len / SG_BUFFER_SIZE;
42*14baf4d9SChristophe Lombard 	mod = len % SG_BUFFER_SIZE;
43*14baf4d9SChristophe Lombard 	if (mod)
44*14baf4d9SChristophe Lombard 		entries++;
45*14baf4d9SChristophe Lombard 
46*14baf4d9SChristophe Lombard 	if (entries > SG_MAX_ENTRIES) {
47*14baf4d9SChristophe Lombard 		entries = SG_MAX_ENTRIES;
48*14baf4d9SChristophe Lombard 		len = SG_MAX_ENTRIES * SG_BUFFER_SIZE;
49*14baf4d9SChristophe Lombard 		mod = 0;
50*14baf4d9SChristophe Lombard 	}
51*14baf4d9SChristophe Lombard 
52*14baf4d9SChristophe Lombard 	vpd_buf = kzalloc(entries * sizeof(unsigned long *), GFP_KERNEL);
53*14baf4d9SChristophe Lombard 	if (!vpd_buf)
54*14baf4d9SChristophe Lombard 		return -ENOMEM;
55*14baf4d9SChristophe Lombard 
56*14baf4d9SChristophe Lombard 	le = (struct sg_list *)get_zeroed_page(GFP_KERNEL);
57*14baf4d9SChristophe Lombard 	if (!le) {
58*14baf4d9SChristophe Lombard 		rc = -ENOMEM;
59*14baf4d9SChristophe Lombard 		goto err1;
60*14baf4d9SChristophe Lombard 	}
61*14baf4d9SChristophe Lombard 
62*14baf4d9SChristophe Lombard 	for (i = 0; i < entries; i++) {
63*14baf4d9SChristophe Lombard 		vpd_buf[i] = (unsigned long *)get_zeroed_page(GFP_KERNEL);
64*14baf4d9SChristophe Lombard 		if (!vpd_buf[i]) {
65*14baf4d9SChristophe Lombard 			rc = -ENOMEM;
66*14baf4d9SChristophe Lombard 			goto err2;
67*14baf4d9SChristophe Lombard 		}
68*14baf4d9SChristophe Lombard 		le[i].phys_addr = cpu_to_be64(virt_to_phys(vpd_buf[i]));
69*14baf4d9SChristophe Lombard 		le[i].len = cpu_to_be64(SG_BUFFER_SIZE);
70*14baf4d9SChristophe Lombard 		if ((i == (entries - 1)) && mod)
71*14baf4d9SChristophe Lombard 			le[i].len = cpu_to_be64(mod);
72*14baf4d9SChristophe Lombard 	}
73*14baf4d9SChristophe Lombard 
74*14baf4d9SChristophe Lombard 	if (adapter)
75*14baf4d9SChristophe Lombard 		rc = cxl_h_collect_vpd_adapter(adapter->guest->handle,
76*14baf4d9SChristophe Lombard 					virt_to_phys(le), entries, &out);
77*14baf4d9SChristophe Lombard 	else
78*14baf4d9SChristophe Lombard 		rc = cxl_h_collect_vpd(afu->guest->handle, 0,
79*14baf4d9SChristophe Lombard 				virt_to_phys(le), entries, &out);
80*14baf4d9SChristophe Lombard 	pr_devel("length of available (entries: %i), vpd: %#llx\n",
81*14baf4d9SChristophe Lombard 		entries, out);
82*14baf4d9SChristophe Lombard 
83*14baf4d9SChristophe Lombard 	if (!rc) {
84*14baf4d9SChristophe Lombard 		/*
85*14baf4d9SChristophe Lombard 		 * hcall returns in 'out' the size of available VPDs.
86*14baf4d9SChristophe Lombard 		 * It fills the buffer with as much data as possible.
87*14baf4d9SChristophe Lombard 		 */
88*14baf4d9SChristophe Lombard 		if (out < len)
89*14baf4d9SChristophe Lombard 			len = out;
90*14baf4d9SChristophe Lombard 		rc = len;
91*14baf4d9SChristophe Lombard 		if (out) {
92*14baf4d9SChristophe Lombard 			for (i = 0; i < entries; i++) {
93*14baf4d9SChristophe Lombard 				if (len < SG_BUFFER_SIZE)
94*14baf4d9SChristophe Lombard 					tocopy = len;
95*14baf4d9SChristophe Lombard 				else
96*14baf4d9SChristophe Lombard 					tocopy = SG_BUFFER_SIZE;
97*14baf4d9SChristophe Lombard 				memcpy(buf, vpd_buf[i], tocopy);
98*14baf4d9SChristophe Lombard 				buf += tocopy;
99*14baf4d9SChristophe Lombard 				len -= tocopy;
100*14baf4d9SChristophe Lombard 			}
101*14baf4d9SChristophe Lombard 		}
102*14baf4d9SChristophe Lombard 	}
103*14baf4d9SChristophe Lombard err2:
104*14baf4d9SChristophe Lombard 	for (i = 0; i < entries; i++) {
105*14baf4d9SChristophe Lombard 		if (vpd_buf[i])
106*14baf4d9SChristophe Lombard 			free_page((unsigned long) vpd_buf[i]);
107*14baf4d9SChristophe Lombard 	}
108*14baf4d9SChristophe Lombard 	free_page((unsigned long) le);
109*14baf4d9SChristophe Lombard err1:
110*14baf4d9SChristophe Lombard 	kfree(vpd_buf);
111*14baf4d9SChristophe Lombard 	return rc;
112*14baf4d9SChristophe Lombard }
113*14baf4d9SChristophe Lombard 
114*14baf4d9SChristophe Lombard static int guest_get_irq_info(struct cxl_context *ctx, struct cxl_irq_info *info)
115*14baf4d9SChristophe Lombard {
116*14baf4d9SChristophe Lombard 	return cxl_h_collect_int_info(ctx->afu->guest->handle, ctx->process_token, info);
117*14baf4d9SChristophe Lombard }
118*14baf4d9SChristophe Lombard 
119*14baf4d9SChristophe Lombard static irqreturn_t guest_psl_irq(int irq, void *data)
120*14baf4d9SChristophe Lombard {
121*14baf4d9SChristophe Lombard 	struct cxl_context *ctx = data;
122*14baf4d9SChristophe Lombard 	struct cxl_irq_info irq_info;
123*14baf4d9SChristophe Lombard 	int rc;
124*14baf4d9SChristophe Lombard 
125*14baf4d9SChristophe Lombard 	pr_devel("%d: received PSL interrupt %i\n", ctx->pe, irq);
126*14baf4d9SChristophe Lombard 	rc = guest_get_irq_info(ctx, &irq_info);
127*14baf4d9SChristophe Lombard 	if (rc) {
128*14baf4d9SChristophe Lombard 		WARN(1, "Unable to get IRQ info: %i\n", rc);
129*14baf4d9SChristophe Lombard 		return IRQ_HANDLED;
130*14baf4d9SChristophe Lombard 	}
131*14baf4d9SChristophe Lombard 
132*14baf4d9SChristophe Lombard 	rc = cxl_irq(irq, ctx, &irq_info);
133*14baf4d9SChristophe Lombard 	return rc;
134*14baf4d9SChristophe Lombard }
135*14baf4d9SChristophe Lombard 
136*14baf4d9SChristophe Lombard static irqreturn_t guest_slice_irq_err(int irq, void *data)
137*14baf4d9SChristophe Lombard {
138*14baf4d9SChristophe Lombard 	struct cxl_afu *afu = data;
139*14baf4d9SChristophe Lombard 	int rc;
140*14baf4d9SChristophe Lombard 	u64 serr;
141*14baf4d9SChristophe Lombard 
142*14baf4d9SChristophe Lombard 	WARN(irq, "CXL SLICE ERROR interrupt %i\n", irq);
143*14baf4d9SChristophe Lombard 	rc = cxl_h_get_fn_error_interrupt(afu->guest->handle, &serr);
144*14baf4d9SChristophe Lombard 	if (rc) {
145*14baf4d9SChristophe Lombard 		dev_crit(&afu->dev, "Couldn't read PSL_SERR_An: %d\n", rc);
146*14baf4d9SChristophe Lombard 		return IRQ_HANDLED;
147*14baf4d9SChristophe Lombard 	}
148*14baf4d9SChristophe Lombard 	dev_crit(&afu->dev, "PSL_SERR_An: 0x%.16llx\n", serr);
149*14baf4d9SChristophe Lombard 
150*14baf4d9SChristophe Lombard 	rc = cxl_h_ack_fn_error_interrupt(afu->guest->handle, serr);
151*14baf4d9SChristophe Lombard 	if (rc)
152*14baf4d9SChristophe Lombard 		dev_crit(&afu->dev, "Couldn't ack slice error interrupt: %d\n",
153*14baf4d9SChristophe Lombard 			rc);
154*14baf4d9SChristophe Lombard 
155*14baf4d9SChristophe Lombard 	return IRQ_HANDLED;
156*14baf4d9SChristophe Lombard }
157*14baf4d9SChristophe Lombard 
158*14baf4d9SChristophe Lombard 
159*14baf4d9SChristophe Lombard static int irq_alloc_range(struct cxl *adapter, int len, int *irq)
160*14baf4d9SChristophe Lombard {
161*14baf4d9SChristophe Lombard 	int i, n;
162*14baf4d9SChristophe Lombard 	struct irq_avail *cur;
163*14baf4d9SChristophe Lombard 
164*14baf4d9SChristophe Lombard 	for (i = 0; i < adapter->guest->irq_nranges; i++) {
165*14baf4d9SChristophe Lombard 		cur = &adapter->guest->irq_avail[i];
166*14baf4d9SChristophe Lombard 		n = bitmap_find_next_zero_area(cur->bitmap, cur->range,
167*14baf4d9SChristophe Lombard 					0, len, 0);
168*14baf4d9SChristophe Lombard 		if (n < cur->range) {
169*14baf4d9SChristophe Lombard 			bitmap_set(cur->bitmap, n, len);
170*14baf4d9SChristophe Lombard 			*irq = cur->offset + n;
171*14baf4d9SChristophe Lombard 			pr_devel("guest: allocate IRQs %#x->%#x\n",
172*14baf4d9SChristophe Lombard 				*irq, *irq + len - 1);
173*14baf4d9SChristophe Lombard 
174*14baf4d9SChristophe Lombard 			return 0;
175*14baf4d9SChristophe Lombard 		}
176*14baf4d9SChristophe Lombard 	}
177*14baf4d9SChristophe Lombard 	return -ENOSPC;
178*14baf4d9SChristophe Lombard }
179*14baf4d9SChristophe Lombard 
180*14baf4d9SChristophe Lombard static int irq_free_range(struct cxl *adapter, int irq, int len)
181*14baf4d9SChristophe Lombard {
182*14baf4d9SChristophe Lombard 	int i, n;
183*14baf4d9SChristophe Lombard 	struct irq_avail *cur;
184*14baf4d9SChristophe Lombard 
185*14baf4d9SChristophe Lombard 	if (len == 0)
186*14baf4d9SChristophe Lombard 		return -ENOENT;
187*14baf4d9SChristophe Lombard 
188*14baf4d9SChristophe Lombard 	for (i = 0; i < adapter->guest->irq_nranges; i++) {
189*14baf4d9SChristophe Lombard 		cur = &adapter->guest->irq_avail[i];
190*14baf4d9SChristophe Lombard 		if (irq >= cur->offset &&
191*14baf4d9SChristophe Lombard 			(irq + len) <= (cur->offset + cur->range)) {
192*14baf4d9SChristophe Lombard 			n = irq - cur->offset;
193*14baf4d9SChristophe Lombard 			bitmap_clear(cur->bitmap, n, len);
194*14baf4d9SChristophe Lombard 			pr_devel("guest: release IRQs %#x->%#x\n",
195*14baf4d9SChristophe Lombard 				irq, irq + len - 1);
196*14baf4d9SChristophe Lombard 			return 0;
197*14baf4d9SChristophe Lombard 		}
198*14baf4d9SChristophe Lombard 	}
199*14baf4d9SChristophe Lombard 	return -ENOENT;
200*14baf4d9SChristophe Lombard }
201*14baf4d9SChristophe Lombard 
202*14baf4d9SChristophe Lombard static int guest_reset(struct cxl *adapter)
203*14baf4d9SChristophe Lombard {
204*14baf4d9SChristophe Lombard 	int rc;
205*14baf4d9SChristophe Lombard 
206*14baf4d9SChristophe Lombard 	pr_devel("Adapter reset request\n");
207*14baf4d9SChristophe Lombard 	rc = cxl_h_reset_adapter(adapter->guest->handle);
208*14baf4d9SChristophe Lombard 	return rc;
209*14baf4d9SChristophe Lombard }
210*14baf4d9SChristophe Lombard 
211*14baf4d9SChristophe Lombard static int guest_alloc_one_irq(struct cxl *adapter)
212*14baf4d9SChristophe Lombard {
213*14baf4d9SChristophe Lombard 	int irq;
214*14baf4d9SChristophe Lombard 
215*14baf4d9SChristophe Lombard 	spin_lock(&adapter->guest->irq_alloc_lock);
216*14baf4d9SChristophe Lombard 	if (irq_alloc_range(adapter, 1, &irq))
217*14baf4d9SChristophe Lombard 		irq = -ENOSPC;
218*14baf4d9SChristophe Lombard 	spin_unlock(&adapter->guest->irq_alloc_lock);
219*14baf4d9SChristophe Lombard 	return irq;
220*14baf4d9SChristophe Lombard }
221*14baf4d9SChristophe Lombard 
222*14baf4d9SChristophe Lombard static void guest_release_one_irq(struct cxl *adapter, int irq)
223*14baf4d9SChristophe Lombard {
224*14baf4d9SChristophe Lombard 	spin_lock(&adapter->guest->irq_alloc_lock);
225*14baf4d9SChristophe Lombard 	irq_free_range(adapter, irq, 1);
226*14baf4d9SChristophe Lombard 	spin_unlock(&adapter->guest->irq_alloc_lock);
227*14baf4d9SChristophe Lombard }
228*14baf4d9SChristophe Lombard 
229*14baf4d9SChristophe Lombard static int guest_alloc_irq_ranges(struct cxl_irq_ranges *irqs,
230*14baf4d9SChristophe Lombard 				struct cxl *adapter, unsigned int num)
231*14baf4d9SChristophe Lombard {
232*14baf4d9SChristophe Lombard 	int i, try, irq;
233*14baf4d9SChristophe Lombard 
234*14baf4d9SChristophe Lombard 	memset(irqs, 0, sizeof(struct cxl_irq_ranges));
235*14baf4d9SChristophe Lombard 
236*14baf4d9SChristophe Lombard 	spin_lock(&adapter->guest->irq_alloc_lock);
237*14baf4d9SChristophe Lombard 	for (i = 0; i < CXL_IRQ_RANGES && num; i++) {
238*14baf4d9SChristophe Lombard 		try = num;
239*14baf4d9SChristophe Lombard 		while (try) {
240*14baf4d9SChristophe Lombard 			if (irq_alloc_range(adapter, try, &irq) == 0)
241*14baf4d9SChristophe Lombard 				break;
242*14baf4d9SChristophe Lombard 			try /= 2;
243*14baf4d9SChristophe Lombard 		}
244*14baf4d9SChristophe Lombard 		if (!try)
245*14baf4d9SChristophe Lombard 			goto error;
246*14baf4d9SChristophe Lombard 		irqs->offset[i] = irq;
247*14baf4d9SChristophe Lombard 		irqs->range[i] = try;
248*14baf4d9SChristophe Lombard 		num -= try;
249*14baf4d9SChristophe Lombard 	}
250*14baf4d9SChristophe Lombard 	if (num)
251*14baf4d9SChristophe Lombard 		goto error;
252*14baf4d9SChristophe Lombard 	spin_unlock(&adapter->guest->irq_alloc_lock);
253*14baf4d9SChristophe Lombard 	return 0;
254*14baf4d9SChristophe Lombard 
255*14baf4d9SChristophe Lombard error:
256*14baf4d9SChristophe Lombard 	for (i = 0; i < CXL_IRQ_RANGES; i++)
257*14baf4d9SChristophe Lombard 		irq_free_range(adapter, irqs->offset[i], irqs->range[i]);
258*14baf4d9SChristophe Lombard 	spin_unlock(&adapter->guest->irq_alloc_lock);
259*14baf4d9SChristophe Lombard 	return -ENOSPC;
260*14baf4d9SChristophe Lombard }
261*14baf4d9SChristophe Lombard 
262*14baf4d9SChristophe Lombard static void guest_release_irq_ranges(struct cxl_irq_ranges *irqs,
263*14baf4d9SChristophe Lombard 				struct cxl *adapter)
264*14baf4d9SChristophe Lombard {
265*14baf4d9SChristophe Lombard 	int i;
266*14baf4d9SChristophe Lombard 
267*14baf4d9SChristophe Lombard 	spin_lock(&adapter->guest->irq_alloc_lock);
268*14baf4d9SChristophe Lombard 	for (i = 0; i < CXL_IRQ_RANGES; i++)
269*14baf4d9SChristophe Lombard 		irq_free_range(adapter, irqs->offset[i], irqs->range[i]);
270*14baf4d9SChristophe Lombard 	spin_unlock(&adapter->guest->irq_alloc_lock);
271*14baf4d9SChristophe Lombard }
272*14baf4d9SChristophe Lombard 
273*14baf4d9SChristophe Lombard static int guest_register_serr_irq(struct cxl_afu *afu)
274*14baf4d9SChristophe Lombard {
275*14baf4d9SChristophe Lombard 	afu->err_irq_name = kasprintf(GFP_KERNEL, "cxl-%s-err",
276*14baf4d9SChristophe Lombard 				      dev_name(&afu->dev));
277*14baf4d9SChristophe Lombard 	if (!afu->err_irq_name)
278*14baf4d9SChristophe Lombard 		return -ENOMEM;
279*14baf4d9SChristophe Lombard 
280*14baf4d9SChristophe Lombard 	if (!(afu->serr_virq = cxl_map_irq(afu->adapter, afu->serr_hwirq,
281*14baf4d9SChristophe Lombard 				 guest_slice_irq_err, afu, afu->err_irq_name))) {
282*14baf4d9SChristophe Lombard 		kfree(afu->err_irq_name);
283*14baf4d9SChristophe Lombard 		afu->err_irq_name = NULL;
284*14baf4d9SChristophe Lombard 		return -ENOMEM;
285*14baf4d9SChristophe Lombard 	}
286*14baf4d9SChristophe Lombard 
287*14baf4d9SChristophe Lombard 	return 0;
288*14baf4d9SChristophe Lombard }
289*14baf4d9SChristophe Lombard 
290*14baf4d9SChristophe Lombard static void guest_release_serr_irq(struct cxl_afu *afu)
291*14baf4d9SChristophe Lombard {
292*14baf4d9SChristophe Lombard 	cxl_unmap_irq(afu->serr_virq, afu);
293*14baf4d9SChristophe Lombard 	cxl_ops->release_one_irq(afu->adapter, afu->serr_hwirq);
294*14baf4d9SChristophe Lombard 	kfree(afu->err_irq_name);
295*14baf4d9SChristophe Lombard }
296*14baf4d9SChristophe Lombard 
297*14baf4d9SChristophe Lombard static int guest_ack_irq(struct cxl_context *ctx, u64 tfc, u64 psl_reset_mask)
298*14baf4d9SChristophe Lombard {
299*14baf4d9SChristophe Lombard 	return cxl_h_control_faults(ctx->afu->guest->handle, ctx->process_token,
300*14baf4d9SChristophe Lombard 				tfc >> 32, (psl_reset_mask != 0));
301*14baf4d9SChristophe Lombard }
302*14baf4d9SChristophe Lombard 
303*14baf4d9SChristophe Lombard static void disable_afu_irqs(struct cxl_context *ctx)
304*14baf4d9SChristophe Lombard {
305*14baf4d9SChristophe Lombard 	irq_hw_number_t hwirq;
306*14baf4d9SChristophe Lombard 	unsigned int virq;
307*14baf4d9SChristophe Lombard 	int r, i;
308*14baf4d9SChristophe Lombard 
309*14baf4d9SChristophe Lombard 	pr_devel("Disabling AFU(%d) interrupts\n", ctx->afu->slice);
310*14baf4d9SChristophe Lombard 	for (r = 0; r < CXL_IRQ_RANGES; r++) {
311*14baf4d9SChristophe Lombard 		hwirq = ctx->irqs.offset[r];
312*14baf4d9SChristophe Lombard 		for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) {
313*14baf4d9SChristophe Lombard 			virq = irq_find_mapping(NULL, hwirq);
314*14baf4d9SChristophe Lombard 			disable_irq(virq);
315*14baf4d9SChristophe Lombard 		}
316*14baf4d9SChristophe Lombard 	}
317*14baf4d9SChristophe Lombard }
318*14baf4d9SChristophe Lombard 
319*14baf4d9SChristophe Lombard static void enable_afu_irqs(struct cxl_context *ctx)
320*14baf4d9SChristophe Lombard {
321*14baf4d9SChristophe Lombard 	irq_hw_number_t hwirq;
322*14baf4d9SChristophe Lombard 	unsigned int virq;
323*14baf4d9SChristophe Lombard 	int r, i;
324*14baf4d9SChristophe Lombard 
325*14baf4d9SChristophe Lombard 	pr_devel("Enabling AFU(%d) interrupts\n", ctx->afu->slice);
326*14baf4d9SChristophe Lombard 	for (r = 0; r < CXL_IRQ_RANGES; r++) {
327*14baf4d9SChristophe Lombard 		hwirq = ctx->irqs.offset[r];
328*14baf4d9SChristophe Lombard 		for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) {
329*14baf4d9SChristophe Lombard 			virq = irq_find_mapping(NULL, hwirq);
330*14baf4d9SChristophe Lombard 			enable_irq(virq);
331*14baf4d9SChristophe Lombard 		}
332*14baf4d9SChristophe Lombard 	}
333*14baf4d9SChristophe Lombard }
334*14baf4d9SChristophe Lombard 
335*14baf4d9SChristophe Lombard static int _guest_afu_cr_readXX(int sz, struct cxl_afu *afu, int cr_idx,
336*14baf4d9SChristophe Lombard 			u64 offset, u64 *val)
337*14baf4d9SChristophe Lombard {
338*14baf4d9SChristophe Lombard 	unsigned long cr;
339*14baf4d9SChristophe Lombard 	char c;
340*14baf4d9SChristophe Lombard 	int rc = 0;
341*14baf4d9SChristophe Lombard 
342*14baf4d9SChristophe Lombard 	if (afu->crs_len < sz)
343*14baf4d9SChristophe Lombard 		return -ENOENT;
344*14baf4d9SChristophe Lombard 
345*14baf4d9SChristophe Lombard 	if (unlikely(offset >= afu->crs_len))
346*14baf4d9SChristophe Lombard 		return -ERANGE;
347*14baf4d9SChristophe Lombard 
348*14baf4d9SChristophe Lombard 	cr = get_zeroed_page(GFP_KERNEL);
349*14baf4d9SChristophe Lombard 	if (!cr)
350*14baf4d9SChristophe Lombard 		return -ENOMEM;
351*14baf4d9SChristophe Lombard 
352*14baf4d9SChristophe Lombard 	rc = cxl_h_get_config(afu->guest->handle, cr_idx, offset,
353*14baf4d9SChristophe Lombard 			virt_to_phys((void *)cr), sz);
354*14baf4d9SChristophe Lombard 	if (rc)
355*14baf4d9SChristophe Lombard 		goto err;
356*14baf4d9SChristophe Lombard 
357*14baf4d9SChristophe Lombard 	switch (sz) {
358*14baf4d9SChristophe Lombard 	case 1:
359*14baf4d9SChristophe Lombard 		c = *((char *) cr);
360*14baf4d9SChristophe Lombard 		*val = c;
361*14baf4d9SChristophe Lombard 		break;
362*14baf4d9SChristophe Lombard 	case 2:
363*14baf4d9SChristophe Lombard 		*val = in_le16((u16 *)cr);
364*14baf4d9SChristophe Lombard 		break;
365*14baf4d9SChristophe Lombard 	case 4:
366*14baf4d9SChristophe Lombard 		*val = in_le32((unsigned *)cr);
367*14baf4d9SChristophe Lombard 		break;
368*14baf4d9SChristophe Lombard 	case 8:
369*14baf4d9SChristophe Lombard 		*val = in_le64((u64 *)cr);
370*14baf4d9SChristophe Lombard 		break;
371*14baf4d9SChristophe Lombard 	default:
372*14baf4d9SChristophe Lombard 		WARN_ON(1);
373*14baf4d9SChristophe Lombard 	}
374*14baf4d9SChristophe Lombard err:
375*14baf4d9SChristophe Lombard 	free_page(cr);
376*14baf4d9SChristophe Lombard 	return rc;
377*14baf4d9SChristophe Lombard }
378*14baf4d9SChristophe Lombard 
379*14baf4d9SChristophe Lombard static int guest_afu_cr_read32(struct cxl_afu *afu, int cr_idx, u64 offset,
380*14baf4d9SChristophe Lombard 			u32 *out)
381*14baf4d9SChristophe Lombard {
382*14baf4d9SChristophe Lombard 	int rc;
383*14baf4d9SChristophe Lombard 	u64 val;
384*14baf4d9SChristophe Lombard 
385*14baf4d9SChristophe Lombard 	rc = _guest_afu_cr_readXX(4, afu, cr_idx, offset, &val);
386*14baf4d9SChristophe Lombard 	if (!rc)
387*14baf4d9SChristophe Lombard 		*out = (u32) val;
388*14baf4d9SChristophe Lombard 	return rc;
389*14baf4d9SChristophe Lombard }
390*14baf4d9SChristophe Lombard 
391*14baf4d9SChristophe Lombard static int guest_afu_cr_read16(struct cxl_afu *afu, int cr_idx, u64 offset,
392*14baf4d9SChristophe Lombard 			u16 *out)
393*14baf4d9SChristophe Lombard {
394*14baf4d9SChristophe Lombard 	int rc;
395*14baf4d9SChristophe Lombard 	u64 val;
396*14baf4d9SChristophe Lombard 
397*14baf4d9SChristophe Lombard 	rc = _guest_afu_cr_readXX(2, afu, cr_idx, offset, &val);
398*14baf4d9SChristophe Lombard 	if (!rc)
399*14baf4d9SChristophe Lombard 		*out = (u16) val;
400*14baf4d9SChristophe Lombard 	return rc;
401*14baf4d9SChristophe Lombard }
402*14baf4d9SChristophe Lombard 
403*14baf4d9SChristophe Lombard static int guest_afu_cr_read8(struct cxl_afu *afu, int cr_idx, u64 offset,
404*14baf4d9SChristophe Lombard 			u8 *out)
405*14baf4d9SChristophe Lombard {
406*14baf4d9SChristophe Lombard 	int rc;
407*14baf4d9SChristophe Lombard 	u64 val;
408*14baf4d9SChristophe Lombard 
409*14baf4d9SChristophe Lombard 	rc = _guest_afu_cr_readXX(1, afu, cr_idx, offset, &val);
410*14baf4d9SChristophe Lombard 	if (!rc)
411*14baf4d9SChristophe Lombard 		*out = (u8) val;
412*14baf4d9SChristophe Lombard 	return rc;
413*14baf4d9SChristophe Lombard }
414*14baf4d9SChristophe Lombard 
415*14baf4d9SChristophe Lombard static int guest_afu_cr_read64(struct cxl_afu *afu, int cr_idx, u64 offset,
416*14baf4d9SChristophe Lombard 			u64 *out)
417*14baf4d9SChristophe Lombard {
418*14baf4d9SChristophe Lombard 	return _guest_afu_cr_readXX(8, afu, cr_idx, offset, out);
419*14baf4d9SChristophe Lombard }
420*14baf4d9SChristophe Lombard 
421*14baf4d9SChristophe Lombard static int attach_afu_directed(struct cxl_context *ctx, u64 wed, u64 amr)
422*14baf4d9SChristophe Lombard {
423*14baf4d9SChristophe Lombard 	struct cxl_process_element_hcall *elem;
424*14baf4d9SChristophe Lombard 	struct cxl *adapter = ctx->afu->adapter;
425*14baf4d9SChristophe Lombard 	const struct cred *cred;
426*14baf4d9SChristophe Lombard 	u32 pid, idx;
427*14baf4d9SChristophe Lombard 	int rc, r, i;
428*14baf4d9SChristophe Lombard 	u64 mmio_addr, mmio_size;
429*14baf4d9SChristophe Lombard 	__be64 flags = 0;
430*14baf4d9SChristophe Lombard 
431*14baf4d9SChristophe Lombard 	/* Must be 8 byte aligned and cannot cross a 4096 byte boundary */
432*14baf4d9SChristophe Lombard 	if (!(elem = (struct cxl_process_element_hcall *)
433*14baf4d9SChristophe Lombard 			get_zeroed_page(GFP_KERNEL)))
434*14baf4d9SChristophe Lombard 		return -ENOMEM;
435*14baf4d9SChristophe Lombard 
436*14baf4d9SChristophe Lombard 	elem->version = cpu_to_be64(CXL_PROCESS_ELEMENT_VERSION);
437*14baf4d9SChristophe Lombard 	if (ctx->kernel) {
438*14baf4d9SChristophe Lombard 		pid = 0;
439*14baf4d9SChristophe Lombard 		flags |= CXL_PE_TRANSLATION_ENABLED;
440*14baf4d9SChristophe Lombard 		flags |= CXL_PE_PRIVILEGED_PROCESS;
441*14baf4d9SChristophe Lombard 		if (mfmsr() & MSR_SF)
442*14baf4d9SChristophe Lombard 			flags |= CXL_PE_64_BIT;
443*14baf4d9SChristophe Lombard 	} else {
444*14baf4d9SChristophe Lombard 		pid = current->pid;
445*14baf4d9SChristophe Lombard 		flags |= CXL_PE_PROBLEM_STATE;
446*14baf4d9SChristophe Lombard 		flags |= CXL_PE_TRANSLATION_ENABLED;
447*14baf4d9SChristophe Lombard 		if (!test_tsk_thread_flag(current, TIF_32BIT))
448*14baf4d9SChristophe Lombard 			flags |= CXL_PE_64_BIT;
449*14baf4d9SChristophe Lombard 		cred = get_current_cred();
450*14baf4d9SChristophe Lombard 		if (uid_eq(cred->euid, GLOBAL_ROOT_UID))
451*14baf4d9SChristophe Lombard 			flags |= CXL_PE_PRIVILEGED_PROCESS;
452*14baf4d9SChristophe Lombard 		put_cred(cred);
453*14baf4d9SChristophe Lombard 	}
454*14baf4d9SChristophe Lombard 	elem->flags         = cpu_to_be64(flags);
455*14baf4d9SChristophe Lombard 	elem->common.tid    = cpu_to_be32(0); /* Unused */
456*14baf4d9SChristophe Lombard 	elem->common.pid    = cpu_to_be32(pid);
457*14baf4d9SChristophe Lombard 	elem->common.csrp   = cpu_to_be64(0); /* disable */
458*14baf4d9SChristophe Lombard 	elem->common.aurp0  = cpu_to_be64(0); /* disable */
459*14baf4d9SChristophe Lombard 	elem->common.aurp1  = cpu_to_be64(0); /* disable */
460*14baf4d9SChristophe Lombard 
461*14baf4d9SChristophe Lombard 	cxl_prefault(ctx, wed);
462*14baf4d9SChristophe Lombard 
463*14baf4d9SChristophe Lombard 	elem->common.sstp0  = cpu_to_be64(ctx->sstp0);
464*14baf4d9SChristophe Lombard 	elem->common.sstp1  = cpu_to_be64(ctx->sstp1);
465*14baf4d9SChristophe Lombard 	for (r = 0; r < CXL_IRQ_RANGES; r++) {
466*14baf4d9SChristophe Lombard 		for (i = 0; i < ctx->irqs.range[r]; i++) {
467*14baf4d9SChristophe Lombard 			if (r == 0 && i == 0) {
468*14baf4d9SChristophe Lombard 				elem->pslVirtualIsn = cpu_to_be32(ctx->irqs.offset[0]);
469*14baf4d9SChristophe Lombard 			} else {
470*14baf4d9SChristophe Lombard 				idx = ctx->irqs.offset[r] + i - adapter->guest->irq_base_offset;
471*14baf4d9SChristophe Lombard 				elem->applicationVirtualIsnBitmap[idx / 8] |= 0x80 >> (idx % 8);
472*14baf4d9SChristophe Lombard 			}
473*14baf4d9SChristophe Lombard 		}
474*14baf4d9SChristophe Lombard 	}
475*14baf4d9SChristophe Lombard 	elem->common.amr = cpu_to_be64(amr);
476*14baf4d9SChristophe Lombard 	elem->common.wed = cpu_to_be64(wed);
477*14baf4d9SChristophe Lombard 
478*14baf4d9SChristophe Lombard 	disable_afu_irqs(ctx);
479*14baf4d9SChristophe Lombard 
480*14baf4d9SChristophe Lombard 	rc = cxl_h_attach_process(ctx->afu->guest->handle, elem,
481*14baf4d9SChristophe Lombard 				&ctx->process_token, &mmio_addr, &mmio_size);
482*14baf4d9SChristophe Lombard 	if (rc == H_SUCCESS) {
483*14baf4d9SChristophe Lombard 		if (ctx->master || !ctx->afu->pp_psa) {
484*14baf4d9SChristophe Lombard 			ctx->psn_phys = ctx->afu->psn_phys;
485*14baf4d9SChristophe Lombard 			ctx->psn_size = ctx->afu->adapter->ps_size;
486*14baf4d9SChristophe Lombard 		} else {
487*14baf4d9SChristophe Lombard 			ctx->psn_phys = mmio_addr;
488*14baf4d9SChristophe Lombard 			ctx->psn_size = mmio_size;
489*14baf4d9SChristophe Lombard 		}
490*14baf4d9SChristophe Lombard 		if (ctx->afu->pp_psa && mmio_size &&
491*14baf4d9SChristophe Lombard 			ctx->afu->pp_size == 0) {
492*14baf4d9SChristophe Lombard 			/*
493*14baf4d9SChristophe Lombard 			 * There's no property in the device tree to read the
494*14baf4d9SChristophe Lombard 			 * pp_size. We only find out at the 1st attach.
495*14baf4d9SChristophe Lombard 			 * Compared to bare-metal, it is too late and we
496*14baf4d9SChristophe Lombard 			 * should really lock here. However, on powerVM,
497*14baf4d9SChristophe Lombard 			 * pp_size is really only used to display in /sys.
498*14baf4d9SChristophe Lombard 			 * Being discussed with pHyp for their next release.
499*14baf4d9SChristophe Lombard 			 */
500*14baf4d9SChristophe Lombard 			ctx->afu->pp_size = mmio_size;
501*14baf4d9SChristophe Lombard 		}
502*14baf4d9SChristophe Lombard 		/* from PAPR: process element is bytes 4-7 of process token */
503*14baf4d9SChristophe Lombard 		ctx->external_pe = ctx->process_token & 0xFFFFFFFF;
504*14baf4d9SChristophe Lombard 		pr_devel("CXL pe=%i is known as %i for pHyp, mmio_size=%#llx",
505*14baf4d9SChristophe Lombard 			ctx->pe, ctx->external_pe, ctx->psn_size);
506*14baf4d9SChristophe Lombard 		ctx->pe_inserted = true;
507*14baf4d9SChristophe Lombard 		enable_afu_irqs(ctx);
508*14baf4d9SChristophe Lombard 	}
509*14baf4d9SChristophe Lombard 
510*14baf4d9SChristophe Lombard 	free_page((u64)elem);
511*14baf4d9SChristophe Lombard 	return rc;
512*14baf4d9SChristophe Lombard }
513*14baf4d9SChristophe Lombard 
514*14baf4d9SChristophe Lombard static int guest_attach_process(struct cxl_context *ctx, bool kernel, u64 wed, u64 amr)
515*14baf4d9SChristophe Lombard {
516*14baf4d9SChristophe Lombard 	pr_devel("in %s\n", __func__);
517*14baf4d9SChristophe Lombard 
518*14baf4d9SChristophe Lombard 	ctx->kernel = kernel;
519*14baf4d9SChristophe Lombard 	if (ctx->afu->current_mode == CXL_MODE_DIRECTED)
520*14baf4d9SChristophe Lombard 		return attach_afu_directed(ctx, wed, amr);
521*14baf4d9SChristophe Lombard 
522*14baf4d9SChristophe Lombard 	/* dedicated mode not supported on FW840 */
523*14baf4d9SChristophe Lombard 
524*14baf4d9SChristophe Lombard 	return -EINVAL;
525*14baf4d9SChristophe Lombard }
526*14baf4d9SChristophe Lombard 
527*14baf4d9SChristophe Lombard static int detach_afu_directed(struct cxl_context *ctx)
528*14baf4d9SChristophe Lombard {
529*14baf4d9SChristophe Lombard 	if (!ctx->pe_inserted)
530*14baf4d9SChristophe Lombard 		return 0;
531*14baf4d9SChristophe Lombard 	if (cxl_h_detach_process(ctx->afu->guest->handle, ctx->process_token))
532*14baf4d9SChristophe Lombard 		return -1;
533*14baf4d9SChristophe Lombard 	return 0;
534*14baf4d9SChristophe Lombard }
535*14baf4d9SChristophe Lombard 
536*14baf4d9SChristophe Lombard static int guest_detach_process(struct cxl_context *ctx)
537*14baf4d9SChristophe Lombard {
538*14baf4d9SChristophe Lombard 	pr_devel("in %s\n", __func__);
539*14baf4d9SChristophe Lombard 	trace_cxl_detach(ctx);
540*14baf4d9SChristophe Lombard 
541*14baf4d9SChristophe Lombard 	if (!cxl_ops->link_ok(ctx->afu->adapter))
542*14baf4d9SChristophe Lombard 		return -EIO;
543*14baf4d9SChristophe Lombard 
544*14baf4d9SChristophe Lombard 	if (ctx->afu->current_mode == CXL_MODE_DIRECTED)
545*14baf4d9SChristophe Lombard 		return detach_afu_directed(ctx);
546*14baf4d9SChristophe Lombard 
547*14baf4d9SChristophe Lombard 	return -EINVAL;
548*14baf4d9SChristophe Lombard }
549*14baf4d9SChristophe Lombard 
550*14baf4d9SChristophe Lombard static void guest_release_afu(struct device *dev)
551*14baf4d9SChristophe Lombard {
552*14baf4d9SChristophe Lombard 	struct cxl_afu *afu = to_cxl_afu(dev);
553*14baf4d9SChristophe Lombard 
554*14baf4d9SChristophe Lombard 	pr_devel("%s\n", __func__);
555*14baf4d9SChristophe Lombard 
556*14baf4d9SChristophe Lombard 	idr_destroy(&afu->contexts_idr);
557*14baf4d9SChristophe Lombard 
558*14baf4d9SChristophe Lombard 	kfree(afu->guest);
559*14baf4d9SChristophe Lombard 	kfree(afu);
560*14baf4d9SChristophe Lombard }
561*14baf4d9SChristophe Lombard 
562*14baf4d9SChristophe Lombard ssize_t cxl_guest_read_afu_vpd(struct cxl_afu *afu, void *buf, size_t len)
563*14baf4d9SChristophe Lombard {
564*14baf4d9SChristophe Lombard 	return guest_collect_vpd(NULL, afu, buf, len);
565*14baf4d9SChristophe Lombard }
566*14baf4d9SChristophe Lombard 
567*14baf4d9SChristophe Lombard #define ERR_BUFF_MAX_COPY_SIZE PAGE_SIZE
568*14baf4d9SChristophe Lombard static ssize_t guest_afu_read_err_buffer(struct cxl_afu *afu, char *buf,
569*14baf4d9SChristophe Lombard 					loff_t off, size_t count)
570*14baf4d9SChristophe Lombard {
571*14baf4d9SChristophe Lombard 	void *tbuf = NULL;
572*14baf4d9SChristophe Lombard 	int rc = 0;
573*14baf4d9SChristophe Lombard 
574*14baf4d9SChristophe Lombard 	tbuf = (void *) get_zeroed_page(GFP_KERNEL);
575*14baf4d9SChristophe Lombard 	if (!tbuf)
576*14baf4d9SChristophe Lombard 		return -ENOMEM;
577*14baf4d9SChristophe Lombard 
578*14baf4d9SChristophe Lombard 	rc = cxl_h_get_afu_err(afu->guest->handle,
579*14baf4d9SChristophe Lombard 			       off & 0x7,
580*14baf4d9SChristophe Lombard 			       virt_to_phys(tbuf),
581*14baf4d9SChristophe Lombard 			       count);
582*14baf4d9SChristophe Lombard 	if (rc)
583*14baf4d9SChristophe Lombard 		goto err;
584*14baf4d9SChristophe Lombard 
585*14baf4d9SChristophe Lombard 	if (count > ERR_BUFF_MAX_COPY_SIZE)
586*14baf4d9SChristophe Lombard 		count = ERR_BUFF_MAX_COPY_SIZE - (off & 0x7);
587*14baf4d9SChristophe Lombard 	memcpy(buf, tbuf, count);
588*14baf4d9SChristophe Lombard err:
589*14baf4d9SChristophe Lombard 	free_page((u64)tbuf);
590*14baf4d9SChristophe Lombard 
591*14baf4d9SChristophe Lombard 	return rc;
592*14baf4d9SChristophe Lombard }
593*14baf4d9SChristophe Lombard 
594*14baf4d9SChristophe Lombard static int guest_afu_check_and_enable(struct cxl_afu *afu)
595*14baf4d9SChristophe Lombard {
596*14baf4d9SChristophe Lombard 	return 0;
597*14baf4d9SChristophe Lombard }
598*14baf4d9SChristophe Lombard 
599*14baf4d9SChristophe Lombard static int activate_afu_directed(struct cxl_afu *afu)
600*14baf4d9SChristophe Lombard {
601*14baf4d9SChristophe Lombard 	int rc;
602*14baf4d9SChristophe Lombard 
603*14baf4d9SChristophe Lombard 	dev_info(&afu->dev, "Activating AFU(%d) directed mode\n", afu->slice);
604*14baf4d9SChristophe Lombard 
605*14baf4d9SChristophe Lombard 	afu->current_mode = CXL_MODE_DIRECTED;
606*14baf4d9SChristophe Lombard 
607*14baf4d9SChristophe Lombard 	afu->num_procs = afu->max_procs_virtualised;
608*14baf4d9SChristophe Lombard 
609*14baf4d9SChristophe Lombard 	if ((rc = cxl_chardev_m_afu_add(afu)))
610*14baf4d9SChristophe Lombard 		return rc;
611*14baf4d9SChristophe Lombard 
612*14baf4d9SChristophe Lombard 	if ((rc = cxl_sysfs_afu_m_add(afu)))
613*14baf4d9SChristophe Lombard 		goto err;
614*14baf4d9SChristophe Lombard 
615*14baf4d9SChristophe Lombard 	if ((rc = cxl_chardev_s_afu_add(afu)))
616*14baf4d9SChristophe Lombard 		goto err1;
617*14baf4d9SChristophe Lombard 
618*14baf4d9SChristophe Lombard 	return 0;
619*14baf4d9SChristophe Lombard err1:
620*14baf4d9SChristophe Lombard 	cxl_sysfs_afu_m_remove(afu);
621*14baf4d9SChristophe Lombard err:
622*14baf4d9SChristophe Lombard 	cxl_chardev_afu_remove(afu);
623*14baf4d9SChristophe Lombard 	return rc;
624*14baf4d9SChristophe Lombard }
625*14baf4d9SChristophe Lombard 
626*14baf4d9SChristophe Lombard static int guest_afu_activate_mode(struct cxl_afu *afu, int mode)
627*14baf4d9SChristophe Lombard {
628*14baf4d9SChristophe Lombard 	if (!mode)
629*14baf4d9SChristophe Lombard 		return 0;
630*14baf4d9SChristophe Lombard 	if (!(mode & afu->modes_supported))
631*14baf4d9SChristophe Lombard 		return -EINVAL;
632*14baf4d9SChristophe Lombard 
633*14baf4d9SChristophe Lombard 	if (mode == CXL_MODE_DIRECTED)
634*14baf4d9SChristophe Lombard 		return activate_afu_directed(afu);
635*14baf4d9SChristophe Lombard 
636*14baf4d9SChristophe Lombard 	if (mode == CXL_MODE_DEDICATED)
637*14baf4d9SChristophe Lombard 		dev_err(&afu->dev, "Dedicated mode not supported\n");
638*14baf4d9SChristophe Lombard 
639*14baf4d9SChristophe Lombard 	return -EINVAL;
640*14baf4d9SChristophe Lombard }
641*14baf4d9SChristophe Lombard 
642*14baf4d9SChristophe Lombard static int deactivate_afu_directed(struct cxl_afu *afu)
643*14baf4d9SChristophe Lombard {
644*14baf4d9SChristophe Lombard 	dev_info(&afu->dev, "Deactivating AFU(%d) directed mode\n", afu->slice);
645*14baf4d9SChristophe Lombard 
646*14baf4d9SChristophe Lombard 	afu->current_mode = 0;
647*14baf4d9SChristophe Lombard 	afu->num_procs = 0;
648*14baf4d9SChristophe Lombard 
649*14baf4d9SChristophe Lombard 	cxl_sysfs_afu_m_remove(afu);
650*14baf4d9SChristophe Lombard 	cxl_chardev_afu_remove(afu);
651*14baf4d9SChristophe Lombard 
652*14baf4d9SChristophe Lombard 	cxl_ops->afu_reset(afu);
653*14baf4d9SChristophe Lombard 
654*14baf4d9SChristophe Lombard 	return 0;
655*14baf4d9SChristophe Lombard }
656*14baf4d9SChristophe Lombard 
657*14baf4d9SChristophe Lombard static int guest_afu_deactivate_mode(struct cxl_afu *afu, int mode)
658*14baf4d9SChristophe Lombard {
659*14baf4d9SChristophe Lombard 	if (!mode)
660*14baf4d9SChristophe Lombard 		return 0;
661*14baf4d9SChristophe Lombard 	if (!(mode & afu->modes_supported))
662*14baf4d9SChristophe Lombard 		return -EINVAL;
663*14baf4d9SChristophe Lombard 
664*14baf4d9SChristophe Lombard 	if (mode == CXL_MODE_DIRECTED)
665*14baf4d9SChristophe Lombard 		return deactivate_afu_directed(afu);
666*14baf4d9SChristophe Lombard 	return 0;
667*14baf4d9SChristophe Lombard }
668*14baf4d9SChristophe Lombard 
669*14baf4d9SChristophe Lombard static int guest_afu_reset(struct cxl_afu *afu)
670*14baf4d9SChristophe Lombard {
671*14baf4d9SChristophe Lombard 	pr_devel("AFU(%d) reset request\n", afu->slice);
672*14baf4d9SChristophe Lombard 	return cxl_h_reset_afu(afu->guest->handle);
673*14baf4d9SChristophe Lombard }
674*14baf4d9SChristophe Lombard 
675*14baf4d9SChristophe Lombard static int guest_map_slice_regs(struct cxl_afu *afu)
676*14baf4d9SChristophe Lombard {
677*14baf4d9SChristophe Lombard 	if (!(afu->p2n_mmio = ioremap(afu->guest->p2n_phys, afu->guest->p2n_size))) {
678*14baf4d9SChristophe Lombard 		dev_err(&afu->dev, "Error mapping AFU(%d) MMIO regions\n",
679*14baf4d9SChristophe Lombard 			afu->slice);
680*14baf4d9SChristophe Lombard 		return -ENOMEM;
681*14baf4d9SChristophe Lombard 	}
682*14baf4d9SChristophe Lombard 	return 0;
683*14baf4d9SChristophe Lombard }
684*14baf4d9SChristophe Lombard 
685*14baf4d9SChristophe Lombard static void guest_unmap_slice_regs(struct cxl_afu *afu)
686*14baf4d9SChristophe Lombard {
687*14baf4d9SChristophe Lombard 	if (afu->p2n_mmio)
688*14baf4d9SChristophe Lombard 		iounmap(afu->p2n_mmio);
689*14baf4d9SChristophe Lombard }
690*14baf4d9SChristophe Lombard 
691*14baf4d9SChristophe Lombard static bool guest_link_ok(struct cxl *cxl)
692*14baf4d9SChristophe Lombard {
693*14baf4d9SChristophe Lombard 	return true;
694*14baf4d9SChristophe Lombard }
695*14baf4d9SChristophe Lombard 
696*14baf4d9SChristophe Lombard static int afu_properties_look_ok(struct cxl_afu *afu)
697*14baf4d9SChristophe Lombard {
698*14baf4d9SChristophe Lombard 	if (afu->pp_irqs < 0) {
699*14baf4d9SChristophe Lombard 		dev_err(&afu->dev, "Unexpected per-process minimum interrupt value\n");
700*14baf4d9SChristophe Lombard 		return -EINVAL;
701*14baf4d9SChristophe Lombard 	}
702*14baf4d9SChristophe Lombard 
703*14baf4d9SChristophe Lombard 	if (afu->max_procs_virtualised < 1) {
704*14baf4d9SChristophe Lombard 		dev_err(&afu->dev, "Unexpected max number of processes virtualised value\n");
705*14baf4d9SChristophe Lombard 		return -EINVAL;
706*14baf4d9SChristophe Lombard 	}
707*14baf4d9SChristophe Lombard 
708*14baf4d9SChristophe Lombard 	if (afu->crs_len < 0) {
709*14baf4d9SChristophe Lombard 		dev_err(&afu->dev, "Unexpected configuration record size value\n");
710*14baf4d9SChristophe Lombard 		return -EINVAL;
711*14baf4d9SChristophe Lombard 	}
712*14baf4d9SChristophe Lombard 
713*14baf4d9SChristophe Lombard 	return 0;
714*14baf4d9SChristophe Lombard }
715*14baf4d9SChristophe Lombard 
716*14baf4d9SChristophe Lombard int cxl_guest_init_afu(struct cxl *adapter, int slice, struct device_node *afu_np)
717*14baf4d9SChristophe Lombard {
718*14baf4d9SChristophe Lombard 	struct cxl_afu *afu;
719*14baf4d9SChristophe Lombard 	bool free = true;
720*14baf4d9SChristophe Lombard 	int rc;
721*14baf4d9SChristophe Lombard 
722*14baf4d9SChristophe Lombard 	pr_devel("in %s - AFU(%d)\n", __func__, slice);
723*14baf4d9SChristophe Lombard 	if (!(afu = cxl_alloc_afu(adapter, slice)))
724*14baf4d9SChristophe Lombard 		return -ENOMEM;
725*14baf4d9SChristophe Lombard 
726*14baf4d9SChristophe Lombard 	if (!(afu->guest = kzalloc(sizeof(struct cxl_afu_guest), GFP_KERNEL))) {
727*14baf4d9SChristophe Lombard 		kfree(afu);
728*14baf4d9SChristophe Lombard 		return -ENOMEM;
729*14baf4d9SChristophe Lombard 	}
730*14baf4d9SChristophe Lombard 
731*14baf4d9SChristophe Lombard 	if ((rc = dev_set_name(&afu->dev, "afu%i.%i",
732*14baf4d9SChristophe Lombard 					  adapter->adapter_num,
733*14baf4d9SChristophe Lombard 					  slice)))
734*14baf4d9SChristophe Lombard 		goto err1;
735*14baf4d9SChristophe Lombard 
736*14baf4d9SChristophe Lombard 	adapter->slices++;
737*14baf4d9SChristophe Lombard 
738*14baf4d9SChristophe Lombard 	if ((rc = cxl_of_read_afu_handle(afu, afu_np)))
739*14baf4d9SChristophe Lombard 		goto err1;
740*14baf4d9SChristophe Lombard 
741*14baf4d9SChristophe Lombard 	if ((rc = cxl_ops->afu_reset(afu)))
742*14baf4d9SChristophe Lombard 		goto err1;
743*14baf4d9SChristophe Lombard 
744*14baf4d9SChristophe Lombard 	if ((rc = cxl_of_read_afu_properties(afu, afu_np)))
745*14baf4d9SChristophe Lombard 		goto err1;
746*14baf4d9SChristophe Lombard 
747*14baf4d9SChristophe Lombard 	if ((rc = afu_properties_look_ok(afu)))
748*14baf4d9SChristophe Lombard 		goto err1;
749*14baf4d9SChristophe Lombard 
750*14baf4d9SChristophe Lombard 	if ((rc = guest_map_slice_regs(afu)))
751*14baf4d9SChristophe Lombard 		goto err1;
752*14baf4d9SChristophe Lombard 
753*14baf4d9SChristophe Lombard 	if ((rc = guest_register_serr_irq(afu)))
754*14baf4d9SChristophe Lombard 		goto err2;
755*14baf4d9SChristophe Lombard 
756*14baf4d9SChristophe Lombard 	/*
757*14baf4d9SChristophe Lombard 	 * After we call this function we must not free the afu directly, even
758*14baf4d9SChristophe Lombard 	 * if it returns an error!
759*14baf4d9SChristophe Lombard 	 */
760*14baf4d9SChristophe Lombard 	if ((rc = cxl_register_afu(afu)))
761*14baf4d9SChristophe Lombard 		goto err_put1;
762*14baf4d9SChristophe Lombard 
763*14baf4d9SChristophe Lombard 	if ((rc = cxl_sysfs_afu_add(afu)))
764*14baf4d9SChristophe Lombard 		goto err_put1;
765*14baf4d9SChristophe Lombard 
766*14baf4d9SChristophe Lombard 	/*
767*14baf4d9SChristophe Lombard 	 * pHyp doesn't expose the programming models supported by the
768*14baf4d9SChristophe Lombard 	 * AFU. pHyp currently only supports directed mode. If it adds
769*14baf4d9SChristophe Lombard 	 * dedicated mode later, this version of cxl has no way to
770*14baf4d9SChristophe Lombard 	 * detect it. So we'll initialize the driver, but the first
771*14baf4d9SChristophe Lombard 	 * attach will fail.
772*14baf4d9SChristophe Lombard 	 * Being discussed with pHyp to do better (likely new property)
773*14baf4d9SChristophe Lombard 	 */
774*14baf4d9SChristophe Lombard 	if (afu->max_procs_virtualised == 1)
775*14baf4d9SChristophe Lombard 		afu->modes_supported = CXL_MODE_DEDICATED;
776*14baf4d9SChristophe Lombard 	else
777*14baf4d9SChristophe Lombard 		afu->modes_supported = CXL_MODE_DIRECTED;
778*14baf4d9SChristophe Lombard 
779*14baf4d9SChristophe Lombard 	if ((rc = cxl_afu_select_best_mode(afu)))
780*14baf4d9SChristophe Lombard 		goto err_put2;
781*14baf4d9SChristophe Lombard 
782*14baf4d9SChristophe Lombard 	adapter->afu[afu->slice] = afu;
783*14baf4d9SChristophe Lombard 
784*14baf4d9SChristophe Lombard 	afu->enabled = true;
785*14baf4d9SChristophe Lombard 
786*14baf4d9SChristophe Lombard 	return 0;
787*14baf4d9SChristophe Lombard 
788*14baf4d9SChristophe Lombard err_put2:
789*14baf4d9SChristophe Lombard 	cxl_sysfs_afu_remove(afu);
790*14baf4d9SChristophe Lombard err_put1:
791*14baf4d9SChristophe Lombard 	device_unregister(&afu->dev);
792*14baf4d9SChristophe Lombard 	free = false;
793*14baf4d9SChristophe Lombard 	guest_release_serr_irq(afu);
794*14baf4d9SChristophe Lombard err2:
795*14baf4d9SChristophe Lombard 	guest_unmap_slice_regs(afu);
796*14baf4d9SChristophe Lombard err1:
797*14baf4d9SChristophe Lombard 	if (free) {
798*14baf4d9SChristophe Lombard 		kfree(afu->guest);
799*14baf4d9SChristophe Lombard 		kfree(afu);
800*14baf4d9SChristophe Lombard 	}
801*14baf4d9SChristophe Lombard 	return rc;
802*14baf4d9SChristophe Lombard }
803*14baf4d9SChristophe Lombard 
804*14baf4d9SChristophe Lombard void cxl_guest_remove_afu(struct cxl_afu *afu)
805*14baf4d9SChristophe Lombard {
806*14baf4d9SChristophe Lombard 	pr_devel("in %s - AFU(%d)\n", __func__, afu->slice);
807*14baf4d9SChristophe Lombard 
808*14baf4d9SChristophe Lombard 	if (!afu)
809*14baf4d9SChristophe Lombard 		return;
810*14baf4d9SChristophe Lombard 
811*14baf4d9SChristophe Lombard 	cxl_sysfs_afu_remove(afu);
812*14baf4d9SChristophe Lombard 
813*14baf4d9SChristophe Lombard 	spin_lock(&afu->adapter->afu_list_lock);
814*14baf4d9SChristophe Lombard 	afu->adapter->afu[afu->slice] = NULL;
815*14baf4d9SChristophe Lombard 	spin_unlock(&afu->adapter->afu_list_lock);
816*14baf4d9SChristophe Lombard 
817*14baf4d9SChristophe Lombard 	cxl_context_detach_all(afu);
818*14baf4d9SChristophe Lombard 	cxl_ops->afu_deactivate_mode(afu, afu->current_mode);
819*14baf4d9SChristophe Lombard 	guest_release_serr_irq(afu);
820*14baf4d9SChristophe Lombard 	guest_unmap_slice_regs(afu);
821*14baf4d9SChristophe Lombard 
822*14baf4d9SChristophe Lombard 	device_unregister(&afu->dev);
823*14baf4d9SChristophe Lombard }
824*14baf4d9SChristophe Lombard 
825*14baf4d9SChristophe Lombard static void free_adapter(struct cxl *adapter)
826*14baf4d9SChristophe Lombard {
827*14baf4d9SChristophe Lombard 	struct irq_avail *cur;
828*14baf4d9SChristophe Lombard 	int i;
829*14baf4d9SChristophe Lombard 
830*14baf4d9SChristophe Lombard 	if (adapter->guest->irq_avail) {
831*14baf4d9SChristophe Lombard 		for (i = 0; i < adapter->guest->irq_nranges; i++) {
832*14baf4d9SChristophe Lombard 			cur = &adapter->guest->irq_avail[i];
833*14baf4d9SChristophe Lombard 			kfree(cur->bitmap);
834*14baf4d9SChristophe Lombard 		}
835*14baf4d9SChristophe Lombard 		kfree(adapter->guest->irq_avail);
836*14baf4d9SChristophe Lombard 	}
837*14baf4d9SChristophe Lombard 	kfree(adapter->guest->status);
838*14baf4d9SChristophe Lombard 	cxl_remove_adapter_nr(adapter);
839*14baf4d9SChristophe Lombard 	kfree(adapter->guest);
840*14baf4d9SChristophe Lombard 	kfree(adapter);
841*14baf4d9SChristophe Lombard }
842*14baf4d9SChristophe Lombard 
843*14baf4d9SChristophe Lombard static int properties_look_ok(struct cxl *adapter)
844*14baf4d9SChristophe Lombard {
845*14baf4d9SChristophe Lombard 	/* The absence of this property means that the operational
846*14baf4d9SChristophe Lombard 	 * status is unknown or okay
847*14baf4d9SChristophe Lombard 	 */
848*14baf4d9SChristophe Lombard 	if (strlen(adapter->guest->status) &&
849*14baf4d9SChristophe Lombard 	    strcmp(adapter->guest->status, "okay")) {
850*14baf4d9SChristophe Lombard 		pr_err("ABORTING:Bad operational status of the device\n");
851*14baf4d9SChristophe Lombard 		return -EINVAL;
852*14baf4d9SChristophe Lombard 	}
853*14baf4d9SChristophe Lombard 
854*14baf4d9SChristophe Lombard 	return 0;
855*14baf4d9SChristophe Lombard }
856*14baf4d9SChristophe Lombard 
857*14baf4d9SChristophe Lombard ssize_t cxl_guest_read_adapter_vpd(struct cxl *adapter, void *buf, size_t len)
858*14baf4d9SChristophe Lombard {
859*14baf4d9SChristophe Lombard 	return guest_collect_vpd(adapter, NULL, buf, len);
860*14baf4d9SChristophe Lombard }
861*14baf4d9SChristophe Lombard 
862*14baf4d9SChristophe Lombard void cxl_guest_remove_adapter(struct cxl *adapter)
863*14baf4d9SChristophe Lombard {
864*14baf4d9SChristophe Lombard 	pr_devel("in %s\n", __func__);
865*14baf4d9SChristophe Lombard 
866*14baf4d9SChristophe Lombard 	cxl_sysfs_adapter_remove(adapter);
867*14baf4d9SChristophe Lombard 
868*14baf4d9SChristophe Lombard 	device_unregister(&adapter->dev);
869*14baf4d9SChristophe Lombard }
870*14baf4d9SChristophe Lombard 
871*14baf4d9SChristophe Lombard static void release_adapter(struct device *dev)
872*14baf4d9SChristophe Lombard {
873*14baf4d9SChristophe Lombard 	free_adapter(to_cxl_adapter(dev));
874*14baf4d9SChristophe Lombard }
875*14baf4d9SChristophe Lombard 
876*14baf4d9SChristophe Lombard struct cxl *cxl_guest_init_adapter(struct device_node *np, struct platform_device *pdev)
877*14baf4d9SChristophe Lombard {
878*14baf4d9SChristophe Lombard 	struct cxl *adapter;
879*14baf4d9SChristophe Lombard 	bool free = true;
880*14baf4d9SChristophe Lombard 	int rc;
881*14baf4d9SChristophe Lombard 
882*14baf4d9SChristophe Lombard 	if (!(adapter = cxl_alloc_adapter()))
883*14baf4d9SChristophe Lombard 		return ERR_PTR(-ENOMEM);
884*14baf4d9SChristophe Lombard 
885*14baf4d9SChristophe Lombard 	if (!(adapter->guest = kzalloc(sizeof(struct cxl_guest), GFP_KERNEL))) {
886*14baf4d9SChristophe Lombard 		free_adapter(adapter);
887*14baf4d9SChristophe Lombard 		return ERR_PTR(-ENOMEM);
888*14baf4d9SChristophe Lombard 	}
889*14baf4d9SChristophe Lombard 
890*14baf4d9SChristophe Lombard 	adapter->slices = 0;
891*14baf4d9SChristophe Lombard 	adapter->guest->pdev = pdev;
892*14baf4d9SChristophe Lombard 	adapter->dev.parent = &pdev->dev;
893*14baf4d9SChristophe Lombard 	adapter->dev.release = release_adapter;
894*14baf4d9SChristophe Lombard 	dev_set_drvdata(&pdev->dev, adapter);
895*14baf4d9SChristophe Lombard 
896*14baf4d9SChristophe Lombard 	if ((rc = cxl_of_read_adapter_handle(adapter, np)))
897*14baf4d9SChristophe Lombard 		goto err1;
898*14baf4d9SChristophe Lombard 
899*14baf4d9SChristophe Lombard 	if ((rc = cxl_of_read_adapter_properties(adapter, np)))
900*14baf4d9SChristophe Lombard 		goto err1;
901*14baf4d9SChristophe Lombard 
902*14baf4d9SChristophe Lombard 	if ((rc = properties_look_ok(adapter)))
903*14baf4d9SChristophe Lombard 		goto err1;
904*14baf4d9SChristophe Lombard 
905*14baf4d9SChristophe Lombard 	/*
906*14baf4d9SChristophe Lombard 	 * After we call this function we must not free the adapter directly,
907*14baf4d9SChristophe Lombard 	 * even if it returns an error!
908*14baf4d9SChristophe Lombard 	 */
909*14baf4d9SChristophe Lombard 	if ((rc = cxl_register_adapter(adapter)))
910*14baf4d9SChristophe Lombard 		goto err_put1;
911*14baf4d9SChristophe Lombard 
912*14baf4d9SChristophe Lombard 	if ((rc = cxl_sysfs_adapter_add(adapter)))
913*14baf4d9SChristophe Lombard 		goto err_put1;
914*14baf4d9SChristophe Lombard 
915*14baf4d9SChristophe Lombard 	return adapter;
916*14baf4d9SChristophe Lombard 
917*14baf4d9SChristophe Lombard err_put1:
918*14baf4d9SChristophe Lombard 	device_unregister(&adapter->dev);
919*14baf4d9SChristophe Lombard 	free = false;
920*14baf4d9SChristophe Lombard err1:
921*14baf4d9SChristophe Lombard 	if (free)
922*14baf4d9SChristophe Lombard 		free_adapter(adapter);
923*14baf4d9SChristophe Lombard 	return ERR_PTR(rc);
924*14baf4d9SChristophe Lombard }
925*14baf4d9SChristophe Lombard 
926*14baf4d9SChristophe Lombard const struct cxl_backend_ops cxl_guest_ops = {
927*14baf4d9SChristophe Lombard 	.module = THIS_MODULE,
928*14baf4d9SChristophe Lombard 	.adapter_reset = guest_reset,
929*14baf4d9SChristophe Lombard 	.alloc_one_irq = guest_alloc_one_irq,
930*14baf4d9SChristophe Lombard 	.release_one_irq = guest_release_one_irq,
931*14baf4d9SChristophe Lombard 	.alloc_irq_ranges = guest_alloc_irq_ranges,
932*14baf4d9SChristophe Lombard 	.release_irq_ranges = guest_release_irq_ranges,
933*14baf4d9SChristophe Lombard 	.setup_irq = NULL,
934*14baf4d9SChristophe Lombard 	.handle_psl_slice_error = guest_handle_psl_slice_error,
935*14baf4d9SChristophe Lombard 	.psl_interrupt = guest_psl_irq,
936*14baf4d9SChristophe Lombard 	.ack_irq = guest_ack_irq,
937*14baf4d9SChristophe Lombard 	.attach_process = guest_attach_process,
938*14baf4d9SChristophe Lombard 	.detach_process = guest_detach_process,
939*14baf4d9SChristophe Lombard 	.link_ok = guest_link_ok,
940*14baf4d9SChristophe Lombard 	.release_afu = guest_release_afu,
941*14baf4d9SChristophe Lombard 	.afu_read_err_buffer = guest_afu_read_err_buffer,
942*14baf4d9SChristophe Lombard 	.afu_check_and_enable = guest_afu_check_and_enable,
943*14baf4d9SChristophe Lombard 	.afu_activate_mode = guest_afu_activate_mode,
944*14baf4d9SChristophe Lombard 	.afu_deactivate_mode = guest_afu_deactivate_mode,
945*14baf4d9SChristophe Lombard 	.afu_reset = guest_afu_reset,
946*14baf4d9SChristophe Lombard 	.afu_cr_read8 = guest_afu_cr_read8,
947*14baf4d9SChristophe Lombard 	.afu_cr_read16 = guest_afu_cr_read16,
948*14baf4d9SChristophe Lombard 	.afu_cr_read32 = guest_afu_cr_read32,
949*14baf4d9SChristophe Lombard 	.afu_cr_read64 = guest_afu_cr_read64,
950*14baf4d9SChristophe Lombard };
951