xref: /openbmc/linux/drivers/firmware/arm_scmi/smc.c (revision fcd7c269)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * System Control and Management Interface (SCMI) Message SMC/HVC
4  * Transport driver
5  *
6  * Copyright 2020 NXP
7  */
8 
9 #include <linux/arm-smccc.h>
10 #include <linux/atomic.h>
11 #include <linux/device.h>
12 #include <linux/err.h>
13 #include <linux/interrupt.h>
14 #include <linux/mutex.h>
15 #include <linux/of.h>
16 #include <linux/of_address.h>
17 #include <linux/of_irq.h>
18 #include <linux/processor.h>
19 #include <linux/slab.h>
20 
21 #include "common.h"
22 
23 /**
24  * struct scmi_smc - Structure representing a SCMI smc transport
25  *
26  * @cinfo: SCMI channel info
27  * @shmem: Transmit/Receive shared memory area
28  * @shmem_lock: Lock to protect access to Tx/Rx shared memory area.
29  *		Used when NOT operating in atomic mode.
30  * @inflight: Atomic flag to protect access to Tx/Rx shared memory area.
31  *	      Used when operating in atomic mode.
32  * @func_id: smc/hvc call function id
33  */
34 
35 struct scmi_smc {
36 	struct scmi_chan_info *cinfo;
37 	struct scmi_shared_mem __iomem *shmem;
38 	/* Protect access to shmem area */
39 	struct mutex shmem_lock;
40 #define INFLIGHT_NONE	MSG_TOKEN_MAX
41 	atomic_t inflight;
42 	u32 func_id;
43 };
44 
45 static irqreturn_t smc_msg_done_isr(int irq, void *data)
46 {
47 	struct scmi_smc *scmi_info = data;
48 
49 	scmi_rx_callback(scmi_info->cinfo,
50 			 shmem_read_header(scmi_info->shmem), NULL);
51 
52 	return IRQ_HANDLED;
53 }
54 
55 static bool smc_chan_available(struct device *dev, int idx)
56 {
57 	struct device_node *np = of_parse_phandle(dev->of_node, "shmem", 0);
58 	if (!np)
59 		return false;
60 
61 	of_node_put(np);
62 	return true;
63 }
64 
65 static inline void smc_channel_lock_init(struct scmi_smc *scmi_info)
66 {
67 	if (IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE))
68 		atomic_set(&scmi_info->inflight, INFLIGHT_NONE);
69 	else
70 		mutex_init(&scmi_info->shmem_lock);
71 }
72 
73 static bool smc_xfer_inflight(struct scmi_xfer *xfer, atomic_t *inflight)
74 {
75 	int ret;
76 
77 	ret = atomic_cmpxchg(inflight, INFLIGHT_NONE, xfer->hdr.seq);
78 
79 	return ret == INFLIGHT_NONE;
80 }
81 
82 static inline void
83 smc_channel_lock_acquire(struct scmi_smc *scmi_info,
84 			 struct scmi_xfer *xfer __maybe_unused)
85 {
86 	if (IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE))
87 		spin_until_cond(smc_xfer_inflight(xfer, &scmi_info->inflight));
88 	else
89 		mutex_lock(&scmi_info->shmem_lock);
90 }
91 
92 static inline void smc_channel_lock_release(struct scmi_smc *scmi_info)
93 {
94 	if (IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE))
95 		atomic_set(&scmi_info->inflight, INFLIGHT_NONE);
96 	else
97 		mutex_unlock(&scmi_info->shmem_lock);
98 }
99 
100 static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
101 			  bool tx)
102 {
103 	struct device *cdev = cinfo->dev;
104 	struct scmi_smc *scmi_info;
105 	resource_size_t size;
106 	struct resource res;
107 	struct device_node *np;
108 	u32 func_id;
109 	int ret, irq;
110 
111 	if (!tx)
112 		return -ENODEV;
113 
114 	scmi_info = devm_kzalloc(dev, sizeof(*scmi_info), GFP_KERNEL);
115 	if (!scmi_info)
116 		return -ENOMEM;
117 
118 	np = of_parse_phandle(cdev->of_node, "shmem", 0);
119 	if (!of_device_is_compatible(np, "arm,scmi-shmem"))
120 		return -ENXIO;
121 
122 	ret = of_address_to_resource(np, 0, &res);
123 	of_node_put(np);
124 	if (ret) {
125 		dev_err(cdev, "failed to get SCMI Tx shared memory\n");
126 		return ret;
127 	}
128 
129 	size = resource_size(&res);
130 	scmi_info->shmem = devm_ioremap(dev, res.start, size);
131 	if (!scmi_info->shmem) {
132 		dev_err(dev, "failed to ioremap SCMI Tx shared memory\n");
133 		return -EADDRNOTAVAIL;
134 	}
135 
136 	ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id);
137 	if (ret < 0)
138 		return ret;
139 
140 	/*
141 	 * If there is an interrupt named "a2p", then the service and
142 	 * completion of a message is signaled by an interrupt rather than by
143 	 * the return of the SMC call.
144 	 */
145 	irq = of_irq_get_byname(cdev->of_node, "a2p");
146 	if (irq > 0) {
147 		ret = devm_request_irq(dev, irq, smc_msg_done_isr,
148 				       IRQF_NO_SUSPEND,
149 				       dev_name(dev), scmi_info);
150 		if (ret) {
151 			dev_err(dev, "failed to setup SCMI smc irq\n");
152 			return ret;
153 		}
154 	} else {
155 		cinfo->no_completion_irq = true;
156 	}
157 
158 	scmi_info->func_id = func_id;
159 	scmi_info->cinfo = cinfo;
160 	smc_channel_lock_init(scmi_info);
161 	cinfo->transport_info = scmi_info;
162 
163 	return 0;
164 }
165 
166 static int smc_chan_free(int id, void *p, void *data)
167 {
168 	struct scmi_chan_info *cinfo = p;
169 	struct scmi_smc *scmi_info = cinfo->transport_info;
170 
171 	cinfo->transport_info = NULL;
172 	scmi_info->cinfo = NULL;
173 
174 	scmi_free_channel(cinfo, data, id);
175 
176 	return 0;
177 }
178 
179 static int smc_send_message(struct scmi_chan_info *cinfo,
180 			    struct scmi_xfer *xfer)
181 {
182 	struct scmi_smc *scmi_info = cinfo->transport_info;
183 	struct arm_smccc_res res;
184 
185 	/*
186 	 * Channel will be released only once response has been
187 	 * surely fully retrieved, so after .mark_txdone()
188 	 */
189 	smc_channel_lock_acquire(scmi_info, xfer);
190 
191 	shmem_tx_prepare(scmi_info->shmem, xfer);
192 
193 	arm_smccc_1_1_invoke(scmi_info->func_id, 0, 0, 0, 0, 0, 0, 0, &res);
194 
195 	/* Only SMCCC_RET_NOT_SUPPORTED is valid error code */
196 	if (res.a0) {
197 		smc_channel_lock_release(scmi_info);
198 		return -EOPNOTSUPP;
199 	}
200 
201 	return 0;
202 }
203 
204 static void smc_fetch_response(struct scmi_chan_info *cinfo,
205 			       struct scmi_xfer *xfer)
206 {
207 	struct scmi_smc *scmi_info = cinfo->transport_info;
208 
209 	shmem_fetch_response(scmi_info->shmem, xfer);
210 }
211 
212 static void smc_mark_txdone(struct scmi_chan_info *cinfo, int ret,
213 			    struct scmi_xfer *__unused)
214 {
215 	struct scmi_smc *scmi_info = cinfo->transport_info;
216 
217 	smc_channel_lock_release(scmi_info);
218 }
219 
220 static const struct scmi_transport_ops scmi_smc_ops = {
221 	.chan_available = smc_chan_available,
222 	.chan_setup = smc_chan_setup,
223 	.chan_free = smc_chan_free,
224 	.send_message = smc_send_message,
225 	.mark_txdone = smc_mark_txdone,
226 	.fetch_response = smc_fetch_response,
227 };
228 
229 const struct scmi_desc scmi_smc_desc = {
230 	.ops = &scmi_smc_ops,
231 	.max_rx_timeout_ms = 30,
232 	.max_msg = 20,
233 	.max_msg_size = 128,
234 	/*
235 	 * Setting .sync_cmds_atomic_replies to true for SMC assumes that,
236 	 * once the SMC instruction has completed successfully, the issued
237 	 * SCMI command would have been already fully processed by the SCMI
238 	 * platform firmware and so any possible response value expected
239 	 * for the issued command will be immmediately ready to be fetched
240 	 * from the shared memory area.
241 	 */
242 	.sync_cmds_completed_on_ret = true,
243 	.atomic_enabled = IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE),
244 };
245