xref: /openbmc/linux/drivers/firmware/arm_scmi/smc.c (revision fa0dadde)
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_node *of_node, int idx)
56 {
57 	struct device_node *np = of_parse_phandle(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 	return 0;
175 }
176 
177 static int smc_send_message(struct scmi_chan_info *cinfo,
178 			    struct scmi_xfer *xfer)
179 {
180 	struct scmi_smc *scmi_info = cinfo->transport_info;
181 	struct arm_smccc_res res;
182 
183 	/*
184 	 * Channel will be released only once response has been
185 	 * surely fully retrieved, so after .mark_txdone()
186 	 */
187 	smc_channel_lock_acquire(scmi_info, xfer);
188 
189 	shmem_tx_prepare(scmi_info->shmem, xfer, cinfo);
190 
191 	arm_smccc_1_1_invoke(scmi_info->func_id, 0, 0, 0, 0, 0, 0, 0, &res);
192 
193 	/* Only SMCCC_RET_NOT_SUPPORTED is valid error code */
194 	if (res.a0) {
195 		smc_channel_lock_release(scmi_info);
196 		return -EOPNOTSUPP;
197 	}
198 
199 	return 0;
200 }
201 
202 static void smc_fetch_response(struct scmi_chan_info *cinfo,
203 			       struct scmi_xfer *xfer)
204 {
205 	struct scmi_smc *scmi_info = cinfo->transport_info;
206 
207 	shmem_fetch_response(scmi_info->shmem, xfer);
208 }
209 
210 static void smc_mark_txdone(struct scmi_chan_info *cinfo, int ret,
211 			    struct scmi_xfer *__unused)
212 {
213 	struct scmi_smc *scmi_info = cinfo->transport_info;
214 
215 	smc_channel_lock_release(scmi_info);
216 }
217 
218 static const struct scmi_transport_ops scmi_smc_ops = {
219 	.chan_available = smc_chan_available,
220 	.chan_setup = smc_chan_setup,
221 	.chan_free = smc_chan_free,
222 	.send_message = smc_send_message,
223 	.mark_txdone = smc_mark_txdone,
224 	.fetch_response = smc_fetch_response,
225 };
226 
227 const struct scmi_desc scmi_smc_desc = {
228 	.ops = &scmi_smc_ops,
229 	.max_rx_timeout_ms = 30,
230 	.max_msg = 20,
231 	.max_msg_size = 128,
232 	/*
233 	 * Setting .sync_cmds_atomic_replies to true for SMC assumes that,
234 	 * once the SMC instruction has completed successfully, the issued
235 	 * SCMI command would have been already fully processed by the SCMI
236 	 * platform firmware and so any possible response value expected
237 	 * for the issued command will be immmediately ready to be fetched
238 	 * from the shared memory area.
239 	 */
240 	.sync_cmds_completed_on_ret = true,
241 	.atomic_enabled = IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE),
242 };
243