#include <linux/bootmem.h>
#include <linux/pci.h>
#include <linux/lockdep.h>
-#include <linux/lmb.h>
+#include <linux/memblock.h>
#include <asm/io.h>
#include <asm/kdump.h>
#include <asm/prom.h>
#include <asm/xmon.h>
#include <asm/udbg.h>
#include <asm/kexec.h>
+#include <asm/mmu_context.h>
#include "setup.h"
#define DBG(fmt...)
#endif
-int have_of = 1;
int boot_cpuid = 0;
u64 ppc64_pft_size;
#define check_smt_enabled()
#endif /* CONFIG_SMP */
-/* Put the paca pointer into r13 and SPRG3 */
-void __init setup_paca(int cpu)
+/* Put the paca pointer into r13 and SPRG_PACA */
+static void __init setup_paca(struct paca_struct *new_paca)
{
- local_paca = &paca[cpu];
- mtspr(SPRN_SPRG3, local_paca);
+ local_paca = new_paca;
+ mtspr(SPRN_SPRG_PACA, local_paca);
+#ifdef CONFIG_PPC_BOOK3E
+ mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb);
+#endif
}
/*
* the CPU that ignores the top 2 bits of the address in real
* mode so we can access kernel globals normally provided we
* only toy with things in the RMO region. From here, we do
- * some early parsing of the device-tree to setup out LMB
+ * some early parsing of the device-tree to setup out MEMBLOCK
* data structures, and allocate & initialize the hash table
* and segment tables so we can start running with translation
* enabled.
{
/* -------- printk is _NOT_ safe to use here ! ------- */
- /* Fill in any unititialised pacas */
- initialise_pacas();
-
/* Identify CPU type */
identify_cpu(0, mfspr(SPRN_PVR));
/* Assume we're on cpu 0 for now. Don't write to the paca yet! */
- setup_paca(0);
+ initialise_paca(&boot_paca, 0);
+ setup_paca(&boot_paca);
/* Initialize lockdep early or else spinlocks will blow */
lockdep_init();
early_init_devtree(__va(dt_ptr));
/* Now we know the logical id of our boot cpu, setup the paca. */
- setup_paca(boot_cpuid);
+ setup_paca(&paca[boot_cpuid]);
/* Fix up paca fields required for the boot cpu */
get_paca()->cpu_start = 1;
- get_paca()->stab_real = __pa((u64)&initial_stab);
- get_paca()->stab_addr = (u64)&initial_stab;
/* Probe the machine type */
probe_machine();
DBG("Found, Initializing memory management...\n");
- /*
- * Initialize the MMU Hash table and create the linear mapping
- * of memory. Has to be done before stab/slb initialization as
- * this is currently where the page size encoding is obtained
- */
- htab_initialize();
-
- /*
- * Initialize stab / SLB management except on iSeries
- */
- if (cpu_has_feature(CPU_FTR_SLB))
- slb_initialize();
- else if (!firmware_has_feature(FW_FEATURE_ISERIES))
- stab_initialize(get_paca()->stab_real);
+ /* Initialize the hash table or TLB handling */
+ early_init_mmu();
DBG(" <- early_setup()\n");
}
#ifdef CONFIG_SMP
void early_setup_secondary(void)
{
- struct paca_struct *lpaca = get_paca();
-
/* Mark interrupts enabled in PACA */
- lpaca->soft_enabled = 0;
-
- /* Initialize hash table for that CPU */
- htab_initialize_secondary();
+ get_paca()->soft_enabled = 0;
- /* Initialize STAB/SLB. We use a virtual address as it works
- * in real mode on pSeries and we want a virutal address on
- * iSeries anyway
- */
- if (cpu_has_feature(CPU_FTR_SLB))
- slb_initialize();
- else
- stab_initialize(lpaca->stab_addr);
+ /* Initialize the hash table or TLB handling */
+ early_init_mmu_secondary();
}
#endif /* CONFIG_SMP */
#if defined(CONFIG_SMP) || defined(CONFIG_KEXEC)
void smp_release_cpus(void)
{
- extern unsigned long __secondary_hold_spinloop;
unsigned long *ptr;
DBG(" -> smp_release_cpus()\n");
* all now so they can start to spin on their individual paca
* spinloops. For non SMP kernels, the secondary cpus never get out
* of the common spinloop.
- * This is useless but harmless on iSeries, secondaries are already
- * waiting on their paca spinloops. */
+ */
ptr = (unsigned long *)((unsigned long)&__secondary_hold_spinloop
- PHYSICAL_START);
- *ptr = 1;
+ *ptr = __pa(generic_secondary_smp_init);
mb();
DBG(" <- smp_release_cpus()\n");
*/
do_feature_fixups(cur_cpu_spec->cpu_features,
&__start___ftr_fixup, &__stop___ftr_fixup);
+ do_feature_fixups(cur_cpu_spec->mmu_features,
+ &__start___mmu_ftr_fixup, &__stop___mmu_ftr_fixup);
do_feature_fixups(powerpc_firmware_features,
&__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
+ do_lwsync_fixups(cur_cpu_spec->cpu_features,
+ &__start___lwsync_fixup, &__stop___lwsync_fixup);
/*
* Unflatten the device-tree passed by prom_init or kexec
*/
initialize_cache_info();
- /*
- * Initialize irq remapping subsystem
- */
- irq_early_init();
-
#ifdef CONFIG_PPC_RTAS
/*
* Initialize RTAS if available
printk("Starting Linux PPC64 %s\n", init_utsname()->version);
printk("-----------------------------------------------------\n");
- printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size);
- printk("physicalMemorySize = 0x%lx\n", lmb_phys_mem_size());
+ printk("ppc64_pft_size = 0x%llx\n", ppc64_pft_size);
+ printk("physicalMemorySize = 0x%llx\n", memblock_phys_mem_size());
if (ppc64_caches.dline_size != 0x80)
printk("ppc64_caches.dcache_line_size = 0x%x\n",
ppc64_caches.dline_size);
if (ppc64_caches.iline_size != 0x80)
printk("ppc64_caches.icache_line_size = 0x%x\n",
ppc64_caches.iline_size);
+#ifdef CONFIG_PPC_STD_MMU_64
if (htab_address)
printk("htab_address = 0x%p\n", htab_address);
printk("htab_hash_mask = 0x%lx\n", htab_hash_mask);
-#if PHYSICAL_START > 0
- printk("physical_start = 0x%lx\n", PHYSICAL_START);
-#endif
+#endif /* CONFIG_PPC_STD_MMU_64 */
+ if (PHYSICAL_START > 0)
+ printk("physical_start = 0x%llx\n",
+ (unsigned long long)PHYSICAL_START);
printk("-----------------------------------------------------\n");
DBG(" <- setup_system()\n");
}
-#ifdef CONFIG_IRQSTACKS
+static u64 slb0_limit(void)
+{
+ if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) {
+ return 1UL << SID_SHIFT_1T;
+ }
+ return 1UL << SID_SHIFT;
+}
+
static void __init irqstack_early_init(void)
{
+ u64 limit = slb0_limit();
unsigned int i;
/*
*/
for_each_possible_cpu(i) {
softirq_ctx[i] = (struct thread_info *)
- __va(lmb_alloc_base(THREAD_SIZE,
- THREAD_SIZE, 0x10000000));
+ __va(memblock_alloc_base(THREAD_SIZE,
+ THREAD_SIZE, limit));
hardirq_ctx[i] = (struct thread_info *)
- __va(lmb_alloc_base(THREAD_SIZE,
- THREAD_SIZE, 0x10000000));
+ __va(memblock_alloc_base(THREAD_SIZE,
+ THREAD_SIZE, limit));
+ }
+}
+
+#ifdef CONFIG_PPC_BOOK3E
+static void __init exc_lvl_early_init(void)
+{
+ unsigned int i;
+
+ for_each_possible_cpu(i) {
+ critirq_ctx[i] = (struct thread_info *)
+ __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
+ dbgirq_ctx[i] = (struct thread_info *)
+ __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
+ mcheckirq_ctx[i] = (struct thread_info *)
+ __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
}
}
#else
-#define irqstack_early_init()
+#define exc_lvl_early_init()
#endif
/*
*/
static void __init emergency_stack_init(void)
{
- unsigned long limit;
+ u64 limit;
unsigned int i;
/*
* bringup, we need to get at them in real mode. This means they
* must also be within the RMO region.
*/
- limit = min(0x10000000UL, lmb.rmo_size);
+ limit = min(slb0_limit(), ppc64_rma_size);
for_each_possible_cpu(i) {
unsigned long sp;
- sp = lmb_alloc_base(THREAD_SIZE, THREAD_SIZE, limit);
+ sp = memblock_alloc_base(THREAD_SIZE, THREAD_SIZE, limit);
sp += THREAD_SIZE;
paca[i].emergency_sp = __va(sp);
}
init_mm.brk = klimit;
irqstack_early_init();
+ exc_lvl_early_init();
emergency_stack_init();
+#ifdef CONFIG_PPC_STD_MMU_64
stabs_alloc();
-
+#endif
/* set up the bootmem stuff with available memory */
do_init_bootmem();
sparse_init();
ppc_md.setup_arch();
paging_init();
+
+ /* Initialize the MMU context management stuff */
+ mmu_context_init();
+
ppc64_boot_msg(0x15, "Setup Done");
}
printk("[boot]%04x %s\n", src, msg);
}
-/* Print a termination message (print only -- does not stop the kernel) */
-void ppc64_terminate_msg(unsigned int src, const char *msg)
+#ifdef CONFIG_SMP
+#define PCPU_DYN_SIZE ()
+
+static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size, size_t align)
+{
+ return __alloc_bootmem_node(NODE_DATA(cpu_to_node(cpu)), size, align,
+ __pa(MAX_DMA_ADDRESS));
+}
+
+static void __init pcpu_fc_free(void *ptr, size_t size)
{
- ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_TERM_MESSAGE|src, msg);
- printk("[terminate]%04x %s\n", src, msg);
+ free_bootmem(__pa(ptr), size);
}
-void cpu_die(void)
+static int pcpu_cpu_distance(unsigned int from, unsigned int to)
{
- if (ppc_md.cpu_die)
- ppc_md.cpu_die();
+ if (cpu_to_node(from) == cpu_to_node(to))
+ return LOCAL_DISTANCE;
+ else
+ return REMOTE_DISTANCE;
}
-#ifdef CONFIG_SMP
void __init setup_per_cpu_areas(void)
{
- int i;
- unsigned long size;
- char *ptr;
-
- /* Copy section for each CPU (we discard the original) */
- size = ALIGN(__per_cpu_end - __per_cpu_start, PAGE_SIZE);
-#ifdef CONFIG_MODULES
- if (size < PERCPU_ENOUGH_ROOM)
- size = PERCPU_ENOUGH_ROOM;
-#endif
+ const size_t dyn_size = PERCPU_MODULE_RESERVE + PERCPU_DYNAMIC_RESERVE;
+ size_t atom_size;
+ unsigned long delta;
+ unsigned int cpu;
+ int rc;
- for_each_possible_cpu(i) {
- ptr = alloc_bootmem_pages_node(NODE_DATA(cpu_to_node(i)), size);
- if (!ptr)
- panic("Cannot allocate cpu data for CPU %d\n", i);
+ /*
+ * Linear mapping is one of 4K, 1M and 16M. For 4K, no need
+ * to group units. For larger mappings, use 1M atom which
+ * should be large enough to contain a number of units.
+ */
+ if (mmu_linear_psize == MMU_PAGE_4K)
+ atom_size = PAGE_SIZE;
+ else
+ atom_size = 1 << 20;
- paca[i].data_offset = ptr - __per_cpu_start;
- memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
- }
+ rc = pcpu_embed_first_chunk(0, dyn_size, atom_size, pcpu_cpu_distance,
+ pcpu_fc_alloc, pcpu_fc_free);
+ if (rc < 0)
+ panic("cannot initialize percpu area (err=%d)", rc);
- /* Now that per_cpu is setup, initialize cpu_sibling_map */
- smp_setup_cpu_sibling_map();
+ delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
+ for_each_possible_cpu(cpu)
+ paca[cpu].data_offset = delta + pcpu_unit_offsets[cpu];
}
#endif