diff options
| author | Xiao Guangrong <guangrong.xiao@linux.intel.com> | 2018-06-29 20:53:34 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-07-15 07:55:47 -0400 |
| commit | 857a26222ff75eecf7d701ef0e91e4fbf6efa663 (patch) | |
| tree | 5e8ec7a739d2e65ce87e8456d1f3884257293300 | |
| parent | 6fd893c409e5939ea2145b27796c155535988734 (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-port | 9 | ||||
| -rw-r--r-- | drivers/fpga/Makefile | 2 | ||||
| -rw-r--r-- | drivers/fpga/dfl-afu-main.c | 219 | ||||
| -rw-r--r-- | drivers/fpga/dfl-afu-region.c | 166 | ||||
| -rw-r--r-- | drivers/fpga/dfl-afu.h | 71 | ||||
| -rw-r--r-- | include/uapi/linux/fpga-dfl.h | 48 |
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> | |||
| 5 | Description: Read-only. It returns id of this port. One DFL FPGA device | 5 | Description: 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 | |||
| 9 | What: /sys/bus/platform/devices/dfl-port.0/afu_id | ||
| 10 | Date: June 2018 | ||
| 11 | KernelVersion: 4.19 | ||
| 12 | Contact: Wu Hao <hao.wu@intel.com> | ||
| 13 | Description: 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 | |||
| 38 | obj-$(CONFIG_FPGA_DFL_AFU) += dfl-afu.o | 38 | obj-$(CONFIG_FPGA_DFL_AFU) += dfl-afu.o |
| 39 | 39 | ||
| 40 | dfl-fme-objs := dfl-fme-main.o dfl-fme-pr.o | 40 | dfl-fme-objs := dfl-fme-main.o dfl-fme-pr.o |
| 41 | dfl-afu-objs := dfl-afu-main.o | 41 | dfl-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 |
| 44 | obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o | 44 | obj-$(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 | */ |
| 32 | static void port_enable(struct platform_device *pdev) | 32 | static 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 | ||
| 194 | static ssize_t | ||
| 195 | afu_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 | } | ||
| 215 | static DEVICE_ATTR_RO(afu_id); | ||
| 216 | |||
| 217 | static const struct attribute *port_afu_attrs[] = { | ||
| 218 | &dev_attr_afu_id.attr, | ||
| 219 | NULL | ||
| 220 | }; | ||
| 221 | |||
| 222 | static 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 | |||
| 240 | static 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 | |||
| 248 | static const struct dfl_feature_ops port_afu_ops = { | ||
| 249 | .init = port_afu_init, | ||
| 250 | .uinit = port_afu_uinit, | ||
| 251 | }; | ||
| 252 | |||
| 194 | static struct dfl_feature_driver port_feature_drvs[] = { | 253 | static 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 | ||
| 309 | static long | ||
| 310 | afu_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 | |||
| 337 | static 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, ®ion); | ||
| 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))) | ||
