Currently the armv7 pmap does something fairly retarded.  When you ask
for a non-cachable mapping of sorts, it first creates a cachable
mapping, and then frobs the pte to make it uncachable.  With the
speculative tricks that modern ARM CPUs have up their sleeve, that is
not such a good idea.

The diff below fixes this by introducing a PMAP_NOCACHE flags like we
have on many other architectures.  This can be or'ed into the pa to
ask for a non-cachable mapping of normal memory.  It also adds a
PMAP_DEVICE flag to map device memory, which is what you're supposed
to use to map device registers.  Note that previously we mapped *all*
non-cachable memory as device memory.  When you pass PMAP_NOCACHE, the
new code also takes care of flushing and invalidating the data cache.

That last part overlaps with the previous diff I sent.  I'll resolve
the conflict when either of the diffs get commited.

ok?


Index: include/pmap.h
===================================================================
RCS file: /cvs/src/sys/arch/arm/include/pmap.h,v
retrieving revision 1.40
diff -u -p -r1.40 pmap.h
--- include/pmap.h      22 Mar 2016 23:35:01 -0000      1.40
+++ include/pmap.h      7 Aug 2016 20:55:09 -0000
@@ -181,6 +181,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
  * addresses of various pages
Index: arm/pmap7.c
===================================================================
RCS file: /cvs/src/sys/arch/arm/arm/pmap7.c,v
retrieving revision 1.33
diff -u -p -r1.33 pmap7.c
--- arm/pmap7.c 6 Aug 2016 16:46:25 -0000       1.33
+++ arm/pmap7.c 7 Aug 2016 20:55:09 -0000
@@ -931,30 +931,6 @@ pmap_l2ptp_ctor(void *v)
 }
 
 /*
- * 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();
-}
-
-/*
  * Modify pte bits for all ptes corresponding to the given physical address.
  * We use `maskbits' rather than `clearbits' because we're always passing
  * constants and the latter would require an extra inversion at run-time.
@@ -1562,6 +1538,7 @@ pmap_kenter_pa(vaddr_t va, paddr_t pa, v
 {
        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",
@@ -1580,22 +1557,32 @@ pmap_kenter_pa(vaddr_t va, paddr_t pa, v
        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

Reply via email to