* [RFC PATCH v2 1/3] riscv: alternatives: support auipc+load pair
2026-03-16 6:03 [RFC PATCH v2 0/3] riscv: support EIC770X/JH7110 noncoherent devices with XPbmtUC Bo Gan
@ 2026-03-16 6:03 ` Bo Gan
2026-03-16 6:03 ` [RFC PATCH v2 2/3] riscv: errata: sifive: support auipc/load pair in patched alternatives Bo Gan
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Bo Gan @ 2026-03-16 6:03 UTC (permalink / raw)
To: linux-riscv, samuel.holland, david, palmer, pjw, gaohan, me
Cc: lizhi2, hal.feng, marcel, conor, kernel, devicetree
Previously only auipc+jalr pair is supported. Add auipc+load pair
to support PC-relative memory load instruction as well.
Signed-off-by: Bo Gan <ganboing@gmail.com>
---
arch/riscv/include/asm/insn.h | 8 ++++++++
arch/riscv/kernel/alternative.c | 11 ++++++-----
2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/arch/riscv/include/asm/insn.h b/arch/riscv/include/asm/insn.h
index c3005573e8c99..1c791a8732efc 100644
--- a/arch/riscv/include/asm/insn.h
+++ b/arch/riscv/include/asm/insn.h
@@ -135,6 +135,8 @@
#define RVC_C2_RS1_MASK GENMASK(4, 0)
/* parts of opcode for RVG*/
+#define RVG_OPCODE_LOAD 0x03
+#define RVG_OPCODE_STORE 0x23
#define RVG_OPCODE_FENCE 0x0f
#define RVG_OPCODE_AUIPC 0x17
#define RVG_OPCODE_BRANCH 0x63
@@ -198,6 +200,8 @@
#define RVG_MATCH_BGE (RV_ENCODE_FUNCT3(BGE) | RVG_OPCODE_BRANCH)
#define RVG_MATCH_BLTU (RV_ENCODE_FUNCT3(BLTU) | RVG_OPCODE_BRANCH)
#define RVG_MATCH_BGEU (RV_ENCODE_FUNCT3(BGEU) | RVG_OPCODE_BRANCH)
+#define RVG_MATCH_LOAD (RVG_OPCODE_LOAD)
+#define RVG_MATCH_STORE (RVG_OPCODE_STORE)
#define RVG_MATCH_EBREAK (RV_ENCODE_FUNCT12(EBREAK) | RVG_OPCODE_SYSTEM)
#define RVG_MATCH_SRET (RV_ENCODE_FUNCT12(SRET) | RVG_OPCODE_SYSTEM)
#define RVC_MATCH_C_BEQZ (RVC_ENCODE_FUNCT3(C_BEQZ) | RVC_OPCODE_C1)
@@ -222,6 +226,8 @@
#define RVG_MASK_BGE (RV_INSN_FUNCT3_MASK | RV_INSN_OPCODE_MASK)
#define RVG_MASK_BLTU (RV_INSN_FUNCT3_MASK | RV_INSN_OPCODE_MASK)
#define RVG_MASK_BGEU (RV_INSN_FUNCT3_MASK | RV_INSN_OPCODE_MASK)
+#define RVG_MASK_LOAD (RV_INSN_OPCODE_MASK)
+#define RVG_MASK_STORE (RV_INSN_OPCODE_MASK)
#define RVC_MASK_C_BEQZ (RVC_INSN_FUNCT3_MASK | RVC_INSN_OPCODE_MASK)
#define RVC_MASK_C_BNEZ (RVC_INSN_FUNCT3_MASK | RVC_INSN_OPCODE_MASK)
#define RVC_MASK_C_EBREAK 0xffff
@@ -262,6 +268,8 @@ __RISCV_INSN_FUNCS(c_ebreak, RVC_MASK_C_EBREAK, RVC_MATCH_C_EBREAK)
__RISCV_INSN_FUNCS(ebreak, RVG_MASK_EBREAK, RVG_MATCH_EBREAK)
__RISCV_INSN_FUNCS(sret, RVG_MASK_SRET, RVG_MATCH_SRET)
__RISCV_INSN_FUNCS(fence, RVG_MASK_FENCE, RVG_MATCH_FENCE);
+__RISCV_INSN_FUNCS(load, RVG_MASK_LOAD, RVG_MATCH_LOAD);
+__RISCV_INSN_FUNCS(store, RVG_MASK_STORE, RVG_MATCH_STORE);
/* special case to catch _any_ system instruction */
static __always_inline bool riscv_insn_is_system(u32 code)
diff --git a/arch/riscv/kernel/alternative.c b/arch/riscv/kernel/alternative.c
index 7642704c7f184..04a9d3aed4647 100644
--- a/arch/riscv/kernel/alternative.c
+++ b/arch/riscv/kernel/alternative.c
@@ -74,7 +74,7 @@ static u32 riscv_instruction_at(void *p)
return (u32)parcel[0] | (u32)parcel[1] << 16;
}
-static void riscv_alternative_fix_auipc_jalr(void *ptr, u32 auipc_insn,
+static void riscv_alternative_fix_auipc_pair(void *ptr, u32 auipc_insn,
u32 jalr_insn, int patch_offset)
{
u32 call[2] = { auipc_insn, jalr_insn };
@@ -123,14 +123,15 @@ void riscv_alternative_fix_offsets(void *alt_ptr, unsigned int len,
if (riscv_insn_is_auipc(insn) && i < num_insn - 1) {
u32 insn2 = riscv_instruction_at(alt_ptr + (i + 1) * sizeof(u32));
- if (!riscv_insn_is_jalr(insn2))
+ if (!riscv_insn_is_jalr(insn2) &&
+ !riscv_insn_is_load(insn2))
continue;
- /* if instruction pair is a call, it will use the ra register */
- if (RV_EXTRACT_RD_REG(insn) != 1)
+ if (RV_EXTRACT_RD_REG(insn) != RV_EXTRACT_RS1_REG(insn2))
continue;
- riscv_alternative_fix_auipc_jalr(alt_ptr + i * sizeof(u32),
+ /* insn2 use rd of insn as rs1, patch it */
+ riscv_alternative_fix_auipc_pair(alt_ptr + i * sizeof(u32),
insn, insn2, patch_offset);
i++;
}
--
2.34.1
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 6+ messages in thread* [RFC PATCH v2 2/3] riscv: errata: sifive: support auipc/load pair in patched alternatives
2026-03-16 6:03 [RFC PATCH v2 0/3] riscv: support EIC770X/JH7110 noncoherent devices with XPbmtUC Bo Gan
2026-03-16 6:03 ` [RFC PATCH v2 1/3] riscv: alternatives: support auipc+load pair Bo Gan
@ 2026-03-16 6:03 ` Bo Gan
2026-03-16 6:03 ` [RFC PATCH v2 3/3] riscv: errata: sifive: Add an "errata" to simulate Svpbmt on cores without Bo Gan
2026-03-23 23:08 ` [RFC PATCH v2 0/3] riscv: support EIC770X/JH7110 noncoherent devices with XPbmtUC Bo Gan
3 siblings, 0 replies; 6+ messages in thread
From: Bo Gan @ 2026-03-16 6:03 UTC (permalink / raw)
To: linux-riscv, samuel.holland, david, palmer, pjw, gaohan, me
Cc: lizhi2, hal.feng, marcel, conor, kernel, devicetree
Enhance the errata/sifive patching function to support auipc/load
insn pair by fixing the offsets in immediate, just like in function
`riscv_cpufeature_patch_func`. Refer to commit 27c653c06505
("RISC-V: fix auipc-jalr addresses in patched alternatives")
Signed-off-by: Bo Gan <ganboing@gmail.com>
---
arch/riscv/errata/sifive/errata.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/errata/sifive/errata.c b/arch/riscv/errata/sifive/errata.c
index d0c61f86cba33..f26c997e04e59 100644
--- a/arch/riscv/errata/sifive/errata.c
+++ b/arch/riscv/errata/sifive/errata.c
@@ -80,6 +80,7 @@ void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
unsigned int stage)
{
struct alt_entry *alt;
+ void *oldptr, *altptr;
u32 cpu_req_errata;
u32 tmp;
@@ -100,9 +101,12 @@ void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
tmp = (1U << alt->patch_id);
if (cpu_req_errata & tmp) {
+ oldptr = ALT_OLD_PTR(alt);
+ altptr = ALT_ALT_PTR(alt);
+
mutex_lock(&text_mutex);
- patch_text_nosync(ALT_OLD_PTR(alt), ALT_ALT_PTR(alt),
- alt->alt_len);
+ patch_text_nosync(oldptr, altptr, alt->alt_len);
+ riscv_alternative_fix_offsets(oldptr, alt->alt_len, oldptr - altptr);
mutex_unlock(&text_mutex);
}
}
--
2.34.1
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 6+ messages in thread* [RFC PATCH v2 3/3] riscv: errata: sifive: Add an "errata" to simulate Svpbmt on cores without
2026-03-16 6:03 [RFC PATCH v2 0/3] riscv: support EIC770X/JH7110 noncoherent devices with XPbmtUC Bo Gan
2026-03-16 6:03 ` [RFC PATCH v2 1/3] riscv: alternatives: support auipc+load pair Bo Gan
2026-03-16 6:03 ` [RFC PATCH v2 2/3] riscv: errata: sifive: support auipc/load pair in patched alternatives Bo Gan
@ 2026-03-16 6:03 ` Bo Gan
2026-03-23 23:08 ` [RFC PATCH v2 0/3] riscv: support EIC770X/JH7110 noncoherent devices with XPbmtUC Bo Gan
3 siblings, 0 replies; 6+ messages in thread
From: Bo Gan @ 2026-03-16 6:03 UTC (permalink / raw)
To: linux-riscv, samuel.holland, david, palmer, pjw, gaohan, me
Cc: lizhi2, hal.feng, marcel, conor, kernel, devicetree
On some platforms with pre-Svpbmt Sifive cores, they map the system
memory twice in physical address space, one as cached (through the
front port), and the other as uncached (through the system port), to
enable drivers working with non-cache-coherent devices. Drivers can map
the DMA buffers uncached through the uncached alias, and don't have to
flush caches explicitly. It eases the driver programming. For complex
device drivers, such as the GPU, this is a must have, as DMA pages can
be mmap'ed to user space, and the userspace can't do caches flushes due
to the lack of Zicbom on these older cores.
Introduce a Sifive "errata" to model such setup with a customized
version of Svpbmt, "XPbmtUC", where a single, artificial bit in the PTE
is used for cache/uncache control (UC), effectively offsetting the PPN
by power-of-2. I.e.,
Starfive JH7110 (Sifive U74):
[0x0, 0x40000000) Low MMIO
[0x40000000, 0x2_40000000) Cached Mem
[0x4_40000000, 0x6_40000000) Uncached Mem UC+
[0x9_00000000, 0x9_d0000000) High MMIO
Using PTE bit 32 (PPN bit 34) as UC (uncache) control perfectly matches
the memory map of the SoC.
Other SoCs like ESWIN EIC770X is not directly compatible to this model,
as the uncached regions are not power-of-2 offseted, and the offsets are
different between Dies in the dual-die version (EIC7702). The firmware,
however, could use G-stage page table to transparently re-map, and make
the address space suitable for XPbmtUC scheme to be applied:
[0x0, 0x20000000) Core Internal
[0x20000000, 0x40000000) Core Internal (Die 1)
[0x40000000, 0x60000000) Low MMIO
[0x60000000, 0x80000000) Low MMIO (Die 1)
[0x80000000, 0x10_80000000) Cached Mem
[0x20_00000000, 0x30_00000000) Cached Mem (Die 1)
[0x80_00000000, 0xa0_00000000) High MMIO
[0xa0_00000000, 0xc0_00000000) High MMIO (Die 1)
[0xc0_00000000, 0xd0_00000000) Uncached Mem <----------.
[0xe0_00000000, 0xf0_00000000) Uncached Mem (Die 1) <--+--.
with firmware/hypervisor re-mapping: | |
------------------------------------ | |
[0x100_80000000, 0x110_80000000) Mem UC+ ----------------' |
[0x120_00000000, 0x130_00000000) Mem UC+ (Die 1) -----------'
Such firmware capability is detected at boot time by sbi ecalls. The
firmware will provide us the UC bit position if re-map is in effect.
Note: currently this feature is gated by JH7110 and EIC770X SoCs to
avoid unnecessary sbi ecalls. There's also no IO bit in such XPbmtUC
scheme, as it's assumed that the PMA (hard-wired on these SoCs) will
convey the strongly-ordered, non-idempotent attribute of MMIO regions.
Signed-off-by: Bo Gan <ganboing@gmail.com>
---
arch/riscv/Kconfig.errata | 13 ++++
arch/riscv/errata/sifive/errata.c | 72 ++++++++++++++++++++
arch/riscv/include/asm/errata_list.h | 19 +++++-
arch/riscv/include/asm/errata_list_vendors.h | 3 +-
arch/riscv/include/asm/pgtable-64.h | 9 ++-
5 files changed, 112 insertions(+), 4 deletions(-)
diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata
index 3c945d086c7d0..0722dc8df4a9e 100644
--- a/arch/riscv/Kconfig.errata
+++ b/arch/riscv/Kconfig.errata
@@ -76,6 +76,19 @@ config ERRATA_SIFIVE_CIP_1200
If you don't know what to do here, say "Y".
+config ERRATA_SIFIVE_XPBMTUC
+ bool "Support XPbmtUC (customized uncache bit)"
+ depends on ERRATA_SIFIVE && 64BIT && MMU
+ default y
+ select DMA_DIRECT_REMAP
+ help
+ This will detect and enable the XPbmtUC, where a bit in PTE
+ is chosen as the UC (uncache) control bit to emulate Svpbmt
+ on supported SoCs. For SoCs with non-cache-coherent devices,
+ enabling XPbmtUC allows drivers to map DMA buffers uncached.
+
+ If you don't know what to do here, say "Y".
+
config ERRATA_STARFIVE_JH7100
bool "StarFive JH7100 support"
depends on ARCH_STARFIVE
diff --git a/arch/riscv/errata/sifive/errata.c b/arch/riscv/errata/sifive/errata.c
index f26c997e04e59..fd804e53cfcaa 100644
--- a/arch/riscv/errata/sifive/errata.c
+++ b/arch/riscv/errata/sifive/errata.c
@@ -8,11 +8,37 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/bug.h>
+#include <linux/of.h>
#include <asm/text-patching.h>
#include <asm/alternative.h>
#include <asm/vendorid_list.h>
#include <asm/errata_list.h>
#include <asm/vendor_extensions.h>
+#include <asm/cacheflush.h>
+#include <asm/sbi.h>
+
+#define SIFIVE_SBI_EXT_SIFIVE 0x09000489
+#define SIFIVE_SBI_EXT_XPBMTUC_PRESENT 0x50425543 // PBUC
+
+#ifdef CONFIG_ERRATA_SIFIVE_XPBMTUC
+
+u64 riscv_xpbmtuc_mask;
+EXPORT_SYMBOL(riscv_xpbmtuc_mask);
+
+static const struct {
+ const char *machine;
+ int xpbmtuc_bit;
+} xpbmtuc_platforms[] = {
+ {
+ .machine = "starfive,jh7110",
+ .xpbmtuc_bit = 32
+ },
+ {
+ .machine = "eswin,eic7700",
+ .xpbmtuc_bit = -1 // detect
+ },
+};
+#endif
struct errata_info_t {
char name[32];
@@ -51,6 +77,46 @@ static bool errata_cip_1200_check_func(unsigned long arch_id, unsigned long imp
return true;
}
+#ifdef CONFIG_ERRATA_SIFIVE_XPBMTUC
+static void detect_xpbmtuc(void)
+{
+ int riscv_xpbmtuc_bit = -1, i;
+ struct sbiret ret;
+
+ for (i = 0; i < ARRAY_SIZE(xpbmtuc_platforms); i++) {
+ if (!of_machine_is_compatible(xpbmtuc_platforms[i].machine))
+ continue;
+
+ riscv_xpbmtuc_bit = xpbmtuc_platforms[i].xpbmtuc_bit;
+ if (riscv_xpbmtuc_bit >= 0)
+ break;
+
+ ret = sbi_ecall(SIFIVE_SBI_EXT_SIFIVE,
+ SIFIVE_SBI_EXT_XPBMTUC_PRESENT,
+ 0, 0, 0, 0, 0, 0);
+ riscv_xpbmtuc_bit = ret.error ? -1 : ret.value;
+ break;
+ }
+ if (riscv_xpbmtuc_bit < 0)
+ return;
+
+ riscv_xpbmtuc_mask = 1UL << riscv_xpbmtuc_bit;
+ pr_info("Using XPbmtUC bit %d\n", riscv_xpbmtuc_bit);
+}
+
+static bool errata_xpbmtuc_check_func(unsigned long arch_id, unsigned long impid)
+{
+ return riscv_xpbmtuc_mask != 0;
+}
+#else
+static void detect_xpbmtuc(void) { }
+
+static bool errata_xpbmtuc_check_func(unsigned long arch_id, unsigned long impid)
+{
+ return false;
+}
+#endif
+
static struct errata_info_t errata_list[ERRATA_SIFIVE_NUMBER] = {
{
.name = "cip-453",
@@ -60,6 +126,10 @@ static struct errata_info_t errata_list[ERRATA_SIFIVE_NUMBER] = {
.name = "cip-1200",
.check_func = errata_cip_1200_check_func
},
+ {
+ .name = "xpbmtuc",
+ .check_func = errata_xpbmtuc_check_func
+ },
};
static u32 __init_or_module sifive_errata_probe(unsigned long archid,
@@ -88,6 +158,8 @@ void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
return;
+ else if (stage == RISCV_ALTERNATIVES_BOOT)
+ detect_xpbmtuc();
cpu_req_errata = sifive_errata_probe(archid, impid);
diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h
index 6694b5ccdcf85..a05086f05a0cf 100644
--- a/arch/riscv/include/asm/errata_list.h
+++ b/arch/riscv/include/asm/errata_list.h
@@ -53,18 +53,33 @@ asm(ALTERNATIVE( \
: /* no inputs */ \
: "memory")
+#ifdef CONFIG_64BIT
+#define ALT_PAGE_CUST_BIT(_bit) \
+asm(ALTERNATIVE("li %0, 0\t\nnop", \
+ "1: auipc %0, %%pcrel_hi(riscv_xpbmtuc_mask)\t\n" \
+ "ld %0, %%pcrel_lo(1b)(%0)", SIFIVE_VENDOR_ID, \
+ ERRATA_SIFIVE_XPBMTUC, \
+ CONFIG_ERRATA_SIFIVE_XPBMTUC) \
+ : "=r"(_bit))
+#endif
+
/*
* _val is marked as "will be overwritten", so need to set it to 0
* in the default case.
*/
#define ALT_SVPBMT_SHIFT 61
#define ALT_THEAD_MAE_SHIFT 59
+#define HAS_XPBMTUC_PAGE_NOCACHE CONFIG_ERRATA_SIFIVE_XPBMTUC
+#define HAS_XPBMTUC_PAGE_MTMASK CONFIG_ERRATA_SIFIVE_XPBMTUC
#define ALT_SVPBMT(_val, prot) \
-asm(ALTERNATIVE_2("li %0, 0\t\nnop", \
+asm(ALTERNATIVE_3("li %0, 0\t\nnop", \
"li %0, %1\t\nslli %0,%0,%3", 0, \
RISCV_ISA_EXT_SVPBMT, CONFIG_RISCV_ISA_SVPBMT, \
"li %0, %2\t\nslli %0,%0,%4", THEAD_VENDOR_ID, \
- ERRATA_THEAD_MAE, CONFIG_ERRATA_THEAD_MAE) \
+ ERRATA_THEAD_MAE, CONFIG_ERRATA_THEAD_MAE, \
+ "1: auipc %0, %%pcrel_hi(riscv_xpbmtuc_mask)\t\n" \
+ "ld %0, %%pcrel_lo(1b)(%0)", SIFIVE_VENDOR_ID, \
+ ERRATA_SIFIVE_XPBMTUC, HAS_XPBMTUC##prot) \
: "=r"(_val) \
: "I"(prot##_SVPBMT >> ALT_SVPBMT_SHIFT), \
"I"(prot##_THEAD >> ALT_THEAD_MAE_SHIFT), \
diff --git a/arch/riscv/include/asm/errata_list_vendors.h b/arch/riscv/include/asm/errata_list_vendors.h
index ec7eba3734371..b2bf8d7a52c30 100644
--- a/arch/riscv/include/asm/errata_list_vendors.h
+++ b/arch/riscv/include/asm/errata_list_vendors.h
@@ -11,7 +11,8 @@
#ifdef CONFIG_ERRATA_SIFIVE
#define ERRATA_SIFIVE_CIP_453 0
#define ERRATA_SIFIVE_CIP_1200 1
-#define ERRATA_SIFIVE_NUMBER 2
+#define ERRATA_SIFIVE_XPBMTUC 2
+#define ERRATA_SIFIVE_NUMBER 3
#endif
#ifdef CONFIG_ERRATA_THEAD
diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h
index 6e789fa58514c..7f47a361d8003 100644
--- a/arch/riscv/include/asm/pgtable-64.h
+++ b/arch/riscv/include/asm/pgtable-64.h
@@ -76,7 +76,14 @@ typedef struct {
* | 63 | 62 61 | 60 54 | 53 10 | 9 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
* N MT RSV PFN reserved for SW D A G U X W R V
*/
-#define _PAGE_PFN_MASK GENMASK(53, 10)
+static inline u64 riscv_pfn_mask(void)
+{
+ u64 cust_bit;
+
+ ALT_PAGE_CUST_BIT(cust_bit);
+ return GENMASK(53, 10) ^ cust_bit;
+}
+#define _PAGE_PFN_MASK riscv_pfn_mask()
/*
* [63] Svnapot definitions:
--
2.34.1
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [RFC PATCH v2 0/3] riscv: support EIC770X/JH7110 noncoherent devices with XPbmtUC
2026-03-16 6:03 [RFC PATCH v2 0/3] riscv: support EIC770X/JH7110 noncoherent devices with XPbmtUC Bo Gan
` (2 preceding siblings ...)
2026-03-16 6:03 ` [RFC PATCH v2 3/3] riscv: errata: sifive: Add an "errata" to simulate Svpbmt on cores without Bo Gan
@ 2026-03-23 23:08 ` Bo Gan
2026-03-24 17:49 ` Conor Dooley
3 siblings, 1 reply; 6+ messages in thread
From: Bo Gan @ 2026-03-23 23:08 UTC (permalink / raw)
To: linux-riscv, samuel.holland, david, palmer, pjw, gaohan, me
Cc: lizhi2, hal.feng, marcel, conor, kernel, devicetree
Hi All,
Any suggestions/comments on this?
On 3/15/26 23:03, Bo Gan wrote:
> SoCs with pre-Svpbmt Sifive cores, e.g., Starfive JH7110 and ESWIN
> EIC770X both have non cache-coherent peripherals. On JH7110[1], video
> subsystem (GPU/VOUT/VPU/ISP) is routed to the sys port, making them not
> cache-coherent. On EIC770X, all peripherals are routed to the sys port,
> and none is cache-coherent. Instead of Svpbmt, these SoCs map system
> memory twice -- the conventional cached region (through front port),
> and the uncached alias (through sys port) at different base addresses.
> The uncached alias implicitly applies the uncacheable PMA. Drivers
> working with noncoherent devices can utilize the uncache alias to map
> DMA buffers, without doing explicit cache flushes.
>
> This feature is not an ISA standard, and the cache/uncache base can be
> configured by the SoC vendor. To expose it properly, introduce a Sifive
> "errata", namely "XPbmtUC", to model the setup as a customized version
> of Svpbmt. It choses a single, artificial bit in PTE at runtime for
> cache/uncache control, effectively offsetting the PPN by power-of-2.
> On JH7110, it aligns perfectly with the HW: it maps the cached region
> at 0x40000000, and the uncached alias at 0x4_40000000. Chosing bit 32
> (PPN bit 34) as the UC bit matches HW exactly.
>
> Starfive JH7110 (Sifive U74 core) memory map:
>
> [0x0, 0x40000000) Low MMIO
> [0x40000000, 0x2_40000000) Cached Mem
> [0x4_40000000, 0x6_40000000) Uncached Mem (UC+)
> [0x9_00000000, 0x9_d0000000) High MMIO
>
> On EIC770X, the aliased UC region is put to a offset not power-of-2.
> There can also be 2 NUMA node (dual-die) with 2 separate memory regions
> and their UC alias counterparts are offsetted differently. We detect if
> the firmware has the capability to re-arrange the memory map, using
> G-stage pagetable, making the the offsets power-of-2 again.
>
> [0x0, 0x20000000) Core Internal
> [0x20000000, 0x40000000) Core Internal (Die 1)
> [0x40000000, 0x60000000) Low MMIO
> [0x60000000, 0x80000000) Low MMIO (Die 1)
> [0x80000000, 0x10_80000000) Cached Mem
> [0x20_00000000, 0x30_00000000) Cached Mem (Die 1)
> [0x80_00000000, 0xa0_00000000) High MMIO
> [0xa0_00000000, 0xc0_00000000) High MMIO (Die 1)
> [0xc0_00000000, 0xd0_00000000) Uncached Mem <----------.
> [0xe0_00000000, 0xf0_00000000) Uncached Mem (Die 1) <--+--.
> with firmware/hypervisor re-mapping: | |
> ------------------------------------ | |
> [0x100_80000000, 0x110_80000000) Mem UC+ ----------------' |
> [0x120_00000000, 0x130_00000000) Mem UC+ (Die 1) -----------'
>
> The "XPbmtUC" alternative PTE format is the cleanest solution I can
> think of to solve the non-coherent device enablement w/o Svpbmt from
> kernel side. Drivers can do explicit cache flushes to workaround the
> problem, but a. it pushes the burden of cache flushes to driver code,
> and we don't want to complicate them if it's already written with the
> cache coherent assumption in mind. b. complex drivers like GPU could
> allow user-space to mmap DMA pages, but userspace can't flush caches
> due to the lack of Zicbom on these SoCs. I'm aware there's an ongoing
> series[2] that Samuel sent for physical memory aliases, which is
> essentially a superset of my patch. I don't mean to step ahead of him,
> but try to find a middle ground if the community still worries about
> his change touching too many areas. My change is very minimal and
> local. It's fairly easy to remove, too.
>
> ----------------------------------------
> Notes about PoC firmware implementation on EIC7700X[3]:
>
> The OpenSBI is augmented to provide a very thin layer hypervisor, where
> it runs the entire host OS in VS-mode, and provide the aforementioned
> remapping. I remap UC+ memory to 2^40+ to make the 2-stage translation
> efficient, where I can utilize Sv39x4 G-stage scheme to map the entire
> physical address space at bottom-half, and the uncache counterparts to
> system memory at top-half. I also make use of the largest page in Sv39
> -- 1GB page, to map everything, keeping the G-stage page-table minimal,
> only 16KB in size, while also minimizing TLB misses. A very slight,
> unavoidable, slow down is with the external interrupt delivery. Due to
> the lack of AIA in EIC770X, all device irq now needs to trap to M mode
> first, before forwarding to VS mode. The overhead of running KVM in
> such setup is yet unknown, and may well be noticeable. All HS-qualified
> instructions will trap to M mode, which is costly. The NACL extension,
> if implemented, will alleviate it, but there's also the extra cost of
> flushing G/VS-stage TLBs. I'm analyzing it in parallel.
>
> Use [4] if you have a Hifive Premier P550 to try it out.
>
> [1] https://github.com/starfive-tech/JH7100_Docs/blob/main/JH7100%20Cache%20Coherence%20V1.0.pdf
> [2] https://lore.kernel.org/all/20251113014656.2605447-20-samuel.holland@sifive.com/
> [3] https://github.com/ganboing/opensbi/tree/eic77x-vspt-physalias-wip
> [4] https://github.com/ganboing/linux-eic77/tree/ganboing-xpbmt-uc-v2-eic77-clk-v15
>
> ---
> v2:
> - Move the core logic to Sifive errata to address Conor's comments
>
> v1: https://lore.kernel.org/linux-riscv/338f0f79-1eed-4c5c-9966-04a2eaeb3d98@gmail.com
>
> Bo Gan (3):
> riscv: alternatives: support auipc+load pair
> riscv: errata: sifive: support auipc/load pair in patched alternatives
> riscv: errata: sifive: Add an "errata" to simulate Svpbmt on cores
> without
>
> arch/riscv/Kconfig.errata | 13 ++++
> arch/riscv/errata/sifive/errata.c | 80 +++++++++++++++++++-
> arch/riscv/include/asm/errata_list.h | 19 ++++-
> arch/riscv/include/asm/errata_list_vendors.h | 3 +-
> arch/riscv/include/asm/insn.h | 8 ++
> arch/riscv/include/asm/pgtable-64.h | 9 ++-
> arch/riscv/kernel/alternative.c | 11 +--
> 7 files changed, 132 insertions(+), 11 deletions(-)
>
Bo
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [RFC PATCH v2 0/3] riscv: support EIC770X/JH7110 noncoherent devices with XPbmtUC
2026-03-23 23:08 ` [RFC PATCH v2 0/3] riscv: support EIC770X/JH7110 noncoherent devices with XPbmtUC Bo Gan
@ 2026-03-24 17:49 ` Conor Dooley
0 siblings, 0 replies; 6+ messages in thread
From: Conor Dooley @ 2026-03-24 17:49 UTC (permalink / raw)
To: Bo Gan
Cc: linux-riscv, samuel.holland, david, palmer, pjw, gaohan, me,
lizhi2, hal.feng, marcel, kernel, devicetree
[-- Attachment #1.1: Type: text/plain, Size: 159 bytes --]
On Mon, Mar 23, 2026 at 04:08:33PM -0700, Bo Gan wrote:
> Hi All,
>
> Any suggestions/comments on this?
I'll get to it at some point, just busy sorry!
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
[-- Attachment #2: Type: text/plain, Size: 161 bytes --]
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 6+ messages in thread