1// 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 <cpu_func.h> 8#include <dm.h> 9#include <asm/barrier.h> 10#include <asm/global_data.h> 11#include <asm/smp.h> 12#include <linux/printk.h> 13 14DECLARE_GLOBAL_DATA_PTR; 15 16static int send_ipi_many(struct ipi_data *ipi, int wait) 17{ 18 ofnode node, cpus; 19 u32 reg; 20 int ret, pending; 21 22 cpus = ofnode_path("/cpus"); 23 if (!ofnode_valid(cpus)) { 24 pr_err("Can't find cpus node!\n"); 25 return -EINVAL; 26 } 27 28 ofnode_for_each_subnode(node, cpus) { 29 /* skip if hart is marked as not available in the device tree */ 30 if (!ofnode_is_enabled(node)) 31 continue; 32 33 /* read hart ID of CPU */ 34 ret = ofnode_read_u32(node, "reg", ®); 35 if (ret) 36 continue; 37 38 /* skip if it is the hart we are running on */ 39 if (reg == gd->arch.boot_hart) 40 continue; 41 42 if (reg >= CONFIG_NR_CPUS) { 43 pr_err("Hart ID %d is out of range, increase CONFIG_NR_CPUS\n", 44 reg); 45 continue; 46 } 47 48#if !CONFIG_IS_ENABLED(XIP) 49#ifdef CONFIG_AVAILABLE_HARTS 50 /* skip if hart is not available */ 51 if (!(gd->arch.available_harts & (1 << reg))) 52 continue; 53#endif 54#endif 55 56 gd->arch.ipi[reg].addr = ipi->addr; 57 gd->arch.ipi[reg].arg0 = ipi->arg0; 58 gd->arch.ipi[reg].arg1 = ipi->arg1; 59 60 /* 61 * Ensure valid only becomes set when the IPI parameters are 62 * set. An IPI may already be pending on other harts, so we 63 * need a way to signal that the IPI device has been 64 * initialized, and that it is ok to call the function. 65 */ 66 __smp_store_release(&gd->arch.ipi[reg].valid, 1); 67 68 ret = riscv_send_ipi(reg); 69 if (ret) { 70 pr_err("Cannot send IPI to hart %d\n", reg); 71 return ret; 72 } 73 74 if (wait) { 75 pending = 1; 76 while (pending) { 77 ret = riscv_get_ipi(reg, &pending); 78 if (ret) 79 return ret; 80 } 81 } 82 } 83 84 return 0; 85} 86 87void handle_ipi(ulong hart) 88{ 89 int ret; 90 void (*smp_function)(ulong hart, ulong arg0, ulong arg1); 91 92 if (hart >= CONFIG_NR_CPUS) 93 return; 94 95 /* 96 * If valid is not set, then U-Boot has not requested the IPI. The 97 * IPI device may not be initialized, so all we can do is wait for 98 * U-Boot to initialize it and send an IPI 99 */ 100 if (!__smp_load_acquire(&gd->arch.ipi[hart].valid)) 101 return; 102 103 smp_function = (void (*)(ulong, ulong, ulong))gd->arch.ipi[hart].addr; 104 invalidate_icache_all(); 105 106 /* 107 * Clear the IPI to acknowledge the request before jumping to the 108 * requested function. 109 */ 110 ret = riscv_clear_ipi(hart); 111 if (ret) { 112 pr_err("Cannot clear IPI of hart %ld (error %d)\n", hart, ret); 113 return; 114 } 115 116 smp_function(hart, gd->arch.ipi[hart].arg0, gd->arch.ipi[hart].arg1); 117} 118 119int smp_call_function(ulong addr, ulong arg0, ulong arg1, int wait) 120{ 121 struct ipi_data ipi = { 122 .addr = addr, 123 .arg0 = arg0, 124 .arg1 = arg1, 125 }; 126 127 return send_ipi_many(&ipi, wait); 128} 129