From 25fa01822b7864ace7abe792e81662ea291e87fa Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 22 Jun 2025 09:26:36 +0100 Subject: [PATCH] [riscv] Serialise MMIO accesses with respect to each other iPXE drivers have been written with the implicit assumption that MMIO writes are allowed to be posted but that an MMIO register read or write after another MMIO register write will always observe the effects of the first write. For example: after having written a byte to the transmit holding register (THR) of a 16550 UART, it is expected that any subsequent read of the line status register (LSR) will observe a value consistent with the occurrence of the write. RISC-V does not seem to provide any ordering guarantees between accesses to different registers within the same MMIO device. Add fences as part of the MMIO accessors to provide the assumed guarantees. Use "fence io, io" before each MMIO read or write to enforce full serialisation of MMIO accesses with respect to each other. This is almost certainly more conservative than is strictly necessary. Signed-off-by: Michael Brown --- src/arch/riscv/include/ipxe/riscv_io.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/arch/riscv/include/ipxe/riscv_io.h b/src/arch/riscv/include/ipxe/riscv_io.h index be4449ff1..539dbd7ed 100644 --- a/src/arch/riscv/include/ipxe/riscv_io.h +++ b/src/arch/riscv/include/ipxe/riscv_io.h @@ -47,7 +47,8 @@ IOAPI_INLINE ( riscv, bus_to_phys ) ( unsigned long bus_addr ) { static inline __always_inline _type \ IOAPI_INLINE ( riscv, read ## _suffix ) ( volatile _type *io_addr ) { \ unsigned long data; \ - __asm__ __volatile__ ( "l" _insn_suffix " %0, %1" \ + __asm__ __volatile__ ( "fence io, io\n\t" \ + "l" _insn_suffix " %0, %1\n\t" \ : "=r" ( data ) : "m" ( *io_addr ) ); \ return data; \ } @@ -57,7 +58,8 @@ IOAPI_INLINE ( riscv, read ## _suffix ) ( volatile _type *io_addr ) { \ static inline __always_inline void \ IOAPI_INLINE ( riscv, write ## _suffix ) ( _type data, \ volatile _type *io_addr ) { \ - __asm__ __volatile__ ( "s" _insn_suffix " %0, %1" \ + __asm__ __volatile__ ( "fence io, io\n\t" \ + "s" _insn_suffix " %0, %1\n\t" \ : : "r" ( data ), "m" ( *io_addr ) ); \ } @@ -69,7 +71,8 @@ IOAPI_INLINE ( riscv, read ## _suffix ) ( volatile _type *io_addr ) { \ unsigned long half[2]; \ _type data; \ } u; \ - __asm__ __volatile__ ( "l" _insn_suffix " %0, 0(%2)\n\t" \ + __asm__ __volatile__ ( "fence io, io\n\t" \ + "l" _insn_suffix " %0, 0(%2)\n\t" \ "l" _insn_suffix " %1, %3(%2)\n\t" \ : "=&r" ( u.half[0] ), \ "=&r" ( u.half[1] ) \ @@ -87,7 +90,8 @@ IOAPI_INLINE ( riscv, write ## _suffix ) ( _type data, \ unsigned long half[2]; \ _type data; \ } u = { .data = data }; \ - __asm__ __volatile__ ( "s" _insn_suffix " %0, 0(%2)\n\t" \ + __asm__ __volatile__ ( "fence io, io\n\t" \ + "s" _insn_suffix " %0, 0(%2)\n\t" \ "s" _insn_suffix " %1, %3(%2)\n\t" : \ : "r" ( u.half[0] ), \ "r" ( u.half[1] ), \ -- 2.47.2