diff options
author | Jason Beloro <Jason.Beloro@Sun.COM> | 2009-07-16 18:10:57 -0700 |
---|---|---|
committer | Jason Beloro <Jason.Beloro@Sun.COM> | 2009-07-16 18:10:57 -0700 |
commit | 9853d9e82e7a067a2b88dae2fd257207e6be5f94 (patch) | |
tree | 83474d6da1693101c62f3f18d7588cd30fb953c4 /usr/src/uts/sun4v/promif | |
parent | f94275ce205810a201404c5f35f4cc96057022b1 (diff) | |
download | illumos-joyent-9853d9e82e7a067a2b88dae2fd257207e6be5f94.tar.gz |
FWARC 2008/540 Memory DR Domain Service
FWARC 2009/300 CPU MD node property for real address bits
6720954 add memory dr feature to ldoms
6742779 fsflush_do_pages() may incorrectly skip constituent file large pages
Diffstat (limited to 'usr/src/uts/sun4v/promif')
-rw-r--r-- | usr/src/uts/sun4v/promif/promif_emul.c | 188 |
1 files changed, 184 insertions, 4 deletions
diff --git a/usr/src/uts/sun4v/promif/promif_emul.c b/usr/src/uts/sun4v/promif/promif_emul.c index 192ba5e2b3..97268b4777 100644 --- a/usr/src/uts/sun4v/promif/promif_emul.c +++ b/usr/src/uts/sun4v/promif/promif_emul.c @@ -20,12 +20,10 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/promif_impl.h> #include <sys/machsystm.h> #include <sys/lpad.h> @@ -37,19 +35,39 @@ #include <sys/hypervisor_api.h> #include <sys/mdesc.h> #include <sys/mach_descrip.h> +#include <sys/cpu_module.h> #ifndef _KMDB +#include <sys/pte.h> +#include <vm/hat_sfmmu.h> +#include <sys/memlist_impl.h> + static processorid_t cif_cpu; static struct translation *cif_prom_trans; static size_t cif_prom_ntrans; int cif_cpu_mp_ready; int (*prom_cif_handler)(void *) = NULL; + +extern struct memlist *phys_avail; +extern struct vnode prom_ppages; +extern void kdi_tlb_page_unlock(caddr_t, int); + +#define COMBINE(hi, lo) (((uint64_t)(uint32_t)(hi) << 32) | (uint32_t)(lo)) +#define OFW_PT_START_ADDR 0xfffffffc00000000 /* OBP PT start */ +#define OFW_PT_END_ADDR 0xffffffffffffffff /* OBP PT end */ + +#define PROM_ADDR(a) (((a) >= OFW_START_ADDR && (a) <= OFW_END_ADDR) || \ + ((a) >= OFW_PT_START_ADDR && (a) <= OFW_PT_END_ADDR)) #endif #ifdef DEBUG uint_t cif_debug; -#endif /* DEBUG */ +int prom_free_debug; +#define PMFREE_DEBUG(args...) if (prom_free_debug) printf(args) +#else +#define PMFREE_DEBUG(args...) +#endif extern int (*cif_handler)(void *); @@ -171,6 +189,161 @@ cif_init(char *pgmname, caddr_t root, ihandle_t in, ihandle_t out, #else +static struct translation * +read_prom_mappings(size_t *ntransp) +{ + char *prop = "translations"; + pnode_t node; + size_t translen; + ihandle_t immu; + struct translation *transroot; + + *ntransp = 0; + + /* + * the "translations" property is associated with the mmu node + */ + if ((immu = prom_mmu_ihandle()) == (ihandle_t)-1) { + PMFREE_DEBUG("no mmu ihandle"); + return (NULL); + } + node = (pnode_t)prom_getphandle(immu); + if (node == OBP_NONODE || node == OBP_BADNODE) { + PMFREE_DEBUG("no mmu node"); + return (NULL); + } + + if ((translen = prom_getproplen(node, prop)) == -1) { + PMFREE_DEBUG("no translations property"); + return (NULL); + } + transroot = (struct translation *)kmem_zalloc(translen, KM_SLEEP); + + if (prom_getprop(node, prop, (caddr_t)transroot) == -1) { + PMFREE_DEBUG("translations getprop failed"); + kmem_free(transroot, translen); + return (NULL); + } + *ntransp = translen / sizeof (*transroot); + + return (transroot); +} + +static void +unmap_prom_mappings(struct translation *transroot, size_t ntransroot) +{ + int i, j, rv; + int npgs, nunmapped, nfreed, nskipped; + char *p; + tte_t tte; + pfn_t pfn; + page_t *pp; + uint64_t vaddr; + struct translation *promt; + cpuset_t other_cpus; + + /* + * During startup isa_list is allocated in OBP address space + * so it needs to be re-allocated in kernel address space + * before OBP memory is unmapped. + * + * see cpu_setup_common(). + */ + p = kmem_zalloc(strlen(isa_list) + 1, KM_SLEEP); + (void) strcpy(p, isa_list); + isa_list = p; + + nfreed = 0; + nunmapped = 0; + nskipped = 0; + + for (i = 0, promt = transroot; i < ntransroot; i++, promt++) { + ASSERT(promt->tte_hi != 0); + ASSERT32(promt->virt_hi == 0 && promt->size_hi == 0); + + vaddr = COMBINE(promt->virt_hi, promt->virt_lo); + + if (!PROM_ADDR(vaddr)) { + nskipped++; + continue; + } + + npgs = mmu_btopr(COMBINE(promt->size_hi, promt->size_lo)); + + if (npgs > 1) { + PMFREE_DEBUG("large trans vaddr=0x%lx, npgs=%d\n", + vaddr, npgs); + } + for (j = 0; j < npgs; j++) { + + pfn = sfmmu_vatopfn((caddr_t)vaddr, KHATID, &tte); + + if (pfn == PFN_INVALID) { + tte.tte_inthi = promt->tte_hi; + tte.tte_intlo = promt->tte_lo; + pfn = TTE_TO_PFN((caddr_t)COMBINE( + promt->virt_hi, promt->virt_lo), &tte); + PMFREE_DEBUG( + "no mapping for vaddr=0x%lx (opfn=0x%lx)\n", + vaddr, pfn); + break; + } + ASSERT(!TTE_IS_LOCKED(&tte)); + ASSERT(TTE_IS_8K(&tte)); + + /* + * Unload the current mapping for the page and + * if it is the last mapping, free the page. + */ + pp = page_numtopp_nolock(pfn); + PMFREE_DEBUG("unmap vaddr=0x%lx pfn=0x%lx pp=0x%p", + vaddr, pfn, (void *)pp); + ASSERT(pp); + ASSERT(PAGE_EXCL(pp)); + ASSERT(PP_ISNORELOC(pp)); + ASSERT(!PP_ISFREE(pp)); + ASSERT(page_find(&prom_ppages, pfn)); + ASSERT(page_get_pagecnt(pp->p_szc) == 1); + + hat_unload(kas.a_hat, (caddr_t)vaddr, PAGESIZE, + HAT_UNLOAD_UNLOCK); + + if (pp->p_mapping) { + PMFREE_DEBUG(" skip\n"); + } else { + PP_CLRNORELOC(pp); + page_destroy(pp, 0); + memlist_write_lock(); + rv = memlist_add_span(pfn << PAGESHIFT, + PAGESIZE, &phys_avail); + ASSERT(rv == MEML_SPANOP_OK); + memlist_write_unlock(); + PMFREE_DEBUG(" free\n"); + nfreed++; + } + nunmapped++; + vaddr += PAGESIZE; + } + } + + if (transroot) { + PMFREE_DEBUG("nunmapped=%d nfreed=%d nskipped=%d\n", + nunmapped, nfreed, nskipped); + kmem_free(transroot, ntransroot * sizeof (*transroot)); + } + + /* + * Unload OBP permanent mappings. + */ + kdi_tlb_page_unlock((caddr_t)OFW_START_ADDR, 1); + kpreempt_disable(); + other_cpus = cpu_ready_set; + CPUSET_DEL(other_cpus, CPU->cpu_id); + xt_some(other_cpus, vtag_unmap_perm_tl1, (uint64_t)OFW_START_ADDR, + KCONTEXT); + kpreempt_enable(); +} + static void cache_prom_data(void); /* @@ -252,6 +425,8 @@ cif_init(void) void (*kmdb_cb)(void); uint64_t rtba; uint64_t rv; + size_t ntransroot; + struct translation *transroot; /* * Check if domaining is enabled. If not, do not @@ -260,6 +435,8 @@ cif_init(void) if (!domaining_enabled()) return; + transroot = read_prom_mappings(&ntransroot); + /* * Cache PROM data that is needed later, e.g. a shadow * copy of the device tree, IO mappings, etc. @@ -301,6 +478,9 @@ cif_init(void) } cif_check_cpus(); + + if (transroot != NULL) + unmap_prom_mappings(transroot, ntransroot); } static void |