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
4444 this FPGA belongs to, only valid for integrated solution.
4545 User only needs this information, in case standard numa node
4646 can't provide correct information.
47+
48+What: /sys/bus/platform/devices/dfl-fme.0/errors/pcie0_errors
49+Date: August 2019
50+KernelVersion: 5.4
51+Contact: Wu Hao <hao.wu@intel.com>
52+Description: 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+
57+What: /sys/bus/platform/devices/dfl-fme.0/errors/pcie1_errors
58+Date: August 2019
59+KernelVersion: 5.4
60+Contact: Wu Hao <hao.wu@intel.com>
61+Description: 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+
66+What: /sys/bus/platform/devices/dfl-fme.0/errors/nonfatal_errors
67+Date: August 2019
68+KernelVersion: 5.4
69+Contact: Wu Hao <hao.wu@intel.com>
70+Description: Read-only. It returns non-fatal errors detected.
71+
72+What: /sys/bus/platform/devices/dfl-fme.0/errors/catfatal_errors
73+Date: August 2019
74+KernelVersion: 5.4
75+Contact: Wu Hao <hao.wu@intel.com>
76+Description: Read-only. It returns catastrophic and fatal errors detected.
77+
78+What: /sys/bus/platform/devices/dfl-fme.0/errors/inject_errors
79+Date: August 2019
80+KernelVersion: 5.4
81+Contact: Wu Hao <hao.wu@intel.com>
82+Description: 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+
87+What: /sys/bus/platform/devices/dfl-fme.0/errors/fme_errors
88+Date: August 2019
89+KernelVersion: 5.4
90+Contact: Wu Hao <hao.wu@intel.com>
91+Description: 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+
96+What: /sys/bus/platform/devices/dfl-fme.0/errors/first_error
97+Date: August 2019
98+KernelVersion: 5.4
99+Contact: Wu Hao <hao.wu@intel.com>
100+Description: Read-only. Read this file to get the first error detected by
101+ hardware.
102+
103+What: /sys/bus/platform/devices/dfl-fme.0/errors/next_error
104+Date: August 2019
105+KernelVersion: 5.4
106+Contact: Wu Hao <hao.wu@intel.com>
107+Description: 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
4646 Description: Read-write. Read or set AFU latency tolerance reporting value.
4747 Set ltr to 1 if the AFU can tolerate latency >= 40us or set it
4848 to 0 if it is latency sensitive.
49+
50+What: /sys/bus/platform/devices/dfl-port.0/userclk_freqcmd
51+Date: August 2019
52+KernelVersion: 5.4
53+Contact: Wu Hao <hao.wu@intel.com>
54+Description: Write-only. User writes command to this interface to set
55+ userclock to AFU.
56+
57+What: /sys/bus/platform/devices/dfl-port.0/userclk_freqsts
58+Date: August 2019
59+KernelVersion: 5.4
60+Contact: Wu Hao <hao.wu@intel.com>
61+Description: Read-only. Read this file to get the status of issued command
62+ to userclck_freqcmd.
63+
64+What: /sys/bus/platform/devices/dfl-port.0/userclk_freqcntrcmd
65+Date: August 2019
66+KernelVersion: 5.4
67+Contact: Wu Hao <hao.wu@intel.com>
68+Description: Write-only. User writes command to this interface to set
69+ userclock counter.
70+
71+What: /sys/bus/platform/devices/dfl-port.0/userclk_freqcntrsts
72+Date: August 2019
73+KernelVersion: 5.4
74+Contact: Wu Hao <hao.wu@intel.com>
75+Description: Read-only. Read this file to get the status of issued command
76+ to userclck_freqcntrcmd.
77+
78+What: /sys/bus/platform/devices/dfl-port.0/errors/errors
79+Date: August 2019
80+KernelVersion: 5.4
81+Contact: Wu Hao <hao.wu@intel.com>
82+Description: 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+
89+What: /sys/bus/platform/devices/dfl-port.0/errors/first_error
90+Date: August 2019
91+KernelVersion: 5.4
92+Contact: Wu Hao <hao.wu@intel.com>
93+Description: Read-only. Read this file to get the first error detected by
94+ hardware.
95+
96+What: /sys/bus/platform/devices/dfl-port.0/errors/first_malformed_req
97+Date: August 2019
98+KernelVersion: 5.4
99+Contact: Wu Hao <hao.wu@intel.com>
100+Description: 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
8787 - Get driver API version (DFL_FPGA_GET_API_VERSION)
8888 - Check for extensions (DFL_FPGA_CHECK_EXTENSION)
8989 - 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)
9092
9193 More functions are exposed through sysfs
9294 (/sys/class/fpga_region/regionX/dfl-fme.n/):
@@ -102,6 +104,10 @@ More functions are exposed through sysfs · 9 unmodified lines
102104 one FPGA device may have more than one port, this sysfs interface indicates
103105 how many ports the FPGA device has.
104106
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+
105111
106112 FIU - PORT
107113 ==========
@@ -143,6 +149,10 @@ More functions are exposed through sysfs: · 35 unmodified lines
143149 Read Accelerator GUID (afu_id)
144150 afu_id indicates which PR bitstream is programmed to this AFU.
145151
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+
146156
147157 DFL Framework Overview
148158 ======================
@@ -218,6 +228,101 @@ the compat_id exposed by the target FPGA region. This check is usually done by · 69 unmodified lines
218228 userspace before calling the reconfiguration IOCTL.
219229
220230
231+FPGA virtualization - PCIe SRIOV
232+================================
233+This section describes the virtualization support on DFL based FPGA device to
234+enable 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+
237+Features supported by the particular FPGA device are exposed through Device
238+Feature 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+
261+FME is always accessed through the physical function (PF).
262+
263+Ports (and related AFUs) are accessed via PF by default, but could be exposed
264+through virtual function (VF) devices via PCIe SRIOV. Each VF only contains
265+1 Port and 1 AFU for isolation. Users could assign individual VFs (accelerators)
266+created via PCIe SRIOV interface, to virtual machines.
267+
268+The 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+
292+FPGA PCIe device driver is always loaded first once a FPGA PCIe PF or VF device
293+is 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+
299+The FME device driver plays a management role in this driver architecture, it
300+provides ioctls to release Port from PF and assign Port to PF. After release
301+a port from PF, then it's safe to expose this port through a VF via PCIe SRIOV
302+sysfs interface.
303+
304+To enable accessing an accelerator from applications running in a VM, the
305+respective 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+
323+Note that an FME can't be assigned to a VF, thus PR and other management
324+functions are only available via the PF.
325+
221326 Device enumeration
222327 ==================
223328 This section introduces how applications enumerate the fpga device from
drivers/base/dd.c+14−0
@@ -554,9 +554,16 @@ re_probe: · 553 unmodified lines
554554 goto probe_failed;
555555 }
556556
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+
557562 if (test_remove) {
558563 test_remove = false;
559564
565+ device_remove_groups(dev, drv->dev_groups);
566+
560567 if (dev->bus->remove)
561568 dev->bus->remove(dev);
562569 else if (drv->remove)
@@ -584,6 +591,11 @@ re_probe: · 21 unmodified lines
584591 drv->bus->name, __func__, dev_name(dev), drv->name);
585592 goto done;
586593
594+dev_groups_failed:
595+ if (dev->bus->remove)
596+ dev->bus->remove(dev);
597+ else if (drv->remove)
598+ drv->remove(dev);
587599 probe_failed:
588600 if (dev->bus)
589601 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
11141126
11151127 pm_runtime_put_sync(dev);
11161128
1129+ device_remove_groups(dev, drv->dev_groups);
1130+
11171131 if (dev->bus && dev->bus->remove)
11181132 dev->bus->remove(dev);
11191133 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
3939 obj-$(CONFIG_FPGA_DFL_FME_REGION) += dfl-fme-region.o
4040 obj-$(CONFIG_FPGA_DFL_AFU) += dfl-afu.o
4141
42−dfl-fme-objs := dfl-fme-main.o dfl-fme-pr.o
42+dfl-fme-objs := dfl-fme-main.o dfl-fme-pr.o dfl-fme-error.o
4343 dfl-afu-objs := dfl-afu-main.o dfl-afu-region.o dfl-afu-dma-region.o
44+dfl-afu-objs += dfl-afu-error.o
4445
4546 # Drivers for FPGAs which implement DFL
4647 obj-$(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. */
30+static 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+
39+static 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. */
49+static 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+
107+done:
108+ mutex_unlock(&pdata->lock);
109+ return ret;
110+}
111+
112+static 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+
128+static 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+}
141+static DEVICE_ATTR_RW(errors);
142+
143+static 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+}
158+static DEVICE_ATTR_RO(first_error);
159+
160+static 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+}
178+static DEVICE_ATTR_RO(first_malformed_req);
179+
180+static 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+
187+static 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+
202+const struct attribute_group port_err_group = {
203+ .name = "errors",
204+ .attrs = port_err_attrs,
205+ .is_visible = port_err_attrs_visible,
206+};
207+
208+static 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+
216+static void port_err_uinit(struct platform_device *pdev,
217+ struct dfl_feature *feature)
218+{
219+ afu_port_err_mask(&pdev->dev, true);
220+}
221+
222+const struct dfl_feature_id port_err_id_table[] = {
223+ {.id = PORT_FEATURE_ID_ERROR,},
224+ {0,}
225+};
226+
227+const 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
2222 #include "dfl-afu.h"
2323
2424 /**
25− * port_enable - enable a port
25+ * __afu_port_enable - enable a port by clear reset
2626 * @pdev: port platform device.
2727 *
2828 * Enable Port by clear the port soft reset bit, which is set by default.
2929 * 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.
3134 */
32−static void port_enable(struct platform_device *pdev)
35+void __afu_port_enable(struct platform_device *pdev)
3336 {
3437 struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
3538 void __iomem *base;
@@ -52,13 +55,14 @@ static void port_enable(struct platform_device *pdev) · 16 unmodified lines
5255 #define RST_POLL_TIMEOUT 1000 /* us */
5356
5457 /**
55− * port_disable - disable a port
58+ * __afu_port_disable - disable a port by hold reset
5659 * @pdev: port platform device.
5760 *
58− * Disable Port by setting the port soft reset bit, it puts the port into
59− * reset.
61+ * Disable Port by setting the port soft reset bit, it puts the port into reset.
62+ *
63+ * The caller needs to hold lock for protection.
6064 */
61−static int port_disable(struct platform_device *pdev)
65+int __afu_port_disable(struct platform_device *pdev)
6266 {
6367 struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
6468 void __iomem *base;
@@ -104,9 +108,9 @@ static int __port_reset(struct platform_device *pdev) · 39 unmodified lines
104108 {
105109 int ret;
106110
107− ret = port_disable(pdev);
111+ ret = __afu_port_disable(pdev);
108112 if (!ret)
109− port_enable(pdev);
113+ __afu_port_enable(pdev);
110114
111115 return ret;
112116 }
@@ -274,32 +278,134 @@ power_state_show(struct device *dev, struct device_attribute *attr, char *buf) · 161 unmodified lines
274278 }
275279 static DEVICE_ATTR_RO(power_state);
276280
281+static ssize_t
282+userclk_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+}
300+static DEVICE_ATTR_WO(userclk_freqcmd);
301+
302+static ssize_t
303+userclk_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+}
321+static DEVICE_ATTR_WO(userclk_freqcntrcmd);
322+
323+static ssize_t
324+userclk_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+}
339+static DEVICE_ATTR_RO(userclk_freqsts);
340+
341+static ssize_t
342+userclk_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+}
358+static DEVICE_ATTR_RO(userclk_freqcntrsts);
359+
277360 static struct attribute *port_hdr_attrs[] = {
278361 &dev_attr_id.attr,
279362 &dev_attr_ltr.attr,
280363 &dev_attr_ap1_event.attr,
281364 &dev_attr_ap2_event.attr,
282365 &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,
283370 NULL,
284371 };
285−ATTRIBUTE_GROUPS(port_hdr);
286372
287−static int port_hdr_init(struct platform_device *pdev,
288− struct dfl_feature *feature)
373+static umode_t port_hdr_attrs_visible(struct kobject *kobj,
374+ struct attribute *attr, int n)
289375 {
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;
291379
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+ }
293394
294− return device_add_groups(&pdev->dev, port_hdr_groups);
395+ return mode;
295396 }
296397
297−static void port_hdr_uinit(struct platform_device *pdev,
298− struct dfl_feature *feature)
398+static const struct attribute_group port_hdr_group = {
399+ .attrs = port_hdr_attrs,
400+ .is_visible = port_hdr_attrs_visible,
401+};
402+
403+static int port_hdr_init(struct platform_device *pdev,
404+ struct dfl_feature *feature)
299405 {
300− dev_dbg(&pdev->dev, "PORT HDR UInit.\n");
406+ port_reset(pdev);
301407
302− device_remove_groups(&pdev->dev, port_hdr_groups);
408+ return 0;
303409 }
304410
305411 static long
@@ -330,7 +436,6 @@ static const struct dfl_feature_id port_hdr_id_table[] = { · 24 unmodified lines
330436
331437 static const struct dfl_feature_ops port_hdr_ops = {
332438 .init = port_hdr_init,
333− .uinit = port_hdr_uinit,
334439 .ioctl = port_hdr_ioctl,
335440 };
336441
@@ -361,32 +466,37 @@ static struct attribute *port_afu_attrs[] = { · 24 unmodified lines
361466 &dev_attr_afu_id.attr,
362467 NULL
363468 };
364−ATTRIBUTE_GROUPS(port_afu);
365469
366−static int port_afu_init(struct platform_device *pdev,
367− struct dfl_feature *feature)
470+static umode_t port_afu_attrs_visible(struct kobject *kobj,
471+ struct attribute *attr, int n)
368472 {
369− struct resource *res = &pdev->resource[feature->resource_index];
370− int ret;
473+ struct device *dev = kobj_to_dev(kobj);
371474
372− dev_dbg(&pdev->dev, "PORT AFU Init.\n");
373−
374− ret = afu_mmio_region_add(dev_get_platdata(&pdev->dev),
375− DFL_PORT_REGION_INDEX_AFU, resource_size(res),
376− res->start, DFL_PORT_REGION_READ |
377− DFL_PORT_REGION_WRITE | DFL_PORT_REGION_MMAP);
378− if (ret)
379− return ret;
475+ /*
476+ * sysfs entries are visible only if related private feature is
477+ * enumerated.
478+ */
479+ if (!dfl_get_feature_by_id(dev, PORT_FEATURE_ID_AFU))
480+ return 0;
380481
381− return device_add_groups(&pdev->dev, port_afu_groups);
482+ return attr->mode;
382483 }
383484
384−static void port_afu_uinit(struct platform_device *pdev,
385− struct dfl_feature *feature)
485+static const struct attribute_group port_afu_group = {
486+ .attrs = port_afu_attrs,
487+ .is_visible = port_afu_attrs_visible,
488+};
489+
490+static int port_afu_init(struct platform_device *pdev,
491+ struct dfl_feature *feature)
386492 {
387− dev_dbg(&pdev->dev, "PORT AFU UInit.\n");
493+ struct resource *res = &pdev->resource[feature->resource_index];
388494
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);
390500 }
391501
392502 static 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
396506
397507 static const struct dfl_feature_ops port_afu_ops = {
398508 .init = port_afu_init,
399− .uinit = port_afu_uinit,
509+};
510+
511+static 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+
523+static const struct dfl_feature_id port_stp_id_table[] = {
524+ {.id = PORT_FEATURE_ID_STP,},
525+ {0,}
526+};
527+
528+static const struct dfl_feature_ops port_stp_ops = {
529+ .init = port_stp_init,
400530 };
401531
402532 static struct dfl_feature_driver port_feature_drvs[] = {
@@ -408,6 +538,14 @@ static struct dfl_feature_driver port_feature_drvs[] = { · 5 unmodified lines
408538 .id_table = port_afu_id_table,
409539 .ops = &port_afu_ops,
410540 },
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+ },
411549 {
412550 .ops = NULL,
413551 }
@@ -694,9 +832,9 @@ static int port_enable_set(struct platform_device *pdev, bool enable) · 280 unmodified lines
694832
695833 mutex_lock(&pdata->lock);
696834 if (enable)
697− port_enable(pdev);
835+ __afu_port_enable(pdev);
698836 else
699− ret = port_disable(pdev);
837+ ret = __afu_port_disable(pdev);
700838 mutex_unlock(&pdata->lock);
701839
702840 return ret;
@@ -748,9 +886,17 @@ static int afu_remove(struct platform_device *pdev) · 45 unmodified lines
748886 return 0;
749887 }
750888
889+static const struct attribute_group *afu_dev_groups[] = {
890+ &port_hdr_group,
891+ &port_afu_group,
892+ &port_err_group,
893+ NULL
894+};
895+
751896 static struct platform_driver afu_driver = {
752897 .driver = {
753− .name = DFL_FPGA_FEATURE_DEV_PORT,
898+ .name = DFL_FPGA_FEATURE_DEV_PORT,
899+ .dev_groups = afu_dev_groups,
754900 },
755901 .probe = afu_probe,
756902 .remove = afu_remove,
drivers/fpga/dfl-afu.h+9−0
@@ -79,6 +79,10 @@ struct dfl_afu { · 78 unmodified lines
7979 struct dfl_feature_platform_data *pdata;
8080 };
8181
82+/* hold pdata->lock when call __afu_port_enable/disable */
83+void __afu_port_enable(struct platform_device *pdev);
84+int __afu_port_disable(struct platform_device *pdev);
85+
8286 void afu_mmio_region_init(struct dfl_feature_platform_data *pdata);
8387 int afu_mmio_region_add(struct dfl_feature_platform_data *pdata,
8488 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
97101 struct dfl_afu_dma_region *
98102 afu_dma_region_find(struct dfl_feature_platform_data *pdata,
99103 u64 iova, u64 size);
104+
105+extern const struct dfl_feature_ops port_err_ops;
106+extern const struct dfl_feature_id port_err_id_table[];
107+extern const struct attribute_group port_err_group;
108+
100109 #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+
41+static 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+
57+static 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+}
84+static DEVICE_ATTR_RW(pcie0_errors);
85+
86+static 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+
102+static 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+}
129+static DEVICE_ATTR_RW(pcie1_errors);
130+
131+static 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+}
141+static DEVICE_ATTR_RO(nonfatal_errors);
142+
143+static 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+}
153+static DEVICE_ATTR_RO(catfatal_errors);
154+
155+static 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+
172+static 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+}
198+static DEVICE_ATTR_RW(inject_errors);
199+
200+static 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+
216+static 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+}
245+static DEVICE_ATTR_RW(fme_errors);
246+
247+static 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+}
262+static DEVICE_ATTR_RO(first_error);
263+
264+static 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+}
279+static DEVICE_ATTR_RO(next_error);
280+
281+static 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+
293+static 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+
308+const 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+
314+static 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+
337+static 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+
345+static void fme_global_err_uinit(struct platform_device *pdev,
346+ struct dfl_feature *feature)
347+{
348+ fme_err_mask(&pdev->dev, true);
349+}
350+
351+const struct dfl_feature_id fme_global_err_id_table[] = {
352+ {.id = FME_FEATURE_ID_GLOBAL_ERR,},
353+ {0,}
354+};
355+
356+const 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
127127 &dev_attr_socket_id.attr,
128128 NULL,
129129 };
130−ATTRIBUTE_GROUPS(fme_hdr);
131130
132−static int fme_hdr_init(struct platform_device *pdev,
133− struct dfl_feature *feature)
134−{
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−
149−static 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−}
131+static const struct attribute_group fme_hdr_group = {
132+ .attrs = fme_hdr_attrs,
133+};
155134
156135 static long fme_hdr_ioctl_release_port(struct dfl_feature_platform_data *pdata,
157136 unsigned long arg)
@@ -199,8 +178,6 @@ static const struct dfl_feature_id fme_hdr_id_table[] = { · 41 unmodified lines
199178 };
200179
201180 static const struct dfl_feature_ops fme_hdr_ops = {
202− .init = fme_hdr_init,
203− .uinit = fme_hdr_uinit,
204181 .ioctl = fme_hdr_ioctl,
205182 };
206183
@@ -213,6 +190,10 @@ static struct dfl_feature_driver fme_feature_drvs[] = { · 6 unmodified lines
213190 .id_table = fme_pr_mgmt_id_table,
214191 .ops = &fme_pr_mgmt_ops,
215192 },
193+ {
194+ .id_table = fme_global_err_id_table,
195+ .ops = &fme_global_err_ops,
196+ },
216197 {
217198 .ops = NULL,
218199 },
@@ -359,9 +340,16 @@ static int fme_remove(struct platform_device *pdev) · 140 unmodified lines
359340 return 0;
360341 }
361342
343+static const struct attribute_group *fme_dev_groups[] = {
344+ &fme_hdr_group,
345+ &fme_global_err_group,
346+ NULL
347+};
348+
362349 static struct platform_driver fme_driver = {
363350 .driver = {
364− .name = DFL_FPGA_FEATURE_DEV_FME,
351+ .name = DFL_FPGA_FEATURE_DEV_FME,
352+ .dev_groups = fme_dev_groups,
365353 },
366354 .probe = fme_probe,
367355 .remove = fme_remove,
drivers/fpga/dfl-fme.h+3−0
@@ -35,5 +35,8 @@ struct dfl_fme { · 34 unmodified lines
3535
3636 extern const struct dfl_feature_ops fme_pr_mgmt_ops;
3737 extern const struct dfl_feature_id fme_pr_mgmt_id_table[];
38+extern const struct dfl_feature_ops fme_global_err_ops;
39+extern const struct dfl_feature_id fme_global_err_id_table[];
40+extern const struct attribute_group fme_global_err_group;
3841
3942 #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
271271 struct dfl_feature *feature,
272272 struct dfl_feature_driver *drv)
273273 {
274− int ret;
274+ int ret = 0;
275275
276− ret = drv->ops->init(pdev, feature);
277− if (ret)
278− return ret;
276+ if (drv->ops->init) {
277+ ret = drv->ops->init(pdev, feature);
278+ if (ret)
279+ return ret;
280+ }
279281
280282 feature->ops = drv->ops;
281283
drivers/fpga/dfl.h+9−0
@@ -120,6 +120,10 @@ · 119 unmodified lines
120120 #define PORT_HDR_CAP 0x30
121121 #define PORT_HDR_CTRL 0x38
122122 #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
123127
124128 /* Port Capability Register Bitfield */
125129 #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
355359 (FIELD_GET(DFH_ID, v) == DFH_ID_FIU_PORT);
356360 }
357361
362+static inline u8 dfl_feature_revision(void __iomem *base)
363+{
364+ return (u8)FIELD_GET(DFH_REVISION, readq(base + DFH));
365+}
366+
358367 /**
359368 * struct dfl_fpga_enum_info - DFL FPGA enumeration information
360369 *
include/linux/device.h+3−0
@@ -262,6 +262,8 @@ enum probe_type { · 261 unmodified lines
262262 * @resume: Called to bring a device from sleep mode.
263263 * @groups: Default attributes that get created by the driver core
264264 * automatically.
265+ * @dev_groups: Additional attributes attached to device instance once the
266+ * it is bound to the driver.
265267 * @pm: Power management operations of the device which matched
266268 * this driver.
267269 * @coredump: Called when sysfs entry is written to. The device driver
@@ -296,6 +298,7 @@ struct device_driver { · 28 unmodified lines
296298 int (*suspend) (struct device *dev, pm_message_t state);
297299 int (*resume) (struct device *dev);
298300 const struct attribute_group **groups;
301+ const struct attribute_group **dev_groups;
299302
300303 const struct dev_pm_ops *pm;
301304 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