u-boot-brain/common/spl/spl_opensbi.c
Lukas Auer 90ae281437 riscv: add option to wait for ack from secondary harts in smp functions
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>
2019-12-10 08:23:10 +08:00

88 lines
2.1 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019 Fraunhofer AISEC,
* Lukas Auer <lukas.auer@aisec.fraunhofer.de>
*
* Based on common/spl/spl_atf.c
*/
#include <common.h>
#include <cpu_func.h>
#include <errno.h>
#include <spl.h>
#include <asm/smp.h>
#include <opensbi.h>
DECLARE_GLOBAL_DATA_PTR;
struct fw_dynamic_info opensbi_info;
static int spl_opensbi_find_uboot_node(void *blob, int *uboot_node)
{
int fit_images_node, node;
const char *fit_os;
fit_images_node = fdt_path_offset(blob, "/fit-images");
if (fit_images_node < 0)
return -ENODEV;
fdt_for_each_subnode(node, blob, fit_images_node) {
fit_os = fdt_getprop(blob, node, FIT_OS_PROP, NULL);
if (!fit_os)
continue;
if (genimg_get_os_id(fit_os) == IH_OS_U_BOOT) {
*uboot_node = node;
return 0;
}
}
return -ENODEV;
}
void spl_invoke_opensbi(struct spl_image_info *spl_image)
{
int ret, uboot_node;
ulong uboot_entry;
void (*opensbi_entry)(ulong hartid, ulong dtb, ulong info);
if (!spl_image->fdt_addr) {
pr_err("No device tree specified in SPL image\n");
hang();
}
/* Find U-Boot image in /fit-images */
ret = spl_opensbi_find_uboot_node(spl_image->fdt_addr, &uboot_node);
if (ret) {
pr_err("Can't find U-Boot node, %d", ret);
hang();
}
/* Get U-Boot entry point */
uboot_entry = fdt_getprop_u32(spl_image->fdt_addr, uboot_node,
"entry-point");
if (uboot_entry == FDT_ERROR)
uboot_entry = fdt_getprop_u32(spl_image->fdt_addr, uboot_node,
"load-addr");
/* Prepare obensbi_info object */
opensbi_info.magic = FW_DYNAMIC_INFO_MAGIC_VALUE;
opensbi_info.version = FW_DYNAMIC_INFO_VERSION;
opensbi_info.next_addr = uboot_entry;
opensbi_info.next_mode = FW_DYNAMIC_INFO_NEXT_MODE_S;
opensbi_info.options = SBI_SCRATCH_NO_BOOT_PRINTS;
opensbi_info.boot_hart = gd->arch.boot_hart;
opensbi_entry = (void (*)(ulong, ulong, ulong))spl_image->entry_point;
invalidate_icache_all();
#ifdef CONFIG_SMP
ret = smp_call_function((ulong)spl_image->entry_point,
(ulong)spl_image->fdt_addr,
(ulong)&opensbi_info, 0);
if (ret)
hang();
#endif
opensbi_entry(gd->arch.boot_hart, (ulong)spl_image->fdt_addr,
(ulong)&opensbi_info);
}