diff options
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/head_64.S | 6 | ||||
-rw-r--r-- | arch/powerpc/kernel/paca.c | 93 | ||||
-rw-r--r-- | arch/powerpc/kernel/prom.c | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/setup-common.c | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/setup_64.c | 12 |
5 files changed, 86 insertions, 31 deletions
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 925807488022..b24b7001ae19 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S | |||
@@ -219,7 +219,8 @@ generic_secondary_common_init: | |||
219 | * physical cpu id in r24, we need to search the pacas to find | 219 | * physical cpu id in r24, we need to search the pacas to find |
220 | * which logical id maps to our physical one. | 220 | * which logical id maps to our physical one. |
221 | */ | 221 | */ |
222 | LOAD_REG_ADDR(r13, paca) /* Get base vaddr of paca array */ | 222 | LOAD_REG_ADDR(r13, paca) /* Load paca pointer */ |
223 | ld r13,0(r13) /* Get base vaddr of paca array */ | ||
223 | li r5,0 /* logical cpu id */ | 224 | li r5,0 /* logical cpu id */ |
224 | 1: lhz r6,PACAHWCPUID(r13) /* Load HW procid from paca */ | 225 | 1: lhz r6,PACAHWCPUID(r13) /* Load HW procid from paca */ |
225 | cmpw r6,r24 /* Compare to our id */ | 226 | cmpw r6,r24 /* Compare to our id */ |
@@ -536,7 +537,8 @@ _GLOBAL(pmac_secondary_start) | |||
536 | mtmsrd r3 /* RI on */ | 537 | mtmsrd r3 /* RI on */ |
537 | 538 | ||
538 | /* Set up a paca value for this processor. */ | 539 | /* Set up a paca value for this processor. */ |
539 | LOAD_REG_ADDR(r4,paca) /* Get base vaddr of paca array */ | 540 | LOAD_REG_ADDR(r4,paca) /* Load paca pointer */ |
541 | ld r4,0(r4) /* Get base vaddr of paca array */ | ||
540 | mulli r13,r24,PACA_SIZE /* Calculate vaddr of right paca */ | 542 | mulli r13,r24,PACA_SIZE /* Calculate vaddr of right paca */ |
541 | add r13,r13,r4 /* for this processor. */ | 543 | add r13,r13,r4 /* for this processor. */ |
542 | mtspr SPRN_SPRG_PACA,r13 /* Save vaddr of paca in an SPRG*/ | 544 | mtspr SPRN_SPRG_PACA,r13 /* Save vaddr of paca in an SPRG*/ |
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index d16b1ea55d44..0c40c6f476fe 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c | |||
@@ -9,11 +9,15 @@ | |||
9 | 9 | ||
10 | #include <linux/threads.h> | 10 | #include <linux/threads.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/lmb.h> | ||
12 | 13 | ||
14 | #include <asm/firmware.h> | ||
13 | #include <asm/lppaca.h> | 15 | #include <asm/lppaca.h> |
14 | #include <asm/paca.h> | 16 | #include <asm/paca.h> |
15 | #include <asm/sections.h> | 17 | #include <asm/sections.h> |
16 | #include <asm/pgtable.h> | 18 | #include <asm/pgtable.h> |
19 | #include <asm/iseries/lpar_map.h> | ||
20 | #include <asm/iseries/hv_types.h> | ||
17 | 21 | ||
18 | /* This symbol is provided by the linker - let it fill in the paca | 22 | /* This symbol is provided by the linker - let it fill in the paca |
19 | * field correctly */ | 23 | * field correctly */ |
@@ -70,37 +74,82 @@ struct slb_shadow slb_shadow[] __cacheline_aligned = { | |||
70 | * processors. The processor VPD array needs one entry per physical | 74 | * processors. The processor VPD array needs one entry per physical |
71 | * processor (not thread). | 75 | * processor (not thread). |
72 | */ | 76 | */ |
73 | struct paca_struct paca[NR_CPUS]; | 77 | struct paca_struct *paca; |
74 | EXPORT_SYMBOL(paca); | 78 | EXPORT_SYMBOL(paca); |
75 | 79 | ||
76 | void __init initialise_pacas(void) | 80 | struct paca_struct boot_paca; |
77 | { | ||
78 | int cpu; | ||
79 | 81 | ||
80 | /* The TOC register (GPR2) points 32kB into the TOC, so that 64kB | 82 | void __init initialise_paca(struct paca_struct *new_paca, int cpu) |
81 | * of the TOC can be addressed using a single machine instruction. | 83 | { |
82 | */ | 84 | /* The TOC register (GPR2) points 32kB into the TOC, so that 64kB |
85 | * of the TOC can be addressed using a single machine instruction. | ||
86 | */ | ||
83 | unsigned long kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL; | 87 | unsigned long kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL; |
84 | 88 | ||
85 | /* Can't use for_each_*_cpu, as they aren't functional yet */ | ||
86 | for (cpu = 0; cpu < NR_CPUS; cpu++) { | ||
87 | struct paca_struct *new_paca = &paca[cpu]; | ||
88 | |||
89 | #ifdef CONFIG_PPC_BOOK3S | 89 | #ifdef CONFIG_PPC_BOOK3S |
90 | new_paca->lppaca_ptr = &lppaca[cpu]; | 90 | new_paca->lppaca_ptr = &lppaca[cpu]; |
91 | #else | 91 | #else |
92 | new_paca->kernel_pgd = swapper_pg_dir; | 92 | new_paca->kernel_pgd = swapper_pg_dir; |
93 | #endif | 93 | #endif |
94 | new_paca->lock_token = 0x8000; | 94 | new_paca->lock_token = 0x8000; |
95 | new_paca->paca_index = cpu; | 95 | new_paca->paca_index = cpu; |
96 | new_paca->kernel_toc = kernel_toc; | 96 | new_paca->kernel_toc = kernel_toc; |
97 | new_paca->kernelbase = (unsigned long) _stext; | 97 | new_paca->kernelbase = (unsigned long) _stext; |
98 | new_paca->kernel_msr = MSR_KERNEL; | 98 | new_paca->kernel_msr = MSR_KERNEL; |
99 | new_paca->hw_cpu_id = 0xffff; | 99 | new_paca->hw_cpu_id = 0xffff; |
100 | new_paca->__current = &init_task; | 100 | new_paca->__current = &init_task; |
101 | #ifdef CONFIG_PPC_STD_MMU_64 | 101 | #ifdef CONFIG_PPC_STD_MMU_64 |
102 | new_paca->slb_shadow_ptr = &slb_shadow[cpu]; | 102 | new_paca->slb_shadow_ptr = &slb_shadow[cpu]; |
103 | #endif /* CONFIG_PPC_STD_MMU_64 */ | 103 | #endif /* CONFIG_PPC_STD_MMU_64 */ |
104 | } | ||
105 | |||
106 | static int __initdata paca_size; | ||
107 | |||
108 | void __init allocate_pacas(void) | ||
109 | { | ||
110 | int nr_cpus, cpu, limit; | ||
111 | |||
112 | /* | ||
113 | * We can't take SLB misses on the paca, and we want to access them | ||
114 | * in real mode, so allocate them within the RMA and also within | ||
115 | * the first segment. On iSeries they must be within the area mapped | ||
116 | * by the HV, which is HvPagesToMap * HVPAGESIZE bytes. | ||
117 | */ | ||
118 | limit = min(0x10000000ULL, lmb.rmo_size); | ||
119 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
120 | limit = min(limit, HvPagesToMap * HVPAGESIZE); | ||
121 | |||
122 | nr_cpus = NR_CPUS; | ||
123 | /* On iSeries we know we can never have more than 64 cpus */ | ||
124 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
125 | nr_cpus = min(64, nr_cpus); | ||
126 | |||
127 | paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpus); | ||
128 | |||
129 | paca = __va(lmb_alloc_base(paca_size, PAGE_SIZE, limit)); | ||
130 | memset(paca, 0, paca_size); | ||
131 | |||
132 | printk(KERN_DEBUG "Allocated %u bytes for %d pacas at %p\n", | ||
133 | paca_size, nr_cpus, paca); | ||
134 | |||
135 | /* Can't use for_each_*_cpu, as they aren't functional yet */ | ||
136 | for (cpu = 0; cpu < nr_cpus; cpu++) | ||
137 | initialise_paca(&paca[cpu], cpu); | ||
138 | } | ||
139 | |||
140 | void __init free_unused_pacas(void) | ||
141 | { | ||
142 | int new_size; | ||
143 | |||
144 | new_size = PAGE_ALIGN(sizeof(struct paca_struct) * num_possible_cpus()); | ||
145 | |||
146 | if (new_size >= paca_size) | ||
147 | return; | ||
148 | |||
149 | lmb_free(__pa(paca) + new_size, paca_size - new_size); | ||
150 | |||
151 | printk(KERN_DEBUG "Freed %u bytes for unused pacas\n", | ||
152 | paca_size - new_size); | ||
104 | 153 | ||
105 | } | 154 | paca_size = new_size; |
106 | } | 155 | } |
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 43238b2054b6..05131d634e73 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <asm/smp.h> | 43 | #include <asm/smp.h> |
44 | #include <asm/system.h> | 44 | #include <asm/system.h> |
45 | #include <asm/mmu.h> | 45 | #include <asm/mmu.h> |
46 | #include <asm/paca.h> | ||
46 | #include <asm/pgtable.h> | 47 | #include <asm/pgtable.h> |
47 | #include <asm/pci.h> | 48 | #include <asm/pci.h> |
48 | #include <asm/iommu.h> | 49 | #include <asm/iommu.h> |
@@ -721,6 +722,8 @@ void __init early_init_devtree(void *params) | |||
721 | * FIXME .. and the initrd too? */ | 722 | * FIXME .. and the initrd too? */ |
722 | move_device_tree(); | 723 | move_device_tree(); |
723 | 724 | ||
725 | allocate_pacas(); | ||
726 | |||
724 | DBG("Scanning CPUs ...\n"); | 727 | DBG("Scanning CPUs ...\n"); |
725 | 728 | ||
726 | /* Retreive CPU related informations from the flat tree | 729 | /* Retreive CPU related informations from the flat tree |
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 03dd6a248198..48f0a008b20b 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/lmb.h> | 36 | #include <linux/lmb.h> |
37 | #include <linux/of_platform.h> | 37 | #include <linux/of_platform.h> |
38 | #include <asm/io.h> | 38 | #include <asm/io.h> |
39 | #include <asm/paca.h> | ||
39 | #include <asm/prom.h> | 40 | #include <asm/prom.h> |
40 | #include <asm/processor.h> | 41 | #include <asm/processor.h> |
41 | #include <asm/vdso_datapage.h> | 42 | #include <asm/vdso_datapage.h> |
@@ -493,6 +494,8 @@ void __init smp_setup_cpu_maps(void) | |||
493 | * here will have to be reworked | 494 | * here will have to be reworked |
494 | */ | 495 | */ |
495 | cpu_init_thread_core_maps(nthreads); | 496 | cpu_init_thread_core_maps(nthreads); |
497 | |||
498 | free_unused_pacas(); | ||
496 | } | 499 | } |
497 | #endif /* CONFIG_SMP */ | 500 | #endif /* CONFIG_SMP */ |
498 | 501 | ||
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 6568406b2a30..63547394048c 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
@@ -144,9 +144,9 @@ early_param("smt-enabled", early_smt_enabled); | |||
144 | #endif /* CONFIG_SMP */ | 144 | #endif /* CONFIG_SMP */ |
145 | 145 | ||
146 | /* Put the paca pointer into r13 and SPRG_PACA */ | 146 | /* Put the paca pointer into r13 and SPRG_PACA */ |
147 | void __init setup_paca(int cpu) | 147 | static void __init setup_paca(struct paca_struct *new_paca) |
148 | { | 148 | { |
149 | local_paca = &paca[cpu]; | 149 | local_paca = new_paca; |
150 | mtspr(SPRN_SPRG_PACA, local_paca); | 150 | mtspr(SPRN_SPRG_PACA, local_paca); |
151 | #ifdef CONFIG_PPC_BOOK3E | 151 | #ifdef CONFIG_PPC_BOOK3E |
152 | mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb); | 152 | mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb); |
@@ -176,14 +176,12 @@ void __init early_setup(unsigned long dt_ptr) | |||
176 | { | 176 | { |
177 | /* -------- printk is _NOT_ safe to use here ! ------- */ | 177 | /* -------- printk is _NOT_ safe to use here ! ------- */ |
178 | 178 | ||
179 | /* Fill in any unititialised pacas */ | ||
180 | initialise_pacas(); | ||
181 | |||
182 | /* Identify CPU type */ | 179 | /* Identify CPU type */ |
183 | identify_cpu(0, mfspr(SPRN_PVR)); | 180 | identify_cpu(0, mfspr(SPRN_PVR)); |
184 | 181 | ||
185 | /* Assume we're on cpu 0 for now. Don't write to the paca yet! */ | 182 | /* Assume we're on cpu 0 for now. Don't write to the paca yet! */ |
186 | setup_paca(0); | 183 | initialise_paca(&boot_paca, 0); |
184 | setup_paca(&boot_paca); | ||
187 | 185 | ||
188 | /* Initialize lockdep early or else spinlocks will blow */ | 186 | /* Initialize lockdep early or else spinlocks will blow */ |
189 | lockdep_init(); | 187 | lockdep_init(); |
@@ -203,7 +201,7 @@ void __init early_setup(unsigned long dt_ptr) | |||
203 | early_init_devtree(__va(dt_ptr)); | 201 | early_init_devtree(__va(dt_ptr)); |
204 | 202 | ||
205 | /* Now we know the logical id of our boot cpu, setup the paca. */ | 203 | /* Now we know the logical id of our boot cpu, setup the paca. */ |
206 | setup_paca(boot_cpuid); | 204 | setup_paca(&paca[boot_cpuid]); |
207 | 205 | ||
208 | /* Fix up paca fields required for the boot cpu */ | 206 | /* Fix up paca fields required for the boot cpu */ |
209 | get_paca()->cpu_start = 1; | 207 | get_paca()->cpu_start = 1; |