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