blob: 8f33ce1fe3699a5f0dd20f9e5787e0794a8f2209 [file] [log] [blame]
Lukas Auer83d573d2019-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 Glass63334482019-11-14 12:57:39 -07008#include <cpu_func.h>
Lukas Auer83d573d2019-03-17 19:28:32 +01009#include <dm.h>
10#include <asm/barrier.h>
11#include <asm/smp.h>
12
13DECLARE_GLOBAL_DATA_PTR;
14
Lukas Auerc308e012019-12-08 23:28:51 +010015static int send_ipi_many(struct ipi_data *ipi, int wait)
Lukas Auer83d573d2019-03-17 19:28:32 +010016{
17 ofnode node, cpus;
18 u32 reg;
Lukas Auerc308e012019-12-08 23:28:51 +010019 int ret, pending;
Lukas Auer83d573d2019-03-17 19:28:32 +010020
21 cpus = ofnode_path("/cpus");
22 if (!ofnode_valid(cpus)) {
23 pr_err("Can't find cpus node!\n");
24 return -EINVAL;
25 }
26
27 ofnode_for_each_subnode(node, cpus) {
28 /* skip if hart is marked as not available in the device tree */
29 if (!ofnode_is_available(node))
30 continue;
31
32 /* read hart ID of CPU */
33 ret = ofnode_read_u32(node, "reg", &reg);
34 if (ret)
35 continue;
36
37 /* skip if it is the hart we are running on */
38 if (reg == gd->arch.boot_hart)
39 continue;
40
41 if (reg >= CONFIG_NR_CPUS) {
42 pr_err("Hart ID %d is out of range, increase CONFIG_NR_CPUS\n",
43 reg);
44 continue;
45 }
46
Rick Chene5e6c362019-04-30 13:49:33 +080047#ifndef CONFIG_XIP
Lukas Auer83d573d2019-03-17 19:28:32 +010048 /* skip if hart is not available */
49 if (!(gd->arch.available_harts & (1 << reg)))
50 continue;
Rick Chene5e6c362019-04-30 13:49:33 +080051#endif
Lukas Auer83d573d2019-03-17 19:28:32 +010052
53 gd->arch.ipi[reg].addr = ipi->addr;
54 gd->arch.ipi[reg].arg0 = ipi->arg0;
55 gd->arch.ipi[reg].arg1 = ipi->arg1;
56
Sean Andersonff184fe2020-09-21 07:51:37 -040057 /*
58 * Ensure valid only becomes set when the IPI parameters are
59 * set. An IPI may already be pending on other harts, so we
60 * need a way to signal that the IPI device has been
61 * initialized, and that it is ok to call the function.
62 */
63 __smp_store_release(&gd->arch.ipi[reg].valid, 1);
Sean Andersoncfb08092020-09-21 07:51:36 -040064
Lukas Auer83d573d2019-03-17 19:28:32 +010065 ret = riscv_send_ipi(reg);
66 if (ret) {
67 pr_err("Cannot send IPI to hart %d\n", reg);
68 return ret;
69 }
Lukas Auerc308e012019-12-08 23:28:51 +010070
71 if (wait) {
72 pending = 1;
73 while (pending) {
74 ret = riscv_get_ipi(reg, &pending);
75 if (ret)
76 return ret;
77 }
78 }
Lukas Auer83d573d2019-03-17 19:28:32 +010079 }
80
81 return 0;
82}
83
84void handle_ipi(ulong hart)
85{
86 int ret;
87 void (*smp_function)(ulong hart, ulong arg0, ulong arg1);
88
89 if (hart >= CONFIG_NR_CPUS)
90 return;
91
Sean Andersonff184fe2020-09-21 07:51:37 -040092 /*
93 * If valid is not set, then U-Boot has not requested the IPI. The
94 * IPI device may not be initialized, so all we can do is wait for
95 * U-Boot to initialize it and send an IPI
96 */
97 if (!__smp_load_acquire(&gd->arch.ipi[hart].valid))
98 return;
Lukas Auerc308e012019-12-08 23:28:51 +010099
100 smp_function = (void (*)(ulong, ulong, ulong))gd->arch.ipi[hart].addr;
101 invalidate_icache_all();
102
103 /*
104 * Clear the IPI to acknowledge the request before jumping to the
105 * requested function.
106 */
Lukas Auer83d573d2019-03-17 19:28:32 +0100107 ret = riscv_clear_ipi(hart);
108 if (ret) {
Sean Andersonb1d0cb32020-06-24 06:41:18 -0400109 pr_err("Cannot clear IPI of hart %ld (error %d)\n", hart, ret);
Lukas Auer83d573d2019-03-17 19:28:32 +0100110 return;
111 }
112
Lukas Auer83d573d2019-03-17 19:28:32 +0100113 smp_function(hart, gd->arch.ipi[hart].arg0, gd->arch.ipi[hart].arg1);
114}
115
Lukas Auerc308e012019-12-08 23:28:51 +0100116int smp_call_function(ulong addr, ulong arg0, ulong arg1, int wait)
Lukas Auer83d573d2019-03-17 19:28:32 +0100117{
Sean Andersonb1d0cb32020-06-24 06:41:18 -0400118 struct ipi_data ipi = {
119 .addr = addr,
120 .arg0 = arg0,
121 .arg1 = arg1,
122 };
Lukas Auer83d573d2019-03-17 19:28:32 +0100123
Sean Andersonb1d0cb32020-06-24 06:41:18 -0400124 return send_ipi_many(&ipi, wait);
Lukas Auer83d573d2019-03-17 19:28:32 +0100125}