17ca5ce89SRichard Gong // SPDX-License-Identifier: GPL-2.0
27ca5ce89SRichard Gong /*
37ca5ce89SRichard Gong * Copyright (C) 2017-2018, Intel Corporation
47ca5ce89SRichard Gong */
57ca5ce89SRichard Gong
67ca5ce89SRichard Gong #include <linux/completion.h>
77ca5ce89SRichard Gong #include <linux/delay.h>
87ca5ce89SRichard Gong #include <linux/genalloc.h>
97ca5ce89SRichard Gong #include <linux/io.h>
107ca5ce89SRichard Gong #include <linux/kfifo.h>
117ca5ce89SRichard Gong #include <linux/kthread.h>
127ca5ce89SRichard Gong #include <linux/module.h>
137ca5ce89SRichard Gong #include <linux/mutex.h>
147ca5ce89SRichard Gong #include <linux/of.h>
157ca5ce89SRichard Gong #include <linux/of_platform.h>
167ca5ce89SRichard Gong #include <linux/platform_device.h>
177ca5ce89SRichard Gong #include <linux/slab.h>
187ca5ce89SRichard Gong #include <linux/spinlock.h>
197ca5ce89SRichard Gong #include <linux/firmware/intel/stratix10-smc.h>
207ca5ce89SRichard Gong #include <linux/firmware/intel/stratix10-svc-client.h>
217ca5ce89SRichard Gong #include <linux/types.h>
227ca5ce89SRichard Gong
237ca5ce89SRichard Gong /**
247ca5ce89SRichard Gong * SVC_NUM_DATA_IN_FIFO - number of struct stratix10_svc_data in the FIFO
257ca5ce89SRichard Gong *
267ca5ce89SRichard Gong * SVC_NUM_CHANNEL - number of channel supported by service layer driver
277ca5ce89SRichard Gong *
287ca5ce89SRichard Gong * FPGA_CONFIG_DATA_CLAIM_TIMEOUT_MS - claim back the submitted buffer(s)
297ca5ce89SRichard Gong * from the secure world for FPGA manager to reuse, or to free the buffer(s)
307ca5ce89SRichard Gong * when all bit-stream data had be send.
317ca5ce89SRichard Gong *
327ca5ce89SRichard Gong * FPGA_CONFIG_STATUS_TIMEOUT_SEC - poll the FPGA configuration status,
337ca5ce89SRichard Gong * service layer will return error to FPGA manager when timeout occurs,
347ca5ce89SRichard Gong * timeout is set to 30 seconds (30 * 1000) at Intel Stratix10 SoC.
357ca5ce89SRichard Gong */
367ca5ce89SRichard Gong #define SVC_NUM_DATA_IN_FIFO 32
37e6281c26SAng Tien Sung #define SVC_NUM_CHANNEL 3
387ca5ce89SRichard Gong #define FPGA_CONFIG_DATA_CLAIM_TIMEOUT_MS 200
397ca5ce89SRichard Gong #define FPGA_CONFIG_STATUS_TIMEOUT_SEC 30
40*34949a31STeh Wen Ping #define BYTE_TO_WORD_SIZE 4
417ca5ce89SRichard Gong
42b5dc75c9SRichard Gong /* stratix10 service layer clients */
43b5dc75c9SRichard Gong #define STRATIX10_RSU "stratix10-rsu"
44e6281c26SAng Tien Sung #define INTEL_FCS "intel-fcs"
45b5dc75c9SRichard Gong
467ca5ce89SRichard Gong typedef void (svc_invoke_fn)(unsigned long, unsigned long, unsigned long,
477ca5ce89SRichard Gong unsigned long, unsigned long, unsigned long,
487ca5ce89SRichard Gong unsigned long, unsigned long,
497ca5ce89SRichard Gong struct arm_smccc_res *);
507ca5ce89SRichard Gong struct stratix10_svc_chan;
517ca5ce89SRichard Gong
527ca5ce89SRichard Gong /**
53b5dc75c9SRichard Gong * struct stratix10_svc - svc private data
54b5dc75c9SRichard Gong * @stratix10_svc_rsu: pointer to stratix10 RSU device
55b5dc75c9SRichard Gong */
56b5dc75c9SRichard Gong struct stratix10_svc {
57b5dc75c9SRichard Gong struct platform_device *stratix10_svc_rsu;
58e6281c26SAng Tien Sung struct platform_device *intel_svc_fcs;
59b5dc75c9SRichard Gong };
60b5dc75c9SRichard Gong
61b5dc75c9SRichard Gong /**
627ca5ce89SRichard Gong * struct stratix10_svc_sh_memory - service shared memory structure
637ca5ce89SRichard Gong * @sync_complete: state for a completion
647ca5ce89SRichard Gong * @addr: physical address of shared memory block
657ca5ce89SRichard Gong * @size: size of shared memory block
667ca5ce89SRichard Gong * @invoke_fn: function to issue secure monitor or hypervisor call
677ca5ce89SRichard Gong *
687ca5ce89SRichard Gong * This struct is used to save physical address and size of shared memory
697ca5ce89SRichard Gong * block. The shared memory blocked is allocated by secure monitor software
707ca5ce89SRichard Gong * at secure world.
717ca5ce89SRichard Gong *
727ca5ce89SRichard Gong * Service layer driver uses the physical address and size to create a memory
737ca5ce89SRichard Gong * pool, then allocates data buffer from that memory pool for service client.
747ca5ce89SRichard Gong */
757ca5ce89SRichard Gong struct stratix10_svc_sh_memory {
767ca5ce89SRichard Gong struct completion sync_complete;
777ca5ce89SRichard Gong unsigned long addr;
787ca5ce89SRichard Gong unsigned long size;
797ca5ce89SRichard Gong svc_invoke_fn *invoke_fn;
807ca5ce89SRichard Gong };
817ca5ce89SRichard Gong
827ca5ce89SRichard Gong /**
837ca5ce89SRichard Gong * struct stratix10_svc_data_mem - service memory structure
847ca5ce89SRichard Gong * @vaddr: virtual address
857ca5ce89SRichard Gong * @paddr: physical address
867ca5ce89SRichard Gong * @size: size of memory
877ca5ce89SRichard Gong * @node: link list head node
887ca5ce89SRichard Gong *
897ca5ce89SRichard Gong * This struct is used in a list that keeps track of buffers which have
907ca5ce89SRichard Gong * been allocated or freed from the memory pool. Service layer driver also
917ca5ce89SRichard Gong * uses this struct to transfer physical address to virtual address.
927ca5ce89SRichard Gong */
937ca5ce89SRichard Gong struct stratix10_svc_data_mem {
947ca5ce89SRichard Gong void *vaddr;
957ca5ce89SRichard Gong phys_addr_t paddr;
967ca5ce89SRichard Gong size_t size;
977ca5ce89SRichard Gong struct list_head node;
987ca5ce89SRichard Gong };
997ca5ce89SRichard Gong
1007ca5ce89SRichard Gong /**
1017ca5ce89SRichard Gong * struct stratix10_svc_data - service data structure
1027ca5ce89SRichard Gong * @chan: service channel
1034a4709d4SAng Tien Sung * @paddr: physical address of to be processed payload
1044a4709d4SAng Tien Sung * @size: to be processed playload size
1054a4709d4SAng Tien Sung * @paddr_output: physical address of processed payload
1064a4709d4SAng Tien Sung * @size_output: processed payload size
1077ca5ce89SRichard Gong * @command: service command requested by client
1087ca5ce89SRichard Gong * @flag: configuration type (full or partial)
1097ca5ce89SRichard Gong * @arg: args to be passed via registers and not physically mapped buffers
1107ca5ce89SRichard Gong *
1117ca5ce89SRichard Gong * This struct is used in service FIFO for inter-process communication.
1127ca5ce89SRichard Gong */
1137ca5ce89SRichard Gong struct stratix10_svc_data {
1147ca5ce89SRichard Gong struct stratix10_svc_chan *chan;
1157ca5ce89SRichard Gong phys_addr_t paddr;
1167ca5ce89SRichard Gong size_t size;
1174a4709d4SAng Tien Sung phys_addr_t paddr_output;
1184a4709d4SAng Tien Sung size_t size_output;
1197ca5ce89SRichard Gong u32 command;
1207ca5ce89SRichard Gong u32 flag;
1217ca5ce89SRichard Gong u64 arg[3];
1227ca5ce89SRichard Gong };
1237ca5ce89SRichard Gong
1247ca5ce89SRichard Gong /**
1257ca5ce89SRichard Gong * struct stratix10_svc_controller - service controller
1267ca5ce89SRichard Gong * @dev: device
1277ca5ce89SRichard Gong * @chans: array of service channels
1287ca5ce89SRichard Gong * @num_chans: number of channels in 'chans' array
1297ca5ce89SRichard Gong * @num_active_client: number of active service client
1307ca5ce89SRichard Gong * @node: list management
1317ca5ce89SRichard Gong * @genpool: memory pool pointing to the memory region
1327ca5ce89SRichard Gong * @task: pointer to the thread task which handles SMC or HVC call
1337ca5ce89SRichard Gong * @svc_fifo: a queue for storing service message data
1347ca5ce89SRichard Gong * @complete_status: state for completion
1357ca5ce89SRichard Gong * @svc_fifo_lock: protect access to service message data queue
1367ca5ce89SRichard Gong * @invoke_fn: function to issue secure monitor call or hypervisor call
1377ca5ce89SRichard Gong *
1387ca5ce89SRichard Gong * This struct is used to create communication channels for service clients, to
1397ca5ce89SRichard Gong * handle secure monitor or hypervisor call.
1407ca5ce89SRichard Gong */
1417ca5ce89SRichard Gong struct stratix10_svc_controller {
1427ca5ce89SRichard Gong struct device *dev;
1437ca5ce89SRichard Gong struct stratix10_svc_chan *chans;
1447ca5ce89SRichard Gong int num_chans;
1457ca5ce89SRichard Gong int num_active_client;
1467ca5ce89SRichard Gong struct list_head node;
1477ca5ce89SRichard Gong struct gen_pool *genpool;
1487ca5ce89SRichard Gong struct task_struct *task;
1497ca5ce89SRichard Gong struct kfifo svc_fifo;
1507ca5ce89SRichard Gong struct completion complete_status;
1517ca5ce89SRichard Gong spinlock_t svc_fifo_lock;
1527ca5ce89SRichard Gong svc_invoke_fn *invoke_fn;
1537ca5ce89SRichard Gong };
1547ca5ce89SRichard Gong
1557ca5ce89SRichard Gong /**
1567ca5ce89SRichard Gong * struct stratix10_svc_chan - service communication channel
1577ca5ce89SRichard Gong * @ctrl: pointer to service controller which is the provider of this channel
1587ca5ce89SRichard Gong * @scl: pointer to service client which owns the channel
1597ca5ce89SRichard Gong * @name: service client name associated with the channel
1607ca5ce89SRichard Gong * @lock: protect access to the channel
1617ca5ce89SRichard Gong *
1627ca5ce89SRichard Gong * This struct is used by service client to communicate with service layer, each
1637ca5ce89SRichard Gong * service client has its own channel created by service controller.
1647ca5ce89SRichard Gong */
1657ca5ce89SRichard Gong struct stratix10_svc_chan {
1667ca5ce89SRichard Gong struct stratix10_svc_controller *ctrl;
1677ca5ce89SRichard Gong struct stratix10_svc_client *scl;
1687ca5ce89SRichard Gong char *name;
1697ca5ce89SRichard Gong spinlock_t lock;
1707ca5ce89SRichard Gong };
1717ca5ce89SRichard Gong
1727ca5ce89SRichard Gong static LIST_HEAD(svc_ctrl);
1737ca5ce89SRichard Gong static LIST_HEAD(svc_data_mem);
1747ca5ce89SRichard Gong
1757ca5ce89SRichard Gong /**
1767ca5ce89SRichard Gong * svc_pa_to_va() - translate physical address to virtual address
1777ca5ce89SRichard Gong * @addr: to be translated physical address
1787ca5ce89SRichard Gong *
1797ca5ce89SRichard Gong * Return: valid virtual address or NULL if the provided physical
1807ca5ce89SRichard Gong * address doesn't exist.
1817ca5ce89SRichard Gong */
svc_pa_to_va(unsigned long addr)1827ca5ce89SRichard Gong static void *svc_pa_to_va(unsigned long addr)
1837ca5ce89SRichard Gong {
1847ca5ce89SRichard Gong struct stratix10_svc_data_mem *pmem;
1857ca5ce89SRichard Gong
1867ca5ce89SRichard Gong pr_debug("claim back P-addr=0x%016x\n", (unsigned int)addr);
1877ca5ce89SRichard Gong list_for_each_entry(pmem, &svc_data_mem, node)
1887ca5ce89SRichard Gong if (pmem->paddr == addr)
1897ca5ce89SRichard Gong return pmem->vaddr;
1907ca5ce89SRichard Gong
1917ca5ce89SRichard Gong /* physical address is not found */
1927ca5ce89SRichard Gong return NULL;
1937ca5ce89SRichard Gong }
1947ca5ce89SRichard Gong
1957ca5ce89SRichard Gong /**
1967ca5ce89SRichard Gong * svc_thread_cmd_data_claim() - claim back buffer from the secure world
1977ca5ce89SRichard Gong * @ctrl: pointer to service layer controller
1987ca5ce89SRichard Gong * @p_data: pointer to service data structure
1997ca5ce89SRichard Gong * @cb_data: pointer to callback data structure to service client
2007ca5ce89SRichard Gong *
2017ca5ce89SRichard Gong * Claim back the submitted buffers from the secure world and pass buffer
2027ca5ce89SRichard Gong * back to service client (FPGA manager, etc) for reuse.
2037ca5ce89SRichard Gong */
svc_thread_cmd_data_claim(struct stratix10_svc_controller * ctrl,struct stratix10_svc_data * p_data,struct stratix10_svc_cb_data * cb_data)2047ca5ce89SRichard Gong static void svc_thread_cmd_data_claim(struct stratix10_svc_controller *ctrl,
2057ca5ce89SRichard Gong struct stratix10_svc_data *p_data,
2067ca5ce89SRichard Gong struct stratix10_svc_cb_data *cb_data)
2077ca5ce89SRichard Gong {
2087ca5ce89SRichard Gong struct arm_smccc_res res;
2097ca5ce89SRichard Gong unsigned long timeout;
2107ca5ce89SRichard Gong
2117ca5ce89SRichard Gong reinit_completion(&ctrl->complete_status);
2127ca5ce89SRichard Gong timeout = msecs_to_jiffies(FPGA_CONFIG_DATA_CLAIM_TIMEOUT_MS);
2137ca5ce89SRichard Gong
2147ca5ce89SRichard Gong pr_debug("%s: claim back the submitted buffer\n", __func__);
2157ca5ce89SRichard Gong do {
2167ca5ce89SRichard Gong ctrl->invoke_fn(INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE,
2177ca5ce89SRichard Gong 0, 0, 0, 0, 0, 0, 0, &res);
2187ca5ce89SRichard Gong
2197ca5ce89SRichard Gong if (res.a0 == INTEL_SIP_SMC_STATUS_OK) {
2207ca5ce89SRichard Gong if (!res.a1) {
2217ca5ce89SRichard Gong complete(&ctrl->complete_status);
2227ca5ce89SRichard Gong break;
2237ca5ce89SRichard Gong }
2247536ad8dSRichard Gong cb_data->status = BIT(SVC_STATUS_BUFFER_DONE);
2257ca5ce89SRichard Gong cb_data->kaddr1 = svc_pa_to_va(res.a1);
2267ca5ce89SRichard Gong cb_data->kaddr2 = (res.a2) ?
2277ca5ce89SRichard Gong svc_pa_to_va(res.a2) : NULL;
2287ca5ce89SRichard Gong cb_data->kaddr3 = (res.a3) ?
2297ca5ce89SRichard Gong svc_pa_to_va(res.a3) : NULL;
2307ca5ce89SRichard Gong p_data->chan->scl->receive_cb(p_data->chan->scl,
2317ca5ce89SRichard Gong cb_data);
2327ca5ce89SRichard Gong } else {
2337ca5ce89SRichard Gong pr_debug("%s: secure world busy, polling again\n",
2347ca5ce89SRichard Gong __func__);
2357ca5ce89SRichard Gong }
2367ca5ce89SRichard Gong } while (res.a0 == INTEL_SIP_SMC_STATUS_OK ||
2377536ad8dSRichard Gong res.a0 == INTEL_SIP_SMC_STATUS_BUSY ||
2387ca5ce89SRichard Gong wait_for_completion_timeout(&ctrl->complete_status, timeout));
2397ca5ce89SRichard Gong }
2407ca5ce89SRichard Gong
2417ca5ce89SRichard Gong /**
2427ca5ce89SRichard Gong * svc_thread_cmd_config_status() - check configuration status
2437ca5ce89SRichard Gong * @ctrl: pointer to service layer controller
2447ca5ce89SRichard Gong * @p_data: pointer to service data structure
2457ca5ce89SRichard Gong * @cb_data: pointer to callback data structure to service client
2467ca5ce89SRichard Gong *
2477ca5ce89SRichard Gong * Check whether the secure firmware at secure world has finished the FPGA
2487ca5ce89SRichard Gong * configuration, and then inform FPGA manager the configuration status.
2497ca5ce89SRichard Gong */
svc_thread_cmd_config_status(struct stratix10_svc_controller * ctrl,struct stratix10_svc_data * p_data,struct stratix10_svc_cb_data * cb_data)2507ca5ce89SRichard Gong static void svc_thread_cmd_config_status(struct stratix10_svc_controller *ctrl,
2517ca5ce89SRichard Gong struct stratix10_svc_data *p_data,
2527ca5ce89SRichard Gong struct stratix10_svc_cb_data *cb_data)
2537ca5ce89SRichard Gong {
2547ca5ce89SRichard Gong struct arm_smccc_res res;
2557ca5ce89SRichard Gong int count_in_sec;
25679b93625SAng Tien Sung unsigned long a0, a1, a2;
2577ca5ce89SRichard Gong
2587ca5ce89SRichard Gong cb_data->kaddr1 = NULL;
2597ca5ce89SRichard Gong cb_data->kaddr2 = NULL;
2607ca5ce89SRichard Gong cb_data->kaddr3 = NULL;
2617536ad8dSRichard Gong cb_data->status = BIT(SVC_STATUS_ERROR);
2627ca5ce89SRichard Gong
2637ca5ce89SRichard Gong pr_debug("%s: polling config status\n", __func__);
2647ca5ce89SRichard Gong
26579b93625SAng Tien Sung a0 = INTEL_SIP_SMC_FPGA_CONFIG_ISDONE;
26679b93625SAng Tien Sung a1 = (unsigned long)p_data->paddr;
26779b93625SAng Tien Sung a2 = (unsigned long)p_data->size;
26879b93625SAng Tien Sung
26979b93625SAng Tien Sung if (p_data->command == COMMAND_POLL_SERVICE_STATUS)
27079b93625SAng Tien Sung a0 = INTEL_SIP_SMC_SERVICE_COMPLETED;
27179b93625SAng Tien Sung
2727ca5ce89SRichard Gong count_in_sec = FPGA_CONFIG_STATUS_TIMEOUT_SEC;
2737ca5ce89SRichard Gong while (count_in_sec) {
27479b93625SAng Tien Sung ctrl->invoke_fn(a0, a1, a2, 0, 0, 0, 0, 0, &res);
2757ca5ce89SRichard Gong if ((res.a0 == INTEL_SIP_SMC_STATUS_OK) ||
27679b93625SAng Tien Sung (res.a0 == INTEL_SIP_SMC_STATUS_ERROR) ||
27779b93625SAng Tien Sung (res.a0 == INTEL_SIP_SMC_STATUS_REJECTED))
2787ca5ce89SRichard Gong break;
2797ca5ce89SRichard Gong
2807ca5ce89SRichard Gong /*
28179b93625SAng Tien Sung * request is still in progress, wait one second then
2827ca5ce89SRichard Gong * poll again
2837ca5ce89SRichard Gong */
2847ca5ce89SRichard Gong msleep(1000);
2857ca5ce89SRichard Gong count_in_sec--;
28603ddd2ebSzhengbin }
2877ca5ce89SRichard Gong
28879b93625SAng Tien Sung if (!count_in_sec) {
28979b93625SAng Tien Sung pr_err("%s: poll status timeout\n", __func__);
29079b93625SAng Tien Sung cb_data->status = BIT(SVC_STATUS_BUSY);
29179b93625SAng Tien Sung } else if (res.a0 == INTEL_SIP_SMC_STATUS_OK) {
2927536ad8dSRichard Gong cb_data->status = BIT(SVC_STATUS_COMPLETED);
29379b93625SAng Tien Sung cb_data->kaddr2 = (res.a2) ?
29479b93625SAng Tien Sung svc_pa_to_va(res.a2) : NULL;
29579b93625SAng Tien Sung cb_data->kaddr3 = (res.a3) ? &res.a3 : NULL;
29679b93625SAng Tien Sung } else {
29779b93625SAng Tien Sung pr_err("%s: poll status error\n", __func__);
29879b93625SAng Tien Sung cb_data->kaddr1 = &res.a1;
29979b93625SAng Tien Sung cb_data->kaddr2 = (res.a2) ?
30079b93625SAng Tien Sung svc_pa_to_va(res.a2) : NULL;
30179b93625SAng Tien Sung cb_data->kaddr3 = (res.a3) ? &res.a3 : NULL;
30279b93625SAng Tien Sung cb_data->status = BIT(SVC_STATUS_ERROR);
30379b93625SAng Tien Sung }
3047ca5ce89SRichard Gong
3057ca5ce89SRichard Gong p_data->chan->scl->receive_cb(p_data->chan->scl, cb_data);
3067ca5ce89SRichard Gong }
3077ca5ce89SRichard Gong
3087ca5ce89SRichard Gong /**
3097ca5ce89SRichard Gong * svc_thread_recv_status_ok() - handle the successful status
3107ca5ce89SRichard Gong * @p_data: pointer to service data structure
3117ca5ce89SRichard Gong * @cb_data: pointer to callback data structure to service client
3127ca5ce89SRichard Gong * @res: result from SMC or HVC call
3137ca5ce89SRichard Gong *
3146b50d882SRichard Gong * Send back the correspond status to the service clients.
3157ca5ce89SRichard Gong */
svc_thread_recv_status_ok(struct stratix10_svc_data * p_data,struct stratix10_svc_cb_data * cb_data,struct arm_smccc_res res)3167ca5ce89SRichard Gong static void svc_thread_recv_status_ok(struct stratix10_svc_data *p_data,
3177ca5ce89SRichard Gong struct stratix10_svc_cb_data *cb_data,
3187ca5ce89SRichard Gong struct arm_smccc_res res)
3197ca5ce89SRichard Gong {
3207ca5ce89SRichard Gong cb_data->kaddr1 = NULL;
3217ca5ce89SRichard Gong cb_data->kaddr2 = NULL;
3227ca5ce89SRichard Gong cb_data->kaddr3 = NULL;
3237ca5ce89SRichard Gong
3247ca5ce89SRichard Gong switch (p_data->command) {
3257ca5ce89SRichard Gong case COMMAND_RECONFIG:
3266b50d882SRichard Gong case COMMAND_RSU_UPDATE:
327b5dc75c9SRichard Gong case COMMAND_RSU_NOTIFY:
3284a4709d4SAng Tien Sung case COMMAND_FCS_REQUEST_SERVICE:
3294a4709d4SAng Tien Sung case COMMAND_FCS_SEND_CERTIFICATE:
3304a4709d4SAng Tien Sung case COMMAND_FCS_DATA_ENCRYPTION:
3314a4709d4SAng Tien Sung case COMMAND_FCS_DATA_DECRYPTION:
3327536ad8dSRichard Gong cb_data->status = BIT(SVC_STATUS_OK);
3337536ad8dSRichard Gong break;
3347536ad8dSRichard Gong case COMMAND_RECONFIG_DATA_SUBMIT:
3357536ad8dSRichard Gong cb_data->status = BIT(SVC_STATUS_BUFFER_SUBMITTED);
3367536ad8dSRichard Gong break;
3377536ad8dSRichard Gong case COMMAND_RECONFIG_STATUS:
3387536ad8dSRichard Gong cb_data->status = BIT(SVC_STATUS_COMPLETED);
3396b50d882SRichard Gong break;
340b5dc75c9SRichard Gong case COMMAND_RSU_RETRY:
341bf0e5bf6SRichard Gong case COMMAND_RSU_MAX_RETRY:
3421b4394c5SKah Jing Lee case COMMAND_RSU_DCMF_STATUS:
343085a8844SRichard Gong case COMMAND_FIRMWARE_VERSION:
3447536ad8dSRichard Gong cb_data->status = BIT(SVC_STATUS_OK);
345b5dc75c9SRichard Gong cb_data->kaddr1 = &res.a1;
346b5dc75c9SRichard Gong break;
3477935e899SAng Tien Sung case COMMAND_SMC_SVC_VERSION:
3487935e899SAng Tien Sung cb_data->status = BIT(SVC_STATUS_OK);
3497935e899SAng Tien Sung cb_data->kaddr1 = &res.a1;
3507935e899SAng Tien Sung cb_data->kaddr2 = &res.a2;
3517935e899SAng Tien Sung break;
352bf0e5bf6SRichard Gong case COMMAND_RSU_DCMF_VERSION:
353bf0e5bf6SRichard Gong cb_data->status = BIT(SVC_STATUS_OK);
354bf0e5bf6SRichard Gong cb_data->kaddr1 = &res.a1;
355bf0e5bf6SRichard Gong cb_data->kaddr2 = &res.a2;
356bf0e5bf6SRichard Gong break;
3574a4709d4SAng Tien Sung case COMMAND_FCS_RANDOM_NUMBER_GEN:
3584a4709d4SAng Tien Sung case COMMAND_FCS_GET_PROVISION_DATA:
3594a4709d4SAng Tien Sung case COMMAND_POLL_SERVICE_STATUS:
3604a4709d4SAng Tien Sung cb_data->status = BIT(SVC_STATUS_OK);
3614a4709d4SAng Tien Sung cb_data->kaddr1 = &res.a1;
3624a4709d4SAng Tien Sung cb_data->kaddr2 = svc_pa_to_va(res.a2);
3634a4709d4SAng Tien Sung cb_data->kaddr3 = &res.a3;
3644a4709d4SAng Tien Sung break;
365*34949a31STeh Wen Ping case COMMAND_MBOX_SEND_CMD:
366*34949a31STeh Wen Ping cb_data->status = BIT(SVC_STATUS_OK);
367*34949a31STeh Wen Ping cb_data->kaddr1 = &res.a1;
368*34949a31STeh Wen Ping /* SDM return size in u8. Convert size to u32 word */
369*34949a31STeh Wen Ping res.a2 = res.a2 * BYTE_TO_WORD_SIZE;
370*34949a31STeh Wen Ping cb_data->kaddr2 = &res.a2;
371*34949a31STeh Wen Ping break;
3727ca5ce89SRichard Gong default:
3737ca5ce89SRichard Gong pr_warn("it shouldn't happen\n");
3747ca5ce89SRichard Gong break;
3757ca5ce89SRichard Gong }
3767ca5ce89SRichard Gong
3777ca5ce89SRichard Gong pr_debug("%s: call receive_cb\n", __func__);
3787ca5ce89SRichard Gong p_data->chan->scl->receive_cb(p_data->chan->scl, cb_data);
3797ca5ce89SRichard Gong }
3807ca5ce89SRichard Gong
3817ca5ce89SRichard Gong /**
3827ca5ce89SRichard Gong * svc_normal_to_secure_thread() - the function to run in the kthread
3837ca5ce89SRichard Gong * @data: data pointer for kthread function
3847ca5ce89SRichard Gong *
3857ca5ce89SRichard Gong * Service layer driver creates stratix10_svc_smc_hvc_call kthread on CPU
3867ca5ce89SRichard Gong * node 0, its function stratix10_svc_secure_call_thread is used to handle
3877ca5ce89SRichard Gong * SMC or HVC calls between kernel driver and secure monitor software.
3887ca5ce89SRichard Gong *
3897ca5ce89SRichard Gong * Return: 0 for success or -ENOMEM on error.
3907ca5ce89SRichard Gong */
svc_normal_to_secure_thread(void * data)3917ca5ce89SRichard Gong static int svc_normal_to_secure_thread(void *data)
3927ca5ce89SRichard Gong {
3937ca5ce89SRichard Gong struct stratix10_svc_controller
3947ca5ce89SRichard Gong *ctrl = (struct stratix10_svc_controller *)data;
3957ca5ce89SRichard Gong struct stratix10_svc_data *pdata;
3967ca5ce89SRichard Gong struct stratix10_svc_cb_data *cbdata;
3977ca5ce89SRichard Gong struct arm_smccc_res res;
3984a4709d4SAng Tien Sung unsigned long a0, a1, a2, a3, a4, a5, a6, a7;
3997ca5ce89SRichard Gong int ret_fifo = 0;
4007ca5ce89SRichard Gong
4017ca5ce89SRichard Gong pdata = kmalloc(sizeof(*pdata), GFP_KERNEL);
4027ca5ce89SRichard Gong if (!pdata)
4037ca5ce89SRichard Gong return -ENOMEM;
4047ca5ce89SRichard Gong
4057ca5ce89SRichard Gong cbdata = kmalloc(sizeof(*cbdata), GFP_KERNEL);
4067ca5ce89SRichard Gong if (!cbdata) {
4077ca5ce89SRichard Gong kfree(pdata);
4087ca5ce89SRichard Gong return -ENOMEM;
4097ca5ce89SRichard Gong }
4107ca5ce89SRichard Gong
4117ca5ce89SRichard Gong /* default set, to remove build warning */
4127ca5ce89SRichard Gong a0 = INTEL_SIP_SMC_FPGA_CONFIG_LOOPBACK;
4137ca5ce89SRichard Gong a1 = 0;
4147ca5ce89SRichard Gong a2 = 0;
4154a4709d4SAng Tien Sung a3 = 0;
4164a4709d4SAng Tien Sung a4 = 0;
4174a4709d4SAng Tien Sung a5 = 0;
4184a4709d4SAng Tien Sung a6 = 0;
4194a4709d4SAng Tien Sung a7 = 0;
4207ca5ce89SRichard Gong
4217ca5ce89SRichard Gong pr_debug("smc_hvc_shm_thread is running\n");
4227ca5ce89SRichard Gong
4237ca5ce89SRichard Gong while (!kthread_should_stop()) {
4247ca5ce89SRichard Gong ret_fifo = kfifo_out_spinlocked(&ctrl->svc_fifo,
4257ca5ce89SRichard Gong pdata, sizeof(*pdata),
4267ca5ce89SRichard Gong &ctrl->svc_fifo_lock);
4277ca5ce89SRichard Gong
4287ca5ce89SRichard Gong if (!ret_fifo)
4297ca5ce89SRichard Gong continue;
4307ca5ce89SRichard Gong
4317ca5ce89SRichard Gong pr_debug("get from FIFO pa=0x%016x, command=%u, size=%u\n",
4327ca5ce89SRichard Gong (unsigned int)pdata->paddr, pdata->command,
4337ca5ce89SRichard Gong (unsigned int)pdata->size);
4347ca5ce89SRichard Gong
4357ca5ce89SRichard Gong switch (pdata->command) {
4367ca5ce89SRichard Gong case COMMAND_RECONFIG_DATA_CLAIM:
4377ca5ce89SRichard Gong svc_thread_cmd_data_claim(ctrl, pdata, cbdata);
4387ca5ce89SRichard Gong continue;
4397ca5ce89SRichard Gong case COMMAND_RECONFIG:
4407ca5ce89SRichard Gong a0 = INTEL_SIP_SMC_FPGA_CONFIG_START;
4417ca5ce89SRichard Gong pr_debug("conf_type=%u\n", (unsigned int)pdata->flag);
4427ca5ce89SRichard Gong a1 = pdata->flag;
4437ca5ce89SRichard Gong a2 = 0;
4447ca5ce89SRichard Gong break;
4457ca5ce89SRichard Gong case COMMAND_RECONFIG_DATA_SUBMIT:
4467ca5ce89SRichard Gong a0 = INTEL_SIP_SMC_FPGA_CONFIG_WRITE;
4477ca5ce89SRichard Gong a1 = (unsigned long)pdata->paddr;
4487ca5ce89SRichard Gong a2 = (unsigned long)pdata->size;
4497ca5ce89SRichard Gong break;
4507ca5ce89SRichard Gong case COMMAND_RECONFIG_STATUS:
4517ca5ce89SRichard Gong a0 = INTEL_SIP_SMC_FPGA_CONFIG_ISDONE;
4527ca5ce89SRichard Gong a1 = 0;
4537ca5ce89SRichard Gong a2 = 0;
4547ca5ce89SRichard Gong break;
4556b50d882SRichard Gong case COMMAND_RSU_STATUS:
4566b50d882SRichard Gong a0 = INTEL_SIP_SMC_RSU_STATUS;
4576b50d882SRichard Gong a1 = 0;
4586b50d882SRichard Gong a2 = 0;
4596b50d882SRichard Gong break;
4606b50d882SRichard Gong case COMMAND_RSU_UPDATE:
4616b50d882SRichard Gong a0 = INTEL_SIP_SMC_RSU_UPDATE;
4626b50d882SRichard Gong a1 = pdata->arg[0];
4636b50d882SRichard Gong a2 = 0;
4646b50d882SRichard Gong break;
465b5dc75c9SRichard Gong case COMMAND_RSU_NOTIFY:
466b5dc75c9SRichard Gong a0 = INTEL_SIP_SMC_RSU_NOTIFY;
467b5dc75c9SRichard Gong a1 = pdata->arg[0];
468b5dc75c9SRichard Gong a2 = 0;
469b5dc75c9SRichard Gong break;
470b5dc75c9SRichard Gong case COMMAND_RSU_RETRY:
471b5dc75c9SRichard Gong a0 = INTEL_SIP_SMC_RSU_RETRY_COUNTER;
472b5dc75c9SRichard Gong a1 = 0;
473b5dc75c9SRichard Gong a2 = 0;
474b5dc75c9SRichard Gong break;
475bf0e5bf6SRichard Gong case COMMAND_RSU_MAX_RETRY:
476bf0e5bf6SRichard Gong a0 = INTEL_SIP_SMC_RSU_MAX_RETRY;
477bf0e5bf6SRichard Gong a1 = 0;
478bf0e5bf6SRichard Gong a2 = 0;
479bf0e5bf6SRichard Gong break;
480bf0e5bf6SRichard Gong case COMMAND_RSU_DCMF_VERSION:
481bf0e5bf6SRichard Gong a0 = INTEL_SIP_SMC_RSU_DCMF_VERSION;
482bf0e5bf6SRichard Gong a1 = 0;
483bf0e5bf6SRichard Gong a2 = 0;
484bf0e5bf6SRichard Gong break;
485085a8844SRichard Gong case COMMAND_FIRMWARE_VERSION:
486085a8844SRichard Gong a0 = INTEL_SIP_SMC_FIRMWARE_VERSION;
487085a8844SRichard Gong a1 = 0;
488085a8844SRichard Gong a2 = 0;
489085a8844SRichard Gong break;
4904a4709d4SAng Tien Sung
4914a4709d4SAng Tien Sung /* for FCS */
4924a4709d4SAng Tien Sung case COMMAND_FCS_DATA_ENCRYPTION:
4934a4709d4SAng Tien Sung a0 = INTEL_SIP_SMC_FCS_CRYPTION;
4944a4709d4SAng Tien Sung a1 = 1;
4954a4709d4SAng Tien Sung a2 = (unsigned long)pdata->paddr;
4964a4709d4SAng Tien Sung a3 = (unsigned long)pdata->size;
4974a4709d4SAng Tien Sung a4 = (unsigned long)pdata->paddr_output;
4984a4709d4SAng Tien Sung a5 = (unsigned long)pdata->size_output;
4994a4709d4SAng Tien Sung break;
5004a4709d4SAng Tien Sung case COMMAND_FCS_DATA_DECRYPTION:
5014a4709d4SAng Tien Sung a0 = INTEL_SIP_SMC_FCS_CRYPTION;
5024a4709d4SAng Tien Sung a1 = 0;
5034a4709d4SAng Tien Sung a2 = (unsigned long)pdata->paddr;
5044a4709d4SAng Tien Sung a3 = (unsigned long)pdata->size;
5054a4709d4SAng Tien Sung a4 = (unsigned long)pdata->paddr_output;
5064a4709d4SAng Tien Sung a5 = (unsigned long)pdata->size_output;
5074a4709d4SAng Tien Sung break;
5084a4709d4SAng Tien Sung case COMMAND_FCS_RANDOM_NUMBER_GEN:
5094a4709d4SAng Tien Sung a0 = INTEL_SIP_SMC_FCS_RANDOM_NUMBER;
5104a4709d4SAng Tien Sung a1 = (unsigned long)pdata->paddr;
5114a4709d4SAng Tien Sung a2 = 0;
5124a4709d4SAng Tien Sung break;
5134a4709d4SAng Tien Sung case COMMAND_FCS_REQUEST_SERVICE:
5144a4709d4SAng Tien Sung a0 = INTEL_SIP_SMC_FCS_SERVICE_REQUEST;
5154a4709d4SAng Tien Sung a1 = (unsigned long)pdata->paddr;
5164a4709d4SAng Tien Sung a2 = (unsigned long)pdata->size;
5174a4709d4SAng Tien Sung break;
5184a4709d4SAng Tien Sung case COMMAND_FCS_SEND_CERTIFICATE:
5194a4709d4SAng Tien Sung a0 = INTEL_SIP_SMC_FCS_SEND_CERTIFICATE;
5204a4709d4SAng Tien Sung a1 = (unsigned long)pdata->paddr;
5214a4709d4SAng Tien Sung a2 = (unsigned long)pdata->size;
5224a4709d4SAng Tien Sung break;
5234a4709d4SAng Tien Sung case COMMAND_FCS_GET_PROVISION_DATA:
5244a4709d4SAng Tien Sung a0 = INTEL_SIP_SMC_FCS_GET_PROVISION_DATA;
5254a4709d4SAng Tien Sung a1 = (unsigned long)pdata->paddr;
5264a4709d4SAng Tien Sung a2 = 0;
5274a4709d4SAng Tien Sung break;
5284a4709d4SAng Tien Sung
52979b93625SAng Tien Sung /* for polling */
53079b93625SAng Tien Sung case COMMAND_POLL_SERVICE_STATUS:
53179b93625SAng Tien Sung a0 = INTEL_SIP_SMC_SERVICE_COMPLETED;
53279b93625SAng Tien Sung a1 = (unsigned long)pdata->paddr;
53379b93625SAng Tien Sung a2 = (unsigned long)pdata->size;
53479b93625SAng Tien Sung break;
5351b4394c5SKah Jing Lee case COMMAND_RSU_DCMF_STATUS:
5361b4394c5SKah Jing Lee a0 = INTEL_SIP_SMC_RSU_DCMF_STATUS;
5371b4394c5SKah Jing Lee a1 = 0;
5381b4394c5SKah Jing Lee a2 = 0;
5391b4394c5SKah Jing Lee break;
5407935e899SAng Tien Sung case COMMAND_SMC_SVC_VERSION:
5417935e899SAng Tien Sung a0 = INTEL_SIP_SMC_SVC_VERSION;
5427935e899SAng Tien Sung a1 = 0;
5437935e899SAng Tien Sung a2 = 0;
5447935e899SAng Tien Sung break;
545*34949a31STeh Wen Ping case COMMAND_MBOX_SEND_CMD:
546*34949a31STeh Wen Ping a0 = INTEL_SIP_SMC_MBOX_SEND_CMD;
547*34949a31STeh Wen Ping a1 = pdata->arg[0];
548*34949a31STeh Wen Ping a2 = (unsigned long)pdata->paddr;
549*34949a31STeh Wen Ping a3 = (unsigned long)pdata->size / BYTE_TO_WORD_SIZE;
550*34949a31STeh Wen Ping a4 = pdata->arg[1];
551*34949a31STeh Wen Ping a5 = (unsigned long)pdata->paddr_output;
552*34949a31STeh Wen Ping a6 = (unsigned long)pdata->size_output / BYTE_TO_WORD_SIZE;
553*34949a31STeh Wen Ping break;
5547ca5ce89SRichard Gong default:
5557ca5ce89SRichard Gong pr_warn("it shouldn't happen\n");
5567ca5ce89SRichard Gong break;
5577ca5ce89SRichard Gong }
5587ca5ce89SRichard Gong pr_debug("%s: before SMC call -- a0=0x%016x a1=0x%016x",
5594a4709d4SAng Tien Sung __func__,
5604a4709d4SAng Tien Sung (unsigned int)a0,
5614a4709d4SAng Tien Sung (unsigned int)a1);
5627ca5ce89SRichard Gong pr_debug(" a2=0x%016x\n", (unsigned int)a2);
5634a4709d4SAng Tien Sung pr_debug(" a3=0x%016x\n", (unsigned int)a3);
5644a4709d4SAng Tien Sung pr_debug(" a4=0x%016x\n", (unsigned int)a4);
5654a4709d4SAng Tien Sung pr_debug(" a5=0x%016x\n", (unsigned int)a5);
5664a4709d4SAng Tien Sung ctrl->invoke_fn(a0, a1, a2, a3, a4, a5, a6, a7, &res);
5677ca5ce89SRichard Gong
5687ca5ce89SRichard Gong pr_debug("%s: after SMC call -- res.a0=0x%016x",
5697ca5ce89SRichard Gong __func__, (unsigned int)res.a0);
5707ca5ce89SRichard Gong pr_debug(" res.a1=0x%016x, res.a2=0x%016x",
5717ca5ce89SRichard Gong (unsigned int)res.a1, (unsigned int)res.a2);
5727ca5ce89SRichard Gong pr_debug(" res.a3=0x%016x\n", (unsigned int)res.a3);
5737ca5ce89SRichard Gong
5746b50d882SRichard Gong if (pdata->command == COMMAND_RSU_STATUS) {
5756b50d882SRichard Gong if (res.a0 == INTEL_SIP_SMC_RSU_ERROR)
5767536ad8dSRichard Gong cbdata->status = BIT(SVC_STATUS_ERROR);
5776b50d882SRichard Gong else
5787536ad8dSRichard Gong cbdata->status = BIT(SVC_STATUS_OK);
5796b50d882SRichard Gong
5806b50d882SRichard Gong cbdata->kaddr1 = &res;
5816b50d882SRichard Gong cbdata->kaddr2 = NULL;
5826b50d882SRichard Gong cbdata->kaddr3 = NULL;
5836b50d882SRichard Gong pdata->chan->scl->receive_cb(pdata->chan->scl, cbdata);
5846b50d882SRichard Gong continue;
5856b50d882SRichard Gong }
5866b50d882SRichard Gong
5877ca5ce89SRichard Gong switch (res.a0) {
5887ca5ce89SRichard Gong case INTEL_SIP_SMC_STATUS_OK:
5897ca5ce89SRichard Gong svc_thread_recv_status_ok(pdata, cbdata, res);
5907ca5ce89SRichard Gong break;
5917536ad8dSRichard Gong case INTEL_SIP_SMC_STATUS_BUSY:
5927ca5ce89SRichard Gong switch (pdata->command) {
5937ca5ce89SRichard Gong case COMMAND_RECONFIG_DATA_SUBMIT:
5947ca5ce89SRichard Gong svc_thread_cmd_data_claim(ctrl,
5957ca5ce89SRichard Gong pdata, cbdata);
5967ca5ce89SRichard Gong break;
5977ca5ce89SRichard Gong case COMMAND_RECONFIG_STATUS:
59879b93625SAng Tien Sung case COMMAND_POLL_SERVICE_STATUS:
5997ca5ce89SRichard Gong svc_thread_cmd_config_status(ctrl,
6007ca5ce89SRichard Gong pdata, cbdata);
6017ca5ce89SRichard Gong break;
6027ca5ce89SRichard Gong default:
6037ca5ce89SRichard Gong pr_warn("it shouldn't happen\n");
6047ca5ce89SRichard Gong break;
6057ca5ce89SRichard Gong }
6067ca5ce89SRichard Gong break;
6077536ad8dSRichard Gong case INTEL_SIP_SMC_STATUS_REJECTED:
6087ca5ce89SRichard Gong pr_debug("%s: STATUS_REJECTED\n", __func__);
6094a4709d4SAng Tien Sung /* for FCS */
6104a4709d4SAng Tien Sung switch (pdata->command) {
6114a4709d4SAng Tien Sung case COMMAND_FCS_REQUEST_SERVICE:
6124a4709d4SAng Tien Sung case COMMAND_FCS_SEND_CERTIFICATE:
6134a4709d4SAng Tien Sung case COMMAND_FCS_GET_PROVISION_DATA:
6144a4709d4SAng Tien Sung case COMMAND_FCS_DATA_ENCRYPTION:
6154a4709d4SAng Tien Sung case COMMAND_FCS_DATA_DECRYPTION:
6164a4709d4SAng Tien Sung case COMMAND_FCS_RANDOM_NUMBER_GEN:
617*34949a31STeh Wen Ping case COMMAND_MBOX_SEND_CMD:
6184a4709d4SAng Tien Sung cbdata->status = BIT(SVC_STATUS_INVALID_PARAM);
6194a4709d4SAng Tien Sung cbdata->kaddr1 = NULL;
6204a4709d4SAng Tien Sung cbdata->kaddr2 = NULL;
6214a4709d4SAng Tien Sung cbdata->kaddr3 = NULL;
6224a4709d4SAng Tien Sung pdata->chan->scl->receive_cb(pdata->chan->scl,
6234a4709d4SAng Tien Sung cbdata);
6244a4709d4SAng Tien Sung break;
6254a4709d4SAng Tien Sung }
6267ca5ce89SRichard Gong break;
6277536ad8dSRichard Gong case INTEL_SIP_SMC_STATUS_ERROR:
628b5dc75c9SRichard Gong case INTEL_SIP_SMC_RSU_ERROR:
6297ca5ce89SRichard Gong pr_err("%s: STATUS_ERROR\n", __func__);
6307536ad8dSRichard Gong cbdata->status = BIT(SVC_STATUS_ERROR);
631b850b7a8SAng Tien Sung cbdata->kaddr1 = &res.a1;
6321b4394c5SKah Jing Lee cbdata->kaddr2 = (res.a2) ?
6331b4394c5SKah Jing Lee svc_pa_to_va(res.a2) : NULL;
6341b4394c5SKah Jing Lee cbdata->kaddr3 = (res.a3) ? &res.a3 : NULL;
6357ca5ce89SRichard Gong pdata->chan->scl->receive_cb(pdata->chan->scl, cbdata);
6367ca5ce89SRichard Gong break;
6377ca5ce89SRichard Gong default:
638e9cb0497SRichard Gong pr_warn("Secure firmware doesn't support...\n");
639e9cb0497SRichard Gong
640e9cb0497SRichard Gong /*
641e9cb0497SRichard Gong * be compatible with older version firmware which
6421b4394c5SKah Jing Lee * doesn't support newer RSU commands
643e9cb0497SRichard Gong */
6441b4394c5SKah Jing Lee if ((pdata->command != COMMAND_RSU_UPDATE) &&
6451b4394c5SKah Jing Lee (pdata->command != COMMAND_RSU_STATUS)) {
646e9cb0497SRichard Gong cbdata->status =
6477536ad8dSRichard Gong BIT(SVC_STATUS_NO_SUPPORT);
648e9cb0497SRichard Gong cbdata->kaddr1 = NULL;
649e9cb0497SRichard Gong cbdata->kaddr2 = NULL;
650e9cb0497SRichard Gong cbdata->kaddr3 = NULL;
651e9cb0497SRichard Gong pdata->chan->scl->receive_cb(
652e9cb0497SRichard Gong pdata->chan->scl, cbdata);
653e9cb0497SRichard Gong }
6547ca5ce89SRichard Gong break;
655e9cb0497SRichard Gong
6567ca5ce89SRichard Gong }
65703ddd2ebSzhengbin }
6587ca5ce89SRichard Gong
6597ca5ce89SRichard Gong kfree(cbdata);
6607ca5ce89SRichard Gong kfree(pdata);
6617ca5ce89SRichard Gong
6627ca5ce89SRichard Gong return 0;
6637ca5ce89SRichard Gong }
6647ca5ce89SRichard Gong
6657ca5ce89SRichard Gong /**
6667ca5ce89SRichard Gong * svc_normal_to_secure_shm_thread() - the function to run in the kthread
6677ca5ce89SRichard Gong * @data: data pointer for kthread function
6687ca5ce89SRichard Gong *
6697ca5ce89SRichard Gong * Service layer driver creates stratix10_svc_smc_hvc_shm kthread on CPU
6707ca5ce89SRichard Gong * node 0, its function stratix10_svc_secure_shm_thread is used to query the
6717ca5ce89SRichard Gong * physical address of memory block reserved by secure monitor software at
6727ca5ce89SRichard Gong * secure world.
6737ca5ce89SRichard Gong *
674111e7049SEric W. Biederman * svc_normal_to_secure_shm_thread() terminates directly since it is a
6757ca5ce89SRichard Gong * standlone thread for which no one will call kthread_stop() or return when
6767ca5ce89SRichard Gong * 'kthread_should_stop()' is true.
6777ca5ce89SRichard Gong */
svc_normal_to_secure_shm_thread(void * data)6787ca5ce89SRichard Gong static int svc_normal_to_secure_shm_thread(void *data)
6797ca5ce89SRichard Gong {
6807ca5ce89SRichard Gong struct stratix10_svc_sh_memory
6817ca5ce89SRichard Gong *sh_mem = (struct stratix10_svc_sh_memory *)data;
6827ca5ce89SRichard Gong struct arm_smccc_res res;
6837ca5ce89SRichard Gong
6847ca5ce89SRichard Gong /* SMC or HVC call to get shared memory info from secure world */
6857ca5ce89SRichard Gong sh_mem->invoke_fn(INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM,
6867ca5ce89SRichard Gong 0, 0, 0, 0, 0, 0, 0, &res);
6877ca5ce89SRichard Gong if (res.a0 == INTEL_SIP_SMC_STATUS_OK) {
6887ca5ce89SRichard Gong sh_mem->addr = res.a1;
6897ca5ce89SRichard Gong sh_mem->size = res.a2;
6907ca5ce89SRichard Gong } else {
6917ca5ce89SRichard Gong pr_err("%s: after SMC call -- res.a0=0x%016x", __func__,
6927ca5ce89SRichard Gong (unsigned int)res.a0);
6937ca5ce89SRichard Gong sh_mem->addr = 0;
6947ca5ce89SRichard Gong sh_mem->size = 0;
6957ca5ce89SRichard Gong }
6967ca5ce89SRichard Gong
6977ca5ce89SRichard Gong complete(&sh_mem->sync_complete);
698111e7049SEric W. Biederman return 0;
6997ca5ce89SRichard Gong }
7007ca5ce89SRichard Gong
7017ca5ce89SRichard Gong /**
7027ca5ce89SRichard Gong * svc_get_sh_memory() - get memory block reserved by secure monitor SW
7037ca5ce89SRichard Gong * @pdev: pointer to service layer device
7047ca5ce89SRichard Gong * @sh_memory: pointer to service shared memory structure
7057ca5ce89SRichard Gong *
7067ca5ce89SRichard Gong * Return: zero for successfully getting the physical address of memory block
7077ca5ce89SRichard Gong * reserved by secure monitor software, or negative value on error.
7087ca5ce89SRichard Gong */
svc_get_sh_memory(struct platform_device * pdev,struct stratix10_svc_sh_memory * sh_memory)7097ca5ce89SRichard Gong static int svc_get_sh_memory(struct platform_device *pdev,
7107ca5ce89SRichard Gong struct stratix10_svc_sh_memory *sh_memory)
7117ca5ce89SRichard Gong {
7127ca5ce89SRichard Gong struct device *dev = &pdev->dev;
7137ca5ce89SRichard Gong struct task_struct *sh_memory_task;
7147ca5ce89SRichard Gong unsigned int cpu = 0;
7157ca5ce89SRichard Gong
7167ca5ce89SRichard Gong init_completion(&sh_memory->sync_complete);
7177ca5ce89SRichard Gong
7187ca5ce89SRichard Gong /* smc or hvc call happens on cpu 0 bound kthread */
7197ca5ce89SRichard Gong sh_memory_task = kthread_create_on_node(svc_normal_to_secure_shm_thread,
7207ca5ce89SRichard Gong (void *)sh_memory,
7217ca5ce89SRichard Gong cpu_to_node(cpu),
7227ca5ce89SRichard Gong "svc_smc_hvc_shm_thread");
7237ca5ce89SRichard Gong if (IS_ERR(sh_memory_task)) {
7247ca5ce89SRichard Gong dev_err(dev, "fail to create stratix10_svc_smc_shm_thread\n");
7257ca5ce89SRichard Gong return -EINVAL;
7267ca5ce89SRichard Gong }
7277ca5ce89SRichard Gong
7287ca5ce89SRichard Gong wake_up_process(sh_memory_task);
7297ca5ce89SRichard Gong
7307ca5ce89SRichard Gong if (!wait_for_completion_timeout(&sh_memory->sync_complete, 10 * HZ)) {
7317ca5ce89SRichard Gong dev_err(dev,
7327ca5ce89SRichard Gong "timeout to get sh-memory paras from secure world\n");
7337ca5ce89SRichard Gong return -ETIMEDOUT;
7347ca5ce89SRichard Gong }
7357ca5ce89SRichard Gong
7367ca5ce89SRichard Gong if (!sh_memory->addr || !sh_memory->size) {
7377ca5ce89SRichard Gong dev_err(dev,
738b5dc75c9SRichard Gong "failed to get shared memory info from secure world\n");
7397ca5ce89SRichard Gong return -ENOMEM;
7407ca5ce89SRichard Gong }
7417ca5ce89SRichard Gong
7427ca5ce89SRichard Gong dev_dbg(dev, "SM software provides paddr: 0x%016x, size: 0x%08x\n",
7437ca5ce89SRichard Gong (unsigned int)sh_memory->addr,
7447ca5ce89SRichard Gong (unsigned int)sh_memory->size);
7457ca5ce89SRichard Gong
7467ca5ce89SRichard Gong return 0;
7477ca5ce89SRichard Gong }
7487ca5ce89SRichard Gong
7497ca5ce89SRichard Gong /**
7507ca5ce89SRichard Gong * svc_create_memory_pool() - create a memory pool from reserved memory block
7517ca5ce89SRichard Gong * @pdev: pointer to service layer device
7527ca5ce89SRichard Gong * @sh_memory: pointer to service shared memory structure
7537ca5ce89SRichard Gong *
7547ca5ce89SRichard Gong * Return: pool allocated from reserved memory block or ERR_PTR() on error.
7557ca5ce89SRichard Gong */
7567ca5ce89SRichard Gong static struct gen_pool *
svc_create_memory_pool(struct platform_device * pdev,struct stratix10_svc_sh_memory * sh_memory)7577ca5ce89SRichard Gong svc_create_memory_pool(struct platform_device *pdev,
7587ca5ce89SRichard Gong struct stratix10_svc_sh_memory *sh_memory)
7597ca5ce89SRichard Gong {
7607ca5ce89SRichard Gong struct device *dev = &pdev->dev;
7617ca5ce89SRichard Gong struct gen_pool *genpool;
7627ca5ce89SRichard Gong unsigned long vaddr;
7637ca5ce89SRichard Gong phys_addr_t paddr;
7647ca5ce89SRichard Gong size_t size;
7657ca5ce89SRichard Gong phys_addr_t begin;
7667ca5ce89SRichard Gong phys_addr_t end;
7677ca5ce89SRichard Gong void *va;
7687ca5ce89SRichard Gong size_t page_mask = PAGE_SIZE - 1;
7697ca5ce89SRichard Gong int min_alloc_order = 3;
7707ca5ce89SRichard Gong int ret;
7717ca5ce89SRichard Gong
7727ca5ce89SRichard Gong begin = roundup(sh_memory->addr, PAGE_SIZE);
7737ca5ce89SRichard Gong end = rounddown(sh_memory->addr + sh_memory->size, PAGE_SIZE);
7747ca5ce89SRichard Gong paddr = begin;
7757ca5ce89SRichard Gong size = end - begin;
7761995f155SChristophe JAILLET va = devm_memremap(dev, paddr, size, MEMREMAP_WC);
777dd218433SWang Ming if (IS_ERR(va)) {
7787ca5ce89SRichard Gong dev_err(dev, "fail to remap shared memory\n");
7797ca5ce89SRichard Gong return ERR_PTR(-EINVAL);
7807ca5ce89SRichard Gong }
7817ca5ce89SRichard Gong vaddr = (unsigned long)va;
7827ca5ce89SRichard Gong dev_dbg(dev,
7837ca5ce89SRichard Gong "reserved memory vaddr: %p, paddr: 0x%16x size: 0x%8x\n",
7847ca5ce89SRichard Gong va, (unsigned int)paddr, (unsigned int)size);
7857ca5ce89SRichard Gong if ((vaddr & page_mask) || (paddr & page_mask) ||
7867ca5ce89SRichard Gong (size & page_mask)) {
7877ca5ce89SRichard Gong dev_err(dev, "page is not aligned\n");
7887ca5ce89SRichard Gong return ERR_PTR(-EINVAL);
7897ca5ce89SRichard Gong }
7907ca5ce89SRichard Gong genpool = gen_pool_create(min_alloc_order, -1);
7917ca5ce89SRichard Gong if (!genpool) {
7927ca5ce89SRichard Gong dev_err(dev, "fail to create genpool\n");
7937ca5ce89SRichard Gong return ERR_PTR(-ENOMEM);
7947ca5ce89SRichard Gong }
7957ca5ce89SRichard Gong gen_pool_set_algo(genpool, gen_pool_best_fit, NULL);
7967ca5ce89SRichard Gong ret = gen_pool_add_virt(genpool, vaddr, paddr, size, -1);
7977ca5ce89SRichard Gong if (ret) {
7987ca5ce89SRichard Gong dev_err(dev, "fail to add memory chunk to the pool\n");
7997ca5ce89SRichard Gong gen_pool_destroy(genpool);
8007ca5ce89SRichard Gong return ERR_PTR(ret);
8017ca5ce89SRichard Gong }
8027ca5ce89SRichard Gong
8037ca5ce89SRichard Gong return genpool;
8047ca5ce89SRichard Gong }
8057ca5ce89SRichard Gong
8067ca5ce89SRichard Gong /**
8077ca5ce89SRichard Gong * svc_smccc_smc() - secure monitor call between normal and secure world
8087ca5ce89SRichard Gong * @a0: argument passed in registers 0
8097ca5ce89SRichard Gong * @a1: argument passed in registers 1
8107ca5ce89SRichard Gong * @a2: argument passed in registers 2
8117ca5ce89SRichard Gong * @a3: argument passed in registers 3
8127ca5ce89SRichard Gong * @a4: argument passed in registers 4
8137ca5ce89SRichard Gong * @a5: argument passed in registers 5
8147ca5ce89SRichard Gong * @a6: argument passed in registers 6
8157ca5ce89SRichard Gong * @a7: argument passed in registers 7
8167ca5ce89SRichard Gong * @res: result values from register 0 to 3
8177ca5ce89SRichard Gong */
svc_smccc_smc(unsigned long a0,unsigned long a1,unsigned long a2,unsigned long a3,unsigned long a4,unsigned long a5,unsigned long a6,unsigned long a7,struct arm_smccc_res * res)8187ca5ce89SRichard Gong static void svc_smccc_smc(unsigned long a0, unsigned long a1,
8197ca5ce89SRichard Gong unsigned long a2, unsigned long a3,
8207ca5ce89SRichard Gong unsigned long a4, unsigned long a5,
8217ca5ce89SRichard Gong unsigned long a6, unsigned long a7,
8227ca5ce89SRichard Gong struct arm_smccc_res *res)
8237ca5ce89SRichard Gong {
8247ca5ce89SRichard Gong arm_smccc_smc(a0, a1, a2, a3, a4, a5, a6, a7, res);
8257ca5ce89SRichard Gong }
8267ca5ce89SRichard Gong
8277ca5ce89SRichard Gong /**
8287ca5ce89SRichard Gong * svc_smccc_hvc() - hypervisor call between normal and secure world
8297ca5ce89SRichard Gong * @a0: argument passed in registers 0
8307ca5ce89SRichard Gong * @a1: argument passed in registers 1
8317ca5ce89SRichard Gong * @a2: argument passed in registers 2
8327ca5ce89SRichard Gong * @a3: argument passed in registers 3
8337ca5ce89SRichard Gong * @a4: argument passed in registers 4
8347ca5ce89SRichard Gong * @a5: argument passed in registers 5
8357ca5ce89SRichard Gong * @a6: argument passed in registers 6
8367ca5ce89SRichard Gong * @a7: argument passed in registers 7
8377ca5ce89SRichard Gong * @res: result values from register 0 to 3
8387ca5ce89SRichard Gong */
svc_smccc_hvc(unsigned long a0,unsigned long a1,unsigned long a2,unsigned long a3,unsigned long a4,unsigned long a5,unsigned long a6,unsigned long a7,struct arm_smccc_res * res)8397ca5ce89SRichard Gong static void svc_smccc_hvc(unsigned long a0, unsigned long a1,
8407ca5ce89SRichard Gong unsigned long a2, unsigned long a3,
8417ca5ce89SRichard Gong unsigned long a4, unsigned long a5,
8427ca5ce89SRichard Gong unsigned long a6, unsigned long a7,
8437ca5ce89SRichard Gong struct arm_smccc_res *res)
8447ca5ce89SRichard Gong {
8457ca5ce89SRichard Gong arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res);
8467ca5ce89SRichard Gong }
8477ca5ce89SRichard Gong
8487ca5ce89SRichard Gong /**
8497ca5ce89SRichard Gong * get_invoke_func() - invoke SMC or HVC call
8507ca5ce89SRichard Gong * @dev: pointer to device
8517ca5ce89SRichard Gong *
8527ca5ce89SRichard Gong * Return: function pointer to svc_smccc_smc or svc_smccc_hvc.
8537ca5ce89SRichard Gong */
get_invoke_func(struct device * dev)8547ca5ce89SRichard Gong static svc_invoke_fn *get_invoke_func(struct device *dev)
8557ca5ce89SRichard Gong {
8567ca5ce89SRichard Gong const char *method;
8577ca5ce89SRichard Gong
8587ca5ce89SRichard Gong if (of_property_read_string(dev->of_node, "method", &method)) {
8597ca5ce89SRichard Gong dev_warn(dev, "missing \"method\" property\n");
8607ca5ce89SRichard Gong return ERR_PTR(-ENXIO);
8617ca5ce89SRichard Gong }
8627ca5ce89SRichard Gong
8637ca5ce89SRichard Gong if (!strcmp(method, "smc"))
8647ca5ce89SRichard Gong return svc_smccc_smc;
8657ca5ce89SRichard Gong if (!strcmp(method, "hvc"))
8667ca5ce89SRichard Gong return svc_smccc_hvc;
8677ca5ce89SRichard Gong
8687ca5ce89SRichard Gong dev_warn(dev, "invalid \"method\" property: %s\n", method);
8697ca5ce89SRichard Gong
8707ca5ce89SRichard Gong return ERR_PTR(-EINVAL);
8717ca5ce89SRichard Gong }
8727ca5ce89SRichard Gong
8737ca5ce89SRichard Gong /**
8747ca5ce89SRichard Gong * stratix10_svc_request_channel_byname() - request a service channel
8757ca5ce89SRichard Gong * @client: pointer to service client
8767ca5ce89SRichard Gong * @name: service client name
8777ca5ce89SRichard Gong *
8787ca5ce89SRichard Gong * This function is used by service client to request a service channel.
8797ca5ce89SRichard Gong *
8807ca5ce89SRichard Gong * Return: a pointer to channel assigned to the client on success,
8817ca5ce89SRichard Gong * or ERR_PTR() on error.
8827ca5ce89SRichard Gong */
stratix10_svc_request_channel_byname(struct stratix10_svc_client * client,const char * name)8837ca5ce89SRichard Gong struct stratix10_svc_chan *stratix10_svc_request_channel_byname(
8847ca5ce89SRichard Gong struct stratix10_svc_client *client, const char *name)
8857ca5ce89SRichard Gong {
8867ca5ce89SRichard Gong struct device *dev = client->dev;
8877ca5ce89SRichard Gong struct stratix10_svc_controller *controller;
8887ca5ce89SRichard Gong struct stratix10_svc_chan *chan = NULL;
8897ca5ce89SRichard Gong unsigned long flag;
8907ca5ce89SRichard Gong int i;
8917ca5ce89SRichard Gong
8927ca5ce89SRichard Gong /* if probe was called after client's, or error on probe */
8937ca5ce89SRichard Gong if (list_empty(&svc_ctrl))
8947ca5ce89SRichard Gong return ERR_PTR(-EPROBE_DEFER);
8957ca5ce89SRichard Gong
8967ca5ce89SRichard Gong controller = list_first_entry(&svc_ctrl,
8977ca5ce89SRichard Gong struct stratix10_svc_controller, node);
8987ca5ce89SRichard Gong for (i = 0; i < SVC_NUM_CHANNEL; i++) {
8997ca5ce89SRichard Gong if (!strcmp(controller->chans[i].name, name)) {
9007ca5ce89SRichard Gong chan = &controller->chans[i];
9017ca5ce89SRichard Gong break;
9027ca5ce89SRichard Gong }
9037ca5ce89SRichard Gong }
9047ca5ce89SRichard Gong
9057ca5ce89SRichard Gong /* if there was no channel match */
9067ca5ce89SRichard Gong if (i == SVC_NUM_CHANNEL) {
9077ca5ce89SRichard Gong dev_err(dev, "%s: channel not allocated\n", __func__);
9087ca5ce89SRichard Gong return ERR_PTR(-EINVAL);
9097ca5ce89SRichard Gong }
9107ca5ce89SRichard Gong
9117ca5ce89SRichard Gong if (chan->scl || !try_module_get(controller->dev->driver->owner)) {
9127ca5ce89SRichard Gong dev_dbg(dev, "%s: svc not free\n", __func__);
9137ca5ce89SRichard Gong return ERR_PTR(-EBUSY);
9147ca5ce89SRichard Gong }
9157ca5ce89SRichard Gong
9167ca5ce89SRichard Gong spin_lock_irqsave(&chan->lock, flag);
9177ca5ce89SRichard Gong chan->scl = client;
9187ca5ce89SRichard Gong chan->ctrl->num_active_client++;
9197ca5ce89SRichard Gong spin_unlock_irqrestore(&chan->lock, flag);
9207ca5ce89SRichard Gong
9217ca5ce89SRichard Gong return chan;
9227ca5ce89SRichard Gong }
9237ca5ce89SRichard Gong EXPORT_SYMBOL_GPL(stratix10_svc_request_channel_byname);
9247ca5ce89SRichard Gong
9257ca5ce89SRichard Gong /**
9267ca5ce89SRichard Gong * stratix10_svc_free_channel() - free service channel
9277ca5ce89SRichard Gong * @chan: service channel to be freed
9287ca5ce89SRichard Gong *
9297ca5ce89SRichard Gong * This function is used by service client to free a service channel.
9307ca5ce89SRichard Gong */
stratix10_svc_free_channel(struct stratix10_svc_chan * chan)9317ca5ce89SRichard Gong void stratix10_svc_free_channel(struct stratix10_svc_chan *chan)
9327ca5ce89SRichard Gong {
9337ca5ce89SRichard Gong unsigned long flag;
9347ca5ce89SRichard Gong
9357ca5ce89SRichard Gong spin_lock_irqsave(&chan->lock, flag);
9367ca5ce89SRichard Gong chan->scl = NULL;
9377ca5ce89SRichard Gong chan->ctrl->num_active_client--;
9387ca5ce89SRichard Gong module_put(chan->ctrl->dev->driver->owner);
9397ca5ce89SRichard Gong spin_unlock_irqrestore(&chan->lock, flag);
9407ca5ce89SRichard Gong }
9417ca5ce89SRichard Gong EXPORT_SYMBOL_GPL(stratix10_svc_free_channel);
9427ca5ce89SRichard Gong
9437ca5ce89SRichard Gong /**
9447ca5ce89SRichard Gong * stratix10_svc_send() - send a message data to the remote
9457ca5ce89SRichard Gong * @chan: service channel assigned to the client
9467ca5ce89SRichard Gong * @msg: message data to be sent, in the format of
9477ca5ce89SRichard Gong * "struct stratix10_svc_client_msg"
9487ca5ce89SRichard Gong *
9497ca5ce89SRichard Gong * This function is used by service client to add a message to the service
9507ca5ce89SRichard Gong * layer driver's queue for being sent to the secure world.
9517ca5ce89SRichard Gong *
9527ca5ce89SRichard Gong * Return: 0 for success, -ENOMEM or -ENOBUFS on error.
9537ca5ce89SRichard Gong */
stratix10_svc_send(struct stratix10_svc_chan * chan,void * msg)9547ca5ce89SRichard Gong int stratix10_svc_send(struct stratix10_svc_chan *chan, void *msg)
9557ca5ce89SRichard Gong {
9567ca5ce89SRichard Gong struct stratix10_svc_client_msg
9577ca5ce89SRichard Gong *p_msg = (struct stratix10_svc_client_msg *)msg;
9587ca5ce89SRichard Gong struct stratix10_svc_data_mem *p_mem;
9597ca5ce89SRichard Gong struct stratix10_svc_data *p_data;
9607ca5ce89SRichard Gong int ret = 0;
9617ca5ce89SRichard Gong unsigned int cpu = 0;
9627ca5ce89SRichard Gong
9637ca5ce89SRichard Gong p_data = kzalloc(sizeof(*p_data), GFP_KERNEL);
9647ca5ce89SRichard Gong if (!p_data)
9657ca5ce89SRichard Gong return -ENOMEM;
9667ca5ce89SRichard Gong
9677ca5ce89SRichard Gong /* first client will create kernel thread */
9687ca5ce89SRichard Gong if (!chan->ctrl->task) {
9697ca5ce89SRichard Gong chan->ctrl->task =
9707ca5ce89SRichard Gong kthread_create_on_node(svc_normal_to_secure_thread,
9717ca5ce89SRichard Gong (void *)chan->ctrl,
9727ca5ce89SRichard Gong cpu_to_node(cpu),
9737ca5ce89SRichard Gong "svc_smc_hvc_thread");
9747ca5ce89SRichard Gong if (IS_ERR(chan->ctrl->task)) {
9757ca5ce89SRichard Gong dev_err(chan->ctrl->dev,
976b5dc75c9SRichard Gong "failed to create svc_smc_hvc_thread\n");
9777ca5ce89SRichard Gong kfree(p_data);
9787ca5ce89SRichard Gong return -EINVAL;
9797ca5ce89SRichard Gong }
9807ca5ce89SRichard Gong kthread_bind(chan->ctrl->task, cpu);
9817ca5ce89SRichard Gong wake_up_process(chan->ctrl->task);
9827ca5ce89SRichard Gong }
9837ca5ce89SRichard Gong
9847ca5ce89SRichard Gong pr_debug("%s: sent P-va=%p, P-com=%x, P-size=%u\n", __func__,
9857ca5ce89SRichard Gong p_msg->payload, p_msg->command,
9867ca5ce89SRichard Gong (unsigned int)p_msg->payload_length);
9877ca5ce89SRichard Gong
9887ca5ce89SRichard Gong if (list_empty(&svc_data_mem)) {
9897ca5ce89SRichard Gong if (p_msg->command == COMMAND_RECONFIG) {
9907ca5ce89SRichard Gong struct stratix10_svc_command_config_type *ct =
9917ca5ce89SRichard Gong (struct stratix10_svc_command_config_type *)
9927ca5ce89SRichard Gong p_msg->payload;
9937ca5ce89SRichard Gong p_data->flag = ct->flags;
9947ca5ce89SRichard Gong }
9957ca5ce89SRichard Gong } else {
9967ca5ce89SRichard Gong list_for_each_entry(p_mem, &svc_data_mem, node)
9977ca5ce89SRichard Gong if (p_mem->vaddr == p_msg->payload) {
9987ca5ce89SRichard Gong p_data->paddr = p_mem->paddr;
9994a4709d4SAng Tien Sung p_data->size = p_msg->payload_length;
10007ca5ce89SRichard Gong break;
10017ca5ce89SRichard Gong }
10024a4709d4SAng Tien Sung if (p_msg->payload_output) {
10034a4709d4SAng Tien Sung list_for_each_entry(p_mem, &svc_data_mem, node)
10044a4709d4SAng Tien Sung if (p_mem->vaddr == p_msg->payload_output) {
10054a4709d4SAng Tien Sung p_data->paddr_output =
10064a4709d4SAng Tien Sung p_mem->paddr;
10074a4709d4SAng Tien Sung p_data->size_output =
10084a4709d4SAng Tien Sung p_msg->payload_length_output;
10094a4709d4SAng Tien Sung break;
10104a4709d4SAng Tien Sung }
10114a4709d4SAng Tien Sung }
10127ca5ce89SRichard Gong }
10137ca5ce89SRichard Gong
10147ca5ce89SRichard Gong p_data->command = p_msg->command;
10157ca5ce89SRichard Gong p_data->arg[0] = p_msg->arg[0];
10167ca5ce89SRichard Gong p_data->arg[1] = p_msg->arg[1];
10177ca5ce89SRichard Gong p_data->arg[2] = p_msg->arg[2];
10187ca5ce89SRichard Gong p_data->size = p_msg->payload_length;
10197ca5ce89SRichard Gong p_data->chan = chan;
10207ca5ce89SRichard Gong pr_debug("%s: put to FIFO pa=0x%016x, cmd=%x, size=%u\n", __func__,
10217ca5ce89SRichard Gong (unsigned int)p_data->paddr, p_data->command,
10227ca5ce89SRichard Gong (unsigned int)p_data->size);
10237ca5ce89SRichard Gong ret = kfifo_in_spinlocked(&chan->ctrl->svc_fifo, p_data,
10247ca5ce89SRichard Gong sizeof(*p_data),
10257ca5ce89SRichard Gong &chan->ctrl->svc_fifo_lock);
10267ca5ce89SRichard Gong
10277ca5ce89SRichard Gong kfree(p_data);
10287ca5ce89SRichard Gong
10297ca5ce89SRichard Gong if (!ret)
10307ca5ce89SRichard Gong return -ENOBUFS;
10317ca5ce89SRichard Gong
10327ca5ce89SRichard Gong return 0;
10337ca5ce89SRichard Gong }
10347ca5ce89SRichard Gong EXPORT_SYMBOL_GPL(stratix10_svc_send);
10357ca5ce89SRichard Gong
10367ca5ce89SRichard Gong /**
10377ca5ce89SRichard Gong * stratix10_svc_done() - complete service request transactions
10387ca5ce89SRichard Gong * @chan: service channel assigned to the client
10397ca5ce89SRichard Gong *
10407ca5ce89SRichard Gong * This function should be called when client has finished its request
10417ca5ce89SRichard Gong * or there is an error in the request process. It allows the service layer
10427ca5ce89SRichard Gong * to stop the running thread to have maximize savings in kernel resources.
10437ca5ce89SRichard Gong */
stratix10_svc_done(struct stratix10_svc_chan * chan)10447ca5ce89SRichard Gong void stratix10_svc_done(struct stratix10_svc_chan *chan)
10457ca5ce89SRichard Gong {
10467ca5ce89SRichard Gong /* stop thread when thread is running AND only one active client */
10477ca5ce89SRichard Gong if (chan->ctrl->task && chan->ctrl->num_active_client <= 1) {
10487ca5ce89SRichard Gong pr_debug("svc_smc_hvc_shm_thread is stopped\n");
10497ca5ce89SRichard Gong kthread_stop(chan->ctrl->task);
10507ca5ce89SRichard Gong chan->ctrl->task = NULL;
10517ca5ce89SRichard Gong }
10527ca5ce89SRichard Gong }
10537ca5ce89SRichard Gong EXPORT_SYMBOL_GPL(stratix10_svc_done);
10547ca5ce89SRichard Gong
10557ca5ce89SRichard Gong /**
10567ca5ce89SRichard Gong * stratix10_svc_allocate_memory() - allocate memory
10577ca5ce89SRichard Gong * @chan: service channel assigned to the client
10587ca5ce89SRichard Gong * @size: memory size requested by a specific service client
10597ca5ce89SRichard Gong *
10607ca5ce89SRichard Gong * Service layer allocates the requested number of bytes buffer from the
10617ca5ce89SRichard Gong * memory pool, service client uses this function to get allocated buffers.
10627ca5ce89SRichard Gong *
10637ca5ce89SRichard Gong * Return: address of allocated memory on success, or ERR_PTR() on error.
10647ca5ce89SRichard Gong */
stratix10_svc_allocate_memory(struct stratix10_svc_chan * chan,size_t size)10657ca5ce89SRichard Gong void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan,
10667ca5ce89SRichard Gong size_t size)
10677ca5ce89SRichard Gong {
10687ca5ce89SRichard Gong struct stratix10_svc_data_mem *pmem;
10697ca5ce89SRichard Gong unsigned long va;
10707ca5ce89SRichard Gong phys_addr_t pa;
10717ca5ce89SRichard Gong struct gen_pool *genpool = chan->ctrl->genpool;
10727ca5ce89SRichard Gong size_t s = roundup(size, 1 << genpool->min_alloc_order);
10737ca5ce89SRichard Gong
10747ca5ce89SRichard Gong pmem = devm_kzalloc(chan->ctrl->dev, sizeof(*pmem), GFP_KERNEL);
10757ca5ce89SRichard Gong if (!pmem)
10767ca5ce89SRichard Gong return ERR_PTR(-ENOMEM);
10777ca5ce89SRichard Gong
10787ca5ce89SRichard Gong va = gen_pool_alloc(genpool, s);
10797ca5ce89SRichard Gong if (!va)
10807ca5ce89SRichard Gong return ERR_PTR(-ENOMEM);
10817ca5ce89SRichard Gong
10827ca5ce89SRichard Gong memset((void *)va, 0, s);
10837ca5ce89SRichard Gong pa = gen_pool_virt_to_phys(genpool, va);
10847ca5ce89SRichard Gong
10857ca5ce89SRichard Gong pmem->vaddr = (void *)va;
10867ca5ce89SRichard Gong pmem->paddr = pa;
10877ca5ce89SRichard Gong pmem->size = s;
10887ca5ce89SRichard Gong list_add_tail(&pmem->node, &svc_data_mem);
10897ca5ce89SRichard Gong pr_debug("%s: va=%p, pa=0x%016x\n", __func__,
10907ca5ce89SRichard Gong pmem->vaddr, (unsigned int)pmem->paddr);
10917ca5ce89SRichard Gong
10927ca5ce89SRichard Gong return (void *)va;
10937ca5ce89SRichard Gong }
10947ca5ce89SRichard Gong EXPORT_SYMBOL_GPL(stratix10_svc_allocate_memory);
10957ca5ce89SRichard Gong
10967ca5ce89SRichard Gong /**
10977ca5ce89SRichard Gong * stratix10_svc_free_memory() - free allocated memory
10987ca5ce89SRichard Gong * @chan: service channel assigned to the client
10997ca5ce89SRichard Gong * @kaddr: memory to be freed
11007ca5ce89SRichard Gong *
11017ca5ce89SRichard Gong * This function is used by service client to free allocated buffers.
11027ca5ce89SRichard Gong */
stratix10_svc_free_memory(struct stratix10_svc_chan * chan,void * kaddr)11037ca5ce89SRichard Gong void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr)
11047ca5ce89SRichard Gong {
11057ca5ce89SRichard Gong struct stratix10_svc_data_mem *pmem;
11067ca5ce89SRichard Gong
11077ca5ce89SRichard Gong list_for_each_entry(pmem, &svc_data_mem, node)
11087ca5ce89SRichard Gong if (pmem->vaddr == kaddr) {
11095a0793acSXiaomeng Tong gen_pool_free(chan->ctrl->genpool,
11105a0793acSXiaomeng Tong (unsigned long)kaddr, pmem->size);
11117ca5ce89SRichard Gong pmem->vaddr = NULL;
11127ca5ce89SRichard Gong list_del(&pmem->node);
11135a0793acSXiaomeng Tong return;
11145a0793acSXiaomeng Tong }
11155a0793acSXiaomeng Tong
11165a0793acSXiaomeng Tong list_del(&svc_data_mem);
11177ca5ce89SRichard Gong }
11187ca5ce89SRichard Gong EXPORT_SYMBOL_GPL(stratix10_svc_free_memory);
11197ca5ce89SRichard Gong
11207ca5ce89SRichard Gong static const struct of_device_id stratix10_svc_drv_match[] = {
11217ca5ce89SRichard Gong {.compatible = "intel,stratix10-svc"},
1122f276d3eaSRichard Gong {.compatible = "intel,agilex-svc"},
11237ca5ce89SRichard Gong {},
11247ca5ce89SRichard Gong };
11257ca5ce89SRichard Gong
stratix10_svc_drv_probe(struct platform_device * pdev)11267ca5ce89SRichard Gong static int stratix10_svc_drv_probe(struct platform_device *pdev)
11277ca5ce89SRichard Gong {
11287ca5ce89SRichard Gong struct device *dev = &pdev->dev;
11297ca5ce89SRichard Gong struct stratix10_svc_controller *controller;
11307ca5ce89SRichard Gong struct stratix10_svc_chan *chans;
11317ca5ce89SRichard Gong struct gen_pool *genpool;
11327ca5ce89SRichard Gong struct stratix10_svc_sh_memory *sh_memory;
1133b5dc75c9SRichard Gong struct stratix10_svc *svc;
1134b5dc75c9SRichard Gong
11357ca5ce89SRichard Gong svc_invoke_fn *invoke_fn;
11367ca5ce89SRichard Gong size_t fifo_size;
11377ca5ce89SRichard Gong int ret;
11387ca5ce89SRichard Gong
11397ca5ce89SRichard Gong /* get SMC or HVC function */
11407ca5ce89SRichard Gong invoke_fn = get_invoke_func(dev);
11417ca5ce89SRichard Gong if (IS_ERR(invoke_fn))
11427ca5ce89SRichard Gong return -EINVAL;
11437ca5ce89SRichard Gong
11447ca5ce89SRichard Gong sh_memory = devm_kzalloc(dev, sizeof(*sh_memory), GFP_KERNEL);
11457ca5ce89SRichard Gong if (!sh_memory)
11467ca5ce89SRichard Gong return -ENOMEM;
11477ca5ce89SRichard Gong
11487ca5ce89SRichard Gong sh_memory->invoke_fn = invoke_fn;
11497ca5ce89SRichard Gong ret = svc_get_sh_memory(pdev, sh_memory);
11507ca5ce89SRichard Gong if (ret)
11517ca5ce89SRichard Gong return ret;
11527ca5ce89SRichard Gong
11537ca5ce89SRichard Gong genpool = svc_create_memory_pool(pdev, sh_memory);
1154e1d6ca04SDan Carpenter if (IS_ERR(genpool))
1155e1d6ca04SDan Carpenter return PTR_ERR(genpool);
11567ca5ce89SRichard Gong
11577ca5ce89SRichard Gong /* allocate service controller and supporting channel */
11587ca5ce89SRichard Gong controller = devm_kzalloc(dev, sizeof(*controller), GFP_KERNEL);
11599175ee1aSYang Yingliang if (!controller) {
11609175ee1aSYang Yingliang ret = -ENOMEM;
11619175ee1aSYang Yingliang goto err_destroy_pool;
11629175ee1aSYang Yingliang }
11637ca5ce89SRichard Gong
11647ca5ce89SRichard Gong chans = devm_kmalloc_array(dev, SVC_NUM_CHANNEL,
11657ca5ce89SRichard Gong sizeof(*chans), GFP_KERNEL | __GFP_ZERO);
11669175ee1aSYang Yingliang if (!chans) {
11679175ee1aSYang Yingliang ret = -ENOMEM;
11689175ee1aSYang Yingliang goto err_destroy_pool;
11699175ee1aSYang Yingliang }
11707ca5ce89SRichard Gong
11717ca5ce89SRichard Gong controller->dev = dev;
11727ca5ce89SRichard Gong controller->num_chans = SVC_NUM_CHANNEL;
11737ca5ce89SRichard Gong controller->num_active_client = 0;
11747ca5ce89SRichard Gong controller->chans = chans;
11757ca5ce89SRichard Gong controller->genpool = genpool;
11767ca5ce89SRichard Gong controller->task = NULL;
11777ca5ce89SRichard Gong controller->invoke_fn = invoke_fn;
11787ca5ce89SRichard Gong init_completion(&controller->complete_status);
11797ca5ce89SRichard Gong
11807ca5ce89SRichard Gong fifo_size = sizeof(struct stratix10_svc_data) * SVC_NUM_DATA_IN_FIFO;
11817ca5ce89SRichard Gong ret = kfifo_alloc(&controller->svc_fifo, fifo_size, GFP_KERNEL);
11827ca5ce89SRichard Gong if (ret) {
1183b5dc75c9SRichard Gong dev_err(dev, "failed to allocate FIFO\n");
11849175ee1aSYang Yingliang goto err_destroy_pool;
11857ca5ce89SRichard Gong }
11867ca5ce89SRichard Gong spin_lock_init(&controller->svc_fifo_lock);
11877ca5ce89SRichard Gong
11887ca5ce89SRichard Gong chans[0].scl = NULL;
11897ca5ce89SRichard Gong chans[0].ctrl = controller;
11907ca5ce89SRichard Gong chans[0].name = SVC_CLIENT_FPGA;
11917ca5ce89SRichard Gong spin_lock_init(&chans[0].lock);
11927ca5ce89SRichard Gong
11936b50d882SRichard Gong chans[1].scl = NULL;
11946b50d882SRichard Gong chans[1].ctrl = controller;
11956b50d882SRichard Gong chans[1].name = SVC_CLIENT_RSU;
11966b50d882SRichard Gong spin_lock_init(&chans[1].lock);
11976b50d882SRichard Gong
1198e6281c26SAng Tien Sung chans[2].scl = NULL;
1199e6281c26SAng Tien Sung chans[2].ctrl = controller;
1200e6281c26SAng Tien Sung chans[2].name = SVC_CLIENT_FCS;
1201e6281c26SAng Tien Sung spin_lock_init(&chans[2].lock);
1202e6281c26SAng Tien Sung
12037ca5ce89SRichard Gong list_add_tail(&controller->node, &svc_ctrl);
12047ca5ce89SRichard Gong platform_set_drvdata(pdev, controller);
12057ca5ce89SRichard Gong
1206b5dc75c9SRichard Gong /* add svc client device(s) */
1207b5dc75c9SRichard Gong svc = devm_kzalloc(dev, sizeof(*svc), GFP_KERNEL);
1208d99247f9SChristophe JAILLET if (!svc) {
1209d99247f9SChristophe JAILLET ret = -ENOMEM;
1210d99247f9SChristophe JAILLET goto err_free_kfifo;
1211d99247f9SChristophe JAILLET }
1212b5dc75c9SRichard Gong
1213b5dc75c9SRichard Gong svc->stratix10_svc_rsu = platform_device_alloc(STRATIX10_RSU, 0);
1214b5dc75c9SRichard Gong if (!svc->stratix10_svc_rsu) {
1215b5dc75c9SRichard Gong dev_err(dev, "failed to allocate %s device\n", STRATIX10_RSU);
1216d99247f9SChristophe JAILLET ret = -ENOMEM;
1217d99247f9SChristophe JAILLET goto err_free_kfifo;
1218b5dc75c9SRichard Gong }
1219b5dc75c9SRichard Gong
1220b5dc75c9SRichard Gong ret = platform_device_add(svc->stratix10_svc_rsu);
1221e6281c26SAng Tien Sung if (ret) {
1222e6281c26SAng Tien Sung platform_device_put(svc->stratix10_svc_rsu);
1223d66a4c20SYang Yingliang goto err_free_kfifo;
1224e6281c26SAng Tien Sung }
1225e6281c26SAng Tien Sung
1226e6281c26SAng Tien Sung svc->intel_svc_fcs = platform_device_alloc(INTEL_FCS, 1);
1227e6281c26SAng Tien Sung if (!svc->intel_svc_fcs) {
1228e6281c26SAng Tien Sung dev_err(dev, "failed to allocate %s device\n", INTEL_FCS);
1229d66a4c20SYang Yingliang ret = -ENOMEM;
1230d66a4c20SYang Yingliang goto err_unregister_dev;
1231e6281c26SAng Tien Sung }
1232e6281c26SAng Tien Sung
1233e6281c26SAng Tien Sung ret = platform_device_add(svc->intel_svc_fcs);
1234e6281c26SAng Tien Sung if (ret) {
1235e6281c26SAng Tien Sung platform_device_put(svc->intel_svc_fcs);
1236d66a4c20SYang Yingliang goto err_unregister_dev;
1237e6281c26SAng Tien Sung }
1238d99247f9SChristophe JAILLET
1239b5dc75c9SRichard Gong dev_set_drvdata(dev, svc);
1240b5dc75c9SRichard Gong
12417ca5ce89SRichard Gong pr_info("Intel Service Layer Driver Initialized\n");
12427ca5ce89SRichard Gong
1243d99247f9SChristophe JAILLET return 0;
1244d99247f9SChristophe JAILLET
1245d66a4c20SYang Yingliang err_unregister_dev:
1246d66a4c20SYang Yingliang platform_device_unregister(svc->stratix10_svc_rsu);
1247d99247f9SChristophe JAILLET err_free_kfifo:
1248d99247f9SChristophe JAILLET kfifo_free(&controller->svc_fifo);
12499175ee1aSYang Yingliang err_destroy_pool:
12509175ee1aSYang Yingliang gen_pool_destroy(genpool);
12517ca5ce89SRichard Gong return ret;
12527ca5ce89SRichard Gong }
12537ca5ce89SRichard Gong
stratix10_svc_drv_remove(struct platform_device * pdev)12547ca5ce89SRichard Gong static int stratix10_svc_drv_remove(struct platform_device *pdev)
12557ca5ce89SRichard Gong {
1256b5dc75c9SRichard Gong struct stratix10_svc *svc = dev_get_drvdata(&pdev->dev);
12577ca5ce89SRichard Gong struct stratix10_svc_controller *ctrl = platform_get_drvdata(pdev);
12587ca5ce89SRichard Gong
1259e6281c26SAng Tien Sung platform_device_unregister(svc->intel_svc_fcs);
1260b5dc75c9SRichard Gong platform_device_unregister(svc->stratix10_svc_rsu);
1261b5dc75c9SRichard Gong
12627ca5ce89SRichard Gong kfifo_free(&ctrl->svc_fifo);
12637ca5ce89SRichard Gong if (ctrl->task) {
12647ca5ce89SRichard Gong kthread_stop(ctrl->task);
12657ca5ce89SRichard Gong ctrl->task = NULL;
12667ca5ce89SRichard Gong }
12677ca5ce89SRichard Gong if (ctrl->genpool)
12687ca5ce89SRichard Gong gen_pool_destroy(ctrl->genpool);
12697ca5ce89SRichard Gong list_del(&ctrl->node);
12707ca5ce89SRichard Gong
12717ca5ce89SRichard Gong return 0;
12727ca5ce89SRichard Gong }
12737ca5ce89SRichard Gong
12747ca5ce89SRichard Gong static struct platform_driver stratix10_svc_driver = {
12757ca5ce89SRichard Gong .probe = stratix10_svc_drv_probe,
12767ca5ce89SRichard Gong .remove = stratix10_svc_drv_remove,
12777ca5ce89SRichard Gong .driver = {
12787ca5ce89SRichard Gong .name = "stratix10-svc",
12797ca5ce89SRichard Gong .of_match_table = stratix10_svc_drv_match,
12807ca5ce89SRichard Gong },
12817ca5ce89SRichard Gong };
12827ca5ce89SRichard Gong
stratix10_svc_init(void)12837ca5ce89SRichard Gong static int __init stratix10_svc_init(void)
12847ca5ce89SRichard Gong {
12857ca5ce89SRichard Gong struct device_node *fw_np;
12867ca5ce89SRichard Gong struct device_node *np;
12877ca5ce89SRichard Gong int ret;
12887ca5ce89SRichard Gong
12897ca5ce89SRichard Gong fw_np = of_find_node_by_name(NULL, "firmware");
12907ca5ce89SRichard Gong if (!fw_np)
12917ca5ce89SRichard Gong return -ENODEV;
12927ca5ce89SRichard Gong
12937ca5ce89SRichard Gong np = of_find_matching_node(fw_np, stratix10_svc_drv_match);
1294b5058483SNicolas Saenz Julienne if (!np)
12957ca5ce89SRichard Gong return -ENODEV;
12967ca5ce89SRichard Gong
12977ca5ce89SRichard Gong of_node_put(np);
12987ca5ce89SRichard Gong ret = of_platform_populate(fw_np, stratix10_svc_drv_match, NULL, NULL);
12997ca5ce89SRichard Gong if (ret)
13007ca5ce89SRichard Gong return ret;
13017ca5ce89SRichard Gong
13027ca5ce89SRichard Gong return platform_driver_register(&stratix10_svc_driver);
13037ca5ce89SRichard Gong }
13047ca5ce89SRichard Gong
stratix10_svc_exit(void)13057ca5ce89SRichard Gong static void __exit stratix10_svc_exit(void)
13067ca5ce89SRichard Gong {
13077ca5ce89SRichard Gong return platform_driver_unregister(&stratix10_svc_driver);
13087ca5ce89SRichard Gong }
13097ca5ce89SRichard Gong
13107ca5ce89SRichard Gong subsys_initcall(stratix10_svc_init);
13117ca5ce89SRichard Gong module_exit(stratix10_svc_exit);
13127ca5ce89SRichard Gong
13137ca5ce89SRichard Gong MODULE_LICENSE("GPL v2");
13147ca5ce89SRichard Gong MODULE_DESCRIPTION("Intel Stratix10 Service Layer Driver");
13157ca5ce89SRichard Gong MODULE_AUTHOR("Richard Gong <richard.gong@intel.com>");
13167ca5ce89SRichard Gong MODULE_ALIAS("platform:stratix10-svc");
1317