162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * c 2001 PPC 64 Team, IBM Corp 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/smp.h> 762306a36Sopenharmony_ci#include <linux/export.h> 862306a36Sopenharmony_ci#include <linux/memblock.h> 962306a36Sopenharmony_ci#include <linux/sched/task.h> 1062306a36Sopenharmony_ci#include <linux/numa.h> 1162306a36Sopenharmony_ci#include <linux/pgtable.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <asm/lppaca.h> 1462306a36Sopenharmony_ci#include <asm/paca.h> 1562306a36Sopenharmony_ci#include <asm/sections.h> 1662306a36Sopenharmony_ci#include <asm/kexec.h> 1762306a36Sopenharmony_ci#include <asm/svm.h> 1862306a36Sopenharmony_ci#include <asm/ultravisor.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "setup.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#ifndef CONFIG_SMP 2362306a36Sopenharmony_ci#define boot_cpuid 0 2462306a36Sopenharmony_ci#endif 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic void *__init alloc_paca_data(unsigned long size, unsigned long align, 2762306a36Sopenharmony_ci unsigned long limit, int cpu) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci void *ptr; 3062306a36Sopenharmony_ci int nid; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci /* 3362306a36Sopenharmony_ci * boot_cpuid paca is allocated very early before cpu_to_node is up. 3462306a36Sopenharmony_ci * Set bottom-up mode, because the boot CPU should be on node-0, 3562306a36Sopenharmony_ci * which will put its paca in the right place. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ci if (cpu == boot_cpuid) { 3862306a36Sopenharmony_ci nid = NUMA_NO_NODE; 3962306a36Sopenharmony_ci memblock_set_bottom_up(true); 4062306a36Sopenharmony_ci } else { 4162306a36Sopenharmony_ci nid = early_cpu_to_node(cpu); 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci ptr = memblock_alloc_try_nid(size, align, MEMBLOCK_LOW_LIMIT, 4562306a36Sopenharmony_ci limit, nid); 4662306a36Sopenharmony_ci if (!ptr) 4762306a36Sopenharmony_ci panic("cannot allocate paca data"); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (cpu == boot_cpuid) 5062306a36Sopenharmony_ci memblock_set_bottom_up(false); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci return ptr; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#ifdef CONFIG_PPC_PSERIES 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define LPPACA_SIZE 0x400 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic void *__init alloc_shared_lppaca(unsigned long size, unsigned long limit, 6062306a36Sopenharmony_ci int cpu) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci size_t shared_lppaca_total_size = PAGE_ALIGN(nr_cpu_ids * LPPACA_SIZE); 6362306a36Sopenharmony_ci static unsigned long shared_lppaca_size; 6462306a36Sopenharmony_ci static void *shared_lppaca; 6562306a36Sopenharmony_ci void *ptr; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (!shared_lppaca) { 6862306a36Sopenharmony_ci memblock_set_bottom_up(true); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* 7162306a36Sopenharmony_ci * See Documentation/powerpc/ultravisor.rst for more details. 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * UV/HV data sharing is in PAGE_SIZE granularity. In order to 7462306a36Sopenharmony_ci * minimize the number of pages shared, align the allocation to 7562306a36Sopenharmony_ci * PAGE_SIZE. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ci shared_lppaca = 7862306a36Sopenharmony_ci memblock_alloc_try_nid(shared_lppaca_total_size, 7962306a36Sopenharmony_ci PAGE_SIZE, MEMBLOCK_LOW_LIMIT, 8062306a36Sopenharmony_ci limit, NUMA_NO_NODE); 8162306a36Sopenharmony_ci if (!shared_lppaca) 8262306a36Sopenharmony_ci panic("cannot allocate shared data"); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci memblock_set_bottom_up(false); 8562306a36Sopenharmony_ci uv_share_page(PHYS_PFN(__pa(shared_lppaca)), 8662306a36Sopenharmony_ci shared_lppaca_total_size >> PAGE_SHIFT); 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci ptr = shared_lppaca + shared_lppaca_size; 9062306a36Sopenharmony_ci shared_lppaca_size += size; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* 9362306a36Sopenharmony_ci * This is very early in boot, so no harm done if the kernel crashes at 9462306a36Sopenharmony_ci * this point. 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_ci BUG_ON(shared_lppaca_size > shared_lppaca_total_size); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return ptr; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/* 10262306a36Sopenharmony_ci * See asm/lppaca.h for more detail. 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * lppaca structures must must be 1kB in size, L1 cache line aligned, 10562306a36Sopenharmony_ci * and not cross 4kB boundary. A 1kB size and 1kB alignment will satisfy 10662306a36Sopenharmony_ci * these requirements. 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_cistatic inline void init_lppaca(struct lppaca *lppaca) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct lppaca) != 640); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci *lppaca = (struct lppaca) { 11362306a36Sopenharmony_ci .desc = cpu_to_be32(0xd397d781), /* "LpPa" */ 11462306a36Sopenharmony_ci .size = cpu_to_be16(LPPACA_SIZE), 11562306a36Sopenharmony_ci .fpregs_in_use = 1, 11662306a36Sopenharmony_ci .slb_count = cpu_to_be16(64), 11762306a36Sopenharmony_ci .vmxregs_in_use = 0, 11862306a36Sopenharmony_ci .page_ins = 0, }; 11962306a36Sopenharmony_ci}; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic struct lppaca * __init new_lppaca(int cpu, unsigned long limit) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct lppaca *lp; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct lppaca) > LPPACA_SIZE); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (early_cpu_has_feature(CPU_FTR_HVMODE)) 12862306a36Sopenharmony_ci return NULL; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (is_secure_guest()) 13162306a36Sopenharmony_ci lp = alloc_shared_lppaca(LPPACA_SIZE, limit, cpu); 13262306a36Sopenharmony_ci else 13362306a36Sopenharmony_ci lp = alloc_paca_data(LPPACA_SIZE, 0x400, limit, cpu); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci init_lppaca(lp); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci return lp; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci#endif /* CONFIG_PPC_PSERIES */ 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci#ifdef CONFIG_PPC_64S_HASH_MMU 14262306a36Sopenharmony_ci/* 14362306a36Sopenharmony_ci * 3 persistent SLBs are allocated here. The buffer will be zero 14462306a36Sopenharmony_ci * initially, hence will all be invaild until we actually write them. 14562306a36Sopenharmony_ci * 14662306a36Sopenharmony_ci * If you make the number of persistent SLB entries dynamic, please also 14762306a36Sopenharmony_ci * update PR KVM to flush and restore them accordingly. 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_cistatic struct slb_shadow * __init new_slb_shadow(int cpu, unsigned long limit) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct slb_shadow *s; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (cpu != boot_cpuid) { 15462306a36Sopenharmony_ci /* 15562306a36Sopenharmony_ci * Boot CPU comes here before early_radix_enabled 15662306a36Sopenharmony_ci * is parsed (e.g., for disable_radix). So allocate 15762306a36Sopenharmony_ci * always and this will be fixed up in free_unused_pacas. 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_ci if (early_radix_enabled()) 16062306a36Sopenharmony_ci return NULL; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci s = alloc_paca_data(sizeof(*s), L1_CACHE_BYTES, limit, cpu); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci s->persistent = cpu_to_be32(SLB_NUM_BOLTED); 16662306a36Sopenharmony_ci s->buffer_length = cpu_to_be32(sizeof(*s)); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return s; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci#endif /* CONFIG_PPC_64S_HASH_MMU */ 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/* The Paca is an array with one entry per processor. Each contains an 17362306a36Sopenharmony_ci * lppaca, which contains the information shared between the 17462306a36Sopenharmony_ci * hypervisor and Linux. 17562306a36Sopenharmony_ci * On systems with hardware multi-threading, there are two threads 17662306a36Sopenharmony_ci * per processor. The Paca array must contain an entry for each thread. 17762306a36Sopenharmony_ci * The VPD Areas will give a max logical processors = 2 * max physical 17862306a36Sopenharmony_ci * processors. The processor VPD array needs one entry per physical 17962306a36Sopenharmony_ci * processor (not thread). 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_cistruct paca_struct **paca_ptrs __read_mostly; 18262306a36Sopenharmony_ciEXPORT_SYMBOL(paca_ptrs); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_civoid __init initialise_paca(struct paca_struct *new_paca, int cpu) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci#ifdef CONFIG_PPC_PSERIES 18762306a36Sopenharmony_ci new_paca->lppaca_ptr = NULL; 18862306a36Sopenharmony_ci#endif 18962306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3E_64 19062306a36Sopenharmony_ci new_paca->kernel_pgd = swapper_pg_dir; 19162306a36Sopenharmony_ci#endif 19262306a36Sopenharmony_ci new_paca->lock_token = 0x8000; 19362306a36Sopenharmony_ci new_paca->paca_index = cpu; 19462306a36Sopenharmony_ci#ifndef CONFIG_PPC_KERNEL_PCREL 19562306a36Sopenharmony_ci new_paca->kernel_toc = kernel_toc_addr(); 19662306a36Sopenharmony_ci#endif 19762306a36Sopenharmony_ci new_paca->kernelbase = (unsigned long) _stext; 19862306a36Sopenharmony_ci /* Only set MSR:IR/DR when MMU is initialized */ 19962306a36Sopenharmony_ci new_paca->kernel_msr = MSR_KERNEL & ~(MSR_IR | MSR_DR); 20062306a36Sopenharmony_ci new_paca->hw_cpu_id = 0xffff; 20162306a36Sopenharmony_ci new_paca->kexec_state = KEXEC_STATE_NONE; 20262306a36Sopenharmony_ci new_paca->__current = &init_task; 20362306a36Sopenharmony_ci new_paca->data_offset = 0xfeeeeeeeeeeeeeeeULL; 20462306a36Sopenharmony_ci#ifdef CONFIG_PPC_64S_HASH_MMU 20562306a36Sopenharmony_ci new_paca->slb_shadow_ptr = NULL; 20662306a36Sopenharmony_ci#endif 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3E_64 20962306a36Sopenharmony_ci /* For now -- if we have threads this will be adjusted later */ 21062306a36Sopenharmony_ci new_paca->tcd_ptr = &new_paca->tcd; 21162306a36Sopenharmony_ci#endif 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci/* Put the paca pointer into r13 and SPRG_PACA */ 21562306a36Sopenharmony_civoid setup_paca(struct paca_struct *new_paca) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci /* Setup r13 */ 21862306a36Sopenharmony_ci local_paca = new_paca; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3E_64 22162306a36Sopenharmony_ci /* On Book3E, initialize the TLB miss exception frames */ 22262306a36Sopenharmony_ci mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb); 22362306a36Sopenharmony_ci#else 22462306a36Sopenharmony_ci /* 22562306a36Sopenharmony_ci * In HV mode, we setup both HPACA and PACA to avoid problems 22662306a36Sopenharmony_ci * if we do a GET_PACA() before the feature fixups have been 22762306a36Sopenharmony_ci * applied. 22862306a36Sopenharmony_ci * 22962306a36Sopenharmony_ci * Normally you should test against CPU_FTR_HVMODE, but CPU features 23062306a36Sopenharmony_ci * are not yet set up when we first reach here. 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci if (mfmsr() & MSR_HV) 23362306a36Sopenharmony_ci mtspr(SPRN_SPRG_HPACA, local_paca); 23462306a36Sopenharmony_ci#endif 23562306a36Sopenharmony_ci mtspr(SPRN_SPRG_PACA, local_paca); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int __initdata paca_nr_cpu_ids; 24062306a36Sopenharmony_cistatic int __initdata paca_ptrs_size; 24162306a36Sopenharmony_cistatic int __initdata paca_struct_size; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_civoid __init allocate_paca_ptrs(void) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci paca_nr_cpu_ids = nr_cpu_ids; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci paca_ptrs_size = sizeof(struct paca_struct *) * nr_cpu_ids; 24862306a36Sopenharmony_ci paca_ptrs = memblock_alloc_raw(paca_ptrs_size, SMP_CACHE_BYTES); 24962306a36Sopenharmony_ci if (!paca_ptrs) 25062306a36Sopenharmony_ci panic("Failed to allocate %d bytes for paca pointers\n", 25162306a36Sopenharmony_ci paca_ptrs_size); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci memset(paca_ptrs, 0x88, paca_ptrs_size); 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_civoid __init allocate_paca(int cpu) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci u64 limit; 25962306a36Sopenharmony_ci struct paca_struct *paca; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci BUG_ON(cpu >= paca_nr_cpu_ids); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 26462306a36Sopenharmony_ci /* 26562306a36Sopenharmony_ci * We access pacas in real mode, and cannot take SLB faults 26662306a36Sopenharmony_ci * on them when in virtual mode, so allocate them accordingly. 26762306a36Sopenharmony_ci */ 26862306a36Sopenharmony_ci limit = min(ppc64_bolted_size(), ppc64_rma_size); 26962306a36Sopenharmony_ci#else 27062306a36Sopenharmony_ci limit = ppc64_rma_size; 27162306a36Sopenharmony_ci#endif 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci paca = alloc_paca_data(sizeof(struct paca_struct), L1_CACHE_BYTES, 27462306a36Sopenharmony_ci limit, cpu); 27562306a36Sopenharmony_ci paca_ptrs[cpu] = paca; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci initialise_paca(paca, cpu); 27862306a36Sopenharmony_ci#ifdef CONFIG_PPC_PSERIES 27962306a36Sopenharmony_ci paca->lppaca_ptr = new_lppaca(cpu, limit); 28062306a36Sopenharmony_ci#endif 28162306a36Sopenharmony_ci#ifdef CONFIG_PPC_64S_HASH_MMU 28262306a36Sopenharmony_ci paca->slb_shadow_ptr = new_slb_shadow(cpu, limit); 28362306a36Sopenharmony_ci#endif 28462306a36Sopenharmony_ci paca_struct_size += sizeof(struct paca_struct); 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_civoid __init free_unused_pacas(void) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci int new_ptrs_size; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci new_ptrs_size = sizeof(struct paca_struct *) * nr_cpu_ids; 29262306a36Sopenharmony_ci if (new_ptrs_size < paca_ptrs_size) 29362306a36Sopenharmony_ci memblock_phys_free(__pa(paca_ptrs) + new_ptrs_size, 29462306a36Sopenharmony_ci paca_ptrs_size - new_ptrs_size); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci paca_nr_cpu_ids = nr_cpu_ids; 29762306a36Sopenharmony_ci paca_ptrs_size = new_ptrs_size; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci#ifdef CONFIG_PPC_64S_HASH_MMU 30062306a36Sopenharmony_ci if (early_radix_enabled()) { 30162306a36Sopenharmony_ci /* Ugly fixup, see new_slb_shadow() */ 30262306a36Sopenharmony_ci memblock_phys_free(__pa(paca_ptrs[boot_cpuid]->slb_shadow_ptr), 30362306a36Sopenharmony_ci sizeof(struct slb_shadow)); 30462306a36Sopenharmony_ci paca_ptrs[boot_cpuid]->slb_shadow_ptr = NULL; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci#endif 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci printk(KERN_DEBUG "Allocated %u bytes for %u pacas\n", 30962306a36Sopenharmony_ci paca_ptrs_size + paca_struct_size, nr_cpu_ids); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci#ifdef CONFIG_PPC_64S_HASH_MMU 31362306a36Sopenharmony_civoid copy_mm_to_paca(struct mm_struct *mm) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci mm_context_t *context = &mm->context; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci VM_BUG_ON(!mm_ctx_slb_addr_limit(context)); 31862306a36Sopenharmony_ci memcpy(&get_paca()->mm_ctx_low_slices_psize, mm_ctx_low_slices(context), 31962306a36Sopenharmony_ci LOW_SLICE_ARRAY_SZ); 32062306a36Sopenharmony_ci memcpy(&get_paca()->mm_ctx_high_slices_psize, mm_ctx_high_slices(context), 32162306a36Sopenharmony_ci TASK_SLICE_ARRAY_SZ(context)); 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci#endif /* CONFIG_PPC_64S_HASH_MMU */ 324