diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-platform-dfl-port | 7 | ||||
-rw-r--r-- | drivers/fpga/dfl-afu-main.c | 79 | ||||
-rw-r--r-- | include/uapi/linux/fpga-dfl.h | 17 |
3 files changed, 102 insertions, 1 deletions
diff --git a/Documentation/ABI/testing/sysfs-platform-dfl-port b/Documentation/ABI/testing/sysfs-platform-dfl-port new file mode 100644 index 000000000000..cb91165f5397 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-dfl-port | |||
@@ -0,0 +1,7 @@ | |||
1 | What: /sys/bus/platform/devices/dfl-port.0/id | ||
2 | Date: June 2018 | ||
3 | KernelVersion: 4.19 | ||
4 | Contact: Wu Hao <hao.wu@intel.com> | ||
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 | ||
7 | distinguish different ports under same FPGA device. | ||
diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c index a38d6a825e7e..d36b3e9f3984 100644 --- a/drivers/fpga/dfl-afu-main.c +++ b/drivers/fpga/dfl-afu-main.c | |||
@@ -16,6 +16,7 @@ | |||
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/fpga-dfl.h> | ||
19 | 20 | ||
20 | #include "dfl.h" | 21 | #include "dfl.h" |
21 | 22 | ||
@@ -87,6 +88,41 @@ static int port_disable(struct platform_device *pdev) | |||
87 | return 0; | 88 | return 0; |
88 | } | 89 | } |
89 | 90 | ||
91 | /* | ||
92 | * This function resets the FPGA Port and its accelerator (AFU) by function | ||
93 | * __port_disable and __port_enable (set port soft reset bit and then clear | ||
94 | * it). Userspace can do Port reset at any time, e.g. during DMA or Partial | ||
95 | * Reconfiguration. But it should never cause any system level issue, only | ||
96 | * functional failure (e.g. DMA or PR operation failure) and be recoverable | ||
97 | * from the failure. | ||
98 | * | ||
99 | * Note: the accelerator (AFU) is not accessible when its port is in reset | ||
100 | * (disabled). Any attempts on MMIO access to AFU while in reset, will | ||
101 | * result errors reported via port error reporting sub feature (if present). | ||
102 | */ | ||
103 | static int __port_reset(struct platform_device *pdev) | ||
104 | { | ||
105 | int ret; | ||
106 | |||
107 | ret = port_disable(pdev); | ||
108 | if (!ret) | ||
109 | port_enable(pdev); | ||
110 | |||
111 | return ret; | ||
112 | } | ||
113 | |||
114 | static int port_reset(struct platform_device *pdev) | ||
115 | { | ||
116 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); | ||
117 | int ret; | ||
118 | |||
119 | mutex_lock(&pdata->lock); | ||
120 | ret = __port_reset(pdev); | ||
121 | mutex_unlock(&pdata->lock); | ||
122 | |||
123 | return ret; | ||
124 | } | ||
125 | |||
90 | static int port_get_id(struct platform_device *pdev) | 126 | static int port_get_id(struct platform_device *pdev) |
91 | { | 127 | { |
92 | void __iomem *base; | 128 | void __iomem *base; |
@@ -96,23 +132,63 @@ static int port_get_id(struct platform_device *pdev) | |||
96 | return FIELD_GET(PORT_CAP_PORT_NUM, readq(base + PORT_HDR_CAP)); | 132 | return FIELD_GET(PORT_CAP_PORT_NUM, readq(base + PORT_HDR_CAP)); |
97 | } | 133 | } |
98 | 134 | ||
135 | static ssize_t | ||
136 | id_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
137 | { | ||
138 | int id = port_get_id(to_platform_device(dev)); | ||
139 | |||
140 | return scnprintf(buf, PAGE_SIZE, "%d\n", id); | ||
141 | } | ||
142 | static DEVICE_ATTR_RO(id); | ||
143 | |||
144 | static const struct attribute *port_hdr_attrs[] = { | ||
145 | &dev_attr_id.attr, | ||
146 | NULL, | ||
147 | }; | ||
148 | |||
99 | static int port_hdr_init(struct platform_device *pdev, | 149 | static int port_hdr_init(struct platform_device *pdev, |
100 | struct dfl_feature *feature) | 150 | struct dfl_feature *feature) |
101 | { | 151 | { |
102 | dev_dbg(&pdev->dev, "PORT HDR Init.\n"); | 152 | dev_dbg(&pdev->dev, "PORT HDR Init.\n"); |
103 | 153 | ||
104 | return 0; | 154 | port_reset(pdev); |
155 | |||
156 | return sysfs_create_files(&pdev->dev.kobj, port_hdr_attrs); | ||
105 | } | 157 | } |
106 | 158 | ||
107 | static void port_hdr_uinit(struct platform_device *pdev, | 159 | static void port_hdr_uinit(struct platform_device *pdev, |
108 | struct dfl_feature *feature) | 160 | struct dfl_feature *feature) |
109 | { | 161 | { |
110 | dev_dbg(&pdev->dev, "PORT HDR UInit.\n"); | 162 | dev_dbg(&pdev->dev, "PORT HDR UInit.\n"); |
163 | |||
164 | sysfs_remove_files(&pdev->dev.kobj, port_hdr_attrs); | ||
165 | } | ||
166 | |||
167 | static long | ||
168 | port_hdr_ioctl(struct platform_device *pdev, struct dfl_feature *feature, | ||
169 | unsigned int cmd, unsigned long arg) | ||
170 | { | ||
171 | long ret; | ||
172 | |||
173 | switch (cmd) { | ||
174 | case DFL_FPGA_PORT_RESET: | ||
175 | if (!arg) | ||
176 | ret = port_reset(pdev); | ||
177 | else | ||
178 | ret = -EINVAL; | ||
179 | break; | ||
180 | default: | ||
181 | dev_dbg(&pdev->dev, "%x cmd not handled", cmd); | ||
182 | ret = -ENODEV; | ||
183 | } | ||
184 | |||
185 | return ret; | ||
111 | } | 186 | } |
112 | 187 | ||
113 | static const struct dfl_feature_ops port_hdr_ops = { | 188 | static const struct dfl_feature_ops port_hdr_ops = { |
114 | .init = port_hdr_init, | 189 | .init = port_hdr_init, |
115 | .uinit = port_hdr_uinit, | 190 | .uinit = port_hdr_uinit, |
191 | .ioctl = port_hdr_ioctl, | ||
116 | }; | 192 | }; |
117 | 193 | ||
118 | static struct dfl_feature_driver port_feature_drvs[] = { | 194 | static struct dfl_feature_driver port_feature_drvs[] = { |
@@ -154,6 +230,7 @@ static int afu_release(struct inode *inode, struct file *filp) | |||
154 | 230 | ||
155 | pdata = dev_get_platdata(&pdev->dev); | 231 | pdata = dev_get_platdata(&pdev->dev); |
156 | 232 | ||
233 | port_reset(pdev); | ||
157 | dfl_feature_dev_use_end(pdata); | 234 | dfl_feature_dev_use_end(pdata); |
158 | 235 | ||
159 | return 0; | 236 | return 0; |
diff --git a/include/uapi/linux/fpga-dfl.h b/include/uapi/linux/fpga-dfl.h index 9666af85a8f5..e6b4dd26cc68 100644 --- a/include/uapi/linux/fpga-dfl.h +++ b/include/uapi/linux/fpga-dfl.h | |||
@@ -29,8 +29,11 @@ | |||
29 | #define DFL_FPGA_MAGIC 0xB6 | 29 | #define DFL_FPGA_MAGIC 0xB6 |
30 | 30 | ||
31 | #define DFL_FPGA_BASE 0 | 31 | #define DFL_FPGA_BASE 0 |
32 | #define DFL_PORT_BASE 0x40 | ||
32 | #define DFL_FME_BASE 0x80 | 33 | #define DFL_FME_BASE 0x80 |
33 | 34 | ||
35 | /* Common IOCTLs for both FME and AFU file descriptor */ | ||
36 | |||
34 | /** | 37 | /** |
35 | * DFL_FPGA_GET_API_VERSION - _IO(DFL_FPGA_MAGIC, DFL_FPGA_BASE + 0) | 38 | * DFL_FPGA_GET_API_VERSION - _IO(DFL_FPGA_MAGIC, DFL_FPGA_BASE + 0) |
36 | * | 39 | * |
@@ -49,6 +52,20 @@ | |||
49 | 52 | ||
50 | #define DFL_FPGA_CHECK_EXTENSION _IO(DFL_FPGA_MAGIC, DFL_FPGA_BASE + 1) | 53 | #define DFL_FPGA_CHECK_EXTENSION _IO(DFL_FPGA_MAGIC, DFL_FPGA_BASE + 1) |
51 | 54 | ||
55 | /* IOCTLs for AFU file descriptor */ | ||
56 | |||
57 | /** | ||
58 | * DFL_FPGA_PORT_RESET - _IO(DFL_FPGA_MAGIC, DFL_PORT_BASE + 0) | ||
59 | * | ||
60 | * Reset the FPGA Port and its AFU. No parameters are supported. | ||
61 | * Userspace can do Port reset at any time, e.g. during DMA or PR. But | ||
62 | * it should never cause any system level issue, only functional failure | ||
63 | * (e.g. DMA or PR operation failure) and be recoverable from the failure. | ||
64 | * Return: 0 on success, -errno of failure | ||
65 | */ | ||
66 | |||
67 | #define DFL_FPGA_PORT_RESET _IO(DFL_FPGA_MAGIC, DFL_PORT_BASE + 0) | ||
68 | |||
52 | /* IOCTLs for FME file descriptor */ | 69 | /* IOCTLs for FME file descriptor */ |
53 | 70 | ||
54 | /** | 71 | /** |