summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/lib/efcode/engine/init.c15
-rw-r--r--usr/src/uts/sun4u/io/opl_cfg.c53
-rw-r--r--usr/src/uts/sun4u/io/px/px_lib4u.c6
-rw-r--r--usr/src/uts/sun4u/ngdr/io/dr.c8
-rw-r--r--usr/src/uts/sun4u/opl/io/dr_mem.c300
-rw-r--r--usr/src/uts/sun4u/opl/io/drmach.c346
-rw-r--r--usr/src/uts/sun4u/opl/io/mc-opl.c29
-rw-r--r--usr/src/uts/sun4u/opl/ml/drmach.il.cpp31
-rw-r--r--usr/src/uts/sun4u/opl/ml/drmach_asm.s4
-rw-r--r--usr/src/uts/sun4u/opl/os/opl.c6
-rw-r--r--usr/src/uts/sun4u/opl/sys/drmach.h131
-rw-r--r--usr/src/uts/sun4u/opl/sys/opl_hwdesc.h10
-rw-r--r--usr/src/uts/sun4u/sys/sbd_ioctl.h10
13 files changed, 635 insertions, 314 deletions
diff --git a/usr/src/lib/efcode/engine/init.c b/usr/src/lib/efcode/engine/init.c
index 128476cf4e..d6540c316f 100644
--- a/usr/src/lib/efcode/engine/init.c
+++ b/usr/src/lib/efcode/engine/init.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,8 +19,8 @@
* CDDL HEADER END
*/
/*
- * Copyright (c) 1999 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -34,7 +33,7 @@
#include <fcode/log.h>
fcode_env_t *initial_env = 0;
-int dict_size = 0x100000; /* 1Mb, hopefully big enough... */
+int dict_size = 0x4000000; /* 64Mb, hopefully big enough... */
int stack_size = 0x200;
void *
@@ -42,7 +41,7 @@ safe_malloc(size_t n, char *f, int l)
{
void *p;
- p = malloc((size_t) n);
+ p = malloc((size_t)n);
#if defined(__sparcv9)
/*
* For Ultrasparc, we must force addresses to be less than 4Gb,
@@ -55,7 +54,7 @@ safe_malloc(size_t n, char *f, int l)
}
#endif /* __sparcv9 */
if (p) {
- memset(p, 0, (size_t) n);
+ memset(p, 0, (size_t)n);
} else
log_message(MSG_ERROR, "%s:%d:Malloc(%llx) failed\n", f, l,
(uint64_t)n);
diff --git a/usr/src/uts/sun4u/io/opl_cfg.c b/usr/src/uts/sun4u/io/opl_cfg.c
index dc414ed94d..62df21f9c7 100644
--- a/usr/src/uts/sun4u/io/opl_cfg.c
+++ b/usr/src/uts/sun4u/io/opl_cfg.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -721,8 +721,14 @@ opl_create_node(opl_probe_t *probe)
static int
opl_destroy_node(dev_info_t *node)
{
- if (e_ddi_branch_destroy(node, NULL, 0) != 0)
+ if (e_ddi_branch_destroy(node, NULL, 0) != 0) {
+ char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+ (void) ddi_pathname(node, path);
+ cmn_err(CE_WARN, "OPL node removal failed: %s (%p)",
+ path, (void *)node);
+ kmem_free(path, MAXPATHLEN);
return (-1);
+ }
return (0);
}
@@ -1046,8 +1052,18 @@ opl_create_pseudo_mc(dev_info_t *node, void *arg, uint_t flags)
mc[j].mc_lo = OPL_LO(bank[i].bank_register_address);
j++;
}
- ASSERT(j > 0);
- OPL_UPDATE_PROP_ARRAY(int, node, "mc-addr", (int *)mc, j*3);
+
+ if (j > 0) {
+ OPL_UPDATE_PROP_ARRAY(int, node, "mc-addr", (int *)mc, j*3);
+ } else {
+ /*
+ * If there is no memory, we need the mc-addr property, but
+ * it is length 0. The only way to do this using ndi seems
+ * to be by creating a boolean property.
+ */
+ ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, node, "mc-addr");
+ OPL_UPDATE_PROP_ERR(ret, "mc-addr");
+ }
OPL_UPDATE_PROP_ARRAY(byte, node, "cs0-mc-pa-trans-table",
mem->mem_cs[0].cs_pa_mac_table, 64);
@@ -1074,9 +1090,20 @@ opl_create_pseudo_mc(dev_info_t *node, void *arg, uint_t flags)
j++;
}
}
- ASSERT(j > 0);
- OPL_UPDATE_PROP_ARRAY(int, node, "cs-status", (int *)status,
- j*7);
+
+ if (j > 0) {
+ OPL_UPDATE_PROP_ARRAY(int, node, "cs-status", (int *)status,
+ j*7);
+ } else {
+ /*
+ * If there is no memory, we need the cs-status property, but
+ * it is length 0. The only way to do this using ndi seems
+ * to be by creating a boolean property.
+ */
+ ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, node,
+ "cs-status");
+ OPL_UPDATE_PROP_ERR(ret, "cs-status");
+ }
return (DDI_WALK_TERMINATE);
}
@@ -1170,6 +1197,13 @@ opl_fc_ops_free_handle(fco_handle_t rp)
switch (resp->type) {
case RT_MAP:
+ /*
+ * If this is still mapped, we'd better unmap it now,
+ * or all our structures that are tracking it will
+ * be leaked.
+ */
+ if (resp->fc_map_handle != NULL)
+ opl_unmap_phys(&resp->fc_map_handle);
break;
case RT_DMA:
@@ -1897,6 +1931,7 @@ opl_map_phys(dev_info_t *dip, struct regspec *phys_spec,
if (result != DDI_SUCCESS) {
impl_acc_hdl_free(*handlep);
+ kmem_free(rspecp, sizeof (struct regspec));
*handlep = (ddi_acc_handle_t)NULL;
} else {
acc_handlep->ah_addr = *addrp;
@@ -2512,8 +2547,10 @@ opl_init_leaves(int myboard)
ret = OPL_GET_PROP(int, node, "board#",
&board, -1);
if ((ret != DDI_PROP_SUCCESS) ||
- (board != myboard))
+ (board != myboard)) {
+ kmem_free(name, len);
continue;
+ }
cfg = &opl_boards[board];
channel = OPL_PORTID_TO_CHANNEL(portid);
diff --git a/usr/src/uts/sun4u/io/px/px_lib4u.c b/usr/src/uts/sun4u/io/px/px_lib4u.c
index d8f547ec13..7541bdd19d 100644
--- a/usr/src/uts/sun4u/io/px/px_lib4u.c
+++ b/usr/src/uts/sun4u/io/px/px_lib4u.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -2215,6 +2215,10 @@ px_cb_intr_redist(px_t *px_p)
devino_t ino = px_p->px_inos[PX_INTR_XBC];
cpuid_t cpuid;
+ /* Make sure there is an interrupt control block setup. */
+ if (!cb_p)
+ return;
+
mutex_enter(&cb_p->cb_mutex);
if (cb_p->sysino != f_p->px_fh_sysino) {
diff --git a/usr/src/uts/sun4u/ngdr/io/dr.c b/usr/src/uts/sun4u/ngdr/io/dr.c
index 2d84b9e4ef..6eb5d588fd 100644
--- a/usr/src/uts/sun4u/ngdr/io/dr.c
+++ b/usr/src/uts/sun4u/ngdr/io/dr.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1478,7 +1478,8 @@ dr_disconnect(dr_handle_t *hp)
(hp->h_err->e_code == ESTC_MBXRQST) ||
(hp->h_err->e_code == ESTC_SMS_ERR_UNRECOVERABLE) ||
(hp->h_err->e_code == ESTC_SMS_ERR_RECOVERABLE) ||
- (hp->h_err->e_code == ESTC_DEPROBE)) {
+ (hp->h_err->e_code == ESTC_DEPROBE) ||
+ (hp->h_err->e_code == EOPL_DEPROBE)) {
bp->b_ostate = SBD_STAT_UNCONFIGURED;
bp->b_busy = 0;
(void) drv_getparm(TIME, (void *)&bp->b_time);
@@ -1499,7 +1500,8 @@ dr_disconnect(dr_handle_t *hp)
*/
if ((hp->h_err->e_code == ESTC_MBXRQST) ||
(hp->h_err->e_code == ESTC_SMS_ERR_RECOVERABLE) ||
- (hp->h_err->e_code == ESTC_DEPROBE)) {
+ (hp->h_err->e_code == ESTC_DEPROBE) ||
+ (hp->h_err->e_code == EOPL_DEPROBE)) {
/*
* With this failure, the board has been deprobed
* by IKP, and reprobed. We've already gotten rid
diff --git a/usr/src/uts/sun4u/opl/io/dr_mem.c b/usr/src/uts/sun4u/opl/io/dr_mem.c
index 0d4a415d7b..a63ffad50f 100644
--- a/usr/src/uts/sun4u/opl/io/dr_mem.c
+++ b/usr/src/uts/sun4u/opl/io/dr_mem.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -56,15 +56,16 @@
#include <sys/dr.h>
#include <sys/dr_util.h>
#include <sys/drmach.h>
+#include <sys/kobj.h>
extern struct memlist *phys_install;
-extern vnode_t retired_pages;
+extern vnode_t *retired_pages;
/* TODO: push this reference below drmach line */
extern int kcage_on;
/* for the DR*INTERNAL_ERROR macros. see sys/dr.h. */
-static char *dr_ie_fmt = "%M% %d";
+static char *dr_ie_fmt = "dr_mem.c %d";
typedef enum {
DR_TP_INVALID = -1,
@@ -99,8 +100,6 @@ static int dr_memlist_canfit(struct memlist *s_mlist,
struct memlist *t_mlist, dr_mem_unit_t *s_mp,
dr_mem_unit_t *t_mp);
-extern void page_unretire_pages(void);
-
/*
* dr_mem_unit_t.sbm_flags
*/
@@ -385,7 +384,7 @@ dr_memlist_del_retired_pages(struct memlist *mlist)
page_t *pp;
pfn_t pfn;
kmutex_t *vphm;
- vnode_t *vp = &retired_pages;
+ vnode_t *vp = retired_pages;
static fn_t f = "dr_memlist_del_retired_pages";
vphm = page_vnode_mutex(vp);
@@ -406,7 +405,7 @@ dr_memlist_del_retired_pages(struct memlist *mlist)
* changes to the retired vnode locking scheme.
*/
ASSERT(PAGE_LOCKED(pp));
- ASSERT(pp->p_vnode == &retired_pages);
+ ASSERT(pp->p_vnode == retired_pages);
if (!page_trylock(pp, SE_SHARED))
continue;
@@ -435,84 +434,6 @@ dr_memlist_del_retired_pages(struct memlist *mlist)
return (mlist);
}
-#ifdef DEBUG
-int dbg_retirecnt = 10;
-
-static void
-dbg_page_retire(struct memlist *r_ml)
-{
- struct memlist *t_ml;
- page_t *pp, *epp;
- pfn_t pfn, epfn;
- struct memseg *seg;
-
- int dbg_retired = 0;
- int dbg_skip = 10;
- int dbg_seq = 1;
-
- if (r_ml == NULL)
- return;
-
- for (t_ml = r_ml; (t_ml != NULL); t_ml = t_ml->next) {
- pfn = _b64top(t_ml->address);
- epfn = _b64top(t_ml->address + t_ml->size);
-
- for (seg = memsegs; seg != NULL; seg = seg->next) {
- int retire = 0;
- int skip = 0;
- if (pfn >= seg->pages_end || epfn < seg->pages_base)
- continue;
-
- pp = seg->pages;
- if (pfn > seg->pages_base)
- pp += pfn - seg->pages_base;
-
- epp = seg->epages;
- if (epfn < seg->pages_end)
- epp -= seg->pages_end - epfn;
-
- ASSERT(pp < epp);
-#if 0
- while (pp < epp) {
- if (PP_ISFREE(pp) && !page_isfaulty(pp)) {
- if (retire++ < dbg_seq) {
- page_settoxic(pp,
- PAGE_IS_FAULTY);
- page_retire(pp,
- PAGE_IS_FAILING);
- if (++dbg_retired >=
- dbg_retirecnt)
- return;
- } else if (skip++ >= dbg_skip) {
- skip = 0;
- retire = 0;
- dbg_seq++;
- }
- }
- pp++;
- }
-#endif /* 0 */
- while (pp < epp) {
- if (PP_ISFREE(pp)) {
- if (retire++ < dbg_seq) {
- page_retire(t_ml->address,
- PR_OK);
- if (++dbg_retired >=
- dbg_retirecnt)
- return;
- } else if (skip++ >= dbg_skip) {
- skip = 0;
- retire = 0;
- dbg_seq++;
- }
- }
- pp++;
- }
- }
- }
-}
-#endif
-
static int
dr_move_memory(dr_handle_t *hp, dr_mem_unit_t *s_mp, dr_mem_unit_t *t_mp)
{
@@ -537,11 +458,6 @@ dr_move_memory(dr_handle_t *hp, dr_mem_unit_t *s_mp, dr_mem_unit_t *t_mp)
ASSERT(t_mp->sbm_flags & DR_MFLAG_TARGET);
ASSERT(t_mp->sbm_peer == s_mp);
-#ifdef DEBUG
- if (dbg_retirecnt)
- dbg_page_retire(s_mp->sbm_mlist);
-#endif
-
/*
* create a memlist of spans to copy by removing
* the spans that have been deleted, if any, from
@@ -1014,6 +930,26 @@ dr_pre_attach_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
return (err_flag ? -1 : 0);
}
+static void
+dr_update_mc_memory()
+{
+ void (*mc_update_mlist)(void);
+
+ /*
+ * mc-opl is configured during drmach_mem_new but the memory
+ * has not been added to phys_install at that time.
+ * we must inform mc-opl to update the mlist after we
+ * attach or detach a system board.
+ */
+
+ mc_update_mlist = (void (*)(void))
+ modgetsymvalue("opl_mc_update_mlist", 0);
+
+ if (mc_update_mlist != NULL) {
+ (*mc_update_mlist)();
+ }
+}
+
int
dr_post_attach_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
{
@@ -1030,7 +966,7 @@ dr_post_attach_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
mlist = dr_get_memlist(mp);
if (mlist == NULL) {
- dr_dev_err(CE_WARN, &mp->sbm_cm, ESBD_MEMFAIL);
+ /* OPL supports memoryless board */
continue;
}
@@ -1084,6 +1020,8 @@ dr_post_attach_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
}
}
+ dr_update_mc_memory();
+
return (0);
}
@@ -1122,6 +1060,7 @@ dr_post_detach_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
if (dr_post_detach_mem_unit(mp))
rv = -1;
}
+ dr_update_mc_memory();
return (rv);
}
@@ -1174,6 +1113,139 @@ dr_add_memory_spans(dr_mem_unit_t *mp, struct memlist *ml)
}
static int
+memlist_touch(struct memlist *ml, uint64_t add)
+{
+ while (ml != NULL) {
+ if ((add == ml->address) ||
+ (add == (ml->address + ml->size)))
+ return (1);
+ ml = ml->next;
+ }
+ return (0);
+}
+
+static sbd_error_t *
+dr_process_excess_mlist(dr_mem_unit_t *s_mp,
+ dr_mem_unit_t *t_mp, struct memlist *t_excess_mlist)
+{
+ struct memlist *ml;
+ sbd_error_t *err;
+ static fn_t f = "dr_process_excess_mlist";
+ uint64_t new_pa, nbytes;
+ int rv;
+
+ err = NULL;
+
+ /*
+ * After the small <-> big copy-rename,
+ * the original address space for the
+ * source board may have excess to be
+ * deleted. This is a case different
+ * from the big->small excess source
+ * memory case listed below.
+ * Remove s_mp->sbm_del_mlist from
+ * the kernel cage glist.
+ */
+ for (ml = s_mp->sbm_del_mlist; ml;
+ ml = ml->next) {
+ PR_MEM("%s: delete small<->big copy-"
+ "rename source excess memory", f);
+ PR_MEMLIST_DUMP(ml);
+
+ err = drmach_mem_del_span(
+ s_mp->sbm_cm.sbdev_id,
+ ml->address, ml->size);
+ if (err)
+ DRERR_SET_C(&s_mp->
+ sbm_cm.sbdev_error, &err);
+ ASSERT(err == NULL);
+ }
+
+ PR_MEM("%s: adding back remaining portion"
+ " of %s, memlist:\n",
+ f, t_mp->sbm_cm.sbdev_path);
+ PR_MEMLIST_DUMP(t_excess_mlist);
+
+ for (ml = t_excess_mlist; ml; ml = ml->next) {
+ struct memlist ml0;
+
+ ml0.address = ml->address;
+ ml0.size = ml->size;
+ ml0.next = ml0.prev = NULL;
+
+ /*
+ * If the memory object is 256 MB aligned (max page size
+ * on OPL, it will not be coalesced to the adjacent memory
+ * chunks. The coalesce logic assumes contiguous page
+ * structures for contiguous memory and we hit panic.
+ * For anything less than 256 MB alignment, we have
+ * to make sure that it is not adjacent to anything.
+ * If the new chunk is adjacent to phys_install, we
+ * truncate it to 4MB boundary. 4 MB is somewhat
+ * arbitrary. However we do not want to create
+ * very small segments because they can cause problem.
+ * The extreme case of 8K segment will fail
+ * kphysm_add_memory_dynamic(), e.g.
+ */
+ if ((ml->address & (MH_MPSS_ALIGNMENT - 1)) ||
+ (ml->size & (MH_MPSS_ALIGNMENT - 1))) {
+
+ memlist_read_lock();
+ rv = memlist_touch(phys_install, ml0.address);
+ memlist_read_unlock();
+
+ if (rv) {
+ new_pa = roundup(ml0.address + 1, MH_MIN_ALIGNMENT);
+ nbytes = (new_pa - ml0.address);
+ if (nbytes >= ml0.size) {
+ t_mp->sbm_dyn_segs =
+ memlist_del_span(t_mp->sbm_dyn_segs,
+ ml0.address, ml0.size);
+ continue;
+ }
+ t_mp->sbm_dyn_segs =
+ memlist_del_span(t_mp->sbm_dyn_segs,
+ ml0.address, nbytes);
+ ml0.size -= nbytes;
+ ml0.address = new_pa;
+ }
+
+ if (ml0.size == 0) {
+ continue;
+ }
+
+ memlist_read_lock();
+ rv = memlist_touch(phys_install, ml0.address + ml0.size);
+ memlist_read_unlock();
+
+ if (rv) {
+ new_pa = rounddown(ml0.address + ml0.size - 1,
+ MH_MIN_ALIGNMENT);
+ nbytes = (ml0.address + ml0.size - new_pa);
+ if (nbytes >= ml0.size) {
+ t_mp->sbm_dyn_segs =
+ memlist_del_span(t_mp->sbm_dyn_segs,
+ ml0.address, ml0.size);
+ continue;
+ }
+ t_mp->sbm_dyn_segs =
+ memlist_del_span(t_mp->sbm_dyn_segs,
+ new_pa, nbytes);
+ ml0.size -= nbytes;
+ }
+
+ if (ml0.size > 0) {
+ dr_add_memory_spans(s_mp, &ml0);
+ }
+ } else if (ml0.size > 0) {
+ dr_add_memory_spans(s_mp, &ml0);
+ }
+ }
+ memlist_delete(t_excess_mlist);
+ return (err);
+}
+
+static int
dr_post_detach_mem_unit(dr_mem_unit_t *s_mp)
{
uint64_t sz = s_mp->sbm_slice_size;
@@ -1321,6 +1393,8 @@ dr_post_detach_mem_unit(dr_mem_unit_t *s_mp)
PR_MEM("%s: renamed source memlist:\n", f);
PR_MEMLIST_DUMP(s_mp->sbm_mlist);
+ PR_MEM("%s: source dyn seg memlist:\n", f);
+ PR_MEMLIST_DUMP(s_mp->sbm_dyn_segs);
/*
* Keep track of dynamically added segments
@@ -1344,6 +1418,8 @@ dr_post_detach_mem_unit(dr_mem_unit_t *s_mp)
memlist_del_span(t_excess_mlist,
ml->address, ml->size);
}
+ PR_MEM("%s: excess memlist:\n", f);
+ PR_MEMLIST_DUMP(t_excess_mlist);
/*
* Update dynamically added segs
@@ -1363,46 +1439,11 @@ dr_post_detach_mem_unit(dr_mem_unit_t *s_mp)
PR_MEMLIST_DUMP(t_mp->sbm_dyn_segs);
if (t_excess_mlist != NULL) {
- /*
- * After the small <-> big copy-rename,
- * the original address space for the
- * source board may have excess to be
- * deleted. This is a case different
- * from the big->small excess source
- * memory case listed below.
- * Remove s_mp->sbm_del_mlist from
- * the kernel cage glist.
- */
- for (ml = s_mp->sbm_del_mlist; ml;
- ml = ml->next) {
- PR_MEM("%s: delete small<->big copy-"
- "rename source excess memory", f);
- PR_MEMLIST_DUMP(ml);
-
- err = drmach_mem_del_span(
- s_mp->sbm_cm.sbdev_id,
- ml->address, ml->size);
- if (err)
- DRERR_SET_C(&s_mp->
- sbm_cm.sbdev_error, &err);
- ASSERT(err == NULL);
- }
-
- /*
- * mark sbm_del_mlist as been deleted so that
- * we won't end up to delete it twice later
- * from the span list
- */
+ err = dr_process_excess_mlist(s_mp, t_mp,
+ t_excess_mlist);
s_excess_mem_deleted = 1;
-
- PR_MEM("%s: adding back remaining portion"
- " of %s, memlist:\n",
- f, t_mp->sbm_cm.sbdev_path);
- PR_MEMLIST_DUMP(t_excess_mlist);
-
- dr_add_memory_spans(s_mp, t_excess_mlist);
- memlist_delete(t_excess_mlist);
}
+
memlist_delete(s_copy_mlist);
#ifdef DEBUG
@@ -1579,6 +1620,7 @@ dr_pre_release_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
* copy-rename.
*/
ASSERT(mp->sbm_npages != 0);
+
rv = dr_del_mlist_query(ml, &mq);
if (rv != KPHYSM_OK) {
memlist_delete(ml);
diff --git a/usr/src/uts/sun4u/opl/io/drmach.c b/usr/src/uts/sun4u/opl/io/drmach.c
index 61609b0d97..fcc6f01874 100644
--- a/usr/src/uts/sun4u/opl/io/drmach.c
+++ b/usr/src/uts/sun4u/opl/io/drmach.c
@@ -19,12 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
+
#include <sys/debug.h>
#include <sys/types.h>
#include <sys/varargs.h>
@@ -354,11 +355,6 @@ _info(struct modinfo *modinfop)
return (mod_info(&modlinkage, modinfop));
}
-/*
- * The following routines are used to set up the memory
- * properties in the board structure.
- */
-
struct drmach_mc_lookup {
int bnum;
drmach_board_t *bp;
@@ -1398,7 +1394,7 @@ drmach_board_connect(drmachid_t id, drmach_opts_t *opts)
return (drerr_new(0, EOPL_INAPPROP, NULL));
if (opl_probe_sb(obj->bnum) != 0)
- return (DRMACH_INTERNAL_ERROR());
+ return (drerr_new(0, EOPL_PROBE, NULL));
(void) prom_attach_notice(obj->bnum);
@@ -2030,6 +2026,7 @@ struct drmach_io_cb {
char *name; /* name of the node */
int (*func)(dev_info_t *);
int rv;
+ dev_info_t *dip;
};
#define DRMACH_IO_POST_ATTACH 0
@@ -2049,7 +2046,8 @@ drmach_io_cb_check(dev_info_t *dip, void *arg)
}
if (strcmp(name, p->name) == 0) {
- p->rv = (*p->func)(dip);
+ ndi_hold_devi(dip);
+ p->dip = dip;
return (DDI_WALK_TERMINATE);
}
@@ -2083,15 +2081,16 @@ drmach_console_ops(drmachid_t *id, int state)
modgetsymvalue("oplmsu_dr_attach", 0);
if (msuattp != NULL)
arg.func = msuattp;
- }
- else
+ } else {
return (0);
+ }
if (arg.func == NULL) {
return (0);
}
arg.rv = 0;
+ arg.dip = NULL;
dip = obj->dev.node->n_getdip(obj->dev.node);
if (pdip = ddi_get_parent(dip)) {
@@ -2104,9 +2103,14 @@ drmach_console_ops(drmachid_t *id, int state)
ddi_walk_devs(dip, drmach_io_cb_check, (void *)&arg);
- if (pdip) {
- ndi_devi_exit(pdip, circ);
- ndi_rele_devi(pdip);
+ ndi_devi_exit(pdip, circ);
+ ndi_rele_devi(pdip);
+
+ if (arg.dip) {
+ arg.rv = (*arg.func)(arg.dip);
+ ndi_rele_devi(arg.dip);
+ } else {
+ arg.rv = -1;
}
return (arg.rv);
@@ -2199,9 +2203,18 @@ drmach_mem_new(drmach_device_t *proto, drmachid_t *idp)
static sbd_error_t *drmach_mem_release(drmachid_t);
static sbd_error_t *drmach_mem_status(drmachid_t, drmach_status_t *);
dev_info_t *dip;
+ int rv;
drmach_mem_t *mp;
+ rv = 0;
+
+ if ((proto->node->n_getproplen(proto->node, "mc-addr", &rv) < 0) ||
+ (rv <= 0)) {
+ *idp = (drmachid_t)0;
+ return (NULL);
+ }
+
mp = kmem_zalloc(sizeof (drmach_mem_t), KM_SLEEP);
proto->unum = 0;
@@ -2217,10 +2230,16 @@ drmach_mem_new(drmach_device_t *proto, drmachid_t *idp)
dip = mp->dev.node->n_getdip(mp->dev.node);
if (drmach_setup_mc_info(dip, mp) != 0) {
- return (DRMACH_INTERNAL_ERROR());
+ return (drerr_new(0, EOPL_MC_SETUP, NULL));
}
- *idp = (drmachid_t)mp;
+ /* make sure we do not create memoryless nodes */
+ if (mp->nbytes == 0) {
+ *idp = (drmachid_t)NULL;
+ kmem_free(mp, sizeof (drmach_mem_t));
+ } else
+ *idp = (drmachid_t)mp;
+
return (NULL);
}
@@ -2241,6 +2260,8 @@ drmach_mem_dispose(drmachid_t id)
memlist_delete(mp->memlist);
mp->memlist = NULL;
}
+
+ kmem_free(mp, sizeof (*mp));
}
sbd_error_t *
@@ -2394,7 +2415,6 @@ drmach_mem_get_memlist(drmachid_t id, struct memlist **ml)
DRMACH_PR("Derived memlist:");
memlist_dump(mlist);
#endif
-
*ml = mlist;
return (NULL);
@@ -2476,7 +2496,7 @@ drmach_board_deprobe(drmachid_t id)
bp = id;
- cmn_err(CE_CONT, "DR: PROM detach board %d\n", bp->bnum);
+ cmn_err(CE_CONT, "DR: detach board %d\n", bp->bnum);
if (bp->tree) {
drmach_node_dispose(bp->tree);
@@ -2929,21 +2949,6 @@ opl_check_dr_status()
}
}
-static sbd_error_t *
-drmach_get_scf_addr(uint64_t *addr)
-{
- caddr_t *scf_cmd_addr;
- uint64_t pa;
- scf_cmd_addr = (caddr_t *)modgetsymvalue("scf_avail_cmd_reg_vaddr", 0);
- if (scf_cmd_addr != NULL) {
- pa = (uint64_t)va_to_pa(*scf_cmd_addr);
- *addr = pa;
- return (NULL);
- }
-
- return (DRMACH_INTERNAL_ERROR());
-}
-
/* we are allocating memlist from TLB locked pages to avoid tlbmisses */
static struct memlist *
@@ -3050,6 +3055,12 @@ static int fmem_timeout = 17;
static int min_copy_size_per_sec = 20 * 1024 * 1024;
int drmach_disable_mcopy = 0;
+/*
+ * The following delay loop executes sleep instruction to yield the
+ * CPU to other strands. If this is not done, some strand will tie
+ * up the CPU in busy loops while the other strand cannot do useful
+ * work. The copy procedure will take a much longer time without this.
+ */
#define DR_DELAY_IL(ms, freq) \
{ \
uint64_t start; \
@@ -3075,15 +3086,29 @@ drmach_copy_rename_prog__relocatable(drmach_copy_rename_program_t *prog,
extern uint64_t drmach_get_stick_il();
extern void membar_sync_il();
extern void flush_instr_mem_il(void*);
+ extern void flush_windows_il(void);
uint64_t copy_start;
+ /*
+ * flush_windows is moved here to make sure all
+ * registers used in the callers are flushed to
+ * memory before the copy.
+ *
+ * If flush_windows() is called too early in the
+ * calling function, the compiler might put some
+ * data in the local registers after flush_windows().
+ * After FMA, if there is any fill trap, the registers
+ * will contain stale data.
+ */
+
+ flush_windows_il();
+
prog->critical->stat[cpuid] = FMEM_LOOP_COPY_READY;
membar_sync_il();
if (prog->data->cpuid == cpuid) {
limit = drmach_get_stick_il();
limit += prog->critical->delay;
-
for (i = 0; i < NCPU; i++) {
if (CPU_IN_SET(prog->data->cpu_slave_set, i)) {
/* wait for all CPU's to be ready */
@@ -3092,6 +3117,7 @@ drmach_copy_rename_prog__relocatable(drmach_copy_rename_program_t *prog,
FMEM_LOOP_COPY_READY) {
break;
}
+ DR_DELAY_IL(1, prog->data->stick_freq);
}
curr = drmach_get_stick_il();
if (curr > limit) {
@@ -3114,6 +3140,7 @@ drmach_copy_rename_prog__relocatable(drmach_copy_rename_program_t *prog,
prog->data->error[cpuid] = FMEM_TERMINATE;
return (FMEM_TERMINATE);
}
+ DR_DELAY_IL(1, prog->data->stick_freq);
}
}
@@ -3248,7 +3275,6 @@ drmach_copy_rename_prog__relocatable(drmach_copy_rename_program_t *prog,
*/
rtn = prog->critical->loop((void *)(prog->critical),
PAGESIZE, (void *)&(prog->critical->stat[cpuid]));
-
prog->data->error[cpuid] = rtn;
/* slave thread does not care the rv */
return (0);
@@ -3288,6 +3314,39 @@ drmach_setup_memlist(drmach_copy_rename_program_t *p)
}
}
+static void
+drmach_lock_critical(caddr_t va, caddr_t new_va)
+{
+ tte_t tte;
+ int i;
+
+ kpreempt_disable();
+
+ for (i = 0; i < DRMACH_FMEM_LOCKED_PAGES; i++) {
+ vtag_flushpage(new_va, (uint64_t)ksfmmup);
+ sfmmu_memtte(&tte, va_to_pfn(va),
+ PROC_DATA|HAT_NOSYNC, TTE8K);
+ tte.tte_intlo |= TTE_LCK_INT;
+ sfmmu_dtlb_ld_kva(new_va, &tte);
+ sfmmu_itlb_ld_kva(new_va, &tte);
+ va += PAGESIZE;
+ new_va += PAGESIZE;
+ }
+}
+
+static void
+drmach_unlock_critical(caddr_t va)
+{
+ int i;
+
+ for (i = 0; i < DRMACH_FMEM_LOCKED_PAGES; i++) {
+ vtag_flushpage(va, (uint64_t)ksfmmup);
+ va += PAGESIZE;
+ }
+
+ kpreempt_enable();
+}
+
sbd_error_t *
drmach_copy_rename_init(drmachid_t t_id, drmachid_t s_id,
struct memlist *c_ml, drmachid_t *pgm_id)
@@ -3301,18 +3360,19 @@ drmach_copy_rename_init(drmachid_t t_id, drmachid_t s_id,
int s_bd, t_bd, cpuid, active_cpus, i;
uint64_t c_addr;
size_t c_size, copy_sz, sz;
- static sbd_error_t *drmach_get_scf_addr(uint64_t *);
extern void drmach_fmem_loop_script();
extern void drmach_fmem_loop_script_rtn();
extern int drmach_fmem_exec_script();
extern void drmach_fmem_exec_script_end();
sbd_error_t *err;
- drmach_copy_rename_program_t *prog;
+ drmach_copy_rename_program_t *prog = NULL;
+ drmach_copy_rename_program_t *prog_kmem = NULL;
void (*mc_suspend)(void);
void (*mc_resume)(void);
int (*scf_fmem_start)(int, int);
int (*scf_fmem_end)(void);
int (*scf_fmem_cancel)(void);
+ uint64_t (*scf_get_base_addr)(void);
if (!DRMACH_IS_MEM_ID(s_id))
return (drerr_new(0, EOPL_INAPPROP, NULL));
@@ -3344,7 +3404,7 @@ drmach_copy_rename_init(drmachid_t t_id, drmachid_t s_id,
(1 << strand_id)) {
if (!(bp->cores[onb_core_num].core_started &
(1 << strand_id))) {
- return (DRMACH_INTERNAL_ERROR());
+ return (drerr_new(0, EOPL_CPU_STATE, NULL));
}
}
}
@@ -3355,23 +3415,28 @@ drmach_copy_rename_init(drmachid_t t_id, drmachid_t s_id,
modgetsymvalue("opl_mc_resume", 0);
if (mc_suspend == NULL || mc_resume == NULL) {
- return (DRMACH_INTERNAL_ERROR());
+ return (drerr_new(0, EOPL_MC_OPL, NULL));
}
scf_fmem_start = (int (*)(int, int))
modgetsymvalue("scf_fmem_start", 0);
if (scf_fmem_start == NULL) {
- return (DRMACH_INTERNAL_ERROR());
+ return (drerr_new(0, EOPL_SCF_FMEM, NULL));
}
scf_fmem_end = (int (*)(void))
modgetsymvalue("scf_fmem_end", 0);
if (scf_fmem_end == NULL) {
- return (DRMACH_INTERNAL_ERROR());
+ return (drerr_new(0, EOPL_SCF_FMEM, NULL));
}
scf_fmem_cancel = (int (*)(void))
modgetsymvalue("scf_fmem_cancel", 0);
if (scf_fmem_cancel == NULL) {
- return (DRMACH_INTERNAL_ERROR());
+ return (drerr_new(0, EOPL_SCF_FMEM, NULL));
+ }
+ scf_get_base_addr = (uint64_t (*)(void))
+ modgetsymvalue("scf_get_base_addr", 0);
+ if (scf_get_base_addr == NULL) {
+ return (drerr_new(0, EOPL_SCF_FMEM, NULL));
}
s_mem = s_id;
t_mem = t_id;
@@ -3395,11 +3460,36 @@ drmach_copy_rename_init(drmachid_t t_id, drmachid_t s_id,
* bp will be page aligned, since we're calling
* kmem_zalloc() with an exact multiple of PAGESIZE.
*/
- wp = bp = kmem_zalloc(DRMACH_FMEM_LOCKED_PAGES * PAGESIZE,
- KM_SLEEP);
- prog = (drmach_copy_rename_program_t *)(wp +
- DRMACH_FMEM_DATA_PAGE * PAGESIZE);
+ prog_kmem = (drmach_copy_rename_program_t *)kmem_zalloc(
+ DRMACH_FMEM_LOCKED_PAGES * PAGESIZE, KM_SLEEP);
+
+ prog_kmem->prog = prog_kmem;
+
+ /*
+ * To avoid MTLB hit, we allocate a new VM space and remap
+ * the kmem_alloc buffer to that address. This solves
+ * 2 problems we found:
+ * - the kmem_alloc buffer can be just a chunk inside
+ * a much larger, e.g. 4MB buffer and MTLB will occur
+ * if there are both a 4MB and a 8K TLB mapping to
+ * the same VA range.
+ * - the kmem mapping got dropped into the TLB by other
+ * strands, unintentionally.
+ * Note that the pointers like data, critical, memlist_buffer,
+ * and stat inside the copy rename structure are mapped to this
+ * alternate VM space so we must make sure we lock the TLB mapping
+ * whenever we access data pointed to by these pointers.
+ */
+
+ prog = prog_kmem->locked_prog = vmem_alloc(heap_arena,
+ DRMACH_FMEM_LOCKED_PAGES * PAGESIZE, VM_SLEEP);
+ wp = bp = (caddr_t)prog;
+
+ /* Now remap prog_kmem to prog */
+ drmach_lock_critical((caddr_t)prog_kmem, (caddr_t)prog);
+
+ /* All pointers in prog are based on the alternate mapping */
prog->data = (drmach_copy_rename_data_t *)roundup(((uint64_t)prog +
sizeof (drmach_copy_rename_program_t)), sizeof (void *));
@@ -3421,12 +3511,6 @@ drmach_copy_rename_init(drmachid_t t_id, drmachid_t s_id,
* PAGESIZE));
prog->critical->scf_reg_base = (uint64_t)-1;
- err = drmach_get_scf_addr(&(prog->critical->scf_reg_base));
- if (err) {
- kmem_free(wp, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE);
- return (err);
- }
-
prog->critical->scf_td[0] = (s_bd & 0xff);
prog->critical->scf_td[1] = (t_bd & 0xff);
for (i = 2; i < 15; i++) {
@@ -3459,8 +3543,8 @@ drmach_copy_rename_init(drmachid_t t_id, drmachid_t s_id,
/* now we make sure there is 1K extra */
if ((wp - bp) > PAGESIZE) {
- kmem_free(prog, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE);
- return (DRMACH_INTERNAL_ERROR());
+ err = drerr_new(0, EOPL_FMEM_SETUP, NULL);
+ goto out;
}
bp = (caddr_t)prog->critical;
@@ -3494,11 +3578,12 @@ drmach_copy_rename_init(drmachid_t t_id, drmachid_t s_id,
/* now we are committed, call SCF, soft suspend mac patrol */
if ((*scf_fmem_start)(s_bd, t_bd)) {
- kmem_free(prog, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE);
- return (DRMACH_INTERNAL_ERROR());
+ err = drerr_new(0, EOPL_SCF_FMEM_START, NULL);
+ goto out;
}
prog->data->scf_fmem_end = scf_fmem_end;
prog->data->scf_fmem_cancel = scf_fmem_cancel;
+ prog->data->scf_get_base_addr = scf_get_base_addr;
prog->data->fmem_status.op |= OPL_FMEM_SCF_START;
/* soft suspend mac patrol */
(*mc_suspend)();
@@ -3607,9 +3692,21 @@ end:
prog->data->s_copybasepa = s_copybasepa;
prog->data->t_copybasepa = t_copybasepa;
prog->data->c_ml = c_ml;
- *pgm_id = prog;
+ *pgm_id = prog_kmem;
+ /* Unmap the alternate space. It will have to be remapped again */
+ drmach_unlock_critical((caddr_t)prog);
return (NULL);
+out:
+ if (prog != NULL) {
+ drmach_unlock_critical((caddr_t)prog);
+ vmem_free(heap_arena, prog,
+ DRMACH_FMEM_LOCKED_PAGES * PAGESIZE);
+ }
+ if (prog_kmem != NULL) {
+ kmem_free(prog_kmem, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE);
+ }
+ return (err);
}
sbd_error_t *
@@ -3629,6 +3726,12 @@ drmach_copy_rename_fini(drmachid_t id)
* mc-opl will return UNKNOWN as the unum.
*/
+ /*
+ * we have to remap again because all the pointer like data,
+ * critical in prog are based on the alternate vmem space.
+ */
+ (void) drmach_lock_critical((caddr_t)prog, (caddr_t)prog->locked_prog);
+
if (prog->data->c_ml != NULL)
memlist_delete(prog->data->c_ml);
@@ -3646,7 +3749,7 @@ drmach_copy_rename_fini(drmachid_t id)
cmn_err(CE_PANIC, "scf fmem request failed");
rv = (*prog->data->scf_fmem_end)();
if (rv) {
- cmn_err(CE_PANIC, "scf_fmem_end() failed");
+ cmn_err(CE_PANIC, "scf_fmem_end() failed rv=%d", rv);
}
/*
* If we get here, rename is successful.
@@ -3658,78 +3761,52 @@ drmach_copy_rename_fini(drmachid_t id)
if (prog->data->fmem_status.error != 0) {
cmn_err(CE_WARN, "Kernel Migration fails. 0x%x",
prog->data->fmem_status.error);
- err = DRMACH_INTERNAL_ERROR();
+ err = drerr_new(1, EOPL_FMEM_ERROR, "FMEM error = 0x%x",
+ prog->data->fmem_status.error);
}
rv = (*prog->data->scf_fmem_cancel)();
if (rv) {
- cmn_err(CE_WARN, "scf_fmem_cancel() failed");
- if (!err)
- err = DRMACH_INTERNAL_ERROR();
+ cmn_err(CE_WARN, "scf_fmem_cancel() failed rv=0x%x", rv);
+ if (!err)
+ err = drerr_new(1, EOPL_SCF_FMEM_CANCEL,
+ "rv = 0x%x", rv);
}
}
/* soft resume mac patrol */
(*prog->data->mc_resume)();
+ drmach_unlock_critical((caddr_t)prog->locked_prog);
+
+ vmem_free(heap_arena, prog->locked_prog,
+ DRMACH_FMEM_LOCKED_PAGES * PAGESIZE);
kmem_free(prog, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE);
return (err);
}
-static void
-drmach_lock_critical(caddr_t va)
-{
- tte_t tte;
- int i;
-
- for (i = 0; i < DRMACH_FMEM_LOCKED_PAGES; i++) {
- vtag_flushpage(va, (uint64_t)ksfmmup);
- sfmmu_memtte(&tte, va_to_pfn(va),
- PROC_DATA|HAT_NOSYNC, TTE8K);
- tte.tte_intlo |= TTE_LCK_INT;
- sfmmu_dtlb_ld_kva(va, &tte);
- sfmmu_itlb_ld_kva(va, &tte);
- va += PAGESIZE;
- }
-}
-
-static void
-drmach_unlock_critical(caddr_t va)
-{
- int i;
-
- for (i = 0; i < DRMACH_FMEM_LOCKED_PAGES; i++) {
- vtag_flushpage(va, (uint64_t)ksfmmup);
- va += PAGESIZE;
- }
-}
-
/*ARGSUSED*/
static void
drmach_copy_rename_slave(struct regs *rp, drmachid_t id)
{
- drmach_copy_rename_program_t *prog = id;
+ drmach_copy_rename_program_t *prog =
+ (drmach_copy_rename_program_t *)id;
register int cpuid;
extern void drmach_flush();
extern void membar_sync_il();
extern void drmach_flush_icache();
on_trap_data_t otd;
- kpreempt_disable();
cpuid = CPU->cpu_id;
if (on_trap(&otd, OT_DATA_EC)) {
no_trap();
- drmach_unlock_critical((caddr_t)prog);
- kpreempt_enable();
prog->data->error[cpuid] = FMEM_COPY_ERROR;
prog->critical->stat[cpuid] = FMEM_LOOP_EXIT;
+ drmach_flush_icache();
+ membar_sync_il();
return;
}
- (void) drmach_lock_critical((caddr_t)prog);
-
- flush_windows();
-
/*
* jmp drmach_copy_rename_prog().
*/
@@ -3739,11 +3816,9 @@ drmach_copy_rename_slave(struct regs *rp, drmachid_t id)
drmach_flush_icache();
no_trap();
- drmach_unlock_critical((caddr_t)prog);
-
- kpreempt_enable();
prog->critical->stat[cpuid] = FMEM_LOOP_EXIT;
+
membar_sync_il();
}
@@ -3789,7 +3864,8 @@ drmach_swap_pa(drmach_mem_t *s_mem, drmach_mem_t *t_mem)
void
drmach_copy_rename(drmachid_t id)
{
- drmach_copy_rename_program_t *prog = id;
+ drmach_copy_rename_program_t *prog_kmem = id;
+ drmach_copy_rename_program_t *prog;
cpuset_t cpuset;
int cpuid;
uint64_t inst;
@@ -3802,12 +3878,30 @@ drmach_copy_rename(drmachid_t id)
extern uint64_t patch_inst(uint64_t *, uint64_t);
on_trap_data_t otd;
- if (prog->critical->scf_reg_base == (uint64_t)-1) {
+ prog = prog_kmem->locked_prog;
+
+ /*
+ * We must immediately drop in the TLB because all pointers
+ * are based on the alternate vmem space.
+ */
+
+ (void) drmach_lock_critical((caddr_t)prog_kmem, (caddr_t)prog);
+
+ /*
+ * we call scf to get the base address here becuase if scf
+ * has not been suspended yet, the active path can be changing and
+ * sometimes it is not even mapped. We call the interface when
+ * the OS has been quiesced.
+ */
+ prog->critical->scf_reg_base = (*prog->data->scf_get_base_addr)();
+
+ if (prog->critical->scf_reg_base == (uint64_t)-1 ||
+ prog->critical->scf_reg_base == NULL) {
prog->data->fmem_status.error = FMEM_SCF_ERR;
+ drmach_unlock_critical((caddr_t)prog);
return;
}
- kpreempt_disable();
cpuset = prog->data->cpu_ready_set;
for (cpuid = 0; cpuid < NCPU; cpuid++) {
@@ -3823,22 +3917,26 @@ drmach_copy_rename(drmachid_t id)
CPUSET_DEL(cpuset, cpuid);
- xc_some(cpuset, (xcfunc_t *)drmach_lock_critical,
- (uint64_t)prog, (uint64_t)0);
+ for (cpuid = 0; cpuid < NCPU; cpuid++) {
+ if (CPU_IN_SET(cpuset, cpuid)) {
+ xc_one(cpuid, (xcfunc_t *)drmach_lock_critical,
+ (uint64_t)prog_kmem, (uint64_t)prog);
+ }
+ }
+
+ cpuid = CPU->cpu_id;
xt_some(cpuset, (xcfunc_t *)drmach_sys_trap,
- (uint64_t)drmach_copy_rename_slave, (uint64_t)prog);
+ (uint64_t)drmach_copy_rename_slave,
+ (uint64_t)prog);
xt_sync(cpuset);
- (void) drmach_lock_critical((caddr_t)prog);
-
if (on_trap(&otd, OT_DATA_EC)) {
rtn = FMEM_COPY_ERROR;
+ drmach_flush_icache();
goto done;
}
- flush_windows();
-
/*
* jmp drmach_copy_rename_prog().
*/
@@ -3912,11 +4010,34 @@ done:
"detected during FMEM.\n");
}
}
- drmach_unlock_critical((caddr_t)prog);
+
+ /*
+ * This must be done after all strands have exit.
+ * Removing the TLB entry will affect both strands
+ * in the same core.
+ */
+
+ for (cpuid = 0; cpuid < NCPU; cpuid++) {
+ if (CPU_IN_SET(cpuset, cpuid)) {
+ xc_one(cpuid, (xcfunc_t *)drmach_unlock_critical,
+ (uint64_t)prog, 0);
+ }
+ }
in_sync = old_in_sync;
- kpreempt_enable();
+ /*
+ * we should unlock before the following lock to keep the kpreempt
+ * count correct.
+ */
+ (void) drmach_unlock_critical((caddr_t)prog);
+
+ /*
+ * we must remap again. TLB might have been removed in above xcall.
+ */
+
+ (void) drmach_lock_critical((caddr_t)prog_kmem, (caddr_t)prog);
+
if (prog->data->fmem_status.error == 0)
prog->data->fmem_status.error = rtn;
@@ -3926,4 +4047,5 @@ done:
prog->data->copy_wait_time/prog->data->stick_freq,
prog->data->slowest_cpuid);
}
+ drmach_unlock_critical((caddr_t)prog);
}
diff --git a/usr/src/uts/sun4u/opl/io/mc-opl.c b/usr/src/uts/sun4u/opl/io/mc-opl.c
index 555de55f75..7cd59aaf18 100644
--- a/usr/src/uts/sun4u/opl/io/mc-opl.c
+++ b/usr/src/uts/sun4u/opl/io/mc-opl.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
@@ -2583,6 +2583,33 @@ mc_suspend(mc_opl_t *mcp, uint32_t flag)
return (DDI_SUCCESS);
}
+void
+opl_mc_update_mlist(void)
+{
+ int i;
+ mc_opl_t *mcp;
+
+ /*
+ * memory information is not updated until
+ * the post attach/detach stage during DR.
+ * This interface is used by dr_mem to inform
+ * mc-opl to update the mlist.
+ */
+
+ mutex_enter(&mcmutex);
+ for (i = 0; i < OPL_MAX_BOARDS; i++) {
+ if ((mcp = mc_instances[i]) == NULL)
+ continue;
+ mutex_enter(&mcp->mc_lock);
+ if (mcp->mlist)
+ mc_memlist_delete(mcp->mlist);
+ mcp->mlist = NULL;
+ mc_get_mlist(mcp);
+ mutex_exit(&mcp->mc_lock);
+ }
+ mutex_exit(&mcmutex);
+}
+
/* caller must clear the SUSPEND bits or this will do nothing */
int
diff --git a/usr/src/uts/sun4u/opl/ml/drmach.il.cpp b/usr/src/uts/sun4u/opl/ml/drmach.il.cpp
index 24d9c195c2..87990a8efc 100644
--- a/usr/src/uts/sun4u/opl/ml/drmach.il.cpp
+++ b/usr/src/uts/sun4u/opl/ml/drmach.il.cpp
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -168,7 +168,7 @@ flush_instr_mem_il(caddr_t vaddr)
ENTRY_NP(flush_instr_mem_il)
flush %o0 ! address irrelevent
retl
- nop
+ nop
SET_SIZE(flush_instr_mem_il)
#endif /* lint */
@@ -191,8 +191,29 @@ drmach_sleep_il(void)
ENTRY_NP(drmach_sleep_il)
.word 0x81b01060
- retl
- nop
- SET_SIZE(flush_instr_mem_il)
+ retl
+ nop
+ SET_SIZE(drmach_sleep_il)
+
+#endif /* lint */
+
+#if defined(lint)
+
+/* ARGSUSED */
+void
+flush_windows_il(void)
+{}
+
+#else /* lint */
+
+/*
+ * flush_windows_il:
+ *
+ */
+
+ ENTRY_NP(flush_windows_il)
+ retl
+ flushw
+ SET_SIZE(flush_windows_il)
#endif /* lint */
diff --git a/usr/src/uts/sun4u/opl/ml/drmach_asm.s b/usr/src/uts/sun4u/opl/ml/drmach_asm.s
index 870b954b7c..d79b156303 100644
--- a/usr/src/uts/sun4u/opl/ml/drmach_asm.s
+++ b/usr/src/uts/sun4u/opl/ml/drmach_asm.s
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -121,7 +121,6 @@ drmach_fmem_loop_script(caddr_t critical, int size, caddr_t stat)
* is already in inconsistent state.
*/
2:
- mov %g0, %o1
mov ASI_L2_CTRL_RW_ADDR, %o3
ldxa [%o3]ASI_L2_CTRL, %o3
sethi %hi(ASI_L2_CTRL_UGE_TRAP), %o4
@@ -158,7 +157,6 @@ drmach_fmem_loop_script(caddr_t critical, int size, caddr_t stat)
*/
ba 2b
.word 0x81b01060
- nop
SET_SIZE(drmach_fmem_loop_script)
#endif /* lint */
diff --git a/usr/src/uts/sun4u/opl/os/opl.c b/usr/src/uts/sun4u/opl/os/opl.c
index 2d4b3f702e..2be4d5f95d 100644
--- a/usr/src/uts/sun4u/opl/os/opl.c
+++ b/usr/src/uts/sun4u/opl/os/opl.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -634,8 +634,8 @@ plat_lgrp_config(lgrp_config_flag_t evt, uintptr_t arg)
* Special handling for possible memory holes.
*/
if (tnode != -1 && mem_node_config[tnode].exists) {
- start = mem_node_config[mnode].physbase;
- end = mem_node_config[mnode].physmax;
+ start = mem_node_config[tnode].physbase;
+ end = mem_node_config[tnode].physmax;
mem_node_pre_del_slice(start, end);
mem_node_post_del_slice(start, end, 0);
}
diff --git a/usr/src/uts/sun4u/opl/sys/drmach.h b/usr/src/uts/sun4u/opl/sys/drmach.h
index 3a336b6422..0dd563245e 100644
--- a/usr/src/uts/sun4u/opl/sys/drmach.h
+++ b/usr/src/uts/sun4u/opl/sys/drmach.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -73,16 +73,15 @@ extern "C" {
#define FMEM_LOOP_EXIT 7
#define FMEM_NO_ERROR 0
-#define FMEM_OBP_FAIL 1
-#define FMEM_XC_TIMEOUT 2
-#define FMEM_COPY_TIMEOUT 3
-#define FMEM_SCF_BUSY 4
-#define FMEM_RETRY_OUT 5
-#define FMEM_TIMEOUT 6
-#define FMEM_HW_ERROR 7
-#define FMEM_TERMINATE 8
-#define FMEM_COPY_ERROR 9
-#define FMEM_SCF_ERR 10
+#define FMEM_XC_TIMEOUT 1
+#define FMEM_COPY_TIMEOUT 2
+#define FMEM_SCF_BUSY 3
+#define FMEM_RETRY_OUT 4
+#define FMEM_TIMEOUT 5
+#define FMEM_HW_ERROR 6
+#define FMEM_TERMINATE 7
+#define FMEM_COPY_ERROR 8
+#define FMEM_SCF_ERR 9
#define SCF_CMD_BUSY 0x8000
#define SCF_STATUS_READY 0x8000
@@ -100,6 +99,23 @@ extern "C" {
#define SCF_RETRY_CNT 15
+/*
+ * dynamic memory blocks cannot be added back to phys_install
+ * safely if the alignment is smaller than the largest
+ * physical page size the OS supports. The VM subsystem
+ * will try to coalesce smaller pages together and
+ * it assumes that the page structures are contiguous.
+ * That assumption does not hold so we have to work around it.
+ * On OPL, the largest page size is 256MB so we can just
+ * add such memory block back. For everything else,
+ * we round them up to 4MB boundaries and make sure
+ * they are disjoint from phys_install.
+ */
+
+#define MH_MPSS_ALIGNMENT (256 * 1024 * 1024)
+#define MH_MIN_ALIGNMENT (4 * 1024 * 1024)
+#define rounddown(x, y) ((x) & ~(y - 1))
+
#ifndef _ASM
/*
@@ -110,28 +126,68 @@ extern "C" {
typedef void *drmachid_t;
/*
- * We have to split up the copy rename data structure
- * into several pieces:
- * 1. critical region that must be locked in TLB and must
- * be physically contiguous/no ecache conflict.
- * This region contains the assembly code that handles
- * the rename programming, the slave code that loops
- * until the master script completes and all data
- * required to do the programming.
+ * There are several requirements to do copy rename:
+ * 1 There should be no subroutine calls/TLBmiss
+ * once the copying has begun.
+ * 2 There should be no external memory access by the CPU
+ * during the memory rename programming.
+ *
+ * All data and instruction pages used in the copy rename
+ * procedure are kept in locked pages to satisfy 1 and 2.
+ * However that is not enough. To satisfy 2, we must keep
+ * all the data and instructions in the 2 assembly routines
+ * drmach_fmem_loop_script and drmach_fmem_exec_script
+ * in the same contiguous page. They are packed into
+ * the 2nd 8K page of the buffer as shown in the diagram
+ * below.
+ *
+ * Note that it is important to keep the "critical"
+ * data in one 8K page to avoid any cache line
+ * contention. The assembly routines read all the
+ * critical data into the cache so that there is no
+ * external memory access during FMEM operation.
*
- * It also contains the status of each CPU because the
- * master must wait for all the slaves to get ready before
- * it can program the SCF.
+ * layout of the FMEM buffers:
+ * They are all locked in TLB and the critical data
+ * used in drmach_fmem_xxx assembly code are all
+ * packed in the second page.
*
- * We do not need the error code in the critical section.
- * It is not set until the FMEM is done.
- * 2. relocatable section that must be locked in TLB. All data
- * referenced in this section must also be locked in TLB to
- * avoid tlbmiss.
+ * 1st 8k page
+ * +--------------------------------+
+ * |drmach_copy_rename_program_t |
+ * +--------------------------------+
+ * |drmach_copy_rename_data_t |
+ * | |
+ * +--------------------------------+
+ *
+ * 2nd 8k page
+ * +--------------------------------+
+ * |drmach_copy_rename_critical_t |
+ * | |
+ * +--------------------------------+
+ * |run (drmach_copy_rename_prog__relocatable)
+ * |(roundup boundary to 1K) |
+ * +--------------------------------+
+ * | fmem_script |
+ * |(roundup boundary to 1K) |
+ * +--------------------------------+
+ * |loop_script |
+ * | |
+ * +--------------------------------+
+ * |at least 1K NOP/0's |
+ * | |
+ * +--------------------------------+
+ *
+ * 3rd 8k page
+ * +--------------------------------+
+ * |memlist_buffer (free_mlist) |
+ * | |
+ * +--------------------------------+
+ *
+ * 4th 8k page - drmach_cr_stat_t.
*
- * We will also put everything else in this section even it
- * does not need such protection.
*/
+
typedef struct {
int16_t scf_command;
int8_t scf_rsv1[2];
@@ -183,11 +239,10 @@ typedef struct {
volatile uchar_t error[NCPU];
struct memlist *c_ml;
struct memlist *cpu_ml[NCPU];
- caddr_t locked_va;
- tte_t locked_tte;
void (*mc_resume)(void);
int (*scf_fmem_end)(void);
int (*scf_fmem_cancel)(void);
+ uint64_t (*scf_get_base_addr)(void);
uint64_t copy_delay;
uint64_t stick_freq;
uint64_t copy_wait_time;
@@ -198,12 +253,14 @@ typedef struct {
uint64_t nbytes[NCPU];
} drmach_cr_stat_t;
-typedef struct {
- drmach_copy_rename_critical_t *critical;
- drmach_copy_rename_data_t *data;
- caddr_t memlist_buffer;
- struct memlist *free_mlist;
- drmach_cr_stat_t *stat;
+typedef struct drmach_copy_rename_program {
+ drmach_copy_rename_critical_t *critical;
+ struct drmach_copy_rename_program *locked_prog;
+ struct drmach_copy_rename_program *prog;
+ drmach_copy_rename_data_t *data;
+ caddr_t memlist_buffer;
+ struct memlist *free_mlist;
+ drmach_cr_stat_t *stat;
} drmach_copy_rename_program_t;
#define DRMACH_FMEM_LOCKED_PAGES 4
diff --git a/usr/src/uts/sun4u/opl/sys/opl_hwdesc.h b/usr/src/uts/sun4u/opl/sys/opl_hwdesc.h
index 19fffe91df..c9ecc9b1bc 100644
--- a/usr/src/uts/sun4u/opl/sys/opl_hwdesc.h
+++ b/usr/src/uts/sun4u/opl/sys/opl_hwdesc.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -125,7 +125,9 @@ typedef struct {
*/
typedef struct {
hwd_stat_t sb_status[HWD_SBS_PER_DOMAIN]; /* status of all LSBs */
- uint32_t sb_spare[15];
+ /* PSB number of respective LSB */
+ uint8_t sb_psb_number[HWD_SBS_PER_DOMAIN];
+ uint32_t sb_spare[7];
uint32_t sb_check_sum;
} hwd_sb_status_t;
@@ -169,7 +171,9 @@ typedef struct {
char dinf_banner_name[64]; /* system banner string */
char dinf_platform_token[64]; /* platform name */
uint32_t dinf_floating_board_bitmap; /* bit 0 = SB0 ... */
- uint32_t dinf_spare2[12];
+ char dinf_chassis_sn[16];
+ uint32_t dinf_brand_control;
+ uint32_t dinf_spare2[7];
uint32_t dinf_check_sum;
} hwd_domain_info_t;
diff --git a/usr/src/uts/sun4u/sys/sbd_ioctl.h b/usr/src/uts/sun4u/sys/sbd_ioctl.h
index a917f3833f..2bbd537b59 100644
--- a/usr/src/uts/sun4u/sys/sbd_ioctl.h
+++ b/usr/src/uts/sun4u/sys/sbd_ioctl.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -594,6 +594,14 @@ typedef struct {
/* drmach parameter is inappropriate for operation */
#define EOPL_INTERNAL 5011 /* Unexpected internal condition */
#define EOPL_FINDDEVICE 5012 /* Firmware cannot find node. */
+#define EOPL_MC_SETUP 5013 /* Cannot setup memory node */
+#define EOPL_CPU_STATE 5014 /* Invalid CPU/core state */
+#define EOPL_MC_OPL 5015 /* Cannot find mc-opl interface */
+#define EOPL_SCF_FMEM 5016 /* Cannot find scf_fmem interface */
+#define EOPL_FMEM_SETUP 5017 /* Error setting up FMEM buffer */
+#define EOPL_SCF_FMEM_START 5018 /* scf_fmem_start error */
+#define EOPL_FMEM_ERROR 5019 /* FMEM error */
+#define EOPL_SCF_FMEM_CANCEL 5020 /* scf_fmem_cancel error */
#ifdef __cplusplus
}