]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[riscv] Serialise MMIO accesses with respect to each other
authorMichael Brown <mcb30@ipxe.org>
Sun, 22 Jun 2025 08:26:36 +0000 (09:26 +0100)
committerMichael Brown <mcb30@ipxe.org>
Sun, 22 Jun 2025 08:45:09 +0000 (09:45 +0100)
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 <mcb30@ipxe.org>
src/arch/riscv/include/ipxe/riscv_io.h

index be4449ff19cfc7da28a482c87ac61e44f3fa15ef..539dbd7ed9364ddb8b22b6156768fd64dca340ef 100644 (file)
@@ -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] ),                     \