Mapping non-cachable memory as cachable and subsequently changing the mapping
authorkettenis <kettenis@openbsd.org>
Mon, 8 Aug 2016 14:47:52 +0000 (14:47 +0000)
committerkettenis <kettenis@openbsd.org>
Mon, 8 Aug 2016 14:47:52 +0000 (14:47 +0000)
to non-cachable is retarded.  Fix this by introducing PMAP_NOCACHE and
PMAP_DEVICE flags that can be or'ed into the physical address passed to
pmap_kenter(9), like we have on many of our other architectures.  This way we
can also properly distinguish between device memory and normal (non-cachable)
memory.

ok visa@

sys/arch/arm/arm/pmap7.c
sys/arch/arm/armv7/armv7_space.c
sys/arch/arm/include/pmap.h

index e0631ef..a283779 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pmap7.c,v 1.34 2016/08/08 09:06:47 kettenis Exp $     */
+/*     $OpenBSD: pmap7.c,v 1.35 2016/08/08 14:47:52 kettenis Exp $     */
 /*     $NetBSD: pmap.c,v 1.147 2004/01/18 13:03:50 scw Exp $   */
 
 /*
@@ -927,33 +927,6 @@ pmap_l2ptp_ctor(void *v)
        PTE_SYNC_RANGE(v, L2_TABLE_SIZE_REAL / sizeof(pt_entry_t));
 }
 
-/*
- * Make a pmap_kernel() mapping uncached. Used by bus_dma for coherent pages.
- */
-void
-pmap_uncache_page(paddr_t va, vaddr_t pa)
-{
-       struct vm_page *pg;
-       struct pv_entry *pv;
-       pt_entry_t *pte;
-
-       if ((pg = PHYS_TO_VM_PAGE(pa)) != NULL) {
-               pv = pmap_find_pv(pg, pmap_kernel(), va);
-               if (pv != NULL)
-                       pv->pv_flags |= PVF_NC; /* XXX ought to be pg attr */
-       }
-
-       pte = vtopte(va);
-       *pte &= ~L2_S_CACHE_MASK;
-       *pte |= L2_B; /* device memory */
-       PTE_SYNC(pte);
-       cpu_tlb_flushD_SE(va);
-       cpu_cpwait();
-
-       cpu_dcache_wbinv_range(va, PAGE_SIZE);
-       cpu_sdcache_wbinv_range(va, pa, PAGE_SIZE);
-}
-
 /*
  * Modify pte bits for all ptes corresponding to the given physical address.
  * We use `maskbits' rather than `clearbits' because we're always passing
@@ -1514,6 +1487,7 @@ pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot)
 {
        struct l2_bucket *l2b;
        pt_entry_t *ptep, opte, npte;
+       pt_entry_t cache_mode = pte_l2_s_cache_mode;
 
        NPDEBUG(PDB_KENTER,
            printf("pmap_kenter_pa: va 0x%08lx, pa 0x%08lx, prot 0x%x\n",
@@ -1528,22 +1502,32 @@ pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot)
        if (opte == 0)
                l2b->l2b_occupancy++;
 
-       npte = L2_S_PROTO | pa | L2_S_PROT(PTE_KERNEL, prot) |
-           pte_l2_s_cache_mode;
+       if (pa & PMAP_DEVICE)
+               cache_mode = L2_B;
+       else if (pa & PMAP_NOCACHE)
+               cache_mode = L2_V7_S_TEX(1);
+
+       npte = L2_S_PROTO | (pa & PMAP_PA_MASK) |
+           L2_S_PROT(PTE_KERNEL, prot) | cache_mode;
        *ptep = npte;
        PTE_SYNC(ptep);
        if (l2pte_valid(opte)) {
                cpu_tlb_flushD_SE(va);
                cpu_cpwait();
        }
+
+       if (pa & PMAP_NOCACHE) {
+               cpu_dcache_wbinv_range(va, PAGE_SIZE);
+               cpu_sdcache_wbinv_range(va, (pa & PMAP_PA_MASK), PAGE_SIZE);
+       }
 }
 
 void
 pmap_kenter_cache(vaddr_t va, paddr_t pa, vm_prot_t prot, int cacheable)
 {
-       pmap_kenter_pa(va, pa, prot);
        if (cacheable == 0)
-               pmap_uncache_page(va, pa);
+               pa |= PMAP_NOCACHE;
+       pmap_kenter_pa(va, pa, prot);
 }
 
 void
index d615493..4f6c1e0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: armv7_space.c,v 1.7 2016/07/27 21:25:25 patrick Exp $ */
+/*     $OpenBSD: armv7_space.c,v 1.8 2016/08/08 14:47:52 kettenis Exp $ */
 
 /*
  * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
@@ -166,11 +166,11 @@ struct bus_space armv7_bs_tag = {
 
 int
 armv7_bs_map(void *t, bus_addr_t bpa, bus_size_t size,
-             int flag, bus_space_handle_t *bshp)
+             int flags, bus_space_handle_t *bshp)
 {
        u_long startpa, endpa, pa;
        vaddr_t va;
-       pt_entry_t *pte;
+       int pmap_flags = PMAP_DEVICE;
 
        startpa = trunc_page(bpa);
        endpa = round_page(bpa + size);
@@ -183,18 +183,11 @@ armv7_bs_map(void *t, bus_addr_t bpa, bus_size_t size,
 
        *bshp = (bus_space_handle_t)(va + (bpa - startpa));
 
-       for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) {
-               pmap_kenter_pa(va, pa, PROT_READ | PROT_WRITE);
-               if ((flag & BUS_SPACE_MAP_CACHEABLE) == 0) {
-                       pte = vtopte(va);
-                       *pte &= ~L2_S_CACHE_MASK;
-                       *pte |= L2_B;
-                       PTE_SYNC(pte);
-                       /* XXX: pmap_kenter_pa() also does PTE_SYNC(). a bit of
-                        *      waste.
-                        */
-               }
-       }
+       if (flags & BUS_SPACE_MAP_CACHEABLE)
+               pmap_flags = 0;
+
+       for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE)
+               pmap_kenter_pa(va, pa | pmap_flags, PROT_READ | PROT_WRITE);
        pmap_update(pmap_kernel());
 
        return(0);
index b382dc3..393b548 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pmap.h,v 1.40 2016/03/22 23:35:01 patrick Exp $       */
+/*     $OpenBSD: pmap.h,v 1.41 2016/08/08 14:47:52 kettenis Exp $      */
 /*     $NetBSD: pmap.h,v 1.76 2003/09/06 09:10:46 rearnsha Exp $       */
 
 /*
@@ -180,6 +180,13 @@ struct pmap {
 
 typedef struct pmap *pmap_t;
 
+/*
+ * MD flags that we use for pmap_enter (in the pa):
+ */
+#define PMAP_PA_MASK   ~((paddr_t)PAGE_MASK) /* to remove the flags */
+#define PMAP_NOCACHE   0x1 /* non-cacheable memory. */
+#define PMAP_DEVICE    0x2 /* device memory. */
+
 /*
  * Physical / virtual address structure. In a number of places (particularly
  * during bootstrapping) we need to keep track of the physical and virtual