diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/lib/efcode/engine/init.c | 15 | ||||
-rw-r--r-- | usr/src/uts/sun4u/io/opl_cfg.c | 53 | ||||
-rw-r--r-- | usr/src/uts/sun4u/io/px/px_lib4u.c | 6 | ||||
-rw-r--r-- | usr/src/uts/sun4u/ngdr/io/dr.c | 8 | ||||
-rw-r--r-- | usr/src/uts/sun4u/opl/io/dr_mem.c | 300 | ||||
-rw-r--r-- | usr/src/uts/sun4u/opl/io/drmach.c | 346 | ||||
-rw-r--r-- | usr/src/uts/sun4u/opl/io/mc-opl.c | 29 | ||||
-rw-r--r-- | usr/src/uts/sun4u/opl/ml/drmach.il.cpp | 31 | ||||
-rw-r--r-- | usr/src/uts/sun4u/opl/ml/drmach_asm.s | 4 | ||||
-rw-r--r-- | usr/src/uts/sun4u/opl/os/opl.c | 6 | ||||
-rw-r--r-- | usr/src/uts/sun4u/opl/sys/drmach.h | 131 | ||||
-rw-r--r-- | usr/src/uts/sun4u/opl/sys/opl_hwdesc.h | 10 | ||||
-rw-r--r-- | usr/src/uts/sun4u/sys/sbd_ioctl.h | 10 |
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 } |