diff options
author | jl139090 <none@none> | 2007-01-03 11:36:28 -0800 |
---|---|---|
committer | jl139090 <none@none> | 2007-01-03 11:36:28 -0800 |
commit | 68ac2337c38c8af06edcf32a72e42de36ec72a9d (patch) | |
tree | 3d491af7977b6180e00da2501b3ac517462aa6cb /usr/src | |
parent | fa864c018a8a591e2185f96815ba4d33afb14236 (diff) | |
download | illumos-joyent-68ac2337c38c8af06edcf32a72e42de36ec72a9d.tar.gz |
6442804 memory leaks in drmach() modules
6442821 System hangs during addboard (OS configure phase)
6443020 Need IKP deprobe error handling code for OPL
6444087 SCF did not report error in case of a timeout
6445761 Support memoryless board in DR
6445769 MTLB hit panic during DR copy rename
6445772 uninitialized variable used in plat_lgrp_config
6455124 Not enough dictionary size in fcode interpreter for I/O Max Conf.
6457380 HW Descriptior specification update
6459708 Kernel Migration fails when tried second time.
6461633 DR review cleanups
6464256 DR RED_State panic while running it with psradm command
6464274 DR panic when migrating kernel from a board with memory hole.
6473299 Skipping of retired pages during copy-rename not working properly
6489095 flushw is needed in drmach_copy_rename_prog__relocatable
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 } |