History

Merge tag 'fpga-dfl-for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/mdf/linux-fpga into char-misc-next

Moritz writes: FPGA DFL Changes for 5.4 This pull-request contains the FPGA DFL changes for 5.4 - The first three patches are cleanup patches making use of dev_groups and making the init callback optional. - One patch adds userclock sysfs entries that are DFL specific - One patch exposes AFU port disable/enable functions - One patch adds error reporting - One patch adds AFU SignalTap support - One patch adds FME global error reporting - The final patch is a documentation patch that decribes the virtualization interfaces This patchset requires the 'dev_groups_all_drivers' tag from drivers core for the dev_groups refactoring as well as the DFL changes already in char-misc-next. Signed-off-by: Moritz Fischer <mdf@kernel.org> * tag 'fpga-dfl-for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/mdf/linux-fpga: Documentation: fpga: dfl: add descriptions for virtualization and new interfaces. fpga: dfl: fme: add global error reporting support fpga: dfl: afu: add STP (SignalTap) support fpga: dfl: afu: add error reporting support. fpga: dfl: afu: expose __afu_port_enable/disable function. fpga: dfl: afu: add userclock sysfs interfaces. fpga: dfl: afu: convert platform_driver to use dev_groups fpga: dfl: fme: convert platform_driver to use dev_groups fpga: dfl: make init callback optional driver core: add dev_groups to all drivers

Greg Kroah-Hartman committed 7 years ago

Commit b8bf2682 parents ec13c78 77a0ef414 files · +1058 −74Browse files

Unified · Split

14 files
  1. Documentation/ABI/testing/sysfs-platform-dfl-fme +62 −0
  2. Documentation/ABI/testing/sysfs-platform-dfl-port +53 −0
  3. Documentation/fpga/dfl.rst +105 −0
  4. drivers/base/dd.c +14 −0
  5. drivers/fpga/Makefile +2 −1
  6. drivers/fpga/dfl-afu-error.c +230 −0
  7. drivers/fpga/dfl-afu-main.c +188 −42
  8. drivers/fpga/dfl-afu.h +9 −0
  9. drivers/fpga/dfl-fme-error.c +359 −0
  10. drivers/fpga/dfl-fme-main.c +15 −27
  11. drivers/fpga/dfl-fme.h +3 −0
  12. drivers/fpga/dfl.c +6 −4
  13. drivers/fpga/dfl.h +9 −0
  14. include/linux/device.h +3 −0
Documentation/ABI/testing/sysfs-platform-dfl-fme+62−0
@@ -44,3 +44,65 @@ Description: Read-only. It returns socket_id to indicate which socket · 43 unmodified lines
44 this FPGA belongs to, only valid for integrated solution.44 this FPGA belongs to, only valid for integrated solution.
45 User only needs this information, in case standard numa node45 User only needs this information, in case standard numa node
46 can't provide correct information.46 can't provide correct information.
47
48What: /sys/bus/platform/devices/dfl-fme.0/errors/pcie0_errors
49Date: August 2019
50KernelVersion: 5.4
51Contact: Wu Hao <hao.wu@intel.com>
52Description: Read-Write. Read this file for errors detected on pcie0 link.
53 Write this file to clear errors logged in pcie0_errors. Write
54 fails with -EINVAL if input parsing fails or input error code
55 doesn't match.
56
57What: /sys/bus/platform/devices/dfl-fme.0/errors/pcie1_errors
58Date: August 2019
59KernelVersion: 5.4
60Contact: Wu Hao <hao.wu@intel.com>
61Description: Read-Write. Read this file for errors detected on pcie1 link.
62 Write this file to clear errors logged in pcie1_errors. Write
63 fails with -EINVAL if input parsing fails or input error code
64 doesn't match.
65
66What: /sys/bus/platform/devices/dfl-fme.0/errors/nonfatal_errors
67Date: August 2019
68KernelVersion: 5.4
69Contact: Wu Hao <hao.wu@intel.com>
70Description: Read-only. It returns non-fatal errors detected.
71
72What: /sys/bus/platform/devices/dfl-fme.0/errors/catfatal_errors
73Date: August 2019
74KernelVersion: 5.4
75Contact: Wu Hao <hao.wu@intel.com>
76Description: Read-only. It returns catastrophic and fatal errors detected.
77
78What: /sys/bus/platform/devices/dfl-fme.0/errors/inject_errors
79Date: August 2019
80KernelVersion: 5.4
81Contact: Wu Hao <hao.wu@intel.com>
82Description: Read-Write. Read this file to check errors injected. Write this
83 file to inject errors for testing purpose. Write fails with
84 -EINVAL if input parsing fails or input inject error code isn't
85 supported.
86
87What: /sys/bus/platform/devices/dfl-fme.0/errors/fme_errors
88Date: August 2019
89KernelVersion: 5.4
90Contact: Wu Hao <hao.wu@intel.com>
91Description: Read-Write. Read this file to get errors detected on FME.
92 Write this file to clear errors logged in fme_errors. Write
93 fials with -EINVAL if input parsing fails or input error code
94 doesn't match.
95
96What: /sys/bus/platform/devices/dfl-fme.0/errors/first_error
97Date: August 2019
98KernelVersion: 5.4
99Contact: Wu Hao <hao.wu@intel.com>
100Description: Read-only. Read this file to get the first error detected by
101 hardware.
102
103What: /sys/bus/platform/devices/dfl-fme.0/errors/next_error
104Date: August 2019
105KernelVersion: 5.4
106Contact: Wu Hao <hao.wu@intel.com>
107Description: Read-only. Read this file to get the second error detected by
108 hardware.
Documentation/ABI/testing/sysfs-platform-dfl-port+53−0
@@ -46,3 +46,56 @@ Contact: Wu Hao <hao.wu@intel.com> · 45 unmodified lines
46Description: Read-write. Read or set AFU latency tolerance reporting value.46Description: Read-write. Read or set AFU latency tolerance reporting value.
47 Set ltr to 1 if the AFU can tolerate latency >= 40us or set it47 Set ltr to 1 if the AFU can tolerate latency >= 40us or set it
48 to 0 if it is latency sensitive.48 to 0 if it is latency sensitive.
49
50What: /sys/bus/platform/devices/dfl-port.0/userclk_freqcmd
51Date: August 2019
52KernelVersion: 5.4
53Contact: Wu Hao <hao.wu@intel.com>
54Description: Write-only. User writes command to this interface to set
55 userclock to AFU.
56
57What: /sys/bus/platform/devices/dfl-port.0/userclk_freqsts
58Date: August 2019
59KernelVersion: 5.4
60Contact: Wu Hao <hao.wu@intel.com>
61Description: Read-only. Read this file to get the status of issued command
62 to userclck_freqcmd.
63
64What: /sys/bus/platform/devices/dfl-port.0/userclk_freqcntrcmd
65Date: August 2019
66KernelVersion: 5.4
67Contact: Wu Hao <hao.wu@intel.com>
68Description: Write-only. User writes command to this interface to set
69 userclock counter.
70
71What: /sys/bus/platform/devices/dfl-port.0/userclk_freqcntrsts
72Date: August 2019
73KernelVersion: 5.4
74Contact: Wu Hao <hao.wu@intel.com>
75Description: Read-only. Read this file to get the status of issued command
76 to userclck_freqcntrcmd.
77
78What: /sys/bus/platform/devices/dfl-port.0/errors/errors
79Date: August 2019
80KernelVersion: 5.4
81Contact: Wu Hao <hao.wu@intel.com>
82Description: Read-Write. Read this file to get errors detected on port and
83 Accelerated Function Unit (AFU). Write error code to this file
84 to clear errors. Write fails with -EINVAL if input parsing
85 fails or input error code doesn't match. Write fails with
86 -EBUSY or -ETIMEDOUT if error can't be cleared as hardware
87 in low power state (-EBUSY) or not respoding (-ETIMEDOUT).
88
89What: /sys/bus/platform/devices/dfl-port.0/errors/first_error
90Date: August 2019
91KernelVersion: 5.4
92Contact: Wu Hao <hao.wu@intel.com>
93Description: Read-only. Read this file to get the first error detected by
94 hardware.
95
96What: /sys/bus/platform/devices/dfl-port.0/errors/first_malformed_req
97Date: August 2019
98KernelVersion: 5.4
99Contact: Wu Hao <hao.wu@intel.com>
100Description: Read-only. Read this file to get the first malformed request
101 captured by hardware.
Documentation/fpga/dfl.rst+105−0
@@ -87,6 +87,8 @@ The following functions are exposed through ioctls: · 86 unmodified lines
87- Get driver API version (DFL_FPGA_GET_API_VERSION)87- Get driver API version (DFL_FPGA_GET_API_VERSION)
88- Check for extensions (DFL_FPGA_CHECK_EXTENSION)88- Check for extensions (DFL_FPGA_CHECK_EXTENSION)
89- Program bitstream (DFL_FPGA_FME_PORT_PR)89- Program bitstream (DFL_FPGA_FME_PORT_PR)
90- Assign port to PF (DFL_FPGA_FME_PORT_ASSIGN)
91- Release port from PF (DFL_FPGA_FME_PORT_RELEASE)
90 92
91More functions are exposed through sysfs93More functions are exposed through sysfs
92(/sys/class/fpga_region/regionX/dfl-fme.n/):94(/sys/class/fpga_region/regionX/dfl-fme.n/):
@@ -102,6 +104,10 @@ More functions are exposed through sysfs · 9 unmodified lines
102 one FPGA device may have more than one port, this sysfs interface indicates104 one FPGA device may have more than one port, this sysfs interface indicates
103 how many ports the FPGA device has.105 how many ports the FPGA device has.
104 106
107 Global error reporting management (errors/)
108 error reporting sysfs interfaces allow user to read errors detected by the
109 hardware, and clear the logged errors.
110
105 111
106FIU - PORT112FIU - PORT
107==========113==========
@@ -143,6 +149,10 @@ More functions are exposed through sysfs: · 35 unmodified lines
143 Read Accelerator GUID (afu_id)149 Read Accelerator GUID (afu_id)
144 afu_id indicates which PR bitstream is programmed to this AFU.150 afu_id indicates which PR bitstream is programmed to this AFU.
145 151
152 Error reporting (errors/)
153 error reporting sysfs interfaces allow user to read port/afu errors
154 detected by the hardware, and clear the logged errors.
155
146 156
147DFL Framework Overview157DFL Framework Overview
148======================158======================
@@ -218,6 +228,101 @@ the compat_id exposed by the target FPGA region. This check is usually done by · 69 unmodified lines
218userspace before calling the reconfiguration IOCTL.228userspace before calling the reconfiguration IOCTL.
219 229
220 230
231FPGA virtualization - PCIe SRIOV
232================================
233This section describes the virtualization support on DFL based FPGA device to
234enable accessing an accelerator from applications running in a virtual machine
235(VM). This section only describes the PCIe based FPGA device with SRIOV support.
236
237Features supported by the particular FPGA device are exposed through Device
238Feature Lists, as illustrated below:
239
240::
241
242 +-------------------------------+ +-------------+
243 | PF | | VF |
244 +-------------------------------+ +-------------+
245 ^ ^ ^ ^
246 | | | |
247 +-----|------------|---------|--------------|-------+
248 | | | | | |
249 | +-----+ +-------+ +-------+ +-------+ |
250 | | FME | | Port0 | | Port1 | | Port2 | |
251 | +-----+ +-------+ +-------+ +-------+ |
252 | ^ ^ ^ |
253 | | | | |
254 | +-------+ +------+ +-------+ |
255 | | AFU | | AFU | | AFU | |
256 | +-------+ +------+ +-------+ |
257 | |
258 | DFL based FPGA PCIe Device |
259 +---------------------------------------------------+
260
261FME is always accessed through the physical function (PF).
262
263Ports (and related AFUs) are accessed via PF by default, but could be exposed
264through virtual function (VF) devices via PCIe SRIOV. Each VF only contains
2651 Port and 1 AFU for isolation. Users could assign individual VFs (accelerators)
266created via PCIe SRIOV interface, to virtual machines.
267
268The driver organization in virtualization case is illustrated below:
269::
270
271 +-------++------++------+ |
272 | FME || FME || FME | |
273 | FPGA || FPGA || FPGA | |
274 |Manager||Bridge||Region| |
275 +-------++------++------+ |
276 +-----------------------+ +--------+ | +--------+
277 | FME | | AFU | | | AFU |
278 | Module | | Module | | | Module |
279 +-----------------------+ +--------+ | +--------+
280 +-----------------------+ | +-----------------------+
281 | FPGA Container Device | | | FPGA Container Device |
282 | (FPGA Base Region) | | | (FPGA Base Region) |
283 +-----------------------+ | +-----------------------+
284 +------------------+ | +------------------+
285 | FPGA PCIE Module | | Virtual | FPGA PCIE Module |
286 +------------------+ Host | Machine +------------------+
287 -------------------------------------- | ------------------------------
288 +---------------+ | +---------------+
289 | PCI PF Device | | | PCI VF Device |
290 +---------------+ | +---------------+
291
292FPGA PCIe device driver is always loaded first once a FPGA PCIe PF or VF device
293is detected. It:
294
295* Finishes enumeration on both FPGA PCIe PF and VF device using common
296 interfaces from DFL framework.
297* Supports SRIOV.
298
299The FME device driver plays a management role in this driver architecture, it
300provides ioctls to release Port from PF and assign Port to PF. After release
301a port from PF, then it's safe to expose this port through a VF via PCIe SRIOV
302sysfs interface.
303
304To enable accessing an accelerator from applications running in a VM, the
305respective AFU's port needs to be assigned to a VF using the following steps:
306
307#. The PF owns all AFU ports by default. Any port that needs to be
308 reassigned to a VF must first be released through the
309 DFL_FPGA_FME_PORT_RELEASE ioctl on the FME device.
310
311#. Once N ports are released from PF, then user can use command below
312 to enable SRIOV and VFs. Each VF owns only one Port with AFU.
313
314 ::
315
316 echo N > $PCI_DEVICE_PATH/sriov_numvfs
317
318#. Pass through the VFs to VMs
319
320#. The AFU under VF is accessible from applications in VM (using the
321 same driver inside the VF).
322
323Note that an FME can't be assigned to a VF, thus PR and other management
324functions are only available via the PF.
325
221Device enumeration326Device enumeration
222==================327==================
223This section introduces how applications enumerate the fpga device from328This section introduces how applications enumerate the fpga device from
drivers/base/dd.c+14−0
@@ -554,9 +554,16 @@ re_probe: · 553 unmodified lines
554 goto probe_failed;554 goto probe_failed;
555 }555 }
556 556
557 if (device_add_groups(dev, drv->dev_groups)) {
558 dev_err(dev, "device_add_groups() failed\n");
559 goto dev_groups_failed;
560 }
561
557 if (test_remove) {562 if (test_remove) {
558 test_remove = false;563 test_remove = false;
559 564
565 device_remove_groups(dev, drv->dev_groups);
566
560 if (dev->bus->remove)567 if (dev->bus->remove)
561 dev->bus->remove(dev);568 dev->bus->remove(dev);
562 else if (drv->remove)569 else if (drv->remove)
@@ -584,6 +591,11 @@ re_probe: · 21 unmodified lines
584 drv->bus->name, __func__, dev_name(dev), drv->name);591 drv->bus->name, __func__, dev_name(dev), drv->name);
585 goto done;592 goto done;
586 593
594dev_groups_failed:
595 if (dev->bus->remove)
596 dev->bus->remove(dev);
597 else if (drv->remove)
598 drv->remove(dev);
587probe_failed:599probe_failed:
588 if (dev->bus)600 if (dev->bus)
589 blocking_notifier_call_chain(&dev->bus->p->bus_notifier,601 blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
@@ -1114,6 +1126,8 @@ static void __device_release_driver(struct device *dev, struct device *parent) · 524 unmodified lines
1114 1126
1115 pm_runtime_put_sync(dev);1127 pm_runtime_put_sync(dev);
1116 1128
1129 device_remove_groups(dev, drv->dev_groups);
1130
1117 if (dev->bus && dev->bus->remove)1131 if (dev->bus && dev->bus->remove)
1118 dev->bus->remove(dev);1132 dev->bus->remove(dev);
1119 else if (drv->remove)1133 else if (drv->remove)
drivers/fpga/Makefile+2−1
@@ -39,8 +39,9 @@ obj-$(CONFIG_FPGA_DFL_FME_BRIDGE) += dfl-fme-br.o · 38 unmodified lines
39obj-$(CONFIG_FPGA_DFL_FME_REGION) += dfl-fme-region.o39obj-$(CONFIG_FPGA_DFL_FME_REGION) += dfl-fme-region.o
40obj-$(CONFIG_FPGA_DFL_AFU) += dfl-afu.o40obj-$(CONFIG_FPGA_DFL_AFU) += dfl-afu.o
41 41
42dfl-fme-objs := dfl-fme-main.o dfl-fme-pr.o42dfl-fme-objs := dfl-fme-main.o dfl-fme-pr.o dfl-fme-error.o
43dfl-afu-objs := dfl-afu-main.o dfl-afu-region.o dfl-afu-dma-region.o43dfl-afu-objs := dfl-afu-main.o dfl-afu-region.o dfl-afu-dma-region.o
44dfl-afu-objs += dfl-afu-error.o
44 45
45# Drivers for FPGAs which implement DFL46# Drivers for FPGAs which implement DFL
46obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o47obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o
drivers/fpga/dfl-afu-error.c+230−0
@@ -0,0 +1,230 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Driver for FPGA Accelerated Function Unit (AFU) Error Reporting
4 *
5 * Copyright 2019 Intel Corporation, Inc.
6 *
7 * Authors:
8 * Wu Hao <hao.wu@linux.intel.com>
9 * Xiao Guangrong <guangrong.xiao@linux.intel.com>
10 * Joseph Grecco <joe.grecco@intel.com>
11 * Enno Luebbers <enno.luebbers@intel.com>
12 * Tim Whisonant <tim.whisonant@intel.com>
13 * Ananda Ravuri <ananda.ravuri@intel.com>
14 * Mitchel Henry <henry.mitchel@intel.com>
15 */
16
17#include <linux/uaccess.h>
18
19#include "dfl-afu.h"
20
21#define PORT_ERROR_MASK 0x8
22#define PORT_ERROR 0x10
23#define PORT_FIRST_ERROR 0x18
24#define PORT_MALFORMED_REQ0 0x20
25#define PORT_MALFORMED_REQ1 0x28
26
27#define ERROR_MASK GENMASK_ULL(63, 0)
28
29/* mask or unmask port errors by the error mask register. */
30static void __afu_port_err_mask(struct device *dev, bool mask)
31{
32 void __iomem *base;
33
34 base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR);
35
36 writeq(mask ? ERROR_MASK : 0, base + PORT_ERROR_MASK);
37}
38
39static void afu_port_err_mask(struct device *dev, bool mask)
40{
41 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
42
43 mutex_lock(&pdata->lock);
44 __afu_port_err_mask(dev, mask);
45 mutex_unlock(&pdata->lock);
46}
47
48/* clear port errors. */
49static int afu_port_err_clear(struct device *dev, u64 err)
50{
51 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
52 struct platform_device *pdev = to_platform_device(dev);
53 void __iomem *base_err, *base_hdr;
54 int ret = -EBUSY;
55 u64 v;
56
57 base_err = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR);
58 base_hdr = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
59
60 mutex_lock(&pdata->lock);
61
62 /*
63 * clear Port Errors
64 *
65 * - Check for AP6 State
66 * - Halt Port by keeping Port in reset
67 * - Set PORT Error mask to all 1 to mask errors
68 * - Clear all errors
69 * - Set Port mask to all 0 to enable errors
70 * - All errors start capturing new errors
71 * - Enable Port by pulling the port out of reset
72 */
73
74 /* if device is still in AP6 power state, can not clear any error. */
75 v = readq(base_hdr + PORT_HDR_STS);
76 if (FIELD_GET(PORT_STS_PWR_STATE, v) == PORT_STS_PWR_STATE_AP6) {
77 dev_err(dev, "Could not clear errors, device in AP6 state.\n");
78 goto done;
79 }
80
81 /* Halt Port by keeping Port in reset */
82 ret = __afu_port_disable(pdev);
83 if (ret)
84 goto done;
85
86 /* Mask all errors */
87 __afu_port_err_mask(dev, true);
88
89 /* Clear errors if err input matches with current port errors.*/
90 v = readq(base_err + PORT_ERROR);
91
92 if (v == err) {
93 writeq(v, base_err + PORT_ERROR);
94
95 v = readq(base_err + PORT_FIRST_ERROR);
96 writeq(v, base_err + PORT_FIRST_ERROR);
97 } else {
98 ret = -EINVAL;
99 }
100
101 /* Clear mask */
102 __afu_port_err_mask(dev, false);
103
104 /* Enable the Port by clear the reset */
105 __afu_port_enable(pdev);
106
107done:
108 mutex_unlock(&pdata->lock);
109 return ret;
110}
111
112static ssize_t errors_show(struct device *dev, struct device_attribute *attr,
113 char *buf)
114{
115 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
116 void __iomem *base;
117 u64 error;
118
119 base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR);
120
121 mutex_lock(&pdata->lock);
122 error = readq(base + PORT_ERROR);
123 mutex_unlock(&pdata->lock);
124
125 return sprintf(buf, "0x%llx\n", (unsigned long long)error);
126}
127
128static ssize_t errors_store(struct device *dev, struct device_attribute *attr,
129 const char *buff, size_t count)
130{
131 u64 value;
132 int ret;
133
134 if (kstrtou64(buff, 0, &value))
135 return -EINVAL;
136
137 ret = afu_port_err_clear(dev, value);
138
139 return ret ? ret : count;
140}
141static DEVICE_ATTR_RW(errors);
142
143static ssize_t first_error_show(struct device *dev,
144 struct device_attribute *attr, char *buf)
145{
146 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
147 void __iomem *base;
148 u64 error;
149
150 base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR);
151
152 mutex_lock(&pdata->lock);
153 error = readq(base + PORT_FIRST_ERROR);
154 mutex_unlock(&pdata->lock);
155
156 return sprintf(buf, "0x%llx\n", (unsigned long long)error);
157}
158static DEVICE_ATTR_RO(first_error);
159
160static ssize_t first_malformed_req_show(struct device *dev,
161 struct device_attribute *attr,
162 char *buf)
163{
164 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
165 void __iomem *base;
166 u64 req0, req1;
167
168 base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR);
169
170 mutex_lock(&pdata->lock);
171 req0 = readq(base + PORT_MALFORMED_REQ0);
172 req1 = readq(base + PORT_MALFORMED_REQ1);
173 mutex_unlock(&pdata->lock);
174
175 return sprintf(buf, "0x%016llx%016llx\n",
176 (unsigned long long)req1, (unsigned long long)req0);
177}
178static DEVICE_ATTR_RO(first_malformed_req);
179
180static struct attribute *port_err_attrs[] = {
181 &dev_attr_errors.attr,
182 &dev_attr_first_error.attr,
183 &dev_attr_first_malformed_req.attr,
184 NULL,
185};
186
187static umode_t port_err_attrs_visible(struct kobject *kobj,
188 struct attribute *attr, int n)
189{
190 struct device *dev = kobj_to_dev(kobj);
191
192 /*
193 * sysfs entries are visible only if related private feature is
194 * enumerated.
195 */
196 if (!dfl_get_feature_by_id(dev, PORT_FEATURE_ID_ERROR))
197 return 0;
198
199 return attr->mode;
200}
201
202const struct attribute_group port_err_group = {
203 .name = "errors",
204 .attrs = port_err_attrs,
205 .is_visible = port_err_attrs_visible,
206};
207
208static int port_err_init(struct platform_device *pdev,
209 struct dfl_feature *feature)
210{
211 afu_port_err_mask(&pdev->dev, false);
212
213 return 0;
214}
215
216static void port_err_uinit(struct platform_device *pdev,
217 struct dfl_feature *feature)
218{
219 afu_port_err_mask(&pdev->dev, true);
220}
221
222const struct dfl_feature_id port_err_id_table[] = {
223 {.id = PORT_FEATURE_ID_ERROR,},
224 {0,}
225};
226
227const struct dfl_feature_ops port_err_ops = {
228 .init = port_err_init,
229 .uinit = port_err_uinit,
230};
drivers/fpga/dfl-afu-main.c+188−42
@@ -22,14 +22,17 @@ · 21 unmodified lines
22#include "dfl-afu.h"22#include "dfl-afu.h"
23 23
24/**24/**
25 * port_enable - enable a port25 * __afu_port_enable - enable a port by clear reset
26 * @pdev: port platform device.26 * @pdev: port platform device.
27 *27 *
28 * 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.
29 * The 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.
30 * port_enable function should only be used after port_disable function.30 * __afu_port_enable function should only be used after __afu_port_disable
31 * function.
32 *
33 * The caller needs to hold lock for protection.
31 */34 */
32static void port_enable(struct platform_device *pdev)35void __afu_port_enable(struct platform_device *pdev)
33{36{
34 struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);37 struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
35 void __iomem *base;38 void __iomem *base;
@@ -52,13 +55,14 @@ static void port_enable(struct platform_device *pdev) · 16 unmodified lines
52#define RST_POLL_TIMEOUT 1000 /* us */55#define RST_POLL_TIMEOUT 1000 /* us */
53 56
54/**57/**
55 * port_disable - disable a port58 * __afu_port_disable - disable a port by hold reset
56 * @pdev: port platform device.59 * @pdev: port platform device.
57 *60 *
58 * Disable Port by setting the port soft reset bit, it puts the port into61 * Disable Port by setting the port soft reset bit, it puts the port into reset.
59 * reset.62 *
63 * The caller needs to hold lock for protection.
60 */64 */
61static int port_disable(struct platform_device *pdev)65int __afu_port_disable(struct platform_device *pdev)
62{66{
63 struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);67 struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
64 void __iomem *base;68 void __iomem *base;
@@ -104,9 +108,9 @@ static int __port_reset(struct platform_device *pdev) · 39 unmodified lines
104{108{
105 int ret;109 int ret;
106 110
107 ret = port_disable(pdev);111 ret = __afu_port_disable(pdev);
108 if (!ret)112 if (!ret)
109 port_enable(pdev);113 __afu_port_enable(pdev);
110 114
111 return ret;115 return ret;
112}116}
@@ -274,32 +278,134 @@ power_state_show(struct device *dev, struct device_attribute *attr, char *buf) · 161 unmodified lines
274}278}
275static DEVICE_ATTR_RO(power_state);279static DEVICE_ATTR_RO(power_state);
276 280
281static ssize_t
282userclk_freqcmd_store(struct device *dev, struct device_attribute *attr,
283 const char *buf, size_t count)
284{
285 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
286 u64 userclk_freq_cmd;
287 void __iomem *base;
288
289 if (kstrtou64(buf, 0, &userclk_freq_cmd))
290 return -EINVAL;
291
292 base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
293
294 mutex_lock(&pdata->lock);
295 writeq(userclk_freq_cmd, base + PORT_HDR_USRCLK_CMD0);
296 mutex_unlock(&pdata->lock);
297
298 return count;
299}
300static DEVICE_ATTR_WO(userclk_freqcmd);
301
302static ssize_t
303userclk_freqcntrcmd_store(struct device *dev, struct device_attribute *attr,
304 const char *buf, size_t count)
305{
306 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
307 u64 userclk_freqcntr_cmd;
308 void __iomem *base;
309
310 if (kstrtou64(buf, 0, &userclk_freqcntr_cmd))
311 return -EINVAL;
312
313 base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
314
315 mutex_lock(&pdata->lock);
316 writeq(userclk_freqcntr_cmd, base + PORT_HDR_USRCLK_CMD1);
317 mutex_unlock(&pdata->lock);
318
319 return count;
320}
321static DEVICE_ATTR_WO(userclk_freqcntrcmd);
322
323static ssize_t
324userclk_freqsts_show(struct device *dev, struct device_attribute *attr,
325 char *buf)
326{
327 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
328 u64 userclk_freqsts;
329 void __iomem *base;
330
331 base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
332
333 mutex_lock(&pdata->lock);
334 userclk_freqsts = readq(base + PORT_HDR_USRCLK_STS0);
335 mutex_unlock(&pdata->lock);
336
337 return sprintf(buf, "0x%llx\n", (unsigned long long)userclk_freqsts);
338}
339static DEVICE_ATTR_RO(userclk_freqsts);
340
341static ssize_t
342userclk_freqcntrsts_show(struct device *dev, struct device_attribute *attr,
343 char *buf)
344{
345 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
346 u64 userclk_freqcntrsts;
347 void __iomem *base;
348
349 base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
350
351 mutex_lock(&pdata->lock);
352 userclk_freqcntrsts = readq(base + PORT_HDR_USRCLK_STS1);
353 mutex_unlock(&pdata->lock);
354
355 return sprintf(buf, "0x%llx\n",
356 (unsigned long long)userclk_freqcntrsts);
357}
358static DEVICE_ATTR_RO(userclk_freqcntrsts);
359
277static struct attribute *port_hdr_attrs[] = {360static struct attribute *port_hdr_attrs[] = {
278 &dev_attr_id.attr,361 &dev_attr_id.attr,
279 &dev_attr_ltr.attr,362 &dev_attr_ltr.attr,
280 &dev_attr_ap1_event.attr,363 &dev_attr_ap1_event.attr,
281 &dev_attr_ap2_event.attr,364 &dev_attr_ap2_event.attr,
282 &dev_attr_power_state.attr,365 &dev_attr_power_state.attr,
366 &dev_attr_userclk_freqcmd.attr,
367 &dev_attr_userclk_freqcntrcmd.attr,
368 &dev_attr_userclk_freqsts.attr,
369 &dev_attr_userclk_freqcntrsts.attr,
283 NULL,370 NULL,
284};371};
285ATTRIBUTE_GROUPS(port_hdr);
286 372
287static int port_hdr_init(struct platform_device *pdev,373static umode_t port_hdr_attrs_visible(struct kobject *kobj,
288 struct dfl_feature *feature)374 struct attribute *attr, int n)
289{375{
290 dev_dbg(&pdev->dev, "PORT HDR Init.\n");376 struct device *dev = kobj_to_dev(kobj);
377 umode_t mode = attr->mode;
378 void __iomem *base;
291 379
292 port_reset(pdev);380 base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
381
382 if (dfl_feature_revision(base) > 0) {
383 /*
384 * userclk sysfs interfaces are only visible in case port
385 * revision is 0, as hardware with revision >0 doesn't
386 * support this.
387 */
388 if (attr == &dev_attr_userclk_freqcmd.attr ||
389 attr == &dev_attr_userclk_freqcntrcmd.attr ||
390 attr == &dev_attr_userclk_freqsts.attr ||
391 attr == &dev_attr_userclk_freqcntrsts.attr)
392 mode = 0;
393 }
293 394
294 return device_add_groups(&pdev->dev, port_hdr_groups);395 return mode;
295}396}
296 397
297static void port_hdr_uinit(struct platform_device *pdev,398static const struct attribute_group port_hdr_group = {
298 struct dfl_feature *feature)399 .attrs = port_hdr_attrs,
400 .is_visible = port_hdr_attrs_visible,
401};
402
403static int port_hdr_init(struct platform_device *pdev,
404 struct dfl_feature *feature)
299{405{
300 dev_dbg(&pdev->dev, "PORT HDR UInit.\n");406 port_reset(pdev);
301 407
302 device_remove_groups(&pdev->dev, port_hdr_groups);408 return 0;
303}409}
304 410
305static long411static long
@@ -330,7 +436,6 @@ static const struct dfl_feature_id port_hdr_id_table[] = { · 24 unmodified lines
330 436
331static const struct dfl_feature_ops port_hdr_ops = {437static const struct dfl_feature_ops port_hdr_ops = {
332 .init = port_hdr_init,438 .init = port_hdr_init,
333 .uinit = port_hdr_uinit,
334 .ioctl = port_hdr_ioctl,439 .ioctl = port_hdr_ioctl,
335};440};
336 441
@@ -361,32 +466,37 @@ static struct attribute *port_afu_attrs[] = { · 24 unmodified lines
361 &dev_attr_afu_id.attr,466 &dev_attr_afu_id.attr,
362 NULL467 NULL
363};468};
364ATTRIBUTE_GROUPS(port_afu);
365 469
366static int port_afu_init(struct platform_device *pdev,470static umode_t port_afu_attrs_visible(struct kobject *kobj,
367 struct dfl_feature *feature)471 struct attribute *attr, int n)
368{472{
369 struct resource *res = &pdev->resource[feature->resource_index];473 struct device *dev = kobj_to_dev(kobj);
370 int ret;
371 474
372 dev_dbg(&pdev->dev, "PORT AFU Init.\n");475 /*
373 476 * sysfs entries are visible only if related private feature is
374 ret = afu_mmio_region_add(dev_get_platdata(&pdev->dev),477 * enumerated.
375 DFL_PORT_REGION_INDEX_AFU, resource_size(res),478 */
376 res->start, DFL_PORT_REGION_READ |479 if (!dfl_get_feature_by_id(dev, PORT_FEATURE_ID_AFU))
377 DFL_PORT_REGION_WRITE | DFL_PORT_REGION_MMAP);480 return 0;
378 if (ret)
379 return ret;
380 481
381 return device_add_groups(&pdev->dev, port_afu_groups);482 return attr->mode;
382}483}
383 484
384static void port_afu_uinit(struct platform_device *pdev,485static const struct attribute_group port_afu_group = {
385 struct dfl_feature *feature)486 .attrs = port_afu_attrs,
487 .is_visible = port_afu_attrs_visible,
488};
489
490static int port_afu_init(struct platform_device *pdev,
491 struct dfl_feature *feature)
386{492{
387 dev_dbg(&pdev->dev, "PORT AFU UInit.\n");493 struct resource *res = &pdev->resource[feature->resource_index];
388 494
389 device_remove_groups(&pdev->dev, port_afu_groups);495 return afu_mmio_region_add(dev_get_platdata(&pdev->dev),
496 DFL_PORT_REGION_INDEX_AFU,
497 resource_size(res), res->start,
498 DFL_PORT_REGION_MMAP | DFL_PORT_REGION_READ |
499 DFL_PORT_REGION_WRITE);
390}500}
391 501
392static const struct dfl_feature_id port_afu_id_table[] = {502static const struct dfl_feature_id port_afu_id_table[] = {
@@ -396,7 +506,27 @@ static const struct dfl_feature_id port_afu_id_table[] = { · 3 unmodified lines
396 506
397static const struct dfl_feature_ops port_afu_ops = {507static const struct dfl_feature_ops port_afu_ops = {
398 .init = port_afu_init,508 .init = port_afu_init,
399 .uinit = port_afu_uinit,509};
510
511static int port_stp_init(struct platform_device *pdev,
512 struct dfl_feature *feature)
513{
514 struct resource *res = &pdev->resource[feature->resource_index];
515
516 return afu_mmio_region_add(dev_get_platdata(&pdev->dev),
517 DFL_PORT_REGION_INDEX_STP,
518 resource_size(res), res->start,
519 DFL_PORT_REGION_MMAP | DFL_PORT_REGION_READ |
520 DFL_PORT_REGION_WRITE);
521}
522
523static const struct dfl_feature_id port_stp_id_table[] = {
524 {.id = PORT_FEATURE_ID_STP,},
525 {0,}
526};
527
528static const struct dfl_feature_ops port_stp_ops = {
529 .init = port_stp_init,
400};530};
401 531
402static struct dfl_feature_driver port_feature_drvs[] = {532static struct dfl_feature_driver port_feature_drvs[] = {
@@ -408,6 +538,14 @@ static struct dfl_feature_driver port_feature_drvs[] = { · 5 unmodified lines
408 .id_table = port_afu_id_table,538 .id_table = port_afu_id_table,
409 .ops = &port_afu_ops,539 .ops = &port_afu_ops,
410 },540 },
541 {
542 .id_table = port_err_id_table,
543 .ops = &port_err_ops,
544 },
545 {
546 .id_table = port_stp_id_table,
547 .ops = &port_stp_ops,
548 },
411 {549 {
412 .ops = NULL,550 .ops = NULL,
413 }551 }
@@ -694,9 +832,9 @@ static int port_enable_set(struct platform_device *pdev, bool enable) · 280 unmodified lines
694 832
695 mutex_lock(&pdata->lock);833 mutex_lock(&pdata->lock);
696 if (enable)834 if (enable)
697 port_enable(pdev);835 __afu_port_enable(pdev);
698 else836 else
699 ret = port_disable(pdev);837 ret = __afu_port_disable(pdev);
700 mutex_unlock(&pdata->lock);838 mutex_unlock(&pdata->lock);
701 839
702 return ret;840 return ret;
@@ -748,9 +886,17 @@ static int afu_remove(struct platform_device *pdev) · 45 unmodified lines
748 return 0;886 return 0;
749}887}
750 888
889static const struct attribute_group *afu_dev_groups[] = {
890 &port_hdr_group,
891 &port_afu_group,
892 &port_err_group,
893 NULL
894};
895
751static struct platform_driver afu_driver = {896static struct platform_driver afu_driver = {
752 .driver = {897 .driver = {
753 .name = DFL_FPGA_FEATURE_DEV_PORT,898 .name = DFL_FPGA_FEATURE_DEV_PORT,
899 .dev_groups = afu_dev_groups,
754 },900 },
755 .probe = afu_probe,901 .probe = afu_probe,
756 .remove = afu_remove,902 .remove = afu_remove,
drivers/fpga/dfl-afu.h+9−0
@@ -79,6 +79,10 @@ struct dfl_afu { · 78 unmodified lines
79 struct dfl_feature_platform_data *pdata;79 struct dfl_feature_platform_data *pdata;
80};80};
81 81
82/* hold pdata->lock when call __afu_port_enable/disable */
83void __afu_port_enable(struct platform_device *pdev);
84int __afu_port_disable(struct platform_device *pdev);
85
82void afu_mmio_region_init(struct dfl_feature_platform_data *pdata);86void afu_mmio_region_init(struct dfl_feature_platform_data *pdata);
83int afu_mmio_region_add(struct dfl_feature_platform_data *pdata,87int afu_mmio_region_add(struct dfl_feature_platform_data *pdata,
84 u32 region_index, u64 region_size, u64 phys, u32 flags);88 u32 region_index, u64 region_size, u64 phys, u32 flags);
@@ -97,4 +101,9 @@ int afu_dma_unmap_region(struct dfl_feature_platform_data *pdata, u64 iova); · 12 unmodified lines
97struct dfl_afu_dma_region *101struct dfl_afu_dma_region *
98afu_dma_region_find(struct dfl_feature_platform_data *pdata,102afu_dma_region_find(struct dfl_feature_platform_data *pdata,
99 u64 iova, u64 size);103 u64 iova, u64 size);
104
105extern const struct dfl_feature_ops port_err_ops;
106extern const struct dfl_feature_id port_err_id_table[];
107extern const struct attribute_group port_err_group;
108
100#endif /* __DFL_AFU_H */109#endif /* __DFL_AFU_H */
drivers/fpga/dfl-fme-error.c+359−0
@@ -0,0 +1,359 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Driver for FPGA Management Engine Error Management
4 *
5 * Copyright 2019 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 * Mitchel, Henry <henry.mitchel@intel.com>
16 */
17
18#include <linux/uaccess.h>
19
20#include "dfl.h"
21#include "dfl-fme.h"
22
23#define FME_ERROR_MASK 0x8
24#define FME_ERROR 0x10
25#define MBP_ERROR BIT_ULL(6)
26#define PCIE0_ERROR_MASK 0x18
27#define PCIE0_ERROR 0x20
28#define PCIE1_ERROR_MASK 0x28
29#define PCIE1_ERROR 0x30
30#define FME_FIRST_ERROR 0x38
31#define FME_NEXT_ERROR 0x40
32#define RAS_NONFAT_ERROR_MASK 0x48
33#define RAS_NONFAT_ERROR 0x50
34#define RAS_CATFAT_ERROR_MASK 0x58
35#define RAS_CATFAT_ERROR 0x60
36#define RAS_ERROR_INJECT 0x68
37#define INJECT_ERROR_MASK GENMASK_ULL(2, 0)
38
39#define ERROR_MASK GENMASK_ULL(63, 0)
40
41static ssize_t pcie0_errors_show(struct device *dev,
42 struct device_attribute *attr, char *buf)
43{
44 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
45 void __iomem *base;
46 u64 value;
47
48 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
49
50 mutex_lock(&pdata->lock);
51 value = readq(base + PCIE0_ERROR);
52 mutex_unlock(&pdata->lock);
53
54 return sprintf(buf, "0x%llx\n", (unsigned long long)value);
55}
56
57static ssize_t pcie0_errors_store(struct device *dev,
58 struct device_attribute *attr,
59 const char *buf, size_t count)
60{
61 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
62 void __iomem *base;
63 int ret = 0;
64 u64 v, val;
65
66 if (kstrtou64(buf, 0, &val))
67 return -EINVAL;
68
69 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
70
71 mutex_lock(&pdata->lock);
72 writeq(GENMASK_ULL(63, 0), base + PCIE0_ERROR_MASK);
73
74 v = readq(base + PCIE0_ERROR);
75 if (val == v)
76 writeq(v, base + PCIE0_ERROR);
77 else
78 ret = -EINVAL;
79
80 writeq(0ULL, base + PCIE0_ERROR_MASK);
81 mutex_unlock(&pdata->lock);
82 return ret ? ret : count;
83}
84static DEVICE_ATTR_RW(pcie0_errors);
85
86static ssize_t pcie1_errors_show(struct device *dev,
87 struct device_attribute *attr, char *buf)
88{
89 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
90 void __iomem *base;
91 u64 value;
92
93 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
94
95 mutex_lock(&pdata->lock);
96 value = readq(base + PCIE1_ERROR);
97 mutex_unlock(&pdata->lock);
98
99 return sprintf(buf, "0x%llx\n", (unsigned long long)value);
100}
101
102static ssize_t pcie1_errors_store(struct device *dev,
103 struct device_attribute *attr,
104 const char *buf, size_t count)
105{
106 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
107 void __iomem *base;
108 int ret = 0;
109 u64 v, val;
110
111 if (kstrtou64(buf, 0, &val))
112 return -EINVAL;
113
114 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
115
116 mutex_lock(&pdata->lock);
117 writeq(GENMASK_ULL(63, 0), base + PCIE1_ERROR_MASK);
118
119 v = readq(base + PCIE1_ERROR);
120 if (val == v)
121 writeq(v, base + PCIE1_ERROR);
122 else
123 ret = -EINVAL;
124
125 writeq(0ULL, base + PCIE1_ERROR_MASK);
126 mutex_unlock(&pdata->lock);
127 return ret ? ret : count;
128}
129static DEVICE_ATTR_RW(pcie1_errors);
130
131static ssize_t nonfatal_errors_show(struct device *dev,
132 struct device_attribute *attr, char *buf)
133{
134 void __iomem *base;
135
136 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
137
138 return sprintf(buf, "0x%llx\n",
139 (unsigned long long)readq(base + RAS_NONFAT_ERROR));
140}
141static DEVICE_ATTR_RO(nonfatal_errors);
142
143static ssize_t catfatal_errors_show(struct device *dev,
144 struct device_attribute *attr, char *buf)
145{
146 void __iomem *base;
147
148 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
149
150 return sprintf(buf, "0x%llx\n",
151 (unsigned long long)readq(base + RAS_CATFAT_ERROR));
152}
153static DEVICE_ATTR_RO(catfatal_errors);
154
155static ssize_t inject_errors_show(struct device *dev,
156 struct device_attribute *attr, char *buf)
157{
158 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
159 void __iomem *base;
160 u64 v;
161
162 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
163
164 mutex_lock(&pdata->lock);
165 v = readq(base + RAS_ERROR_INJECT);
166 mutex_unlock(&pdata->lock);
167
168 return sprintf(buf, "0x%llx\n",
169 (unsigned long long)FIELD_GET(INJECT_ERROR_MASK, v));
170}
171
172static ssize_t inject_errors_store(struct device *dev,
173 struct device_attribute *attr,
174 const char *buf, size_t count)
175{
176 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
177 void __iomem *base;
178 u8 inject_error;
179 u64 v;
180
181 if (kstrtou8(buf, 0, &inject_error))
182 return -EINVAL;
183
184 if (inject_error & ~INJECT_ERROR_MASK)
185 return -EINVAL;
186
187 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
188
189 mutex_lock(&pdata->lock);
190 v = readq(base + RAS_ERROR_INJECT);
191 v &= ~INJECT_ERROR_MASK;
192 v |= FIELD_PREP(INJECT_ERROR_MASK, inject_error);
193 writeq(v, base + RAS_ERROR_INJECT);
194 mutex_unlock(&pdata->lock);
195
196 return count;
197}
198static DEVICE_ATTR_RW(inject_errors);
199
200static ssize_t fme_errors_show(struct device *dev,
201 struct device_attribute *attr, char *buf)
202{
203 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
204 void __iomem *base;
205 u64 value;
206
207 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
208
209 mutex_lock(&pdata->lock);
210 value = readq(base + FME_ERROR);
211 mutex_unlock(&pdata->lock);
212
213 return sprintf(buf, "0x%llx\n", (unsigned long long)value);
214}
215
216static ssize_t fme_errors_store(struct device *dev,
217 struct device_attribute *attr,
218 const char *buf, size_t count)
219{
220 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
221 void __iomem *base;
222 u64 v, val;
223 int ret = 0;
224
225 if (kstrtou64(buf, 0, &val))
226 return -EINVAL;
227
228 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
229
230 mutex_lock(&pdata->lock);
231 writeq(GENMASK_ULL(63, 0), base + FME_ERROR_MASK);
232
233 v = readq(base + FME_ERROR);
234 if (val == v)
235 writeq(v, base + FME_ERROR);
236 else
237 ret = -EINVAL;
238
239 /* Workaround: disable MBP_ERROR if feature revision is 0 */
240 writeq(dfl_feature_revision(base) ? 0ULL : MBP_ERROR,
241 base + FME_ERROR_MASK);
242 mutex_unlock(&pdata->lock);
243 return ret ? ret : count;
244}
245static DEVICE_ATTR_RW(fme_errors);
246
247static ssize_t first_error_show(struct device *dev,
248 struct device_attribute *attr, char *buf)
249{
250 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
251 void __iomem *base;
252 u64 value;
253
254 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
255
256 mutex_lock(&pdata->lock);
257 value = readq(base + FME_FIRST_ERROR);
258 mutex_unlock(&pdata->lock);
259
260 return sprintf(buf, "0x%llx\n", (unsigned long long)value);
261}
262static DEVICE_ATTR_RO(first_error);
263
264static ssize_t next_error_show(struct device *dev,
265 struct device_attribute *attr, char *buf)
266{
267 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
268 void __iomem *base;
269 u64 value;
270
271 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
272
273 mutex_lock(&pdata->lock);
274 value = readq(base + FME_NEXT_ERROR);
275 mutex_unlock(&pdata->lock);
276
277 return sprintf(buf, "0x%llx\n", (unsigned long long)value);
278}
279static DEVICE_ATTR_RO(next_error);
280
281static struct attribute *fme_global_err_attrs[] = {
282 &dev_attr_pcie0_errors.attr,
283 &dev_attr_pcie1_errors.attr,
284 &dev_attr_nonfatal_errors.attr,
285 &dev_attr_catfatal_errors.attr,
286 &dev_attr_inject_errors.attr,
287 &dev_attr_fme_errors.attr,
288 &dev_attr_first_error.attr,
289 &dev_attr_next_error.attr,
290 NULL,
291};
292
293static umode_t fme_global_err_attrs_visible(struct kobject *kobj,
294 struct attribute *attr, int n)
295{
296 struct device *dev = kobj_to_dev(kobj);
297
298 /*
299 * sysfs entries are visible only if related private feature is
300 * enumerated.
301 */
302 if (!dfl_get_feature_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR))
303 return 0;
304
305 return attr->mode;
306}
307
308const struct attribute_group fme_global_err_group = {
309 .name = "errors",
310 .attrs = fme_global_err_attrs,
311 .is_visible = fme_global_err_attrs_visible,
312};
313
314static void fme_err_mask(struct device *dev, bool mask)
315{
316 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
317 void __iomem *base;
318
319 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
320
321 mutex_lock(&pdata->lock);
322
323 /* Workaround: keep MBP_ERROR always masked if revision is 0 */
324 if (dfl_feature_revision(base))
325 writeq(mask ? ERROR_MASK : 0, base + FME_ERROR_MASK);
326 else
327 writeq(mask ? ERROR_MASK : MBP_ERROR, base + FME_ERROR_MASK);
328
329 writeq(mask ? ERROR_MASK : 0, base + PCIE0_ERROR_MASK);
330 writeq(mask ? ERROR_MASK : 0, base + PCIE1_ERROR_MASK);
331 writeq(mask ? ERROR_MASK : 0, base + RAS_NONFAT_ERROR_MASK);
332 writeq(mask ? ERROR_MASK : 0, base + RAS_CATFAT_ERROR_MASK);
333
334 mutex_unlock(&pdata->lock);
335}
336
337static int fme_global_err_init(struct platform_device *pdev,
338 struct dfl_feature *feature)
339{
340 fme_err_mask(&pdev->dev, false);
341
342 return 0;
343}
344
345static void fme_global_err_uinit(struct platform_device *pdev,
346 struct dfl_feature *feature)
347{
348 fme_err_mask(&pdev->dev, true);
349}
350
351const struct dfl_feature_id fme_global_err_id_table[] = {
352 {.id = FME_FEATURE_ID_GLOBAL_ERR,},
353 {0,}
354};
355
356const struct dfl_feature_ops fme_global_err_ops = {
357 .init = fme_global_err_init,
358 .uinit = fme_global_err_uinit,
359};
drivers/fpga/dfl-fme-main.c+15−27
@@ -127,31 +127,10 @@ static struct attribute *fme_hdr_attrs[] = { · 126 unmodified lines
127 &dev_attr_socket_id.attr,127 &dev_attr_socket_id.attr,
128 NULL,128 NULL,
129};129};
130ATTRIBUTE_GROUPS(fme_hdr);
131 130
132static int fme_hdr_init(struct platform_device *pdev,131static const struct attribute_group fme_hdr_group = {
133 struct dfl_feature *feature)132 .attrs = fme_hdr_attrs,
134{133};
135 void __iomem *base = feature->ioaddr;
136 int ret;
137
138 dev_dbg(&pdev->dev, "FME HDR Init.\n");
139 dev_dbg(&pdev->dev, "FME cap %llx.\n",
140 (unsigned long long)readq(base + FME_HDR_CAP));
141
142 ret = device_add_groups(&pdev->dev, fme_hdr_groups);
143 if (ret)
144 return ret;
145
146 return 0;
147}
148
149static void fme_hdr_uinit(struct platform_device *pdev,
150 struct dfl_feature *feature)
151{
152 dev_dbg(&pdev->dev, "FME HDR UInit.\n");
153 device_remove_groups(&pdev->dev, fme_hdr_groups);
154}
155 134
156static long fme_hdr_ioctl_release_port(struct dfl_feature_platform_data *pdata,135static long fme_hdr_ioctl_release_port(struct dfl_feature_platform_data *pdata,
157 unsigned long arg)136 unsigned long arg)
@@ -199,8 +178,6 @@ static const struct dfl_feature_id fme_hdr_id_table[] = { · 41 unmodified lines
199};178};
200 179
201static const struct dfl_feature_ops fme_hdr_ops = {180static const struct dfl_feature_ops fme_hdr_ops = {
202 .init = fme_hdr_init,
203 .uinit = fme_hdr_uinit,
204 .ioctl = fme_hdr_ioctl,181 .ioctl = fme_hdr_ioctl,
205};182};
206 183
@@ -213,6 +190,10 @@ static struct dfl_feature_driver fme_feature_drvs[] = { · 6 unmodified lines
213 .id_table = fme_pr_mgmt_id_table,190 .id_table = fme_pr_mgmt_id_table,
214 .ops = &fme_pr_mgmt_ops,191 .ops = &fme_pr_mgmt_ops,
215 },192 },
193 {
194 .id_table = fme_global_err_id_table,
195 .ops = &fme_global_err_ops,
196 },
216 {197 {
217 .ops = NULL,198 .ops = NULL,
218 },199 },
@@ -359,9 +340,16 @@ static int fme_remove(struct platform_device *pdev) · 140 unmodified lines
359 return 0;340 return 0;
360}341}
361 342
343static const struct attribute_group *fme_dev_groups[] = {
344 &fme_hdr_group,
345 &fme_global_err_group,
346 NULL
347};
348
362static struct platform_driver fme_driver = {349static struct platform_driver fme_driver = {
363 .driver = {350 .driver = {
364 .name = DFL_FPGA_FEATURE_DEV_FME,351 .name = DFL_FPGA_FEATURE_DEV_FME,
352 .dev_groups = fme_dev_groups,
365 },353 },
366 .probe = fme_probe,354 .probe = fme_probe,
367 .remove = fme_remove,355 .remove = fme_remove,
drivers/fpga/dfl-fme.h+3−0
@@ -35,5 +35,8 @@ struct dfl_fme { · 34 unmodified lines
35 35
36extern const struct dfl_feature_ops fme_pr_mgmt_ops;36extern const struct dfl_feature_ops fme_pr_mgmt_ops;
37extern const struct dfl_feature_id fme_pr_mgmt_id_table[];37extern const struct dfl_feature_id fme_pr_mgmt_id_table[];
38extern const struct dfl_feature_ops fme_global_err_ops;
39extern const struct dfl_feature_id fme_global_err_id_table[];
40extern const struct attribute_group fme_global_err_group;
38 41
39#endif /* __DFL_FME_H */42#endif /* __DFL_FME_H */
drivers/fpga/dfl.c+6−4
@@ -271,11 +271,13 @@ static int dfl_feature_instance_init(struct platform_device *pdev, · 270 unmodified lines
271 struct dfl_feature *feature,271 struct dfl_feature *feature,
272 struct dfl_feature_driver *drv)272 struct dfl_feature_driver *drv)
273{273{
274 int ret;274 int ret = 0;
275 275
276 ret = drv->ops->init(pdev, feature);276 if (drv->ops->init) {
277 if (ret)277 ret = drv->ops->init(pdev, feature);
278 return ret;278 if (ret)
279 return ret;
280 }
279 281
280 feature->ops = drv->ops;282 feature->ops = drv->ops;
281 283
drivers/fpga/dfl.h+9−0
@@ -120,6 +120,10 @@ · 119 unmodified lines
120#define PORT_HDR_CAP 0x30120#define PORT_HDR_CAP 0x30
121#define PORT_HDR_CTRL 0x38121#define PORT_HDR_CTRL 0x38
122#define PORT_HDR_STS 0x40122#define PORT_HDR_STS 0x40
123#define PORT_HDR_USRCLK_CMD0 0x50
124#define PORT_HDR_USRCLK_CMD1 0x58
125#define PORT_HDR_USRCLK_STS0 0x60
126#define PORT_HDR_USRCLK_STS1 0x68
123 127
124/* Port Capability Register Bitfield */128/* Port Capability Register Bitfield */
125#define PORT_CAP_PORT_NUM GENMASK_ULL(1, 0) /* ID of this port */129#define PORT_CAP_PORT_NUM GENMASK_ULL(1, 0) /* ID of this port */
@@ -355,6 +359,11 @@ static inline bool dfl_feature_is_port(void __iomem *base) · 229 unmodified lines
355 (FIELD_GET(DFH_ID, v) == DFH_ID_FIU_PORT);359 (FIELD_GET(DFH_ID, v) == DFH_ID_FIU_PORT);
356}360}
357 361
362static inline u8 dfl_feature_revision(void __iomem *base)
363{
364 return (u8)FIELD_GET(DFH_REVISION, readq(base + DFH));
365}
366
358/**367/**
359 * struct dfl_fpga_enum_info - DFL FPGA enumeration information368 * struct dfl_fpga_enum_info - DFL FPGA enumeration information
360 *369 *
include/linux/device.h+3−0
@@ -262,6 +262,8 @@ enum probe_type { · 261 unmodified lines
262 * @resume: Called to bring a device from sleep mode.262 * @resume: Called to bring a device from sleep mode.
263 * @groups: Default attributes that get created by the driver core263 * @groups: Default attributes that get created by the driver core
264 * automatically.264 * automatically.
265 * @dev_groups: Additional attributes attached to device instance once the
266 * it is bound to the driver.
265 * @pm: Power management operations of the device which matched267 * @pm: Power management operations of the device which matched
266 * this driver.268 * this driver.
267 * @coredump: Called when sysfs entry is written to. The device driver269 * @coredump: Called when sysfs entry is written to. The device driver
@@ -296,6 +298,7 @@ struct device_driver { · 28 unmodified lines
296 int (*suspend) (struct device *dev, pm_message_t state);298 int (*suspend) (struct device *dev, pm_message_t state);
297 int (*resume) (struct device *dev);299 int (*resume) (struct device *dev);
298 const struct attribute_group **groups;300 const struct attribute_group **groups;
301 const struct attribute_group **dev_groups;
299 302
300 const struct dev_pm_ops *pm;303 const struct dev_pm_ops *pm;
301 void (*coredump) (struct device *dev);304 void (*coredump) (struct device *dev);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t