1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 3 #ifndef _ASM_RISCV_CSR_INDIRECT_H 4 #define _ASM_RISCV_CSR_INDIRECT_H 5 6 #include <linux/irqflags.h> 7 8 #include <asm/csr.h> 9 10 /* 11 * These have to be macros rather than functions: csr_read()/csr_write() 12 * stringify their CSR argument into the inline asm template via __ASM_STR(), 13 * so the CSR number must be a literal token at preprocessing time. Passing it 14 * as a function parameter emits "csrr %0, iregcsr", which no assembler can 15 * resolve. RISC-V has no register-indirect form of csrr/csrw - the CSR is a 16 * 12-bit immediate - so the sireg CSR selecting the indirect window cannot 17 * itself be a variable. 18 */ 19 #define csr_indirect_read(iregcsr, iselbase, iseloff) ({ \ 20 unsigned long __value = 0; \ 21 unsigned long __flags; \ 22 local_irq_save(__flags); \ 23 csr_write(CSR_ISELECT, (iselbase) + (iseloff)); \ 24 __value = csr_read(iregcsr); \ 25 local_irq_restore(__flags); \ 26 __value; \ 27 }) 28 29 #define csr_indirect_write(iregcsr, iselbase, iseloff, value) ({ \ 30 unsigned long __flags; \ 31 local_irq_save(__flags); \ 32 csr_write(CSR_ISELECT, (iselbase) + (iseloff)); \ 33 csr_write(iregcsr, (value)); \ 34 local_irq_restore(__flags); \ 35 }) 36 37 #define csr_indirect_warl(iregcsr, iselbase, iseloff, warl_val) ({ \ 38 unsigned long __old_val = 0, __value = 0; \ 39 unsigned long __flags; \ 40 local_irq_save(__flags); \ 41 csr_write(CSR_ISELECT, (iselbase) + (iseloff)); \ 42 __old_val = csr_read(iregcsr); \ 43 csr_write(iregcsr, (warl_val)); \ 44 __value = csr_read(iregcsr); \ 45 csr_write(iregcsr, __old_val); \ 46 local_irq_restore(__flags); \ 47 __value; \ 48 }) 49 50 #endif 51