Commit 93c22703 authored by Paul Mackerras's avatar Paul Mackerras Committed by Benjamin Herrenschmidt

powerpc: Dynamically allocate most lppaca structs

This arranges for the lppaca structs for most cpus to be dynamically
allocated in the same manner as the paca structs.  If we don't include
support for legacy iSeries, only the first lppaca is statically
allocated; the rest are dynamically allocated.  If we include legacy
iSeries support, then we statically allocate the first 64 lppaca
structs, since the iSeries hypervisor requires that the lppaca
structs be present in the data section of the kernel image, but
legacy iSeries supports at most 64 cpus.

With CONFIG_NR_CPUS, the kernel image size for a typical pSeries config
went from:

   text    data     bss     dec     hex filename
9524478 4734564 8469944 22728986        15ad11a ../test-1024/vmlinux

to:

   text    data     bss     dec     hex filename
9524482 3751508 8469944 21745934        14bd10e ../test-1024/vmlinux

a reduction of 983052 bytes overall.
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 8154c5d2
...@@ -153,7 +153,7 @@ struct lppaca { ...@@ -153,7 +153,7 @@ struct lppaca {
extern struct lppaca lppaca[]; extern struct lppaca lppaca[];
#define lppaca_of(cpu) (lppaca[cpu]) #define lppaca_of(cpu) (*paca[cpu].lppaca_ptr)
/* /*
* SLB shadow buffer structure as defined in the PAPR. The save_area * SLB shadow buffer structure as defined in the PAPR. The save_area
......
...@@ -26,6 +26,20 @@ extern unsigned long __toc_start; ...@@ -26,6 +26,20 @@ extern unsigned long __toc_start;
#ifdef CONFIG_PPC_BOOK3S #ifdef CONFIG_PPC_BOOK3S
/*
* We only have to have statically allocated lppaca structs on
* legacy iSeries, which supports at most 64 cpus.
*/
#ifdef CONFIG_PPC_ISERIES
#if NR_CPUS < 64
#define NR_LPPACAS NR_CPUS
#else
#define NR_LPPACAS 64
#endif
#else /* not iSeries */
#define NR_LPPACAS 1
#endif
/* /*
* The structure which the hypervisor knows about - this structure * The structure which the hypervisor knows about - this structure
* should not cross a page boundary. The vpa_init/register_vpa call * should not cross a page boundary. The vpa_init/register_vpa call
...@@ -36,7 +50,7 @@ extern unsigned long __toc_start; ...@@ -36,7 +50,7 @@ extern unsigned long __toc_start;
* will suffice to ensure that it doesn't cross a page boundary. * will suffice to ensure that it doesn't cross a page boundary.
*/ */
struct lppaca lppaca[] = { struct lppaca lppaca[] = {
[0 ... (NR_CPUS-1)] = { [0 ... (NR_LPPACAS-1)] = {
.desc = 0xd397d781, /* "LpPa" */ .desc = 0xd397d781, /* "LpPa" */
.size = sizeof(struct lppaca), .size = sizeof(struct lppaca),
.dyn_proc_status = 2, .dyn_proc_status = 2,
...@@ -49,6 +63,54 @@ struct lppaca lppaca[] = { ...@@ -49,6 +63,54 @@ struct lppaca lppaca[] = {
}, },
}; };
static struct lppaca *extra_lppacas;
static long __initdata lppaca_size;
static void allocate_lppacas(int nr_cpus, unsigned long limit)
{
if (nr_cpus <= NR_LPPACAS)
return;
lppaca_size = PAGE_ALIGN(sizeof(struct lppaca) *
(nr_cpus - NR_LPPACAS));
extra_lppacas = __va(memblock_alloc_base(lppaca_size,
PAGE_SIZE, limit));
}
static struct lppaca *new_lppaca(int cpu)
{
struct lppaca *lp;
if (cpu < NR_LPPACAS)
return &lppaca[cpu];
lp = extra_lppacas + (cpu - NR_LPPACAS);
*lp = lppaca[0];
return lp;
}
static void free_lppacas(void)
{
long new_size = 0, nr;
if (!lppaca_size)
return;
nr = num_possible_cpus() - NR_LPPACAS;
if (nr > 0)
new_size = PAGE_ALIGN(nr * sizeof(struct lppaca));
if (new_size >= lppaca_size)
return;
memblock_free(__pa(extra_lppacas) + new_size, lppaca_size - new_size);
lppaca_size = new_size;
}
#else
static inline void allocate_lppacas(int, unsigned long) { }
static inline void free_lppacas(void) { }
#endif /* CONFIG_PPC_BOOK3S */ #endif /* CONFIG_PPC_BOOK3S */
#ifdef CONFIG_PPC_STD_MMU_64 #ifdef CONFIG_PPC_STD_MMU_64
...@@ -88,7 +150,7 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu) ...@@ -88,7 +150,7 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu)
unsigned long kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL; unsigned long kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL;
#ifdef CONFIG_PPC_BOOK3S #ifdef CONFIG_PPC_BOOK3S
new_paca->lppaca_ptr = &lppaca[cpu]; new_paca->lppaca_ptr = new_lppaca(cpu);
#else #else
new_paca->kernel_pgd = swapper_pg_dir; new_paca->kernel_pgd = swapper_pg_dir;
#endif #endif
...@@ -144,6 +206,8 @@ void __init allocate_pacas(void) ...@@ -144,6 +206,8 @@ void __init allocate_pacas(void)
printk(KERN_DEBUG "Allocated %u bytes for %d pacas at %p\n", printk(KERN_DEBUG "Allocated %u bytes for %d pacas at %p\n",
paca_size, nr_cpus, paca); paca_size, nr_cpus, paca);
allocate_lppacas(nr_cpus, limit);
/* Can't use for_each_*_cpu, as they aren't functional yet */ /* Can't use for_each_*_cpu, as they aren't functional yet */
for (cpu = 0; cpu < nr_cpus; cpu++) for (cpu = 0; cpu < nr_cpus; cpu++)
initialise_paca(&paca[cpu], cpu); initialise_paca(&paca[cpu], cpu);
...@@ -164,4 +228,6 @@ void __init free_unused_pacas(void) ...@@ -164,4 +228,6 @@ void __init free_unused_pacas(void)
paca_size - new_size); paca_size - new_size);
paca_size = new_size; paca_size = new_size;
free_lppacas();
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment