aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/fpga
diff options
context:
space:
mode:
authorWu Hao <hao.wu@intel.com>2018-06-29 20:53:25 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-07-15 07:55:46 -0400
commitaf275ec6160ba68714371cfe0575f9aa478ce02f (patch)
tree2c968af3bb4db2a5ae83b9e8d44521d32a9029f6 /drivers/fpga
parent29de76240e861d52b75405166337e94184f1875d (diff)
fpga: dfl: add fpga manager platform driver for FME
This patch adds fpga manager driver for FPGA Management Engine (FME). It implements fpga_manager_ops for FPGA Partial Reconfiguration function. Signed-off-by: Tim Whisonant <tim.whisonant@intel.com> Signed-off-by: Enno Luebbers <enno.luebbers@intel.com> Signed-off-by: Shiva Rao <shiva.rao@intel.com> Signed-off-by: Christopher Rauer <christopher.rauer@intel.com> Signed-off-by: Kang Luwei <luwei.kang@intel.com> Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com> Signed-off-by: Wu Hao <hao.wu@intel.com> Acked-by: Alan Tull <atull@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/fpga')
-rw-r--r--drivers/fpga/Kconfig6
-rw-r--r--drivers/fpga/Makefile1
-rw-r--r--drivers/fpga/dfl-fme-mgr.c334
3 files changed, 341 insertions, 0 deletions
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 43803a10cdae..46b48e5164db 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -156,6 +156,12 @@ config FPGA_DFL_FME
156 FPGA platform level management features. There shall be one FME 156 FPGA platform level management features. There shall be one FME
157 per DFL based FPGA device. 157 per DFL based FPGA device.
158 158
159config FPGA_DFL_FME_MGR
160 tristate "FPGA DFL FME Manager Driver"
161 depends on FPGA_DFL_FME && HAS_IOMEM
162 help
163 Say Y to enable FPGA Manager driver for FPGA Management Engine.
164
159config FPGA_DFL_PCI 165config FPGA_DFL_PCI
160 tristate "FPGA DFL PCIe Device Driver" 166 tristate "FPGA DFL PCIe Device Driver"
161 depends on PCI && FPGA_DFL 167 depends on PCI && FPGA_DFL
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index fd334d40aa1c..23f41b02f894 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_OF_FPGA_REGION) += of-fpga-region.o
32# FPGA Device Feature List Support 32# FPGA Device Feature List Support
33obj-$(CONFIG_FPGA_DFL) += dfl.o 33obj-$(CONFIG_FPGA_DFL) += dfl.o
34obj-$(CONFIG_FPGA_DFL_FME) += dfl-fme.o 34obj-$(CONFIG_FPGA_DFL_FME) += dfl-fme.o
35obj-$(CONFIG_FPGA_DFL_FME_MGR) += dfl-fme-mgr.o
35 36
36dfl-fme-objs := dfl-fme-main.o dfl-fme-pr.o 37dfl-fme-objs := dfl-fme-main.o dfl-fme-pr.o
37 38
diff --git a/drivers/fpga/dfl-fme-mgr.c b/drivers/fpga/dfl-fme-mgr.c
new file mode 100644
index 000000000000..df843b51c663
--- /dev/null
+++ b/drivers/fpga/dfl-fme-mgr.c
@@ -0,0 +1,334 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * FPGA Manager Driver for FPGA Management Engine (FME)
4 *
5 * Copyright (C) 2017-2018 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 * Christopher Rauer <christopher.rauer@intel.com>
16 * Henry Mitchel <henry.mitchel@intel.com>
17 */
18
19#include <linux/bitfield.h>
20#include <linux/module.h>
21#include <linux/iopoll.h>
22#include <linux/io-64-nonatomic-lo-hi.h>
23#include <linux/fpga/fpga-mgr.h>
24
25#include "dfl-fme-pr.h"
26
27/* FME Partial Reconfiguration Sub Feature Register Set */
28#define FME_PR_DFH 0x0
29#define FME_PR_CTRL 0x8
30#define FME_PR_STS 0x10
31#define FME_PR_DATA 0x18
32#define FME_PR_ERR 0x20
33#define FME_PR_INTFC_ID_H 0xA8
34#define FME_PR_INTFC_ID_L 0xB0
35
36/* FME PR Control Register Bitfield */
37#define FME_PR_CTRL_PR_RST BIT_ULL(0) /* Reset PR engine */
38#define FME_PR_CTRL_PR_RSTACK BIT_ULL(4) /* Ack for PR engine reset */
39#define FME_PR_CTRL_PR_RGN_ID GENMASK_ULL(9, 7) /* PR Region ID */
40#define FME_PR_CTRL_PR_START BIT_ULL(12) /* Start to request PR service */
41#define FME_PR_CTRL_PR_COMPLETE BIT_ULL(13) /* PR data push completion */
42
43/* FME PR Status Register Bitfield */
44/* Number of available entries in HW queue inside the PR engine. */
45#define FME_PR_STS_PR_CREDIT GENMASK_ULL(8, 0)
46#define FME_PR_STS_PR_STS BIT_ULL(16) /* PR operation status */
47#define FME_PR_STS_PR_STS_IDLE 0
48#define FME_PR_STS_PR_CTRLR_STS GENMASK_ULL(22, 20) /* Controller status */
49#define FME_PR_STS_PR_HOST_STS GENMASK_ULL(27, 24) /* PR host status */
50
51/* FME PR Data Register Bitfield */
52/* PR data from the raw-binary file. */
53#define FME_PR_DATA_PR_DATA_RAW GENMASK_ULL(32, 0)
54
55/* FME PR Error Register */
56/* PR Operation errors detected. */
57#define FME_PR_ERR_OPERATION_ERR BIT_ULL(0)
58/* CRC error detected. */
59#define FME_PR_ERR_CRC_ERR BIT_ULL(1)
60/* Incompatible PR bitstream detected. */
61#define FME_PR_ERR_INCOMPATIBLE_BS BIT_ULL(2)
62/* PR data push protocol violated. */
63#define FME_PR_ERR_PROTOCOL_ERR BIT_ULL(3)
64/* PR data fifo overflow error detected */
65#define FME_PR_ERR_FIFO_OVERFLOW BIT_ULL(4)
66
67#define PR_WAIT_TIMEOUT 8000000
68#define PR_HOST_STATUS_IDLE 0
69
70struct fme_mgr_priv {
71 void __iomem *ioaddr;
72 u64 pr_error;
73};
74
75static u64 pr_error_to_mgr_status(u64 err)
76{
77 u64 status = 0;
78
79 if (err & FME_PR_ERR_OPERATION_ERR)
80 status |= FPGA_MGR_STATUS_OPERATION_ERR;
81 if (err & FME_PR_ERR_CRC_ERR)
82 status |= FPGA_MGR_STATUS_CRC_ERR;
83 if (err & FME_PR_ERR_INCOMPATIBLE_BS)
84 status |= FPGA_MGR_STATUS_INCOMPATIBLE_IMAGE_ERR;
85 if (err & FME_PR_ERR_PROTOCOL_ERR)
86 status |= FPGA_MGR_STATUS_IP_PROTOCOL_ERR;
87 if (err & FME_PR_ERR_FIFO_OVERFLOW)
88 status |= FPGA_MGR_STATUS_FIFO_OVERFLOW_ERR;
89
90 return status;
91}
92
93static u64 fme_mgr_pr_error_handle(void __iomem *fme_pr)
94{
95 u64 pr_status, pr_error;
96
97 pr_status = readq(fme_pr + FME_PR_STS);
98 if (!(pr_status & FME_PR_STS_PR_STS))
99 return 0;
100
101 pr_error = readq(fme_pr + FME_PR_ERR);
102 writeq(pr_error, fme_pr + FME_PR_ERR);
103
104 return pr_error;
105}
106
107static int fme_mgr_write_init(struct fpga_manager *mgr,
108 struct fpga_image_info *info,
109 const char *buf, size_t count)
110{
111 struct device *dev = &mgr->dev;
112 struct fme_mgr_priv *priv = mgr->priv;
113 void __iomem *fme_pr = priv->ioaddr;
114 u64 pr_ctrl, pr_status;
115
116 if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) {
117 dev_err(dev, "only supports partial reconfiguration.\n");
118 return -EINVAL;
119 }
120
121 dev_dbg(dev, "resetting PR before initiated PR\n");
122
123 pr_ctrl = readq(fme_pr + FME_PR_CTRL);
124 pr_ctrl |= FME_PR_CTRL_PR_RST;
125 writeq(pr_ctrl, fme_pr + FME_PR_CTRL);
126
127 if (readq_poll_timeout(fme_pr + FME_PR_CTRL, pr_ctrl,
128 pr_ctrl & FME_PR_CTRL_PR_RSTACK, 1,
129 PR_WAIT_TIMEOUT)) {
130 dev_err(dev, "PR Reset ACK timeout\n");
131 return -ETIMEDOUT;
132 }
133
134 pr_ctrl = readq(fme_pr + FME_PR_CTRL);
135 pr_ctrl &= ~FME_PR_CTRL_PR_RST;
136 writeq(pr_ctrl, fme_pr + FME_PR_CTRL);
137
138 dev_dbg(dev,
139 "waiting for PR resource in HW to be initialized and ready\n");
140
141 if (readq_poll_timeout(fme_pr + FME_PR_STS, pr_status,
142 (pr_status & FME_PR_STS_PR_STS) ==
143 FME_PR_STS_PR_STS_IDLE, 1, PR_WAIT_TIMEOUT)) {
144 dev_err(dev, "PR Status timeout\n");
145 priv->pr_error = fme_mgr_pr_error_handle(fme_pr);
146 return -ETIMEDOUT;
147 }
148
149 dev_dbg(dev, "check and clear previous PR error\n");
150 priv->pr_error = fme_mgr_pr_error_handle(fme_pr);
151 if (priv->pr_error)
152 dev_dbg(dev, "previous PR error detected %llx\n",
153 (unsigned long long)priv->pr_error);
154
155 dev_dbg(dev, "set PR port ID\n");
156
157 pr_ctrl = readq(fme_pr + FME_PR_CTRL);
158 pr_ctrl &= ~FME_PR_CTRL_PR_RGN_ID;
159 pr_ctrl |= FIELD_PREP(FME_PR_CTRL_PR_RGN_ID, info->region_id);
160 writeq(pr_ctrl, fme_pr + FME_PR_CTRL);
161
162 return 0;
163}
164
165static int fme_mgr_write(struct fpga_manager *mgr,
166 const char *buf, size_t count)
167{
168 struct device *dev = &mgr->dev;
169 struct fme_mgr_priv *priv = mgr->priv;
170 void __iomem *fme_pr = priv->ioaddr;
171 u64 pr_ctrl, pr_status, pr_data;
172 int delay = 0, pr_credit, i = 0;
173
174 dev_dbg(dev, "start request\n");
175
176 pr_ctrl = readq(fme_pr + FME_PR_CTRL);
177 pr_ctrl |= FME_PR_CTRL_PR_START;
178 writeq(pr_ctrl, fme_pr + FME_PR_CTRL);
179
180 dev_dbg(dev, "pushing data from bitstream to HW\n");
181
182 /*
183 * driver can push data to PR hardware using PR_DATA register once HW
184 * has enough pr_credit (> 1), pr_credit reduces one for every 32bit
185 * pr data write to PR_DATA register. If pr_credit <= 1, driver needs
186 * to wait for enough pr_credit from hardware by polling.
187 */
188 pr_status = readq(fme_pr + FME_PR_STS);
189 pr_credit = FIELD_GET(FME_PR_STS_PR_CREDIT, pr_status);
190
191 while (count > 0) {
192 while (pr_credit <= 1) {
193 if (delay++ > PR_WAIT_TIMEOUT) {
194 dev_err(dev, "PR_CREDIT timeout\n");
195 return -ETIMEDOUT;
196 }
197 udelay(1);
198
199 pr_status = readq(fme_pr + FME_PR_STS);
200 pr_credit = FIELD_GET(FME_PR_STS_PR_CREDIT, pr_status);
201 }
202
203 if (count < 4) {
204 dev_err(dev, "Invaild PR bitstream size\n");
205 return -EINVAL;
206 }
207
208 pr_data = 0;
209 pr_data |= FIELD_PREP(FME_PR_DATA_PR_DATA_RAW,
210 *(((u32 *)buf) + i));
211 writeq(pr_data, fme_pr + FME_PR_DATA);
212 count -= 4;
213 pr_credit--;
214 i++;
215 }
216
217 return 0;
218}
219
220static int fme_mgr_write_complete(struct fpga_manager *mgr,
221 struct fpga_image_info *info)
222{
223 struct device *dev = &mgr->dev;
224 struct fme_mgr_priv *priv = mgr->priv;
225 void __iomem *fme_pr = priv->ioaddr;
226 u64 pr_ctrl;
227
228 pr_ctrl = readq(fme_pr + FME_PR_CTRL);
229 pr_ctrl |= FME_PR_CTRL_PR_COMPLETE;
230 writeq(pr_ctrl, fme_pr + FME_PR_CTRL);
231
232 dev_dbg(dev, "green bitstream push complete\n");
233 dev_dbg(dev, "waiting for HW to release PR resource\n");
234
235 if (readq_poll_timeout(fme_pr + FME_PR_CTRL, pr_ctrl,
236 !(pr_ctrl & FME_PR_CTRL_PR_START), 1,
237 PR_WAIT_TIMEOUT)) {
238 dev_err(dev, "PR Completion ACK timeout.\n");
239 return -ETIMEDOUT;
240 }
241
242 dev_dbg(dev, "PR operation complete, checking status\n");
243 priv->pr_error = fme_mgr_pr_error_handle(fme_pr);
244 if (priv->pr_error) {
245 dev_dbg(dev, "PR error detected %llx\n",
246 (unsigned long long)priv->pr_error);
247 return -EIO;
248 }
249
250 dev_dbg(dev, "PR done successfully\n");
251
252 return 0;
253}
254
255static enum fpga_mgr_states fme_mgr_state(struct fpga_manager *mgr)
256{
257 return FPGA_MGR_STATE_UNKNOWN;
258}
259
260static u64 fme_mgr_status(struct fpga_manager *mgr)
261{
262 struct fme_mgr_priv *priv = mgr->priv;
263
264 return pr_error_to_mgr_status(priv->pr_error);
265}
266
267static const struct fpga_manager_ops fme_mgr_ops = {
268 .write_init = fme_mgr_write_init,
269 .write = fme_mgr_write,
270 .write_complete = fme_mgr_write_complete,
271 .state = fme_mgr_state,
272 .status = fme_mgr_status,
273};
274
275static int fme_mgr_probe(struct platform_device *pdev)
276{
277 struct dfl_fme_mgr_pdata *pdata = dev_get_platdata(&pdev->dev);
278 struct device *dev = &pdev->dev;
279 struct fme_mgr_priv *priv;
280 struct fpga_manager *mgr;
281 struct resource *res;
282 int ret;
283
284 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
285 if (!priv)
286 return -ENOMEM;
287
288 if (pdata->ioaddr)
289 priv->ioaddr = pdata->ioaddr;
290
291 if (!priv->ioaddr) {
292 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
293 priv->ioaddr = devm_ioremap_resource(dev, res);
294 if (IS_ERR(priv->ioaddr))
295 return PTR_ERR(priv->ioaddr);
296 }
297
298 mgr = fpga_mgr_create(dev, "DFL FME FPGA Manager",
299 &fme_mgr_ops, priv);
300 if (!mgr)
301 return -ENOMEM;
302
303 platform_set_drvdata(pdev, mgr);
304
305 ret = fpga_mgr_register(mgr);
306 if (ret)
307 fpga_mgr_free(mgr);
308
309 return ret;
310}
311
312static int fme_mgr_remove(struct platform_device *pdev)
313{
314 struct fpga_manager *mgr = platform_get_drvdata(pdev);
315
316 fpga_mgr_unregister(mgr);
317
318 return 0;
319}
320
321static struct platform_driver fme_mgr_driver = {
322 .driver = {
323 .name = DFL_FPGA_FME_MGR,
324 },
325 .probe = fme_mgr_probe,
326 .remove = fme_mgr_remove,
327};
328
329module_platform_driver(fme_mgr_driver);
330
331MODULE_DESCRIPTION("FPGA Manager for DFL FPGA Management Engine");
332MODULE_AUTHOR("Intel Corporation");
333MODULE_LICENSE("GPL v2");
334MODULE_ALIAS("platform:dfl-fme-mgr");