Skip to content

Commit

Permalink
powerpc/64: Use array of paca pointers and allocate pacas individually
Browse files Browse the repository at this point in the history
Change the paca array into an array of pointers to pacas. Allocate
pacas individually.

This allows flexibility in where the PACAs are allocated. Future work
will allocate them node-local. Platforms that don't have address limits
on PACAs would be able to defer PACA allocations until later in boot
rather than allocate all possible ones up-front then freeing unused.

This is slightly more overhead (one additional indirection) for cross
CPU paca references, but those aren't too common.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
  • Loading branch information
Nicholas Piggin authored and Michael Ellerman committed Mar 30, 2018
1 parent 8e0b634 commit d2e6007
Show file tree
Hide file tree
Showing 26 changed files with 143 additions and 107 deletions.
8 changes: 4 additions & 4 deletions arch/powerpc/include/asm/kvm_ppc.h
Original file line number Diff line number Diff line change
Expand Up @@ -436,15 +436,15 @@ struct openpic;
extern void kvm_cma_reserve(void) __init;
static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr)
{
paca[cpu].kvm_hstate.xics_phys = (void __iomem *)addr;
paca_ptrs[cpu]->kvm_hstate.xics_phys = (void __iomem *)addr;
}

static inline void kvmppc_set_xive_tima(int cpu,
unsigned long phys_addr,
void __iomem *virt_addr)
{
paca[cpu].kvm_hstate.xive_tima_phys = (void __iomem *)phys_addr;
paca[cpu].kvm_hstate.xive_tima_virt = virt_addr;
paca_ptrs[cpu]->kvm_hstate.xive_tima_phys = (void __iomem *)phys_addr;
paca_ptrs[cpu]->kvm_hstate.xive_tima_virt = virt_addr;
}

static inline u32 kvmppc_get_xics_latch(void)
Expand All @@ -458,7 +458,7 @@ static inline u32 kvmppc_get_xics_latch(void)

static inline void kvmppc_set_host_ipi(int cpu, u8 host_ipi)
{
paca[cpu].kvm_hstate.host_ipi = host_ipi;
paca_ptrs[cpu]->kvm_hstate.host_ipi = host_ipi;
}

static inline void kvmppc_fast_vcpu_kick(struct kvm_vcpu *vcpu)
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/include/asm/lppaca.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ struct lppaca {

extern struct lppaca lppaca[];

#define lppaca_of(cpu) (*paca[cpu].lppaca_ptr)
#define lppaca_of(cpu) (*paca_ptrs[cpu]->lppaca_ptr)

/*
* We are using a non architected field to determine if a partition is
Expand Down
4 changes: 2 additions & 2 deletions arch/powerpc/include/asm/paca.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,10 +249,10 @@ struct paca_struct {
void *rfi_flush_fallback_area;
u64 l1d_flush_size;
#endif
};
} ____cacheline_aligned;

extern void copy_mm_to_paca(struct mm_struct *mm);
extern struct paca_struct *paca;
extern struct paca_struct **paca_ptrs;
extern void initialise_paca(struct paca_struct *new_paca, int cpu);
extern void setup_paca(struct paca_struct *new_paca);
extern void allocate_pacas(void);
Expand Down
4 changes: 2 additions & 2 deletions arch/powerpc/include/asm/smp.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,12 @@ static inline const struct cpumask *cpu_sibling_mask(int cpu)
#ifdef CONFIG_PPC64
static inline int get_hard_smp_processor_id(int cpu)
{
return paca[cpu].hw_cpu_id;
return paca_ptrs[cpu]->hw_cpu_id;
}

static inline void set_hard_smp_processor_id(int cpu, int phys)
{
paca[cpu].hw_cpu_id = phys;
paca_ptrs[cpu]->hw_cpu_id = phys;
}
#else
/* 32-bit */
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/kernel/crash.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ static void __maybe_unused crash_kexec_wait_realmode(int cpu)
if (i == cpu)
continue;

while (paca[i].kexec_state < KEXEC_STATE_REAL_MODE) {
while (paca_ptrs[i]->kexec_state < KEXEC_STATE_REAL_MODE) {
barrier();
if (!cpu_possible(i) || !cpu_online(i) || (msecs <= 0))
break;
Expand Down
19 changes: 10 additions & 9 deletions arch/powerpc/kernel/head_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -392,19 +392,20 @@ generic_secondary_common_init:
* physical cpu id in r24, we need to search the pacas to find
* which logical id maps to our physical one.
*/
LOAD_REG_ADDR(r13, paca) /* Load paca pointer */
ld r13,0(r13) /* Get base vaddr of paca array */
#ifndef CONFIG_SMP
addi r13,r13,PACA_SIZE /* know r13 if used accidentally */
b kexec_wait /* wait for next kernel if !SMP */
#else
LOAD_REG_ADDR(r8, paca_ptrs) /* Load paca_ptrs pointe */
ld r8,0(r8) /* Get base vaddr of array */
LOAD_REG_ADDR(r7, nr_cpu_ids) /* Load nr_cpu_ids address */
lwz r7,0(r7) /* also the max paca allocated */
li r5,0 /* logical cpu id */
1: lhz r6,PACAHWCPUID(r13) /* Load HW procid from paca */
1:
sldi r9,r5,3 /* get paca_ptrs[] index from cpu id */
ldx r13,r9,r8 /* r13 = paca_ptrs[cpu id] */
lhz r6,PACAHWCPUID(r13) /* Load HW procid from paca */
cmpw r6,r24 /* Compare to our id */
beq 2f
addi r13,r13,PACA_SIZE /* Loop to next PACA on miss */
addi r5,r5,1
cmpw r5,r7 /* Check if more pacas exist */
blt 1b
Expand Down Expand Up @@ -756,10 +757,10 @@ _GLOBAL(pmac_secondary_start)
mtmsrd r3 /* RI on */

/* Set up a paca value for this processor. */
LOAD_REG_ADDR(r4,paca) /* Load paca pointer */
ld r4,0(r4) /* Get base vaddr of paca array */
mulli r13,r24,PACA_SIZE /* Calculate vaddr of right paca */
add r13,r13,r4 /* for this processor. */
LOAD_REG_ADDR(r4,paca_ptrs) /* Load paca pointer */
ld r4,0(r4) /* Get base vaddr of paca_ptrs array */
sldi r5,r24,3 /* get paca_ptrs[] index from cpu id */
ldx r13,r5,r4 /* r13 = paca_ptrs[cpu id] */
SET_PACA(r13) /* Save vaddr of paca in an SPRG*/

/* Mark interrupts soft and hard disabled (they might be enabled
Expand Down
22 changes: 11 additions & 11 deletions arch/powerpc/kernel/machine_kexec_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,24 +168,25 @@ static void kexec_prepare_cpus_wait(int wait_state)
* are correctly onlined. If somehow we start a CPU on boot with RTAS
* start-cpu, but somehow that CPU doesn't write callin_cpu_map[] in
* time, the boot CPU will timeout. If it does eventually execute
* stuff, the secondary will start up (paca[].cpu_start was written) and
* get into a peculiar state. If the platform supports
* smp_ops->take_timebase(), the secondary CPU will probably be spinning
* in there. If not (i.e. pseries), the secondary will continue on and
* try to online itself/idle/etc. If it survives that, we need to find
* these possible-but-not-online-but-should-be CPUs and chaperone them
* into kexec_smp_wait().
* stuff, the secondary will start up (paca_ptrs[]->cpu_start was
* written) and get into a peculiar state.
* If the platform supports smp_ops->take_timebase(), the secondary CPU
* will probably be spinning in there. If not (i.e. pseries), the
* secondary will continue on and try to online itself/idle/etc. If it
* survives that, we need to find these
* possible-but-not-online-but-should-be CPUs and chaperone them into
* kexec_smp_wait().
*/
for_each_online_cpu(i) {
if (i == my_cpu)
continue;

while (paca[i].kexec_state < wait_state) {
while (paca_ptrs[i]->kexec_state < wait_state) {
barrier();
if (i != notified) {
printk(KERN_INFO "kexec: waiting for cpu %d "
"(physical %d) to enter %i state\n",
i, paca[i].hw_cpu_id, wait_state);
i, paca_ptrs[i]->hw_cpu_id, wait_state);
notified = i;
}
}
Expand Down Expand Up @@ -327,8 +328,7 @@ void default_machine_kexec(struct kimage *image)
*/
memcpy(&kexec_paca, get_paca(), sizeof(struct paca_struct));
kexec_paca.data_offset = 0xedeaddeadeeeeeeeUL;
paca = (struct paca_struct *)RELOC_HIDE(&kexec_paca, 0) -
kexec_paca.paca_index;
paca_ptrs[kexec_paca.paca_index] = &kexec_paca;
setup_paca(&kexec_paca);

/* XXX: If anyone does 'dynamic lppacas' this will also need to be
Expand Down
70 changes: 49 additions & 21 deletions arch/powerpc/kernel/paca.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ static void __init allocate_slb_shadows(int nr_cpus, int limit) { }
* processors. The processor VPD array needs one entry per physical
* processor (not thread).
*/
struct paca_struct *paca;
EXPORT_SYMBOL(paca);
struct paca_struct **paca_ptrs __read_mostly;
EXPORT_SYMBOL(paca_ptrs);

void __init initialise_paca(struct paca_struct *new_paca, int cpu)
{
Expand Down Expand Up @@ -213,11 +213,13 @@ void setup_paca(struct paca_struct *new_paca)

}

static int __initdata paca_size;
static int __initdata paca_nr_cpu_ids;
static int __initdata paca_ptrs_size;

void __init allocate_pacas(void)
{
u64 limit;
unsigned long size = 0;
int cpu;

#ifdef CONFIG_PPC_BOOK3S_64
Expand All @@ -230,40 +232,66 @@ void __init allocate_pacas(void)
limit = ppc64_rma_size;
#endif

paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpu_ids);
paca_nr_cpu_ids = nr_cpu_ids;

paca = __va(memblock_alloc_base(paca_size, PAGE_SIZE, limit));
memset(paca, 0, paca_size);
paca_ptrs_size = sizeof(struct paca_struct *) * nr_cpu_ids;
paca_ptrs = __va(memblock_alloc_base(paca_ptrs_size, 0, limit));
memset(paca_ptrs, 0, paca_ptrs_size);

printk(KERN_DEBUG "Allocated %u bytes for %u pacas at %p\n",
paca_size, nr_cpu_ids, paca);
size += paca_ptrs_size;

for (cpu = 0; cpu < nr_cpu_ids; cpu++) {
unsigned long pa;

pa = memblock_alloc_base(sizeof(struct paca_struct),
L1_CACHE_BYTES, limit);
paca_ptrs[cpu] = __va(pa);
memset(paca_ptrs[cpu], 0, sizeof(struct paca_struct));

size += sizeof(struct paca_struct);
}

printk(KERN_DEBUG "Allocated %lu bytes for %u pacas\n",
size, nr_cpu_ids);

allocate_lppacas(nr_cpu_ids, limit);

allocate_slb_shadows(nr_cpu_ids, limit);

/* Can't use for_each_*_cpu, as they aren't functional yet */
for (cpu = 0; cpu < nr_cpu_ids; cpu++)
initialise_paca(&paca[cpu], cpu);
initialise_paca(paca_ptrs[cpu], cpu);
}

void __init free_unused_pacas(void)
{
int new_size;

new_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpu_ids);

if (new_size >= paca_size)
return;

memblock_free(__pa(paca) + new_size, paca_size - new_size);

printk(KERN_DEBUG "Freed %u bytes for unused pacas\n",
paca_size - new_size);
unsigned long size = 0;
int new_ptrs_size;
int cpu;

paca_size = new_size;
for (cpu = 0; cpu < paca_nr_cpu_ids; cpu++) {
if (!cpu_possible(cpu)) {
unsigned long pa = __pa(paca_ptrs[cpu]);
memblock_free(pa, sizeof(struct paca_struct));
paca_ptrs[cpu] = NULL;
size += sizeof(struct paca_struct);
}
}

new_ptrs_size = sizeof(struct paca_struct *) * nr_cpu_ids;
if (new_ptrs_size < paca_ptrs_size) {
memblock_free(__pa(paca_ptrs) + new_ptrs_size,
paca_ptrs_size - new_ptrs_size);
size += paca_ptrs_size - new_ptrs_size;
}

if (size)
printk(KERN_DEBUG "Freed %lu bytes for unused pacas\n", size);

free_lppacas();

paca_nr_cpu_ids = nr_cpu_ids;
paca_ptrs_size = new_ptrs_size;
}

void copy_mm_to_paca(struct mm_struct *mm)
Expand Down
23 changes: 12 additions & 11 deletions arch/powerpc/kernel/setup_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ void __init setup_tlb_core_data(void)
if (cpu_first_thread_sibling(boot_cpuid) == first)
first = boot_cpuid;

paca[cpu].tcd_ptr = &paca[first].tcd;
paca_ptrs[cpu]->tcd_ptr = &paca_ptrs[first]->tcd;

/*
* If we have threads, we need either tlbsrx.
Expand Down Expand Up @@ -304,7 +304,7 @@ void __init early_setup(unsigned long dt_ptr)
early_init_devtree(__va(dt_ptr));

/* Now we know the logical id of our boot cpu, setup the paca. */
setup_paca(&paca[boot_cpuid]);
setup_paca(paca_ptrs[boot_cpuid]);
fixup_boot_paca();

/*
Expand Down Expand Up @@ -628,15 +628,15 @@ void __init exc_lvl_early_init(void)
for_each_possible_cpu(i) {
sp = memblock_alloc(THREAD_SIZE, THREAD_SIZE);
critirq_ctx[i] = (struct thread_info *)__va(sp);
paca[i].crit_kstack = __va(sp + THREAD_SIZE);
paca_ptrs[i]->crit_kstack = __va(sp + THREAD_SIZE);

sp = memblock_alloc(THREAD_SIZE, THREAD_SIZE);
dbgirq_ctx[i] = (struct thread_info *)__va(sp);
paca[i].dbg_kstack = __va(sp + THREAD_SIZE);
paca_ptrs[i]->dbg_kstack = __va(sp + THREAD_SIZE);

sp = memblock_alloc(THREAD_SIZE, THREAD_SIZE);
mcheckirq_ctx[i] = (struct thread_info *)__va(sp);
paca[i].mc_kstack = __va(sp + THREAD_SIZE);
paca_ptrs[i]->mc_kstack = __va(sp + THREAD_SIZE);
}

if (cpu_has_feature(CPU_FTR_DEBUG_LVL_EXC))
Expand Down Expand Up @@ -693,20 +693,20 @@ void __init emergency_stack_init(void)
ti = __va(memblock_alloc_base(THREAD_SIZE, THREAD_SIZE, limit));
memset(ti, 0, THREAD_SIZE);
emerg_stack_init_thread_info(ti, i);
paca[i].emergency_sp = (void *)ti + THREAD_SIZE;
paca_ptrs[i]->emergency_sp = (void *)ti + THREAD_SIZE;

#ifdef CONFIG_PPC_BOOK3S_64
/* emergency stack for NMI exception handling. */
ti = __va(memblock_alloc_base(THREAD_SIZE, THREAD_SIZE, limit));
memset(ti, 0, THREAD_SIZE);
emerg_stack_init_thread_info(ti, i);
paca[i].nmi_emergency_sp = (void *)ti + THREAD_SIZE;
paca_ptrs[i]->nmi_emergency_sp = (void *)ti + THREAD_SIZE;

/* emergency stack for machine check exception handling. */
ti = __va(memblock_alloc_base(THREAD_SIZE, THREAD_SIZE, limit));
memset(ti, 0, THREAD_SIZE);
emerg_stack_init_thread_info(ti, i);
paca[i].mc_emergency_sp = (void *)ti + THREAD_SIZE;
paca_ptrs[i]->mc_emergency_sp = (void *)ti + THREAD_SIZE;
#endif
}
}
Expand Down Expand Up @@ -762,7 +762,7 @@ void __init setup_per_cpu_areas(void)
delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
for_each_possible_cpu(cpu) {
__per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu];
paca[cpu].data_offset = __per_cpu_offset[cpu];
paca_ptrs[cpu]->data_offset = __per_cpu_offset[cpu];
}
}
#endif
Expand Down Expand Up @@ -875,8 +875,9 @@ static void init_fallback_flush(void)
memset(l1d_flush_fallback_area, 0, l1d_size * 2);

for_each_possible_cpu(cpu) {
paca[cpu].rfi_flush_fallback_area = l1d_flush_fallback_area;
paca[cpu].l1d_flush_size = l1d_size;
struct paca_struct *paca = paca_ptrs[cpu];
paca->rfi_flush_fallback_area = l1d_flush_fallback_area;
paca->l1d_flush_size = l1d_size;
}
}

Expand Down
10 changes: 5 additions & 5 deletions arch/powerpc/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ int smp_generic_kick_cpu(int nr)
* cpu_start field to become non-zero After we set cpu_start,
* the processor will continue on to secondary_start
*/
if (!paca[nr].cpu_start) {
paca[nr].cpu_start = 1;
if (!paca_ptrs[nr]->cpu_start) {
paca_ptrs[nr]->cpu_start = 1;
smp_mb();
return 0;
}
Expand Down Expand Up @@ -657,7 +657,7 @@ void smp_prepare_boot_cpu(void)
{
BUG_ON(smp_processor_id() != boot_cpuid);
#ifdef CONFIG_PPC64
paca[boot_cpuid].__current = current;
paca_ptrs[boot_cpuid]->__current = current;
#endif
set_numa_node(numa_cpu_lookup_table[boot_cpuid]);
current_set[boot_cpuid] = task_thread_info(current);
Expand Down Expand Up @@ -748,8 +748,8 @@ static void cpu_idle_thread_init(unsigned int cpu, struct task_struct *idle)
struct thread_info *ti = task_thread_info(idle);

#ifdef CONFIG_PPC64
paca[cpu].__current = idle;
paca[cpu].kstack = (unsigned long)ti + THREAD_SIZE - STACK_FRAME_OVERHEAD;
paca_ptrs[cpu]->__current = idle;
paca_ptrs[cpu]->kstack = (unsigned long)ti + THREAD_SIZE - STACK_FRAME_OVERHEAD;
#endif
ti->cpu = cpu;
secondary_ti = current_set[cpu] = ti;
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/kernel/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ void __init record_spr_defaults(void)
if (cpu_has_feature(CPU_FTR_DSCR)) {
dscr_default = mfspr(SPRN_DSCR);
for (cpu = 0; cpu < nr_cpu_ids; cpu++)
paca[cpu].dscr_default = dscr_default;
paca_ptrs[cpu]->dscr_default = dscr_default;
}
}
#endif /* CONFIG_PPC64 */
Expand Down
Loading

0 comments on commit d2e6007

Please sign in to comment.