RFC: Dynamic segment table allocation

David Gibson david at gibson.dropbear.id.au
Fri Jul 2 13:58:49 EST 2004


On Fri, Jul 02, 2004 at 12:45:51PM +1000, Anton Blanchard wrote:
>
> > Ah... good point.
> >
> > I can see two ways around that:  allocate the tables from bootmem
> > sufficiently low, or bolt into each table an STE for itself.  Paulus
> > says he prefers the former option, so I'll look at doing that.
>
> irqstack_early_init is doing a similar thing for irq stacks, it would be
> worth consolidating the dynamic segment table allocation code with this.

Yes, noticed thats.

> Also it would be worth working with Nathan Lynch to calculate
> smp_possible_cpus earlier at boot so that irqstack_early_init doesnt
> allocate NR_CPUS worth of stacks all the time.

Erm.. as far as I can tell smp_possible_cpus is already early enough
for the call to irqstack_early_init().  The patch below uses it for
the stabs allocation immediately after the call to
irqstack_early_init()...

PPC64 machines before Power4 need a segment table page allocated for
each CPU.  Currently these are allocated statically in a big array in
head.S for all CPUs.  The segment tables need to be in the first
segment (so do_stab_bolted doesn't take a recursive fault on the stab
itself), but other than that there are no constraints which require
the stabs for the secondary CPUs to be statically allocated.

This patch allocates segment tables dynamically during boot, using
lmb_alloc() to ensure they are within the first 256M segment.  This
reduces the kernel image size by 192k...

Signed-off-by: David Gibson <david at gibson.dropbear.id.au>

Index: working-2.6/arch/ppc64/kernel/head.S
===================================================================
--- working-2.6.orig/arch/ppc64/kernel/head.S
+++ working-2.6/arch/ppc64/kernel/head.S
@@ -2201,11 +2201,6 @@
 ioremap_dir:
 	.space	4096

-/* 1 page segment table per cpu (max 48, cpu0 allocated at STAB0_PHYS_ADDR) */
-	.globl	stab_array
-stab_array:
-	.space	4096 * 48
-
 /*
  * This space gets a copy of optional info passed to us by the bootstrap
  * Used to pass parameters into the kernel like root=/dev/sda1, etc.
Index: working-2.6/arch/ppc64/kernel/smp.c
===================================================================
--- working-2.6.orig/arch/ppc64/kernel/smp.c
+++ working-2.6/arch/ppc64/kernel/smp.c
@@ -876,19 +876,6 @@
 	paca[cpu].prof_multiplier = 1;
 	paca[cpu].default_decr = tb_ticks_per_jiffy / decr_overclock;

-	if (!(cur_cpu_spec->cpu_features & CPU_FTR_SLB)) {
-		void *tmp;
-
-		/* maximum of 48 CPUs on machines with a segment table */
-		if (cpu >= 48)
-			BUG();
-
-		tmp = &stab_array[PAGE_SIZE * cpu];
-		memset(tmp, 0, PAGE_SIZE);
-		paca[cpu].stab_addr = (unsigned long)tmp;
-		paca[cpu].stab_real = virt_to_abs(tmp);
-	}
-
 	/* The information for processor bringup must
 	 * be written out to main store before we release
 	 * the processor.
Index: working-2.6/arch/ppc64/kernel/setup.c
===================================================================
--- working-2.6.orig/arch/ppc64/kernel/setup.c
+++ working-2.6/arch/ppc64/kernel/setup.c
@@ -76,6 +76,7 @@
 extern void pseries_secondary_smp_init(unsigned long);
 extern int  idle_setup(void);
 extern void vpa_init(int cpu);
+void stabs_alloc(void);

 unsigned long decr_overclock = 1;
 unsigned long decr_overclock_proc0 = 1;
@@ -639,6 +640,7 @@
 	*cmdline_p = cmd_line;

 	irqstack_early_init();
+	stabs_alloc();

 	/* set up the bootmem stuff with available memory */
 	do_init_bootmem();
Index: working-2.6/arch/ppc64/kernel/stab.c
===================================================================
--- working-2.6.orig/arch/ppc64/kernel/stab.c
+++ working-2.6/arch/ppc64/kernel/stab.c
@@ -19,6 +19,8 @@
 #include <asm/paca.h>
 #include <asm/naca.h>
 #include <asm/cputable.h>
+#include <asm/lmb.h>
+#include <asm/abs_addr.h>

 static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid);
 static void make_slbe(unsigned long esid, unsigned long vsid, int large,
@@ -41,6 +43,34 @@
 #endif
 }

+/* Allocate segment tables for secondary CPUs.  These must all go in
+ * the first (bolted) segment, so that do_stab_bolted won't get a
+ * segment miss on the segment table itself. */
+void stabs_alloc(void)
+{
+	int cpu;
+
+	if (cur_cpu_spec->cpu_features & CPU_FTR_SLB)
+		return;
+
+	for_each_cpu(cpu) {
+		unsigned long newstab;
+
+		if (cpu == 0)
+			continue; /* stab for CPU 0 is statically allocated */
+
+		newstab = lmb_alloc_base(PAGE_SIZE, PAGE_SIZE, 1<<SID_SHIFT);
+		if (! newstab)
+			panic("Unable to allocate segment table for CPU %d.\n", cpu);
+
+		newstab += KERNELBASE;
+
+		paca[cpu].stab_addr = newstab;
+		paca[cpu].stab_real = virt_to_abs(newstab);
+		printk(KERN_DEBUG "Segment table for CPU %d at 0x%lx virtual, 0x%lx absolute\n", cpu, paca[cpu].stab_addr, paca[cpu].stab_real);
+	}
+}
+
 /*
  * Build an entry for the base kernel segment and put it into
  * the segment table or SLB.  All other segment table or SLB


--
David Gibson			| For every complex problem there is a
david AT gibson.dropbear.id.au	| solution which is simple, neat and
				| wrong.
http://www.ozlabs.org/people/dgibson

** Sent via the linuxppc64-dev mail list. See http://lists.linuxppc.org/





More information about the Linuxppc64-dev mailing list