diff options
Diffstat (limited to 'arch/powerpc/kernel/paca.c')
-rw-r--r-- | arch/powerpc/kernel/paca.c | 88 |
1 files changed, 73 insertions, 15 deletions
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index d0a26f1770fe..efeb88184182 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * 2 of the License, or (at your option) any later version. | 7 | * 2 of the License, or (at your option) any later version. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/threads.h> | 10 | #include <linux/smp.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/memblock.h> | 12 | #include <linux/memblock.h> |
13 | 13 | ||
@@ -36,7 +36,7 @@ extern unsigned long __toc_start; | |||
36 | * will suffice to ensure that it doesn't cross a page boundary. | 36 | * will suffice to ensure that it doesn't cross a page boundary. |
37 | */ | 37 | */ |
38 | struct lppaca lppaca[] = { | 38 | struct lppaca lppaca[] = { |
39 | [0 ... (NR_CPUS-1)] = { | 39 | [0 ... (NR_LPPACAS-1)] = { |
40 | .desc = 0xd397d781, /* "LpPa" */ | 40 | .desc = 0xd397d781, /* "LpPa" */ |
41 | .size = sizeof(struct lppaca), | 41 | .size = sizeof(struct lppaca), |
42 | .dyn_proc_status = 2, | 42 | .dyn_proc_status = 2, |
@@ -49,6 +49,54 @@ struct lppaca lppaca[] = { | |||
49 | }, | 49 | }, |
50 | }; | 50 | }; |
51 | 51 | ||
52 | static struct lppaca *extra_lppacas; | ||
53 | static long __initdata lppaca_size; | ||
54 | |||
55 | static void allocate_lppacas(int nr_cpus, unsigned long limit) | ||
56 | { | ||
57 | if (nr_cpus <= NR_LPPACAS) | ||
58 | return; | ||
59 | |||
60 | lppaca_size = PAGE_ALIGN(sizeof(struct lppaca) * | ||
61 | (nr_cpus - NR_LPPACAS)); | ||
62 | extra_lppacas = __va(memblock_alloc_base(lppaca_size, | ||
63 | PAGE_SIZE, limit)); | ||
64 | } | ||
65 | |||
66 | static struct lppaca *new_lppaca(int cpu) | ||
67 | { | ||
68 | struct lppaca *lp; | ||
69 | |||
70 | if (cpu < NR_LPPACAS) | ||
71 | return &lppaca[cpu]; | ||
72 | |||
73 | lp = extra_lppacas + (cpu - NR_LPPACAS); | ||
74 | *lp = lppaca[0]; | ||
75 | |||
76 | return lp; | ||
77 | } | ||
78 | |||
79 | static void free_lppacas(void) | ||
80 | { | ||
81 | long new_size = 0, nr; | ||
82 | |||
83 | if (!lppaca_size) | ||
84 | return; | ||
85 | nr = num_possible_cpus() - NR_LPPACAS; | ||
86 | if (nr > 0) | ||
87 | new_size = PAGE_ALIGN(nr * sizeof(struct lppaca)); | ||
88 | if (new_size >= lppaca_size) | ||
89 | return; | ||
90 | |||
91 | memblock_free(__pa(extra_lppacas) + new_size, lppaca_size - new_size); | ||
92 | lppaca_size = new_size; | ||
93 | } | ||
94 | |||
95 | #else | ||
96 | |||
97 | static inline void allocate_lppacas(int nr_cpus, unsigned long limit) { } | ||
98 | static inline void free_lppacas(void) { } | ||
99 | |||
52 | #endif /* CONFIG_PPC_BOOK3S */ | 100 | #endif /* CONFIG_PPC_BOOK3S */ |
53 | 101 | ||
54 | #ifdef CONFIG_PPC_STD_MMU_64 | 102 | #ifdef CONFIG_PPC_STD_MMU_64 |
@@ -88,7 +136,7 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu) | |||
88 | unsigned long kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL; | 136 | unsigned long kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL; |
89 | 137 | ||
90 | #ifdef CONFIG_PPC_BOOK3S | 138 | #ifdef CONFIG_PPC_BOOK3S |
91 | new_paca->lppaca_ptr = &lppaca[cpu]; | 139 | new_paca->lppaca_ptr = new_lppaca(cpu); |
92 | #else | 140 | #else |
93 | new_paca->kernel_pgd = swapper_pg_dir; | 141 | new_paca->kernel_pgd = swapper_pg_dir; |
94 | #endif | 142 | #endif |
@@ -108,18 +156,29 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu) | |||
108 | /* Put the paca pointer into r13 and SPRG_PACA */ | 156 | /* Put the paca pointer into r13 and SPRG_PACA */ |
109 | void setup_paca(struct paca_struct *new_paca) | 157 | void setup_paca(struct paca_struct *new_paca) |
110 | { | 158 | { |
159 | /* Setup r13 */ | ||
111 | local_paca = new_paca; | 160 | local_paca = new_paca; |
112 | mtspr(SPRN_SPRG_PACA, local_paca); | 161 | |
113 | #ifdef CONFIG_PPC_BOOK3E | 162 | #ifdef CONFIG_PPC_BOOK3E |
163 | /* On Book3E, initialize the TLB miss exception frames */ | ||
114 | mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb); | 164 | mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb); |
165 | #else | ||
166 | /* In HV mode, we setup both HPACA and PACA to avoid problems | ||
167 | * if we do a GET_PACA() before the feature fixups have been | ||
168 | * applied | ||
169 | */ | ||
170 | if (cpu_has_feature(CPU_FTR_HVMODE_206)) | ||
171 | mtspr(SPRN_SPRG_HPACA, local_paca); | ||
115 | #endif | 172 | #endif |
173 | mtspr(SPRN_SPRG_PACA, local_paca); | ||
174 | |||
116 | } | 175 | } |
117 | 176 | ||
118 | static int __initdata paca_size; | 177 | static int __initdata paca_size; |
119 | 178 | ||
120 | void __init allocate_pacas(void) | 179 | void __init allocate_pacas(void) |
121 | { | 180 | { |
122 | int nr_cpus, cpu, limit; | 181 | int cpu, limit; |
123 | 182 | ||
124 | /* | 183 | /* |
125 | * We can't take SLB misses on the paca, and we want to access them | 184 | * We can't take SLB misses on the paca, and we want to access them |
@@ -127,25 +186,22 @@ void __init allocate_pacas(void) | |||
127 | * the first segment. On iSeries they must be within the area mapped | 186 | * the first segment. On iSeries they must be within the area mapped |
128 | * by the HV, which is HvPagesToMap * HVPAGESIZE bytes. | 187 | * by the HV, which is HvPagesToMap * HVPAGESIZE bytes. |
129 | */ | 188 | */ |
130 | limit = min(0x10000000ULL, memblock.rmo_size); | 189 | limit = min(0x10000000ULL, ppc64_rma_size); |
131 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | 190 | if (firmware_has_feature(FW_FEATURE_ISERIES)) |
132 | limit = min(limit, HvPagesToMap * HVPAGESIZE); | 191 | limit = min(limit, HvPagesToMap * HVPAGESIZE); |
133 | 192 | ||
134 | nr_cpus = NR_CPUS; | 193 | paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpu_ids); |
135 | /* On iSeries we know we can never have more than 64 cpus */ | ||
136 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
137 | nr_cpus = min(64, nr_cpus); | ||
138 | |||
139 | paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpus); | ||
140 | 194 | ||
141 | paca = __va(memblock_alloc_base(paca_size, PAGE_SIZE, limit)); | 195 | paca = __va(memblock_alloc_base(paca_size, PAGE_SIZE, limit)); |
142 | memset(paca, 0, paca_size); | 196 | memset(paca, 0, paca_size); |
143 | 197 | ||
144 | printk(KERN_DEBUG "Allocated %u bytes for %d pacas at %p\n", | 198 | printk(KERN_DEBUG "Allocated %u bytes for %d pacas at %p\n", |
145 | paca_size, nr_cpus, paca); | 199 | paca_size, nr_cpu_ids, paca); |
200 | |||
201 | allocate_lppacas(nr_cpu_ids, limit); | ||
146 | 202 | ||
147 | /* Can't use for_each_*_cpu, as they aren't functional yet */ | 203 | /* Can't use for_each_*_cpu, as they aren't functional yet */ |
148 | for (cpu = 0; cpu < nr_cpus; cpu++) | 204 | for (cpu = 0; cpu < nr_cpu_ids; cpu++) |
149 | initialise_paca(&paca[cpu], cpu); | 205 | initialise_paca(&paca[cpu], cpu); |
150 | } | 206 | } |
151 | 207 | ||
@@ -153,7 +209,7 @@ void __init free_unused_pacas(void) | |||
153 | { | 209 | { |
154 | int new_size; | 210 | int new_size; |
155 | 211 | ||
156 | new_size = PAGE_ALIGN(sizeof(struct paca_struct) * num_possible_cpus()); | 212 | new_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpu_ids); |
157 | 213 | ||
158 | if (new_size >= paca_size) | 214 | if (new_size >= paca_size) |
159 | return; | 215 | return; |
@@ -164,4 +220,6 @@ void __init free_unused_pacas(void) | |||
164 | paca_size - new_size); | 220 | paca_size - new_size); |
165 | 221 | ||
166 | paca_size = new_size; | 222 | paca_size = new_size; |
223 | |||
224 | free_lppacas(); | ||
167 | } | 225 | } |