File Index
Files and directories
Sign in
FILE

macsmc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/mfd/macsmc.c C
  1// SPDX-License-Identifier: GPL-2.0-only OR MIT
  2/*
  3 * Apple SMC (System Management Controller) MFD driver
  4 *
  5 * Copyright The Asahi Linux Contributors
  6 */
  7
  8#include <linux/bitfield.h>
  9#include <linux/delay.h>
 10#include <linux/device.h>
 11#include <linux/io.h>
 12#include <linux/ioport.h>
 13#include <linux/math.h>
 14#include <linux/mfd/core.h>
 15#include <linux/mfd/macsmc.h>
 16#include <linux/notifier.h>
 17#include <linux/of.h>
 18#include <linux/of_platform.h>
 19#include <linux/overflow.h>
 20#include <linux/platform_device.h>
 21#include <linux/soc/apple/rtkit.h>
 22#include <linux/unaligned.h>
 23
 24#define SMC_ENDPOINT			0x20
 25
 26/* We don't actually know the true size here but this seem reasonable */
 27#define SMC_SHMEM_SIZE			0x1000
 28#define SMC_MAX_SIZE			255
 29
 30#define SMC_MSG_READ_KEY		0x10
 31#define SMC_MSG_WRITE_KEY		0x11
 32#define SMC_MSG_GET_KEY_BY_INDEX	0x12
 33#define SMC_MSG_GET_KEY_INFO		0x13
 34#define SMC_MSG_INITIALIZE		0x17
 35#define SMC_MSG_NOTIFICATION		0x18
 36#define SMC_MSG_RW_KEY			0x20
 37
 38#define SMC_DATA			GENMASK_ULL(63, 32)
 39#define SMC_WSIZE			GENMASK_ULL(31, 24)
 40#define SMC_SIZE			GENMASK_ULL(23, 16)
 41#define SMC_ID				GENMASK_ULL(15, 12)
 42#define SMC_MSG				GENMASK_ULL(7, 0)
 43#define SMC_RESULT			SMC_MSG
 44
 45#define SMC_TIMEOUT_MS		500
 46
 47static const struct mfd_cell apple_smc_devs[] = {
 48	MFD_CELL_OF("macsmc-gpio", NULL, NULL, 0, 0, "apple,smc-gpio"),
 49	MFD_CELL_OF("macsmc-reboot", NULL, NULL, 0, 0, "apple,smc-reboot"),
 50};
 51
 52static int apple_smc_cmd_locked(struct apple_smc *smc, u64 cmd, u64 arg,
 53				  u64 size, u64 wsize, u32 *ret_data)
 54{
 55	u8 result;
 56	int ret;
 57	u64 msg;
 58
 59	lockdep_assert_held(&smc->mutex);
 60
 61	if (smc->boot_stage != APPLE_SMC_INITIALIZED)
 62		return -EIO;
 63	if (smc->atomic_mode)
 64		return -EIO;
 65
 66	reinit_completion(&smc->cmd_done);
 67
 68	smc->msg_id = (smc->msg_id + 1) & 0xf;
 69	msg = (FIELD_PREP(SMC_MSG, cmd) |
 70	       FIELD_PREP(SMC_SIZE, size) |
 71	       FIELD_PREP(SMC_WSIZE, wsize) |
 72	       FIELD_PREP(SMC_ID, smc->msg_id) |
 73	       FIELD_PREP(SMC_DATA, arg));
 74
 75	ret = apple_rtkit_send_message(smc->rtk, SMC_ENDPOINT, msg, NULL, false);
 76	if (ret) {
 77		dev_err(smc->dev, "Failed to send command\n");
 78		return ret;
 79	}
 80
 81	if (wait_for_completion_timeout(&smc->cmd_done, msecs_to_jiffies(SMC_TIMEOUT_MS)) <= 0) {
 82		dev_err(smc->dev, "Command timed out (%llx)", msg);
 83		return -ETIMEDOUT;
 84	}
 85
 86	if (FIELD_GET(SMC_ID, smc->cmd_ret) != smc->msg_id) {
 87		dev_err(smc->dev, "Command sequence mismatch (expected %d, got %d)\n",
 88			smc->msg_id, (unsigned int)FIELD_GET(SMC_ID, smc->cmd_ret));
 89		return -EIO;
 90	}
 91
 92	result = FIELD_GET(SMC_RESULT, smc->cmd_ret);
 93	if (result)
 94		return -EIO;
 95
 96	if (ret_data)
 97		*ret_data = FIELD_GET(SMC_DATA, smc->cmd_ret);
 98
 99	return FIELD_GET(SMC_SIZE, smc->cmd_ret);
100}
101
102static int apple_smc_cmd(struct apple_smc *smc, u64 cmd, u64 arg,
103			 u64 size, u64 wsize, u32 *ret_data)
104{
105	guard(mutex)(&smc->mutex);
106
107	return apple_smc_cmd_locked(smc, cmd, arg, size, wsize, ret_data);
108}
109
110static int apple_smc_rw_locked(struct apple_smc *smc, smc_key key,
111				const void *wbuf, size_t wsize,
112				void *rbuf, size_t rsize)
113{
114	u64 smc_size, smc_wsize;
115	u32 rdata;
116	int ret;
117	u64 cmd;
118
119	lockdep_assert_held(&smc->mutex);
120
121	if (rsize > SMC_MAX_SIZE)
122		return -EINVAL;
123	if (wsize > SMC_MAX_SIZE)
124		return -EINVAL;
125
126	if (rsize && wsize) {
127		cmd = SMC_MSG_RW_KEY;
128		memcpy_toio(smc->shmem.iomem, wbuf, wsize);
129		smc_size = rsize;
130		smc_wsize = wsize;
131	} else if (wsize && !rsize) {
132		cmd = SMC_MSG_WRITE_KEY;
133		memcpy_toio(smc->shmem.iomem, wbuf, wsize);
134		/*
135		 * Setting size to the length we want to write and wsize to 0
136		 * looks silly but that's how the SMC protocol works ¯\_(ツ)_/¯
137		 */
138		smc_size = wsize;
139		smc_wsize = 0;
140	} else if (!wsize && rsize) {
141		cmd = SMC_MSG_READ_KEY;
142		smc_size = rsize;
143		smc_wsize = 0;
144	} else {
145		return -EINVAL;
146	}
147
148	ret = apple_smc_cmd_locked(smc, cmd, key, smc_size, smc_wsize, &rdata);
149	if (ret < 0)
150		return ret;
151
152	if (rsize) {
153		/*
154		 * Small data <= 4 bytes is returned as part of the reply
155		 * message which is sent over the mailbox FIFO. Everything
156		 * bigger has to be copied from SRAM which is mapped as
157		 * Device memory.
158		 */
159		if (rsize <= 4)
160			memcpy(rbuf, &rdata, rsize);
161		else
162			memcpy_fromio(rbuf, smc->shmem.iomem, rsize);
163	}
164
165	return ret;
166}
167
168int apple_smc_read(struct apple_smc *smc, smc_key key, void *buf, size_t size)
169{
170	guard(mutex)(&smc->mutex);
171
172	return apple_smc_rw_locked(smc, key, NULL, 0, buf, size);
173}
174EXPORT_SYMBOL(apple_smc_read);
175
176int apple_smc_write(struct apple_smc *smc, smc_key key, const void *buf, size_t size)
177{
178	guard(mutex)(&smc->mutex);
179
180	return apple_smc_rw_locked(smc, key, buf, size, NULL, 0);
181}
182EXPORT_SYMBOL(apple_smc_write);
183
184int apple_smc_rw(struct apple_smc *smc, smc_key key, const void *wbuf, size_t wsize,
185		 void *rbuf, size_t rsize)
186{
187	guard(mutex)(&smc->mutex);
188
189	return apple_smc_rw_locked(smc, key, wbuf, wsize, rbuf, rsize);
190}
191EXPORT_SYMBOL(apple_smc_rw);
192
193int apple_smc_get_key_by_index(struct apple_smc *smc, int index, smc_key *key)
194{
195	int ret;
196
197	ret = apple_smc_cmd(smc, SMC_MSG_GET_KEY_BY_INDEX, index, 0, 0, key);
198
199	*key = swab32(*key);
200	return ret;
201}
202EXPORT_SYMBOL(apple_smc_get_key_by_index);
203
204int apple_smc_get_key_info(struct apple_smc *smc, smc_key key, struct apple_smc_key_info *info)
205{
206	u8 key_info[6];
207	int ret;
208
209	ret = apple_smc_cmd(smc, SMC_MSG_GET_KEY_INFO, key, 0, 0, NULL);
210	if (ret >= 0 && info) {
211		memcpy_fromio(key_info, smc->shmem.iomem, sizeof(key_info));
212		info->size = key_info[0];
213		info->type_code = get_unaligned_be32(&key_info[1]);
214		info->flags = key_info[5];
215	}
216	return ret;
217}
218EXPORT_SYMBOL(apple_smc_get_key_info);
219
220int apple_smc_enter_atomic(struct apple_smc *smc)
221{
222	guard(mutex)(&smc->mutex);
223
224	/*
225	 * Disable notifications since this is called before shutdown and no
226	 * notification handler will be able to handle the notification
227	 * using atomic operations only. Also ignore any failure here
228	 * because we're about to shut down or reboot anyway.
229	 * We can't use apple_smc_write_flag here since that would try to lock
230	 * smc->mutex again.
231	 */
232	const u8 flag = 0;
233
234	apple_smc_rw_locked(smc, SMC_KEY(NTAP), &flag, sizeof(flag), NULL, 0);
235
236	smc->atomic_mode = true;
237
238	return 0;
239}
240EXPORT_SYMBOL(apple_smc_enter_atomic);
241
242int apple_smc_write_atomic(struct apple_smc *smc, smc_key key, const void *buf, size_t size)
243{
244	guard(spinlock_irqsave)(&smc->lock);
245	u8 result;
246	int ret;
247	u64 msg;
248
249	if (size > SMC_MAX_SIZE || size == 0)
250		return -EINVAL;
251
252	if (smc->boot_stage != APPLE_SMC_INITIALIZED)
253		return -EIO;
254	if (!smc->atomic_mode)
255		return -EIO;
256
257	memcpy_toio(smc->shmem.iomem, buf, size);
258	smc->msg_id = (smc->msg_id + 1) & 0xf;
259	msg = (FIELD_PREP(SMC_MSG, SMC_MSG_WRITE_KEY) |
260	       FIELD_PREP(SMC_SIZE, size) |
261	       FIELD_PREP(SMC_ID, smc->msg_id) |
262	       FIELD_PREP(SMC_DATA, key));
263	smc->atomic_pending = true;
264
265	ret = apple_rtkit_send_message(smc->rtk, SMC_ENDPOINT, msg, NULL, true);
266	if (ret < 0) {
267		dev_err(smc->dev, "Failed to send command (%d)\n", ret);
268		return ret;
269	}
270
271	while (smc->atomic_pending) {
272		ret = apple_rtkit_poll(smc->rtk);
273		if (ret < 0) {
274			dev_err(smc->dev, "RTKit poll failed (%llx)", msg);
275			return ret;
276		}
277		udelay(100);
278	}
279
280	if (FIELD_GET(SMC_ID, smc->cmd_ret) != smc->msg_id) {
281		dev_err(smc->dev, "Command sequence mismatch (expected %d, got %d)\n",
282			smc->msg_id, (unsigned int)FIELD_GET(SMC_ID, smc->cmd_ret));
283		return -EIO;
284	}
285
286	result = FIELD_GET(SMC_RESULT, smc->cmd_ret);
287	if (result)
288		return -EIO;
289
290	return FIELD_GET(SMC_SIZE, smc->cmd_ret);
291}
292EXPORT_SYMBOL(apple_smc_write_atomic);
293
294static void apple_smc_rtkit_crashed(void *cookie, const void *bfr, size_t bfr_len)
295{
296	struct apple_smc *smc = cookie;
297
298	smc->boot_stage = APPLE_SMC_ERROR_CRASHED;
299	dev_err(smc->dev, "SMC crashed! Your system will reboot in a few seconds...\n");
300}
301
302static int apple_smc_rtkit_shmem_setup(void *cookie, struct apple_rtkit_shmem *bfr)
303{
304	struct apple_smc *smc = cookie;
305	size_t bfr_end;
306
307	if (!bfr->iova) {
308		dev_err(smc->dev, "RTKit wants a RAM buffer\n");
309		return -EIO;
310	}
311
312	if (check_add_overflow(bfr->iova, bfr->size - 1, &bfr_end))
313		return -EFAULT;
314
315	if (bfr->iova < smc->sram->start || bfr->iova > smc->sram->end ||
316	    bfr_end > smc->sram->end) {
317		dev_err(smc->dev, "RTKit buffer request outside SRAM region: [0x%llx, 0x%llx]\n",
318			(unsigned long long)bfr->iova,
319			(unsigned long long)bfr_end);
320		return -EFAULT;
321	}
322
323	bfr->iomem = smc->sram_base + (bfr->iova - smc->sram->start);
324	bfr->is_mapped = true;
325
326	return 0;
327}
328
329static bool apple_smc_rtkit_recv_early(void *cookie, u8 endpoint, u64 message)
330{
331	struct apple_smc *smc = cookie;
332
333	if (endpoint != SMC_ENDPOINT) {
334		dev_warn(smc->dev, "Received message for unknown endpoint 0x%x\n", endpoint);
335		return false;
336	}
337
338	if (smc->boot_stage == APPLE_SMC_BOOTING) {
339		int ret;
340
341		smc->shmem.iova = message;
342		smc->shmem.size = SMC_SHMEM_SIZE;
343		ret = apple_smc_rtkit_shmem_setup(smc, &smc->shmem);
344		if (ret < 0) {
345			smc->boot_stage = APPLE_SMC_ERROR_NO_SHMEM;
346			dev_err(smc->dev, "Failed to initialize shared memory (%d)\n", ret);
347		} else {
348			smc->boot_stage = APPLE_SMC_INITIALIZED;
349		}
350		complete(&smc->init_done);
351	} else if (FIELD_GET(SMC_MSG, message) == SMC_MSG_NOTIFICATION) {
352		/* Handle these in the RTKit worker thread */
353		return false;
354	} else {
355		smc->cmd_ret = message;
356		if (smc->atomic_pending)
357			smc->atomic_pending = false;
358		else
359			complete(&smc->cmd_done);
360	}
361
362	return true;
363}
364
365static void apple_smc_rtkit_recv(void *cookie, u8 endpoint, u64 message)
366{
367	struct apple_smc *smc = cookie;
368
369	if (endpoint != SMC_ENDPOINT) {
370		dev_warn(smc->dev, "Received message for unknown endpoint 0x%x\n", endpoint);
371		return;
372	}
373
374	if (FIELD_GET(SMC_MSG, message) != SMC_MSG_NOTIFICATION) {
375		dev_warn(smc->dev, "Received unknown message from worker: 0x%llx\n", message);
376		return;
377	}
378
379	blocking_notifier_call_chain(&smc->event_handlers, FIELD_GET(SMC_DATA, message), NULL);
380}
381
382static const struct apple_rtkit_ops apple_smc_rtkit_ops = {
383	.crashed = apple_smc_rtkit_crashed,
384	.recv_message = apple_smc_rtkit_recv,
385	.recv_message_early = apple_smc_rtkit_recv_early,
386	.shmem_setup = apple_smc_rtkit_shmem_setup,
387};
388
389static void apple_smc_rtkit_shutdown(void *data)
390{
391	struct apple_smc *smc = data;
392
393	/* Shut down SMC firmware, if it's not completely wedged */
394	if (apple_rtkit_is_running(smc->rtk))
395		apple_rtkit_quiesce(smc->rtk);
396}
397
398static void apple_smc_disable_notifications(void *data)
399{
400	struct apple_smc *smc = data;
401
402	apple_smc_write_flag(smc, SMC_KEY(NTAP), false);
403}
404
405static int apple_smc_probe(struct platform_device *pdev)
406{
407	struct device *dev = &pdev->dev;
408	struct apple_smc *smc;
409	u32 count;
410	int ret;
411
412	smc = devm_kzalloc(dev, sizeof(*smc), GFP_KERNEL);
413	if (!smc)
414		return -ENOMEM;
415
416	mutex_init(&smc->mutex);
417	smc->dev = &pdev->dev;
418	smc->sram_base = devm_platform_get_and_ioremap_resource(pdev, 1, &smc->sram);
419	if (IS_ERR(smc->sram_base))
420		return dev_err_probe(dev, PTR_ERR(smc->sram_base), "Failed to map SRAM region");
421
422	smc->rtk = devm_apple_rtkit_init(dev, smc, NULL, 0, &apple_smc_rtkit_ops);
423	if (IS_ERR(smc->rtk))
424		return dev_err_probe(dev, PTR_ERR(smc->rtk), "Failed to initialize RTKit");
425
426	smc->boot_stage = APPLE_SMC_BOOTING;
427	ret = apple_rtkit_wake(smc->rtk);
428	if (ret)
429		return dev_err_probe(dev, ret, "Failed to wake up SMC");
430
431	ret = devm_add_action_or_reset(dev, apple_smc_rtkit_shutdown, smc);
432	if (ret)
433		return ret;
434
435	ret = apple_rtkit_start_ep(smc->rtk, SMC_ENDPOINT);
436	if (ret)
437		return dev_err_probe(dev, ret, "Failed to start SMC endpoint");
438
439	init_completion(&smc->init_done);
440	init_completion(&smc->cmd_done);
441
442	ret = apple_rtkit_send_message(smc->rtk, SMC_ENDPOINT,
443				       FIELD_PREP(SMC_MSG, SMC_MSG_INITIALIZE), NULL, false);
444	if (ret)
445		return dev_err_probe(dev, ret, "Failed to send init message");
446
447	if (wait_for_completion_timeout(&smc->init_done, msecs_to_jiffies(SMC_TIMEOUT_MS)) == 0) {
448		dev_err(dev, "Timed out initializing SMC");
449		return -ETIMEDOUT;
450	}
451
452	if (smc->boot_stage != APPLE_SMC_INITIALIZED) {
453		dev_err(dev, "SMC failed to boot successfully, boot stage=%d\n", smc->boot_stage);
454		return -EIO;
455	}
456
457	dev_set_drvdata(&pdev->dev, smc);
458	BLOCKING_INIT_NOTIFIER_HEAD(&smc->event_handlers);
459
460	ret = apple_smc_read_u32(smc, SMC_KEY(#KEY), &count);
461	if (ret)
462		return dev_err_probe(smc->dev, ret, "Failed to get key count");
463	smc->key_count = be32_to_cpu(count);
464
465	/* Enable notifications */
466	apple_smc_write_flag(smc, SMC_KEY(NTAP), true);
467	ret = devm_add_action_or_reset(dev, apple_smc_disable_notifications, smc);
468	if (ret)
469		return ret;
470
471	ret = devm_mfd_add_devices(smc->dev, PLATFORM_DEVID_NONE,
472				   apple_smc_devs, ARRAY_SIZE(apple_smc_devs),
473				   NULL, 0, NULL);
474	if (ret)
475		return dev_err_probe(smc->dev, ret, "Failed to register sub-devices");
476
477
478	return 0;
479}
480
481static const struct of_device_id apple_smc_of_match[] = {
482	{ .compatible = "apple,t8103-smc" },
483	{ .compatible = "apple,smc" },
484	{},
485};
486MODULE_DEVICE_TABLE(of, apple_smc_of_match);
487
488static struct platform_driver apple_smc_driver = {
489	.driver = {
490		.name = "macsmc",
491		.of_match_table = apple_smc_of_match,
492	},
493	.probe = apple_smc_probe,
494};
495module_platform_driver(apple_smc_driver);
496
497MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
498MODULE_AUTHOR("Sven Peter <sven@kernel.org>");
499MODULE_LICENSE("Dual MIT/GPL");
500MODULE_DESCRIPTION("Apple SMC driver");
~/ Read-only file preview.