diff options
-rw-r--r-- | drivers/firmware/Kconfig | 12 | ||||
-rw-r--r-- | drivers/firmware/Makefile | 1 | ||||
-rw-r--r-- | drivers/firmware/stratix10-svc.c | 1013 | ||||
-rw-r--r-- | include/linux/firmware/intel/stratix10-smc.h | 265 | ||||
-rw-r--r-- | include/linux/firmware/intel/stratix10-svc-client.h | 201 |
5 files changed, 1492 insertions, 0 deletions
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 7273e5082b41..f754578414f0 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig | |||
@@ -216,6 +216,18 @@ config FW_CFG_SYSFS_CMDLINE | |||
216 | WARNING: Using incorrect parameters (base address in particular) | 216 | WARNING: Using incorrect parameters (base address in particular) |
217 | may crash your system. | 217 | may crash your system. |
218 | 218 | ||
219 | config INTEL_STRATIX10_SERVICE | ||
220 | tristate "Intel Stratix10 Service Layer" | ||
221 | depends on HAVE_ARM_SMCCC | ||
222 | default n | ||
223 | help | ||
224 | Intel Stratix10 service layer runs at privileged exception level, | ||
225 | interfaces with the service providers (FPGA manager is one of them) | ||
226 | and manages secure monitor call to communicate with secure monitor | ||
227 | software at secure monitor exception level. | ||
228 | |||
229 | Say Y here if you want Stratix10 service layer support. | ||
230 | |||
219 | config QCOM_SCM | 231 | config QCOM_SCM |
220 | bool | 232 | bool |
221 | depends on ARM || ARM64 | 233 | depends on ARM || ARM64 |
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 3158dffd9914..80feb635120f 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile | |||
@@ -12,6 +12,7 @@ obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o | |||
12 | obj-$(CONFIG_EDD) += edd.o | 12 | obj-$(CONFIG_EDD) += edd.o |
13 | obj-$(CONFIG_EFI_PCDP) += pcdp.o | 13 | obj-$(CONFIG_EFI_PCDP) += pcdp.o |
14 | obj-$(CONFIG_DMIID) += dmi-id.o | 14 | obj-$(CONFIG_DMIID) += dmi-id.o |
15 | obj-$(CONFIG_INTEL_STRATIX10_SERVICE) += stratix10-svc.o | ||
15 | obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o | 16 | obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o |
16 | obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o | 17 | obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o |
17 | obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o | 18 | obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o |
diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c new file mode 100644 index 000000000000..168f52314963 --- /dev/null +++ b/drivers/firmware/stratix10-svc.c | |||
@@ -0,0 +1,1013 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Copyright (C) 2017-2018, Intel Corporation | ||
4 | */ | ||
5 | |||
6 | #include <linux/completion.h> | ||
7 | #include <linux/delay.h> | ||
8 | #include <linux/genalloc.h> | ||
9 | #include <linux/io.h> | ||
10 | #include <linux/kfifo.h> | ||
11 | #include <linux/kthread.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/mutex.h> | ||
14 | #include <linux/of.h> | ||
15 | #include <linux/of_platform.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include <linux/firmware/intel/stratix10-smc.h> | ||
20 | #include <linux/firmware/intel/stratix10-svc-client.h> | ||
21 | #include <linux/types.h> | ||
22 | |||
23 | /** | ||
24 | * SVC_NUM_DATA_IN_FIFO - number of struct stratix10_svc_data in the FIFO | ||
25 | * | ||
26 | * SVC_NUM_CHANNEL - number of channel supported by service layer driver | ||
27 | * | ||
28 | * FPGA_CONFIG_DATA_CLAIM_TIMEOUT_MS - claim back the submitted buffer(s) | ||
29 | * from the secure world for FPGA manager to reuse, or to free the buffer(s) | ||
30 | * when all bit-stream data had be send. | ||
31 | * | ||
32 | * FPGA_CONFIG_STATUS_TIMEOUT_SEC - poll the FPGA configuration status, | ||
33 | * service layer will return error to FPGA manager when timeout occurs, | ||
34 | * timeout is set to 30 seconds (30 * 1000) at Intel Stratix10 SoC. | ||
35 | */ | ||
36 | #define SVC_NUM_DATA_IN_FIFO 32 | ||
37 | #define SVC_NUM_CHANNEL 1 | ||
38 | #define FPGA_CONFIG_DATA_CLAIM_TIMEOUT_MS 200 | ||
39 | #define FPGA_CONFIG_STATUS_TIMEOUT_SEC 30 | ||
40 | |||
41 | typedef void (svc_invoke_fn)(unsigned long, unsigned long, unsigned long, | ||
42 | unsigned long, unsigned long, unsigned long, | ||
43 | unsigned long, unsigned long, | ||
44 | struct arm_smccc_res *); | ||
45 | struct stratix10_svc_chan; | ||
46 | |||
47 | /** | ||
48 | * struct stratix10_svc_sh_memory - service shared memory structure | ||
49 | * @sync_complete: state for a completion | ||
50 | * @addr: physical address of shared memory block | ||
51 | * @size: size of shared memory block | ||
52 | * @invoke_fn: function to issue secure monitor or hypervisor call | ||
53 | * | ||
54 | * This struct is used to save physical address and size of shared memory | ||
55 | * block. The shared memory blocked is allocated by secure monitor software | ||
56 | * at secure world. | ||
57 | * | ||
58 | * Service layer driver uses the physical address and size to create a memory | ||
59 | * pool, then allocates data buffer from that memory pool for service client. | ||
60 | */ | ||
61 | struct stratix10_svc_sh_memory { | ||
62 | struct completion sync_complete; | ||
63 | unsigned long addr; | ||
64 | unsigned long size; | ||
65 | svc_invoke_fn *invoke_fn; | ||
66 | }; | ||
67 | |||
68 | /** | ||
69 | * struct stratix10_svc_data_mem - service memory structure | ||
70 | * @vaddr: virtual address | ||
71 | * @paddr: physical address | ||
72 | * @size: size of memory | ||
73 | * @node: link list head node | ||
74 | * | ||
75 | * This struct is used in a list that keeps track of buffers which have | ||
76 | * been allocated or freed from the memory pool. Service layer driver also | ||
77 | * uses this struct to transfer physical address to virtual address. | ||
78 | */ | ||
79 | struct stratix10_svc_data_mem { | ||
80 | void *vaddr; | ||
81 | phys_addr_t paddr; | ||
82 | size_t size; | ||
83 | struct list_head node; | ||
84 | }; | ||
85 | |||
86 | /** | ||
87 | * struct stratix10_svc_data - service data structure | ||
88 | * @chan: service channel | ||
89 | * @paddr: playload physical address | ||
90 | * @size: playload size | ||
91 | * @command: service command requested by client | ||
92 | * @flag: configuration type (full or partial) | ||
93 | * @arg: args to be passed via registers and not physically mapped buffers | ||
94 | * | ||
95 | * This struct is used in service FIFO for inter-process communication. | ||
96 | */ | ||
97 | struct stratix10_svc_data { | ||
98 | struct stratix10_svc_chan *chan; | ||
99 | phys_addr_t paddr; | ||
100 | size_t size; | ||
101 | u32 command; | ||
102 | u32 flag; | ||
103 | u64 arg[3]; | ||
104 | }; | ||
105 | |||
106 | /** | ||
107 | * struct stratix10_svc_controller - service controller | ||
108 | * @dev: device | ||
109 | * @chans: array of service channels | ||
110 | * @num_chans: number of channels in 'chans' array | ||
111 | * @num_active_client: number of active service client | ||
112 | * @node: list management | ||
113 | * @genpool: memory pool pointing to the memory region | ||
114 | * @task: pointer to the thread task which handles SMC or HVC call | ||
115 | * @svc_fifo: a queue for storing service message data | ||
116 | * @complete_status: state for completion | ||
117 | * @svc_fifo_lock: protect access to service message data queue | ||
118 | * @invoke_fn: function to issue secure monitor call or hypervisor call | ||
119 | * | ||
120 | * This struct is used to create communication channels for service clients, to | ||
121 | * handle secure monitor or hypervisor call. | ||
122 | */ | ||
123 | struct stratix10_svc_controller { | ||
124 | struct device *dev; | ||
125 | struct stratix10_svc_chan *chans; | ||
126 | int num_chans; | ||
127 | int num_active_client; | ||
128 | struct list_head node; | ||
129 | struct gen_pool *genpool; | ||
130 | struct task_struct *task; | ||
131 | struct kfifo svc_fifo; | ||
132 | struct completion complete_status; | ||
133 | spinlock_t svc_fifo_lock; | ||
134 | svc_invoke_fn *invoke_fn; | ||
135 | }; | ||
136 | |||
137 | /** | ||
138 | * struct stratix10_svc_chan - service communication channel | ||
139 | * @ctrl: pointer to service controller which is the provider of this channel | ||
140 | * @scl: pointer to service client which owns the channel | ||
141 | * @name: service client name associated with the channel | ||
142 | * @lock: protect access to the channel | ||
143 | * | ||
144 | * This struct is used by service client to communicate with service layer, each | ||
145 | * service client has its own channel created by service controller. | ||
146 | */ | ||
147 | struct stratix10_svc_chan { | ||
148 | struct stratix10_svc_controller *ctrl; | ||
149 | struct stratix10_svc_client *scl; | ||
150 | char *name; | ||
151 | spinlock_t lock; | ||
152 | }; | ||
153 | |||
154 | static LIST_HEAD(svc_ctrl); | ||
155 | static LIST_HEAD(svc_data_mem); | ||
156 | |||
157 | /** | ||
158 | * svc_pa_to_va() - translate physical address to virtual address | ||
159 | * @addr: to be translated physical address | ||
160 | * | ||
161 | * Return: valid virtual address or NULL if the provided physical | ||
162 | * address doesn't exist. | ||
163 | */ | ||
164 | static void *svc_pa_to_va(unsigned long addr) | ||
165 | { | ||
166 | struct stratix10_svc_data_mem *pmem; | ||
167 | |||
168 | pr_debug("claim back P-addr=0x%016x\n", (unsigned int)addr); | ||
169 | list_for_each_entry(pmem, &svc_data_mem, node) | ||
170 | if (pmem->paddr == addr) | ||
171 | return pmem->vaddr; | ||
172 | |||
173 | /* physical address is not found */ | ||
174 | return NULL; | ||
175 | } | ||
176 | |||
177 | /** | ||
178 | * svc_thread_cmd_data_claim() - claim back buffer from the secure world | ||
179 | * @ctrl: pointer to service layer controller | ||
180 | * @p_data: pointer to service data structure | ||
181 | * @cb_data: pointer to callback data structure to service client | ||
182 | * | ||
183 | * Claim back the submitted buffers from the secure world and pass buffer | ||
184 | * back to service client (FPGA manager, etc) for reuse. | ||
185 | */ | ||
186 | static void svc_thread_cmd_data_claim(struct stratix10_svc_controller *ctrl, | ||
187 | struct stratix10_svc_data *p_data, | ||
188 | struct stratix10_svc_cb_data *cb_data) | ||
189 | { | ||
190 | struct arm_smccc_res res; | ||
191 | unsigned long timeout; | ||
192 | |||
193 | reinit_completion(&ctrl->complete_status); | ||
194 | timeout = msecs_to_jiffies(FPGA_CONFIG_DATA_CLAIM_TIMEOUT_MS); | ||
195 | |||
196 | pr_debug("%s: claim back the submitted buffer\n", __func__); | ||
197 | do { | ||
198 | ctrl->invoke_fn(INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE, | ||
199 | 0, 0, 0, 0, 0, 0, 0, &res); | ||
200 | |||
201 | if (res.a0 == INTEL_SIP_SMC_STATUS_OK) { | ||
202 | if (!res.a1) { | ||
203 | complete(&ctrl->complete_status); | ||
204 | break; | ||
205 | } | ||
206 | cb_data->status = BIT(SVC_STATUS_RECONFIG_BUFFER_DONE); | ||
207 | cb_data->kaddr1 = svc_pa_to_va(res.a1); | ||
208 | cb_data->kaddr2 = (res.a2) ? | ||
209 | svc_pa_to_va(res.a2) : NULL; | ||
210 | cb_data->kaddr3 = (res.a3) ? | ||
211 | svc_pa_to_va(res.a3) : NULL; | ||
212 | p_data->chan->scl->receive_cb(p_data->chan->scl, | ||
213 | cb_data); | ||
214 | } else { | ||
215 | pr_debug("%s: secure world busy, polling again\n", | ||
216 | __func__); | ||
217 | } | ||
218 | } while (res.a0 == INTEL_SIP_SMC_STATUS_OK || | ||
219 | res.a0 == INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY || | ||
220 | wait_for_completion_timeout(&ctrl->complete_status, timeout)); | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * svc_thread_cmd_config_status() - check configuration status | ||
225 | * @ctrl: pointer to service layer controller | ||
226 | * @p_data: pointer to service data structure | ||
227 | * @cb_data: pointer to callback data structure to service client | ||
228 | * | ||
229 | * Check whether the secure firmware at secure world has finished the FPGA | ||
230 | * configuration, and then inform FPGA manager the configuration status. | ||
231 | */ | ||
232 | static void svc_thread_cmd_config_status(struct stratix10_svc_controller *ctrl, | ||
233 | struct stratix10_svc_data *p_data, | ||
234 | struct stratix10_svc_cb_data *cb_data) | ||
235 | { | ||
236 | struct arm_smccc_res res; | ||
237 | int count_in_sec; | ||
238 | |||
239 | cb_data->kaddr1 = NULL; | ||
240 | cb_data->kaddr2 = NULL; | ||
241 | cb_data->kaddr3 = NULL; | ||
242 | cb_data->status = BIT(SVC_STATUS_RECONFIG_ERROR); | ||
243 | |||
244 | pr_debug("%s: polling config status\n", __func__); | ||
245 | |||
246 | count_in_sec = FPGA_CONFIG_STATUS_TIMEOUT_SEC; | ||
247 | while (count_in_sec) { | ||
248 | ctrl->invoke_fn(INTEL_SIP_SMC_FPGA_CONFIG_ISDONE, | ||
249 | 0, 0, 0, 0, 0, 0, 0, &res); | ||
250 | if ((res.a0 == INTEL_SIP_SMC_STATUS_OK) || | ||
251 | (res.a0 == INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR)) | ||
252 | break; | ||
253 | |||
254 | /* | ||
255 | * configuration is still in progress, wait one second then | ||
256 | * poll again | ||
257 | */ | ||
258 | msleep(1000); | ||
259 | count_in_sec--; | ||
260 | }; | ||
261 | |||
262 | if (res.a0 == INTEL_SIP_SMC_STATUS_OK && count_in_sec) | ||
263 | cb_data->status = BIT(SVC_STATUS_RECONFIG_COMPLETED); | ||
264 | |||
265 | p_data->chan->scl->receive_cb(p_data->chan->scl, cb_data); | ||
266 | } | ||
267 | |||
268 | /** | ||
269 | * svc_thread_recv_status_ok() - handle the successful status | ||
270 | * @p_data: pointer to service data structure | ||
271 | * @cb_data: pointer to callback data structure to service client | ||
272 | * @res: result from SMC or HVC call | ||
273 | * | ||
274 | * Send back the correspond status to the service client (FPGA manager etc). | ||
275 | */ | ||
276 | static void svc_thread_recv_status_ok(struct stratix10_svc_data *p_data, | ||
277 | struct stratix10_svc_cb_data *cb_data, | ||
278 | struct arm_smccc_res res) | ||
279 | { | ||
280 | cb_data->kaddr1 = NULL; | ||
281 | cb_data->kaddr2 = NULL; | ||
282 | cb_data->kaddr3 = NULL; | ||
283 | |||
284 | switch (p_data->command) { | ||
285 | case COMMAND_RECONFIG: | ||
286 | cb_data->status = BIT(SVC_STATUS_RECONFIG_REQUEST_OK); | ||
287 | break; | ||
288 | case COMMAND_RECONFIG_DATA_SUBMIT: | ||
289 | cb_data->status = BIT(SVC_STATUS_RECONFIG_BUFFER_SUBMITTED); | ||
290 | break; | ||
291 | case COMMAND_NOOP: | ||
292 | cb_data->status = BIT(SVC_STATUS_RECONFIG_BUFFER_SUBMITTED); | ||
293 | cb_data->kaddr1 = svc_pa_to_va(res.a1); | ||
294 | break; | ||
295 | case COMMAND_RECONFIG_STATUS: | ||
296 | cb_data->status = BIT(SVC_STATUS_RECONFIG_COMPLETED); | ||
297 | break; | ||
298 | default: | ||
299 | pr_warn("it shouldn't happen\n"); | ||
300 | break; | ||
301 | } | ||
302 | |||
303 | pr_debug("%s: call receive_cb\n", __func__); | ||
304 | p_data->chan->scl->receive_cb(p_data->chan->scl, cb_data); | ||
305 | } | ||
306 | |||
307 | /** | ||
308 | * svc_normal_to_secure_thread() - the function to run in the kthread | ||
309 | * @data: data pointer for kthread function | ||
310 | * | ||
311 | * Service layer driver creates stratix10_svc_smc_hvc_call kthread on CPU | ||
312 | * node 0, its function stratix10_svc_secure_call_thread is used to handle | ||
313 | * SMC or HVC calls between kernel driver and secure monitor software. | ||
314 | * | ||
315 | * Return: 0 for success or -ENOMEM on error. | ||
316 | */ | ||
317 | static int svc_normal_to_secure_thread(void *data) | ||
318 | { | ||
319 | struct stratix10_svc_controller | ||
320 | *ctrl = (struct stratix10_svc_controller *)data; | ||
321 | struct stratix10_svc_data *pdata; | ||
322 | struct stratix10_svc_cb_data *cbdata; | ||
323 | struct arm_smccc_res res; | ||
324 | unsigned long a0, a1, a2; | ||
325 | int ret_fifo = 0; | ||
326 | |||
327 | pdata = kmalloc(sizeof(*pdata), GFP_KERNEL); | ||
328 | if (!pdata) | ||
329 | return -ENOMEM; | ||
330 | |||
331 | cbdata = kmalloc(sizeof(*cbdata), GFP_KERNEL); | ||
332 | if (!cbdata) { | ||
333 | kfree(pdata); | ||
334 | return -ENOMEM; | ||
335 | } | ||
336 | |||
337 | /* default set, to remove build warning */ | ||
338 | a0 = INTEL_SIP_SMC_FPGA_CONFIG_LOOPBACK; | ||
339 | a1 = 0; | ||
340 | a2 = 0; | ||
341 | |||
342 | pr_debug("smc_hvc_shm_thread is running\n"); | ||
343 | |||
344 | while (!kthread_should_stop()) { | ||
345 | ret_fifo = kfifo_out_spinlocked(&ctrl->svc_fifo, | ||
346 | pdata, sizeof(*pdata), | ||
347 | &ctrl->svc_fifo_lock); | ||
348 | |||
349 | if (!ret_fifo) | ||
350 | continue; | ||
351 | |||
352 | pr_debug("get from FIFO pa=0x%016x, command=%u, size=%u\n", | ||
353 | (unsigned int)pdata->paddr, pdata->command, | ||
354 | (unsigned int)pdata->size); | ||
355 | |||
356 | switch (pdata->command) { | ||
357 | case COMMAND_RECONFIG_DATA_CLAIM: | ||
358 | svc_thread_cmd_data_claim(ctrl, pdata, cbdata); | ||
359 | continue; | ||
360 | case COMMAND_RECONFIG: | ||
361 | a0 = INTEL_SIP_SMC_FPGA_CONFIG_START; | ||
362 | pr_debug("conf_type=%u\n", (unsigned int)pdata->flag); | ||
363 | a1 = pdata->flag; | ||
364 | a2 = 0; | ||
365 | break; | ||
366 | case COMMAND_RECONFIG_DATA_SUBMIT: | ||
367 | a0 = INTEL_SIP_SMC_FPGA_CONFIG_WRITE; | ||
368 | a1 = (unsigned long)pdata->paddr; | ||
369 | a2 = (unsigned long)pdata->size; | ||
370 | break; | ||
371 | case COMMAND_RECONFIG_STATUS: | ||
372 | a0 = INTEL_SIP_SMC_FPGA_CONFIG_ISDONE; | ||
373 | a1 = 0; | ||
374 | a2 = 0; | ||
375 | break; | ||
376 | default: | ||
377 | pr_warn("it shouldn't happen\n"); | ||
378 | break; | ||
379 | } | ||
380 | pr_debug("%s: before SMC call -- a0=0x%016x a1=0x%016x", | ||
381 | __func__, (unsigned int)a0, (unsigned int)a1); | ||
382 | pr_debug(" a2=0x%016x\n", (unsigned int)a2); | ||
383 | |||
384 | ctrl->invoke_fn(a0, a1, a2, 0, 0, 0, 0, 0, &res); | ||
385 | |||
386 | pr_debug("%s: after SMC call -- res.a0=0x%016x", | ||
387 | __func__, (unsigned int)res.a0); | ||
388 | pr_debug(" res.a1=0x%016x, res.a2=0x%016x", | ||
389 | (unsigned int)res.a1, (unsigned int)res.a2); | ||
390 | pr_debug(" res.a3=0x%016x\n", (unsigned int)res.a3); | ||
391 | |||
392 | switch (res.a0) { | ||
393 | case INTEL_SIP_SMC_STATUS_OK: | ||
394 | svc_thread_recv_status_ok(pdata, cbdata, res); | ||
395 | break; | ||
396 | case INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY: | ||
397 | switch (pdata->command) { | ||
398 | case COMMAND_RECONFIG_DATA_SUBMIT: | ||
399 | svc_thread_cmd_data_claim(ctrl, | ||
400 | pdata, cbdata); | ||
401 | break; | ||
402 | case COMMAND_RECONFIG_STATUS: | ||
403 | svc_thread_cmd_config_status(ctrl, | ||
404 | pdata, cbdata); | ||
405 | break; | ||
406 | default: | ||
407 | pr_warn("it shouldn't happen\n"); | ||
408 | break; | ||
409 | } | ||
410 | break; | ||
411 | case INTEL_SIP_SMC_FPGA_CONFIG_STATUS_REJECTED: | ||
412 | pr_debug("%s: STATUS_REJECTED\n", __func__); | ||
413 | break; | ||
414 | case INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR: | ||
415 | pr_err("%s: STATUS_ERROR\n", __func__); | ||
416 | cbdata->status = BIT(SVC_STATUS_RECONFIG_ERROR); | ||
417 | cbdata->kaddr1 = NULL; | ||
418 | cbdata->kaddr2 = NULL; | ||
419 | cbdata->kaddr3 = NULL; | ||
420 | pdata->chan->scl->receive_cb(pdata->chan->scl, cbdata); | ||
421 | break; | ||
422 | default: | ||
423 | pr_warn("it shouldn't happen\n"); | ||
424 | break; | ||
425 | } | ||
426 | }; | ||
427 | |||
428 | kfree(cbdata); | ||
429 | kfree(pdata); | ||
430 | |||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | /** | ||
435 | * svc_normal_to_secure_shm_thread() - the function to run in the kthread | ||
436 | * @data: data pointer for kthread function | ||
437 | * | ||
438 | * Service layer driver creates stratix10_svc_smc_hvc_shm kthread on CPU | ||
439 | * node 0, its function stratix10_svc_secure_shm_thread is used to query the | ||
440 | * physical address of memory block reserved by secure monitor software at | ||
441 | * secure world. | ||
442 | * | ||
443 | * svc_normal_to_secure_shm_thread() calls do_exit() directly since it is a | ||
444 | * standlone thread for which no one will call kthread_stop() or return when | ||
445 | * 'kthread_should_stop()' is true. | ||
446 | */ | ||
447 | static int svc_normal_to_secure_shm_thread(void *data) | ||
448 | { | ||
449 | struct stratix10_svc_sh_memory | ||
450 | *sh_mem = (struct stratix10_svc_sh_memory *)data; | ||
451 | struct arm_smccc_res res; | ||
452 | |||
453 | /* SMC or HVC call to get shared memory info from secure world */ | ||
454 | sh_mem->invoke_fn(INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM, | ||
455 | 0, 0, 0, 0, 0, 0, 0, &res); | ||
456 | if (res.a0 == INTEL_SIP_SMC_STATUS_OK) { | ||
457 | sh_mem->addr = res.a1; | ||
458 | sh_mem->size = res.a2; | ||
459 | } else { | ||
460 | pr_err("%s: after SMC call -- res.a0=0x%016x", __func__, | ||
461 | (unsigned int)res.a0); | ||
462 | sh_mem->addr = 0; | ||
463 | sh_mem->size = 0; | ||
464 | } | ||
465 | |||
466 | complete(&sh_mem->sync_complete); | ||
467 | do_exit(0); | ||
468 | } | ||
469 | |||
470 | /** | ||
471 | * svc_get_sh_memory() - get memory block reserved by secure monitor SW | ||
472 | * @pdev: pointer to service layer device | ||
473 | * @sh_memory: pointer to service shared memory structure | ||
474 | * | ||
475 | * Return: zero for successfully getting the physical address of memory block | ||
476 | * reserved by secure monitor software, or negative value on error. | ||
477 | */ | ||
478 | static int svc_get_sh_memory(struct platform_device *pdev, | ||
479 | struct stratix10_svc_sh_memory *sh_memory) | ||
480 | { | ||
481 | struct device *dev = &pdev->dev; | ||
482 | struct task_struct *sh_memory_task; | ||
483 | unsigned int cpu = 0; | ||
484 | |||
485 | init_completion(&sh_memory->sync_complete); | ||
486 | |||
487 | /* smc or hvc call happens on cpu 0 bound kthread */ | ||
488 | sh_memory_task = kthread_create_on_node(svc_normal_to_secure_shm_thread, | ||
489 | (void *)sh_memory, | ||
490 | cpu_to_node(cpu), | ||
491 | "svc_smc_hvc_shm_thread"); | ||
492 | if (IS_ERR(sh_memory_task)) { | ||
493 | dev_err(dev, "fail to create stratix10_svc_smc_shm_thread\n"); | ||
494 | return -EINVAL; | ||
495 | } | ||
496 | |||
497 | wake_up_process(sh_memory_task); | ||
498 | |||
499 | if (!wait_for_completion_timeout(&sh_memory->sync_complete, 10 * HZ)) { | ||
500 | dev_err(dev, | ||
501 | "timeout to get sh-memory paras from secure world\n"); | ||
502 | return -ETIMEDOUT; | ||
503 | } | ||
504 | |||
505 | if (!sh_memory->addr || !sh_memory->size) { | ||
506 | dev_err(dev, | ||
507 | "fails to get shared memory info from secure world\n"); | ||
508 | return -ENOMEM; | ||
509 | } | ||
510 | |||
511 | dev_dbg(dev, "SM software provides paddr: 0x%016x, size: 0x%08x\n", | ||
512 | (unsigned int)sh_memory->addr, | ||
513 | (unsigned int)sh_memory->size); | ||
514 | |||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | /** | ||
519 | * svc_create_memory_pool() - create a memory pool from reserved memory block | ||
520 | * @pdev: pointer to service layer device | ||
521 | * @sh_memory: pointer to service shared memory structure | ||
522 | * | ||
523 | * Return: pool allocated from reserved memory block or ERR_PTR() on error. | ||
524 | */ | ||
525 | static struct gen_pool * | ||
526 | svc_create_memory_pool(struct platform_device *pdev, | ||
527 | struct stratix10_svc_sh_memory *sh_memory) | ||
528 | { | ||
529 | struct device *dev = &pdev->dev; | ||
530 | struct gen_pool *genpool; | ||
531 | unsigned long vaddr; | ||
532 | phys_addr_t paddr; | ||
533 | size_t size; | ||
534 | phys_addr_t begin; | ||
535 | phys_addr_t end; | ||
536 | void *va; | ||
537 | size_t page_mask = PAGE_SIZE - 1; | ||
538 | int min_alloc_order = 3; | ||
539 | int ret; | ||
540 | |||
541 | begin = roundup(sh_memory->addr, PAGE_SIZE); | ||
542 | end = rounddown(sh_memory->addr + sh_memory->size, PAGE_SIZE); | ||
543 | paddr = begin; | ||
544 | size = end - begin; | ||
545 | va = memremap(paddr, size, MEMREMAP_WC); | ||
546 | if (!va) { | ||
547 | dev_err(dev, "fail to remap shared memory\n"); | ||
548 | return ERR_PTR(-EINVAL); | ||
549 | } | ||
550 | vaddr = (unsigned long)va; | ||
551 | dev_dbg(dev, | ||
552 | "reserved memory vaddr: %p, paddr: 0x%16x size: 0x%8x\n", | ||
553 | va, (unsigned int)paddr, (unsigned int)size); | ||
554 | if ((vaddr & page_mask) || (paddr & page_mask) || | ||
555 | (size & page_mask)) { | ||
556 | dev_err(dev, "page is not aligned\n"); | ||
557 | return ERR_PTR(-EINVAL); | ||
558 | } | ||
559 | genpool = gen_pool_create(min_alloc_order, -1); | ||
560 | if (!genpool) { | ||
561 | dev_err(dev, "fail to create genpool\n"); | ||
562 | return ERR_PTR(-ENOMEM); | ||
563 | } | ||
564 | gen_pool_set_algo(genpool, gen_pool_best_fit, NULL); | ||
565 | ret = gen_pool_add_virt(genpool, vaddr, paddr, size, -1); | ||
566 | if (ret) { | ||
567 | dev_err(dev, "fail to add memory chunk to the pool\n"); | ||
568 | gen_pool_destroy(genpool); | ||
569 | return ERR_PTR(ret); | ||
570 | } | ||
571 | |||
572 | return genpool; | ||
573 | } | ||
574 | |||
575 | /** | ||
576 | * svc_smccc_smc() - secure monitor call between normal and secure world | ||
577 | * @a0: argument passed in registers 0 | ||
578 | * @a1: argument passed in registers 1 | ||
579 | * @a2: argument passed in registers 2 | ||
580 | * @a3: argument passed in registers 3 | ||
581 | * @a4: argument passed in registers 4 | ||
582 | * @a5: argument passed in registers 5 | ||
583 | * @a6: argument passed in registers 6 | ||
584 | * @a7: argument passed in registers 7 | ||
585 | * @res: result values from register 0 to 3 | ||
586 | */ | ||
587 | static void svc_smccc_smc(unsigned long a0, unsigned long a1, | ||
588 | unsigned long a2, unsigned long a3, | ||
589 | unsigned long a4, unsigned long a5, | ||
590 | unsigned long a6, unsigned long a7, | ||
591 | struct arm_smccc_res *res) | ||
592 | { | ||
593 | arm_smccc_smc(a0, a1, a2, a3, a4, a5, a6, a7, res); | ||
594 | } | ||
595 | |||
596 | /** | ||
597 | * svc_smccc_hvc() - hypervisor call between normal and secure world | ||
598 | * @a0: argument passed in registers 0 | ||
599 | * @a1: argument passed in registers 1 | ||
600 | * @a2: argument passed in registers 2 | ||
601 | * @a3: argument passed in registers 3 | ||
602 | * @a4: argument passed in registers 4 | ||
603 | * @a5: argument passed in registers 5 | ||
604 | * @a6: argument passed in registers 6 | ||
605 | * @a7: argument passed in registers 7 | ||
606 | * @res: result values from register 0 to 3 | ||
607 | */ | ||
608 | static void svc_smccc_hvc(unsigned long a0, unsigned long a1, | ||
609 | unsigned long a2, unsigned long a3, | ||
610 | unsigned long a4, unsigned long a5, | ||
611 | unsigned long a6, unsigned long a7, | ||
612 | struct arm_smccc_res *res) | ||
613 | { | ||
614 | arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res); | ||
615 | } | ||
616 | |||
617 | /** | ||
618 | * get_invoke_func() - invoke SMC or HVC call | ||
619 | * @dev: pointer to device | ||
620 | * | ||
621 | * Return: function pointer to svc_smccc_smc or svc_smccc_hvc. | ||
622 | */ | ||
623 | static svc_invoke_fn *get_invoke_func(struct device *dev) | ||
624 | { | ||
625 | const char *method; | ||
626 | |||
627 | if (of_property_read_string(dev->of_node, "method", &method)) { | ||
628 | dev_warn(dev, "missing \"method\" property\n"); | ||
629 | return ERR_PTR(-ENXIO); | ||
630 | } | ||
631 | |||
632 | if (!strcmp(method, "smc")) | ||
633 | return svc_smccc_smc; | ||
634 | if (!strcmp(method, "hvc")) | ||
635 | return svc_smccc_hvc; | ||
636 | |||
637 | dev_warn(dev, "invalid \"method\" property: %s\n", method); | ||
638 | |||
639 | return ERR_PTR(-EINVAL); | ||
640 | } | ||
641 | |||
642 | /** | ||
643 | * stratix10_svc_request_channel_byname() - request a service channel | ||
644 | * @client: pointer to service client | ||
645 | * @name: service client name | ||
646 | * | ||
647 | * This function is used by service client to request a service channel. | ||
648 | * | ||
649 | * Return: a pointer to channel assigned to the client on success, | ||
650 | * or ERR_PTR() on error. | ||
651 | */ | ||
652 | struct stratix10_svc_chan *stratix10_svc_request_channel_byname( | ||
653 | struct stratix10_svc_client *client, const char *name) | ||
654 | { | ||
655 | struct device *dev = client->dev; | ||
656 | struct stratix10_svc_controller *controller; | ||
657 | struct stratix10_svc_chan *chan = NULL; | ||
658 | unsigned long flag; | ||
659 | int i; | ||
660 | |||
661 | /* if probe was called after client's, or error on probe */ | ||
662 | if (list_empty(&svc_ctrl)) | ||
663 | return ERR_PTR(-EPROBE_DEFER); | ||
664 | |||
665 | controller = list_first_entry(&svc_ctrl, | ||
666 | struct stratix10_svc_controller, node); | ||
667 | for (i = 0; i < SVC_NUM_CHANNEL; i++) { | ||
668 | if (!strcmp(controller->chans[i].name, name)) { | ||
669 | chan = &controller->chans[i]; | ||
670 | break; | ||
671 | } | ||
672 | } | ||
673 | |||
674 | /* if there was no channel match */ | ||
675 | if (i == SVC_NUM_CHANNEL) { | ||
676 | dev_err(dev, "%s: channel not allocated\n", __func__); | ||
677 | return ERR_PTR(-EINVAL); | ||
678 | } | ||
679 | |||
680 | if (chan->scl || !try_module_get(controller->dev->driver->owner)) { | ||
681 | dev_dbg(dev, "%s: svc not free\n", __func__); | ||
682 | return ERR_PTR(-EBUSY); | ||
683 | } | ||
684 | |||
685 | spin_lock_irqsave(&chan->lock, flag); | ||
686 | chan->scl = client; | ||
687 | chan->ctrl->num_active_client++; | ||
688 | spin_unlock_irqrestore(&chan->lock, flag); | ||
689 | |||
690 | return chan; | ||
691 | } | ||
692 | EXPORT_SYMBOL_GPL(stratix10_svc_request_channel_byname); | ||
693 | |||
694 | /** | ||
695 | * stratix10_svc_free_channel() - free service channel | ||
696 | * @chan: service channel to be freed | ||
697 | * | ||
698 | * This function is used by service client to free a service channel. | ||
699 | */ | ||
700 | void stratix10_svc_free_channel(struct stratix10_svc_chan *chan) | ||
701 | { | ||
702 | unsigned long flag; | ||
703 | |||
704 | spin_lock_irqsave(&chan->lock, flag); | ||
705 | chan->scl = NULL; | ||
706 | chan->ctrl->num_active_client--; | ||
707 | module_put(chan->ctrl->dev->driver->owner); | ||
708 | spin_unlock_irqrestore(&chan->lock, flag); | ||
709 | } | ||
710 | EXPORT_SYMBOL_GPL(stratix10_svc_free_channel); | ||
711 | |||
712 | /** | ||
713 | * stratix10_svc_send() - send a message data to the remote | ||
714 | * @chan: service channel assigned to the client | ||
715 | * @msg: message data to be sent, in the format of | ||
716 | * "struct stratix10_svc_client_msg" | ||
717 | * | ||
718 | * This function is used by service client to add a message to the service | ||
719 | * layer driver's queue for being sent to the secure world. | ||
720 | * | ||
721 | * Return: 0 for success, -ENOMEM or -ENOBUFS on error. | ||
722 | */ | ||
723 | int stratix10_svc_send(struct stratix10_svc_chan *chan, void *msg) | ||
724 | { | ||
725 | struct stratix10_svc_client_msg | ||
726 | *p_msg = (struct stratix10_svc_client_msg *)msg; | ||
727 | struct stratix10_svc_data_mem *p_mem; | ||
728 | struct stratix10_svc_data *p_data; | ||
729 | int ret = 0; | ||
730 | unsigned int cpu = 0; | ||
731 | |||
732 | p_data = kzalloc(sizeof(*p_data), GFP_KERNEL); | ||
733 | if (!p_data) | ||
734 | return -ENOMEM; | ||
735 | |||
736 | /* first client will create kernel thread */ | ||
737 | if (!chan->ctrl->task) { | ||
738 | chan->ctrl->task = | ||
739 | kthread_create_on_node(svc_normal_to_secure_thread, | ||
740 | (void *)chan->ctrl, | ||
741 | cpu_to_node(cpu), | ||
742 | "svc_smc_hvc_thread"); | ||
743 | if (IS_ERR(chan->ctrl->task)) { | ||
744 | dev_err(chan->ctrl->dev, | ||
745 | "fails to create svc_smc_hvc_thread\n"); | ||
746 | kfree(p_data); | ||
747 | return -EINVAL; | ||
748 | } | ||
749 | kthread_bind(chan->ctrl->task, cpu); | ||
750 | wake_up_process(chan->ctrl->task); | ||
751 | } | ||
752 | |||
753 | pr_debug("%s: sent P-va=%p, P-com=%x, P-size=%u\n", __func__, | ||
754 | p_msg->payload, p_msg->command, | ||
755 | (unsigned int)p_msg->payload_length); | ||
756 | |||
757 | if (list_empty(&svc_data_mem)) { | ||
758 | if (p_msg->command == COMMAND_RECONFIG) { | ||
759 | struct stratix10_svc_command_config_type *ct = | ||
760 | (struct stratix10_svc_command_config_type *) | ||
761 | p_msg->payload; | ||
762 | p_data->flag = ct->flags; | ||
763 | } | ||
764 | } else { | ||
765 | list_for_each_entry(p_mem, &svc_data_mem, node) | ||
766 | if (p_mem->vaddr == p_msg->payload) { | ||
767 | p_data->paddr = p_mem->paddr; | ||
768 | break; | ||
769 | } | ||
770 | } | ||
771 | |||
772 | p_data->command = p_msg->command; | ||
773 | p_data->arg[0] = p_msg->arg[0]; | ||
774 | p_data->arg[1] = p_msg->arg[1]; | ||
775 | p_data->arg[2] = p_msg->arg[2]; | ||
776 | p_data->size = p_msg->payload_length; | ||
777 | p_data->chan = chan; | ||
778 | pr_debug("%s: put to FIFO pa=0x%016x, cmd=%x, size=%u\n", __func__, | ||
779 | (unsigned int)p_data->paddr, p_data->command, | ||
780 | (unsigned int)p_data->size); | ||
781 | ret = kfifo_in_spinlocked(&chan->ctrl->svc_fifo, p_data, | ||
782 | sizeof(*p_data), | ||
783 | &chan->ctrl->svc_fifo_lock); | ||
784 | |||
785 | kfree(p_data); | ||
786 | |||
787 | if (!ret) | ||
788 | return -ENOBUFS; | ||
789 | |||
790 | return 0; | ||
791 | } | ||
792 | EXPORT_SYMBOL_GPL(stratix10_svc_send); | ||
793 | |||
794 | /** | ||
795 | * stratix10_svc_done() - complete service request transactions | ||
796 | * @chan: service channel assigned to the client | ||
797 | * | ||
798 | * This function should be called when client has finished its request | ||
799 | * or there is an error in the request process. It allows the service layer | ||
800 | * to stop the running thread to have maximize savings in kernel resources. | ||
801 | */ | ||
802 | void stratix10_svc_done(struct stratix10_svc_chan *chan) | ||
803 | { | ||
804 | /* stop thread when thread is running AND only one active client */ | ||
805 | if (chan->ctrl->task && chan->ctrl->num_active_client <= 1) { | ||
806 | pr_debug("svc_smc_hvc_shm_thread is stopped\n"); | ||
807 | kthread_stop(chan->ctrl->task); | ||
808 | chan->ctrl->task = NULL; | ||
809 | } | ||
810 | } | ||
811 | EXPORT_SYMBOL_GPL(stratix10_svc_done); | ||
812 | |||
813 | /** | ||
814 | * stratix10_svc_allocate_memory() - allocate memory | ||
815 | * @chan: service channel assigned to the client | ||
816 | * @size: memory size requested by a specific service client | ||
817 | * | ||
818 | * Service layer allocates the requested number of bytes buffer from the | ||
819 | * memory pool, service client uses this function to get allocated buffers. | ||
820 | * | ||
821 | * Return: address of allocated memory on success, or ERR_PTR() on error. | ||
822 | */ | ||
823 | void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan, | ||
824 | size_t size) | ||
825 | { | ||
826 | struct stratix10_svc_data_mem *pmem; | ||
827 | unsigned long va; | ||
828 | phys_addr_t pa; | ||
829 | struct gen_pool *genpool = chan->ctrl->genpool; | ||
830 | size_t s = roundup(size, 1 << genpool->min_alloc_order); | ||
831 | |||
832 | pmem = devm_kzalloc(chan->ctrl->dev, sizeof(*pmem), GFP_KERNEL); | ||
833 | if (!pmem) | ||
834 | return ERR_PTR(-ENOMEM); | ||
835 | |||
836 | va = gen_pool_alloc(genpool, s); | ||
837 | if (!va) | ||
838 | return ERR_PTR(-ENOMEM); | ||
839 | |||
840 | memset((void *)va, 0, s); | ||
841 | pa = gen_pool_virt_to_phys(genpool, va); | ||
842 | |||
843 | pmem->vaddr = (void *)va; | ||
844 | pmem->paddr = pa; | ||
845 | pmem->size = s; | ||
846 | list_add_tail(&pmem->node, &svc_data_mem); | ||
847 | pr_debug("%s: va=%p, pa=0x%016x\n", __func__, | ||
848 | pmem->vaddr, (unsigned int)pmem->paddr); | ||
849 | |||
850 | return (void *)va; | ||
851 | } | ||
852 | EXPORT_SYMBOL_GPL(stratix10_svc_allocate_memory); | ||
853 | |||
854 | /** | ||
855 | * stratix10_svc_free_memory() - free allocated memory | ||
856 | * @chan: service channel assigned to the client | ||
857 | * @kaddr: memory to be freed | ||
858 | * | ||
859 | * This function is used by service client to free allocated buffers. | ||
860 | */ | ||
861 | void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr) | ||
862 | { | ||
863 | struct stratix10_svc_data_mem *pmem; | ||
864 | size_t size = 0; | ||
865 | |||
866 | list_for_each_entry(pmem, &svc_data_mem, node) | ||
867 | if (pmem->vaddr == kaddr) { | ||
868 | size = pmem->size; | ||
869 | break; | ||
870 | } | ||
871 | |||
872 | gen_pool_free(chan->ctrl->genpool, (unsigned long)kaddr, size); | ||
873 | pmem->vaddr = NULL; | ||
874 | list_del(&pmem->node); | ||
875 | } | ||
876 | EXPORT_SYMBOL_GPL(stratix10_svc_free_memory); | ||
877 | |||
878 | static const struct of_device_id stratix10_svc_drv_match[] = { | ||
879 | {.compatible = "intel,stratix10-svc"}, | ||
880 | {}, | ||
881 | }; | ||
882 | |||
883 | static int stratix10_svc_drv_probe(struct platform_device *pdev) | ||
884 | { | ||
885 | struct device *dev = &pdev->dev; | ||
886 | struct stratix10_svc_controller *controller; | ||
887 | struct stratix10_svc_chan *chans; | ||
888 | struct gen_pool *genpool; | ||
889 | struct stratix10_svc_sh_memory *sh_memory; | ||
890 | svc_invoke_fn *invoke_fn; | ||
891 | size_t fifo_size; | ||
892 | int ret; | ||
893 | |||
894 | /* get SMC or HVC function */ | ||
895 | invoke_fn = get_invoke_func(dev); | ||
896 | if (IS_ERR(invoke_fn)) | ||
897 | return -EINVAL; | ||
898 | |||
899 | sh_memory = devm_kzalloc(dev, sizeof(*sh_memory), GFP_KERNEL); | ||
900 | if (!sh_memory) | ||
901 | return -ENOMEM; | ||
902 | |||
903 | sh_memory->invoke_fn = invoke_fn; | ||
904 | ret = svc_get_sh_memory(pdev, sh_memory); | ||
905 | if (ret) | ||
906 | return ret; | ||
907 | |||
908 | genpool = svc_create_memory_pool(pdev, sh_memory); | ||
909 | if (!genpool) | ||
910 | return -ENOMEM; | ||
911 | |||
912 | /* allocate service controller and supporting channel */ | ||
913 | controller = devm_kzalloc(dev, sizeof(*controller), GFP_KERNEL); | ||
914 | if (!controller) | ||
915 | return -ENOMEM; | ||
916 | |||
917 | chans = devm_kmalloc_array(dev, SVC_NUM_CHANNEL, | ||
918 | sizeof(*chans), GFP_KERNEL | __GFP_ZERO); | ||
919 | if (!chans) | ||
920 | return -ENOMEM; | ||
921 | |||
922 | controller->dev = dev; | ||
923 | controller->num_chans = SVC_NUM_CHANNEL; | ||
924 | controller->num_active_client = 0; | ||
925 | controller->chans = chans; | ||
926 | controller->genpool = genpool; | ||
927 | controller->task = NULL; | ||
928 | controller->invoke_fn = invoke_fn; | ||
929 | init_completion(&controller->complete_status); | ||
930 | |||
931 | fifo_size = sizeof(struct stratix10_svc_data) * SVC_NUM_DATA_IN_FIFO; | ||
932 | ret = kfifo_alloc(&controller->svc_fifo, fifo_size, GFP_KERNEL); | ||
933 | if (ret) { | ||
934 | dev_err(dev, "fails to allocate FIFO\n"); | ||
935 | return ret; | ||
936 | } | ||
937 | spin_lock_init(&controller->svc_fifo_lock); | ||
938 | |||
939 | chans[0].scl = NULL; | ||
940 | chans[0].ctrl = controller; | ||
941 | chans[0].name = SVC_CLIENT_FPGA; | ||
942 | spin_lock_init(&chans[0].lock); | ||
943 | |||
944 | list_add_tail(&controller->node, &svc_ctrl); | ||
945 | platform_set_drvdata(pdev, controller); | ||
946 | |||
947 | pr_info("Intel Service Layer Driver Initialized\n"); | ||
948 | |||
949 | return ret; | ||
950 | } | ||
951 | |||
952 | static int stratix10_svc_drv_remove(struct platform_device *pdev) | ||
953 | { | ||
954 | struct stratix10_svc_controller *ctrl = platform_get_drvdata(pdev); | ||
955 | |||
956 | kfifo_free(&ctrl->svc_fifo); | ||
957 | if (ctrl->task) { | ||
958 | kthread_stop(ctrl->task); | ||
959 | ctrl->task = NULL; | ||
960 | } | ||
961 | if (ctrl->genpool) | ||
962 | gen_pool_destroy(ctrl->genpool); | ||
963 | list_del(&ctrl->node); | ||
964 | |||
965 | return 0; | ||
966 | } | ||
967 | |||
968 | static struct platform_driver stratix10_svc_driver = { | ||
969 | .probe = stratix10_svc_drv_probe, | ||
970 | .remove = stratix10_svc_drv_remove, | ||
971 | .driver = { | ||
972 | .name = "stratix10-svc", | ||
973 | .of_match_table = stratix10_svc_drv_match, | ||
974 | }, | ||
975 | }; | ||
976 | |||
977 | static int __init stratix10_svc_init(void) | ||
978 | { | ||
979 | struct device_node *fw_np; | ||
980 | struct device_node *np; | ||
981 | int ret; | ||
982 | |||
983 | fw_np = of_find_node_by_name(NULL, "firmware"); | ||
984 | if (!fw_np) | ||
985 | return -ENODEV; | ||
986 | |||
987 | np = of_find_matching_node(fw_np, stratix10_svc_drv_match); | ||
988 | if (!np) { | ||
989 | of_node_put(fw_np); | ||
990 | return -ENODEV; | ||
991 | } | ||
992 | |||
993 | of_node_put(np); | ||
994 | ret = of_platform_populate(fw_np, stratix10_svc_drv_match, NULL, NULL); | ||
995 | of_node_put(fw_np); | ||
996 | if (ret) | ||
997 | return ret; | ||
998 | |||
999 | return platform_driver_register(&stratix10_svc_driver); | ||
1000 | } | ||
1001 | |||
1002 | static void __exit stratix10_svc_exit(void) | ||
1003 | { | ||
1004 | return platform_driver_unregister(&stratix10_svc_driver); | ||
1005 | } | ||
1006 | |||
1007 | subsys_initcall(stratix10_svc_init); | ||
1008 | module_exit(stratix10_svc_exit); | ||
1009 | |||
1010 | MODULE_LICENSE("GPL v2"); | ||
1011 | MODULE_DESCRIPTION("Intel Stratix10 Service Layer Driver"); | ||
1012 | MODULE_AUTHOR("Richard Gong <richard.gong@intel.com>"); | ||
1013 | MODULE_ALIAS("platform:stratix10-svc"); | ||
diff --git a/include/linux/firmware/intel/stratix10-smc.h b/include/linux/firmware/intel/stratix10-smc.h new file mode 100644 index 000000000000..a109e4ccbc7e --- /dev/null +++ b/include/linux/firmware/intel/stratix10-smc.h | |||
@@ -0,0 +1,265 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* | ||
3 | * Copyright (C) 2017-2018, Intel Corporation | ||
4 | */ | ||
5 | |||
6 | #ifndef __STRATIX10_SMC_H | ||
7 | #define __STRATIX10_SMC_H | ||
8 | |||
9 | #include <linux/arm-smccc.h> | ||
10 | #include <linux/bitops.h> | ||
11 | |||
12 | /** | ||
13 | * This file defines the Secure Monitor Call (SMC) message protocol used for | ||
14 | * service layer driver in normal world (EL1) to communicate with secure | ||
15 | * monitor software in Secure Monitor Exception Level 3 (EL3). | ||
16 | * | ||
17 | * This file is shared with secure firmware (FW) which is out of kernel tree. | ||
18 | * | ||
19 | * An ARM SMC instruction takes a function identifier and up to 6 64-bit | ||
20 | * register values as arguments, and can return up to 4 64-bit register | ||
21 | * value. The operation of the secure monitor is determined by the parameter | ||
22 | * values passed in through registers. | ||
23 | * | ||
24 | * EL1 and EL3 communicates pointer as physical address rather than the | ||
25 | * virtual address. | ||
26 | * | ||
27 | * Functions specified by ARM SMC Calling convention: | ||
28 | * | ||
29 | * FAST call executes atomic operations, returns when the requested operation | ||
30 | * has completed. | ||
31 | * STD call starts a operation which can be preempted by a non-secure | ||
32 | * interrupt. The call can return before the requested operation has | ||
33 | * completed. | ||
34 | * | ||
35 | * a0..a7 is used as register names in the descriptions below, on arm32 | ||
36 | * that translates to r0..r7 and on arm64 to w0..w7. | ||
37 | */ | ||
38 | |||
39 | /** | ||
40 | * @func_num: function ID | ||
41 | */ | ||
42 | #define INTEL_SIP_SMC_STD_CALL_VAL(func_num) \ | ||
43 | ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, ARM_SMCCC_SMC_64, \ | ||
44 | ARM_SMCCC_OWNER_SIP, (func_num)) | ||
45 | |||
46 | #define INTEL_SIP_SMC_FAST_CALL_VAL(func_num) \ | ||
47 | ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \ | ||
48 | ARM_SMCCC_OWNER_SIP, (func_num)) | ||
49 | |||
50 | /** | ||
51 | * Return values in INTEL_SIP_SMC_* call | ||
52 | * | ||
53 | * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION: | ||
54 | * Secure monitor software doesn't recognize the request. | ||
55 | * | ||
56 | * INTEL_SIP_SMC_STATUS_OK: | ||
57 | * FPGA configuration completed successfully, | ||
58 | * In case of FPGA configuration write operation, it means secure monitor | ||
59 | * software can accept the next chunk of FPGA configuration data. | ||
60 | * | ||
61 | * INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY: | ||
62 | * In case of FPGA configuration write operation, it means secure monitor | ||
63 | * software is still processing previous data & can't accept the next chunk | ||
64 | * of data. Service driver needs to issue | ||
65 | * INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE call to query the | ||
66 | * completed block(s). | ||
67 | * | ||
68 | * INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR: | ||
69 | * There is error during the FPGA configuration process. | ||
70 | */ | ||
71 | #define INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION 0xFFFFFFFF | ||
72 | #define INTEL_SIP_SMC_STATUS_OK 0x0 | ||
73 | #define INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY 0x1 | ||
74 | #define INTEL_SIP_SMC_FPGA_CONFIG_STATUS_REJECTED 0x2 | ||
75 | #define INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR 0x4 | ||
76 | #define INTEL_SIP_SMC_REG_ERROR 0x5 | ||
77 | |||
78 | /** | ||
79 | * Request INTEL_SIP_SMC_FPGA_CONFIG_START | ||
80 | * | ||
81 | * Sync call used by service driver at EL1 to request the FPGA in EL3 to | ||
82 | * be prepare to receive a new configuration. | ||
83 | * | ||
84 | * Call register usage: | ||
85 | * a0: INTEL_SIP_SMC_FPGA_CONFIG_START. | ||
86 | * a1: flag for full or partial configuration. 0 for full and 1 for partial | ||
87 | * configuration. | ||
88 | * a2-7: not used. | ||
89 | * | ||
90 | * Return status: | ||
91 | * a0: INTEL_SIP_SMC_STATUS_OK, or INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR. | ||
92 | * a1-3: not used. | ||
93 | */ | ||
94 | #define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_START 1 | ||
95 | #define INTEL_SIP_SMC_FPGA_CONFIG_START \ | ||
96 | INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_START) | ||
97 | |||
98 | /** | ||
99 | * Request INTEL_SIP_SMC_FPGA_CONFIG_WRITE | ||
100 | * | ||
101 | * Async call used by service driver at EL1 to provide FPGA configuration data | ||
102 | * to secure world. | ||
103 | * | ||
104 | * Call register usage: | ||
105 | * a0: INTEL_SIP_SMC_FPGA_CONFIG_WRITE. | ||
106 | * a1: 64bit physical address of the configuration data memory block | ||
107 | * a2: Size of configuration data block. | ||
108 | * a3-7: not used. | ||
109 | * | ||
110 | * Return status: | ||
111 | * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY or | ||
112 | * INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR. | ||
113 | * a1: 64bit physical address of 1st completed memory block if any completed | ||
114 | * block, otherwise zero value. | ||
115 | * a2: 64bit physical address of 2nd completed memory block if any completed | ||
116 | * block, otherwise zero value. | ||
117 | * a3: 64bit physical address of 3rd completed memory block if any completed | ||
118 | * block, otherwise zero value. | ||
119 | */ | ||
120 | #define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_WRITE 2 | ||
121 | #define INTEL_SIP_SMC_FPGA_CONFIG_WRITE \ | ||
122 | INTEL_SIP_SMC_STD_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_WRITE) | ||
123 | |||
124 | /** | ||
125 | * Request INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE | ||
126 | * | ||
127 | * Sync call used by service driver at EL1 to track the completed write | ||
128 | * transactions. This request is called after INTEL_SIP_SMC_FPGA_CONFIG_WRITE | ||
129 | * call returns INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY. | ||
130 | * | ||
131 | * Call register usage: | ||
132 | * a0: INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE. | ||
133 | * a1-7: not used. | ||
134 | * | ||
135 | * Return status: | ||
136 | * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY or | ||
137 | * INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR. | ||
138 | * a1: 64bit physical address of 1st completed memory block. | ||
139 | * a2: 64bit physical address of 2nd completed memory block if | ||
140 | * any completed block, otherwise zero value. | ||
141 | * a3: 64bit physical address of 3rd completed memory block if | ||
142 | * any completed block, otherwise zero value. | ||
143 | */ | ||
144 | #define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE 3 | ||
145 | #define INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE \ | ||
146 | INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE) | ||
147 | |||
148 | /** | ||
149 | * Request INTEL_SIP_SMC_FPGA_CONFIG_ISDONE | ||
150 | * | ||
151 | * Sync call used by service driver at EL1 to inform secure world that all | ||
152 | * data are sent, to check whether or not the secure world had completed | ||
153 | * the FPGA configuration process. | ||
154 | * | ||
155 | * Call register usage: | ||
156 | * a0: INTEL_SIP_SMC_FPGA_CONFIG_ISDONE. | ||
157 | * a1-7: not used. | ||
158 | * | ||
159 | * Return status: | ||
160 | * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY or | ||
161 | * INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR. | ||
162 | * a1-3: not used. | ||
163 | */ | ||
164 | #define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_ISDONE 4 | ||
165 | #define INTEL_SIP_SMC_FPGA_CONFIG_ISDONE \ | ||
166 | INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_ISDONE) | ||
167 | |||
168 | /** | ||
169 | * Request INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM | ||
170 | * | ||
171 | * Sync call used by service driver at EL1 to query the physical address of | ||
172 | * memory block reserved by secure monitor software. | ||
173 | * | ||
174 | * Call register usage: | ||
175 | * a0:INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM. | ||
176 | * a1-7: not used. | ||
177 | * | ||
178 | * Return status: | ||
179 | * a0: INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR. | ||
180 | * a1: start of physical address of reserved memory block. | ||
181 | * a2: size of reserved memory block. | ||
182 | * a3: not used. | ||
183 | */ | ||
184 | #define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_GET_MEM 5 | ||
185 | #define INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM \ | ||
186 | INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_GET_MEM) | ||
187 | |||
188 | /** | ||
189 | * Request INTEL_SIP_SMC_FPGA_CONFIG_LOOPBACK | ||
190 | * | ||
191 | * For SMC loop-back mode only, used for internal integration, debugging | ||
192 | * or troubleshooting. | ||
193 | * | ||
194 | * Call register usage: | ||
195 | * a0: INTEL_SIP_SMC_FPGA_CONFIG_LOOPBACK. | ||
196 | * a1-7: not used. | ||
197 | * | ||
198 | * Return status: | ||
199 | * a0: INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR. | ||
200 | * a1-3: not used. | ||
201 | */ | ||
202 | #define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_LOOPBACK 6 | ||
203 | #define INTEL_SIP_SMC_FPGA_CONFIG_LOOPBACK \ | ||
204 | INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_LOOPBACK) | ||
205 | |||
206 | /* | ||
207 | * Request INTEL_SIP_SMC_REG_READ | ||
208 | * | ||
209 | * Read a protected register at EL3 | ||
210 | * | ||
211 | * Call register usage: | ||
212 | * a0: INTEL_SIP_SMC_REG_READ. | ||
213 | * a1: register address. | ||
214 | * a2-7: not used. | ||
215 | * | ||
216 | * Return status: | ||
217 | * a0: INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_REG_ERROR. | ||
218 | * a1: value in the register | ||
219 | * a2-3: not used. | ||
220 | */ | ||
221 | #define INTEL_SIP_SMC_FUNCID_REG_READ 7 | ||
222 | #define INTEL_SIP_SMC_REG_READ \ | ||
223 | INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_REG_READ) | ||
224 | |||
225 | /* | ||
226 | * Request INTEL_SIP_SMC_REG_WRITE | ||
227 | * | ||
228 | * Write a protected register at EL3 | ||
229 | * | ||
230 | * Call register usage: | ||
231 | * a0: INTEL_SIP_SMC_REG_WRITE. | ||
232 | * a1: register address | ||
233 | * a2: value to program into register. | ||
234 | * a3-7: not used. | ||
235 | * | ||
236 | * Return status: | ||
237 | * a0: INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_REG_ERROR. | ||
238 | * a1-3: not used. | ||
239 | */ | ||
240 | #define INTEL_SIP_SMC_FUNCID_REG_WRITE 8 | ||
241 | #define INTEL_SIP_SMC_REG_WRITE \ | ||
242 | INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_REG_WRITE) | ||
243 | |||
244 | /* | ||
245 | * Request INTEL_SIP_SMC_FUNCID_REG_UPDATE | ||
246 | * | ||
247 | * Update one or more bits in a protected register at EL3 using a | ||
248 | * read-modify-write operation. | ||
249 | * | ||
250 | * Call register usage: | ||
251 | * a0: INTEL_SIP_SMC_REG_UPDATE. | ||
252 | * a1: register address | ||
253 | * a2: write Mask. | ||
254 | * a3: value to write. | ||
255 | * a4-7: not used. | ||
256 | * | ||
257 | * Return status: | ||
258 | * a0: INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_REG_ERROR. | ||
259 | * a1-3: Not used. | ||
260 | */ | ||
261 | #define INTEL_SIP_SMC_FUNCID_REG_UPDATE 9 | ||
262 | #define INTEL_SIP_SMC_REG_UPDATE \ | ||
263 | INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_REG_UPDATE) | ||
264 | |||
265 | #endif | ||
diff --git a/include/linux/firmware/intel/stratix10-svc-client.h b/include/linux/firmware/intel/stratix10-svc-client.h new file mode 100644 index 000000000000..f2fda7e1ca52 --- /dev/null +++ b/include/linux/firmware/intel/stratix10-svc-client.h | |||
@@ -0,0 +1,201 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* | ||
3 | * Copyright (C) 2017-2018, Intel Corporation | ||
4 | */ | ||
5 | |||
6 | #ifndef __STRATIX10_SVC_CLIENT_H | ||
7 | #define __STRATIX10_SVC_CLIENT_H | ||
8 | |||
9 | /** | ||
10 | * Service layer driver supports client names | ||
11 | * | ||
12 | * fpga: for FPGA configuration | ||
13 | */ | ||
14 | #define SVC_CLIENT_FPGA "fpga" | ||
15 | |||
16 | /** | ||
17 | * Status of the sent command, in bit number | ||
18 | * | ||
19 | * SVC_COMMAND_STATUS_RECONFIG_REQUEST_OK: | ||
20 | * Secure firmware accepts the request of FPGA reconfiguration. | ||
21 | * | ||
22 | * SVC_STATUS_RECONFIG_BUFFER_SUBMITTED: | ||
23 | * Service client successfully submits FPGA configuration | ||
24 | * data buffer to secure firmware. | ||
25 | * | ||
26 | * SVC_COMMAND_STATUS_RECONFIG_BUFFER_DONE: | ||
27 | * Secure firmware completes data process, ready to accept the | ||
28 | * next WRITE transaction. | ||
29 | * | ||
30 | * SVC_COMMAND_STATUS_RECONFIG_COMPLETED: | ||
31 | * Secure firmware completes FPGA configuration successfully, FPGA should | ||
32 | * be in user mode. | ||
33 | * | ||
34 | * SVC_COMMAND_STATUS_RECONFIG_BUSY: | ||
35 | * FPGA configuration is still in process. | ||
36 | * | ||
37 | * SVC_COMMAND_STATUS_RECONFIG_ERROR: | ||
38 | * Error encountered during FPGA configuration. | ||
39 | */ | ||
40 | #define SVC_STATUS_RECONFIG_REQUEST_OK 0 | ||
41 | #define SVC_STATUS_RECONFIG_BUFFER_SUBMITTED 1 | ||
42 | #define SVC_STATUS_RECONFIG_BUFFER_DONE 2 | ||
43 | #define SVC_STATUS_RECONFIG_COMPLETED 3 | ||
44 | #define SVC_STATUS_RECONFIG_BUSY 4 | ||
45 | #define SVC_STATUS_RECONFIG_ERROR 5 | ||
46 | |||
47 | /** | ||
48 | * Flag bit for COMMAND_RECONFIG | ||
49 | * | ||
50 | * COMMAND_RECONFIG_FLAG_PARTIAL: | ||
51 | * Set to FPGA configuration type (full or partial), the default | ||
52 | * is full reconfig. | ||
53 | */ | ||
54 | #define COMMAND_RECONFIG_FLAG_PARTIAL 0 | ||
55 | |||
56 | /** | ||
57 | * Timeout settings for service clients: | ||
58 | * timeout value used in Stratix10 FPGA manager driver. | ||
59 | */ | ||
60 | #define SVC_RECONFIG_REQUEST_TIMEOUT_MS 100 | ||
61 | #define SVC_RECONFIG_BUFFER_TIMEOUT_MS 240 | ||
62 | |||
63 | struct stratix10_svc_chan; | ||
64 | |||
65 | /** | ||
66 | * enum stratix10_svc_command_code - supported service commands | ||
67 | * | ||
68 | * @COMMAND_NOOP: do 'dummy' request for integration/debug/trouble-shooting | ||
69 | * | ||
70 | * @COMMAND_RECONFIG: ask for FPGA configuration preparation, return status | ||
71 | * is SVC_STATUS_RECONFIG_REQUEST_OK | ||
72 | * | ||
73 | * @COMMAND_RECONFIG_DATA_SUBMIT: submit buffer(s) of bit-stream data for the | ||
74 | * FPGA configuration, return status is SVC_STATUS_RECONFIG_BUFFER_SUBMITTED, | ||
75 | * or SVC_STATUS_RECONFIG_ERROR | ||
76 | * | ||
77 | * @COMMAND_RECONFIG_DATA_CLAIM: check the status of the configuration, return | ||
78 | * status is SVC_STATUS_RECONFIG_COMPLETED, or SVC_STATUS_RECONFIG_BUSY, or | ||
79 | * SVC_STATUS_RECONFIG_ERROR | ||
80 | * | ||
81 | * @COMMAND_RECONFIG_STATUS: check the status of the configuration, return | ||
82 | * status is SVC_STATUS_RECONFIG_COMPLETED, or SVC_STATUS_RECONFIG_BUSY, or | ||
83 | * SVC_STATUS_RECONFIG_ERROR | ||
84 | */ | ||
85 | enum stratix10_svc_command_code { | ||
86 | COMMAND_NOOP = 0, | ||
87 | COMMAND_RECONFIG, | ||
88 | COMMAND_RECONFIG_DATA_SUBMIT, | ||
89 | COMMAND_RECONFIG_DATA_CLAIM, | ||
90 | COMMAND_RECONFIG_STATUS | ||
91 | }; | ||
92 | |||
93 | /** | ||
94 | * struct stratix10_svc_client_msg - message sent by client to service | ||
95 | * @payload: starting address of data need be processed | ||
96 | * @payload_length: data size in bytes | ||
97 | * @command: service command | ||
98 | * @arg: args to be passed via registers and not physically mapped buffers | ||
99 | */ | ||
100 | struct stratix10_svc_client_msg { | ||
101 | void *payload; | ||
102 | size_t payload_length; | ||
103 | enum stratix10_svc_command_code command; | ||
104 | u64 arg[3]; | ||
105 | }; | ||
106 | |||
107 | /** | ||
108 | * struct stratix10_svc_command_config_type - config type | ||
109 | * @flags: flag bit for the type of FPGA configuration | ||
110 | */ | ||
111 | struct stratix10_svc_command_config_type { | ||
112 | u32 flags; | ||
113 | }; | ||
114 | |||
115 | /** | ||
116 | * struct stratix10_svc_cb_data - callback data structure from service layer | ||
117 | * @status: the status of sent command | ||
118 | * @kaddr1: address of 1st completed data block | ||
119 | * @kaddr2: address of 2nd completed data block | ||
120 | * @kaddr3: address of 3rd completed data block | ||
121 | */ | ||
122 | struct stratix10_svc_cb_data { | ||
123 | u32 status; | ||
124 | void *kaddr1; | ||
125 | void *kaddr2; | ||
126 | void *kaddr3; | ||
127 | }; | ||
128 | |||
129 | /** | ||
130 | * struct stratix10_svc_client - service client structure | ||
131 | * @dev: the client device | ||
132 | * @receive_cb: callback to provide service client the received data | ||
133 | * @priv: client private data | ||
134 | */ | ||
135 | struct stratix10_svc_client { | ||
136 | struct device *dev; | ||
137 | void (*receive_cb)(struct stratix10_svc_client *client, | ||
138 | struct stratix10_svc_cb_data *cb_data); | ||
139 | void *priv; | ||
140 | }; | ||
141 | |||
142 | /** | ||
143 | * stratix10_svc_request_channel_byname() - request service channel | ||
144 | * @client: identity of the client requesting the channel | ||
145 | * @name: supporting client name defined above | ||
146 | * | ||
147 | * Return: a pointer to channel assigned to the client on success, | ||
148 | * or ERR_PTR() on error. | ||
149 | */ | ||
150 | struct stratix10_svc_chan | ||
151 | *stratix10_svc_request_channel_byname(struct stratix10_svc_client *client, | ||
152 | const char *name); | ||
153 | |||
154 | /** | ||
155 | * stratix10_svc_free_channel() - free service channel. | ||
156 | * @chan: service channel to be freed | ||
157 | */ | ||
158 | void stratix10_svc_free_channel(struct stratix10_svc_chan *chan); | ||
159 | |||
160 | /** | ||
161 | * stratix10_svc_allocate_memory() - allocate the momory | ||
162 | * @chan: service channel assigned to the client | ||
163 | * @size: number of bytes client requests | ||
164 | * | ||
165 | * Service layer allocates the requested number of bytes from the memory | ||
166 | * pool for the client. | ||
167 | * | ||
168 | * Return: the starting address of allocated memory on success, or | ||
169 | * ERR_PTR() on error. | ||
170 | */ | ||
171 | void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan, | ||
172 | size_t size); | ||
173 | |||
174 | /** | ||
175 | * stratix10_svc_free_memory() - free allocated memory | ||
176 | * @chan: service channel assigned to the client | ||
177 | * @kaddr: starting address of memory to be free back to pool | ||
178 | */ | ||
179 | void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr); | ||
180 | |||
181 | /** | ||
182 | * stratix10_svc_send() - send a message to the remote | ||
183 | * @chan: service channel assigned to the client | ||
184 | * @msg: message data to be sent, in the format of | ||
185 | * struct stratix10_svc_client_msg | ||
186 | * | ||
187 | * Return: 0 for success, -ENOMEM or -ENOBUFS on error. | ||
188 | */ | ||
189 | int stratix10_svc_send(struct stratix10_svc_chan *chan, void *msg); | ||
190 | |||
191 | /** | ||
192 | * intel_svc_done() - complete service request | ||
193 | * @chan: service channel assigned to the client | ||
194 | * | ||
195 | * This function is used by service client to inform service layer that | ||
196 | * client's service requests are completed, or there is an error in the | ||
197 | * request process. | ||
198 | */ | ||
199 | void stratix10_svc_done(struct stratix10_svc_chan *chan); | ||
200 | #endif | ||
201 | |||