Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F105773661
D8894.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D8894.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D8894: Implement pmap_change_attr and related APIs on MIPS
Attached
Detach File
Event Timeline
Log In to Comment