Page MenuHomeFreeBSD

D8894.diff
No OneTemporary

D8894.diff

Index: head/sys/mips/include/cpuregs.h
===================================================================
--- head/sys/mips/include/cpuregs.h
+++ head/sys/mips/include/cpuregs.h
@@ -171,6 +171,10 @@
#define MIPS_CCA_CACHED MIPS_CCA_CCS
#endif
+#if defined(CPU_XBURST)
+#define MIPS_CCA_UA 0x01
+#endif
+
#ifndef MIPS_CCA_UNCACHED
#define MIPS_CCA_UNCACHED MIPS_CCA_UC
#endif
@@ -188,6 +192,16 @@
#endif
#endif
+/*
+ * Use uncached-accelerated mode for write-combining maps, if one is defined,
+ * otherwise fall back to uncached
+ */
+#ifndef MIPS_CCA_WC
+#ifdef MIPS_CCA_UA
+#define MIPS_CCA_WC MIPS_CCA_UA
+#endif
+#endif
+
#define MIPS_PHYS_TO_XKPHYS(cca,x) \
((0x2ULL << 62) | ((unsigned long long)(cca) << 59) | (x))
#define MIPS_PHYS_TO_XKPHYS_CACHED(x) \
Index: head/sys/mips/include/pmap.h
===================================================================
--- head/sys/mips/include/pmap.h
+++ head/sys/mips/include/pmap.h
@@ -74,7 +74,8 @@
};
#define PV_TABLE_REF 0x02 /* referenced */
-#define PV_MEMATTR_UNCACHEABLE 0x04
+#define PV_MEMATTR_MASK 0xf0 /* store vm_memattr_t here */
+#define PV_MEMATTR_SHIFT 0x04
#define ASID_BITS 8
#define ASIDGEN_BITS (32 - ASID_BITS)
@@ -163,22 +164,24 @@
extern vm_paddr_t dump_avail[PHYS_AVAIL_ENTRIES + 2];
-#define pmap_page_get_memattr(m) VM_MEMATTR_DEFAULT
+#define pmap_page_get_memattr(m) (((m)->md.pv_flags & PV_MEMATTR_MASK) >> PV_MEMATTR_SHIFT)
#define pmap_page_is_mapped(m) (!TAILQ_EMPTY(&(m)->md.pv_list))
#define pmap_page_is_write_mapped(m) (((m)->aflags & PGA_WRITEABLE) != 0)
void pmap_bootstrap(void);
void *pmap_mapdev(vm_paddr_t, vm_size_t);
+void *pmap_mapdev_attr(vm_paddr_t, vm_size_t, vm_memattr_t);
void pmap_unmapdev(vm_offset_t, vm_size_t);
vm_offset_t pmap_steal_memory(vm_size_t size);
void pmap_kenter(vm_offset_t va, vm_paddr_t pa);
-void pmap_kenter_attr(vm_offset_t va, vm_paddr_t pa, int attr);
+void pmap_kenter_attr(vm_offset_t va, vm_paddr_t pa, vm_memattr_t attr);
void pmap_kremove(vm_offset_t va);
void *pmap_kenter_temporary(vm_paddr_t pa, int i);
void pmap_kenter_temporary_free(vm_paddr_t pa);
void pmap_flush_pvcache(vm_page_t m);
int pmap_emulate_modified(pmap_t pmap, vm_offset_t va);
void pmap_page_set_memattr(vm_page_t, vm_memattr_t);
+int pmap_change_attr(vm_offset_t, vm_size_t, vm_memattr_t);
#endif /* _KERNEL */
Index: head/sys/mips/include/pte.h
===================================================================
--- head/sys/mips/include/pte.h
+++ head/sys/mips/include/pte.h
@@ -132,8 +132,10 @@
* it is matched.
*/
#define PTE_C(attr) ((attr & 0x07) << 3)
+#define PTE_C_MASK (PTE_C(0x07))
#define PTE_C_UNCACHED (PTE_C(MIPS_CCA_UNCACHED))
#define PTE_C_CACHE (PTE_C(MIPS_CCA_CACHED))
+#define PTE_C_WC (PTE_C(MIPS_CCA_WC))
#define PTE_D 0x04
#define PTE_V 0x02
#define PTE_G 0x01
@@ -158,6 +160,7 @@
#define pte_clear(pte, bit) (*(pte) &= ~(bit))
#define pte_set(pte, bit) (*(pte) |= (bit))
#define pte_test(pte, bit) ((*(pte) & (bit)) == (bit))
+#define pte_cache_bits(pte) ((*(pte) >> 3) & 0x07)
/* Assembly support for PTE access*/
#ifdef LOCORE
Index: head/sys/mips/include/vm.h
===================================================================
--- head/sys/mips/include/vm.h
+++ head/sys/mips/include/vm.h
@@ -32,7 +32,11 @@
#include <machine/pte.h>
/* Memory attributes. */
-#define VM_MEMATTR_UNCACHEABLE ((vm_memattr_t)PTE_C_UNCACHED)
-#define VM_MEMATTR_DEFAULT ((vm_memattr_t)PTE_C_CACHE)
+#define VM_MEMATTR_UNCACHEABLE ((vm_memattr_t)MIPS_CCA_UNCACHED)
+#define VM_MEMATTR_WRITE_BACK ((vm_memattr_t)MIPS_CCA_CACHED)
+#define VM_MEMATTR_DEFAULT VM_MEMATTR_WRITE_BACK
+#ifdef MIPS_CCA_WC
+#define VM_MEMATTR_WRITE_COMBINING ((vm_memattr_t)MIPS_CCA_WC)
+#endif
#endif /* !_MACHINE_VM_H_ */
Index: head/sys/mips/mips/pmap.c
===================================================================
--- head/sys/mips/mips/pmap.c
+++ head/sys/mips/mips/pmap.c
@@ -189,10 +189,10 @@
* The highmem area does not have a KSEG0 mapping, and we need a mechanism to
* do temporary per-CPU mappings for pmap_zero_page, pmap_copy_page etc.
*
- * At bootup, we reserve 2 virtual pages per CPU for mapping highmem pages. To
+ * At bootup, we reserve 2 virtual pages per CPU for mapping highmem pages. To
* access a highmem physical address on a CPU, we map the physical address to
- * the reserved virtual address for the CPU in the kernel pagetable. This is
- * done with interrupts disabled(although a spinlock and sched_pin would be
+ * the reserved virtual address for the CPU in the kernel pagetable. This is
+ * done with interrupts disabled(although a spinlock and sched_pin would be
* sufficient).
*/
struct local_sysmaps {
@@ -303,7 +303,7 @@
return (0);
}
-static __inline vm_offset_t
+static __inline vm_offset_t
pmap_lmem_unmap(void)
{
@@ -312,12 +312,18 @@
#endif /* !__mips_n64 */
static __inline int
-is_cacheable_page(vm_paddr_t pa, vm_page_t m)
+pmap_pte_cache_bits(vm_paddr_t pa, vm_page_t m)
{
+ vm_memattr_t ma;
- return ((m->md.pv_flags & PV_MEMATTR_UNCACHEABLE) == 0 &&
- is_cacheable_mem(pa));
-
+ ma = pmap_page_get_memattr(m);
+ if (ma == VM_MEMATTR_WRITE_BACK && !is_cacheable_mem(pa))
+ ma = VM_MEMATTR_UNCACHEABLE;
+ return PTE_C(ma);
+}
+#define PMAP_PTE_SET_CACHE_BITS(pte, ps, m) { \
+ pte &= ~PTE_C_MASK; \
+ pte |= pmap_pte_cache_bits(pa, m); \
}
/*
@@ -359,7 +365,7 @@
return (pdpe);
}
-static __inline
+static __inline
pd_entry_t *pmap_pde(pmap_t pmap, vm_offset_t va)
{
@@ -423,7 +429,7 @@
* Bootstrap the system enough to run with virtual memory. This
* assumes that the phys_avail array has been initialized.
*/
-static void
+static void
pmap_create_kernel_pagetable(void)
{
int i, j;
@@ -486,7 +492,7 @@
pmap_bootstrap(void)
{
int i;
- int need_local_mappings = 0;
+ int need_local_mappings = 0;
/* Sort. */
again:
@@ -600,7 +606,7 @@
{
TAILQ_INIT(&m->md.pv_list);
- m->md.pv_flags = 0;
+ m->md.pv_flags = VM_MEMATTR_DEFAULT << PV_MEMATTR_SHIFT;
}
/*
@@ -635,8 +641,8 @@
pmap->pm_asid[cpu].gen = 0;
}
cpuid = PCPU_GET(cpuid);
- /*
- * XXX: barrier/locking for active?
+ /*
+ * XXX: barrier/locking for active?
*
* Take a snapshot of active here, any further changes are ignored.
* tlb update/invalidate should be harmless on inactive CPUs
@@ -819,7 +825,7 @@
* add a wired page to the kva
*/
void
-pmap_kenter_attr(vm_offset_t va, vm_paddr_t pa, int attr)
+pmap_kenter_attr(vm_offset_t va, vm_paddr_t pa, vm_memattr_t ma)
{
pt_entry_t *pte;
pt_entry_t opte, npte;
@@ -830,7 +836,7 @@
pte = pmap_pte(kernel_pmap, va);
opte = *pte;
- npte = TLBLO_PA_TO_PFN(pa) | attr | PTE_D | PTE_V | PTE_G;
+ npte = TLBLO_PA_TO_PFN(pa) | PTE_C(ma) | PTE_D | PTE_V | PTE_G;
*pte = npte;
if (pte_test(&opte, PTE_V) && opte != npte)
pmap_update_page(kernel_pmap, va, npte);
@@ -843,7 +849,7 @@
KASSERT(is_cacheable_mem(pa),
("pmap_kenter: memory at 0x%lx is not cacheable", (u_long)pa));
- pmap_kenter_attr(va, pa, PTE_C_CACHE);
+ pmap_kenter_attr(va, pa, VM_MEMATTR_DEFAULT);
}
/*
@@ -1144,11 +1150,11 @@
int segindex = ptepindex >> (SEGSHIFT - PDRSHIFT);
int pdeindex = ptepindex & (NPDEPG - 1);
vm_page_t pg;
-
+
pdep = &pmap->pm_segtab[segindex];
- if (*pdep == NULL) {
+ if (*pdep == NULL) {
/* recurse for allocating page dir */
- if (_pmap_allocpte(pmap, NUPDE + segindex,
+ if (_pmap_allocpte(pmap, NUPDE + segindex,
flags) == NULL) {
/* alloc failed, release current */
--m->wire_count;
@@ -1680,7 +1686,7 @@
* pmap_remove_pte: do the things to unmap a page in a process
*/
static int
-pmap_remove_pte(struct pmap *pmap, pt_entry_t *ptq, vm_offset_t va,
+pmap_remove_pte(struct pmap *pmap, pt_entry_t *ptq, vm_offset_t va,
pd_entry_t pde)
{
pt_entry_t oldpte;
@@ -1864,7 +1870,7 @@
PMAP_LOCK(pmap);
/*
- * If it's last mapping writeback all caches from
+ * If it's last mapping writeback all caches from
* the page being destroyed
*/
if (TAILQ_NEXT(pv, pv_list) == NULL)
@@ -2030,10 +2036,7 @@
newpte |= PTE_W;
if (is_kernel_pmap(pmap))
newpte |= PTE_G;
- if (is_cacheable_page(pa, m))
- newpte |= PTE_C_CACHE;
- else
- newpte |= PTE_C_UNCACHED;
+ PMAP_PTE_SET_CACHE_BITS(newpte, pa, m);
mpte = NULL;
@@ -2218,7 +2221,7 @@
pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m,
vm_prot_t prot, vm_page_t mpte)
{
- pt_entry_t *pte;
+ pt_entry_t *pte, npte;
vm_paddr_t pa;
KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva ||
@@ -2297,18 +2300,16 @@
/*
* Now validate mapping with RO protection
*/
- *pte = PTE_RO | TLBLO_PA_TO_PFN(pa) | PTE_V;
+ npte = PTE_RO | TLBLO_PA_TO_PFN(pa) | PTE_V;
if ((m->oflags & VPO_UNMANAGED) == 0)
- *pte |= PTE_MANAGED;
+ npte |= PTE_MANAGED;
- if (is_cacheable_page(pa, m))
- *pte |= PTE_C_CACHE;
- else
- *pte |= PTE_C_UNCACHED;
+ PMAP_PTE_SET_CACHE_BITS(npte, pa, m);
if (is_kernel_pmap(pmap))
- *pte |= PTE_G;
+ *pte = npte | PTE_G;
else {
+ *pte = npte;
/*
* Sync I & D caches. Do this only if the target pmap
* belongs to the current process. Otherwise, an
@@ -2649,12 +2650,12 @@
#else
vm_paddr_t pa;
struct local_sysmaps *sysm;
- pt_entry_t *pte;
+ pt_entry_t *pte, npte;
pa = VM_PAGE_TO_PHYS(m);
if (MIPS_DIRECT_MAPPABLE(pa)) {
- if (m->md.pv_flags & PV_MEMATTR_UNCACHEABLE)
+ if (pmap_page_get_memattr(m) != VM_MEMATTR_WRITE_BACK)
return (MIPS_PHYS_TO_DIRECT_UNCACHED(pa));
else
return (MIPS_PHYS_TO_DIRECT(pa));
@@ -2665,8 +2666,9 @@
KASSERT(sysm->valid1 == 0, ("pmap_quick_enter_page: PTE busy"));
pte = pmap_pte(kernel_pmap, sysm->base);
- *pte = TLBLO_PA_TO_PFN(pa) | PTE_D | PTE_V | PTE_G |
- (is_cacheable_page(pa, m) ? PTE_C_CACHE : PTE_C_UNCACHED);
+ npte = TLBLO_PA_TO_PFN(pa) | PTE_D | PTE_V | PTE_G;
+ PMAP_PTE_SET_CACHE_BITS(npte, pa, m);
+ *pte = npte;
sysm->valid1 = 1;
return (sysm->base);
@@ -3146,26 +3148,26 @@
* Use XKPHYS uncached for 64 bit, and KSEG1 where possible for 32 bit.
*/
void *
-pmap_mapdev(vm_paddr_t pa, vm_size_t size)
+pmap_mapdev_attr(vm_paddr_t pa, vm_size_t size, vm_memattr_t ma)
{
vm_offset_t va, tmpva, offset;
- /*
- * KSEG1 maps only first 512M of phys address space. For
+ /*
+ * KSEG1 maps only first 512M of phys address space. For
* pa > 0x20000000 we should make proper mapping * using pmap_kenter.
*/
- if (MIPS_DIRECT_MAPPABLE(pa + size - 1))
+ if (MIPS_DIRECT_MAPPABLE(pa + size - 1) && ma == VM_MEMATTR_UNCACHEABLE)
return ((void *)MIPS_PHYS_TO_DIRECT_UNCACHED(pa));
else {
offset = pa & PAGE_MASK;
size = roundup(size + offset, PAGE_SIZE);
-
+
va = kva_alloc(size);
if (!va)
panic("pmap_mapdev: Couldn't alloc kernel virtual memory");
pa = trunc_page(pa);
for (tmpva = va; size > 0;) {
- pmap_kenter_attr(tmpva, pa, PTE_C_UNCACHED);
+ pmap_kenter_attr(tmpva, pa, ma);
size -= PAGE_SIZE;
tmpva += PAGE_SIZE;
pa += PAGE_SIZE;
@@ -3175,6 +3177,12 @@
return ((void *)(va + offset));
}
+void *
+pmap_mapdev(vm_paddr_t pa, vm_size_t size)
+{
+ return pmap_mapdev_attr(pa, size, VM_MEMATTR_UNCACHEABLE);
+}
+
void
pmap_unmapdev(vm_offset_t va, vm_size_t size)
{
@@ -3220,7 +3228,7 @@
* This may falsely report the given address as
* MINCORE_REFERENCED. Unfortunately, due to the lack of
* per-PTE reference information, it is impossible to
- * determine if the address is MINCORE_REFERENCED.
+ * determine if the address is MINCORE_REFERENCED.
*/
m = PHYS_TO_VM_PAGE(pa);
if ((m->aflags & PGA_REFERENCED) != 0)
@@ -3500,7 +3508,7 @@
mapped = (va >= MIPS_KSEG2_START || va < MIPS_KSEG2_END);
#if defined(__mips_n64)
mapped = mapped || (va >= MIPS_XKSEG_START || va < MIPS_XKSEG_END);
-#endif
+#endif
/*
* Kernel virtual.
*/
@@ -3524,7 +3532,7 @@
}
-void
+void
pmap_flush_pvcache(vm_page_t m)
{
pv_entry_t pv;
@@ -3551,12 +3559,85 @@
if (TAILQ_FIRST(&m->md.pv_list) != NULL)
panic("Can't change memattr on page with existing mappings");
- /*
- * The only memattr we support is UNCACHEABLE, translate the (semi-)MI
- * representation of that into our internal flag in the page MD struct.
- */
- if (ma == VM_MEMATTR_UNCACHEABLE)
- m->md.pv_flags |= PV_MEMATTR_UNCACHEABLE;
- else
- m->md.pv_flags &= ~PV_MEMATTR_UNCACHEABLE;
+ /* Clean memattr portion of pv_flags */
+ m->md.pv_flags &= ~PV_MEMATTR_MASK;
+ m->md.pv_flags |= (ma << PV_MEMATTR_SHIFT) & PV_MEMATTR_MASK;
+}
+
+static __inline void
+pmap_pte_attr(pt_entry_t *pte, vm_memattr_t ma)
+{
+ u_int npte;
+
+ npte = *(u_int *)pte;
+ npte &= ~PTE_C_MASK;
+ npte |= PTE_C(ma);
+ *pte = npte;
+}
+
+int
+pmap_change_attr(vm_offset_t sva, vm_size_t size, vm_memattr_t ma)
+{
+ pd_entry_t *pde, *pdpe;
+ pt_entry_t *pte;
+ vm_offset_t ova, eva, va, va_next;
+ pmap_t pmap;
+
+ ova = sva;
+ eva = sva + size;
+ if (eva < sva)
+ return (EINVAL);
+
+ pmap = kernel_pmap;
+ PMAP_LOCK(pmap);
+
+ for (; sva < eva; sva = va_next) {
+ pdpe = pmap_segmap(pmap, sva);
+#ifdef __mips_n64
+ if (*pdpe == 0) {
+ va_next = (sva + NBSEG) & ~SEGMASK;
+ if (va_next < sva)
+ va_next = eva;
+ continue;
+ }
+#endif
+ va_next = (sva + NBPDR) & ~PDRMASK;
+ if (va_next < sva)
+ va_next = eva;
+
+ pde = pmap_pdpe_to_pde(pdpe, sva);
+ if (*pde == NULL)
+ continue;
+
+ /*
+ * Limit our scan to either the end of the va represented
+ * by the current page table page, or to the end of the
+ * range being removed.
+ */
+ if (va_next > eva)
+ va_next = eva;
+
+ va = va_next;
+ for (pte = pmap_pde_to_pte(pde, sva); sva != va_next; pte++,
+ sva += PAGE_SIZE) {
+ if (!pte_test(pte, PTE_V) || pte_cache_bits(pte) == ma) {
+ if (va != va_next) {
+ pmap_invalidate_range(pmap, va, sva);
+ va = va_next;
+ }
+ continue;
+ }
+ if (va == va_next)
+ va = sva;
+
+ pmap_pte_attr(pte, ma);
+ }
+ if (va != va_next)
+ pmap_invalidate_range(pmap, va, sva);
+ }
+ PMAP_UNLOCK(pmap);
+
+ /* Flush caches to be in the safe side */
+ mips_dcache_wbinv_range(ova, size);
+ return 0;
}

File Metadata

Mime Type
text/plain
Expires
Sat, Dec 21, 12:27 PM (18 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15541344
Default Alt Text
D8894.diff (13 KB)

Event Timeline