Commit 6bcff515 authored by Anup Patel's avatar Anup Patel Committed by Palmer Dabbelt

RISC-V: Add bitmap reprensenting ISA features common across CPUs

This patch adds riscv_isa bitmap which represents Host ISA features
common across all Host CPUs. The riscv_isa is not same as elf_hwcap
because elf_hwcap will only have ISA features relevant for user-space
apps whereas riscv_isa will have ISA features relevant to both kernel
and user-space apps.

One of the use-case for riscv_isa bitmap is in KVM hypervisor where
we will use it to do following operations:

1. Check whether hypervisor extension is available
2. Find ISA features that need to be virtualized (e.g. floating
   point support, vector extension, etc.)
Signed-off-by: default avatarAnup Patel <anup.patel@wdc.com>
Signed-off-by: default avatarAtish Patra <atish.patra@wdc.com>
Reviewed-by: default avatarAlexander Graf <graf@amazon.com>
Signed-off-by: default avatarPalmer Dabbelt <palmerdabbelt@google.com>
parent 7391efa4
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#ifndef _ASM_RISCV_HWCAP_H #ifndef _ASM_RISCV_HWCAP_H
#define _ASM_RISCV_HWCAP_H #define _ASM_RISCV_HWCAP_H
#include <linux/bits.h>
#include <uapi/asm/hwcap.h> #include <uapi/asm/hwcap.h>
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
...@@ -22,6 +23,27 @@ enum { ...@@ -22,6 +23,27 @@ enum {
}; };
extern unsigned long elf_hwcap; extern unsigned long elf_hwcap;
#define RISCV_ISA_EXT_a ('a' - 'a')
#define RISCV_ISA_EXT_c ('c' - 'a')
#define RISCV_ISA_EXT_d ('d' - 'a')
#define RISCV_ISA_EXT_f ('f' - 'a')
#define RISCV_ISA_EXT_h ('h' - 'a')
#define RISCV_ISA_EXT_i ('i' - 'a')
#define RISCV_ISA_EXT_m ('m' - 'a')
#define RISCV_ISA_EXT_s ('s' - 'a')
#define RISCV_ISA_EXT_u ('u' - 'a')
#define RISCV_ISA_EXT_MAX 64
unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap);
#define riscv_isa_extension_mask(ext) BIT_MASK(RISCV_ISA_EXT_##ext)
bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit);
#define riscv_isa_extension_available(isa_bitmap, ext) \
__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_##ext)
#endif #endif
#endif /* _ASM_RISCV_HWCAP_H */ #endif /* _ASM_RISCV_HWCAP_H */
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
* Copyright (C) 2017 SiFive * Copyright (C) 2017 SiFive
*/ */
#include <linux/bitmap.h>
#include <linux/of.h> #include <linux/of.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/hwcap.h> #include <asm/hwcap.h>
...@@ -13,15 +14,57 @@ ...@@ -13,15 +14,57 @@
#include <asm/switch_to.h> #include <asm/switch_to.h>
unsigned long elf_hwcap __read_mostly; unsigned long elf_hwcap __read_mostly;
/* Host ISA bitmap */
static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
#ifdef CONFIG_FPU #ifdef CONFIG_FPU
bool has_fpu __read_mostly; bool has_fpu __read_mostly;
#endif #endif
/**
* riscv_isa_extension_base() - Get base extension word
*
* @isa_bitmap: ISA bitmap to use
* Return: base extension word as unsigned long value
*
* NOTE: If isa_bitmap is NULL then Host ISA bitmap will be used.
*/
unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap)
{
if (!isa_bitmap)
return riscv_isa[0];
return isa_bitmap[0];
}
EXPORT_SYMBOL_GPL(riscv_isa_extension_base);
/**
* __riscv_isa_extension_available() - Check whether given extension
* is available or not
*
* @isa_bitmap: ISA bitmap to use
* @bit: bit position of the desired extension
* Return: true or false
*
* NOTE: If isa_bitmap is NULL then Host ISA bitmap will be used.
*/
bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit)
{
const unsigned long *bmap = (isa_bitmap) ? isa_bitmap : riscv_isa;
if (bit >= RISCV_ISA_EXT_MAX)
return false;
return test_bit(bit, bmap) ? true : false;
}
EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
void riscv_fill_hwcap(void) void riscv_fill_hwcap(void)
{ {
struct device_node *node; struct device_node *node;
const char *isa; const char *isa;
size_t i; char print_str[BITS_PER_LONG + 1];
size_t i, j, isa_len;
static unsigned long isa2hwcap[256] = {0}; static unsigned long isa2hwcap[256] = {0};
isa2hwcap['i'] = isa2hwcap['I'] = COMPAT_HWCAP_ISA_I; isa2hwcap['i'] = isa2hwcap['I'] = COMPAT_HWCAP_ISA_I;
...@@ -33,8 +76,11 @@ void riscv_fill_hwcap(void) ...@@ -33,8 +76,11 @@ void riscv_fill_hwcap(void)
elf_hwcap = 0; elf_hwcap = 0;
bitmap_zero(riscv_isa, RISCV_ISA_EXT_MAX);
for_each_of_cpu_node(node) { for_each_of_cpu_node(node) {
unsigned long this_hwcap = 0; unsigned long this_hwcap = 0;
unsigned long this_isa = 0;
if (riscv_of_processor_hartid(node) < 0) if (riscv_of_processor_hartid(node) < 0)
continue; continue;
...@@ -44,8 +90,24 @@ void riscv_fill_hwcap(void) ...@@ -44,8 +90,24 @@ void riscv_fill_hwcap(void)
continue; continue;
} }
for (i = 0; i < strlen(isa); ++i) i = 0;
isa_len = strlen(isa);
#if IS_ENABLED(CONFIG_32BIT)
if (!strncmp(isa, "rv32", 4))
i += 4;
#elif IS_ENABLED(CONFIG_64BIT)
if (!strncmp(isa, "rv64", 4))
i += 4;
#endif
for (; i < isa_len; ++i) {
this_hwcap |= isa2hwcap[(unsigned char)(isa[i])]; this_hwcap |= isa2hwcap[(unsigned char)(isa[i])];
/*
* TODO: X, Y and Z extension parsing for Host ISA
* bitmap will be added in-future.
*/
if ('a' <= isa[i] && isa[i] < 'x')
this_isa |= (1UL << (isa[i] - 'a'));
}
/* /*
* All "okay" hart should have same isa. Set HWCAP based on * All "okay" hart should have same isa. Set HWCAP based on
...@@ -56,6 +118,11 @@ void riscv_fill_hwcap(void) ...@@ -56,6 +118,11 @@ void riscv_fill_hwcap(void)
elf_hwcap &= this_hwcap; elf_hwcap &= this_hwcap;
else else
elf_hwcap = this_hwcap; elf_hwcap = this_hwcap;
if (riscv_isa[0])
riscv_isa[0] &= this_isa;
else
riscv_isa[0] = this_isa;
} }
/* We don't support systems with F but without D, so mask those out /* We don't support systems with F but without D, so mask those out
...@@ -65,7 +132,17 @@ void riscv_fill_hwcap(void) ...@@ -65,7 +132,17 @@ void riscv_fill_hwcap(void)
elf_hwcap &= ~COMPAT_HWCAP_ISA_F; elf_hwcap &= ~COMPAT_HWCAP_ISA_F;
} }
pr_info("elf_hwcap is 0x%lx\n", elf_hwcap); memset(print_str, 0, sizeof(print_str));
for (i = 0, j = 0; i < BITS_PER_LONG; i++)
if (riscv_isa[0] & BIT_MASK(i))
print_str[j++] = (char)('a' + i);
pr_info("riscv: ISA extensions %s\n", print_str);
memset(print_str, 0, sizeof(print_str));
for (i = 0, j = 0; i < BITS_PER_LONG; i++)
if (elf_hwcap & BIT_MASK(i))
print_str[j++] = (char)('a' + i);
pr_info("riscv: ELF capabilities %s\n", print_str);
#ifdef CONFIG_FPU #ifdef CONFIG_FPU
if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)) if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment