^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copied from arch/arm64/kernel/cpufeature.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2015 ARM Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2017 SiFive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/bitmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <asm/processor.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <asm/hwcap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/switch_to.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) unsigned long elf_hwcap __read_mostly;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) /* Host ISA bitmap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #ifdef CONFIG_FPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) bool has_fpu __read_mostly;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * riscv_isa_extension_base() - Get base extension word
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * @isa_bitmap: ISA bitmap to use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * Return: base extension word as unsigned long value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * NOTE: If isa_bitmap is NULL then Host ISA bitmap will be used.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) if (!isa_bitmap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) return riscv_isa[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return isa_bitmap[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) EXPORT_SYMBOL_GPL(riscv_isa_extension_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * __riscv_isa_extension_available() - Check whether given extension
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * is available or not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * @isa_bitmap: ISA bitmap to use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * @bit: bit position of the desired extension
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * Return: true or false
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * NOTE: If isa_bitmap is NULL then Host ISA bitmap will be used.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) const unsigned long *bmap = (isa_bitmap) ? isa_bitmap : riscv_isa;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (bit >= RISCV_ISA_EXT_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return test_bit(bit, bmap) ? true : false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) void riscv_fill_hwcap(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) struct device_node *node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) const char *isa;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) char print_str[BITS_PER_LONG + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) size_t i, j, isa_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static unsigned long isa2hwcap[256] = {0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) isa2hwcap['i'] = isa2hwcap['I'] = COMPAT_HWCAP_ISA_I;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) isa2hwcap['m'] = isa2hwcap['M'] = COMPAT_HWCAP_ISA_M;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) isa2hwcap['a'] = isa2hwcap['A'] = COMPAT_HWCAP_ISA_A;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) isa2hwcap['f'] = isa2hwcap['F'] = COMPAT_HWCAP_ISA_F;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) isa2hwcap['d'] = isa2hwcap['D'] = COMPAT_HWCAP_ISA_D;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) isa2hwcap['c'] = isa2hwcap['C'] = COMPAT_HWCAP_ISA_C;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) elf_hwcap = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) bitmap_zero(riscv_isa, RISCV_ISA_EXT_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) for_each_of_cpu_node(node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) unsigned long this_hwcap = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) unsigned long this_isa = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (riscv_of_processor_hartid(node) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (of_property_read_string(node, "riscv,isa", &isa)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) pr_warn("Unable to find \"riscv,isa\" devicetree entry\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) isa_len = strlen(isa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #if IS_ENABLED(CONFIG_32BIT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (!strncmp(isa, "rv32", 4))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) i += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) #elif IS_ENABLED(CONFIG_64BIT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (!strncmp(isa, "rv64", 4))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) i += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) for (; i < isa_len; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) this_hwcap |= isa2hwcap[(unsigned char)(isa[i])];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * TODO: X, Y and Z extension parsing for Host ISA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * bitmap will be added in-future.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if ('a' <= isa[i] && isa[i] < 'x')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) this_isa |= (1UL << (isa[i] - 'a'));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * All "okay" hart should have same isa. Set HWCAP based on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) * common capabilities of every "okay" hart, in case they don't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) * have.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (elf_hwcap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) elf_hwcap &= this_hwcap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) elf_hwcap = this_hwcap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (riscv_isa[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) riscv_isa[0] &= this_isa;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) riscv_isa[0] = this_isa;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /* We don't support systems with F but without D, so mask those out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * here. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if ((elf_hwcap & COMPAT_HWCAP_ISA_F) && !(elf_hwcap & COMPAT_HWCAP_ISA_D)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) pr_info("This kernel does not support systems with F but not D\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) elf_hwcap &= ~COMPAT_HWCAP_ISA_F;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) memset(print_str, 0, sizeof(print_str));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) for (i = 0, j = 0; i < BITS_PER_LONG; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (riscv_isa[0] & BIT_MASK(i))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) print_str[j++] = (char)('a' + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) pr_info("riscv: ISA extensions %s\n", print_str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) memset(print_str, 0, sizeof(print_str));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) for (i = 0, j = 0; i < BITS_PER_LONG; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (elf_hwcap & BIT_MASK(i))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) print_str[j++] = (char)('a' + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) pr_info("riscv: ELF capabilities %s\n", print_str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) #ifdef CONFIG_FPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) has_fpu = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }