summaryrefslogtreecommitdiff
path: root/usr/src/uts/sun4v/promif
diff options
context:
space:
mode:
authorJason Beloro <Jason.Beloro@Sun.COM>2009-07-16 18:10:57 -0700
committerJason Beloro <Jason.Beloro@Sun.COM>2009-07-16 18:10:57 -0700
commit9853d9e82e7a067a2b88dae2fd257207e6be5f94 (patch)
tree83474d6da1693101c62f3f18d7588cd30fb953c4 /usr/src/uts/sun4v/promif
parentf94275ce205810a201404c5f35f4cc96057022b1 (diff)
downloadillumos-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.c188
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