diff options
Diffstat (limited to 'arch/powerpc/kernel/paca.c')
| -rw-r--r-- | arch/powerpc/kernel/paca.c | 70 |
1 files changed, 68 insertions, 2 deletions
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index a4e72159234f..ebf9846f3c3b 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 | */ |
| 38 | struct lppaca lppaca[] = { | 52 | struct 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 | ||
| 66 | static struct lppaca *extra_lppacas; | ||
| 67 | static long __initdata lppaca_size; | ||
| 68 | |||
| 69 | static 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 | |||
| 80 | static 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 | |||
| 93 | static 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 | |||
| 111 | static inline void allocate_lppacas(int nr_cpus, unsigned long limit) { } | ||
| 112 | static 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 | } |
