104 lines
3.2 KiB
C
104 lines
3.2 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Copyright 2024 Rivos, Inc
|
|
*/
|
|
|
|
#ifndef _ASM_VENDOR_EXTENSIONS_H
|
|
#define _ASM_VENDOR_EXTENSIONS_H
|
|
|
|
#include <asm/cpufeature.h>
|
|
|
|
#include <linux/array_size.h>
|
|
#include <linux/types.h>
|
|
|
|
/*
|
|
* The extension keys of each vendor must be strictly less than this value.
|
|
*/
|
|
#define RISCV_ISA_VENDOR_EXT_MAX 32
|
|
|
|
struct riscv_isavendorinfo {
|
|
DECLARE_BITMAP(isa, RISCV_ISA_VENDOR_EXT_MAX);
|
|
};
|
|
|
|
struct riscv_isa_vendor_ext_data_list {
|
|
bool is_initialized;
|
|
const size_t ext_data_count;
|
|
const struct riscv_isa_ext_data *ext_data;
|
|
struct riscv_isavendorinfo per_hart_isa_bitmap[NR_CPUS];
|
|
struct riscv_isavendorinfo all_harts_isa_bitmap;
|
|
};
|
|
|
|
extern struct riscv_isa_vendor_ext_data_list *riscv_isa_vendor_ext_list[];
|
|
|
|
extern const size_t riscv_isa_vendor_ext_list_size;
|
|
|
|
/*
|
|
* The alternatives need some way of distinguishing between vendor extensions
|
|
* and errata. Incrementing all of the vendor extension keys so they are at
|
|
* least 0x8000 accomplishes that.
|
|
*/
|
|
#define RISCV_VENDOR_EXT_ALTERNATIVES_BASE 0x8000
|
|
|
|
#define VENDOR_EXT_ALL_CPUS -1
|
|
|
|
bool __riscv_isa_vendor_extension_available(int cpu, unsigned long vendor, unsigned int bit);
|
|
#define riscv_cpu_isa_vendor_extension_available(cpu, vendor, ext) \
|
|
__riscv_isa_vendor_extension_available(cpu, vendor, RISCV_ISA_VENDOR_EXT_##ext)
|
|
#define riscv_isa_vendor_extension_available(vendor, ext) \
|
|
__riscv_isa_vendor_extension_available(VENDOR_EXT_ALL_CPUS, vendor, \
|
|
RISCV_ISA_VENDOR_EXT_##ext)
|
|
|
|
static __always_inline bool riscv_has_vendor_extension_likely(const unsigned long vendor,
|
|
const unsigned long ext)
|
|
{
|
|
if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT))
|
|
return false;
|
|
|
|
if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
|
|
return __riscv_has_extension_likely(vendor,
|
|
ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
|
|
|
|
return __riscv_isa_vendor_extension_available(VENDOR_EXT_ALL_CPUS, vendor, ext);
|
|
}
|
|
|
|
static __always_inline bool riscv_has_vendor_extension_unlikely(const unsigned long vendor,
|
|
const unsigned long ext)
|
|
{
|
|
if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT))
|
|
return false;
|
|
|
|
if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
|
|
return __riscv_has_extension_unlikely(vendor,
|
|
ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
|
|
|
|
return __riscv_isa_vendor_extension_available(VENDOR_EXT_ALL_CPUS, vendor, ext);
|
|
}
|
|
|
|
static __always_inline bool riscv_cpu_has_vendor_extension_likely(const unsigned long vendor,
|
|
int cpu, const unsigned long ext)
|
|
{
|
|
if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT))
|
|
return false;
|
|
|
|
if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
|
|
__riscv_has_extension_likely(vendor, ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE))
|
|
return true;
|
|
|
|
return __riscv_isa_vendor_extension_available(cpu, vendor, ext);
|
|
}
|
|
|
|
static __always_inline bool riscv_cpu_has_vendor_extension_unlikely(const unsigned long vendor,
|
|
int cpu,
|
|
const unsigned long ext)
|
|
{
|
|
if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT))
|
|
return false;
|
|
|
|
if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
|
|
__riscv_has_extension_unlikely(vendor, ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE))
|
|
return true;
|
|
|
|
return __riscv_isa_vendor_extension_available(cpu, vendor, ext);
|
|
}
|
|
|
|
#endif /* _ASM_VENDOR_EXTENSIONS_H */
|