aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXiao Guangrong <guangrong.xiao@linux.intel.com>2018-06-29 20:53:34 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-07-15 07:55:47 -0400
commit857a26222ff75eecf7d701ef0e91e4fbf6efa663 (patch)
tree5e8ec7a739d2e65ce87e8456d1f3884257293300
parent6fd893c409e5939ea2145b27796c155535988734 (diff)
fpga: dfl: afu: add afu sub feature support
User Accelerated Function Unit sub feature exposes the MMIO region of the AFU. After valid PR bitstream is programmed and the port is enabled, then this MMIO region could be accessed. This patch adds support to enumerate the AFU MMIO region and expose it to userspace via mmap file operation. Below interfaces are exposed to user: Sysfs interface: * /sys/class/fpga_region/<regionX>/<dfl-port.x>/afu_id Read-only. Indicate which PR bitstream is programmed to this AFU. Ioctl interfaces: * DFL_FPGA_PORT_GET_INFO Provide info to userspace on the number of supported region. Only UAFU region is supported now. * DFL_FPGA_PORT_GET_REGION_INFO Provide region information, including access permission, region size, offset from the start of device fd. Signed-off-by: Tim Whisonant <tim.whisonant@intel.com> Signed-off-by: Enno Luebbers <enno.luebbers@intel.com> Signed-off-by: Shiva Rao <shiva.rao@intel.com> Signed-off-by: Christopher Rauer <christopher.rauer@intel.com> Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com> Signed-off-by: Wu Hao <hao.wu@intel.com> Acked-by: Alan Tull <atull@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--Documentation/ABI/testing/sysfs-platform-dfl-port9
-rw-r--r--drivers/fpga/Makefile2
-rw-r--r--drivers/fpga/dfl-afu-main.c219
-rw-r--r--drivers/fpga/dfl-afu-region.c166
-rw-r--r--drivers/fpga/dfl-afu.h71
-rw-r--r--include/uapi/linux/fpga-dfl.h48
6 files changed, 508 insertions, 7 deletions
diff --git a/Documentation/ABI/testing/sysfs-platform-dfl-port b/Documentation/ABI/testing/sysfs-platform-dfl-port
index cb91165f5397..6a92dda517b0 100644
--- a/Documentation/ABI/testing/sysfs-platform-dfl-port
+++ b/Documentation/ABI/testing/sysfs-platform-dfl-port
@@ -5,3 +5,12 @@ Contact: Wu Hao <hao.wu@intel.com>
5Description: Read-only. It returns id of this port. One DFL FPGA device 5Description: Read-only. It returns id of this port. One DFL FPGA device
6 may have more than one port. Userspace could use this id to 6 may have more than one port. Userspace could use this id to
7 distinguish different ports under same FPGA device. 7 distinguish different ports under same FPGA device.
8
9What: /sys/bus/platform/devices/dfl-port.0/afu_id
10Date: June 2018
11KernelVersion: 4.19
12Contact: Wu Hao <hao.wu@intel.com>
13Description: Read-only. User can program different PR bitstreams to FPGA
14 Accelerator Function Unit (AFU) for different functions. It
15 returns uuid which could be used to identify which PR bitstream
16 is programmed in this AFU.
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 1ac7749b2542..a44d50dd0b70 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -38,7 +38,7 @@ obj-$(CONFIG_FPGA_DFL_FME_REGION) += dfl-fme-region.o
38obj-$(CONFIG_FPGA_DFL_AFU) += dfl-afu.o 38obj-$(CONFIG_FPGA_DFL_AFU) += dfl-afu.o
39 39
40dfl-fme-objs := dfl-fme-main.o dfl-fme-pr.o 40dfl-fme-objs := dfl-fme-main.o dfl-fme-pr.o
41dfl-afu-objs := dfl-afu-main.o 41dfl-afu-objs := dfl-afu-main.o dfl-afu-region.o
42 42
43# Drivers for FPGAs which implement DFL 43# Drivers for FPGAs which implement DFL
44obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o 44obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o
diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c
index 4074b97122e2..f67a78d7e9ad 100644
--- a/drivers/fpga/dfl-afu-main.c
+++ b/drivers/fpga/dfl-afu-main.c
@@ -16,18 +16,18 @@
16 16
17#include <linux/kernel.h> 17#include <linux/kernel.h>
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/uaccess.h>
19#include <linux/fpga-dfl.h> 20#include <linux/fpga-dfl.h>
20 21
21#include "dfl.h" 22#include "dfl-afu.h"
22 23
23/** 24/**
24 * port_enable - enable a port 25 * port_enable - enable a port
25 * @pdev: port platform device. 26 * @pdev: port platform device.
26 * 27 *
27 * Enable Port by clear the port soft reset bit, which is set by default. 28 * Enable Port by clear the port soft reset bit, which is set by default.
28 * The User AFU is unable to respond to any MMIO access while in reset. 29 * The AFU is unable to respond to any MMIO access while in reset.
29 * port_enable function should only be used after port_disable 30 * port_enable function should only be used after port_disable function.
30 * function.
31 */ 31 */
32static void port_enable(struct platform_device *pdev) 32static void port_enable(struct platform_device *pdev)
33{ 33{
@@ -191,12 +191,75 @@ static const struct dfl_feature_ops port_hdr_ops = {
191 .ioctl = port_hdr_ioctl, 191 .ioctl = port_hdr_ioctl,
192}; 192};
193 193
194static ssize_t
195afu_id_show(struct device *dev, struct device_attribute *attr, char *buf)
196{
197 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
198 void __iomem *base;
199 u64 guidl, guidh;
200
201 base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_AFU);
202
203 mutex_lock(&pdata->lock);
204 if (pdata->disable_count) {
205 mutex_unlock(&pdata->lock);
206 return -EBUSY;
207 }
208
209 guidl = readq(base + GUID_L);
210 guidh = readq(base + GUID_H);
211 mutex_unlock(&pdata->lock);
212
213 return scnprintf(buf, PAGE_SIZE, "%016llx%016llx\n", guidh, guidl);
214}
215static DEVICE_ATTR_RO(afu_id);
216
217static const struct attribute *port_afu_attrs[] = {
218 &dev_attr_afu_id.attr,
219 NULL
220};
221
222static int port_afu_init(struct platform_device *pdev,
223 struct dfl_feature *feature)
224{
225 struct resource *res = &pdev->resource[feature->resource_index];
226 int ret;
227
228 dev_dbg(&pdev->dev, "PORT AFU Init.\n");
229
230 ret = afu_mmio_region_add(dev_get_platdata(&pdev->dev),
231 DFL_PORT_REGION_INDEX_AFU, resource_size(res),
232 res->start, DFL_PORT_REGION_READ |
233 DFL_PORT_REGION_WRITE | DFL_PORT_REGION_MMAP);
234 if (ret)
235 return ret;
236
237 return sysfs_create_files(&pdev->dev.kobj, port_afu_attrs);
238}
239
240static void port_afu_uinit(struct platform_device *pdev,
241 struct dfl_feature *feature)
242{
243 dev_dbg(&pdev->dev, "PORT AFU UInit.\n");
244
245 sysfs_remove_files(&pdev->dev.kobj, port_afu_attrs);
246}
247
248static const struct dfl_feature_ops port_afu_ops = {
249 .init = port_afu_init,
250 .uinit = port_afu_uinit,
251};
252
194static struct dfl_feature_driver port_feature_drvs[] = { 253static struct dfl_feature_driver port_feature_drvs[] = {
195 { 254 {
196 .id = PORT_FEATURE_ID_HEADER, 255 .id = PORT_FEATURE_ID_HEADER,
197 .ops = &port_hdr_ops, 256 .ops = &port_hdr_ops,
198 }, 257 },
199 { 258 {
259 .id = PORT_FEATURE_ID_AFU,
260 .ops = &port_afu_ops,
261 },
262 {
200 .ops = NULL, 263 .ops = NULL,
201 } 264 }
202}; 265};
@@ -243,6 +306,64 @@ static long afu_ioctl_check_extension(struct dfl_feature_platform_data *pdata,
243 return 0; 306 return 0;
244} 307}
245 308
309static long
310afu_ioctl_get_info(struct dfl_feature_platform_data *pdata, void __user *arg)
311{
312 struct dfl_fpga_port_info info;
313 struct dfl_afu *afu;
314 unsigned long minsz;
315
316 minsz = offsetofend(struct dfl_fpga_port_info, num_umsgs);
317
318 if (copy_from_user(&info, arg, minsz))
319 return -EFAULT;
320
321 if (info.argsz < minsz)
322 return -EINVAL;
323
324 mutex_lock(&pdata->lock);
325 afu = dfl_fpga_pdata_get_private(pdata);
326 info.flags = 0;
327 info.num_regions = afu->num_regions;
328 info.num_umsgs = afu->num_umsgs;
329 mutex_unlock(&pdata->lock);
330
331 if (copy_to_user(arg, &info, sizeof(info)))
332 return -EFAULT;
333
334 return 0;
335}
336
337static long afu_ioctl_get_region_info(struct dfl_feature_platform_data *pdata,
338 void __user *arg)
339{
340 struct dfl_fpga_port_region_info rinfo;
341 struct dfl_afu_mmio_region region;
342 unsigned long minsz;
343 long ret;
344
345 minsz = offsetofend(struct dfl_fpga_port_region_info, offset);
346
347 if (copy_from_user(&rinfo, arg, minsz))
348 return -EFAULT;
349
350 if (rinfo.argsz < minsz || rinfo.padding)
351 return -EINVAL;
352
353 ret = afu_mmio_region_get_by_index(pdata, rinfo.index, &region);
354 if (ret)
355 return ret;
356
357 rinfo.flags = region.flags;
358 rinfo.size = region.size;
359 rinfo.offset = region.offset;
360
361 if (copy_to_user(arg, &rinfo, sizeof(rinfo)))