LoongArch: Add adaptive CSR accessors for 32BIT/64BIT

32BIT platforms only have 32bit CSR/IOCSR registers, 64BIT platforms
have both 32bit/64bit CSR/IOCSR registers. Now there are both 32bit and
64bit CSR accessors:

csr_read32()/csr_write32()/csr_xchg32();
csr_read64()/csr_write64()/csr_xchg64();

Some CSR registers (address and timer registers) are 32bit length on
32BIT platform and 64bit length on 64BIT platform. To avoid #ifdefs here
and there, they need adaptive accessors, so we define and use:

csr_read()/csr_write()/csr_xchg();

IOCSR doesn't have a "natural length", which means a 64bit register can
be treated as two 32bit registers, so we just use two 32bit accessors to
emulate a 64bit accessors.

Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
pull/1354/merge
Huacai Chen 2025-12-06 10:40:32 +08:00
parent 79974cc3ba
commit 81f5d15c48
10 changed files with 81 additions and 59 deletions

View File

@ -182,6 +182,16 @@
#define csr_xchg32(val, mask, reg) __csrxchg_w(val, mask, reg)
#define csr_xchg64(val, mask, reg) __csrxchg_d(val, mask, reg)
#ifdef CONFIG_32BIT
#define csr_read(reg) csr_read32(reg)
#define csr_write(val, reg) csr_write32(val, reg)
#define csr_xchg(val, mask, reg) csr_xchg32(val, mask, reg)
#else
#define csr_read(reg) csr_read64(reg)
#define csr_write(val, reg) csr_write64(val, reg)
#define csr_xchg(val, mask, reg) csr_xchg64(val, mask, reg)
#endif
/* IOCSR */
#define iocsr_read32(reg) __iocsrrd_w(reg)
#define iocsr_read64(reg) __iocsrrd_d(reg)
@ -1223,6 +1233,7 @@ static inline unsigned int get_csr_cpuid(void)
return csr_read32(LOONGARCH_CSR_CPUID);
}
#ifdef CONFIG_64BIT
static inline void csr_any_send(unsigned int addr, unsigned int data,
unsigned int data_mask, unsigned int cpu)
{
@ -1234,6 +1245,7 @@ static inline void csr_any_send(unsigned int addr, unsigned int data,
val |= ((uint64_t)data << IOCSR_ANY_SEND_BUF_SHIFT);
iocsr_write64(val, LOONGARCH_IOCSR_ANY_SEND);
}
#endif
static inline unsigned int read_csr_excode(void)
{
@ -1257,22 +1269,22 @@ static inline void write_csr_pagesize(unsigned int size)
static inline unsigned int read_csr_tlbrefill_pagesize(void)
{
return (csr_read64(LOONGARCH_CSR_TLBREHI) & CSR_TLBREHI_PS) >> CSR_TLBREHI_PS_SHIFT;
return (csr_read(LOONGARCH_CSR_TLBREHI) & CSR_TLBREHI_PS) >> CSR_TLBREHI_PS_SHIFT;
}
static inline void write_csr_tlbrefill_pagesize(unsigned int size)
{
csr_xchg64(size << CSR_TLBREHI_PS_SHIFT, CSR_TLBREHI_PS, LOONGARCH_CSR_TLBREHI);
csr_xchg(size << CSR_TLBREHI_PS_SHIFT, CSR_TLBREHI_PS, LOONGARCH_CSR_TLBREHI);
}
#define read_csr_asid() csr_read32(LOONGARCH_CSR_ASID)
#define write_csr_asid(val) csr_write32(val, LOONGARCH_CSR_ASID)
#define read_csr_entryhi() csr_read64(LOONGARCH_CSR_TLBEHI)
#define write_csr_entryhi(val) csr_write64(val, LOONGARCH_CSR_TLBEHI)
#define read_csr_entrylo0() csr_read64(LOONGARCH_CSR_TLBELO0)
#define write_csr_entrylo0(val) csr_write64(val, LOONGARCH_CSR_TLBELO0)
#define read_csr_entrylo1() csr_read64(LOONGARCH_CSR_TLBELO1)
#define write_csr_entrylo1(val) csr_write64(val, LOONGARCH_CSR_TLBELO1)
#define read_csr_entryhi() csr_read(LOONGARCH_CSR_TLBEHI)
#define write_csr_entryhi(val) csr_write(val, LOONGARCH_CSR_TLBEHI)
#define read_csr_entrylo0() csr_read(LOONGARCH_CSR_TLBELO0)
#define write_csr_entrylo0(val) csr_write(val, LOONGARCH_CSR_TLBELO0)
#define read_csr_entrylo1() csr_read(LOONGARCH_CSR_TLBELO1)
#define write_csr_entrylo1(val) csr_write(val, LOONGARCH_CSR_TLBELO1)
#define read_csr_ecfg() csr_read32(LOONGARCH_CSR_ECFG)
#define write_csr_ecfg(val) csr_write32(val, LOONGARCH_CSR_ECFG)
#define read_csr_estat() csr_read32(LOONGARCH_CSR_ESTAT)
@ -1282,20 +1294,20 @@ static inline void write_csr_tlbrefill_pagesize(unsigned int size)
#define read_csr_euen() csr_read32(LOONGARCH_CSR_EUEN)
#define write_csr_euen(val) csr_write32(val, LOONGARCH_CSR_EUEN)
#define read_csr_cpuid() csr_read32(LOONGARCH_CSR_CPUID)
#define read_csr_prcfg1() csr_read64(LOONGARCH_CSR_PRCFG1)
#define write_csr_prcfg1(val) csr_write64(val, LOONGARCH_CSR_PRCFG1)
#define read_csr_prcfg2() csr_read64(LOONGARCH_CSR_PRCFG2)
#define write_csr_prcfg2(val) csr_write64(val, LOONGARCH_CSR_PRCFG2)
#define read_csr_prcfg3() csr_read64(LOONGARCH_CSR_PRCFG3)
#define write_csr_prcfg3(val) csr_write64(val, LOONGARCH_CSR_PRCFG3)
#define read_csr_prcfg1() csr_read(LOONGARCH_CSR_PRCFG1)
#define write_csr_prcfg1(val) csr_write(val, LOONGARCH_CSR_PRCFG1)
#define read_csr_prcfg2() csr_read(LOONGARCH_CSR_PRCFG2)
#define write_csr_prcfg2(val) csr_write(val, LOONGARCH_CSR_PRCFG2)
#define read_csr_prcfg3() csr_read(LOONGARCH_CSR_PRCFG3)
#define write_csr_prcfg3(val) csr_write(val, LOONGARCH_CSR_PRCFG3)
#define read_csr_stlbpgsize() csr_read32(LOONGARCH_CSR_STLBPGSIZE)
#define write_csr_stlbpgsize(val) csr_write32(val, LOONGARCH_CSR_STLBPGSIZE)
#define read_csr_rvacfg() csr_read32(LOONGARCH_CSR_RVACFG)
#define write_csr_rvacfg(val) csr_write32(val, LOONGARCH_CSR_RVACFG)
#define write_csr_tintclear(val) csr_write32(val, LOONGARCH_CSR_TINTCLR)
#define read_csr_impctl1() csr_read64(LOONGARCH_CSR_IMPCTL1)
#define write_csr_impctl1(val) csr_write64(val, LOONGARCH_CSR_IMPCTL1)
#define write_csr_impctl2(val) csr_write64(val, LOONGARCH_CSR_IMPCTL2)
#define read_csr_impctl1() csr_read(LOONGARCH_CSR_IMPCTL1)
#define write_csr_impctl1(val) csr_write(val, LOONGARCH_CSR_IMPCTL1)
#define write_csr_impctl2(val) csr_write(val, LOONGARCH_CSR_IMPCTL2)
#define read_csr_perfctrl0() csr_read64(LOONGARCH_CSR_PERFCTRL0)
#define read_csr_perfcntr0() csr_read64(LOONGARCH_CSR_PERFCNTR0)

View File

@ -27,7 +27,7 @@ register unsigned long __my_cpu_offset __asm__("$r21");
static inline void set_my_cpu_offset(unsigned long off)
{
__my_cpu_offset = off;
csr_write64(off, PERCPU_BASE_KS);
csr_write(off, PERCPU_BASE_KS);
}
#define __my_cpu_offset \

View File

@ -298,8 +298,15 @@ static inline void cpu_probe_loongson(struct cpuinfo_loongarch *c, unsigned int
return;
}
#ifdef CONFIG_64BIT
*vendor = iocsr_read64(LOONGARCH_IOCSR_VENDOR);
*cpuname = iocsr_read64(LOONGARCH_IOCSR_CPUNAME);
#else
*vendor = iocsr_read32(LOONGARCH_IOCSR_VENDOR) |
(u64)iocsr_read32(LOONGARCH_IOCSR_VENDOR + 4) << 32;
*cpuname = iocsr_read32(LOONGARCH_IOCSR_CPUNAME) |
(u64)iocsr_read32(LOONGARCH_IOCSR_CPUNAME + 4) << 32;
#endif
if (!__cpu_full_name[cpu]) {
if (((char *)vendor)[0] == 0)

View File

@ -50,10 +50,10 @@ static int constant_set_state_oneshot(struct clock_event_device *evt)
raw_spin_lock(&state_lock);
timer_config = csr_read64(LOONGARCH_CSR_TCFG);
timer_config = csr_read(LOONGARCH_CSR_TCFG);
timer_config |= CSR_TCFG_EN;
timer_config &= ~CSR_TCFG_PERIOD;
csr_write64(timer_config, LOONGARCH_CSR_TCFG);
csr_write(timer_config, LOONGARCH_CSR_TCFG);
raw_spin_unlock(&state_lock);
@ -70,7 +70,7 @@ static int constant_set_state_periodic(struct clock_event_device *evt)
period = const_clock_freq / HZ;
timer_config = period & CSR_TCFG_VAL;
timer_config |= (CSR_TCFG_PERIOD | CSR_TCFG_EN);
csr_write64(timer_config, LOONGARCH_CSR_TCFG);
csr_write(timer_config, LOONGARCH_CSR_TCFG);
raw_spin_unlock(&state_lock);
@ -83,9 +83,9 @@ static int constant_set_state_shutdown(struct clock_event_device *evt)
raw_spin_lock(&state_lock);
timer_config = csr_read64(LOONGARCH_CSR_TCFG);
timer_config = csr_read(LOONGARCH_CSR_TCFG);
timer_config &= ~CSR_TCFG_EN;
csr_write64(timer_config, LOONGARCH_CSR_TCFG);
csr_write(timer_config, LOONGARCH_CSR_TCFG);
raw_spin_unlock(&state_lock);
@ -98,7 +98,7 @@ static int constant_timer_next_event(unsigned long delta, struct clock_event_dev
delta &= CSR_TCFG_VAL;
timer_config = delta | CSR_TCFG_EN;
csr_write64(timer_config, LOONGARCH_CSR_TCFG);
csr_write(timer_config, LOONGARCH_CSR_TCFG);
return 0;
}
@ -137,7 +137,7 @@ void save_counter(void)
void sync_counter(void)
{
/* Ensure counter begin at 0 */
csr_write64(init_offset, LOONGARCH_CSR_CNTC);
csr_write(init_offset, LOONGARCH_CSR_CNTC);
}
int constant_clockevent_init(void)
@ -235,7 +235,7 @@ void __init time_init(void)
else
const_clock_freq = calc_const_freq();
init_offset = -(drdtime() - csr_read64(LOONGARCH_CSR_CNTC));
init_offset = -(drdtime() - csr_read(LOONGARCH_CSR_CNTC));
constant_clockevent_init();
constant_clocksource_init();

View File

@ -625,7 +625,7 @@ asmlinkage void noinstr do_bce(struct pt_regs *regs)
bool user = user_mode(regs);
bool pie = regs_irqs_disabled(regs);
unsigned long era = exception_era(regs);
u64 badv = 0, lower = 0, upper = ULONG_MAX;
unsigned long badv = 0, lower = 0, upper = ULONG_MAX;
union loongarch_instruction insn;
irqentry_state_t state = irqentry_enter(regs);
@ -1070,10 +1070,13 @@ asmlinkage void noinstr do_reserved(struct pt_regs *regs)
asmlinkage void cache_parity_error(void)
{
u32 merrctl = csr_read32(LOONGARCH_CSR_MERRCTL);
unsigned long merrera = csr_read(LOONGARCH_CSR_MERRERA);
/* For the moment, report the problem and hang. */
pr_err("Cache error exception:\n");
pr_err("csr_merrctl == %08x\n", csr_read32(LOONGARCH_CSR_MERRCTL));
pr_err("csr_merrera == %016lx\n", csr_read64(LOONGARCH_CSR_MERRERA));
pr_err("csr_merrctl == %08x\n", merrctl);
pr_err("csr_merrera == %016lx\n", merrera);
panic("Can't handle the cache error!");
}
@ -1130,9 +1133,9 @@ static void configure_exception_vector(void)
eentry = (unsigned long)exception_handlers;
tlbrentry = (unsigned long)exception_handlers + 80*VECSIZE;
csr_write64(eentry, LOONGARCH_CSR_EENTRY);
csr_write64(__pa(eentry), LOONGARCH_CSR_MERRENTRY);
csr_write64(__pa(tlbrentry), LOONGARCH_CSR_TLBRENTRY);
csr_write(eentry, LOONGARCH_CSR_EENTRY);
csr_write(__pa(eentry), LOONGARCH_CSR_MERRENTRY);
csr_write(__pa(tlbrentry), LOONGARCH_CSR_TLBRENTRY);
}
void per_cpu_trap_init(int cpu)

View File

@ -20,9 +20,9 @@ void dump_tlb_regs(void)
pr_info("Index : 0x%0x\n", read_csr_tlbidx());
pr_info("PageSize : 0x%0x\n", read_csr_pagesize());
pr_info("EntryHi : 0x%0*lx\n", field, read_csr_entryhi());
pr_info("EntryLo0 : 0x%0*lx\n", field, read_csr_entrylo0());
pr_info("EntryLo1 : 0x%0*lx\n", field, read_csr_entrylo1());
pr_info("EntryHi : 0x%0*lx\n", field, (unsigned long)read_csr_entryhi());
pr_info("EntryLo0 : 0x%0*lx\n", field, (unsigned long)read_csr_entrylo0());
pr_info("EntryLo1 : 0x%0*lx\n", field, (unsigned long)read_csr_entrylo1());
}
static void dump_tlb(int first, int last)

View File

@ -229,11 +229,11 @@ static void setup_ptwalker(void)
if (cpu_has_ptw)
pwctl1 |= CSR_PWCTL1_PTW;
csr_write64(pwctl0, LOONGARCH_CSR_PWCTL0);
csr_write64(pwctl1, LOONGARCH_CSR_PWCTL1);
csr_write64((long)swapper_pg_dir, LOONGARCH_CSR_PGDH);
csr_write64((long)invalid_pg_dir, LOONGARCH_CSR_PGDL);
csr_write64((long)smp_processor_id(), LOONGARCH_CSR_TMID);
csr_write(pwctl0, LOONGARCH_CSR_PWCTL0);
csr_write(pwctl1, LOONGARCH_CSR_PWCTL1);
csr_write((long)swapper_pg_dir, LOONGARCH_CSR_PGDH);
csr_write((long)invalid_pg_dir, LOONGARCH_CSR_PGDL);
csr_write((long)smp_processor_id(), LOONGARCH_CSR_TMID);
}
static void output_pgtable_bits_defines(void)

View File

@ -10,7 +10,7 @@ static u32 saved_crmd;
static u32 saved_prmd;
static u32 saved_euen;
static u32 saved_ecfg;
static u64 saved_pcpu_base;
static unsigned long saved_pcpu_base;
struct pt_regs saved_regs;
void save_processor_state(void)
@ -20,7 +20,7 @@ void save_processor_state(void)
saved_prmd = csr_read32(LOONGARCH_CSR_PRMD);
saved_euen = csr_read32(LOONGARCH_CSR_EUEN);
saved_ecfg = csr_read32(LOONGARCH_CSR_ECFG);
saved_pcpu_base = csr_read64(PERCPU_BASE_KS);
saved_pcpu_base = csr_read(PERCPU_BASE_KS);
if (is_fpu_owner())
save_fp(current);
@ -33,7 +33,7 @@ void restore_processor_state(void)
csr_write32(saved_prmd, LOONGARCH_CSR_PRMD);
csr_write32(saved_euen, LOONGARCH_CSR_EUEN);
csr_write32(saved_ecfg, LOONGARCH_CSR_ECFG);
csr_write64(saved_pcpu_base, PERCPU_BASE_KS);
csr_write(saved_pcpu_base, PERCPU_BASE_KS);
if (is_fpu_owner())
restore_fp(current);

View File

@ -20,24 +20,24 @@ u64 loongarch_suspend_addr;
struct saved_registers {
u32 ecfg;
u32 euen;
u64 pgd;
u64 kpgd;
u32 pwctl0;
u32 pwctl1;
u64 pcpu_base;
unsigned long pgd;
unsigned long kpgd;
unsigned long pcpu_base;
};
static struct saved_registers saved_regs;
void loongarch_common_suspend(void)
{
save_counter();
saved_regs.pgd = csr_read64(LOONGARCH_CSR_PGDL);
saved_regs.kpgd = csr_read64(LOONGARCH_CSR_PGDH);
saved_regs.pgd = csr_read(LOONGARCH_CSR_PGDL);
saved_regs.kpgd = csr_read(LOONGARCH_CSR_PGDH);
saved_regs.pwctl0 = csr_read32(LOONGARCH_CSR_PWCTL0);
saved_regs.pwctl1 = csr_read32(LOONGARCH_CSR_PWCTL1);
saved_regs.ecfg = csr_read32(LOONGARCH_CSR_ECFG);
saved_regs.euen = csr_read32(LOONGARCH_CSR_EUEN);
saved_regs.pcpu_base = csr_read64(PERCPU_BASE_KS);
saved_regs.pcpu_base = csr_read(PERCPU_BASE_KS);
loongarch_suspend_addr = loongson_sysconf.suspend_addr;
}
@ -46,17 +46,17 @@ void loongarch_common_resume(void)
{
sync_counter();
local_flush_tlb_all();
csr_write64(eentry, LOONGARCH_CSR_EENTRY);
csr_write64(eentry, LOONGARCH_CSR_MERRENTRY);
csr_write64(tlbrentry, LOONGARCH_CSR_TLBRENTRY);
csr_write(eentry, LOONGARCH_CSR_EENTRY);
csr_write(eentry, LOONGARCH_CSR_MERRENTRY);
csr_write(tlbrentry, LOONGARCH_CSR_TLBRENTRY);
csr_write64(saved_regs.pgd, LOONGARCH_CSR_PGDL);
csr_write64(saved_regs.kpgd, LOONGARCH_CSR_PGDH);
csr_write(saved_regs.pgd, LOONGARCH_CSR_PGDL);
csr_write(saved_regs.kpgd, LOONGARCH_CSR_PGDH);
csr_write32(saved_regs.pwctl0, LOONGARCH_CSR_PWCTL0);
csr_write32(saved_regs.pwctl1, LOONGARCH_CSR_PWCTL1);
csr_write32(saved_regs.ecfg, LOONGARCH_CSR_ECFG);
csr_write32(saved_regs.euen, LOONGARCH_CSR_EUEN);
csr_write64(saved_regs.pcpu_base, PERCPU_BASE_KS);
csr_write(saved_regs.pcpu_base, PERCPU_BASE_KS);
}
int loongarch_acpi_suspend(void)

View File

@ -72,10 +72,10 @@ efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image,
desc_ver, priv.runtime_map);
/* Config Direct Mapping */
csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0);
csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1);
csr_write64(CSR_DMW2_INIT, LOONGARCH_CSR_DMWIN2);
csr_write64(CSR_DMW3_INIT, LOONGARCH_CSR_DMWIN3);
csr_write(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0);
csr_write(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1);
csr_write(CSR_DMW2_INIT, LOONGARCH_CSR_DMWIN2);
csr_write(CSR_DMW3_INIT, LOONGARCH_CSR_DMWIN3);
real_kernel_entry = (void *)kernel_entry_address(kernel_addr, image);