From 5dbfb3ccb31e56a2858e8dc87812ff941f2e1f91 Mon Sep 17 00:00:00 2001 From: mrg Date: Sun, 31 May 2009 20:09:44 +0000 Subject: [PATCH] - bump the size of cpus[] by one, so we have a NULL pointer at the end, from tsutsui - for MP kernels, copy the loop to find the bootcpu in mainbus_attach() into getcacheinfo_obp() so we can get cache properties on the bootcpu before calling main() - in getcpuinfo(), move the call of getmid() before the call to getcacheinfo() so that the above change to getcacheinfo_obp() can work - move the struct cpu_info setup to the end of the initial kernel page setup and don't access this space until after we have switched to the kernel pagetables - revive most of the old CPUINFO_VA alignment/congruency code from the old alloc_cpuinfo_global_va() function, and ensure that all cpuinfo structures are sanely aligned. this makes hypersparc work again - introduce a new way to free the wasted pages back to UVM, as we can't simply uvm_unmap() them this early in bootstrap i believe that the first used cpuinfo_data page is still being wasted, but i haven't checked. --- sys/arch/sparc/sparc/cpu.c | 41 ++++++++-- sys/arch/sparc/sparc/cpuvar.h | 8 +- sys/arch/sparc/sparc/pmap.c | 139 +++++++++++++++++++++++++--------- 3 files changed, 145 insertions(+), 43 deletions(-) diff --git a/sys/arch/sparc/sparc/cpu.c b/sys/arch/sparc/sparc/cpu.c index 424362e1fe25..ffc4ebd56e7a 100644 --- a/sys/arch/sparc/sparc/cpu.c +++ b/sys/arch/sparc/sparc/cpu.c @@ -1,4 +1,4 @@ -/* $NetBSD: cpu.c,v 1.216 2009/05/30 01:19:29 mrg Exp $ */ +/* $NetBSD: cpu.c,v 1.217 2009/05/31 20:09:44 mrg Exp $ */ /* * Copyright (c) 1996 @@ -52,7 +52,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.216 2009/05/30 01:19:29 mrg Exp $"); +__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.217 2009/05/31 20:09:44 mrg Exp $"); #include "opt_multiprocessor.h" #include "opt_lockdebug.h" @@ -102,7 +102,7 @@ char cpu_model[100]; /* machine model (primary CPU) */ extern char machine_model[]; int sparc_ncpus; /* # of CPUs detected by PROM */ -struct cpu_info *cpus[_MAXNCPU]; /* we only support 4 CPUs. */ +struct cpu_info *cpus[_MAXNCPU+1]; /* we only support 4 CPUs. */ /* The CPU configuration driver. */ static void cpu_mainbus_attach(struct device *, struct device *, void *); @@ -1123,6 +1123,35 @@ getcacheinfo_obp(struct cpu_info *sc, int node) struct cacheinfo *ci = &sc->cacheinfo; int i, l; +#if defined(MULTIPROCESSOR) + /* + * We really really want the cache info early for MP systems, + * so figure out the boot node, if we can. + * + * XXX this loop stolen from mainbus_attach() + */ + if (node == 0 && CPU_ISSUN4M && bootmid != 0) { + const char *cp; + char namebuf[32]; + int mid, node2; + + for (node2 = firstchild(findroot()); + node2; + node2 = nextsibling(node2)) { + cp = prom_getpropstringA(node2, "device_type", + namebuf, sizeof namebuf); + if (strcmp(cp, "cpu") != 0) + continue; + + mid = prom_getpropint(node2, "mid", -1); + if (mid == bootmid) { + node = node2; + break; + } + } + } +#endif + if (node == 0) /* Bootstrapping */ return; @@ -1862,6 +1891,9 @@ getcpuinfo(struct cpu_info *sc, int node) if (sc->cacheinfo.c_vactype == VAC_UNKNOWN) sc->cacheinfo.c_vactype = mp->minfo->vactype; + if (sc->master && mp->minfo->getmid != NULL) + bootmid = mp->minfo->getmid(); + mp->minfo->getcacheinfo(sc, node); if (node && sc->hz == 0 && !CPU_ISSUN4/*XXX*/) { @@ -1875,9 +1907,6 @@ getcpuinfo(struct cpu_info *sc, int node) } } - if (sc->master && mp->minfo->getmid != NULL) - bootmid = mp->minfo->getmid(); - /* * Copy CPU/MMU/Cache specific routines into cpu_info. */ diff --git a/sys/arch/sparc/sparc/cpuvar.h b/sys/arch/sparc/sparc/cpuvar.h index 4752c0e758dd..21d1397f83e7 100644 --- a/sys/arch/sparc/sparc/cpuvar.h +++ b/sys/arch/sparc/sparc/cpuvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: cpuvar.h,v 1.78 2009/05/27 02:19:49 mrg Exp $ */ +/* $NetBSD: cpuvar.h,v 1.79 2009/05/31 20:09:44 mrg Exp $ */ /* * Copyright (c) 1996 The NetBSD Foundation, Inc. @@ -325,6 +325,12 @@ struct cpu_info { /*bus_space_handle_t*/ long ci_mxccregs; u_int ci_tt; /* Last trap (if tracing) */ + + /* + * Start/End VA's of this cpu_info region; we upload the other pages + * in this region that aren't part of the cpu_info to uvm. + */ + vaddr_t ci_free_sva1, ci_free_eva1, ci_free_sva2, ci_free_eva2; }; /* diff --git a/sys/arch/sparc/sparc/pmap.c b/sys/arch/sparc/sparc/pmap.c index 589f6715c503..e8c29060f314 100644 --- a/sys/arch/sparc/sparc/pmap.c +++ b/sys/arch/sparc/sparc/pmap.c @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.c,v 1.329 2009/05/27 02:19:50 mrg Exp $ */ +/* $NetBSD: pmap.c,v 1.330 2009/05/31 20:09:44 mrg Exp $ */ /* * Copyright (c) 1996 @@ -56,7 +56,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.329 2009/05/27 02:19:50 mrg Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.330 2009/05/31 20:09:44 mrg Exp $"); #include "opt_ddb.h" #include "opt_kgdb.h" @@ -1148,6 +1148,28 @@ pmap_page_upload(void) atop(start), atop(end), VM_FREELIST_DEFAULT); } + +#if defined(MULTIPROCESSOR) + { + CPU_INFO_ITERATOR cpunum; + struct cpu_info *cpi; + + for (CPU_INFO_FOREACH(cpunum, cpi)) { + if (cpi->ci_free_sva1) + uvm_page_physload(atop(PMAP_BOOTSTRAP_VA2PA(cpi->ci_free_sva1)), + atop(PMAP_BOOTSTRAP_VA2PA(cpi->ci_free_eva1)), + atop(PMAP_BOOTSTRAP_VA2PA(cpi->ci_free_sva1)), + atop(PMAP_BOOTSTRAP_VA2PA(cpi->ci_free_eva1)), + VM_FREELIST_DEFAULT); + if (cpi->ci_free_sva2) + uvm_page_physload(atop(PMAP_BOOTSTRAP_VA2PA(cpi->ci_free_sva2)), + atop(PMAP_BOOTSTRAP_VA2PA(cpi->ci_free_eva2)), + atop(PMAP_BOOTSTRAP_VA2PA(cpi->ci_free_sva2)), + atop(PMAP_BOOTSTRAP_VA2PA(cpi->ci_free_eva2)), + VM_FREELIST_DEFAULT); + } + } +#endif } /* @@ -3467,8 +3489,11 @@ pmap_bootstrap4m(void *top) vaddr_t va; #ifdef MULTIPROCESSOR vsize_t off; - size_t cpuinfo_len; + size_t cpuinfo_len = sizeof(struct cpu_info); uint8_t *cpuinfo_data; + int align = PAGE_SIZE; + vaddr_t sva, cpuinfo_va; + vsize_t sz; #endif /* @@ -3502,22 +3527,7 @@ pmap_bootstrap4m(void *top) */ p = (vaddr_t)top; -#if defined(MULTIPROCESSOR) - /* - * allocate the rest of the cpu_info{} area. note we waste the - * first one to get a VA space. - */ - cpuinfo_len = ((sizeof(struct cpu_info) + NBPG - 1) & ~PGOFSET); - if (sparc_ncpus > 1) { - p = (p + NBPG - 1) & ~PGOFSET; - cpuinfo_data = (uint8_t *)p; - p += (cpuinfo_len * sparc_ncpus); - - /* XXX we waste the first one */ - memset(cpuinfo_data + cpuinfo_len, 0, cpuinfo_len * (sparc_ncpus - 1)); - } else - cpuinfo_data = (uint8_t *)CPUINFO_VA; -#endif + p = (p + NBPG - 1) & ~PGOFSET; /* * Intialize the kernel pmap. @@ -3616,6 +3626,35 @@ pmap_bootstrap4m(void *top) p = (p + NBPG - 1) & ~PGOFSET; pagetables_end = p; +#if defined(MULTIPROCESSOR) + /* + * Allocate aligned KVA. `cpuinfo' resides at a fixed virtual + * address. Since we need to access an other CPU's cpuinfo + * structure occasionally, this must be done at a virtual address + * that's cache congruent to the fixed address CPUINFO_VA. + * + * NOTE: we're using the cache properties of the boot CPU to + * determine the alignment (XXX). + */ + if (sparc_ncpus > 1) { + if (CACHEINFO.c_totalsize > align) { + /* Need a power of two */ + while (align <= CACHEINFO.c_totalsize) + align <<= 1; + align >>= 1; + } + sz = sizeof(struct cpu_info); + + sz = (sz + PAGE_SIZE - 1) & -PAGE_SIZE; + cpuinfo_len = sz + align - PAGE_SIZE; + + /* Grab as much space as we need */ + cpuinfo_data = (uint8_t *)p; + p += (cpuinfo_len * sparc_ncpus); + } else + cpuinfo_data = (uint8_t *)CPUINFO_VA; +#endif + avail_start = PMAP_BOOTSTRAP_VA2PA(p); /* @@ -3798,35 +3837,63 @@ pmap_bootstrap4m(void *top) */ mmu_install_tables(&cpuinfo); -#ifdef MULTIPROCESSOR +#if defined(MULTIPROCESSOR) /* * Initialise any cpu-specific data now. */ cpu_init_system(); - /* - * Remap cpu0 from CPUINFO_VA to the new correct value, wasting the - * backing page we allocated above XXX. - */ - for (off = 0, va = (vaddr_t)cpuinfo_data; - sparc_ncpus > 1 && off < sizeof(struct cpu_info); - va += NBPG, off += NBPG) { - paddr_t pa = PMAP_BOOTSTRAP_VA2PA(CPUINFO_VA + off); - prom_printf("going to pmap_kenter_pa(va=%p, pa=%p)\n", va, pa); - pmap_kremove(va, NBPG); - pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE); - cache_flush_page(va, 0); - cache_flush_page(CPUINFO_VA, 0); - } - /* * Setup the cpus[] array and the ci_self links. */ prom_printf("setting cpus self reference\n"); for (i = 0; i < sparc_ncpus; i++) { - cpus[i] = (struct cpu_info *)(cpuinfo_data + (cpuinfo_len * i)); + sva = (vaddr_t) (cpuinfo_data + (cpuinfo_len * i)); + cpuinfo_va = sva + + (((CPUINFO_VA & (align - 1)) + align - sva) & (align - 1)); + + /* + * Either remap from CPUINFO_VA to the new correct value + * or clear out this cpuinfo. + */ + if (i == 0) { + for (off = 0, va = cpuinfo_va; + sparc_ncpus > 1 && off < sizeof(struct cpu_info); + va += NBPG, off += NBPG) { + paddr_t pa = + PMAP_BOOTSTRAP_VA2PA(CPUINFO_VA + off); + + prom_printf("going to pmap_kenter_pa" + "(va=%p, pa=%p)\n", va, pa); + pmap_kremove(va, NBPG); + pmap_kenter_pa(va, pa, + VM_PROT_READ | VM_PROT_WRITE); + } + + } else + memset((void *)cpuinfo_va, 0, sizeof(struct cpu_info)); + + cpus[i] = (struct cpu_info *)cpuinfo_va; cpus[i]->ci_self = cpus[i]; prom_printf("set cpu%d ci_self address: %p\n", i, cpus[i]); + + /* Unmap and prepare to return unused pages */ + if (cpuinfo_va != sva) { + cpus[i]->ci_free_sva1 = sva; + cpus[i]->ci_free_eva1 = cpuinfo_va; + for (va = cpus[i]->ci_free_sva1; + va < cpus[i]->ci_free_eva1; + va += NBPG) + setpte4m(va, 0); + } + if (cpuinfo_va + sz != sva + cpuinfo_len) { + cpus[i]->ci_free_sva2 = cpuinfo_va + sz; + cpus[i]->ci_free_eva2 = sva + cpuinfo_len; + for (va = cpus[i]->ci_free_sva2; + va < cpus[i]->ci_free_eva2; + va += NBPG) + setpte4m(va, 0); + } } #else cpus[0] = (struct cpu_info *)CPUINFO_VA;