25cf1a301a396c38e8adf52c15f537b80d2483f7jl * CDDL HEADER START
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * The contents of this file are subject to the terms of the
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Common Development and Distribution License (the "License").
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * You may not use this file except in compliance with the License.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * See the License for the specific language governing permissions
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * and limitations under the License.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * When distributing Covered Code, include this CDDL HEADER in each
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * If applicable, add the following below this CDDL HEADER, with the
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * fields enclosed by brackets "[]" replaced with your own identifying
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * information: Portions Copyright [yyyy] [name of copyright owner]
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * CDDL HEADER END
56f33205c9ed776c3c909e07d52e94610a675740Jonathan Adams * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Use is subject to license terms.
25cf1a301a396c38e8adf52c15f537b80d2483f7jlextern void flush_cache_il(void);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlextern void drmach_sleep_il(void);
25cf1a301a396c38e8adf52c15f537b80d2483f7jltypedef struct {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int (*n_getproplen)(struct drmach_node *node, char *name,
25cf1a301a396c38e8adf52c15f537b80d2483f7jltypedef struct {
25cf1a301a396c38e8adf52c15f537b80d2483f7jltypedef struct {
25cf1a301a396c38e8adf52c15f537b80d2483f7jltypedef struct {
25cf1a301a396c38e8adf52c15f537b80d2483f7jltypedef struct {
25cf1a301a396c38e8adf52c15f537b80d2483f7jltypedef struct {
25cf1a301a396c38e8adf52c15f537b80d2483f7jltypedef struct {
25cf1a301a396c38e8adf52c15f537b80d2483f7jltypedef struct {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl sbd_error_t *(*found)(void *a, const char *, int, drmachid_t);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic sbd_error_t *drmach_cpu_new(drmach_device_t *, drmachid_t *);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic sbd_error_t *drmach_mem_new(drmach_device_t *, drmachid_t *);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic sbd_error_t *drmach_io_new(drmach_device_t *, drmachid_t *);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic dev_info_t *drmach_node_ddi_get_dip(drmach_node_t *np);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic sbd_error_t *drmach_i_status(drmachid_t, drmach_status_t *);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic sbd_error_t *drmach_io_status(drmachid_t, drmach_status_t *);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic int drmach_init(void);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic void drmach_fini(void);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic void drmach_swap_pa(drmach_mem_t *, drmach_mem_t *);
8682d1ef2a0960ed5a9f05b9448eaa3e68ac931fRichard Lowestatic sbd_error_t *drmach_board_release(drmachid_t);
8682d1ef2a0960ed5a9f05b9448eaa3e68ac931fRichard Lowestatic sbd_error_t *drmach_board_status(drmachid_t, drmach_status_t *);
8682d1ef2a0960ed5a9f05b9448eaa3e68ac931fRichard Lowestatic sbd_error_t *drmach_cpu_release(drmachid_t);
8682d1ef2a0960ed5a9f05b9448eaa3e68ac931fRichard Lowestatic sbd_error_t *drmach_cpu_status(drmachid_t, drmach_status_t *);
8682d1ef2a0960ed5a9f05b9448eaa3e68ac931fRichard Lowestatic sbd_error_t *drmach_mem_release(drmachid_t);
8682d1ef2a0960ed5a9f05b9448eaa3e68ac931fRichard Lowestatic sbd_error_t *drmach_mem_status(drmachid_t, drmach_status_t *);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/* options for the second argument in drmach_add_remove_cpu() */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#define ON_BOARD_CORE_NUM(x) (((uint_t)(x) / OPL_MAX_STRANDID_PER_CORE) & \
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic int drmach_name2type_idx(char *);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlint drmach_debug = 1; /* set to non-zero to enable debug messages */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#endif /* DEBUG */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl ((id != 0) && \
25cf1a301a396c38e8adf52c15f537b80d2483f7jl ((id != 0) && \
25cf1a301a396c38e8adf52c15f537b80d2483f7jl ((id != 0) && \
25cf1a301a396c38e8adf52c15f537b80d2483f7jl ((id != 0) && \
25cf1a301a396c38e8adf52c15f537b80d2483f7jl ((id != 0) && \
25cf1a301a396c38e8adf52c15f537b80d2483f7jl ((id != 0) && \
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic struct {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/* utility */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * drmach autoconfiguration data structures and interfaces
25cf1a301a396c38e8adf52c15f537b80d2483f7jl "OPL DR 1.1"
e98fafb9956429b59c817d4fbd27720c73879203jl if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl rv = opl_read_hwd(mp->dev.bp->bnum, NULL, NULL, NULL, &hwd);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (rv != 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl for (i = 0; i < HWD_MAX_MEM_CHUNKS; i++) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * we intersect phys_install to get base_pa.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * This only works at bootup time.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* only cmp has board number */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* we have already pruned all unwanted cores and cpu's above */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl ddi_walk_devs(ddi_root_node(), drmach_cpu_cb, (void *)&arg);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl struct drmach_setup_core_arg *p = (struct drmach_setup_core_arg *)arg;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* only cmp has board number */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* we have already pruned all unwanted cores and cpu's above */
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic void
25cf1a301a396c38e8adf52c15f537b80d2483f7jl for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl ddi_walk_devs(ddi_root_node(), drmach_setup_core_cb, (void *)&arg);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * drmach_node_* routines serve the purpose of separating the
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * rest of the code from the device tree and OBP. This is necessary
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * because of In-Kernel-Probing. Devices probed after stod, are probed
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * by the in-kernel-prober, not OBP. These devices, therefore, do not
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * have dnode ids.
25cf1a301a396c38e8adf52c15f537b80d2483f7jltypedef struct {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * dip doesn't have to be held here as we are called
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * from ddi_walk_devs() which holds the dip.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Set "here" to NULL so that unheld dip is not accessible
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * outside ddi_walk_devs()
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* initialized args structure for callback */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Root node doesn't have to be held in any way.
e98fafb9956429b59c817d4fbd27720c73879203jl ddi_walk_devs(ddi_root_node(), drmach_node_ddi_walk_cb, (void *)&nargs);
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_node_ddi_get_parent(drmach_node_t *np, drmach_node_t *pp)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (np);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic void
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_node_ddi_get_prop(drmach_node_t *np, char *name, void *buf, int len)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (rv);
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_node_ddi_get_proplen(drmach_node_t *np, char *name, int *len)
e98fafb9956429b59c817d4fbd27720c73879203jl } else if (ddi_getproplen(DDI_DEV_T_ANY, ndip, DDI_PROP_DONTPASS, name,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (rv);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * drmach_array provides convenient array construction, access,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * bounds checking and array destruction logic.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl arr->arr_sz = (max_index - min_index + 1) * sizeof (void *);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_array_set(drmach_array_t *arr, int idx, drmachid_t val)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*NOTREACHED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_array_get(drmach_array_t *arr, int idx, drmachid_t *val)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*NOTREACHED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_array_first(drmach_array_t *arr, int *idx, drmachid_t *val)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (rv);
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_array_next(drmach_array_t *arr, int *idx, drmachid_t *val)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (rv);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic void
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_array_dispose(drmach_array_t *arr, void (*disposer)(drmachid_t))
25cf1a301a396c38e8adf52c15f537b80d2483f7jl while (rv == 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* If non-NULL, fdip is returned held and must be released */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl rv = node->n_getprop(node, "name", name, OBP_MAXDRVNAME);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* every node is expected to have a name */
e98fafb9956429b59c817d4fbd27720c73879203jl err = drerr_new(1, EOPL_GETPROP, "device node %s: property %s",
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * The node currently being examined is not listed in the name2type[]
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * array. In this case, the node is no interest to drmach. Both
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * dp and err are initialized here to yield nothing (no device or
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * error structure) for this case.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (i < 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* device specific new function will set unum */
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic void
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (void) drmach_board_name(bnum, bp->cm.name, sizeof (bp->cm.name));
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * If this is not bootup initialization, we have to wait till
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * IKP sets up the device nodes in drmach_board_connect().
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (void) drmach_array_set(drmach_boards, bnum, bp);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (bp);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic void
25cf1a301a396c38e8adf52c15f537b80d2483f7jl drmach_array_dispose(bp->devices, drmach_device_dispose);
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (void) strncpy(stat->type, "System Brd", sizeof (stat->type));
25cf1a301a396c38e8adf52c15f537b80d2483f7jl while (rv == 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return ((drmach_domain.floating & (1 << bp->bnum)) ? 1 : 0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (ddi_getproplen(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl cmn_err(CE_WARN, "Cannot get floating-boards proplen\n");
e98fafb9956429b59c817d4fbd27720c73879203jl rv = ddi_prop_op(DDI_DEV_T_ANY, rdip, PROP_LEN_AND_VAL_BUF,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl for (i = 0; i < len / sizeof (int); i++) {
e98fafb9956429b59c817d4fbd27720c73879203jl bnum = ddi_getprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Initialize the IKP feature.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * This can be done only after DR has acquired a hold on all the
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * device nodes that are interesting to IKP.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (opl_init_cfg() != 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl drmach_array_dispose(drmach_boards, drmach_board_dispose);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic void
25cf1a301a396c38e8adf52c15f537b80d2483f7jl drmach_array_dispose(drmach_boards, drmach_board_dispose);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Walk immediate children of the root devinfo node
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * releasing holds acquired on branches in drmach_init()
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Each system board contains 2 Oberon PCI bridge and
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * 1 CMUCH.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Each oberon has 2 channels.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Each channel has 2 pci-ex leaf.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Each CMUCH has 1 pci bus.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Device Path:
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * /pci@<portid>,reg
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * portid[10] = 0
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * portid[9:0] = LLEAF_ID[9:0] of the Oberon Channel
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * LLEAF_ID[9:8] = 0
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * LLEAF_ID[8:4] = LSB_ID[4:0]
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * LLEAF_ID[3:1] = IO Channel#[2:0] (0,1,2,3 for Oberon)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * channel 4 is pcicmu
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * LLEAF_ID[0] = PCI Leaf Number (0 for leaf-A, 1 for leaf-B)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Properties:
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * name = pci
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * device_type = "pciex"
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * board# = LSBID
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * reg = int32 * 2, Oberon CSR space of the leaf and the UBC space
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * portid = Jupiter Bus Device ID ((LSB_ID << 3)|pciport#)
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (void) snprintf(ip->dev.cm.name, sizeof (ip->dev.cm.name), "%s%d",
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic void
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_pre_op(int cmd, drmachid_t id, drmach_opts_t *opts)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* allow status and ncm operations to always succeed */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if ((cmd == SBD_CMD_STATUS) || (cmd == SBD_CMD_GETNCM)) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* check all other commands for the required option string */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl switch (cmd) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_post_op(int cmd, drmachid_t id, drmach_opts_t *opts)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic void
25cf1a301a396c38e8adf52c15f537b80d2483f7jl extern void cpu_flush_ecache(void);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic void
25cf1a301a396c38e8adf52c15f537b80d2483f7jl for (i = 0; i < NCPU; i++) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) {
e98fafb9956429b59c817d4fbd27720c73879203jl return (-1);
e98fafb9956429b59c817d4fbd27720c73879203jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_board_disconnect(drmachid_t id, drmach_opts_t *opts)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (rv == 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (np->n_getprop(np, "portid", &portid, sizeof (portid)) == 0)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Get the device_type property to see if we should
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * continue processing this node.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (np->n_getprop(np, "device_type", &type, sizeof (type)) != 0)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * We return cpuid because it has no portid
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (np->n_getprop(np, "cpuid", &portid, sizeof (portid)) == 0)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * This is a helper function to determine if a given
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * node should be considered for a dr operation according
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * to predefined dr type nodes and the node's name.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Formal Parameter : The name of a device node.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Return Value: -1, name does not map to a valid dr type.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * A value greater or equal to 0, name is a valid dr type.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Determine how many possible types are currently supported
25cf1a301a396c38e8adf52c15f537b80d2483f7jl ntypes = sizeof (drmach_name2type) / sizeof (drmach_name2type[0]);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* Determine if the node's name correspond to a predefined type. */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* The node is an allowed type for dr. */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * If the name of the node does not map to any of the
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * types in the array drmach_name2type then the node is not of
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * interest to dr.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * there is some complication on OPL:
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * - pseudo-mc nodes do not have portid property
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * - portid[9:5] of cmp node is LSB #, portid[7:3] of pci is LSB#
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * - cmp has board#
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * - core and cpu nodes do not have portid and board# properties
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * starcat uses portid to derive the board# but that does not work
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * for us. starfire reads board# property to filter the devices.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * That does not work either. So for these specific device,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * we use specific hard coded methods to get the board# -
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * cpu: LSB# = CPUID[9:5]
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_board_find_devices_cb(drmach_node_walk_args_t *args)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * core, cpu and pseudo-mc do not have portid
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * we use cpuid as the portid of the cpu node
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * for pseudo-mc, we do not use portid info.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl rv = node->n_getprop(node, "name", name, OBP_MAXDRVNAME);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl rv = node->n_getprop(node, OBP_BOARDNUM, &bnum, sizeof (bnum));
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * cpu does not have board# property. We use
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * CPUID[9:5]
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Create a device data structure from this node data.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * The call may yield nothing if the node is not of interest
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * to drmach.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl else if (!id) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * drmach_device_new examined the node we passed in
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * and determined that it was one not of interest to
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * drmach. So, it is skipped.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl data->err = (*data->found)(data->a, device->type, device->unum, id);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl sbd_error_t *(*found)(void *a, const char *, int, drmachid_t))
25cf1a301a396c38e8adf52c15f537b80d2483f7jl rv = drmach_node_walk(bp->tree, &data, drmach_board_find_devices_cb);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (rv == 0)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl drmach_array_dispose(bp->devices, drmach_device_dispose);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (rv);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_board_test(drmachid_t id, drmach_opts_t *opts, int force)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * We have to do more on OPL - e.g. set up sram tte, read cpuid, strand id,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * implementation #, etc
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* portid is CPUID of the node */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* unum = (CMP/CHIP ID) + (ON_BOARD_CORE_NUM * MAX_CMPID_PER_BOARD) */
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (void) snprintf(cp->dev.cm.name, sizeof (cp->dev.cm.name), "%s%d",
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * CPU ID representation
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * CPUID[9:5] = SB#
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * CPUID[4:3] = Chip#
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * CPUID[2:1] = Core# (Only 2 core for OPL)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * CPUID[0:0] = Strand#
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * reg property of the strand contains strand ID
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * reg property of the parent node contains core ID
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * We should use them.
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic void
25cf1a301a396c38e8adf52c15f537b80d2483f7jl extern int restart_other_cpu(int);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * NOTE: restart_other_cpu pauses cpus during the
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * slave cpu start. This helps to quiesce the
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * bus traffic a bit which makes the tick sync
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * routine in the prom more robust.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (void) strncpy(stat->type, dp->type, sizeof (stat->type));
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* get from cpu directly on OPL */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* the parent should be core */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (pp.n_getprop(&pp, "device_type", &type, sizeof (type)) != 0) {
e98fafb9956429b59c817d4fbd27720c73879203jl sizeof (impl)) != 0) {
e98fafb9956429b59c817d4fbd27720c73879203jl if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "name",
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* 4 is pcicmu channel */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* this cannot happen unless something bad happens */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (rv != 0)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (rv != 0)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (void) strncpy(stat->type, dp->type, sizeof (stat->type));
68ac2337c38c8af06edcf32a72e42de36ec72a9djl if ((proto->node->n_getproplen(proto->node, "mc-addr", &rv) < 0) ||
e98fafb9956429b59c817d4fbd27720c73879203jl (rv <= 0)) {
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (void) snprintf(mp->dev.cm.name, sizeof (mp->dev.cm.name), "%s",
68ac2337c38c8af06edcf32a72e42de36ec72a9djl /* make sure we do not create memoryless nodes */
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic void
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_mem_add_span(drmachid_t id, uint64_t basepa, uint64_t size)
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki cmn_err(CE_WARN, "%lu megabytes not available to kernel cage",
25cf1a301a396c38e8adf52c15f537b80d2483f7jl } else if (rv != 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* catch this in debug kernels */
e98fafb9956429b59c817d4fbd27720c73879203jl cmn_err(CE_WARN, "unexpected kcage_range_add return value %d",
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_mem_del_span(drmachid_t id, uint64_t basepa, uint64_t size)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (size > 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (rv != 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl "unexpected kcage_range_delete_post_mem_del"
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_mem_get_info(drmachid_t id, drmach_mem_info_t *mem)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * This is only used by dr to round up/down the memory
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * for copying. Our unit of memory isolation is 64 MB.
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_mem_get_memlist(drmachid_t id, struct memlist **ml)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Make sure the incoming memlist doesn't already
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * intersect with what's present in the system (phys_install).
e98fafb9956429b59c817d4fbd27720c73879203jl DRMACH_PR("Derived memlist intersects with phys_install\n");
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/* ARGSUSED */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* get starting physical address of target memory */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* round down to slice boundary */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* stop at first span that is in slice */
56f33205c9ed776c3c909e07d52e94610a675740Jonathan Adams for (ml = phys_install; ml; ml = ml->ml_next)
56f33205c9ed776c3c909e07d52e94610a675740Jonathan Adams if (ml->ml_address >= pa && ml->ml_address < pa + slice_size)
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (void) strncpy(stat->type, dp->dev.type, sizeof (stat->type));
25cf1a301a396c38e8adf52c15f537b80d2483f7jl drmach_array_dispose(bp->devices, drmach_device_dispose);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jl DRMACH_PR("calling opl_probe_board for bnum=%d\n", bp->bnum);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (rv != 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jl cmn_err(CE_CONT, "DR: in-kernel unprobe board %d\n", bp->bnum);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (rv != 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
56f33205c9ed776c3c909e07d52e94610a675740Jonathan Adams for (ml = phys_install; ml; ml = ml->ml_next) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* copy 32 bytes at arc_pa to dst_pa */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* increment by 32 bytes */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* decrement by 32 bytes */
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic struct {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl sbd_error_t *(*handler)(drmachid_t id, drmach_opts_t *opts);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* the following line must always be last */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (strncmp(drmach_pt_arr[i].name, opts->copts, len) == 0)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jl rv = dp->node->n_getprop(dp->node, "name", name, OBP_MAXDRVNAME);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Note: FORCE flag is no longer necessary under devfs
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * If non-NULL, fdip is returned held and must be released.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl DRMACH_PR("drmach_cpu_poweron: starting cpuid %d\n", cp->cpu_id);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * we must undo the hotadd or no one will do that
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * If this fails, we will do this again in
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * drmach_board_disconnect.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl bp->cores[onb_core_num].core_started |= (1 << strand_id);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl DRMACH_PR("drmach_cpu_poweroff: stopping cpuid %d\n", cp->cpu_id);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Capture all CPUs (except for detaching proc) to prevent
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * crosscalls to the detaching proc until it has cleared its
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * bit in cpu_ready_set.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * The CPU's remain paused and the prom_mutex is known to be free.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * This prevents the x-trap victim from blocking when doing prom
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * IEEE-1275 calls at a high PIL level.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Quiesce interrupts on the target CPU. We do this by setting
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * the CPU 'not ready'- (i.e. removing the CPU from cpu_ready_set) to
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * prevent it from receiving cross calls and cross traps.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * This prevents the processor from receiving any new soft interrupts.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (rv == 0)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_POWEROFF;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (rv == 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl CPU_SIGNATURE(OS_SIG, SIGST_DETACHED, SIGSUBST_NULL, cpuid);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl bp->cores[onb_core_num].core_started &= ~(1 << strand_id);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (rv);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Log a DR sysevent.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Return value: 0 success, non-zero failure.
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_log_sysevent(int board, char *hint, int flag, int verbose)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl DRMACH_PR("drmach_log_sysevent: %s %s, flag: %d, verbose: %d\n",
e98fafb9956429b59c817d4fbd27720c73879203jl if ((rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID, &evnt_val,
e98fafb9956429b59c817d4fbd27720c73879203jl if ((rv = sysevent_add_attr(&evnt_attr_list, DR_HINT, &evnt_val,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Log the event but do not sleep waiting for its
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * delivery. This provides insulation from syseventd.
e98fafb9956429b59c817d4fbd27720c73879203jl cmn_err(CE_WARN, "drmach_log_sysevent failed (rv %d) for %s "
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (rv);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * dr-status doesn't exist when DR is activated and
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * any warning messages aren't needed.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/* we are allocating memlist from TLB locked pages to avoid tlbmisses */
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic struct memlist *
56f33205c9ed776c3c909e07d52e94610a675740Jonathan Adams for (tl = ml = mlist; ml; tl = ml, ml = ml->ml_next) {
56f33205c9ed776c3c909e07d52e94610a675740Jonathan Adams } else if (base <= (ml->ml_address + ml->ml_size)) {
56f33205c9ed776c3c909e07d52e94610a675740Jonathan Adams MAX((base + len), (ml->ml_address + ml->ml_size)) -
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * The routine performs the necessary memory COPY and MC adr SWITCH.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Both operations MUST be at the same "level" so that the stack is
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * maintained correctly between the copy and switch. The switch
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * portion implements a caching mechanism to guarantee the code text
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * is cached prior to execution. This is to guard against possible
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * memory access while the MC adr's are being modified.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * IMPORTANT: The _drmach_copy_rename_end() function must immediately
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * follow drmach_copy_rename_prog__relocatable() so that the correct
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * "length" of the drmach_copy_rename_prog__relocatable can be
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * calculated. This routine MUST be a LEAF function, i.e. it can
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * make NO function calls, primarily for two reasons:
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * 1. We must keep the stack consistent across the "switch".
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * 2. Function calls are compiled to relative offsets, and
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * we execute this function we'll be executing it from
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * a copied version in a different area of memory, thus
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * the relative offsets will be bogus.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Moreover, it must have the "__relocatable" suffix to inform DTrace
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * providers (and anything else, for that matter) that this
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * function's text is manually relocated elsewhere before it is
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * executed. That is, it cannot be safely instrumented with any
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * methodology that is PC-relative.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * We multiply this to system_clock_frequency so we
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * are setting a delay of fmem_timeout second for
b307f191031b69156225d50e36c406311441051abm * the rename command.
b307f191031b69156225d50e36c406311441051abm * FMEM command itself should complete within 15 sec.
b307f191031b69156225d50e36c406311441051abm * We add 2 more sec to be conservative.
b307f191031b69156225d50e36c406311441051abm * Note that there is also a SCF BUSY bit checking
b307f191031b69156225d50e36c406311441051abm * in drmach_asm.s right before FMEM command is
b307f191031b69156225d50e36c406311441051abm * issued. XSCF sets the SCF BUSY bit when the
b307f191031b69156225d50e36c406311441051abm * other domain on the same PSB reboots and it
b307f191031b69156225d50e36c406311441051abm * will not be able to service the FMEM command
b307f191031b69156225d50e36c406311441051abm * within 15 sec. After setting the SCF BUSY
b307f191031b69156225d50e36c406311441051abm * bit, XSCF will wait a while before servicing
b307f191031b69156225d50e36c406311441051abm * other reboot command so there is no race
b307f191031b69156225d50e36c406311441051abm * condition.
b307f191031b69156225d50e36c406311441051abm * The empirical data on some OPL system shows that
b307f191031b69156225d50e36c406311441051abm * we can copy 250 MB per second. We set it to
b307f191031b69156225d50e36c406311441051abm * 80 MB to be conservative. In normal case,
b307f191031b69156225d50e36c406311441051abm * this timeout does not affect anything.
b307f191031b69156225d50e36c406311441051abm * This is the timeout value for the xcall synchronization
b307f191031b69156225d50e36c406311441051abm * to get all the CPU ready to do the parallel copying.
b307f191031b69156225d50e36c406311441051abm * Even on a fully loaded system, 10 sec. should be long
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * The following delay loop executes sleep instruction to yield the
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * CPU to other strands. If this is not done, some strand will tie
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * up the CPU in busy loops while the other strand cannot do useful
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * work. The copy procedure will take a much longer time without this.
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh/* Each loop is 2ms, timeout at 1000ms */
25cf1a301a396c38e8adf52c15f537b80d2483f7jldrmach_copy_rename_prog__relocatable(drmach_copy_rename_program_t *prog,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl extern void membar_sync_il();
25cf1a301a396c38e8adf52c15f537b80d2483f7jl extern void flush_instr_mem_il(void*);
68ac2337c38c8af06edcf32a72e42de36ec72a9djl extern void flush_windows_il(void);
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * flush_windows is moved here to make sure all
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * registers used in the callers are flushed to
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * memory before the copy.
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * If flush_windows() is called too early in the
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * calling function, the compiler might put some
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * data in the local registers after flush_windows().
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * After FMA, if there is any fill trap, the registers
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * will contain stale data.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl for (i = 0; i < NCPU; i++) {
e98fafb9956429b59c817d4fbd27720c73879203jl /* wait for all CPU's to be ready */
e98fafb9956429b59c817d4fbd27720c73879203jl for (;;) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl for (;;) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * DO COPY.
56f33205c9ed776c3c909e07d52e94610a675740Jonathan Adams for (ml = prog->data->cpu_ml[cpuid]; ml; ml = ml->ml_next) {
56f33205c9ed776c3c909e07d52e94610a675740Jonathan Adams s_pa = prog->data->s_copybasepa + ml->ml_address;
56f33205c9ed776c3c909e07d52e94610a675740Jonathan Adams t_pa = prog->data->t_copybasepa + ml->ml_address;
e98fafb9956429b59c817d4fbd27720c73879203jl * If the master has detected error, we just
e98fafb9956429b59c817d4fbd27720c73879203jl * bail out
e98fafb9956429b59c817d4fbd27720c73879203jl * This copy does NOT use an ASI
e98fafb9956429b59c817d4fbd27720c73879203jl * that avoids the Ecache, therefore
e98fafb9956429b59c817d4fbd27720c73879203jl * the dst_pa addresses may remain
e98fafb9956429b59c817d4fbd27720c73879203jl * in our Ecache after the dst_pa
e98fafb9956429b59c817d4fbd27720c73879203jl * has been removed from the system.
e98fafb9956429b59c817d4fbd27720c73879203jl * A subsequent write-back to memory
e98fafb9956429b59c817d4fbd27720c73879203jl * will cause an ARB-stop because the
e98fafb9956429b59c817d4fbd27720c73879203jl * physical address no longer exists
e98fafb9956429b59c817d4fbd27720c73879203jl * in the system. Therefore we must
e98fafb9956429b59c817d4fbd27720c73879203jl * flush out local Ecache after we
e98fafb9956429b59c817d4fbd27720c73879203jl * finish the copy.
e98fafb9956429b59c817d4fbd27720c73879203jl /* copy 32 bytes at src_pa to dst_pa */
e98fafb9956429b59c817d4fbd27720c73879203jl * increment the counter to signal that we are
e98fafb9956429b59c817d4fbd27720c73879203jl /* increment by 32 bytes */
e98fafb9956429b59c817d4fbd27720c73879203jl /* decrement by 32 bytes */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Since bcopy32_il() does NOT use an ASI to bypass
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * the Ecache, we need to flush our Ecache after
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * the copy is complete.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * drmach_fmem_exec_script()
25cf1a301a396c38e8adf52c15f537b80d2483f7jl for (i = 0; i < NCPU; i++) {
e98fafb9956429b59c817d4fbd27720c73879203jl for (;;) {
e98fafb9956429b59c817d4fbd27720c73879203jl * we get FMEM_LOOP_FMEM_READY in
e98fafb9956429b59c817d4fbd27720c73879203jl * normal case
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* got error traps */
e98fafb9956429b59c817d4fbd27720c73879203jl * if we have not reached limit, wait
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* now check if slave is alive */
e98fafb9956429b59c817d4fbd27720c73879203jl * no progress, perhaps just
e98fafb9956429b59c817d4fbd27720c73879203jl * finished
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* copy error */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * drmach_fmem_exec_script()
25cf1a301a396c38e8adf52c15f537b80d2483f7jl rtn = prog->critical->fmem((void *)prog->critical, PAGESIZE);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * drmach_fmem_loop_script()
e98fafb9956429b59c817d4fbd27720c73879203jl rtn = prog->critical->loop((void *)(prog->critical), PAGESIZE,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* slave thread does not care the rv */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic void
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * IMPORTANT: This function's location MUST be located immediately
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * following drmach_copy_rename_prog__relocatable to
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * accurately estimate its size. Note that this assumes
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * the compiler keeps these functions in the order in
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * which they appear :-o
68ac2337c38c8af06edcf32a72e42de36ec72a9djlstatic void
68ac2337c38c8af06edcf32a72e42de36ec72a9djl for (i = 0; i < DRMACH_FMEM_LOCKED_PAGES; i++) {
e98fafb9956429b59c817d4fbd27720c73879203jl sfmmu_memtte(&tte, va_to_pfn(va), PROC_DATA|HAT_NOSYNC, TTE8K);
68ac2337c38c8af06edcf32a72e42de36ec72a9djlstatic void
68ac2337c38c8af06edcf32a72e42de36ec72a9djl for (i = 0; i < DRMACH_FMEM_LOCKED_PAGES; i++) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl void (*mc_suspend)(void);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl void (*mc_resume)(void);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int (*scf_fmem_start)(int, int);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int (*scf_fmem_end)(void);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int (*scf_fmem_cancel)(void);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl for (i = 0; i < NCPU; i++) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * this kind of CPU will spin in cache
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Now check for any inactive CPU's that
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * have been hotadded. This can only occur in
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * error condition in drmach_cpu_poweron().
25cf1a301a396c38e8adf52c15f537b80d2483f7jl mc_suspend = (void (*)(void))
25cf1a301a396c38e8adf52c15f537b80d2483f7jl mc_resume = (void (*)(void))
25cf1a301a396c38e8adf52c15f537b80d2483f7jl scf_fmem_start = (int (*)(int, int))
25cf1a301a396c38e8adf52c15f537b80d2483f7jl scf_fmem_end = (int (*)(void))
25cf1a301a396c38e8adf52c15f537b80d2483f7jl scf_fmem_cancel = (int (*)(void))
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* calculate source and target base pa */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* adjust copy memlist addresses to be relative to copy base pa */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * bp will be page aligned, since we're calling
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * kmem_zalloc() with an exact multiple of PAGESIZE.
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * To avoid MTLB hit, we allocate a new VM space and remap
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * the kmem_alloc buffer to that address. This solves
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * 2 problems we found:
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * - the kmem_alloc buffer can be just a chunk inside
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * a much larger, e.g. 4MB buffer and MTLB will occur
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * if there are both a 4MB and a 8K TLB mapping to
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * the same VA range.
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * - the kmem mapping got dropped into the TLB by other
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * strands, unintentionally.
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * Note that the pointers like data, critical, memlist_buffer,
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * and stat inside the copy rename structure are mapped to this
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * alternate VM space so we must make sure we lock the TLB mapping
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * whenever we access data pointed to by these pointers.
68ac2337c38c8af06edcf32a72e42de36ec72a9djl /* Now remap prog_kmem to prog */
68ac2337c38c8af06edcf32a72e42de36ec72a9djl /* All pointers in prog are based on the alternate mapping */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl prog->data = (drmach_copy_rename_data_t *)roundup(((uint64_t)prog +
e98fafb9956429b59c817d4fbd27720c73879203jl sizeof (drmach_copy_rename_program_t)), sizeof (void *));
25cf1a301a396c38e8adf52c15f537b80d2483f7jl ASSERT(((uint64_t)prog->data + sizeof (drmach_copy_rename_data_t))
e98fafb9956429b59c817d4fbd27720c73879203jl prog->memlist_buffer = (caddr_t)(wp + DRMACH_FMEM_MLIST_PAGE *
e98fafb9956429b59c817d4fbd27720c73879203jl prog->stat = (drmach_cr_stat_t *)(wp + DRMACH_FMEM_STAT_PAGE *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* LINTED */
e98fafb9956429b59c817d4fbd27720c73879203jl ASSERT(sizeof (drmach_cr_stat_t) <= ((DRMACH_FMEM_LOCKED_PAGES -
25cf1a301a396c38e8adf52c15f537b80d2483f7jl prog->critical->scf_td[15] = ((0xaa + s_bd + t_bd) & 0xff);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl wp = (caddr_t)roundup((uint64_t)bp + len, sizeof (void *));
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * We always leave 1K nop's to prevent the processor from
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * speculative execution that causes memory access
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* this is the entry point of the loop script */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* now we make sure there is 1K extra */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl wp = (caddr_t)roundup((uint64_t)bp + len, sizeof (void *));
25cf1a301a396c38e8adf52c15f537b80d2483f7jl bcopy((caddr_t)drmach_copy_rename_prog__relocatable, wp, len);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl bcopy((caddr_t)drmach_fmem_loop_script, (void *)wp, len);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* now we are committed, call SCF, soft suspend mac patrol */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* soft suspend mac patrol */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * 0x30800000 is op code "ba,a +0"
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *(uint_t *)(prog->critical->loop_rtn) = (uint_t)(0x30800000);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * set the value of SCF FMEM TIMEOUT
25cf1a301a396c38e8adf52c15f537b80d2483f7jl prog->critical->delay = fmem_timeout * system_clock_freq;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl for (i = 0; i < NCPU; i++) {
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * max_elms - max number of memlist structures that
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * may be allocated for the CPU memory list.
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * If there are too many memory span (because
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * of fragmentation) than number of memlist
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * available, we should return error.
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * The parallel copy procedure is going to split some
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * of the elements of the original memory copy list.
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * The number of added elements can be up to
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * (max_cpu_num - 1). It means that max_cpu_num
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * should satisfy the following condition:
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * (max_cpu_num - 1) + mlist_size <= max_elms.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl for (i = 0; i < NCPU; i++) {
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * To reduce the level-2 cache contention only
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * one strand per core will participate
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * in the copy. If the strand with even cpu_id
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * number is present in the ready set, we will
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * include this strand in the copy set. If it
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * is not present in the ready set, we check for
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * the strand with the consecutive odd cpu_id
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * and include it, provided that it is
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * present in the ready set.
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh if (!(i & 0x1) ||
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * We cannot have more than
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * max_cpu_num CPUs in the copy
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * set, because each CPU has to
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * have at least one element
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh * long memory copy list.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl prog->data->copy_delay = ((copy_sz / min_copy_size_per_sec) + 2) *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl for (i = 0; i < NCPU; i++) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl while (sz) {
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh "Unexpected drmach_memlist_add_span"
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh " failure.");
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh "Unexpected drmach_memlist_add_span"
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh " failure.");
68ac2337c38c8af06edcf32a72e42de36ec72a9djl /* Unmap the alternate space. It will have to be remapped again */
6534c6f0d5bc646e300a0609f2ce9ed145013b95wh cmn_err(CE_WARN, "scf_fmem_cancel() failed rv=0x%x", rv);
68ac2337c38c8af06edcf32a72e42de36ec72a9djl kmem_free(prog_kmem, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Note that we have to delay calling SCF to find out the
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * status of the FMEM operation here because SCF cannot
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * respond while it is suspended.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * This create a small window when we are sure about the
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * base address of the system board.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * If there is any call to mc-opl to get memory unum,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * mc-opl will return UNKNOWN as the unum.
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * we have to remap again because all the pointer like data,
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * critical in prog are based on the alternate vmem space.
68ac2337c38c8af06edcf32a72e42de36ec72a9djl (void) drmach_lock_critical((caddr_t)prog, (caddr_t)prog->locked_prog);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* possible ops are SCF_START, MC_SUSPEND */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * If we get here, rename is successful.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Do all the copy rename post processing.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* soft resume mac patrol */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic void
25cf1a301a396c38e8adf52c15f537b80d2483f7jl extern void drmach_flush();
25cf1a301a396c38e8adf52c15f537b80d2483f7jl extern void membar_sync_il();
25cf1a301a396c38e8adf52c15f537b80d2483f7jl extern void drmach_flush_icache();
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * jmp drmach_copy_rename_prog().
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic void
25cf1a301a396c38e8adf52c15f537b80d2483f7jl cmn_err(CE_PANIC, "Cannot locate source or target board\n");
56f33205c9ed776c3c909e07d52e94610a675740Jonathan Adams for (ml = s_mem->memlist; ml; ml = ml->ml_next) {
56f33205c9ed776c3c909e07d52e94610a675740Jonathan Adams ml->ml_address = ml->ml_address - s_base + t_base;
56f33205c9ed776c3c909e07d52e94610a675740Jonathan Adams for (ml = t_mem->memlist; ml; ml = ml->ml_next) {
56f33205c9ed776c3c909e07d52e94610a675740Jonathan Adams ml->ml_address = ml->ml_address - t_base + s_base;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * IKP has to update the sb-mem-ranges for mac patrol driver
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * when it resumes, it will re-read the sb-mem-range property
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * to get the new base address
25cf1a301a396c38e8adf52c15f537b80d2483f7jl extern int in_sync;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl extern void drmach_sys_trap();
25cf1a301a396c38e8adf52c15f537b80d2483f7jl extern void drmach_flush();
25cf1a301a396c38e8adf52c15f537b80d2483f7jl extern void drmach_flush_icache();
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * We must immediately drop in the TLB because all pointers
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * are based on the alternate vmem space.
68ac2337c38c8af06edcf32a72e42de36ec72a9djl (void) drmach_lock_critical((caddr_t)prog_kmem, (caddr_t)prog);
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * we call scf to get the base address here becuase if scf
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * has not been suspended yet, the active path can be changing and
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * sometimes it is not even mapped. We call the interface when
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * the OS has been quiesced.
68ac2337c38c8af06edcf32a72e42de36ec72a9djl prog->critical->scf_reg_base = (*prog->data->scf_get_base_addr)();
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * jmp drmach_copy_rename_prog().
e98fafb9956429b59c817d4fbd27720c73879203jl prom_panic("URGENT_ERROR_TRAP is detected during FMEM.\n");
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * In normal case, all slave CPU's are still spinning in
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * the assembly code. The master has to patch the instruction
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * to get them out.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * In error case, e.g. COPY_ERROR, some slave CPU's might
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * have aborted and already returned and sset LOOP_EXIT status.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Some CPU might still be copying.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * In any case, some delay is necessary to give them
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * enough time to set the LOOP_EXIT status.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl for (;;) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Wait for all CPU to exit.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * However we do not want an infinite loop
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * so we detect hangup situation here.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * If the slave CPU is still copying data,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * we will continue to wait.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * In error cases, the master has already set
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * fmem_status.error to abort the copying.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * 1 m.s delay for them to abort copying and
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * return to drmach_copy_rename_slave to set
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * FMEM_LOOP_EXIT status should be enough.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl for (;;) {
e98fafb9956429b59c817d4fbd27720c73879203jl "FMEM.\n");
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * This must be done after all strands have exit.
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * Removing the TLB entry will affect both strands
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * in the same core.
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * we should unlock before the following lock to keep the kpreempt
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * count correct.
68ac2337c38c8af06edcf32a72e42de36ec72a9djl * we must remap again. TLB might have been removed in above xcall.
68ac2337c38c8af06edcf32a72e42de36ec72a9djl (void) drmach_lock_critical((caddr_t)prog_kmem, (caddr_t)prog);
e98fafb9956429b59c817d4fbd27720c73879203jl "during copy rename on CPU %d\n",