xref: /linux/drivers/fpga/dfl-fme-pr.c (revision 44f57d78)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Driver for FPGA Management Engine (FME) Partial Reconfiguration
4  *
5  * Copyright (C) 2017-2018 Intel Corporation, Inc.
6  *
7  * Authors:
8  *   Kang Luwei <luwei.kang@intel.com>
9  *   Xiao Guangrong <guangrong.xiao@linux.intel.com>
10  *   Wu Hao <hao.wu@intel.com>
11  *   Joseph Grecco <joe.grecco@intel.com>
12  *   Enno Luebbers <enno.luebbers@intel.com>
13  *   Tim Whisonant <tim.whisonant@intel.com>
14  *   Ananda Ravuri <ananda.ravuri@intel.com>
15  *   Christopher Rauer <christopher.rauer@intel.com>
16  *   Henry Mitchel <henry.mitchel@intel.com>
17  */
18 
19 #include <linux/types.h>
20 #include <linux/device.h>
21 #include <linux/vmalloc.h>
22 #include <linux/uaccess.h>
23 #include <linux/fpga/fpga-mgr.h>
24 #include <linux/fpga/fpga-bridge.h>
25 #include <linux/fpga/fpga-region.h>
26 #include <linux/fpga-dfl.h>
27 
28 #include "dfl.h"
29 #include "dfl-fme.h"
30 #include "dfl-fme-pr.h"
31 
32 static struct dfl_fme_region *
33 dfl_fme_region_find_by_port_id(struct dfl_fme *fme, int port_id)
34 {
35 	struct dfl_fme_region *fme_region;
36 
37 	list_for_each_entry(fme_region, &fme->region_list, node)
38 		if (fme_region->port_id == port_id)
39 			return fme_region;
40 
41 	return NULL;
42 }
43 
44 static int dfl_fme_region_match(struct device *dev, const void *data)
45 {
46 	return dev->parent == data;
47 }
48 
49 static struct fpga_region *dfl_fme_region_find(struct dfl_fme *fme, int port_id)
50 {
51 	struct dfl_fme_region *fme_region;
52 	struct fpga_region *region;
53 
54 	fme_region = dfl_fme_region_find_by_port_id(fme, port_id);
55 	if (!fme_region)
56 		return NULL;
57 
58 	region = fpga_region_class_find(NULL, &fme_region->region->dev,
59 					dfl_fme_region_match);
60 	if (!region)
61 		return NULL;
62 
63 	return region;
64 }
65 
66 static int fme_pr(struct platform_device *pdev, unsigned long arg)
67 {
68 	struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
69 	void __user *argp = (void __user *)arg;
70 	struct dfl_fpga_fme_port_pr port_pr;
71 	struct fpga_image_info *info;
72 	struct fpga_region *region;
73 	void __iomem *fme_hdr;
74 	struct dfl_fme *fme;
75 	unsigned long minsz;
76 	void *buf = NULL;
77 	int ret = 0;
78 	u64 v;
79 
80 	minsz = offsetofend(struct dfl_fpga_fme_port_pr, buffer_address);
81 
82 	if (copy_from_user(&port_pr, argp, minsz))
83 		return -EFAULT;
84 
85 	if (port_pr.argsz < minsz || port_pr.flags)
86 		return -EINVAL;
87 
88 	if (!IS_ALIGNED(port_pr.buffer_size, 4))
89 		return -EINVAL;
90 
91 	/* get fme header region */
92 	fme_hdr = dfl_get_feature_ioaddr_by_id(&pdev->dev,
93 					       FME_FEATURE_ID_HEADER);
94 
95 	/* check port id */
96 	v = readq(fme_hdr + FME_HDR_CAP);
97 	if (port_pr.port_id >= FIELD_GET(FME_CAP_NUM_PORTS, v)) {
98 		dev_dbg(&pdev->dev, "port number more than maximum\n");
99 		return -EINVAL;
100 	}
101 
102 	if (!access_ok((void __user *)(unsigned long)port_pr.buffer_address,
103 		       port_pr.buffer_size))
104 		return -EFAULT;
105 
106 	buf = vmalloc(port_pr.buffer_size);
107 	if (!buf)
108 		return -ENOMEM;
109 
110 	if (copy_from_user(buf,
111 			   (void __user *)(unsigned long)port_pr.buffer_address,
112 			   port_pr.buffer_size)) {
113 		ret = -EFAULT;
114 		goto free_exit;
115 	}
116 
117 	/* prepare fpga_image_info for PR */
118 	info = fpga_image_info_alloc(&pdev->dev);
119 	if (!info) {
120 		ret = -ENOMEM;
121 		goto free_exit;
122 	}
123 
124 	info->flags |= FPGA_MGR_PARTIAL_RECONFIG;
125 
126 	mutex_lock(&pdata->lock);
127 	fme = dfl_fpga_pdata_get_private(pdata);
128 	/* fme device has been unregistered. */
129 	if (!fme) {
130 		ret = -EINVAL;
131 		goto unlock_exit;
132 	}
133 
134 	region = dfl_fme_region_find(fme, port_pr.port_id);
135 	if (!region) {
136 		ret = -EINVAL;
137 		goto unlock_exit;
138 	}
139 
140 	fpga_image_info_free(region->info);
141 
142 	info->buf = buf;
143 	info->count = port_pr.buffer_size;
144 	info->region_id = port_pr.port_id;
145 	region->info = info;
146 
147 	ret = fpga_region_program_fpga(region);
148 
149 	/*
150 	 * it allows userspace to reset the PR region's logic by disabling and
151 	 * reenabling the bridge to clear things out between accleration runs.
152 	 * so no need to hold the bridges after partial reconfiguration.
153 	 */
154 	if (region->get_bridges)
155 		fpga_bridges_put(&region->bridge_list);
156 
157 	put_device(&region->dev);
158 unlock_exit:
159 	mutex_unlock(&pdata->lock);
160 free_exit:
161 	vfree(buf);
162 	if (copy_to_user((void __user *)arg, &port_pr, minsz))
163 		return -EFAULT;
164 
165 	return ret;
166 }
167 
168 /**
169  * dfl_fme_create_mgr - create fpga mgr platform device as child device
170  *
171  * @pdata: fme platform_device's pdata
172  *
173  * Return: mgr platform device if successful, and error code otherwise.
174  */
175 static struct platform_device *
176 dfl_fme_create_mgr(struct dfl_feature_platform_data *pdata,
177 		   struct dfl_feature *feature)
178 {
179 	struct platform_device *mgr, *fme = pdata->dev;
180 	struct dfl_fme_mgr_pdata mgr_pdata;
181 	int ret = -ENOMEM;
182 
183 	if (!feature->ioaddr)
184 		return ERR_PTR(-ENODEV);
185 
186 	mgr_pdata.ioaddr = feature->ioaddr;
187 
188 	/*
189 	 * Each FME has only one fpga-mgr, so allocate platform device using
190 	 * the same FME platform device id.
191 	 */
192 	mgr = platform_device_alloc(DFL_FPGA_FME_MGR, fme->id);
193 	if (!mgr)
194 		return ERR_PTR(ret);
195 
196 	mgr->dev.parent = &fme->dev;
197 
198 	ret = platform_device_add_data(mgr, &mgr_pdata, sizeof(mgr_pdata));
199 	if (ret)
200 		goto create_mgr_err;
201 
202 	ret = platform_device_add(mgr);
203 	if (ret)
204 		goto create_mgr_err;
205 
206 	return mgr;
207 
208 create_mgr_err:
209 	platform_device_put(mgr);
210 	return ERR_PTR(ret);
211 }
212 
213 /**
214  * dfl_fme_destroy_mgr - destroy fpga mgr platform device
215  * @pdata: fme platform device's pdata
216  */
217 static void dfl_fme_destroy_mgr(struct dfl_feature_platform_data *pdata)
218 {
219 	struct dfl_fme *priv = dfl_fpga_pdata_get_private(pdata);
220 
221 	platform_device_unregister(priv->mgr);
222 }
223 
224 /**
225  * dfl_fme_create_bridge - create fme fpga bridge platform device as child
226  *
227  * @pdata: fme platform device's pdata
228  * @port_id: port id for the bridge to be created.
229  *
230  * Return: bridge platform device if successful, and error code otherwise.
231  */
232 static struct dfl_fme_bridge *
233 dfl_fme_create_bridge(struct dfl_feature_platform_data *pdata, int port_id)
234 {
235 	struct device *dev = &pdata->dev->dev;
236 	struct dfl_fme_br_pdata br_pdata;
237 	struct dfl_fme_bridge *fme_br;
238 	int ret = -ENOMEM;
239 
240 	fme_br = devm_kzalloc(dev, sizeof(*fme_br), GFP_KERNEL);
241 	if (!fme_br)
242 		return ERR_PTR(ret);
243 
244 	br_pdata.cdev = pdata->dfl_cdev;
245 	br_pdata.port_id = port_id;
246 
247 	fme_br->br = platform_device_alloc(DFL_FPGA_FME_BRIDGE,
248 					   PLATFORM_DEVID_AUTO);
249 	if (!fme_br->br)
250 		return ERR_PTR(ret);
251 
252 	fme_br->br->dev.parent = dev;
253 
254 	ret = platform_device_add_data(fme_br->br, &br_pdata, sizeof(br_pdata));
255 	if (ret)
256 		goto create_br_err;
257 
258 	ret = platform_device_add(fme_br->br);
259 	if (ret)
260 		goto create_br_err;
261 
262 	return fme_br;
263 
264 create_br_err:
265 	platform_device_put(fme_br->br);
266 	return ERR_PTR(ret);
267 }
268 
269 /**
270  * dfl_fme_destroy_bridge - destroy fpga bridge platform device
271  * @fme_br: fme bridge to destroy
272  */
273 static void dfl_fme_destroy_bridge(struct dfl_fme_bridge *fme_br)
274 {
275 	platform_device_unregister(fme_br->br);
276 }
277 
278 /**
279  * dfl_fme_destroy_bridge - destroy all fpga bridge platform device
280  * @pdata: fme platform device's pdata
281  */
282 static void dfl_fme_destroy_bridges(struct dfl_feature_platform_data *pdata)
283 {
284 	struct dfl_fme *priv = dfl_fpga_pdata_get_private(pdata);
285 	struct dfl_fme_bridge *fbridge, *tmp;
286 
287 	list_for_each_entry_safe(fbridge, tmp, &priv->bridge_list, node) {
288 		list_del(&fbridge->node);
289 		dfl_fme_destroy_bridge(fbridge);
290 	}
291 }
292 
293 /**
294  * dfl_fme_create_region - create fpga region platform device as child
295  *
296  * @pdata: fme platform device's pdata
297  * @mgr: mgr platform device needed for region
298  * @br: br platform device needed for region
299  * @port_id: port id
300  *
301  * Return: fme region if successful, and error code otherwise.
302  */
303 static struct dfl_fme_region *
304 dfl_fme_create_region(struct dfl_feature_platform_data *pdata,
305 		      struct platform_device *mgr,
306 		      struct platform_device *br, int port_id)
307 {
308 	struct dfl_fme_region_pdata region_pdata;
309 	struct device *dev = &pdata->dev->dev;
310 	struct dfl_fme_region *fme_region;
311 	int ret = -ENOMEM;
312 
313 	fme_region = devm_kzalloc(dev, sizeof(*fme_region), GFP_KERNEL);
314 	if (!fme_region)
315 		return ERR_PTR(ret);
316 
317 	region_pdata.mgr = mgr;
318 	region_pdata.br = br;
319 
320 	/*
321 	 * Each FPGA device may have more than one port, so allocate platform
322 	 * device using the same port platform device id.
323 	 */
324 	fme_region->region = platform_device_alloc(DFL_FPGA_FME_REGION, br->id);
325 	if (!fme_region->region)
326 		return ERR_PTR(ret);
327 
328 	fme_region->region->dev.parent = dev;
329 
330 	ret = platform_device_add_data(fme_region->region, &region_pdata,
331 				       sizeof(region_pdata));
332 	if (ret)
333 		goto create_region_err;
334 
335 	ret = platform_device_add(fme_region->region);
336 	if (ret)
337 		goto create_region_err;
338 
339 	fme_region->port_id = port_id;
340 
341 	return fme_region;
342 
343 create_region_err:
344 	platform_device_put(fme_region->region);
345 	return ERR_PTR(ret);
346 }
347 
348 /**
349  * dfl_fme_destroy_region - destroy fme region
350  * @fme_region: fme region to destroy
351  */
352 static void dfl_fme_destroy_region(struct dfl_fme_region *fme_region)
353 {
354 	platform_device_unregister(fme_region->region);
355 }
356 
357 /**
358  * dfl_fme_destroy_regions - destroy all fme regions
359  * @pdata: fme platform device's pdata
360  */
361 static void dfl_fme_destroy_regions(struct dfl_feature_platform_data *pdata)
362 {
363 	struct dfl_fme *priv = dfl_fpga_pdata_get_private(pdata);
364 	struct dfl_fme_region *fme_region, *tmp;
365 
366 	list_for_each_entry_safe(fme_region, tmp, &priv->region_list, node) {
367 		list_del(&fme_region->node);
368 		dfl_fme_destroy_region(fme_region);
369 	}
370 }
371 
372 static int pr_mgmt_init(struct platform_device *pdev,
373 			struct dfl_feature *feature)
374 {
375 	struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
376 	struct dfl_fme_region *fme_region;
377 	struct dfl_fme_bridge *fme_br;
378 	struct platform_device *mgr;
379 	struct dfl_fme *priv;
380 	void __iomem *fme_hdr;
381 	int ret = -ENODEV, i = 0;
382 	u64 fme_cap, port_offset;
383 
384 	fme_hdr = dfl_get_feature_ioaddr_by_id(&pdev->dev,
385 					       FME_FEATURE_ID_HEADER);
386 
387 	mutex_lock(&pdata->lock);
388 	priv = dfl_fpga_pdata_get_private(pdata);
389 
390 	/* Initialize the region and bridge sub device list */
391 	INIT_LIST_HEAD(&priv->region_list);
392 	INIT_LIST_HEAD(&priv->bridge_list);
393 
394 	/* Create fpga mgr platform device */
395 	mgr = dfl_fme_create_mgr(pdata, feature);
396 	if (IS_ERR(mgr)) {
397 		dev_err(&pdev->dev, "fail to create fpga mgr pdev\n");
398 		goto unlock;
399 	}
400 
401 	priv->mgr = mgr;
402 
403 	/* Read capability register to check number of regions and bridges */
404 	fme_cap = readq(fme_hdr + FME_HDR_CAP);
405 	for (; i < FIELD_GET(FME_CAP_NUM_PORTS, fme_cap); i++) {
406 		port_offset = readq(fme_hdr + FME_HDR_PORT_OFST(i));
407 		if (!(port_offset & FME_PORT_OFST_IMP))
408 			continue;
409 
410 		/* Create bridge for each port */
411 		fme_br = dfl_fme_create_bridge(pdata, i);
412 		if (IS_ERR(fme_br)) {
413 			ret = PTR_ERR(fme_br);
414 			goto destroy_region;
415 		}
416 
417 		list_add(&fme_br->node, &priv->bridge_list);
418 
419 		/* Create region for each port */
420 		fme_region = dfl_fme_create_region(pdata, mgr,
421 						   fme_br->br, i);
422 		if (IS_ERR(fme_region)) {
423 			ret = PTR_ERR(fme_region);
424 			goto destroy_region;
425 		}
426 
427 		list_add(&fme_region->node, &priv->region_list);
428 	}
429 	mutex_unlock(&pdata->lock);
430 
431 	return 0;
432 
433 destroy_region:
434 	dfl_fme_destroy_regions(pdata);
435 	dfl_fme_destroy_bridges(pdata);
436 	dfl_fme_destroy_mgr(pdata);
437 unlock:
438 	mutex_unlock(&pdata->lock);
439 	return ret;
440 }
441 
442 static void pr_mgmt_uinit(struct platform_device *pdev,
443 			  struct dfl_feature *feature)
444 {
445 	struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
446 
447 	mutex_lock(&pdata->lock);
448 
449 	dfl_fme_destroy_regions(pdata);
450 	dfl_fme_destroy_bridges(pdata);
451 	dfl_fme_destroy_mgr(pdata);
452 	mutex_unlock(&pdata->lock);
453 }
454 
455 static long fme_pr_ioctl(struct platform_device *pdev,
456 			 struct dfl_feature *feature,
457 			 unsigned int cmd, unsigned long arg)
458 {
459 	long ret;
460 
461 	switch (cmd) {
462 	case DFL_FPGA_FME_PORT_PR:
463 		ret = fme_pr(pdev, arg);
464 		break;
465 	default:
466 		ret = -ENODEV;
467 	}
468 
469 	return ret;
470 }
471 
472 const struct dfl_feature_ops pr_mgmt_ops = {
473 	.init = pr_mgmt_init,
474 	.uinit = pr_mgmt_uinit,
475 	.ioctl = fme_pr_ioctl,
476 };
477