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