summaryrefslogtreecommitdiffstats
path: root/drivers/fpga
diff options
context:
space:
mode:
authorAlan Tull <atull@kernel.org>2018-11-13 13:14:04 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-11-26 14:15:07 -0500
commite7eef1d7633a875977705d203e6f651893582374 (patch)
treee6229194b255086ac5db40b9d342278c9ed50fde /drivers/fpga
parent919d1100370c0bcfa05570113751cd5366822318 (diff)
fpga: add intel stratix10 soc fpga manager driver
Add driver for reconfiguring Intel Stratix10 SoC FPGA devices. This driver communicates through the Intel service layer driver which does communication with privileged hardware (that does the FPGA programming) through a secure mailbox. Signed-off-by: Alan Tull <atull@kernel.org> Signed-off-by: Richard Gong <richard.gong@intel.com> Acked-by: Moritz Fischer <mdf@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/stratix10-soc.c535
3 files changed, 542 insertions, 0 deletions
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 1ebcef4bab5b..0bb7b5cd6cdc 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -56,6 +56,12 @@ config FPGA_MGR_ZYNQ_FPGA
56 help 56 help
57 FPGA manager driver support for Xilinx Zynq FPGAs. 57 FPGA manager driver support for Xilinx Zynq FPGAs.
58 58
59config FPGA_MGR_STRATIX10_SOC
60 tristate "Intel Stratix10 SoC FPGA Manager"
61 depends on (ARCH_STRATIX10 && INTEL_STRATIX10_SERVICE)
62 help
63 FPGA manager driver support for the Intel Stratix10 SoC.
64
59config FPGA_MGR_XILINX_SPI 65config FPGA_MGR_XILINX_SPI
60 tristate "Xilinx Configuration over Slave Serial (SPI)" 66 tristate "Xilinx Configuration over Slave Serial (SPI)"
61 depends on SPI 67 depends on SPI
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 7a2d73ba7122..c0dd4c82fbdb 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_FPGA_MGR_ICE40_SPI) += ice40-spi.o
13obj-$(CONFIG_FPGA_MGR_MACHXO2_SPI) += machxo2-spi.o 13obj-$(CONFIG_FPGA_MGR_MACHXO2_SPI) += machxo2-spi.o
14obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o 14obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o
15obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o 15obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o
16obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC) += stratix10-soc.o
16obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o 17obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o
17obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o 18obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o
18obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o 19obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o
diff --git a/drivers/fpga/stratix10-soc.c b/drivers/fpga/stratix10-soc.c
new file mode 100644
index 000000000000..a1a09e04fab8
--- /dev/null
+++ b/drivers/fpga/stratix10-soc.c
@@ -0,0 +1,535 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * FPGA Manager Driver for Intel Stratix10 SoC
4 *
5 * Copyright (C) 2018 Intel Corporation
6 */
7#include <linux/completion.h>
8#include <linux/fpga/fpga-mgr.h>
9#include <linux/firmware/intel/stratix10-svc-client.h>
10#include <linux/module.h>
11#include <linux/of.h>
12#include <linux/of_platform.h>
13
14/*
15 * FPGA programming requires a higher level of privilege (EL3), per the SoC
16 * design.
17 */
18#define NUM_SVC_BUFS 4
19#define SVC_BUF_SIZE SZ_512K
20
21/* Indicates buffer is in use if set */
22#define SVC_BUF_LOCK 0
23
24#define S10_BUFFER_TIMEOUT (msecs_to_jiffies(SVC_RECONFIG_BUFFER_TIMEOUT_MS))
25#define S10_RECONFIG_TIMEOUT (msecs_to_jiffies(SVC_RECONFIG_REQUEST_TIMEOUT_MS))
26
27/*
28 * struct s10_svc_buf
29 * buf: virtual address of buf provided by service layer
30 * lock: locked if buffer is in use
31 */
32struct s10_svc_buf {
33 char *buf;
34 unsigned long lock;
35};
36
37struct s10_priv {
38 struct stratix10_svc_chan *chan;
39 struct stratix10_svc_client client;
40 struct completion status_return_completion;
41 struct s10_svc_buf svc_bufs[NUM_SVC_BUFS];
42 unsigned long status;
43};
44
45static int s10_svc_send_msg(struct s10_priv *priv,
46 enum stratix10_svc_command_code command,
47 void *payload, u32 payload_length)
48{
49 struct stratix10_svc_chan *chan = priv->chan;
50 struct device *dev = priv->client.dev;
51 struct stratix10_svc_client_msg msg;
52 int ret;
53
54 dev_dbg(dev, "%s cmd=%d payload=%p length=%d\n",
55 __func__, command, payload, payload_length);
56
57 msg.command = command;
58 msg.payload = payload;
59 msg.payload_length = payload_length;
60
61 ret = stratix10_svc_send(chan, &msg);
62 dev_dbg(dev, "stratix10_svc_send returned status %d\n", ret);
63
64 return ret;
65}
66
67/*
68 * Free buffers allocated from the service layer's pool that are not in use.
69 * Return true when all buffers are freed.
70 */
71static bool s10_free_buffers(struct fpga_manager *mgr)
72{
73 struct s10_priv *priv = mgr->priv;
74 uint num_free = 0;
75 uint i;
76
77 for (i = 0; i < NUM_SVC_BUFS; i++) {
78 if (!priv->svc_bufs[i].buf) {
79 num_free++;
80 continue;
81 }
82
83 if (!test_and_set_bit_lock(SVC_BUF_LOCK,
84 &priv->svc_bufs[i].lock)) {
85 stratix10_svc_free_memory(priv->chan,
86 priv->svc_bufs[i].buf);
87 priv->svc_bufs[i].buf = NULL;
88 num_free++;
89 }
90 }
91
92 return num_free == NUM_SVC_BUFS;
93}
94
95/*
96 * Returns count of how many buffers are not in use.
97 */
98static uint s10_free_buffer_count(struct fpga_manager *mgr)
99{
100 struct s10_priv *priv = mgr->priv;
101 uint num_free = 0;
102 uint i;
103
104 for (i = 0; i < NUM_SVC_BUFS; i++)
105 if (!priv->svc_bufs[i].buf)
106 num_free++;
107
108 return num_free;
109}
110
111/*
112 * s10_unlock_bufs
113 * Given the returned buffer address, match that address to our buffer struct
114 * and unlock that buffer. This marks it as available to be refilled and sent
115 * (or freed).
116 * priv: private data
117 * kaddr: kernel address of buffer that was returned from service layer
118 */
119static void s10_unlock_bufs(struct s10_priv *priv, void *kaddr)
120{
121 uint i;
122
123 if (!kaddr)
124 return;
125
126 for (i = 0; i < NUM_SVC_BUFS; i++)
127 if (priv->svc_bufs[i].buf == kaddr) {
128 clear_bit_unlock(SVC_BUF_LOCK,
129 &priv->svc_bufs[i].lock);
130 return;
131 }
132
133 WARN(1, "Unknown buffer returned from service layer %p\n", kaddr);
134}
135
136/*
137 * s10_receive_callback - callback for service layer to use to provide client
138 * (this driver) messages received through the mailbox.
139 * client: service layer client struct
140 * data: message from service layer
141 */
142static void s10_receive_callback(struct stratix10_svc_client *client,
143 struct stratix10_svc_cb_data *data)
144{
145 struct s10_priv *priv = client->priv;
146 u32 status;
147 int i;
148
149 WARN_ONCE(!data, "%s: stratix10_svc_rc_data = NULL", __func__);
150
151 status = data->status;
152
153 /*
154 * Here we set status bits as we receive them. Elsewhere, we always use
155 * test_and_clear_bit() to check status in priv->status
156 */
157 for (i = 0; i <= SVC_STATUS_RECONFIG_ERROR; i++)
158 if (status & (1 << i))
159 set_bit(i, &priv->status);
160
161 if (status & BIT(SVC_STATUS_RECONFIG_BUFFER_DONE)) {
162 s10_unlock_bufs(priv, data->kaddr1);
163 s10_unlock_bufs(priv, data->kaddr2);
164 s10_unlock_bufs(priv, data->kaddr3);
165 }
166
167 complete(&priv->status_return_completion);
168}
169
170/*
171 * s10_ops_write_init - prepare for FPGA reconfiguration by requesting
172 * partial reconfig and allocating buffers from the service layer.
173 */
174static int s10_ops_write_init(struct fpga_manager *mgr,
175 struct fpga_image_info *info,
176 const char *buf, size_t count)
177{
178 struct s10_priv *priv = mgr->priv;
179 struct device *dev = priv->client.dev;
180 struct stratix10_svc_command_config_type ctype;
181 char *kbuf;
182 uint i;
183 int ret;
184
185 ctype.flags = 0;
186 if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
187 dev_dbg(dev, "Requesting partial reconfiguration.\n");
188 ctype.flags |= BIT(COMMAND_RECONFIG_FLAG_PARTIAL);
189 } else {
190 dev_dbg(dev, "Requesting full reconfiguration.\n");
191 }
192
193 reinit_completion(&priv->status_return_completion);
194 ret = s10_svc_send_msg(priv, COMMAND_RECONFIG,
195 &ctype, sizeof(ctype));
196 if (ret < 0)
197 goto init_done;
198
199 ret = wait_for_completion_interruptible_timeout(
200 &priv->status_return_completion, S10_RECONFIG_TIMEOUT);
201 if (!ret) {
202 dev_err(dev, "timeout waiting for RECONFIG_REQUEST\n");
203 ret = -ETIMEDOUT;
204 goto init_done;
205 }
206 if (ret < 0) {
207 dev_err(dev, "error (%d) waiting for RECONFIG_REQUEST\n", ret);
208 goto init_done;
209 }
210
211 ret = 0;
212 if (!test_and_clear_bit(SVC_STATUS_RECONFIG_REQUEST_OK,
213 &priv->status)) {
214 ret = -ETIMEDOUT;
215 goto init_done;
216 }
217
218 /* Allocate buffers from the service layer's pool. */
219 for (i = 0; i < NUM_SVC_BUFS; i++) {
220 kbuf = stratix10_svc_allocate_memory(priv->chan, SVC_BUF_SIZE);
221 if (!kbuf) {
222 s10_free_buffers(mgr);
223 ret = -ENOMEM;
224 goto init_done;
225 }
226
227 priv->svc_bufs[i].buf = kbuf;
228 priv->svc_bufs[i].lock = 0;
229 }
230
231init_done:
232 stratix10_svc_done(priv->chan);
233 return ret;
234}
235
236/*
237 * s10_send_buf - send a buffer to the service layer queue
238 * mgr: fpga manager struct
239 * buf: fpga image buffer
240 * count: size of buf in bytes
241 * Returns # of bytes transferred or -ENOBUFS if the all the buffers are in use
242 * or if the service queue is full. Never returns 0.
243 */
244static int s10_send_buf(struct fpga_manager *mgr, const char *buf, size_t count)
245{
246 struct s10_priv *priv = mgr->priv;
247 struct device *dev = priv->client.dev;
248 void *svc_buf;
249 size_t xfer_sz;
250 int ret;
251 uint i;
252
253 /* get/lock a buffer that that's not being used */
254 for (i = 0; i < NUM_SVC_BUFS; i++)
255 if (!test_and_set_bit_lock(SVC_BUF_LOCK,
256 &priv->svc_bufs[i].lock))
257 break;
258
259 if (i == NUM_SVC_BUFS)
260 return -ENOBUFS;
261
262 xfer_sz = count < SVC_BUF_SIZE ? count : SVC_BUF_SIZE;
263
264 svc_buf = priv->svc_bufs[i].buf;
265 memcpy(svc_buf, buf, xfer_sz);
266 ret = s10_svc_send_msg(priv, COMMAND_RECONFIG_DATA_SUBMIT,
267 svc_buf, xfer_sz);
268 if (ret < 0) {
269 dev_err(dev,
270 "Error while sending data to service layer (%d)", ret);
271 clear_bit_unlock(SVC_BUF_LOCK, &priv->svc_bufs[i].lock);
272 return ret;
273 }
274
275 return xfer_sz;
276}
277
278/*
279 * Send a FPGA image to privileged layers to write to the FPGA. When done
280 * sending, free all service layer buffers we allocated in write_init.
281 */
282static int s10_ops_write(struct fpga_manager *mgr, const char *buf,
283 size_t count)
284{
285 struct s10_priv *priv = mgr->priv;
286 struct device *dev = priv->client.dev;
287 long wait_status;
288 int sent = 0;
289 int ret = 0;
290
291 /*
292 * Loop waiting for buffers to be returned. When a buffer is returned,
293 * reuse it to send more data or free if if all data has been sent.
294 */
295 while (count > 0 || s10_free_buffer_count(mgr) != NUM_SVC_BUFS) {
296 reinit_completion(&priv->status_return_completion);
297
298 if (count > 0) {
299 sent = s10_send_buf(mgr, buf, count);
300 if (sent < 0)
301 continue;
302
303 count -= sent;
304 buf += sent;
305 } else {
306 if (s10_free_buffers(mgr))
307 return 0;
308
309 ret = s10_svc_send_msg(
310 priv, COMMAND_RECONFIG_DATA_CLAIM,
311 NULL, 0);
312 if (ret < 0)
313 break;
314 }
315
316 /*
317 * If callback hasn't already happened, wait for buffers to be
318 * returned from service layer
319 */
320 wait_status = 1; /* not timed out */
321 if (!priv->status)
322 wait_status = wait_for_completion_interruptible_timeout(
323 &priv->status_return_completion,
324 S10_BUFFER_TIMEOUT);
325
326 if (test_and_clear_bit(SVC_STATUS_RECONFIG_BUFFER_DONE,
327 &priv->status) ||
328 test_and_clear_bit(SVC_STATUS_RECONFIG_BUFFER_SUBMITTED,
329 &priv->status)) {
330 ret = 0;
331 continue;
332 }
333
334 if (test_and_clear_bit(SVC_STATUS_RECONFIG_ERROR,
335 &priv->status)) {
336 dev_err(dev, "ERROR - giving up - SVC_STATUS_RECONFIG_ERROR\n");
337 ret = -EFAULT;
338 break;
339 }
340
341 if (!wait_status) {
342 dev_err(dev, "timeout waiting for svc layer buffers\n");
343 ret = -ETIMEDOUT;
344 break;
345 }
346 if (wait_status < 0) {
347 ret = wait_status;
348 dev_err(dev,
349 "error (%d) waiting for svc layer buffers\n",
350 ret);
351 break;
352 }
353 }
354
355 if (!s10_free_buffers(mgr))
356 dev_err(dev, "%s not all buffers were freed\n", __func__);
357
358 return ret;
359}
360
361static int s10_ops_write_complete(struct fpga_manager *mgr,
362 struct fpga_image_info *info)
363{
364 struct s10_priv *priv = mgr->priv;
365 struct device *dev = priv->client.dev;
366 unsigned long timeout;
367 int ret;
368
369 timeout = usecs_to_jiffies(info->config_complete_timeout_us);
370
371 do {
372 reinit_completion(&priv->status_return_completion);
373
374 ret = s10_svc_send_msg(priv, COMMAND_RECONFIG_STATUS, NULL, 0);
375 if (ret < 0)
376 break;
377
378 ret = wait_for_completion_interruptible_timeout(
379 &priv->status_return_completion, timeout);
380 if (!ret) {
381 dev_err(dev,
382 "timeout waiting for RECONFIG_COMPLETED\n");
383 ret = -ETIMEDOUT;
384 break;
385 }
386 if (ret < 0) {
387 dev_err(dev,
388 "error (%d) waiting for RECONFIG_COMPLETED\n",
389 ret);
390 break;
391 }
392 /* Not error or timeout, so ret is # of jiffies until timeout */
393 timeout = ret;
394 ret = 0;
395
396 if (test_and_clear_bit(SVC_STATUS_RECONFIG_COMPLETED,
397 &priv->status))
398 break;
399
400 if (test_and_clear_bit(SVC_STATUS_RECONFIG_ERROR,
401 &priv->status)) {
402 dev_err(dev, "ERROR - giving up - SVC_STATUS_RECONFIG_ERROR\n");
403 ret = -EFAULT;
404 break;
405 }
406 } while (1);
407
408 stratix10_svc_done(priv->chan);
409
410 return ret;
411}
412
413static enum fpga_mgr_states s10_ops_state(struct fpga_manager *mgr)
414{
415 return FPGA_MGR_STATE_UNKNOWN;
416}
417
418static const struct fpga_manager_ops s10_ops = {
419 .state = s10_ops_state,
420 .write_init = s10_ops_write_init,
421 .write = s10_ops_write,
422 .write_complete = s10_ops_write_complete,
423};
424
425static int s10_probe(struct platform_device *pdev)
426{
427 struct device *dev = &pdev->dev;
428 struct s10_priv *priv;
429 struct fpga_manager *mgr;
430 int ret;
431
432 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
433 if (!priv)
434 return -ENOMEM;
435
436 priv->client.dev = dev;
437 priv->client.receive_cb = s10_receive_callback;
438 priv->client.priv = priv;
439
440 priv->chan = stratix10_svc_request_channel_byname(&priv->client,
441 SVC_CLIENT_FPGA);
442 if (IS_ERR(priv->chan)) {
443 dev_err(dev, "couldn't get service channel (%s)\n",
444 SVC_CLIENT_FPGA);
445 return PTR_ERR(priv->chan);
446 }
447
448 init_completion(&priv->status_return_completion);
449
450 mgr = fpga_mgr_create(dev, "Stratix10 SOC FPGA Manager",
451 &s10_ops, priv);
452 if (!mgr) {
453 dev_err(dev, "unable to create FPGA manager\n");
454 ret = -ENOMEM;
455 goto probe_err;
456 }
457
458 ret = fpga_mgr_register(mgr);
459 if (ret) {
460 dev_err(dev, "unable to register FPGA manager\n");
461 fpga_mgr_free(mgr);
462 goto probe_err;
463 }
464
465 platform_set_drvdata(pdev, mgr);
466 return ret;
467
468probe_err:
469 stratix10_svc_free_channel(priv->chan);
470 return ret;
471}
472
473static int s10_remove(struct platform_device *pdev)
474{
475 struct fpga_manager *mgr = platform_get_drvdata(pdev);
476 struct s10_priv *priv = mgr->priv;
477
478 fpga_mgr_unregister(mgr);
479 stratix10_svc_free_channel(priv->chan);
480
481 return 0;
482}
483
484static const struct of_device_id s10_of_match[] = {
485 { .compatible = "intel,stratix10-soc-fpga-mgr", },
486 {},
487};
488
489MODULE_DEVICE_TABLE(of, s10_of_match);
490
491static struct platform_driver s10_driver = {
492 .probe = s10_probe,
493 .remove = s10_remove,
494 .driver = {
495 .name = "Stratix10 SoC FPGA manager",
496 .of_match_table = of_match_ptr(s10_of_match),
497 },
498};
499
500static int __init s10_init(void)
501{
502 struct device_node *fw_np;
503 struct device_node *np;
504 int ret;
505
506 fw_np = of_find_node_by_name(NULL, "svc");
507 if (!fw_np)
508 return -ENODEV;
509
510 np = of_find_matching_node(fw_np, s10_of_match);
511 if (!np) {
512 of_node_put(fw_np);
513 return -ENODEV;
514 }
515
516 of_node_put(np);
517 ret = of_platform_populate(fw_np, s10_of_match, NULL, NULL);
518 of_node_put(fw_np);
519 if (ret)
520 return ret;
521
522 return platform_driver_register(&s10_driver);
523}
524
525static void __exit s10_exit(void)
526{
527 return platform_driver_unregister(&s10_driver);
528}
529
530module_init(s10_init);
531module_exit(s10_exit);
532
533MODULE_AUTHOR("Alan Tull <atull@kernel.org>");
534MODULE_DESCRIPTION("Intel Stratix 10 SOC FPGA Manager");
535MODULE_LICENSE("GPL v2");