// SPDX-License-Identifier: GPL-2.0-only /* * SBI initialilization and all extension implementation. * * Copyright (c) 2020 Western Digital Corporation or its affiliates.
*/
/* * There is no maximum hartid concept in RISC-V and NR_CPUS must not be * associated with hartid. As SBI v0.1 is only kept for backward compatibility * and will be removed in the future, there is no point in supporting hartid * greater than BITS_PER_LONG (32 for RV32 and 64 for RV64). Ideally, SBI v0.2 * should be used for platforms with hartid greater than BITS_PER_LONG.
*/
for_each_cpu(cpuid, cpu_mask) {
hartid = cpuid_to_hartid_map(cpuid); if (hartid >= BITS_PER_LONG) {
pr_warn("Unable to send any request to hartid > BITS_PER_LONG for SBI v0.1\n"); break;
}
hmask |= BIT(hartid);
}
return hmask;
}
/** * sbi_console_putchar() - Writes given character to the console device. * @ch: The data to be written to the console. * * Return: None
*/ void sbi_console_putchar(int ch)
{
sbi_ecall(SBI_EXT_0_1_CONSOLE_PUTCHAR, 0, ch, 0, 0, 0, 0, 0);
}
EXPORT_SYMBOL(sbi_console_putchar);
/** * sbi_console_getchar() - Reads a byte from console device. * * Returns the value read from console.
*/ int sbi_console_getchar(void)
{ struct sbiret ret;
ret = sbi_ecall(SBI_EXT_0_1_CONSOLE_GETCHAR, 0, 0, 0, 0, 0, 0, 0);
if (!cpu_mask || cpumask_empty(cpu_mask))
cpu_mask = cpu_online_mask;
hart_mask = __sbi_v01_cpumask_to_hartmask(cpu_mask);
/* v0.2 function IDs are equivalent to v0.1 extension IDs */ switch (fid) { case SBI_EXT_RFENCE_REMOTE_FENCE_I:
sbi_ecall(SBI_EXT_0_1_REMOTE_FENCE_I, 0,
(unsignedlong)&hart_mask, 0, 0, 0, 0, 0); break; case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
sbi_ecall(SBI_EXT_0_1_REMOTE_SFENCE_VMA, 0,
(unsignedlong)&hart_mask, start, size,
0, 0, 0); break; case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
sbi_ecall(SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID, 0,
(unsignedlong)&hart_mask, start, size,
arg4, 0, 0); break; default:
pr_err("SBI call [%d]not supported in SBI v0.1\n", fid);
result = -EINVAL;
}
return result;
}
staticvoid sbi_set_power_off(void)
{
pm_power_off = sbi_shutdown;
} #else staticvoid __sbi_set_timer_v01(uint64_t stime_value)
{
pr_warn("Timer extension is not available in SBI v%lu.%lu\n",
sbi_major_version(), sbi_minor_version());
}
staticvoid __sbi_send_ipi_v01(unsignedint cpu)
{
pr_warn("IPI extension is not available in SBI v%lu.%lu\n",
sbi_major_version(), sbi_minor_version());
}
staticint __sbi_rfence_v01(int fid, conststruct cpumask *cpu_mask, unsignedlong start, unsignedlong size, unsignedlong arg4, unsignedlong arg5)
{
pr_warn("remote fence extension is not available in SBI v%lu.%lu\n",
sbi_major_version(), sbi_minor_version());
ret = sbi_fwft_set(req->feature, req->value, req->flags); if (ret)
atomic_set(&req->error, ret);
}
/** * sbi_fwft_set() - Set a feature on the local hart * @feature: The feature ID to be set * @value: The feature value to be set * @flags: FWFT feature set flags * * Return: 0 on success, appropriate linux error code otherwise.
*/ int sbi_fwft_set(u32 feature, unsignedlong value, unsignedlong flags)
{ struct sbiret ret;
if (!sbi_fwft_supported) return -EOPNOTSUPP;
ret = sbi_ecall(SBI_EXT_FWFT, SBI_EXT_FWFT_SET,
feature, value, flags, 0, 0, 0);
return sbi_err_map_linux_errno(ret.error);
}
/** * sbi_fwft_set_cpumask() - Set a feature for the specified cpumask * @mask: CPU mask of cpus that need the feature to be set * @feature: The feature ID to be set * @value: The feature value to be set * @flags: FWFT feature set flags * * Return: 0 on success, appropriate linux error code otherwise.
*/ int sbi_fwft_set_cpumask(const cpumask_t *mask, u32 feature, unsignedlong value, unsignedlong flags)
{ struct fwft_set_req req = {
.feature = feature,
.value = value,
.flags = flags,
.error = ATOMIC_INIT(0),
};
if (!sbi_fwft_supported) return -EOPNOTSUPP;
if (feature & SBI_FWFT_GLOBAL_FEATURE_BIT) return -EINVAL;
/** * sbi_set_timer() - Program the timer for next timer event. * @stime_value: The value after which next timer event should fire. * * Return: None.
*/ void sbi_set_timer(uint64_t stime_value)
{
__sbi_set_timer(stime_value);
}
/** * sbi_send_ipi() - Send an IPI to any hart. * @cpu: Logical id of the target CPU.
*/ void sbi_send_ipi(unsignedint cpu)
{
__sbi_send_ipi(cpu);
}
EXPORT_SYMBOL(sbi_send_ipi);
/** * sbi_remote_fence_i() - Execute FENCE.I instruction on given remote harts. * @cpu_mask: A cpu mask containing all the target harts. * * Return: 0 on success, appropriate linux error code otherwise.
*/ int sbi_remote_fence_i(conststruct cpumask *cpu_mask)
{ return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_FENCE_I,
cpu_mask, 0, 0, 0, 0);
}
EXPORT_SYMBOL(sbi_remote_fence_i);
/** * sbi_remote_sfence_vma_asid() - Execute SFENCE.VMA instructions on given * remote harts for a virtual address range belonging to a specific ASID or not. * * @cpu_mask: A cpu mask containing all the target harts. * @start: Start of the virtual address * @size: Total size of the virtual address range. * @asid: The value of address space identifier (ASID), or FLUSH_TLB_NO_ASID * for flushing all address spaces. * * Return: 0 on success, appropriate linux error code otherwise.
*/ int sbi_remote_sfence_vma_asid(conststruct cpumask *cpu_mask, unsignedlong start, unsignedlong size, unsignedlong asid)
{ if (asid == FLUSH_TLB_NO_ASID) return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA,
cpu_mask, start, size, 0, 0); else return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID,
cpu_mask, start, size, asid, 0);
}
EXPORT_SYMBOL(sbi_remote_sfence_vma_asid);
/** * sbi_remote_hfence_gvma() - Execute HFENCE.GVMA instructions on given remote * harts for the specified guest physical address range. * @cpu_mask: A cpu mask containing all the target harts. * @start: Start of the guest physical address * @size: Total size of the guest physical address range. * * Return: None
*/ int sbi_remote_hfence_gvma(conststruct cpumask *cpu_mask, unsignedlong start, unsignedlong size)
{ return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA,
cpu_mask, start, size, 0, 0);
}
EXPORT_SYMBOL_GPL(sbi_remote_hfence_gvma);
/** * sbi_remote_hfence_gvma_vmid() - Execute HFENCE.GVMA instructions on given * remote harts for a guest physical address range belonging to a specific VMID. * * @cpu_mask: A cpu mask containing all the target harts. * @start: Start of the guest physical address * @size: Total size of the guest physical address range. * @vmid: The value of guest ID (VMID). * * Return: 0 if success, Error otherwise.
*/ int sbi_remote_hfence_gvma_vmid(conststruct cpumask *cpu_mask, unsignedlong start, unsignedlong size, unsignedlong vmid)
{ return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID,
cpu_mask, start, size, vmid, 0);
}
EXPORT_SYMBOL(sbi_remote_hfence_gvma_vmid);
/** * sbi_remote_hfence_vvma() - Execute HFENCE.VVMA instructions on given remote * harts for the current guest virtual address range. * @cpu_mask: A cpu mask containing all the target harts. * @start: Start of the current guest virtual address * @size: Total size of the current guest virtual address range. * * Return: None
*/ int sbi_remote_hfence_vvma(conststruct cpumask *cpu_mask, unsignedlong start, unsignedlong size)
{ return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA,
cpu_mask, start, size, 0, 0);
}
EXPORT_SYMBOL(sbi_remote_hfence_vvma);
/** * sbi_remote_hfence_vvma_asid() - Execute HFENCE.VVMA instructions on given * remote harts for current guest virtual address range belonging to a specific * ASID. * * @cpu_mask: A cpu mask containing all the target harts. * @start: Start of the current guest virtual address * @size: Total size of the current guest virtual address range. * @asid: The value of address space identifier (ASID). * * Return: None
*/ int sbi_remote_hfence_vvma_asid(conststruct cpumask *cpu_mask, unsignedlong start, unsignedlong size, unsignedlong asid)
{ return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID,
cpu_mask, start, size, asid, 0);
}
EXPORT_SYMBOL(sbi_remote_hfence_vvma_asid);
/** * sbi_probe_extension() - Check if an SBI extension ID is supported or not. * @extid: The extension ID to be probed. * * Return: 1 or an extension specific nonzero value if yes, 0 otherwise.
*/ long sbi_probe_extension(int extid)
{ struct sbiret ret;
ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, extid,
0, 0, 0, 0, 0); if (!ret.error) return ret.value;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.