Module Name: src
Committed By: martin
Date: Fri Dec 29 20:21:40 UTC 2023
Modified Files:
src/sys/arch/powerpc/include [netbsd-10]: pmap.h vmparam.h
src/sys/arch/powerpc/include/oea [netbsd-10]: pmap.h
src/sys/arch/powerpc/oea [netbsd-10]: pmap.c pmap_kernel.c
src/sys/arch/powerpc/powerpc [netbsd-10]: bus_dma.c trap.c vm_machdep.c
Log Message:
Additionally pull up following revision(s) (requested by rin in ticket #400):
sys/arch/powerpc/include/oea/pmap.h: revision 1.39
sys/arch/powerpc/include/pmap.h: revision 1.43
sys/arch/powerpc/oea/pmap_kernel.c: revision 1.14
sys/arch/powerpc/oea/pmap.c: revision 1.117
sys/arch/powerpc/oea/pmap.c: revision 1.118
sys/arch/powerpc/oea/pmap.c: revision 1.119
sys/arch/powerpc/include/vmparam.h: revision 1.27
sys/arch/powerpc/powerpc/trap.c: revision 1.165
sys/arch/powerpc/oea/pmap.c: revision 1.120
sys/arch/powerpc/oea/pmap.c: revision 1.121
sys/arch/powerpc/powerpc/vm_machdep.c: revision 1.106
sys/arch/powerpc/powerpc/bus_dma.c: revision 1.56
powerpc/oea: trap: pmap_{pte,ste}_spill() even in the interrupt context
Page table for oea is something like L2 TLB on memory; kernel and
processes share its entries, and process entries can be spilled out.
As done for MMU based on software-managed TLB, we need to restore
such entries even in the interrupt context.
Note that pmap_pte_spill() require no resouce to restore entries.
Still-not-implemented pmap_ste_spill() for OEA64 should also.
Part of PR kern/57621
powerpc/oea: pmap: Drop unused argument for pmap_pvo_reclaim(), NFC
Part of PR kern/57621
powerpc/oea: pmap: Rework pmap_pte_spill()
It was broken in many ways... Now, it gets working stable both for
OEA and OEA64_BRIDGE, as far as I can see.
Part of PR kern/57621
powerpc/oea: pmap: Fix mostly-pointless overhead of pmap_pvo_pool
(1) Drop __aligned(32) from struct pvo_entry; otherwise,
sizeof(struct pvo_entry) is round-up'ed to a multiple of 32.
(2) Do not set sizeof(struct pvo_entry) to `align` argument for
pool_init(9); it must be power of 2.
(3) Align pvo_entry to 32-byte boundary only if reasonably possible,
i.e., OEA without DIAGNOSTIC (--> POOL_REDZONE) for now.
Part of PR kern/57621
powerpc/oea: pmap_create: Use PR_ZERO and drop memset(9), NFC
Part of PR kern/57621
powerpc: oea: For OEA64_BRIDGE, 1:1 map up to 3GiB memory
As done for OEA. Note that kva over 3GiB is reserved.
Provide PMAP_MAP_POOLPAGE for OEA64_BRIDGE at the same time, by
which direct-mapped memory is utilized in order to work around
starvation of 512MiB kernel virtual space.
PR kern/57621
powerpc: Make sure direct-mapped buffer fits within correct range
For OEA and OEA64_BRIDGE, only first 3GiB memory is direct-mapped.
Part of PR kern/57621
To generate a diff of this commit:
cvs rdiff -u -r1.42 -r1.42.4.1 src/sys/arch/powerpc/include/pmap.h
cvs rdiff -u -r1.26 -r1.26.4.1 src/sys/arch/powerpc/include/vmparam.h
cvs rdiff -u -r1.37 -r1.37.4.1 src/sys/arch/powerpc/include/oea/pmap.h
cvs rdiff -u -r1.114.4.1 -r1.114.4.2 src/sys/arch/powerpc/oea/pmap.c
cvs rdiff -u -r1.13 -r1.13.4.1 src/sys/arch/powerpc/oea/pmap_kernel.c
cvs rdiff -u -r1.55 -r1.55.4.1 src/sys/arch/powerpc/powerpc/bus_dma.c
cvs rdiff -u -r1.163 -r1.163.20.1 src/sys/arch/powerpc/powerpc/trap.c
cvs rdiff -u -r1.105 -r1.105.2.1 src/sys/arch/powerpc/powerpc/vm_machdep.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/powerpc/include/pmap.h
diff -u src/sys/arch/powerpc/include/pmap.h:1.42 src/sys/arch/powerpc/include/pmap.h:1.42.4.1
--- src/sys/arch/powerpc/include/pmap.h:1.42 Sat May 7 07:10:46 2022
+++ src/sys/arch/powerpc/include/pmap.h Fri Dec 29 20:21:39 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.h,v 1.42 2022/05/07 07:10:46 rin Exp $ */
+/* $NetBSD: pmap.h,v 1.42.4.1 2023/12/29 20:21:39 martin Exp $ */
#ifndef _POWERPC_PMAP_H_
#define _POWERPC_PMAP_H_
@@ -20,6 +20,10 @@
#error unknown PPC variant
#endif
+#ifndef PMAP_DIRECT_MAPPED_LEN
+#define PMAP_DIRECT_MAPPED_LEN (~0UL)
+#endif
+
#endif /* !_MODULE */
#if !defined(_LOCORE) && (defined(MODULAR) || defined(_MODULE))
Index: src/sys/arch/powerpc/include/vmparam.h
diff -u src/sys/arch/powerpc/include/vmparam.h:1.26 src/sys/arch/powerpc/include/vmparam.h:1.26.4.1
--- src/sys/arch/powerpc/include/vmparam.h:1.26 Wed May 11 13:58:43 2022
+++ src/sys/arch/powerpc/include/vmparam.h Fri Dec 29 20:21:39 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: vmparam.h,v 1.26 2022/05/11 13:58:43 andvar Exp $ */
+/* $NetBSD: vmparam.h,v 1.26.4.1 2023/12/29 20:21:39 martin Exp $ */
#ifndef _POWERPC_VMPARAM_H_
#define _POWERPC_VMPARAM_H_
@@ -12,7 +12,7 @@
* These are common for BOOKE, IBM4XX, and OEA
*/
#define VM_FREELIST_DEFAULT 0
-#define VM_FREELIST_FIRST256 1
+#define VM_FREELIST_DIRECT_MAPPED 1
#define VM_FREELIST_FIRST16 2
#define VM_NFREELIST 3
Index: src/sys/arch/powerpc/include/oea/pmap.h
diff -u src/sys/arch/powerpc/include/oea/pmap.h:1.37 src/sys/arch/powerpc/include/oea/pmap.h:1.37.4.1
--- src/sys/arch/powerpc/include/oea/pmap.h:1.37 Sat May 7 07:10:46 2022
+++ src/sys/arch/powerpc/include/oea/pmap.h Fri Dec 29 20:21:39 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.h,v 1.37 2022/05/07 07:10:46 rin Exp $ */
+/* $NetBSD: pmap.h,v 1.37.4.1 2023/12/29 20:21:39 martin Exp $ */
/*-
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -121,6 +121,16 @@ __BEGIN_DECLS
#include <sys/param.h>
#include <sys/systm.h>
+/*
+ * For OEA and OEA64_BRIDGE, we guarantee that pa below USER_ADDR
+ * (== 3GB < VM_MIN_KERNEL_ADDRESS) is direct-mapped.
+ */
+#if defined(PPC_OEA) || defined(PPC_OEA64_BRIDGE)
+#define PMAP_DIRECT_MAPPED_SR (USER_SR - 1)
+#define PMAP_DIRECT_MAPPED_LEN \
+ ((vaddr_t)SEGMENT_LENGTH * (PMAP_DIRECT_MAPPED_SR + 1))
+#endif
+
#if defined (PPC_OEA) || defined (PPC_OEA64_BRIDGE)
extern register_t iosrtable[];
#endif
@@ -186,10 +196,13 @@ static __inline paddr_t vtophys (vaddr_t
* VA==PA all at once. But pmap_copy_page() and pmap_zero_page() will have
* this problem, too.
*/
-#if !defined(PPC_OEA64) && !defined (PPC_OEA64_BRIDGE)
+#if !defined(PPC_OEA64)
#define PMAP_MAP_POOLPAGE(pa) (pa)
#define PMAP_UNMAP_POOLPAGE(pa) (pa)
#define POOL_VTOPHYS(va) vtophys((vaddr_t) va)
+
+#define PMAP_ALLOC_POOLPAGE(flags) pmap_alloc_poolpage(flags)
+struct vm_page *pmap_alloc_poolpage(int);
#endif
static __inline paddr_t
Index: src/sys/arch/powerpc/oea/pmap.c
diff -u src/sys/arch/powerpc/oea/pmap.c:1.114.4.1 src/sys/arch/powerpc/oea/pmap.c:1.114.4.2
--- src/sys/arch/powerpc/oea/pmap.c:1.114.4.1 Mon Oct 9 13:36:58 2023
+++ src/sys/arch/powerpc/oea/pmap.c Fri Dec 29 20:21:40 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.c,v 1.114.4.1 2023/10/09 13:36:58 martin Exp $ */
+/* $NetBSD: pmap.c,v 1.114.4.2 2023/12/29 20:21:40 martin Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -63,7 +63,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.114.4.1 2023/10/09 13:36:58 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.114.4.2 2023/12/29 20:21:40 martin Exp $");
#define PMAP_NOOPNAMES
@@ -292,7 +292,7 @@ const struct pmap_ops PMAPNAME(ops) = {
#endif /* !PMAPNAME */
/*
- * The following structure is aligned to 32 bytes
+ * The following structure is aligned to 32 bytes, if reasonably possible.
*/
struct pvo_entry {
LIST_ENTRY(pvo_entry) pvo_vlink; /* Link to common virt page */
@@ -317,7 +317,14 @@ struct pvo_entry {
#define PVO_REMOVE 6 /* PVO has been removed */
#define PVO_WHERE_MASK 15
#define PVO_WHERE_SHFT 8
-} __attribute__ ((aligned (32)));
+};
+
+#if defined(PMAP_OEA) && !defined(DIAGNOSTIC)
+#define PMAP_PVO_ENTRY_ALIGN 32
+#else
+#define PMAP_PVO_ENTRY_ALIGN __alignof(struct pvo_entry)
+#endif
+
#define PVO_VADDR(pvo) ((pvo)->pvo_vaddr & ~ADDR_POFF)
#define PVO_PTEGIDX_GET(pvo) ((pvo)->pvo_vaddr & PVO_PTEGIDX_MASK)
#define PVO_PTEGIDX_ISSET(pvo) ((pvo)->pvo_vaddr & PVO_PTEGIDX_VALID)
@@ -335,18 +342,6 @@ struct pvo_tqhead *pmap_pvo_table; /* pv
struct pool pmap_pool; /* pool for pmap structures */
struct pool pmap_pvo_pool; /* pool for pvo entries */
-/*
- * We keep a cache of unmanaged pages to be used for pvo entries for
- * unmanaged pages.
- */
-struct pvo_page {
- SIMPLEQ_ENTRY(pvo_page) pvop_link;
-};
-SIMPLEQ_HEAD(pvop_head, pvo_page);
-static struct pvop_head pmap_pvop_head = SIMPLEQ_HEAD_INITIALIZER(pmap_pvop_head);
-static u_long pmap_pvop_free;
-static u_long pmap_pvop_maxfree;
-
static void *pmap_pool_alloc(struct pool *, int);
static void pmap_pool_free(struct pool *, void *);
@@ -388,7 +383,7 @@ static void pmap_pvo_free(struct pvo_ent
static void pmap_pvo_free_list(struct pvo_head *);
static struct pvo_entry *pmap_pvo_find_va(pmap_t, vaddr_t, int *);
static volatile struct pte *pmap_pvo_to_pte(const struct pvo_entry *, int);
-static struct pvo_entry *pmap_pvo_reclaim(struct pmap *);
+static struct pvo_entry *pmap_pvo_reclaim(void);
static void pvo_set_exec(struct pvo_entry *);
static void pvo_clear_exec(struct pvo_entry *);
@@ -879,48 +874,35 @@ pmap_pte_insert(int ptegidx, struct pte
* Tries to spill a page table entry from the overflow area.
* This runs in either real mode (if dealing with a exception spill)
* or virtual mode when dealing with manually spilling one of the
- * kernel's pte entries. In either case, interrupts are already
- * disabled.
+ * kernel's pte entries.
*/
int
-pmap_pte_spill(struct pmap *pm, vaddr_t addr, bool exec)
+pmap_pte_spill(struct pmap *pm, vaddr_t addr, bool isi_p)
{
- struct pvo_entry *source_pvo, *victim_pvo, *next_pvo;
- struct pvo_entry *pvo;
- /* XXX: gcc -- vpvoh is always set at either *1* or *2* */
- struct pvo_tqhead *pvoh, *vpvoh = NULL;
- int ptegidx, i, j;
+ struct pvo_tqhead *spvoh, *vpvoh;
+ struct pvo_entry *pvo, *source_pvo, *victim_pvo;
volatile struct pteg *pteg;
volatile struct pte *pt;
+ register_t msr, vsid, hash;
+ int ptegidx, hid, i, j;
+ int done = 0;
PMAP_LOCK();
+ msr = pmap_interrupts_off();
+
+ /* XXXRO paranoid? */
+ if (pm->pm_evictions == 0)
+ goto out;
ptegidx = va_to_pteg(pm, addr);
/*
- * Have to substitute some entry. Use the primary hash for this.
- * Use low bits of timebase as random generator. Make sure we are
- * not picking a kernel pte for replacement.
+ * Find source pvo.
*/
- pteg = &pmap_pteg_table[ptegidx];
- i = MFTB() & 7;
- for (j = 0; j < 8; j++) {
- pt = &pteg->pt[i];
- if ((pt->pte_hi & PTE_VALID) == 0)
- break;
- if (VSID_TO_HASH((pt->pte_hi & PTE_VSID) >> PTE_VSID_SHFT)
- < PHYSMAP_VSIDBITS)
- break;
- i = (i + 1) & 7;
- }
- KASSERT(j < 8);
-
+ spvoh = &pmap_pvo_table[ptegidx];
source_pvo = NULL;
- victim_pvo = NULL;
- pvoh = &pmap_pvo_table[ptegidx];
- TAILQ_FOREACH(pvo, pvoh, pvo_olink) {
-
+ TAILQ_FOREACH(pvo, spvoh, pvo_olink) {
/*
* We need to find pvo entry for this address...
*/
@@ -931,101 +913,105 @@ pmap_pte_spill(struct pmap *pm, vaddr_t
* a valid PTE, then we know we can't find it because all
* evicted PVOs always are first in the list.
*/
- if (source_pvo == NULL && (pvo->pvo_pte.pte_hi & PTE_VALID))
+ if ((pvo->pvo_pte.pte_hi & PTE_VALID) != 0)
break;
- if (source_pvo == NULL && pm == pvo->pvo_pmap &&
- addr == PVO_VADDR(pvo)) {
- /*
- * Now we have found the entry to be spilled into the
- * pteg. Attempt to insert it into the page table.
- */
- j = pmap_pte_insert(ptegidx, &pvo->pvo_pte);
- if (j >= 0) {
- PVO_PTEGIDX_SET(pvo, j);
- PMAP_PVO_CHECK(pvo); /* sanity check */
- PVO_WHERE(pvo, SPILL_INSERT);
- pvo->pvo_pmap->pm_evictions--;
- PMAPCOUNT(ptes_spilled);
- PMAPCOUNT2(((pvo->pvo_pte.pte_hi & PTE_HID)
- ? pmap_evcnt_ptes_secondary
- : pmap_evcnt_ptes_primary)[j]);
-
- /*
- * Since we keep the evicted entries at the
- * from of the PVO list, we need move this
- * (now resident) PVO after the evicted
- * entries.
- */
- next_pvo = TAILQ_NEXT(pvo, pvo_olink);
-
- /*
- * If we don't have to move (either we were the
- * last entry or the next entry was valid),
- * don't change our position. Otherwise
- * move ourselves to the tail of the queue.
- */
- if (next_pvo != NULL &&
- !(next_pvo->pvo_pte.pte_hi & PTE_VALID)) {
- TAILQ_REMOVE(pvoh, pvo, pvo_olink);
- TAILQ_INSERT_TAIL(pvoh, pvo, pvo_olink);
- }
- PMAP_UNLOCK();
- return 1;
+ if (pm == pvo->pvo_pmap && addr == PVO_VADDR(pvo)) {
+ if (isi_p) {
+ if (!PVO_EXECUTABLE_P(pvo))
+ goto out;
+#if defined(PMAP_OEA) || defined(PMAP_OEA64_BRIDGE)
+ int sr __diagused =
+ PVO_VADDR(pvo) >> ADDR_SR_SHFT;
+ KASSERT((pm->pm_sr[sr] & SR_NOEXEC) == 0);
+#endif
}
+ KASSERT(!PVO_PTEGIDX_ISSET(pvo));
+ /* XXXRO where check */
source_pvo = pvo;
- if (exec && !PVO_EXECUTABLE_P(source_pvo)) {
- PMAP_UNLOCK();
- return 0;
- }
- if (victim_pvo != NULL)
- break;
- }
-
- /*
- * We also need the pvo entry of the victim we are replacing
- * so save the R & C bits of the PTE.
- */
- if ((pt->pte_hi & PTE_HID) == 0 && victim_pvo == NULL &&
- pmap_pte_compare(pt, &pvo->pvo_pte)) {
- vpvoh = pvoh; /* *1* */
- victim_pvo = pvo;
- if (source_pvo != NULL)
- break;
+ break;
}
}
-
if (source_pvo == NULL) {
PMAPCOUNT(ptes_unspilled);
- PMAP_UNLOCK();
- return 0;
+ goto out;
}
- if (victim_pvo == NULL) {
- if ((pt->pte_hi & PTE_HID) == 0)
- panic("pmap_pte_spill: victim p-pte (%p) has "
- "no pvo entry!", pt);
+ /*
+ * Now we have found the entry to be spilled into the
+ * pteg. Attempt to insert it into the page table.
+ */
+ i = pmap_pte_insert(ptegidx, &pvo->pvo_pte);
+ if (i >= 0) {
+ PVO_PTEGIDX_SET(pvo, i);
+ PMAP_PVO_CHECK(pvo); /* sanity check */
+ PVO_WHERE(pvo, SPILL_INSERT);
+ pvo->pvo_pmap->pm_evictions--;
+ PMAPCOUNT(ptes_spilled);
+ PMAPCOUNT2(((pvo->pvo_pte.pte_hi & PTE_HID) != 0
+ ? pmap_evcnt_ptes_secondary
+ : pmap_evcnt_ptes_primary)[i]);
- /*
- * If this is a secondary PTE, we need to search
- * its primary pvo bucket for the matching PVO.
- */
- vpvoh = &pmap_pvo_table[ptegidx ^ pmap_pteg_mask]; /* *2* */
- TAILQ_FOREACH(pvo, vpvoh, pvo_olink) {
- PMAP_PVO_CHECK(pvo); /* sanity check */
+ TAILQ_REMOVE(spvoh, pvo, pvo_olink);
+ TAILQ_INSERT_TAIL(spvoh, pvo, pvo_olink);
- /*
- * We also need the pvo entry of the victim we are
- * replacing so save the R & C bits of the PTE.
- */
- if (pmap_pte_compare(pt, &pvo->pvo_pte)) {
- victim_pvo = pvo;
- break;
- }
+ done = 1;
+ goto out;
+ }
+
+ /*
+ * Have to substitute some entry. Use the primary hash for this.
+ * Use low bits of timebase as random generator.
+ *
+ * XXX:
+ * Make sure we are not picking a kernel pte for replacement.
+ */
+ hid = 0;
+ i = MFTB() & 7;
+ pteg = &pmap_pteg_table[ptegidx];
+ retry:
+ for (j = 0; j < 8; j++, i = (i + 1) & 7) {
+ pt = &pteg->pt[i];
+
+ if ((pt->pte_hi & PTE_VALID) == 0)
+ break;
+
+ vsid = (pt->pte_hi & PTE_VSID) >> PTE_VSID_SHFT;
+ hash = VSID_TO_HASH(vsid);
+ if (hash < PHYSMAP_VSIDBITS)
+ break;
+ }
+ if (j == 8) {
+ if (hid != 0)
+ panic("%s: no victim\n", __func__);
+ hid = PTE_HID;
+ pteg = &pmap_pteg_table[ptegidx ^ pmap_pteg_mask];
+ goto retry;
+ }
+
+ /*
+ * We also need the pvo entry of the victim we are replacing
+ * so save the R & C bits of the PTE.
+ */
+ if ((pt->pte_hi & PTE_HID) == hid)
+ vpvoh = spvoh;
+ else
+ vpvoh = &pmap_pvo_table[ptegidx ^ pmap_pteg_mask];
+ victim_pvo = NULL;
+ TAILQ_FOREACH(pvo, vpvoh, pvo_olink) {
+ PMAP_PVO_CHECK(pvo); /* sanity check */
+
+ if ((pvo->pvo_pte.pte_hi & PTE_VALID) == 0)
+ continue;
+
+ if (pmap_pte_compare(pt, &pvo->pvo_pte)) {
+ victim_pvo = pvo;
+ break;
}
- if (victim_pvo == NULL)
- panic("pmap_pte_spill: victim s-pte (%p) has "
- "no pvo entry!", pt);
+ }
+ if (victim_pvo == NULL) {
+ panic("%s: victim p-pte (%p) has no pvo entry!",
+ __func__, pt);
}
/*
@@ -1041,7 +1027,10 @@ pmap_pte_spill(struct pmap *pm, vaddr_t
* we lose any ref/chg bit changes contained in the TLB
* entry.
*/
- source_pvo->pvo_pte.pte_hi &= ~PTE_HID;
+ if (hid == 0)
+ source_pvo->pvo_pte.pte_hi &= ~PTE_HID;
+ else
+ source_pvo->pvo_pte.pte_hi |= PTE_HID;
/*
* To enforce the PVO list ordering constraint that all
@@ -1050,8 +1039,8 @@ pmap_pte_spill(struct pmap *pm, vaddr_t
* victim PVO to the head of its list (which might not be
* the same list, if the victim was using the secondary hash).
*/
- TAILQ_REMOVE(pvoh, source_pvo, pvo_olink);
- TAILQ_INSERT_TAIL(pvoh, source_pvo, pvo_olink);
+ TAILQ_REMOVE(spvoh, source_pvo, pvo_olink);
+ TAILQ_INSERT_TAIL(spvoh, source_pvo, pvo_olink);
TAILQ_REMOVE(vpvoh, victim_pvo, pvo_olink);
TAILQ_INSERT_HEAD(vpvoh, victim_pvo, pvo_olink);
pmap_pte_unset(pt, &victim_pvo->pvo_pte, victim_pvo->pvo_vaddr);
@@ -1071,8 +1060,12 @@ pmap_pte_spill(struct pmap *pm, vaddr_t
PMAP_PVO_CHECK(victim_pvo);
PMAP_PVO_CHECK(source_pvo);
+ done = 1;
+
+ out:
+ pmap_interrupts_restore(msr);
PMAP_UNLOCK();
- return 1;
+ return done;
}
/*
@@ -1131,9 +1124,8 @@ pmap_create(void)
{
pmap_t pm;
- pm = pool_get(&pmap_pool, PR_WAITOK);
- KASSERT((vaddr_t)pm < VM_MIN_KERNEL_ADDRESS);
- memset((void *)pm, 0, sizeof *pm);
+ pm = pool_get(&pmap_pool, PR_WAITOK | PR_ZERO);
+ KASSERT((vaddr_t)pm < PMAP_DIRECT_MAPPED_LEN);
pmap_pinit(pm);
DPRINTFN(CREATE, "pmap_create: pm %p:\n"
@@ -1377,7 +1369,7 @@ pmap_pvo_find_va(pmap_t pm, vaddr_t va,
TAILQ_FOREACH(pvo, &pmap_pvo_table[ptegidx], pvo_olink) {
#if defined(DIAGNOSTIC) || defined(DEBUG) || defined(PMAPCHECK)
- if ((uintptr_t) pvo >= SEGMENT_LENGTH)
+ if ((uintptr_t) pvo >= PMAP_DIRECT_MAPPED_LEN)
panic("pmap_pvo_find_va: invalid pvo %p on "
"list %#x (%p)", pvo, ptegidx,
&pmap_pvo_table[ptegidx]);
@@ -1388,7 +1380,7 @@ pmap_pvo_find_va(pmap_t pm, vaddr_t va,
return pvo;
}
}
- if ((pm == pmap_kernel()) && (va < SEGMENT_LENGTH))
+ if ((pm == pmap_kernel()) && (va < PMAP_DIRECT_MAPPED_LEN))
panic("%s: returning NULL for %s pmap, va: %#" _PRIxva "\n",
__func__, (pm == pmap_kernel() ? "kernel" : "user"), va);
return NULL;
@@ -1405,23 +1397,23 @@ pmap_pvo_check(const struct pvo_entry *p
PMAP_LOCK();
- if ((uintptr_t)(pvo+1) >= SEGMENT_LENGTH)
+ if ((uintptr_t)(pvo+1) >= PMAP_DIRECT_MAPPED_LEN)
panic("pmap_pvo_check: pvo %p: invalid address", pvo);
- if ((uintptr_t)(pvo->pvo_pmap+1) >= SEGMENT_LENGTH) {
+ if ((uintptr_t)(pvo->pvo_pmap+1) >= PMAP_DIRECT_MAPPED_LEN) {
printf("pmap_pvo_check: pvo %p: invalid pmap address %p\n",
pvo, pvo->pvo_pmap);
failed = 1;
}
- if ((uintptr_t)TAILQ_NEXT(pvo, pvo_olink) >= SEGMENT_LENGTH ||
+ if ((uintptr_t)TAILQ_NEXT(pvo, pvo_olink) >= PMAP_DIRECT_MAPPED_LEN ||
(((uintptr_t)TAILQ_NEXT(pvo, pvo_olink)) & 0x1f) != 0) {
printf("pmap_pvo_check: pvo %p: invalid ovlink address %p\n",
pvo, TAILQ_NEXT(pvo, pvo_olink));
failed = 1;
}
- if ((uintptr_t)LIST_NEXT(pvo, pvo_vlink) >= SEGMENT_LENGTH ||
+ if ((uintptr_t)LIST_NEXT(pvo, pvo_vlink) >= PMAP_DIRECT_MAPPED_LEN ||
(((uintptr_t)LIST_NEXT(pvo, pvo_vlink)) & 0x1f) != 0) {
printf("pmap_pvo_check: pvo %p: invalid ovlink address %p\n",
pvo, LIST_NEXT(pvo, pvo_vlink));
@@ -1507,7 +1499,7 @@ pmap_pvo_check(const struct pvo_entry *p
*/
struct pvo_entry *
-pmap_pvo_reclaim(struct pmap *pm)
+pmap_pvo_reclaim(void)
{
struct pvo_tqhead *pvoh;
struct pvo_entry *pvo;
@@ -1615,7 +1607,7 @@ pmap_pvo_enter(pmap_t pm, struct pool *p
++pmap_pvo_enter_depth;
#endif
if (pvo == NULL) {
- pvo = pmap_pvo_reclaim(pm);
+ pvo = pmap_pvo_reclaim();
if (pvo == NULL) {
if ((flags & PMAP_CANFAIL) == 0)
panic("pmap_pvo_enter: failed");
@@ -2173,7 +2165,7 @@ pmap_extract(pmap_t pm, vaddr_t va, padd
* We still check the HTAB...
*/
#elif defined(PMAP_OEA64_BRIDGE)
- if (va < SEGMENT_LENGTH) {
+ if (va < PMAP_DIRECT_MAPPED_LEN) {
if (pap)
*pap = va;
PMAP_UNLOCK();
@@ -2842,7 +2834,7 @@ pmap_pvo_verify(void)
for (ptegidx = 0; ptegidx < pmap_pteg_cnt; ptegidx++) {
struct pvo_entry *pvo;
TAILQ_FOREACH(pvo, &pmap_pvo_table[ptegidx], pvo_olink) {
- if ((uintptr_t) pvo >= SEGMENT_LENGTH)
+ if ((uintptr_t) pvo >= PMAP_DIRECT_MAPPED_LEN)
panic("pmap_pvo_verify: invalid pvo %p "
"on list %#x", pvo, ptegidx);
pmap_pvo_check(pvo);
@@ -2852,61 +2844,89 @@ pmap_pvo_verify(void)
}
#endif /* PMAPCHECK */
+/*
+ * Queue for unmanaged pages, used before uvm.page_init_done.
+ * Reuse when pool shortage; see pmap_pool_alloc() below.
+ */
+struct pup {
+ SIMPLEQ_ENTRY(pup) pup_link;
+};
+SIMPLEQ_HEAD(pup_head, pup);
+static struct pup_head pup_head = SIMPLEQ_HEAD_INITIALIZER(pup_head);
+
+static struct pup *
+pmap_alloc_unmanaged(void)
+{
+ struct pup *pup;
+ register_t msr;
+
+ PMAP_LOCK();
+ msr = pmap_interrupts_off();
+ pup = SIMPLEQ_FIRST(&pup_head);
+ if (pup != NULL)
+ SIMPLEQ_REMOVE_HEAD(&pup_head, pup_link);
+ pmap_interrupts_restore(msr);
+ PMAP_UNLOCK();
+ return pup;
+}
+
+static void
+pmap_free_unmanaged(struct pup *pup)
+{
+ register_t msr;
+
+ PMAP_LOCK();
+ msr = pmap_interrupts_off();
+ SIMPLEQ_INSERT_HEAD(&pup_head, pup, pup_link);
+ pmap_interrupts_restore(msr);
+ PMAP_UNLOCK();
+}
+
void *
pmap_pool_alloc(struct pool *pp, int flags)
{
- struct pvo_page *pvop;
struct vm_page *pg;
+ paddr_t pa;
- if (uvm.page_init_done != true) {
- return (void *) uvm_pageboot_alloc(PAGE_SIZE);
- }
+ if (__predict_false(!uvm.page_init_done))
+ return (void *)uvm_pageboot_alloc(PAGE_SIZE);
- PMAP_LOCK();
- pvop = SIMPLEQ_FIRST(&pmap_pvop_head);
- if (pvop != NULL) {
- pmap_pvop_free--;
- SIMPLEQ_REMOVE_HEAD(&pmap_pvop_head, pvop_link);
- PMAP_UNLOCK();
- return pvop;
- }
- PMAP_UNLOCK();
- again:
- pg = uvm_pagealloc_strat(NULL, 0, NULL, UVM_PGA_USERESERVE,
- UVM_PGA_STRAT_ONLY, VM_FREELIST_FIRST256);
+ retry:
+ pg = uvm_pagealloc_strat(NULL /*obj*/, 0 /*off*/, NULL /*anon*/,
+ UVM_PGA_USERESERVE /*flags*/, UVM_PGA_STRAT_ONLY /*strat*/,
+ VM_FREELIST_DIRECT_MAPPED /*free_list*/);
if (__predict_false(pg == NULL)) {
- if (flags & PR_WAITOK) {
- uvm_wait("plpg");
- goto again;
- } else {
- return (0);
- }
+ void *va = pmap_alloc_unmanaged();
+ if (va != NULL)
+ return va;
+
+ if ((flags & PR_WAITOK) == 0)
+ return NULL;
+ uvm_wait("plpg");
+ goto retry;
}
KDASSERT(VM_PAGE_TO_PHYS(pg) == (uintptr_t)VM_PAGE_TO_PHYS(pg));
- return (void *)(uintptr_t) VM_PAGE_TO_PHYS(pg);
+ pa = VM_PAGE_TO_PHYS(pg);
+ return (void *)(uintptr_t)pa;
}
void
pmap_pool_free(struct pool *pp, void *va)
{
- struct pvo_page *pvop;
+ struct vm_page *pg;
- PMAP_LOCK();
- pvop = va;
- SIMPLEQ_INSERT_HEAD(&pmap_pvop_head, pvop, pvop_link);
- pmap_pvop_free++;
- if (pmap_pvop_free > pmap_pvop_maxfree)
- pmap_pvop_maxfree = pmap_pvop_free;
- PMAP_UNLOCK();
-#if 0
- uvm_pagefree(PHYS_TO_VM_PAGE((paddr_t) va));
-#endif
+ pg = PHYS_TO_VM_PAGE((paddr_t)va);
+ if (__predict_false(pg == NULL)) {
+ pmap_free_unmanaged(va);
+ return;
+ }
+ uvm_pagefree(pg);
}
/*
* This routine in bootstraping to steal to-be-managed memory (which will
- * then be unmanaged). We use it to grab from the first 256MB for our
- * pmap needs and above 256MB for other stuff.
+ * then be unmanaged). We use it to grab from the first PMAP_DIRECT_MAPPED_LEN
+ * for our pmap needs and above it for other stuff.
*/
vaddr_t
pmap_steal_memory(vsize_t vsize, vaddr_t *vstartp, vaddr_t *vendp)
@@ -2939,7 +2959,7 @@ pmap_steal_memory(vsize_t vsize, vaddr_t
start = uvm_physseg_get_start(bank);
end = uvm_physseg_get_end(bank);
- if (freelist == VM_FREELIST_FIRST256 &&
+ if (freelist == VM_FREELIST_DIRECT_MAPPED &&
(end - start) >= npgs) {
pa = ptoa(start);
break;
@@ -3328,8 +3348,8 @@ pmap_bootstrap1(paddr_t kernelstart, pad
#if defined(DIAGNOSTIC) || defined(DEBUG) || defined(PMAPCHECK)
- if ( (uintptr_t) pmap_pteg_table + size > SEGMENT_LENGTH)
- panic("pmap_bootstrap: pmap_pteg_table end (%p + %#" _PRIxpa ") > 256MB",
+ if ( (uintptr_t) pmap_pteg_table + size > PMAP_DIRECT_MAPPED_LEN)
+ panic("pmap_bootstrap: pmap_pteg_table end (%p + %#" _PRIxpa ") > PMAP_DIRECT_MAPPED_LEN",
pmap_pteg_table, size);
#endif
@@ -3344,8 +3364,8 @@ pmap_bootstrap1(paddr_t kernelstart, pad
size = sizeof(pmap_pvo_table[0]) * pmap_pteg_cnt;
pmap_pvo_table = (void *)(uintptr_t) pmap_boot_find_memory(size, PAGE_SIZE, 0);
#if defined(DIAGNOSTIC) || defined(DEBUG) || defined(PMAPCHECK)
- if ( (uintptr_t) pmap_pvo_table + size > SEGMENT_LENGTH)
- panic("pmap_bootstrap: pmap_pvo_table end (%p + %#" _PRIxpa ") > 256MB",
+ if ( (uintptr_t) pmap_pvo_table + size > PMAP_DIRECT_MAPPED_LEN)
+ panic("pmap_bootstrap: pmap_pvo_table end (%p + %#" _PRIxpa ") > PMAP_DIRECT_MAPPED_LEN",
pmap_pvo_table, size);
#endif
@@ -3364,17 +3384,17 @@ pmap_bootstrap1(paddr_t kernelstart, pad
paddr_t pfend = atop(mp->start + mp->size);
if (mp->size == 0)
continue;
- if (mp->start + mp->size <= SEGMENT_LENGTH) {
+ if (mp->start + mp->size <= PMAP_DIRECT_MAPPED_LEN) {
uvm_page_physload(pfstart, pfend, pfstart, pfend,
- VM_FREELIST_FIRST256);
- } else if (mp->start >= SEGMENT_LENGTH) {
+ VM_FREELIST_DIRECT_MAPPED);
+ } else if (mp->start >= PMAP_DIRECT_MAPPED_LEN) {
uvm_page_physload(pfstart, pfend, pfstart, pfend,
VM_FREELIST_DEFAULT);
} else {
- pfend = atop(SEGMENT_LENGTH);
+ pfend = atop(PMAP_DIRECT_MAPPED_LEN);
uvm_page_physload(pfstart, pfend, pfstart, pfend,
- VM_FREELIST_FIRST256);
- pfstart = atop(SEGMENT_LENGTH);
+ VM_FREELIST_DIRECT_MAPPED);
+ pfstart = atop(PMAP_DIRECT_MAPPED_LEN);
pfend = atop(mp->start + mp->size);
uvm_page_physload(pfstart, pfend, pfstart, pfend,
VM_FREELIST_DEFAULT);
@@ -3442,14 +3462,40 @@ pmap_bootstrap1(paddr_t kernelstart, pad
#endif
pool_init(&pmap_pvo_pool, sizeof(struct pvo_entry),
- sizeof(struct pvo_entry), 0, 0, "pmap_pvopl",
+ PMAP_PVO_ENTRY_ALIGN, 0, 0, "pmap_pvopl",
&pmap_pool_allocator, IPL_VM);
pool_setlowat(&pmap_pvo_pool, 1008);
pool_init(&pmap_pool, sizeof(struct pmap),
- sizeof(void *), 0, 0, "pmap_pl", &pool_allocator_nointr,
- IPL_NONE);
+ __alignof(struct pmap), 0, 0, "pmap_pl",
+ &pmap_pool_allocator, IPL_NONE);
+
+#if defined(PMAP_OEA64_BRIDGE)
+ {
+ struct pmap *pm = pmap_kernel();
+ uvm_physseg_t bank;
+ paddr_t pa;
+ struct pte pt;
+ unsigned int ptegidx;
+
+ for (bank = uvm_physseg_get_first();
+ uvm_physseg_valid_p(bank);
+ bank = uvm_physseg_get_next(bank)) {
+ if (uvm_physseg_get_free_list(bank) !=
+ VM_FREELIST_DIRECT_MAPPED)
+ continue;
+ for (pa = uimax(ptoa(uvm_physseg_get_avail_start(bank)),
+ SEGMENT_LENGTH);
+ pa < ptoa(uvm_physseg_get_avail_end(bank));
+ pa += PAGE_SIZE) {
+ ptegidx = va_to_pteg(pm, pa);
+ pmap_pte_create(&pt, pm, pa, pa | PTE_M);
+ pmap_pte_insert(ptegidx, &pt);
+ }
+ }
+ }
+#endif
#if defined(PMAP_NEED_MAPKERNEL)
{
Index: src/sys/arch/powerpc/oea/pmap_kernel.c
diff -u src/sys/arch/powerpc/oea/pmap_kernel.c:1.13 src/sys/arch/powerpc/oea/pmap_kernel.c:1.13.4.1
--- src/sys/arch/powerpc/oea/pmap_kernel.c:1.13 Wed Feb 16 23:31:13 2022
+++ src/sys/arch/powerpc/oea/pmap_kernel.c Fri Dec 29 20:21:40 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap_kernel.c,v 1.13 2022/02/16 23:31:13 riastradh Exp $ */
+/* $NetBSD: pmap_kernel.c,v 1.13.4.1 2023/12/29 20:21:40 martin Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -30,7 +30,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: pmap_kernel.c,v 1.13 2022/02/16 23:31:13 riastradh Exp $");
+__KERNEL_RCSID(1, "$NetBSD: pmap_kernel.c,v 1.13.4.1 2023/12/29 20:21:40 martin Exp $");
#ifdef _KERNEL_OPT
#include "opt_altivec.h"
@@ -39,7 +39,9 @@ __KERNEL_RCSID(1, "$NetBSD: pmap_kernel.
#endif
#include <sys/param.h>
+#include <uvm/uvm.h>
#include <uvm/uvm_extern.h>
+#include <uvm/uvm_page.h>
#ifdef ALTIVEC
int pmap_use_altivec;
@@ -63,6 +65,25 @@ powerpc_mmap_flags(paddr_t pa)
return flags;
}
+struct vm_page *
+pmap_alloc_poolpage(int flags)
+{
+
+ if (__predict_false(!uvm.page_init_done)) {
+ struct vm_page *pg;
+ paddr_t pa __diagused;
+
+ pg = uvm_pagealloc(NULL, 0, NULL, flags);
+ KASSERT(pg != NULL);
+ pa = VM_PAGE_TO_PHYS(pg);
+ KASSERT(pa < PMAP_DIRECT_MAPPED_LEN);
+ return pg;
+ }
+
+ return uvm_pagealloc_strat(NULL, 0, NULL, flags, UVM_PGA_STRAT_ONLY,
+ VM_FREELIST_DIRECT_MAPPED);
+}
+
#ifdef PMAP_NEEDS_FIXUP
#include <powerpc/instr.h>
Index: src/sys/arch/powerpc/powerpc/bus_dma.c
diff -u src/sys/arch/powerpc/powerpc/bus_dma.c:1.55 src/sys/arch/powerpc/powerpc/bus_dma.c:1.55.4.1
--- src/sys/arch/powerpc/powerpc/bus_dma.c:1.55 Tue Jul 26 20:08:56 2022
+++ src/sys/arch/powerpc/powerpc/bus_dma.c Fri Dec 29 20:21:40 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: bus_dma.c,v 1.55 2022/07/26 20:08:56 andvar Exp $ */
+/* $NetBSD: bus_dma.c,v 1.55.4.1 2023/12/29 20:21:40 martin Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
@@ -33,7 +33,7 @@
#define _POWERPC_BUS_DMA_PRIVATE
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.55 2022/07/26 20:08:56 andvar Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.55.4.1 2023/12/29 20:21:40 martin Exp $");
#ifdef _KERNEL_OPT
#include "opt_ppcarch.h"
@@ -707,8 +707,10 @@ _bus_dmamem_map(bus_dma_tag_t t, bus_dma
if (nsegs == 1 && (flags & BUS_DMA_DONTCACHE) == 0) {
KASSERT(size == segs->ds_len);
addr = BUS_MEM_TO_PHYS(t, segs->ds_addr);
- *kvap = (void *)PMAP_MAP_POOLPAGE(addr);
- return 0;
+ if (__predict_true(addr + size < PMAP_DIRECT_MAPPED_LEN)) {
+ *kvap = (void *)PMAP_MAP_POOLPAGE(addr);
+ return 0;
+ }
}
#endif
Index: src/sys/arch/powerpc/powerpc/trap.c
diff -u src/sys/arch/powerpc/powerpc/trap.c:1.163 src/sys/arch/powerpc/powerpc/trap.c:1.163.20.1
--- src/sys/arch/powerpc/powerpc/trap.c:1.163 Wed Jul 15 08:58:52 2020
+++ src/sys/arch/powerpc/powerpc/trap.c Fri Dec 29 20:21:40 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.163 2020/07/15 08:58:52 rin Exp $ */
+/* $NetBSD: trap.c,v 1.163.20.1 2023/12/29 20:21:40 martin Exp $ */
/*
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -35,7 +35,7 @@
#define __UCAS_PRIVATE
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.163 2020/07/15 08:58:52 rin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.163.20.1 2023/12/29 20:21:40 martin Exp $");
#ifdef _KERNEL_OPT
#include "opt_altivec.h"
@@ -137,42 +137,40 @@ trap(struct trapframe *tf)
ci->ci_ev_kdsi.ev_count++;
- /*
- * Only query UVM if no interrupts are active.
- */
- if (ci->ci_idepth < 0) {
- if ((va >> ADDR_SR_SHFT) == pcb->pcb_kmapsr) {
- va &= ADDR_PIDX | ADDR_POFF;
- va |= pcb->pcb_umapsr << ADDR_SR_SHFT;
- map = &p->p_vmspace->vm_map;
-#ifdef PPC_OEA64
- if ((tf->tf_dsisr & DSISR_NOTFOUND) &&
- vm_map_pmap(map)->pm_ste_evictions > 0 &&
- pmap_ste_spill(vm_map_pmap(map),
- trunc_page(va), false)) {
- return;
- }
+ if ((va >> ADDR_SR_SHFT) == pcb->pcb_kmapsr) {
+ va &= ADDR_PIDX | ADDR_POFF;
+ va |= pcb->pcb_umapsr << ADDR_SR_SHFT;
+ map = &p->p_vmspace->vm_map;
+ }
+#if defined(DIAGNOSTIC) && !defined(PPC_OEA64)
+ else if (__predict_false((va >> ADDR_SR_SHFT) == USER_SR)) {
+ printf("trap: kernel %s DSI trap @ %#lx by %#lx"
+ " (DSISR %#x): USER_SR unset\n",
+ (tf->tf_dsisr & DSISR_STORE)
+ ? "write" : "read",
+ va, tf->tf_srr0, tf->tf_dsisr);
+ goto brain_damage2;
+ }
#endif
+ else {
+ map = kernel_map;
+ }
- if ((tf->tf_dsisr & DSISR_NOTFOUND) &&
- vm_map_pmap(map)->pm_evictions > 0 &&
- pmap_pte_spill(vm_map_pmap(map),
- trunc_page(va), false)) {
- return;
- }
-#if defined(DIAGNOSTIC) && !defined(PPC_OEA64)
- } else if ((va >> ADDR_SR_SHFT) == USER_SR) {
- printf("trap: kernel %s DSI trap @ %#lx by %#lx"
- " (DSISR %#x): USER_SR unset\n",
- (tf->tf_dsisr & DSISR_STORE)
- ? "write" : "read",
- va, tf->tf_srr0, tf->tf_dsisr);
- goto brain_damage2;
+#ifdef PPC_OEA64
+ if ((tf->tf_dsisr & DSISR_NOTFOUND) &&
+ vm_map_pmap(map)->pm_ste_evictions > 0 &&
+ pmap_ste_spill(vm_map_pmap(map), trunc_page(va), false))
+ return;
#endif
- } else {
- map = kernel_map;
- }
+ if ((tf->tf_dsisr & DSISR_NOTFOUND) &&
+ vm_map_pmap(map)->pm_evictions > 0 &&
+ pmap_pte_spill(vm_map_pmap(map), trunc_page(va), false))
+ return;
+ /*
+ * Only query UVM if no interrupts are active.
+ */
+ if (ci->ci_idepth < 0) {
if (tf->tf_dsisr & DSISR_STORE)
ftype = VM_PROT_WRITE;
else
Index: src/sys/arch/powerpc/powerpc/vm_machdep.c
diff -u src/sys/arch/powerpc/powerpc/vm_machdep.c:1.105 src/sys/arch/powerpc/powerpc/vm_machdep.c:1.105.2.1
--- src/sys/arch/powerpc/powerpc/vm_machdep.c:1.105 Mon Dec 5 16:01:03 2022
+++ src/sys/arch/powerpc/powerpc/vm_machdep.c Fri Dec 29 20:21:40 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: vm_machdep.c,v 1.105 2022/12/05 16:01:03 martin Exp $ */
+/* $NetBSD: vm_machdep.c,v 1.105.2.1 2023/12/29 20:21:40 martin Exp $ */
/*
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.105 2022/12/05 16:01:03 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.105.2.1 2023/12/29 20:21:40 martin Exp $");
#ifdef _KERNEL_OPT
#include "opt_altivec.h"
@@ -322,7 +322,8 @@ cpu_uarea_alloc(bool system)
* Allocate a new physically contiguous uarea which can be
* direct-mapped.
*/
- error = uvm_pglistalloc(USPACE, 0, ~0UL, 0, 0, &pglist, 1, 1);
+ error = uvm_pglistalloc(USPACE, 0, PMAP_DIRECT_MAPPED_LEN, 0, 0,
+ &pglist, 1, 1);
if (error) {
return NULL;
}