]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[riscv] Create coherent DMA mapping of 32-bit address space on demand
authorMichael Brown <mcb30@ipxe.org>
Fri, 11 Jul 2025 11:00:10 +0000 (12:00 +0100)
committerMichael Brown <mcb30@ipxe.org>
Fri, 11 Jul 2025 11:23:51 +0000 (12:23 +0100)
Reuse the code that creates I/O device page mappings to create the
coherent DMA mapping of the 32-bit address space on demand, instead of
constructing this mapping as part of the initial page table.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/riscv/core/riscv_dma.c
src/arch/riscv/core/svpage.c
src/arch/riscv/include/ipxe/svpage.h
src/arch/riscv/prefix/libprefix.S

index ab88f2785aacf6225a7df943a536585ebe16500f..0a0107bd12b727bd6c72ed3f100eb5514899945c 100644 (file)
@@ -126,7 +126,7 @@ static void * riscv_dma_alloc ( struct dma_device *dma,
        /* Calculate coherently-mapped virtual address */
        phys = virt_to_phys ( addr );
        assert ( phys == ( ( uint32_t ) phys ) );
-       caddr = ( ( void * ) ( intptr_t ) ( phys + SVPAGE_DMA32 ) );
+       caddr = ( ( void * ) ( intptr_t ) ( phys + svpage_dma32() ) );
        assert ( phys == virt_to_phys ( caddr ) );
        DBGC ( dma, "DMA allocated [%#08lx,%#08lx) via %p\n",
               phys, ( phys + len ), caddr );
index 2240b3736440d3d65aea7f7549e6742436228ff1..e64c802fe377547cf4b74d71e6c0599cf02c5bae 100644 (file)
@@ -78,23 +78,30 @@ extern struct page_table page_table;
  * We choose to use 1GB "gigapages", since these are supported by all
  * paging levels.
  */
-#define IO_PAGE_SIZE 0x40000000UL
+#define MAP_PAGE_SIZE 0x40000000UL
 
 /** I/O page base address
  *
  * The recursive page table entry maps the high 512GB of the 64-bit
  * address space as 1GB "gigapages".
  */
-#define IO_BASE ( ( void * ) ( intptr_t ) ( -1ULL << 39 ) )
+#define MAP_BASE ( ( void * ) ( intptr_t ) ( -1ULL << 39 ) )
+
+/** Coherent DMA mapping of the 32-bit address space */
+static void *svpage_dma32_base;
+
+/** Size of the coherent DMA mapping */
+#define DMA32_LEN ( ( size_t ) 0x100000000ULL )
 
 /**
- * Map pages for I/O
+ * Map pages
  *
- * @v bus_addr         Bus address
- * @v len              Length of region
- * @ret io_addr                I/O address
+ * @v phys             Physical address
+ * @v len              Length
+ * @v attrs            Page attributes
+ * @ret virt           Mapped virtual address, or NULL on error
  */
-static void * svpage_ioremap ( unsigned long bus_addr, size_t len ) {
+static void * svpage_map ( physaddr_t phys, size_t len, unsigned long attrs ) {
        unsigned long satp;
        unsigned long start;
        unsigned int count;
@@ -102,30 +109,32 @@ static void * svpage_ioremap ( unsigned long bus_addr, size_t len ) {
        unsigned int first;
        unsigned int i;
        size_t offset;
-       void *io_addr;
+       void *virt;
 
-       DBGC ( &page_table, "SVPAGE mapping %#08lx+%#zx\n", bus_addr, len );
+       DBGC ( &page_table, "SVPAGE mapping %#08lx+%#zx attrs %#016lx\n",
+              phys, len, attrs );
 
-       /* Sanity check */
+       /* Sanity checks */
        if ( ! len )
                return NULL;
+       assert ( attrs & PTE_V );
 
        /* Use physical address directly if paging is disabled */
        __asm__ ( "csrr %0, satp" : "=r" ( satp ) );
        if ( ! satp ) {
-               io_addr = phys_to_virt ( bus_addr );
+               virt = phys_to_virt ( phys );
                DBGC ( &page_table, "SVPAGE mapped %#08lx+%#zx to %p (no "
-                      "paging)\n", bus_addr, len, io_addr );
-               return io_addr;
+                      "paging)\n", phys, len, virt );
+               return virt;
        }
 
        /* Round down start address to a page boundary */
-       start = ( bus_addr & ~( IO_PAGE_SIZE - 1 ) );
-       offset = ( bus_addr - start );
-       assert ( offset < IO_PAGE_SIZE );
+       start = ( phys & ~( MAP_PAGE_SIZE - 1 ) );
+       offset = ( phys - start );
+       assert ( offset < MAP_PAGE_SIZE );
 
        /* Calculate number of pages required */
-       count = ( ( offset + len + IO_PAGE_SIZE - 1 ) / IO_PAGE_SIZE );
+       count = ( ( offset + len + MAP_PAGE_SIZE - 1 ) / MAP_PAGE_SIZE );
        assert ( count != 0 );
        assert ( count < ( sizeof ( page_table.pte ) /
                           sizeof ( page_table.pte[0] ) ) );
@@ -139,24 +148,23 @@ static void * svpage_ioremap ( unsigned long bus_addr, size_t len ) {
                                    sizeof ( page_table.pte[0] ) ) ;
              first += stride ) {
 
-               /* Calculate I/O address */
-               io_addr = ( IO_BASE + ( first * IO_PAGE_SIZE ) + offset );
+               /* Calculate virtual address */
+               virt = ( MAP_BASE + ( first * MAP_PAGE_SIZE ) + offset );
 
                /* Check that page table entries are available */
                for ( i = first ; i < ( first + count ) ; i++ ) {
                        if ( page_table.pte[i] & PTE_V ) {
-                               io_addr = NULL;
+                               virt = NULL;
                                break;
                        }
                }
-               if ( ! io_addr )
+               if ( ! virt )
                        continue;
 
                /* Create page table entries */
                for ( i = first ; i < ( first + count ) ; i++ ) {
-                       page_table.pte[i] = ( PTE_PPN ( start ) | PTE_V |
-                                              PTE_R | PTE_W | PTE_A | PTE_D );
-                       start += IO_PAGE_SIZE;
+                       page_table.pte[i] = ( PTE_PPN ( start ) | attrs );
+                       start += MAP_PAGE_SIZE;
                }
 
                /* Mark last page as being the last in this allocation */
@@ -165,30 +173,30 @@ static void * svpage_ioremap ( unsigned long bus_addr, size_t len ) {
                /* Synchronise page table updates */
                __asm__ __volatile__ ( "sfence.vma" );
 
-               /* Return I/O address */
+               /* Return virtual address */
                DBGC ( &page_table, "SVPAGE mapped %#08lx+%#zx to %p using "
-                      "PTEs [%d-%d]\n", bus_addr, len, io_addr, first,
+                      "PTEs [%d-%d]\n", phys, len, virt, first,
                       ( first + count - 1 ) );
-               return io_addr;
+               return virt;
        }
 
        DBGC ( &page_table, "SVPAGE could not map %#08lx+%#zx\n",
-              bus_addr, len );
+              phys, len );
        return NULL;
 }
 
 /**
- * Unmap pages for I/O
+ * Unmap pages
  *
- * @v io_addr          I/O address
+ * @v virt             Virtual address
  */
-static void svpage_iounmap ( volatile const void *io_addr ) {
+static void svpage_unmap ( const volatile void *virt ) {
        unsigned long satp;
        unsigned int first;
        unsigned int i;
        int is_last;
 
-       DBGC ( &page_table, "SVPAGE unmapping %p\n", io_addr );
+       DBGC ( &page_table, "SVPAGE unmapping %p\n", virt );
 
        /* Do nothing if paging is disabled */
        __asm__ ( "csrr %0, satp" : "=r" ( satp ) );
@@ -196,7 +204,7 @@ static void svpage_iounmap ( volatile const void *io_addr ) {
                return;
 
        /* Calculate first page table entry */
-       first = ( ( io_addr - IO_BASE ) / IO_PAGE_SIZE );
+       first = ( ( virt - MAP_BASE ) / MAP_PAGE_SIZE );
 
        /* Clear page table entries */
        for ( i = first ; ; i++ ) {
@@ -219,9 +227,41 @@ static void svpage_iounmap ( volatile const void *io_addr ) {
        __asm__ __volatile__ ( "sfence.vma" );
 
        DBGC ( &page_table, "SVPAGE unmapped %p using PTEs [%d-%d]\n",
-              io_addr, first, i );
+              virt, first, i );
+}
+
+/**
+ * Map pages for I/O
+ *
+ * @v bus_addr         Bus address
+ * @v len              Length of region
+ * @ret io_addr                I/O address
+ */
+static void * svpage_ioremap ( unsigned long bus_addr, size_t len ) {
+       unsigned long attrs = ( PTE_V | PTE_R | PTE_W | PTE_A | PTE_D );
+
+       /* Map pages for I/O */
+       return svpage_map ( bus_addr, len, attrs );
+}
+
+/**
+ * Get 32-bit address space coherent DMA mapping address
+ *
+ * @ret base           Coherent DMA mapping base address
+ */
+void * svpage_dma32 ( void ) {
+       unsigned long attrs = ( PTE_V | PTE_R | PTE_W | PTE_A | PTE_D );
+
+       /* Create mapping, if necessary */
+       if ( ! svpage_dma32_base )
+               svpage_dma32_base = svpage_map ( 0, DMA32_LEN, attrs );
+
+       /* Sanity check */
+       assert ( virt_to_phys ( svpage_dma32_base ) == 0 );
+
+       return svpage_dma32_base;
 }
 
 PROVIDE_IOMAP_INLINE ( svpage, io_to_bus );
 PROVIDE_IOMAP ( svpage, ioremap, svpage_ioremap );
-PROVIDE_IOMAP ( svpage, iounmap, svpage_iounmap );
+PROVIDE_IOMAP ( svpage, iounmap, svpage_unmap );
index 9a0d38b9f128bad44bd3ccf130cbe05f4194b4e6..897a3379a66effaa6ec3d0085da20eeb9cac3d3c 100644 (file)
@@ -23,11 +23,6 @@ IOMAP_INLINE ( svpage, io_to_bus ) ( volatile const void *io_addr ) {
        return ( ( intptr_t ) io_addr );
 }
 
-/** Base virtual address for coherent DMA mappings
- *
- * The 64-bit page table includes an uncached mapping of the 32-bit
- * address space at this virtual address.
- */
-#define SVPAGE_DMA32 0xffffffc000000000ULL
+extern void * svpage_dma32 ( void );
 
 #endif /* _IPXE_SVPAGE_H */
index 75fac1f5db0f48db665ccd0805dd9a9baf6a0b87..490180862997131a7e664ddc22a6e914c28cb04c 100644 (file)
@@ -785,16 +785,6 @@ page_table:
  *      higher bits set, and so cannot identity-map to a 55-bit
  *      physical address).
  *
- *    - PTE[256-259] : Coherent DMA mapping
- *
- *      These are 1GB "gigapages" used to map the low 4GB of the
- *      physical address space with caching disabled, for use by
- *      coherent DMA mappings.
- *
- *      We use 1GB "gigapages" even for Sv48 and Sv57, since this
- *      allows the virtual address base 0xffffffc000000000 to remain a
- *      constant regardless of supported paging level.
- *
  *    - PTE[x-y] : Virtual address map for iPXE
  *
  *      These are 2MB "megapages" used to map the link-time virtual
@@ -888,24 +878,6 @@ enable_paging_64:
        ori     t0, t0, PTE_V
        STOREN  t0, -PTE_SIZE(a3)
 
-       /* Calculate PTE stride for coherent DMA map
-        *
-        * PPN[2] LSB is PTE bit 28 in all paging modes, and so the
-        * stride is always ( 1 << 28 )
-        */
-       li      a4, 1
-       slli    a4, a4, PTE_PPN2_LSB
-
-       /* Construct PTE[256-259] for 32-bit coherent DMA map */
-       addi    a3, a3, -( ( PTE_COUNT / 2 ) * PTE_SIZE )
-       li      t0, ( 1 << ( 32 - VPN2_LSB ) )
-       li      t1, ( PTE_LEAF & ~PTE_X )
-1:     STOREN  t1, (a3)
-       addi    a3, a3, PTE_SIZE
-       add     t1, t1, a4
-       addi    t0, t0, -1
-       bgtz    t0, 1b
-
        /* Construct base page table entry for address zero */
        li      t0, PTE_LEAF
        STOREN  t0, (a0)