Skip to content

Commit

Permalink
riscv: pgtable: Add DMA_COHERENT with custom PTE attributes
Browse files Browse the repository at this point in the history
The dma-noncoherent SOCs need different virtual memory mappings
with different attributes:
 - noncached + Strong Order (for IO/DMA descriptor)
 - noncached + Weak Order (for writecombine usage, eg: frame
   buffer)

All above base on PTE attributes by MMU hardware. That means
address attributes are determined by PTE entry, not PMA. RISC-V
soc vendors have defined their own custom PTE attributes for
dma-noncoherency.

Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Signed-off-by: Liu Shaohua <liush@allwinnertech.com>
Cc: Palmer Dabbelt <palmerdabbelt@google.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Anup Patel <anup.patel@wdc.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Drew Fustini <drew@beagleboard.org>
Cc: Wei Fu <wefu@redhat.com>
Cc: Wei Wu <lazyparser@gmail.com>
Cc: Chen-Yu Tsai <wens@csie.org>
Cc: Maxime Ripard <maxime@cerno.tech>
  • Loading branch information
guoren83 authored and smaeul committed Nov 15, 2021
1 parent a7f9fdb commit c1bc61c
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 8 deletions.
22 changes: 21 additions & 1 deletion arch/riscv/include/asm/pgtable-bits.h
Expand Up @@ -24,6 +24,11 @@
#define _PAGE_DIRTY (1 << 7) /* Set by hardware on any write */
#define _PAGE_SOFT (1 << 8) /* Reserved for software */

#define _PAGE_DMA_MASK __riscv_custom_pte.mask
#define _PAGE_DMA_CACHE __riscv_custom_pte.cache
#define _PAGE_DMA_IO __riscv_custom_pte.io
#define _PAGE_DMA_WC __riscv_custom_pte.wc

#define _PAGE_SPECIAL _PAGE_SOFT
#define _PAGE_TABLE _PAGE_PRESENT

Expand All @@ -35,10 +40,25 @@

#define _PAGE_PFN_SHIFT 10

#ifndef __ASSEMBLY__

struct riscv_custom_pte {
unsigned long cache;
unsigned long mask;
unsigned long io;
unsigned long wc;
};

extern struct riscv_custom_pte __riscv_custom_pte;

/* Set of bits to preserve across pte_modify() */
#define _PAGE_CHG_MASK (~(unsigned long)(_PAGE_PRESENT | _PAGE_READ | \
_PAGE_WRITE | _PAGE_EXEC | \
_PAGE_USER | _PAGE_GLOBAL))
_PAGE_USER | _PAGE_GLOBAL | \
_PAGE_DMA_MASK))

#endif

/*
* when all of R/W/X are zero, the PTE is a pointer to the next level
* of the page table; otherwise, it is a leaf PTE.
Expand Down
11 changes: 4 additions & 7 deletions arch/riscv/include/asm/pgtable.h
Expand Up @@ -117,7 +117,7 @@
#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)

/* Page protection bits */
#define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER)
#define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER | _PAGE_DMA_CACHE)

#define PAGE_NONE __pgprot(_PAGE_PROT_NONE)
#define PAGE_READ __pgprot(_PAGE_BASE | _PAGE_READ)
Expand All @@ -138,7 +138,8 @@
| _PAGE_PRESENT \
| _PAGE_ACCESSED \
| _PAGE_DIRTY \
| _PAGE_GLOBAL)
| _PAGE_GLOBAL \
| _PAGE_DMA_CACHE)

#define PAGE_KERNEL __pgprot(_PAGE_KERNEL)
#define PAGE_KERNEL_READ __pgprot(_PAGE_KERNEL & ~_PAGE_WRITE)
Expand All @@ -148,11 +149,7 @@

#define PAGE_TABLE __pgprot(_PAGE_TABLE)

/*
* The RISC-V ISA doesn't yet specify how to query or modify PMAs, so we can't
* change the properties of memory regions.
*/
#define _PAGE_IOREMAP _PAGE_KERNEL
#define _PAGE_IOREMAP ((_PAGE_KERNEL & ~_PAGE_DMA_MASK) | _PAGE_DMA_IO)

extern pgd_t swapper_pg_dir[];

Expand Down
1 change: 1 addition & 0 deletions arch/riscv/include/asm/soc.h
Expand Up @@ -17,6 +17,7 @@
= { .compatible = compat, .data = fn }

void soc_early_init(void);
void soc_setup_vm(void);

extern unsigned long __soc_early_init_table_start;
extern unsigned long __soc_early_init_table_end;
Expand Down
1 change: 1 addition & 0 deletions arch/riscv/include/asm/vendorid_list.h
Expand Up @@ -6,5 +6,6 @@
#define ASM_VENDOR_LIST_H

#define SIFIVE_VENDOR_ID 0x489
#define THEAD_VENDOR_ID 0x401

#endif
22 changes: 22 additions & 0 deletions arch/riscv/kernel/soc.c
Expand Up @@ -3,8 +3,10 @@
* Copyright (C) 2020 Western Digital Corporation or its affiliates.
*/
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/libfdt.h>
#include <linux/pgtable.h>
#include <asm/image.h>
#include <asm/soc.h>

/*
Expand All @@ -26,3 +28,23 @@ void __init soc_early_init(void)
}
}
}

static void __init thead_init(void)
{
__riscv_custom_pte.cache = 0x7000000000000000;
__riscv_custom_pte.mask = 0xf800000000000000;
__riscv_custom_pte.io = BIT(63);
__riscv_custom_pte.wc = 0;
}

void __init soc_setup_vm(void)
{
unsigned long vendor_id =
((struct riscv_image_header *)(&_start))->res1;

switch (vendor_id) {
case THEAD_VENDOR_ID:
thead_init();
break;
}
};
4 changes: 4 additions & 0 deletions arch/riscv/mm/init.c
Expand Up @@ -612,6 +612,7 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
{
pmd_t __maybe_unused fix_bmap_spmd, fix_bmap_epmd;

soc_setup_vm();
setup_protection_map();

kernel_map.virt_addr = KERNEL_LINK_ADDR;
Expand Down Expand Up @@ -876,3 +877,6 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
return vmemmap_populate_basepages(start, end, node, NULL);
}
#endif

struct riscv_custom_pte __riscv_custom_pte __ro_after_init;
EXPORT_SYMBOL(__riscv_custom_pte);

0 comments on commit c1bc61c

Please sign in to comment.