aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2010-08-12 16:18:48 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-09-02 00:07:31 -0400
commit93c22703efa72c7527dbd586d1951c1f4a85fd70 (patch)
treee0da49adffc89b068645ef2c577fbebe093faf8c /arch
parent8154c5d22d91cd16bd9985b0638c8957e4688d0e (diff)
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: Paul Mackerras <paulus@samba.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/lppaca.h2
-rw-r--r--arch/powerpc/kernel/paca.c70
2 files changed, 69 insertions, 3 deletions
diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h
index 6b73554433a0..6d02624b622c 100644
--- a/arch/powerpc/include/asm/lppaca.h
+++ b/arch/powerpc/include/asm/lppaca.h
@@ -153,7 +153,7 @@ struct lppaca {
153 153
154extern struct lppaca lppaca[]; 154extern struct lppaca lppaca[];
155 155
156#define lppaca_of(cpu) (lppaca[cpu]) 156#define lppaca_of(cpu) (*paca[cpu].lppaca_ptr)
157 157
158/* 158/*
159 * SLB shadow buffer structure as defined in the PAPR. The save_area 159 * SLB shadow buffer structure as defined in the PAPR. The save_area
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index d0a26f1770fe..1e068a46e6c3 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -27,6 +27,20 @@ extern unsigned long __toc_start;
27#ifdef CONFIG_PPC_BOOK3S 27#ifdef CONFIG_PPC_BOOK3S
28 28
29/* 29/*
30 * We only have to have statically allocated lppaca structs on
31 * legacy iSeries, which supports at most 64 cpus.
32 */
33#ifdef CONFIG_PPC_ISERIES
34#if NR_CPUS < 64
35#define NR_LPPACAS NR_CPUS
36#else
37#define NR_LPPACAS 64
38#endif
39#else /* not iSeries */
40#define NR_LPPACAS 1
41#endif
42
43/*
30 * The structure which the hypervisor knows about - this structure 44 * The structure which the hypervisor knows about - this structure
31 * should not cross a page boundary. The vpa_init/register_vpa call 45 * should not cross a page boundary. The vpa_init/register_vpa call
32 * is now known to fail if the lppaca structure crosses a page 46 * is now known to fail if the lppaca structure crosses a page
@@ -36,7 +50,7 @@ extern unsigned long __toc_start;
36 * will suffice to ensure that it doesn't cross a page boundary. 50 * will suffice to ensure that it doesn't cross a page boundary.
37 */ 51 */
38struct lppaca lppaca[] = { 52struct lppaca lppaca[] = {
39 [0 ... (NR_CPUS-1)] = { 53 [0 ... (NR_LPPACAS-1)] = {
40 .desc = 0xd397d781, /* "LpPa" */ 54 .desc = 0xd397d781, /* "LpPa" */
41 .size = sizeof(struct lppaca), 55 .size = sizeof(struct lppaca),
42 .dyn_proc_status = 2, 56 .dyn_proc_status = 2,
@@ -49,6 +63,54 @@ struct lppaca lppaca[] = {
49 }, 63 },
50}; 64};
51 65
66static struct lppaca *extra_lppacas;
67static long __initdata lppaca_size;
68
69static void allocate_lppacas(int nr_cpus, unsigned long limit)
70{
71 if (nr_cpus <= NR_LPPACAS)
72 return;
73
74 lppaca_size = PAGE_ALIGN(sizeof(struct lppaca) *
75 (nr_cpus - NR_LPPACAS));
76 extra_lppacas = __va(memblock_alloc_base(lppaca_size,
77 PAGE_SIZE, limit));
78}
79
80static struct lppaca *new_lppaca(int cpu)
81{
82 struct lppaca *lp;
83
84 if (cpu < NR_LPPACAS)
85 return &lppaca[cpu];
86
87 lp = extra_lppacas + (cpu - NR_LPPACAS);
88 *lp = lppaca[0];
89
90 return lp;
91}
92
93static void free_lppacas(void)
94{
95 long new_size = 0, nr;
96
97 if (!lppaca_size)
98 return;
99 nr = num_possible_cpus() - NR_LPPACAS;
100 if (nr > 0)
101 new_size = PAGE_ALIGN(nr * sizeof(struct lppaca));
102 if (new_size >= lppaca_size)
103 return;
104
105 memblock_free(__pa(extra_lppacas) + new_size, lppaca_size - new_size);
106 lppaca_size = new_size;
107}
108
109#else
110
111static inline void allocate_lppacas(int, unsigned long) { }
112static inline void free_lppacas(void) { }
113
52#endif /* CONFIG_PPC_BOOK3S */ 114#endif /* CONFIG_PPC_BOOK3S */
53 115
54#ifdef CONFIG_PPC_STD_MMU_64 116#ifdef CONFIG_PPC_STD_MMU_64
@@ -88,7 +150,7 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu)
88 unsigned long kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL; 150 unsigned long kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL;
89 151
90#ifdef CONFIG_PPC_BOOK3S 152#ifdef CONFIG_PPC_BOOK3S
91 new_paca->lppaca_ptr = &lppaca[cpu]; 153 new_paca->lppaca_ptr = new_lppaca(cpu);
92#else 154#else
93 new_paca->kernel_pgd = swapper_pg_dir; 155 new_paca->kernel_pgd = swapper_pg_dir;
94#endif 156#endif
@@ -144,6 +206,8 @@ void __init allocate_pacas(void)
144 printk(KERN_DEBUG "Allocated %u bytes for %d pacas at %p\n", 206 printk(KERN_DEBUG "Allocated %u bytes for %d pacas at %p\n",
145 paca_size, nr_cpus, paca); 207 paca_size, nr_cpus, paca);
146 208
209 allocate_lppacas(nr_cpus, limit);
210
147 /* Can't use for_each_*_cpu, as they aren't functional yet */ 211 /* Can't use for_each_*_cpu, as they aren't functional yet */
148 for (cpu = 0; cpu < nr_cpus; cpu++) 212 for (cpu = 0; cpu < nr_cpus; cpu++)
149 initialise_paca(&paca[cpu], cpu); 213 initialise_paca(&paca[cpu], cpu);
@@ -164,4 +228,6 @@ void __init free_unused_pacas(void)
164 paca_size - new_size); 228 paca_size - new_size);
165 229
166 paca_size = new_size; 230 paca_size = new_size;
231
232 free_lppacas();
167} 233}