blob: f3cd8b9044a8e09d6c1a42bb6246a1fa4d4914e9 [file] [log] [blame]
Lukas Auerfa33f082019-03-17 19:28:32 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2019 Fraunhofer AISEC,
4 * Lukas Auer <lukas.auer@aisec.fraunhofer.de>
5 */
6
7#include <common.h>
Simon Glass1eb69ae2019-11-14 12:57:39 -07008#include <cpu_func.h>
Lukas Auerfa33f082019-03-17 19:28:32 +01009#include <dm.h>
10#include <asm/barrier.h>
Simon Glass401d1c42020-10-30 21:38:53 -060011#include <asm/global_data.h>
Lukas Auerfa33f082019-03-17 19:28:32 +010012#include <asm/smp.h>
Simon Glass1e94b462023-09-14 18:21:46 -060013#include <linux/printk.h>
Lukas Auerfa33f082019-03-17 19:28:32 +010014
15DECLARE_GLOBAL_DATA_PTR;
16
Lukas Auer90ae2812019-12-08 23:28:51 +010017static int send_ipi_many(struct ipi_data *ipi, int wait)
Lukas Auerfa33f082019-03-17 19:28:32 +010018{
19 ofnode node, cpus;
20 u32 reg;
Lukas Auer90ae2812019-12-08 23:28:51 +010021 int ret, pending;
Lukas Auerfa33f082019-03-17 19:28:32 +010022
23 cpus = ofnode_path("/cpus");
24 if (!ofnode_valid(cpus)) {
25 pr_err("Can't find cpus node!\n");
26 return -EINVAL;
27 }
28
29 ofnode_for_each_subnode(node, cpus) {
30 /* skip if hart is marked as not available in the device tree */
Simon Glass89090662022-09-06 20:27:17 -060031 if (!ofnode_is_enabled(node))
Lukas Auerfa33f082019-03-17 19:28:32 +010032 continue;
33
34 /* read hart ID of CPU */
35 ret = ofnode_read_u32(node, "reg", &reg);
36 if (ret)
37 continue;
38
39 /* skip if it is the hart we are running on */
40 if (reg == gd->arch.boot_hart)
41 continue;
42
43 if (reg >= CONFIG_NR_CPUS) {
44 pr_err("Hart ID %d is out of range, increase CONFIG_NR_CPUS\n",
45 reg);
46 continue;
47 }
48
Nikita Shubinc2bdf022022-09-02 11:47:39 +030049#if !CONFIG_IS_ENABLED(XIP)
Rick Chene0465f82022-09-21 14:34:54 +080050#ifdef CONFIG_AVAILABLE_HARTS
Lukas Auerfa33f082019-03-17 19:28:32 +010051 /* skip if hart is not available */
52 if (!(gd->arch.available_harts & (1 << reg)))
53 continue;
Rick Chenbdce3892019-04-30 13:49:33 +080054#endif
Rick Chene0465f82022-09-21 14:34:54 +080055#endif
Lukas Auerfa33f082019-03-17 19:28:32 +010056
57 gd->arch.ipi[reg].addr = ipi->addr;
58 gd->arch.ipi[reg].arg0 = ipi->arg0;
59 gd->arch.ipi[reg].arg1 = ipi->arg1;
60
Sean Andersonf760c9a2020-09-21 07:51:37 -040061 /*
62 * Ensure valid only becomes set when the IPI parameters are
63 * set. An IPI may already be pending on other harts, so we
64 * need a way to signal that the IPI device has been
65 * initialized, and that it is ok to call the function.
66 */
67 __smp_store_release(&gd->arch.ipi[reg].valid, 1);
Sean Andersond4990a42020-09-21 07:51:36 -040068
Lukas Auerfa33f082019-03-17 19:28:32 +010069 ret = riscv_send_ipi(reg);
70 if (ret) {
71 pr_err("Cannot send IPI to hart %d\n", reg);
72 return ret;
73 }
Lukas Auer90ae2812019-12-08 23:28:51 +010074
75 if (wait) {
76 pending = 1;
77 while (pending) {
78 ret = riscv_get_ipi(reg, &pending);
79 if (ret)
80 return ret;
81 }
82 }
Lukas Auerfa33f082019-03-17 19:28:32 +010083 }
84
85 return 0;
86}
87
88void handle_ipi(ulong hart)
89{
90 int ret;
91 void (*smp_function)(ulong hart, ulong arg0, ulong arg1);
92
93 if (hart >= CONFIG_NR_CPUS)
94 return;
95
Sean Andersonf760c9a2020-09-21 07:51:37 -040096 /*
97 * If valid is not set, then U-Boot has not requested the IPI. The
98 * IPI device may not be initialized, so all we can do is wait for
99 * U-Boot to initialize it and send an IPI
100 */
101 if (!__smp_load_acquire(&gd->arch.ipi[hart].valid))
102 return;
Lukas Auer90ae2812019-12-08 23:28:51 +0100103
104 smp_function = (void (*)(ulong, ulong, ulong))gd->arch.ipi[hart].addr;
105 invalidate_icache_all();
106
107 /*
108 * Clear the IPI to acknowledge the request before jumping to the
109 * requested function.
110 */
Lukas Auerfa33f082019-03-17 19:28:32 +0100111 ret = riscv_clear_ipi(hart);
112 if (ret) {
Sean Anderson40686c32020-06-24 06:41:18 -0400113 pr_err("Cannot clear IPI of hart %ld (error %d)\n", hart, ret);
Lukas Auerfa33f082019-03-17 19:28:32 +0100114 return;
115 }
116
Lukas Auerfa33f082019-03-17 19:28:32 +0100117 smp_function(hart, gd->arch.ipi[hart].arg0, gd->arch.ipi[hart].arg1);
118}
119
Lukas Auer90ae2812019-12-08 23:28:51 +0100120int smp_call_function(ulong addr, ulong arg0, ulong arg1, int wait)
Lukas Auerfa33f082019-03-17 19:28:32 +0100121{
Sean Anderson40686c32020-06-24 06:41:18 -0400122 struct ipi_data ipi = {
123 .addr = addr,
124 .arg0 = arg0,
125 .arg1 = arg1,
126 };
Lukas Auerfa33f082019-03-17 19:28:32 +0100127
Sean Anderson40686c32020-06-24 06:41:18 -0400128 return send_ipi_many(&ipi, wait);
Lukas Auerfa33f082019-03-17 19:28:32 +0100129}