[RFC PATCH 09/11] powerpc/64s: Allocate LPPACAs node-local if possible
Nicholas Piggin
npiggin at gmail.com
Sat Jul 22 11:17:39 AEST 2017
Similary to the previous patch, allocate LPPACAs on a per-CPU basis,
attempting to get node-local memory.
---
arch/powerpc/include/asm/lppaca.h | 13 ++-----
arch/powerpc/kernel/machine_kexec_64.c | 15 ++++++--
arch/powerpc/kernel/paca.c | 65 +++++++++++++++++++---------------
arch/powerpc/mm/numa.c | 4 +--
4 files changed, 52 insertions(+), 45 deletions(-)
diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h
index 6e4589eee2da..78f171f298b7 100644
--- a/arch/powerpc/include/asm/lppaca.h
+++ b/arch/powerpc/include/asm/lppaca.h
@@ -36,14 +36,7 @@
#include <asm/mmu.h>
/*
- * We only have to have statically allocated lppaca structs on
- * legacy iSeries, which supports at most 64 cpus.
- */
-#define NR_LPPACAS 1
-
-/*
- * The Hypervisor barfs if the lppaca crosses a page boundary. A 1k
- * alignment is sufficient to prevent this
+ * The Hypervisor barfs if the lppaca crosses a page boundary.
*/
struct lppaca {
/* cacheline 1 contains read-only data */
@@ -99,9 +92,7 @@ struct lppaca {
u8 reserved11[148];
volatile __be64 dtl_idx; /* Dispatch Trace Log head index */
u8 reserved12[96];
-} __attribute__((__aligned__(0x400)));
-
-extern struct lppaca lppaca[];
+} ____cacheline_aligned;
#define lppaca_of(cpu) (*paca_ptrs[cpu]->lppaca_ptr)
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index 700cd25fbd28..c439277e0cf8 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -286,6 +286,10 @@ static union thread_union kexec_stack __init_task_data =
* static PACA; we switch to kexec_paca.
*/
struct paca_struct kexec_paca;
+#ifdef CONFIG_PPC_PSERIES
+/* align lppaca to 1K to avoid crossing page boundary */
+struct lppaca kexec_lppaca __attribute__((aligned(0x400)));
+#endif
/* Our assembly helper, in misc_64.S */
extern void kexec_sequence(void *newstack, unsigned long start,
@@ -329,11 +333,16 @@ void default_machine_kexec(struct kimage *image)
memcpy(&kexec_paca, get_paca(), sizeof(struct paca_struct));
kexec_paca.data_offset = 0xedeaddeadeeeeeeeUL;
paca_ptrs[kexec_paca.paca_index] = &kexec_paca;
+
+#ifdef CONFIG_PPC_PSERIES
+ if (firmware_has_feature(FW_FEATURE_LPAR)) {
+ memcpy(&kexec_lppaca, get_lppaca(), sizeof(struct lppaca));
+ kexec_paca.lppaca_ptr = &kexec_lppaca;
+ }
+#endif
+
setup_paca(&kexec_paca);
- /* XXX: If anyone does 'dynamic lppacas' this will also need to be
- * switched to a static version!
- */
/*
* On Book3S, the copy must happen with the MMU off if we are either
* using Radix page tables or we are not in an LPAR since we can
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index bf5f5820a3e4..d929d146b977 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -18,6 +18,8 @@
#include <asm/pgtable.h>
#include <asm/kexec.h>
+static int __initdata paca_nr_cpu_ids;
+
#ifdef CONFIG_PPC_PSERIES
/*
@@ -29,32 +31,42 @@
* change since the hypervisor knows its layout, so a 1kB alignment
* will suffice to ensure that it doesn't cross a page boundary.
*/
-struct lppaca lppaca[] = {
- [0 ... (NR_LPPACAS-1)] = {
+static inline void init_lppaca(struct lppaca *lppaca)
+{
+ *lppaca = (struct lppaca) {
.desc = cpu_to_be32(0xd397d781), /* "LpPa" */
.size = cpu_to_be16(sizeof(struct lppaca)),
.fpregs_in_use = 1,
.slb_count = cpu_to_be16(64),
.vmxregs_in_use = 0,
- .page_ins = 0,
- },
+ .page_ins = 0, };
};
-static struct lppaca *extra_lppacas;
-static long __initdata lppaca_size;
+static struct lppaca ** __initdata lppaca_ptrs;
+
+static long __initdata lppaca_ptrs_size;
static void __init allocate_lppacas(int nr_cpus, unsigned long limit)
{
+ int cpu;
+
if (!firmware_has_feature(FW_FEATURE_LPAR))
return;
- if (nr_cpus <= NR_LPPACAS)
- return;
+ lppaca_ptrs_size = sizeof(struct lppaca *) * nr_cpu_ids;
+ lppaca_ptrs = __va(memblock_alloc_base(lppaca_ptrs_size, 0, limit));
+
+ for (cpu = 0; cpu < nr_cpu_ids; cpu++) {
+ unsigned long pa;
- lppaca_size = PAGE_ALIGN(sizeof(struct lppaca) *
- (nr_cpus - NR_LPPACAS));
- extra_lppacas = __va(memblock_alloc_base(lppaca_size,
- PAGE_SIZE, limit));
+ pa = memblock_alloc_base_nid(sizeof(struct lppaca), 0x400,
+ limit, early_cpu_to_node(cpu),
+ MEMBLOCK_NONE);
+ if (!pa)
+ pa = memblock_alloc_base(sizeof(struct lppaca), 0x400,
+ limit);
+ lppaca_ptrs[cpu] = __va(pa);
+ }
}
static struct lppaca * __init new_lppaca(int cpu)
@@ -64,29 +76,25 @@ static struct lppaca * __init new_lppaca(int cpu)
if (!firmware_has_feature(FW_FEATURE_LPAR))
return NULL;
- if (cpu < NR_LPPACAS)
- return &lppaca[cpu];
-
- lp = extra_lppacas + (cpu - NR_LPPACAS);
- *lp = lppaca[0];
+ lp = lppaca_ptrs[cpu];
+ init_lppaca(lp);
return lp;
}
static void __init free_lppacas(void)
{
- long new_size = 0, nr;
+ int cpu;
- 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;
+ for (cpu = 0; cpu < paca_nr_cpu_ids; cpu++) {
+ if (!cpu_possible(cpu)) {
+ memblock_free(__pa(lppaca_ptrs[cpu]),
+ sizeof(struct lppaca));
+ lppaca_ptrs[cpu] = NULL;
+ }
+ }
- memblock_free(__pa(extra_lppacas) + new_size, lppaca_size - new_size);
- lppaca_size = new_size;
+ memblock_free(__pa(lppaca_ptrs), lppaca_ptrs_size);
}
#else
@@ -105,7 +113,7 @@ static inline void free_lppacas(void) { }
* If you make the number of persistent SLB entries dynamic, please also
* update PR KVM to flush and restore them accordingly.
*/
-static struct slb_shadow *slb_shadow;
+static struct slb_shadow * __initdata slb_shadow;
static void __init allocate_slb_shadows(int nr_cpus, int limit)
{
@@ -208,7 +216,6 @@ void setup_paca(struct paca_struct *new_paca)
}
-static int __initdata paca_nr_cpu_ids;
static int __initdata paca_ptrs_size;
static __init unsigned long safe_paca_limit(void)
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index b95c584ce19d..55e3fa5fcfb0 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -1168,7 +1168,7 @@ static void setup_cpu_associativity_change_counters(void)
for_each_possible_cpu(cpu) {
int i;
u8 *counts = vphn_cpu_change_counts[cpu];
- volatile u8 *hypervisor_counts = lppaca[cpu].vphn_assoc_counts;
+ volatile u8 *hypervisor_counts = lppaca_of(cpu).vphn_assoc_counts;
for (i = 0; i < distance_ref_points_depth; i++)
counts[i] = hypervisor_counts[i];
@@ -1194,7 +1194,7 @@ static int update_cpu_associativity_changes_mask(void)
for_each_possible_cpu(cpu) {
int i, changed = 0;
u8 *counts = vphn_cpu_change_counts[cpu];
- volatile u8 *hypervisor_counts = lppaca[cpu].vphn_assoc_counts;
+ volatile u8 *hypervisor_counts = lppaca_of(cpu).vphn_assoc_counts;
for (i = 0; i < distance_ref_points_depth; i++) {
if (hypervisor_counts[i] != counts[i]) {
--
2.11.0
More information about the Linuxppc-dev
mailing list