Skip to content

Commit 59a582a

Browse files
Merge patch series "RISC-V: Ensure Zicbom has a valid block size"
Andrew Jones <[email protected]> says: When a DT puts zicbom in the isa string, but does not provide a block size, ALT_CMO_OP() will attempt to do cache operations on address zero since the start address will be ANDed with zero. We can't simply BUG() in riscv_init_cbom_blocksize() when we fail to find a block size because the failure will happen before logging works, leaving users to scratch their heads as to why the boot hung. Instead, ensure Zicbom is disabled and output an error which will hopefully alert people that the DT needs to be fixed. While at it, add a check that the block size is a power-of-2 too. * b4-shazam-merge: RISC-V: Ensure Zicbom has a valid block size RISC-V: Introduce riscv_isa_extension_check RISC-V: Improve use of isa2hwcap[] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
2 parents 6ff8ca3 + 9daaca4 commit 59a582a

File tree

4 files changed

+71
-59
lines changed

4 files changed

+71
-59
lines changed

arch/riscv/include/asm/cacheflush.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,8 @@ void flush_icache_mm(struct mm_struct *mm, bool local);
4949

5050
#endif /* CONFIG_SMP */
5151

52-
/*
53-
* The T-Head CMO errata internally probe the CBOM block size, but otherwise
54-
* don't depend on Zicbom.
55-
*/
5652
extern unsigned int riscv_cbom_block_size;
57-
#ifdef CONFIG_RISCV_ISA_ZICBOM
5853
void riscv_init_cbom_blocksize(void);
59-
#else
60-
static inline void riscv_init_cbom_blocksize(void) { }
61-
#endif
6254

6355
#ifdef CONFIG_RISCV_DMA_NONCOHERENT
6456
void riscv_noncoherent_supported(void);

arch/riscv/kernel/cpufeature.c

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/bitmap.h>
1010
#include <linux/ctype.h>
1111
#include <linux/libfdt.h>
12+
#include <linux/log2.h>
1213
#include <linux/module.h>
1314
#include <linux/of.h>
1415
#include <asm/alternative.h>
@@ -68,21 +69,38 @@ bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit)
6869
}
6970
EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
7071

72+
static bool riscv_isa_extension_check(int id)
73+
{
74+
switch (id) {
75+
case RISCV_ISA_EXT_ZICBOM:
76+
if (!riscv_cbom_block_size) {
77+
pr_err("Zicbom detected in ISA string, but no cbom-block-size found\n");
78+
return false;
79+
} else if (!is_power_of_2(riscv_cbom_block_size)) {
80+
pr_err("cbom-block-size present, but is not a power-of-2\n");
81+
return false;
82+
}
83+
return true;
84+
}
85+
86+
return true;
87+
}
88+
7189
void __init riscv_fill_hwcap(void)
7290
{
7391
struct device_node *node;
7492
const char *isa;
7593
char print_str[NUM_ALPHA_EXTS + 1];
7694
int i, j, rc;
77-
static unsigned long isa2hwcap[256] = {0};
95+
unsigned long isa2hwcap[26] = {0};
7896
unsigned long hartid;
7997

80-
isa2hwcap['i'] = isa2hwcap['I'] = COMPAT_HWCAP_ISA_I;
81-
isa2hwcap['m'] = isa2hwcap['M'] = COMPAT_HWCAP_ISA_M;
82-
isa2hwcap['a'] = isa2hwcap['A'] = COMPAT_HWCAP_ISA_A;
83-
isa2hwcap['f'] = isa2hwcap['F'] = COMPAT_HWCAP_ISA_F;
84-
isa2hwcap['d'] = isa2hwcap['D'] = COMPAT_HWCAP_ISA_D;
85-
isa2hwcap['c'] = isa2hwcap['C'] = COMPAT_HWCAP_ISA_C;
98+
isa2hwcap['i' - 'a'] = COMPAT_HWCAP_ISA_I;
99+
isa2hwcap['m' - 'a'] = COMPAT_HWCAP_ISA_M;
100+
isa2hwcap['a' - 'a'] = COMPAT_HWCAP_ISA_A;
101+
isa2hwcap['f' - 'a'] = COMPAT_HWCAP_ISA_F;
102+
isa2hwcap['d' - 'a'] = COMPAT_HWCAP_ISA_D;
103+
isa2hwcap['c' - 'a'] = COMPAT_HWCAP_ISA_C;
86104

87105
elf_hwcap = 0;
88106

@@ -189,15 +207,20 @@ void __init riscv_fill_hwcap(void)
189207
#define SET_ISA_EXT_MAP(name, bit) \
190208
do { \
191209
if ((ext_end - ext == sizeof(name) - 1) && \
192-
!memcmp(ext, name, sizeof(name) - 1)) \
210+
!memcmp(ext, name, sizeof(name) - 1) && \
211+
riscv_isa_extension_check(bit)) \
193212
set_bit(bit, this_isa); \
194213
} while (false) \
195214

196215
if (unlikely(ext_err))
197216
continue;
198217
if (!ext_long) {
199-
this_hwcap |= isa2hwcap[(unsigned char)(*ext)];
200-
set_bit(*ext - 'a', this_isa);
218+
int nr = *ext - 'a';
219+
220+
if (riscv_isa_extension_check(nr)) {
221+
this_hwcap |= isa2hwcap[nr];
222+
set_bit(nr, this_isa);
223+
}
201224
} else {
202225
SET_ISA_EXT_MAP("sscofpmf", RISCV_ISA_EXT_SSCOFPMF);
203226
SET_ISA_EXT_MAP("svpbmt", RISCV_ISA_EXT_SVPBMT);

arch/riscv/mm/cacheflush.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright (C) 2017 SiFive
44
*/
55

6+
#include <linux/of.h>
67
#include <asm/cacheflush.h>
78

89
#ifdef CONFIG_SMP
@@ -93,3 +94,40 @@ void flush_icache_pte(pte_t pte)
9394
flush_icache_all();
9495
}
9596
#endif /* CONFIG_MMU */
97+
98+
unsigned int riscv_cbom_block_size;
99+
EXPORT_SYMBOL_GPL(riscv_cbom_block_size);
100+
101+
void riscv_init_cbom_blocksize(void)
102+
{
103+
struct device_node *node;
104+
unsigned long cbom_hartid;
105+
u32 val, probed_block_size;
106+
int ret;
107+
108+
probed_block_size = 0;
109+
for_each_of_cpu_node(node) {
110+
unsigned long hartid;
111+
112+
ret = riscv_of_processor_hartid(node, &hartid);
113+
if (ret)
114+
continue;
115+
116+
/* set block-size for cbom extension if available */
117+
ret = of_property_read_u32(node, "riscv,cbom-block-size", &val);
118+
if (ret)
119+
continue;
120+
121+
if (!probed_block_size) {
122+
probed_block_size = val;
123+
cbom_hartid = hartid;
124+
} else {
125+
if (probed_block_size != val)
126+
pr_warn("cbom-block-size mismatched between harts %lu and %lu\n",
127+
cbom_hartid, hartid);
128+
}
129+
}
130+
131+
if (probed_block_size)
132+
riscv_cbom_block_size = probed_block_size;
133+
}

arch/riscv/mm/dma-noncoherent.c

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,8 @@
88
#include <linux/dma-direct.h>
99
#include <linux/dma-map-ops.h>
1010
#include <linux/mm.h>
11-
#include <linux/of.h>
12-
#include <linux/of_device.h>
1311
#include <asm/cacheflush.h>
1412

15-
unsigned int riscv_cbom_block_size;
16-
EXPORT_SYMBOL_GPL(riscv_cbom_block_size);
17-
1813
static bool noncoherent_supported;
1914

2015
void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
@@ -77,42 +72,6 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
7772
dev->dma_coherent = coherent;
7873
}
7974

80-
#ifdef CONFIG_RISCV_ISA_ZICBOM
81-
void riscv_init_cbom_blocksize(void)
82-
{
83-
struct device_node *node;
84-
unsigned long cbom_hartid;
85-
u32 val, probed_block_size;
86-
int ret;
87-
88-
probed_block_size = 0;
89-
for_each_of_cpu_node(node) {
90-
unsigned long hartid;
91-
92-
ret = riscv_of_processor_hartid(node, &hartid);
93-
if (ret)
94-
continue;
95-
96-
/* set block-size for cbom extension if available */
97-
ret = of_property_read_u32(node, "riscv,cbom-block-size", &val);
98-
if (ret)
99-
continue;
100-
101-
if (!probed_block_size) {
102-
probed_block_size = val;
103-
cbom_hartid = hartid;
104-
} else {
105-
if (probed_block_size != val)
106-
pr_warn("cbom-block-size mismatched between harts %lu and %lu\n",
107-
cbom_hartid, hartid);
108-
}
109-
}
110-
111-
if (probed_block_size)
112-
riscv_cbom_block_size = probed_block_size;
113-
}
114-
#endif
115-
11675
void riscv_noncoherent_supported(void)
11776
{
11877
WARN(!riscv_cbom_block_size,

0 commit comments

Comments
 (0)