mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-11 23:47:24 +00:00
90ae281437
Add a wait option to smp_call_function() to wait for the secondary harts to acknowledge the call-function request. The request is considered to be acknowledged once each secondary hart has cleared the corresponding IPI. As part of the call-function request, the secondary harts invalidate the instruction cache after clearing the IPI. This adds a delay between acknowledgment (clear IPI) and fulfillment (call function) of the request. We want to use the acknowledgment to be able to judge when the request has been completed. Remove the delay by clearing the IPI after cache invalidation and just before calling the function from the request. Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de> Reviewed-by: Rick Chen <rick@andestech.com> Tested-by: Rick Chen <rick@andestech.com> Reviewed-by: Anup Patel <anup.patel@wdc.com>
146 lines
3 KiB
C
146 lines
3 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright (C) 2019 Fraunhofer AISEC,
|
|
* Lukas Auer <lukas.auer@aisec.fraunhofer.de>
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <cpu_func.h>
|
|
#include <dm.h>
|
|
#include <asm/barrier.h>
|
|
#include <asm/smp.h>
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
/**
|
|
* riscv_send_ipi() - Send inter-processor interrupt (IPI)
|
|
*
|
|
* Platform code must provide this function.
|
|
*
|
|
* @hart: Hart ID of receiving hart
|
|
* @return 0 if OK, -ve on error
|
|
*/
|
|
extern int riscv_send_ipi(int hart);
|
|
|
|
/**
|
|
* riscv_clear_ipi() - Clear inter-processor interrupt (IPI)
|
|
*
|
|
* Platform code must provide this function.
|
|
*
|
|
* @hart: Hart ID of hart to be cleared
|
|
* @return 0 if OK, -ve on error
|
|
*/
|
|
extern int riscv_clear_ipi(int hart);
|
|
|
|
/**
|
|
* riscv_get_ipi() - Get status of inter-processor interrupt (IPI)
|
|
*
|
|
* Platform code must provide this function.
|
|
*
|
|
* @hart: Hart ID of hart to be checked
|
|
* @pending: Pointer to variable with result of the check,
|
|
* 1 if IPI is pending, 0 otherwise
|
|
* @return 0 if OK, -ve on error
|
|
*/
|
|
extern int riscv_get_ipi(int hart, int *pending);
|
|
|
|
static int send_ipi_many(struct ipi_data *ipi, int wait)
|
|
{
|
|
ofnode node, cpus;
|
|
u32 reg;
|
|
int ret, pending;
|
|
|
|
cpus = ofnode_path("/cpus");
|
|
if (!ofnode_valid(cpus)) {
|
|
pr_err("Can't find cpus node!\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ofnode_for_each_subnode(node, cpus) {
|
|
/* skip if hart is marked as not available in the device tree */
|
|
if (!ofnode_is_available(node))
|
|
continue;
|
|
|
|
/* read hart ID of CPU */
|
|
ret = ofnode_read_u32(node, "reg", ®);
|
|
if (ret)
|
|
continue;
|
|
|
|
/* skip if it is the hart we are running on */
|
|
if (reg == gd->arch.boot_hart)
|
|
continue;
|
|
|
|
if (reg >= CONFIG_NR_CPUS) {
|
|
pr_err("Hart ID %d is out of range, increase CONFIG_NR_CPUS\n",
|
|
reg);
|
|
continue;
|
|
}
|
|
|
|
#ifndef CONFIG_XIP
|
|
/* skip if hart is not available */
|
|
if (!(gd->arch.available_harts & (1 << reg)))
|
|
continue;
|
|
#endif
|
|
|
|
gd->arch.ipi[reg].addr = ipi->addr;
|
|
gd->arch.ipi[reg].arg0 = ipi->arg0;
|
|
gd->arch.ipi[reg].arg1 = ipi->arg1;
|
|
|
|
ret = riscv_send_ipi(reg);
|
|
if (ret) {
|
|
pr_err("Cannot send IPI to hart %d\n", reg);
|
|
return ret;
|
|
}
|
|
|
|
if (wait) {
|
|
pending = 1;
|
|
while (pending) {
|
|
ret = riscv_get_ipi(reg, &pending);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void handle_ipi(ulong hart)
|
|
{
|
|
int ret;
|
|
void (*smp_function)(ulong hart, ulong arg0, ulong arg1);
|
|
|
|
if (hart >= CONFIG_NR_CPUS)
|
|
return;
|
|
|
|
__smp_mb();
|
|
|
|
smp_function = (void (*)(ulong, ulong, ulong))gd->arch.ipi[hart].addr;
|
|
invalidate_icache_all();
|
|
|
|
/*
|
|
* Clear the IPI to acknowledge the request before jumping to the
|
|
* requested function.
|
|
*/
|
|
ret = riscv_clear_ipi(hart);
|
|
if (ret) {
|
|
pr_err("Cannot clear IPI of hart %ld\n", hart);
|
|
return;
|
|
}
|
|
|
|
smp_function(hart, gd->arch.ipi[hart].arg0, gd->arch.ipi[hart].arg1);
|
|
}
|
|
|
|
int smp_call_function(ulong addr, ulong arg0, ulong arg1, int wait)
|
|
{
|
|
int ret = 0;
|
|
struct ipi_data ipi;
|
|
|
|
ipi.addr = addr;
|
|
ipi.arg0 = arg0;
|
|
ipi.arg1 = arg1;
|
|
|
|
ret = send_ipi_many(&ipi, wait);
|
|
|
|
return ret;
|
|
}
|