blob: 17adb35730d83c08d67f477c534379cd561fe5c7 [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
15/**
16 * riscv_send_ipi() - Send inter-processor interrupt (IPI)
17 *
18 * Platform code must provide this function.
19 *
20 * @hart: Hart ID of receiving hart
21 * @return 0 if OK, -ve on error
22 */
23extern int riscv_send_ipi(int hart);
24
25/**
26 * riscv_clear_ipi() - Clear inter-processor interrupt (IPI)
27 *
28 * Platform code must provide this function.
29 *
30 * @hart: Hart ID of hart to be cleared
31 * @return 0 if OK, -ve on error
32 */
33extern int riscv_clear_ipi(int hart);
34
Lukas Auerc7460b82019-12-08 23:28:50 +010035/**
36 * riscv_get_ipi() - Get status of inter-processor interrupt (IPI)
37 *
38 * Platform code must provide this function.
39 *
40 * @hart: Hart ID of hart to be checked
41 * @pending: Pointer to variable with result of the check,
42 * 1 if IPI is pending, 0 otherwise
43 * @return 0 if OK, -ve on error
44 */
45extern int riscv_get_ipi(int hart, int *pending);
46
Lukas Auerc308e012019-12-08 23:28:51 +010047static int send_ipi_many(struct ipi_data *ipi, int wait)
Lukas Auer83d573d2019-03-17 19:28:32 +010048{
49 ofnode node, cpus;
50 u32 reg;
Lukas Auerc308e012019-12-08 23:28:51 +010051 int ret, pending;
Lukas Auer83d573d2019-03-17 19:28:32 +010052
53 cpus = ofnode_path("/cpus");
54 if (!ofnode_valid(cpus)) {
55 pr_err("Can't find cpus node!\n");
56 return -EINVAL;
57 }
58
59 ofnode_for_each_subnode(node, cpus) {
60 /* skip if hart is marked as not available in the device tree */
61 if (!ofnode_is_available(node))
62 continue;
63
64 /* read hart ID of CPU */
65 ret = ofnode_read_u32(node, "reg", &reg);
66 if (ret)
67 continue;
68
69 /* skip if it is the hart we are running on */
70 if (reg == gd->arch.boot_hart)
71 continue;
72
73 if (reg >= CONFIG_NR_CPUS) {
74 pr_err("Hart ID %d is out of range, increase CONFIG_NR_CPUS\n",
75 reg);
76 continue;
77 }
78
Rick Chene5e6c362019-04-30 13:49:33 +080079#ifndef CONFIG_XIP
Lukas Auer83d573d2019-03-17 19:28:32 +010080 /* skip if hart is not available */
81 if (!(gd->arch.available_harts & (1 << reg)))
82 continue;
Rick Chene5e6c362019-04-30 13:49:33 +080083#endif
Lukas Auer83d573d2019-03-17 19:28:32 +010084
85 gd->arch.ipi[reg].addr = ipi->addr;
86 gd->arch.ipi[reg].arg0 = ipi->arg0;
87 gd->arch.ipi[reg].arg1 = ipi->arg1;
88
89 ret = riscv_send_ipi(reg);
90 if (ret) {
91 pr_err("Cannot send IPI to hart %d\n", reg);
92 return ret;
93 }
Lukas Auerc308e012019-12-08 23:28:51 +010094
95 if (wait) {
96 pending = 1;
97 while (pending) {
98 ret = riscv_get_ipi(reg, &pending);
99 if (ret)
100 return ret;
101 }
102 }
Lukas Auer83d573d2019-03-17 19:28:32 +0100103 }
104
105 return 0;
106}
107
108void handle_ipi(ulong hart)
109{
110 int ret;
111 void (*smp_function)(ulong hart, ulong arg0, ulong arg1);
112
113 if (hart >= CONFIG_NR_CPUS)
114 return;
115
Lukas Auerc308e012019-12-08 23:28:51 +0100116 __smp_mb();
117
118 smp_function = (void (*)(ulong, ulong, ulong))gd->arch.ipi[hart].addr;
119 invalidate_icache_all();
120
121 /*
122 * Clear the IPI to acknowledge the request before jumping to the
123 * requested function.
124 */
Lukas Auer83d573d2019-03-17 19:28:32 +0100125 ret = riscv_clear_ipi(hart);
126 if (ret) {
127 pr_err("Cannot clear IPI of hart %ld\n", hart);
128 return;
129 }
130
Lukas Auer83d573d2019-03-17 19:28:32 +0100131 smp_function(hart, gd->arch.ipi[hart].arg0, gd->arch.ipi[hart].arg1);
132}
133
Lukas Auerc308e012019-12-08 23:28:51 +0100134int smp_call_function(ulong addr, ulong arg0, ulong arg1, int wait)
Lukas Auer83d573d2019-03-17 19:28:32 +0100135{
136 int ret = 0;
137 struct ipi_data ipi;
138
139 ipi.addr = addr;
140 ipi.arg0 = arg0;
141 ipi.arg1 = arg1;
142
Lukas Auerc308e012019-12-08 23:28:51 +0100143 ret = send_ipi_many(&ipi, wait);
Lukas Auer83d573d2019-03-17 19:28:32 +0100144
145 return ret;
146}