git: 9faeaac936ae - main - powerpc/pmap: Use variable-sized TID

From: Justin Hibbits <jhibbits_at_FreeBSD.org>
Date: Sun, 21 Jun 2026 22:07:04 UTC
The branch main has been updated by jhibbits:

URL: https://cgit.FreeBSD.org/src/commit/?id=9faeaac936aea78f9b5ce1a8ad3d27e2632d4e37

commit 9faeaac936aea78f9b5ce1a8ad3d27e2632d4e37
Author:     Justin Hibbits <jhibbits@FreeBSD.org>
AuthorDate: 2025-12-17 03:20:55 +0000
Commit:     Justin Hibbits <jhibbits@FreeBSD.org>
CommitDate: 2026-06-21 21:24:03 +0000

    powerpc/pmap: Use variable-sized TID
    
    e6500 core supports 14-bit TIDs (16384), while all earlier cores support
    only 8 bit TIDs.  Dynamically allocate the tidbusy array at bootstrap
    time so that it stays in the TLB1, but is sized appropriately for the
    core.  With MAXCPU of 32, a e6500 tidbusy would be (8 * 32 * 16384), or
    4MB for this array, while e5500 would use (8 * 32 * 256), or 64kB.
---
 sys/powerpc/booke/pmap.c  | 52 ++++++++++++++++++++++++++++++++++++++++-------
 sys/powerpc/include/spr.h |  2 ++
 2 files changed, 47 insertions(+), 7 deletions(-)

diff --git a/sys/powerpc/booke/pmap.c b/sys/powerpc/booke/pmap.c
index 625d57940c01..310d38d5c450 100644
--- a/sys/powerpc/booke/pmap.c
+++ b/sys/powerpc/booke/pmap.c
@@ -87,6 +87,7 @@
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/kerneldump.h>
+#include <sys/limits.h>
 #include <sys/linker.h>
 #include <sys/msgbuf.h>
 #include <sys/lock.h>
@@ -204,8 +205,10 @@ extern int elf32_nxstack;
 /* TLB and TID handling */
 /**************************************************************************/
 
-/* Translation ID busy table */
-static volatile pmap_t tidbusy[MAXCPU][TID_MAX + 1];
+/* Translation ID busy table (dynamically allocated) */
+static __inline void tid_set_busy(int cpu, int tid, pmap_t pmap);
+static volatile pmap_t *tidbusy;
+uint32_t tid_max;
 
 /*
  * TLB0 capabilities (entry, way numbers etc.). These can vary between e500
@@ -637,6 +640,7 @@ mmu_booke_bootstrap(vm_offset_t start, vm_offset_t kernelend)
 	vm_size_t kstack0_sz;
 	vm_paddr_t kstack0_phys;
 	vm_offset_t kstack0;
+	uint32_t tid_bits;
 	void *dpcpu;
 
 	debugf("mmu_booke_bootstrap: entered\n");
@@ -660,6 +664,18 @@ mmu_booke_bootstrap(vm_offset_t start, vm_offset_t kernelend)
 	/* Read TLB0 size and associativity. */
 	tlb0_get_tlbconf();
 
+	/*
+	 * Calculate the max TID from the hardware.  Allow overriding with a
+	 * tunable.  The tunable should be a power of 2.
+	 */
+	tid_bits = ((mfspr(SPR_MMUCFG) & MMUCFG_PIDSIZE_M) >> MMUCFG_PIDSIZE_S);
+	TUNABLE_INT_FETCH("machdep.tid_max", &tid_max);
+	if (tid_max <= 0)
+		tid_max = INT_MAX;
+	else
+		tid_max = 1 << ilog2(tid_max);
+	tid_max = min((1 << tid_bits), tid_max) - 1;
+
 	/*
 	 * Align kernel start and end address (kernel image).
 	 * Note that kernel end does not necessarily relate to kernsize.
@@ -668,6 +684,11 @@ mmu_booke_bootstrap(vm_offset_t start, vm_offset_t kernelend)
 	data_start = round_page(kernelend);
 	data_end = data_start;
 
+	tidbusy = (void *)data_end;
+	printf("tidbusy at %p\n", tidbusy);
+	printf("tidmax = %d\n", tid_max);
+	data_end += round_page(sizeof(pmap_t) * MAXCPU * (tid_max + 1));
+
 	/* Allocate the dynamic per-cpu area. */
 	dpcpu = (void *)data_end;
 	data_end += DPCPU_SIZE;
@@ -913,7 +934,7 @@ mmu_booke_bootstrap(vm_offset_t start, vm_offset_t kernelend)
 		kernel_pmap->pm_tid[i] = TID_KERNEL;
 		
 		/* Initialize each CPU's tidbusy entry 0 with kernel_pmap */
-		tidbusy[i][TID_KERNEL] = kernel_pmap;
+		tid_set_busy(i, TID_KERNEL, kernel_pmap);
 	}
 
 	/* Mark kernel_pmap active on all CPUs */
@@ -2460,6 +2481,22 @@ mmu_booke_page_array_startup(long pages)
 /* TID handling */
 /**************************************************************************/
 
+static __inline void
+tid_set_busy(int cpu, int tid, pmap_t pmap)
+{
+	tidbusy[cpu * (tid_max + 1) + tid] = pmap;
+	if (pmap == NULL)
+		pmap->pm_tid[cpu] = TID_NONE;
+	else
+		pmap->pm_tid[cpu] = tid;
+}
+
+static __inline pmap_t
+tid_get_busy(int cpu, int tid)
+{
+	return (tidbusy[cpu * (tid_max + 1) + tid]);
+}
+
 /*
  * Allocate a TID. If necessary, steal one from someone else.
  * The new TID is flushed from the TLB before returning.
@@ -2477,21 +2514,22 @@ tid_alloc(pmap_t pmap)
 	thiscpu = PCPU_GET(cpuid);
 
 	tid = PCPU_GET(booke.tid_next);
-	if (tid > TID_MAX)
+	/* tid_max is always a power-of-2-minus-1, so check for overflow. */
+	if ((tid & ~tid_max) != 0)
 		tid = TID_MIN;
 	PCPU_SET(booke.tid_next, tid + 1);
 
 	/* If we are stealing TID then clear the relevant pmap's field */
-	if (tidbusy[thiscpu][tid] != NULL) {
+	if (tid_get_busy(thiscpu, tid) != NULL) {
 		CTR2(KTR_PMAP, "%s: warning: stealing tid %d", __func__, tid);
 		
-		tidbusy[thiscpu][tid]->pm_tid[thiscpu] = TID_NONE;
+		tid_set_busy(thiscpu, tid, NULL);
 
 		/* Flush all entries from TLB0 matching this TID. */
 		tid_flush(tid);
 	}
 
-	tidbusy[thiscpu][tid] = pmap;
+	tid_set_busy(thiscpu, tid, pmap);
 	pmap->pm_tid[thiscpu] = tid;
 	__asm __volatile("msync; isync");
 
diff --git a/sys/powerpc/include/spr.h b/sys/powerpc/include/spr.h
index afa1692bed75..40911a7c293d 100644
--- a/sys/powerpc/include/spr.h
+++ b/sys/powerpc/include/spr.h
@@ -868,6 +868,8 @@
 #define	  BUCSR_BBFI		0x00000200	/* Branch Buffer Flash Invalidate */
 
 #define	SPR_MMUCFG		0x3f7	/* ..8 MMU Configuration Register */
+#define	  MMUCFG_LPIDSIZE_M	  0x0F000000
+#define	  MMUCFG_LPIDSIZE_S	  24
 #define	  MMUCFG_PIDSIZE_M	  0x000007c0
 #define	  MMUCFG_PIDSIZE_S	  6
 #define	  MMUCFG_MAVN_M		  0x00000003