11772Sjl139090 /*
21772Sjl139090 * CDDL HEADER START
31772Sjl139090 *
41772Sjl139090 * The contents of this file are subject to the terms of the
51772Sjl139090 * Common Development and Distribution License (the "License").
61772Sjl139090 * You may not use this file except in compliance with the License.
71772Sjl139090 *
81772Sjl139090 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91772Sjl139090 * or http://www.opensolaris.org/os/licensing.
101772Sjl139090 * See the License for the specific language governing permissions
111772Sjl139090 * and limitations under the License.
121772Sjl139090 *
131772Sjl139090 * When distributing Covered Code, include this CDDL HEADER in each
141772Sjl139090 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151772Sjl139090 * If applicable, add the following below this CDDL HEADER, with the
161772Sjl139090 * fields enclosed by brackets "[]" replaced with your own identifying
171772Sjl139090 * information: Portions Copyright [yyyy] [name of copyright owner]
181772Sjl139090 *
191772Sjl139090 * CDDL HEADER END
201772Sjl139090 */
2111311SSurya.Prakki@Sun.COM
221772Sjl139090 /*
23*11474SJonathan.Adams@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
241772Sjl139090 * Use is subject to license terms.
251772Sjl139090 */
261772Sjl139090
271772Sjl139090 #include <sys/debug.h>
281772Sjl139090 #include <sys/types.h>
291772Sjl139090 #include <sys/varargs.h>
301772Sjl139090 #include <sys/errno.h>
311772Sjl139090 #include <sys/cred.h>
321772Sjl139090 #include <sys/dditypes.h>
331772Sjl139090 #include <sys/devops.h>
341772Sjl139090 #include <sys/modctl.h>
351772Sjl139090 #include <sys/poll.h>
361772Sjl139090 #include <sys/conf.h>
371772Sjl139090 #include <sys/ddi.h>
381772Sjl139090 #include <sys/sunddi.h>
391772Sjl139090 #include <sys/sunndi.h>
401772Sjl139090 #include <sys/ndi_impldefs.h>
411772Sjl139090 #include <sys/stat.h>
421772Sjl139090 #include <sys/kmem.h>
431772Sjl139090 #include <sys/vmem.h>
441772Sjl139090 #include <sys/opl_olympus_regs.h>
451772Sjl139090 #include <sys/cpuvar.h>
461772Sjl139090 #include <sys/cpupart.h>
471772Sjl139090 #include <sys/mem_config.h>
481772Sjl139090 #include <sys/ddi_impldefs.h>
491772Sjl139090 #include <sys/systm.h>
501772Sjl139090 #include <sys/machsystm.h>
511772Sjl139090 #include <sys/autoconf.h>
521772Sjl139090 #include <sys/cmn_err.h>
531772Sjl139090 #include <sys/sysmacros.h>
541772Sjl139090 #include <sys/x_call.h>
551772Sjl139090 #include <sys/promif.h>
561772Sjl139090 #include <sys/prom_plat.h>
571772Sjl139090 #include <sys/membar.h>
581772Sjl139090 #include <vm/seg_kmem.h>
591772Sjl139090 #include <sys/mem_cage.h>
601772Sjl139090 #include <sys/stack.h>
611772Sjl139090 #include <sys/archsystm.h>
621772Sjl139090 #include <vm/hat_sfmmu.h>
631772Sjl139090 #include <sys/pte.h>
641772Sjl139090 #include <sys/mmu.h>
651772Sjl139090 #include <sys/cpu_module.h>
661772Sjl139090 #include <sys/obpdefs.h>
671772Sjl139090 #include <sys/note.h>
681772Sjl139090 #include <sys/ontrap.h>
691772Sjl139090 #include <sys/cpu_sgnblk_defs.h>
701772Sjl139090 #include <sys/opl.h>
715037Sjl139090 #include <sys/cpu_impl.h>
721772Sjl139090
731772Sjl139090
741772Sjl139090 #include <sys/promimpl.h>
751772Sjl139090 #include <sys/prom_plat.h>
761772Sjl139090 #include <sys/kobj.h>
771772Sjl139090
781772Sjl139090 #include <sys/sysevent.h>
791772Sjl139090 #include <sys/sysevent/dr.h>
801772Sjl139090 #include <sys/sysevent/eventdefs.h>
811772Sjl139090
821772Sjl139090 #include <sys/drmach.h>
831772Sjl139090 #include <sys/dr_util.h>
841772Sjl139090
851772Sjl139090 #include <sys/fcode.h>
861772Sjl139090 #include <sys/opl_cfg.h>
871772Sjl139090
881772Sjl139090 extern void bcopy32_il(uint64_t, uint64_t);
891772Sjl139090 extern void flush_cache_il(void);
901772Sjl139090 extern void drmach_sleep_il(void);
911772Sjl139090
921772Sjl139090 typedef struct {
931772Sjl139090 struct drmach_node *node;
941772Sjl139090 void *data;
951772Sjl139090 } drmach_node_walk_args_t;
961772Sjl139090
971772Sjl139090 typedef struct drmach_node {
981772Sjl139090 void *here;
991772Sjl139090
1001772Sjl139090 pnode_t (*get_dnode)(struct drmach_node *node);
1011772Sjl139090 int (*walk)(struct drmach_node *node, void *data,
1021772Sjl139090 int (*cb)(drmach_node_walk_args_t *args));
1031772Sjl139090 dev_info_t *(*n_getdip)(struct drmach_node *node);
1041772Sjl139090 int (*n_getproplen)(struct drmach_node *node, char *name,
1051772Sjl139090 int *len);
1061772Sjl139090 int (*n_getprop)(struct drmach_node *node, char *name,
1071772Sjl139090 void *buf, int len);
1081772Sjl139090 int (*get_parent)(struct drmach_node *node,
1091772Sjl139090 struct drmach_node *pnode);
1101772Sjl139090 } drmach_node_t;
1111772Sjl139090
1121772Sjl139090 typedef struct {
1131772Sjl139090 int min_index;
1141772Sjl139090 int max_index;
1151772Sjl139090 int arr_sz;
1161772Sjl139090 drmachid_t *arr;
1171772Sjl139090 } drmach_array_t;
1181772Sjl139090
1191772Sjl139090 typedef struct {
1201772Sjl139090 void *isa;
1211772Sjl139090
1221772Sjl139090 void (*dispose)(drmachid_t);
1231772Sjl139090 sbd_error_t *(*release)(drmachid_t);
1241772Sjl139090 sbd_error_t *(*status)(drmachid_t, drmach_status_t *);
1251772Sjl139090
1261772Sjl139090 char name[MAXNAMELEN];
1271772Sjl139090 } drmach_common_t;
1281772Sjl139090
1291772Sjl139090 typedef struct {
1301772Sjl139090 uint32_t core_present;
1311772Sjl139090 uint32_t core_hotadded;
1321772Sjl139090 uint32_t core_started;
1331772Sjl139090 } drmach_cmp_t;
1341772Sjl139090
1351772Sjl139090 typedef struct {
1361772Sjl139090 drmach_common_t cm;
1371772Sjl139090 int bnum;
1381772Sjl139090 int assigned;
1391772Sjl139090 int powered;
1401772Sjl139090 int connected;
1411772Sjl139090 int cond;
1421772Sjl139090 drmach_node_t *tree;
1431772Sjl139090 drmach_array_t *devices;
1441772Sjl139090 int boot_board; /* if board exists on bootup */
1451772Sjl139090 drmach_cmp_t cores[OPL_MAX_COREID_PER_BOARD];
1461772Sjl139090 } drmach_board_t;
1471772Sjl139090
1481772Sjl139090 typedef struct {
1491772Sjl139090 drmach_common_t cm;
1501772Sjl139090 drmach_board_t *bp;
1511772Sjl139090 int unum;
1521772Sjl139090 int portid;
1531772Sjl139090 int busy;
1541772Sjl139090 int powered;
1551772Sjl139090 const char *type;
1561772Sjl139090 drmach_node_t *node;
1571772Sjl139090 } drmach_device_t;
1581772Sjl139090
1591772Sjl139090 typedef struct drmach_cpu {
1601772Sjl139090 drmach_device_t dev;
1611772Sjl139090 processorid_t cpuid;
1621772Sjl139090 int sb;
1631772Sjl139090 int chipid;
1641772Sjl139090 int coreid;
1651772Sjl139090 int strandid;
1661772Sjl139090 int status;
1671772Sjl139090 #define OPL_CPU_HOTADDED 1
1681772Sjl139090 } drmach_cpu_t;
1691772Sjl139090
1701772Sjl139090 typedef struct drmach_mem {
1711772Sjl139090 drmach_device_t dev;
1721772Sjl139090 uint64_t slice_base;
1731772Sjl139090 uint64_t slice_size;
1741772Sjl139090 uint64_t base_pa; /* lowest installed memory base */
1751772Sjl139090 uint64_t nbytes; /* size of installed memory */
1761772Sjl139090 struct memlist *memlist;
1771772Sjl139090 } drmach_mem_t;
1781772Sjl139090
1791772Sjl139090 typedef struct drmach_io {
1801772Sjl139090 drmach_device_t dev;
1811772Sjl139090 int channel;
1821772Sjl139090 int leaf;
1831772Sjl139090 } drmach_io_t;
1841772Sjl139090
1851772Sjl139090 typedef struct drmach_domain_info {
1861772Sjl139090 uint32_t floating;
1871772Sjl139090 int allow_dr;
1881772Sjl139090 } drmach_domain_info_t;
1891772Sjl139090
1901772Sjl139090 drmach_domain_info_t drmach_domain;
1911772Sjl139090
1921772Sjl139090 typedef struct {
1931772Sjl139090 int flags;
1941772Sjl139090 drmach_device_t *dp;
1951772Sjl139090 sbd_error_t *err;
1961772Sjl139090 dev_info_t *dip;
1971772Sjl139090 } drmach_config_args_t;
1981772Sjl139090
1991772Sjl139090 typedef struct {
2001772Sjl139090 drmach_board_t *obj;
2011772Sjl139090 int ndevs;
2021772Sjl139090 void *a;
2031772Sjl139090 sbd_error_t *(*found)(void *a, const char *, int, drmachid_t);
2041772Sjl139090 sbd_error_t *err;
2051772Sjl139090 } drmach_board_cb_data_t;
2061772Sjl139090
2071772Sjl139090 static drmach_array_t *drmach_boards;
2081772Sjl139090
2091772Sjl139090 static sbd_error_t *drmach_device_new(drmach_node_t *,
2101772Sjl139090 drmach_board_t *, int, drmachid_t *);
2111772Sjl139090 static sbd_error_t *drmach_cpu_new(drmach_device_t *, drmachid_t *);
2121772Sjl139090 static sbd_error_t *drmach_mem_new(drmach_device_t *, drmachid_t *);
2131772Sjl139090 static sbd_error_t *drmach_io_new(drmach_device_t *, drmachid_t *);
2141772Sjl139090
2151772Sjl139090 static dev_info_t *drmach_node_ddi_get_dip(drmach_node_t *np);
2161772Sjl139090 static int drmach_node_ddi_get_prop(drmach_node_t *np,
2171772Sjl139090 char *name, void *buf, int len);
2181772Sjl139090 static int drmach_node_ddi_get_proplen(drmach_node_t *np,
2191772Sjl139090 char *name, int *len);
2201772Sjl139090
2211772Sjl139090 static int drmach_get_portid(drmach_node_t *);
2221772Sjl139090 static sbd_error_t *drmach_i_status(drmachid_t, drmach_status_t *);
2231772Sjl139090 static int opl_check_dr_status();
2241772Sjl139090 static void drmach_io_dispose(drmachid_t);
2251772Sjl139090 static sbd_error_t *drmach_io_release(drmachid_t);
2261772Sjl139090 static sbd_error_t *drmach_io_status(drmachid_t, drmach_status_t *);
2271772Sjl139090 static int drmach_init(void);
2281772Sjl139090 static void drmach_fini(void);
2291772Sjl139090 static void drmach_swap_pa(drmach_mem_t *, drmach_mem_t *);
2301772Sjl139090 static drmach_board_t *drmach_get_board_by_bnum(int);
2311772Sjl139090
2321772Sjl139090 /* options for the second argument in drmach_add_remove_cpu() */
2331772Sjl139090 #define HOTADD_CPU 1
2341772Sjl139090 #define HOTREMOVE_CPU 2
2351772Sjl139090
2361772Sjl139090 #define ON_BOARD_CORE_NUM(x) (((uint_t)(x) / OPL_MAX_STRANDID_PER_CORE) & \
2371772Sjl139090 (OPL_MAX_COREID_PER_BOARD - 1))
2381772Sjl139090
2391772Sjl139090 extern struct cpu *SIGBCPU;
2401772Sjl139090
2411772Sjl139090 static int drmach_name2type_idx(char *);
2421772Sjl139090 static drmach_board_t *drmach_board_new(int, int);
2431772Sjl139090
2441772Sjl139090 #ifdef DEBUG
2451772Sjl139090
2461772Sjl139090 #define DRMACH_PR if (drmach_debug) printf
2471772Sjl139090 int drmach_debug = 1; /* set to non-zero to enable debug messages */
2481772Sjl139090 #else
2491772Sjl139090
2501772Sjl139090 #define DRMACH_PR _NOTE(CONSTANTCONDITION) if (0) printf
2511772Sjl139090 #endif /* DEBUG */
2521772Sjl139090
2531772Sjl139090
2541772Sjl139090 #define DRMACH_OBJ(id) ((drmach_common_t *)id)
2551772Sjl139090
2563493Sbm42561 #define DRMACH_NULL_ID(id) ((id) == 0)
2573493Sbm42561
2581772Sjl139090 #define DRMACH_IS_BOARD_ID(id) \
2591772Sjl139090 ((id != 0) && \
2601772Sjl139090 (DRMACH_OBJ(id)->isa == (void *)drmach_board_new))
2611772Sjl139090
2621772Sjl139090 #define DRMACH_IS_CPU_ID(id) \
2631772Sjl139090 ((id != 0) && \
2641772Sjl139090 (DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new))
2651772Sjl139090
2661772Sjl139090 #define DRMACH_IS_MEM_ID(id) \
2671772Sjl139090 ((id != 0) && \
2681772Sjl139090 (DRMACH_OBJ(id)->isa == (void *)drmach_mem_new))
2691772Sjl139090
2701772Sjl139090 #define DRMACH_IS_IO_ID(id) \
2711772Sjl139090 ((id != 0) && \
2721772Sjl139090 (DRMACH_OBJ(id)->isa == (void *)drmach_io_new))
2731772Sjl139090
2741772Sjl139090 #define DRMACH_IS_DEVICE_ID(id) \
2751772Sjl139090 ((id != 0) && \
2761772Sjl139090 (DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new || \
2771772Sjl139090 DRMACH_OBJ(id)->isa == (void *)drmach_mem_new || \
2781772Sjl139090 DRMACH_OBJ(id)->isa == (void *)drmach_io_new))
2791772Sjl139090
2801772Sjl139090 #define DRMACH_IS_ID(id) \
2811772Sjl139090 ((id != 0) && \
2821772Sjl139090 (DRMACH_OBJ(id)->isa == (void *)drmach_board_new || \
2831772Sjl139090 DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new || \
2841772Sjl139090 DRMACH_OBJ(id)->isa == (void *)drmach_mem_new || \
2851772Sjl139090 DRMACH_OBJ(id)->isa == (void *)drmach_io_new))
2861772Sjl139090
2871772Sjl139090 #define DRMACH_INTERNAL_ERROR() \
2881772Sjl139090 drerr_new(1, EOPL_INTERNAL, drmach_ie_fmt, __LINE__)
2891772Sjl139090
2901772Sjl139090 static char *drmach_ie_fmt = "drmach.c %d";
2911772Sjl139090
2921772Sjl139090 static struct {
2931772Sjl139090 const char *name;
2941772Sjl139090 const char *type;
2951772Sjl139090 sbd_error_t *(*new)(drmach_device_t *, drmachid_t *);
2961772Sjl139090 } drmach_name2type[] = {
2971772Sjl139090 { "cpu", DRMACH_DEVTYPE_CPU, drmach_cpu_new },
2981772Sjl139090 { "pseudo-mc", DRMACH_DEVTYPE_MEM, drmach_mem_new },
2991772Sjl139090 { "pci", DRMACH_DEVTYPE_PCI, drmach_io_new },
3001772Sjl139090 };
3011772Sjl139090
3021772Sjl139090 /* utility */
3031772Sjl139090 #define MBYTE (1048576ull)
3041772Sjl139090
3051772Sjl139090 /*
3061772Sjl139090 * drmach autoconfiguration data structures and interfaces
3071772Sjl139090 */
3081772Sjl139090
3091772Sjl139090 extern struct mod_ops mod_miscops;
3101772Sjl139090
3111772Sjl139090 static struct modlmisc modlmisc = {
3121772Sjl139090 &mod_miscops,
3131772Sjl139090 "OPL DR 1.1"
3141772Sjl139090 };
3151772Sjl139090
3161772Sjl139090 static struct modlinkage modlinkage = {
3171772Sjl139090 MODREV_1,
3181772Sjl139090 (void *)&modlmisc,
3191772Sjl139090 NULL
3201772Sjl139090 };
3211772Sjl139090
3221772Sjl139090 static krwlock_t drmach_boards_rwlock;
3231772Sjl139090
3241772Sjl139090 typedef const char *fn_t;
3251772Sjl139090
3261772Sjl139090 int
_init(void)3271772Sjl139090 _init(void)
3281772Sjl139090 {
3291772Sjl139090 int err;
3301772Sjl139090
3311772Sjl139090 if ((err = drmach_init()) != 0) {
3321772Sjl139090 return (err);
3331772Sjl139090 }
3341772Sjl139090
3351772Sjl139090 if ((err = mod_install(&modlinkage)) != 0) {
3361772Sjl139090 drmach_fini();
3371772Sjl139090 }
3381772Sjl139090
3391772Sjl139090 return (err);
3401772Sjl139090 }
3411772Sjl139090
3421772Sjl139090 int
_fini(void)3431772Sjl139090 _fini(void)
3441772Sjl139090 {
3451772Sjl139090 int err;
3461772Sjl139090
3471772Sjl139090 if ((err = mod_remove(&modlinkage)) == 0)
3481772Sjl139090 drmach_fini();
3491772Sjl139090
3501772Sjl139090 return (err);
3511772Sjl139090 }
3521772Sjl139090
3531772Sjl139090 int
_info(struct modinfo * modinfop)3541772Sjl139090 _info(struct modinfo *modinfop)
3551772Sjl139090 {
3561772Sjl139090 return (mod_info(&modlinkage, modinfop));
3571772Sjl139090 }
3581772Sjl139090
3591772Sjl139090 struct drmach_mc_lookup {
3601772Sjl139090 int bnum;
3611772Sjl139090 drmach_board_t *bp;
3621772Sjl139090 dev_info_t *dip; /* rv - set if found */
3631772Sjl139090 };
3641772Sjl139090
3651772Sjl139090 #define _ptob64(p) ((uint64_t)(p) << PAGESHIFT)
3661772Sjl139090 #define _b64top(b) ((pgcnt_t)((b) >> PAGESHIFT))
3671772Sjl139090
3681772Sjl139090 static int
drmach_setup_mc_info(dev_info_t * dip,drmach_mem_t * mp)3691772Sjl139090 drmach_setup_mc_info(dev_info_t *dip, drmach_mem_t *mp)
3701772Sjl139090 {
3711772Sjl139090 uint64_t memory_ranges[128];
3721772Sjl139090 int len;
3731772Sjl139090 struct memlist *ml;
3741772Sjl139090 int rv;
3751772Sjl139090 hwd_sb_t *hwd;
3761772Sjl139090 hwd_memory_t *pm;
3771772Sjl139090
3781772Sjl139090 len = sizeof (memory_ranges);
3795037Sjl139090 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
3805037Sjl139090 "sb-mem-ranges", (caddr_t)&memory_ranges[0], &len) !=
3815037Sjl139090 DDI_PROP_SUCCESS) {
3821772Sjl139090 mp->slice_base = 0;
3831772Sjl139090 mp->slice_size = 0;
3841772Sjl139090 return (-1);
3851772Sjl139090 }
3861772Sjl139090 mp->slice_base = memory_ranges[0];
3871772Sjl139090 mp->slice_size = memory_ranges[1];
3881772Sjl139090
3891772Sjl139090 if (!mp->dev.bp->boot_board) {
3901772Sjl139090 int i;
3911772Sjl139090
3921772Sjl139090 rv = opl_read_hwd(mp->dev.bp->bnum, NULL, NULL, NULL, &hwd);
3931772Sjl139090
3941772Sjl139090 if (rv != 0) {
3951772Sjl139090 return (-1);
3961772Sjl139090 }
3971772Sjl139090
3981772Sjl139090 ml = NULL;
3991772Sjl139090 pm = &hwd->sb_cmu.cmu_memory;
4001772Sjl139090 for (i = 0; i < HWD_MAX_MEM_CHUNKS; i++) {
4011772Sjl139090 if (pm->mem_chunks[i].chnk_size > 0) {
4021772Sjl139090 ml = memlist_add_span(ml,
4035037Sjl139090 pm->mem_chunks[i].chnk_start_address,
4045037Sjl139090 pm->mem_chunks[i].chnk_size);
4051772Sjl139090 }
4061772Sjl139090 }
4071772Sjl139090 } else {
4081772Sjl139090 /*
4091772Sjl139090 * we intersect phys_install to get base_pa.
4101772Sjl139090 * This only works at bootup time.
4111772Sjl139090 */
4121772Sjl139090
4131772Sjl139090 memlist_read_lock();
4141772Sjl139090 ml = memlist_dup(phys_install);
4151772Sjl139090 memlist_read_unlock();
4161772Sjl139090
4171772Sjl139090 ml = memlist_del_span(ml, 0ull, mp->slice_base);
4181772Sjl139090 if (ml) {
4191772Sjl139090 uint64_t basepa, endpa;
4201772Sjl139090 endpa = _ptob64(physmax + 1);
4211772Sjl139090
4221772Sjl139090 basepa = mp->slice_base + mp->slice_size;
4231772Sjl139090
4241772Sjl139090 ml = memlist_del_span(ml, basepa, endpa - basepa);
4251772Sjl139090 }
4261772Sjl139090 }
4271772Sjl139090
4281772Sjl139090 if (ml) {
4291772Sjl139090 uint64_t nbytes = 0;
4301772Sjl139090 struct memlist *p;
431*11474SJonathan.Adams@Sun.COM for (p = ml; p; p = p->ml_next) {
432*11474SJonathan.Adams@Sun.COM nbytes += p->ml_size;
4331772Sjl139090 }
4341772Sjl139090 if ((mp->nbytes = nbytes) > 0)
435*11474SJonathan.Adams@Sun.COM mp->base_pa = ml->ml_address;
4361772Sjl139090 else
4371772Sjl139090 mp->base_pa = 0;
4381772Sjl139090 mp->memlist = ml;
4391772Sjl139090 } else {
4401772Sjl139090 mp->base_pa = 0;
4411772Sjl139090 mp->nbytes = 0;
4421772Sjl139090 }
4431772Sjl139090 return (0);
4441772Sjl139090 }
4451772Sjl139090
4461772Sjl139090
4471772Sjl139090 struct drmach_hotcpu {
4481772Sjl139090 drmach_board_t *bp;
4491772Sjl139090 int bnum;
4501772Sjl139090 int core_id;
4511772Sjl139090 int rv;
4521772Sjl139090 int option;
4531772Sjl139090 };
4541772Sjl139090
4551772Sjl139090 static int
drmach_cpu_cb(dev_info_t * dip,void * arg)4561772Sjl139090 drmach_cpu_cb(dev_info_t *dip, void *arg)
4571772Sjl139090 {
4581772Sjl139090 struct drmach_hotcpu *p = (struct drmach_hotcpu *)arg;
4591772Sjl139090 char name[OBP_MAXDRVNAME];
4601772Sjl139090 int len = OBP_MAXDRVNAME;
4611772Sjl139090 int bnum, core_id, strand_id;
4621772Sjl139090 drmach_board_t *bp;
4631772Sjl139090
4641772Sjl139090 if (dip == ddi_root_node()) {
4651772Sjl139090 return (DDI_WALK_CONTINUE);
4661772Sjl139090 }
4671772Sjl139090
4681772Sjl139090 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
4691772Sjl139090 DDI_PROP_DONTPASS, "name",
4701772Sjl139090 (caddr_t)name, &len) != DDI_PROP_SUCCESS) {
4711772Sjl139090 return (DDI_WALK_PRUNECHILD);
4721772Sjl139090 }
4731772Sjl139090
4741772Sjl139090 /* only cmp has board number */
4751772Sjl139090 bnum = -1;
4761772Sjl139090 len = sizeof (bnum);
4771772Sjl139090 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
4781772Sjl139090 DDI_PROP_DONTPASS, OBP_BOARDNUM,
4791772Sjl139090 (caddr_t)&bnum, &len) != DDI_PROP_SUCCESS) {
4801772Sjl139090 bnum = -1;
4811772Sjl139090 }
4821772Sjl139090
4831772Sjl139090 if (strcmp(name, "cmp") == 0) {
4841772Sjl139090 if (bnum != p->bnum)
4851772Sjl139090 return (DDI_WALK_PRUNECHILD);
4861772Sjl139090 return (DDI_WALK_CONTINUE);
4871772Sjl139090 }
4881772Sjl139090 /* we have already pruned all unwanted cores and cpu's above */
4891772Sjl139090 if (strcmp(name, "core") == 0) {
4901772Sjl139090 return (DDI_WALK_CONTINUE);
4911772Sjl139090 }
4921772Sjl139090 if (strcmp(name, "cpu") == 0) {
4931772Sjl139090 processorid_t cpuid;
4941772Sjl139090 len = sizeof (cpuid);
4951772Sjl139090 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
4961772Sjl139090 DDI_PROP_DONTPASS, "cpuid",
4971772Sjl139090 (caddr_t)&cpuid, &len) != DDI_PROP_SUCCESS) {
4981772Sjl139090 p->rv = -1;
4991772Sjl139090 return (DDI_WALK_TERMINATE);
5001772Sjl139090 }
5011772Sjl139090
5021772Sjl139090 core_id = p->core_id;
5031772Sjl139090
5041772Sjl139090 bnum = LSB_ID(cpuid);
5051772Sjl139090
5061772Sjl139090 if (ON_BOARD_CORE_NUM(cpuid) != core_id)
5071772Sjl139090 return (DDI_WALK_CONTINUE);
5081772Sjl139090
5091772Sjl139090 bp = p->bp;
5101772Sjl139090 ASSERT(bnum == bp->bnum);
5111772Sjl139090
5121772Sjl139090 if (p->option == HOTADD_CPU) {
5131772Sjl139090 if (prom_hotaddcpu(cpuid) != 0) {
5141772Sjl139090 p->rv = -1;
5151772Sjl139090 return (DDI_WALK_TERMINATE);
5161772Sjl139090 }
5171772Sjl139090 strand_id = STRAND_ID(cpuid);
5181772Sjl139090 bp->cores[core_id].core_hotadded |= (1 << strand_id);
5191772Sjl139090 } else if (p->option == HOTREMOVE_CPU) {
5201772Sjl139090 if (prom_hotremovecpu(cpuid) != 0) {
5211772Sjl139090 p->rv = -1;
5221772Sjl139090 return (DDI_WALK_TERMINATE);
5231772Sjl139090 }
5241772Sjl139090 strand_id = STRAND_ID(cpuid);
5251772Sjl139090 bp->cores[core_id].core_hotadded &= ~(1 << strand_id);
5261772Sjl139090 }
5271772Sjl139090 return (DDI_WALK_CONTINUE);
5281772Sjl139090 }
5291772Sjl139090
5301772Sjl139090 return (DDI_WALK_PRUNECHILD);
5311772Sjl139090 }
5321772Sjl139090
5331772Sjl139090
5341772Sjl139090 static int
drmach_add_remove_cpu(int bnum,int core_id,int option)5351772Sjl139090 drmach_add_remove_cpu(int bnum, int core_id, int option)
5361772Sjl139090 {
5371772Sjl139090 struct drmach_hotcpu arg;
5381772Sjl139090 drmach_board_t *bp;
5391772Sjl139090
5401772Sjl139090 bp = drmach_get_board_by_bnum(bnum);
5411772Sjl139090 ASSERT(bp);
5421772Sjl139090
5431772Sjl139090 arg.bp = bp;
5441772Sjl139090 arg.bnum = bnum;
5451772Sjl139090 arg.core_id = core_id;
5461772Sjl139090 arg.rv = 0;
5471772Sjl139090 arg.option = option;
5481772Sjl139090 ddi_walk_devs(ddi_root_node(), drmach_cpu_cb, (void *)&arg);
5491772Sjl139090 return (arg.rv);
5501772Sjl139090 }
5511772Sjl139090
5521772Sjl139090 struct drmach_setup_core_arg {
5531772Sjl139090 drmach_board_t *bp;
5541772Sjl139090 };
5551772Sjl139090
5561772Sjl139090 static int
drmach_setup_core_cb(dev_info_t * dip,void * arg)5571772Sjl139090 drmach_setup_core_cb(dev_info_t *dip, void *arg)
5581772Sjl139090 {
5591772Sjl139090 struct drmach_setup_core_arg *p = (struct drmach_setup_core_arg *)arg;
5601772Sjl139090 char name[OBP_MAXDRVNAME];
5611772Sjl139090 int len = OBP_MAXDRVNAME;
5621772Sjl139090 int bnum;
5631772Sjl139090 int core_id, strand_id;
5641772Sjl139090
5651772Sjl139090 if (dip == ddi_root_node()) {
5661772Sjl139090 return (DDI_WALK_CONTINUE);
5671772Sjl139090 }
5681772Sjl139090
5691772Sjl139090 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
5701772Sjl139090 DDI_PROP_DONTPASS, "name",
5711772Sjl139090 (caddr_t)name, &len) != DDI_PROP_SUCCESS) {
5721772Sjl139090 return (DDI_WALK_PRUNECHILD);
5731772Sjl139090 }
5741772Sjl139090
5751772Sjl139090 /* only cmp has board number */
5761772Sjl139090 bnum = -1;
5771772Sjl139090 len = sizeof (bnum);
5781772Sjl139090 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
5791772Sjl139090 DDI_PROP_DONTPASS, OBP_BOARDNUM,
5801772Sjl139090 (caddr_t)&bnum, &len) != DDI_PROP_SUCCESS) {
5811772Sjl139090 bnum = -1;
5821772Sjl139090 }
5831772Sjl139090
5841772Sjl139090 if (strcmp(name, "cmp") == 0) {
5851772Sjl139090 if (bnum != p->bp->bnum)
5861772Sjl139090 return (DDI_WALK_PRUNECHILD);
5871772Sjl139090 return (DDI_WALK_CONTINUE);
5881772Sjl139090 }
5891772Sjl139090 /* we have already pruned all unwanted cores and cpu's above */
5901772Sjl139090 if (strcmp(name, "core") == 0) {
5911772Sjl139090 return (DDI_WALK_CONTINUE);
5921772Sjl139090 }
5931772Sjl139090 if (strcmp(name, "cpu") == 0) {
5941772Sjl139090 processorid_t cpuid;
5951772Sjl139090 len = sizeof (cpuid);
5961772Sjl139090 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
5971772Sjl139090 DDI_PROP_DONTPASS, "cpuid",
5981772Sjl139090 (caddr_t)&cpuid, &len) != DDI_PROP_SUCCESS) {
5991772Sjl139090 return (DDI_WALK_TERMINATE);
6001772Sjl139090 }
6011772Sjl139090 bnum = LSB_ID(cpuid);
6021772Sjl139090 ASSERT(bnum == p->bp->bnum);
6031772Sjl139090 core_id = ON_BOARD_CORE_NUM(cpuid);
6041772Sjl139090 strand_id = STRAND_ID(cpuid);
6051772Sjl139090 p->bp->cores[core_id].core_present |= (1 << strand_id);
6061772Sjl139090 return (DDI_WALK_CONTINUE);
6071772Sjl139090 }
6081772Sjl139090
6091772Sjl139090 return (DDI_WALK_PRUNECHILD);
6101772Sjl139090 }
6111772Sjl139090
6121772Sjl139090
6131772Sjl139090 static void
drmach_setup_core_info(drmach_board_t * obj)6141772Sjl139090 drmach_setup_core_info(drmach_board_t *obj)
6151772Sjl139090 {
6161772Sjl139090 struct drmach_setup_core_arg arg;
6171772Sjl139090 int i;
6181772Sjl139090
6191772Sjl139090 for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) {
6201772Sjl139090 obj->cores[i].core_present = 0;
6211772Sjl139090 obj->cores[i].core_hotadded = 0;
6221772Sjl139090 obj->cores[i].core_started = 0;
6231772Sjl139090 }
6241772Sjl139090 arg.bp = obj;
6251772Sjl139090 ddi_walk_devs(ddi_root_node(), drmach_setup_core_cb, (void *)&arg);
6261772Sjl139090
6271772Sjl139090 for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) {
6281772Sjl139090 if (obj->boot_board) {
6291772Sjl139090 obj->cores[i].core_hotadded =
6305037Sjl139090 obj->cores[i].core_started =
6315037Sjl139090 obj->cores[i].core_present;
6321772Sjl139090 }
6331772Sjl139090 }
6341772Sjl139090 }
6351772Sjl139090
6361772Sjl139090 /*
6371772Sjl139090 * drmach_node_* routines serve the purpose of separating the
6381772Sjl139090 * rest of the code from the device tree and OBP. This is necessary
6391772Sjl139090 * because of In-Kernel-Probing. Devices probed after stod, are probed
6401772Sjl139090 * by the in-kernel-prober, not OBP. These devices, therefore, do not
6411772Sjl139090 * have dnode ids.
6421772Sjl139090 */
6431772Sjl139090
6441772Sjl139090 typedef struct {
6451772Sjl139090 drmach_node_walk_args_t *nwargs;
6461772Sjl139090 int (*cb)(drmach_node_walk_args_t *args);
6471772Sjl139090 int err;
6481772Sjl139090 } drmach_node_ddi_walk_args_t;
6491772Sjl139090
6501772Sjl139090 static int
drmach_node_ddi_walk_cb(dev_info_t * dip,void * arg)6511772Sjl139090 drmach_node_ddi_walk_cb(dev_info_t *dip, void *arg)
6521772Sjl139090 {
6531772Sjl139090 drmach_node_ddi_walk_args_t *nargs;
6541772Sjl139090
6551772Sjl139090 nargs = (drmach_node_ddi_walk_args_t *)arg;
6561772Sjl139090
6571772Sjl139090 /*
6581772Sjl139090 * dip doesn't have to be held here as we are called
6591772Sjl139090 * from ddi_walk_devs() which holds the dip.
6601772Sjl139090 */
6611772Sjl139090 nargs->nwargs->node->here = (void *)dip;
6621772Sjl139090
6631772Sjl139090 nargs->err = nargs->cb(nargs->nwargs);
6641772Sjl139090
6651772Sjl139090
6661772Sjl139090 /*
6671772Sjl139090 * Set "here" to NULL so that unheld dip is not accessible
6681772Sjl139090 * outside ddi_walk_devs()
6691772Sjl139090 */
6701772Sjl139090 nargs->nwargs->node->here = NULL;
6711772Sjl139090
6721772Sjl139090 if (nargs->err)
6731772Sjl139090 return (DDI_WALK_TERMINATE);
6741772Sjl139090 else
6751772Sjl139090 return (DDI_WALK_CONTINUE);
6761772Sjl139090 }
6771772Sjl139090
6781772Sjl139090 static int
drmach_node_ddi_walk(drmach_node_t * np,void * data,int (* cb)(drmach_node_walk_args_t * args))6791772Sjl139090 drmach_node_ddi_walk(drmach_node_t *np, void *data,
6801772Sjl139090 int (*cb)(drmach_node_walk_args_t *args))
6811772Sjl139090 {
6821772Sjl139090 drmach_node_walk_args_t args;
6831772Sjl139090 drmach_node_ddi_walk_args_t nargs;
6841772Sjl139090
6851772Sjl139090
6861772Sjl139090 /* initialized args structure for callback */
6871772Sjl139090 args.node = np;
6881772Sjl139090 args.data = data;
6891772Sjl139090
6901772Sjl139090 nargs.nwargs = &args;
6911772Sjl139090 nargs.cb = cb;
6921772Sjl139090 nargs.err = 0;
6931772Sjl139090
6941772Sjl139090 /*
6951772Sjl139090 * Root node doesn't have to be held in any way.
6961772Sjl139090 */
6975037Sjl139090 ddi_walk_devs(ddi_root_node(), drmach_node_ddi_walk_cb, (void *)&nargs);
6981772Sjl139090
6991772Sjl139090 return (nargs.err);
7001772Sjl139090 }
7011772Sjl139090
7021772Sjl139090 static int
drmach_node_ddi_get_parent(drmach_node_t * np,drmach_node_t * pp)7031772Sjl139090 drmach_node_ddi_get_parent(drmach_node_t *np, drmach_node_t *pp)
7041772Sjl139090 {
7051772Sjl139090 dev_info_t *ndip;
7061772Sjl139090 static char *fn = "drmach_node_ddi_get_parent";
7071772Sjl139090
7081772Sjl139090 ndip = np->n_getdip(np);
7091772Sjl139090 if (ndip == NULL) {
7101772Sjl139090 cmn_err(CE_WARN, "%s: NULL dip", fn);
7111772Sjl139090 return (-1);
7121772Sjl139090 }
7131772Sjl139090
7141772Sjl139090 bcopy(np, pp, sizeof (drmach_node_t));
7151772Sjl139090
7161772Sjl139090 pp->here = (void *)ddi_get_parent(ndip);
7171772Sjl139090 if (pp->here == NULL) {
7181772Sjl139090 cmn_err(CE_WARN, "%s: NULL parent dip", fn);
7191772Sjl139090 return (-1);
7201772Sjl139090 }
7211772Sjl139090
7221772Sjl139090 return (0);
7231772Sjl139090 }
7241772Sjl139090
7251772Sjl139090 /*ARGSUSED*/
7261772Sjl139090 static pnode_t
drmach_node_ddi_get_dnode(drmach_node_t * np)7271772Sjl139090 drmach_node_ddi_get_dnode(drmach_node_t *np)
7281772Sjl139090 {
7291772Sjl139090 return ((pnode_t)NULL);
7301772Sjl139090 }
7311772Sjl139090
7321772Sjl139090 static drmach_node_t *
drmach_node_new(void)7331772Sjl139090 drmach_node_new(void)
7341772Sjl139090 {
7351772Sjl139090 drmach_node_t *np;
7361772Sjl139090
7371772Sjl139090 np = kmem_zalloc(sizeof (drmach_node_t), KM_SLEEP);
7381772Sjl139090
7391772Sjl139090 np->get_dnode = drmach_node_ddi_get_dnode;
7401772Sjl139090 np->walk = drmach_node_ddi_walk;
7411772Sjl139090 np->n_getdip = drmach_node_ddi_get_dip;
7421772Sjl139090 np->n_getproplen = drmach_node_ddi_get_proplen;
7431772Sjl139090 np->n_getprop = drmach_node_ddi_get_prop;
7441772Sjl139090 np->get_parent = drmach_node_ddi_get_parent;
7451772Sjl139090
7461772Sjl139090 return (np);
7471772Sjl139090 }
7481772Sjl139090
7491772Sjl139090 static void
drmach_node_dispose(drmach_node_t * np)7501772Sjl139090 drmach_node_dispose(drmach_node_t *np)
7511772Sjl139090 {
7521772Sjl139090 kmem_free(np, sizeof (*np));
7531772Sjl139090 }
7541772Sjl139090
7551772Sjl139090 static dev_info_t *
drmach_node_ddi_get_dip(drmach_node_t * np)7561772Sjl139090 drmach_node_ddi_get_dip(drmach_node_t *np)
7571772Sjl139090 {
7581772Sjl139090 return ((dev_info_t *)np->here);
7591772Sjl139090 }
7601772Sjl139090
7611772Sjl139090 static int
drmach_node_walk(drmach_node_t * np,void * param,int (* cb)(drmach_node_walk_args_t * args))7621772Sjl139090 drmach_node_walk(drmach_node_t *np, void *param,
7631772Sjl139090 int (*cb)(drmach_node_walk_args_t *args))
7641772Sjl139090 {
7651772Sjl139090 return (np->walk(np, param, cb));
7661772Sjl139090 }
7671772Sjl139090
7681772Sjl139090 static int
drmach_node_ddi_get_prop(drmach_node_t * np,char * name,void * buf,int len)7691772Sjl139090 drmach_node_ddi_get_prop(drmach_node_t *np, char *name, void *buf, int len)
7701772Sjl139090 {
7711772Sjl139090 int rv = 0;
7721772Sjl139090 dev_info_t *ndip;
7731772Sjl139090 static char *fn = "drmach_node_ddi_get_prop";
7741772Sjl139090
7751772Sjl139090
7761772Sjl139090 ndip = np->n_getdip(np);
7771772Sjl139090 if (ndip == NULL) {
7781772Sjl139090 cmn_err(CE_WARN, "%s: NULL dip", fn);
7791772Sjl139090 rv = -1;
7801772Sjl139090 } else if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ndip,
7811772Sjl139090 DDI_PROP_DONTPASS, name,
7821772Sjl139090 (caddr_t)buf, &len) != DDI_PROP_SUCCESS) {
7831772Sjl139090 rv = -1;
7841772Sjl139090 }
7851772Sjl139090
7861772Sjl139090 return (rv);
7871772Sjl139090 }
7881772Sjl139090
7891772Sjl139090 static int
drmach_node_ddi_get_proplen(drmach_node_t * np,char * name,int * len)7901772Sjl139090 drmach_node_ddi_get_proplen(drmach_node_t *np, char *name, int *len)
7911772Sjl139090 {
7921772Sjl139090 int rv = 0;
7931772Sjl139090 dev_info_t *ndip;
7941772Sjl139090
7951772Sjl139090 ndip = np->n_getdip(np);
7961772Sjl139090 if (ndip == NULL) {
7971772Sjl139090 rv = -1;
7985037Sjl139090 } else if (ddi_getproplen(DDI_DEV_T_ANY, ndip, DDI_PROP_DONTPASS, name,
7995037Sjl139090 len) != DDI_PROP_SUCCESS) {
8001772Sjl139090 rv = -1;
8011772Sjl139090 }
8021772Sjl139090
8031772Sjl139090 return (rv);
8041772Sjl139090 }
8051772Sjl139090
8061772Sjl139090 static drmachid_t
drmach_node_dup(drmach_node_t * np)8071772Sjl139090 drmach_node_dup(drmach_node_t *np)
8081772Sjl139090 {
8091772Sjl139090 drmach_node_t *dup;
8101772Sjl139090
8111772Sjl139090 dup = drmach_node_new();
8121772Sjl139090 dup->here = np->here;
8131772Sjl139090 dup->get_dnode = np->get_dnode;
8141772Sjl139090 dup->walk = np->walk;
8151772Sjl139090 dup->n_getdip = np->n_getdip;
8161772Sjl139090 dup->n_getproplen = np->n_getproplen;
8171772Sjl139090 dup->n_getprop = np->n_getprop;
8181772Sjl139090 dup->get_parent = np->get_parent;
8191772Sjl139090
8201772Sjl139090 return (dup);
8211772Sjl139090 }
8221772Sjl139090
8231772Sjl139090 /*
8241772Sjl139090 * drmach_array provides convenient array construction, access,
8251772Sjl139090 * bounds checking and array destruction logic.
8261772Sjl139090 */
8271772Sjl139090
8281772Sjl139090 static drmach_array_t *
drmach_array_new(int min_index,int max_index)8291772Sjl139090 drmach_array_new(int min_index, int max_index)
8301772Sjl139090 {
8311772Sjl139090 drmach_array_t *arr;
8321772Sjl139090
8331772Sjl139090 arr = kmem_zalloc(sizeof (drmach_array_t), KM_SLEEP);
8341772Sjl139090
8351772Sjl139090 arr->arr_sz = (max_index - min_index + 1) * sizeof (void *);
8361772Sjl139090 if (arr->arr_sz > 0) {
8371772Sjl139090 arr->min_index = min_index;
8381772Sjl139090 arr->max_index = max_index;
8391772Sjl139090
8401772Sjl139090 arr->arr = kmem_zalloc(arr->arr_sz, KM_SLEEP);
8411772Sjl139090 return (arr);
8421772Sjl139090 } else {
8431772Sjl139090 kmem_free(arr, sizeof (*arr));
8441772Sjl139090 return (0);
8451772Sjl139090 }
8461772Sjl139090 }
8471772Sjl139090
8481772Sjl139090 static int
drmach_array_set(drmach_array_t * arr,int idx,drmachid_t val)8491772Sjl139090 drmach_array_set(drmach_array_t *arr, int idx, drmachid_t val)
8501772Sjl139090 {
8511772Sjl139090 if (idx < arr->min_index || idx > arr->max_index)
8521772Sjl139090 return (-1);
8531772Sjl139090 else {
8541772Sjl139090 arr->arr[idx - arr->min_index] = val;
8551772Sjl139090 return (0);
8561772Sjl139090 }
8571772Sjl139090 /*NOTREACHED*/
8581772Sjl139090 }
8591772Sjl139090
8601772Sjl139090 static int
drmach_array_get(drmach_array_t * arr,int idx,drmachid_t * val)8611772Sjl139090 drmach_array_get(drmach_array_t *arr, int idx, drmachid_t *val)
8621772Sjl139090 {
8631772Sjl139090 if (idx < arr->min_index || idx > arr->max_index)
8641772Sjl139090 return (-1);
8651772Sjl139090 else {
8661772Sjl139090 *val = arr->arr[idx - arr->min_index];
8671772Sjl139090 return (0);
8681772Sjl139090 }
8691772Sjl139090 /*NOTREACHED*/
8701772Sjl139090 }
8711772Sjl139090
8721772Sjl139090 static int
drmach_array_first(drmach_array_t * arr,int * idx,drmachid_t * val)8731772Sjl139090 drmach_array_first(drmach_array_t *arr, int *idx, drmachid_t *val)
8741772Sjl139090 {
8751772Sjl139090 int rv;
8761772Sjl139090
8771772Sjl139090 *idx = arr->min_index;
8781772Sjl139090 while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL)
8791772Sjl139090 *idx += 1;
8801772Sjl139090
8811772Sjl139090 return (rv);
8821772Sjl139090 }
8831772Sjl139090
8841772Sjl139090 static int
drmach_array_next(drmach_array_t * arr,int * idx,drmachid_t * val)8851772Sjl139090 drmach_array_next(drmach_array_t *arr, int *idx, drmachid_t *val)
8861772Sjl139090 {
8871772Sjl139090 int rv;
8881772Sjl139090
8891772Sjl139090 *idx += 1;
8901772Sjl139090 while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL)
8911772Sjl139090 *idx += 1;
8921772Sjl139090
8931772Sjl139090 return (rv);
8941772Sjl139090 }
8951772Sjl139090
8961772Sjl139090 static void
drmach_array_dispose(drmach_array_t * arr,void (* disposer)(drmachid_t))8971772Sjl139090 drmach_array_dispose(drmach_array_t *arr, void (*disposer)(drmachid_t))
8981772Sjl139090 {
8991772Sjl139090 drmachid_t val;
9001772Sjl139090 int idx;
9011772Sjl139090 int rv;
9021772Sjl139090
9031772Sjl139090 rv = drmach_array_first(arr, &idx, &val);
9041772Sjl139090 while (rv == 0) {
9051772Sjl139090 (*disposer)(val);
9061772Sjl139090 rv = drmach_array_next(arr, &idx, &val);
9071772Sjl139090 }
9081772Sjl139090
9091772Sjl139090 kmem_free(arr->arr, arr->arr_sz);
9101772Sjl139090 kmem_free(arr, sizeof (*arr));
9111772Sjl139090 }
9121772Sjl139090
9131772Sjl139090 static drmach_board_t *
drmach_get_board_by_bnum(int bnum)9141772Sjl139090 drmach_get_board_by_bnum(int bnum)
9151772Sjl139090 {
9161772Sjl139090 drmachid_t id;
9171772Sjl139090
9181772Sjl139090 if (drmach_array_get(drmach_boards, bnum, &id) == 0)
9191772Sjl139090 return ((drmach_board_t *)id);
9201772Sjl139090 else
9211772Sjl139090 return (NULL);
9221772Sjl139090 }
9231772Sjl139090
9241772Sjl139090 static pnode_t
drmach_node_get_dnode(drmach_node_t * np)9251772Sjl139090 drmach_node_get_dnode(drmach_node_t *np)
9261772Sjl139090 {
9271772Sjl139090 return (np->get_dnode(np));
9281772Sjl139090 }
9291772Sjl139090
9301772Sjl139090 /*ARGSUSED*/
9311772Sjl139090 sbd_error_t *
drmach_configure(drmachid_t id,int flags)9321772Sjl139090 drmach_configure(drmachid_t id, int flags)
9331772Sjl139090 {
9341772Sjl139090 drmach_device_t *dp;
9351772Sjl139090 sbd_error_t *err = NULL;
9361772Sjl139090 dev_info_t *rdip;
9371772Sjl139090 dev_info_t *fdip = NULL;
9381772Sjl139090
9391772Sjl139090 if (DRMACH_IS_CPU_ID(id)) {
9401772Sjl139090 return (NULL);
9411772Sjl139090 }
9421772Sjl139090 if (!DRMACH_IS_DEVICE_ID(id))
9431772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
9441772Sjl139090 dp = id;
9451772Sjl139090 rdip = dp->node->n_getdip(dp->node);
9461772Sjl139090
9471772Sjl139090 ASSERT(rdip);
9481772Sjl139090
9491772Sjl139090 ASSERT(e_ddi_branch_held(rdip));
9501772Sjl139090
9511772Sjl139090 if (e_ddi_branch_configure(rdip, &fdip, 0) != 0) {
9521772Sjl139090 char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
9531772Sjl139090 dev_info_t *dip = (fdip != NULL) ? fdip : rdip;
9541772Sjl139090
9551772Sjl139090 (void) ddi_pathname(dip, path);
9561772Sjl139090 err = drerr_new(1, EOPL_DRVFAIL, path);
9571772Sjl139090
9581772Sjl139090 kmem_free(path, MAXPATHLEN);
9591772Sjl139090
9601772Sjl139090 /* If non-NULL, fdip is returned held and must be released */
9611772Sjl139090 if (fdip != NULL)
9621772Sjl139090 ddi_release_devi(fdip);
9631772Sjl139090 }
9641772Sjl139090
9651772Sjl139090 return (err);
9661772Sjl139090 }
9671772Sjl139090
9681772Sjl139090
9691772Sjl139090 static sbd_error_t *
drmach_device_new(drmach_node_t * node,drmach_board_t * bp,int portid,drmachid_t * idp)9701772Sjl139090 drmach_device_new(drmach_node_t *node,
9711772Sjl139090 drmach_board_t *bp, int portid, drmachid_t *idp)
9721772Sjl139090 {
9731772Sjl139090 int i;
9741772Sjl139090 int rv;
9751772Sjl139090 drmach_device_t proto;
9761772Sjl139090 sbd_error_t *err;
9771772Sjl139090 char name[OBP_MAXDRVNAME];
9781772Sjl139090
9791772Sjl139090 rv = node->n_getprop(node, "name", name, OBP_MAXDRVNAME);
9801772Sjl139090 if (rv) {
9811772Sjl139090 /* every node is expected to have a name */
9825037Sjl139090 err = drerr_new(1, EOPL_GETPROP, "device node %s: property %s",
9835037Sjl139090 ddi_node_name(node->n_getdip(node)), "name");
9841772Sjl139090 return (err);
9851772Sjl139090 }
9861772Sjl139090
9871772Sjl139090 /*
9881772Sjl139090 * The node currently being examined is not listed in the name2type[]
9891772Sjl139090 * array. In this case, the node is no interest to drmach. Both
9901772Sjl139090 * dp and err are initialized here to yield nothing (no device or
9911772Sjl139090 * error structure) for this case.
9921772Sjl139090 */
9931772Sjl139090 i = drmach_name2type_idx(name);
9941772Sjl139090
9951772Sjl139090
9961772Sjl139090 if (i < 0) {
9971772Sjl139090 *idp = (drmachid_t)0;
9981772Sjl139090 return (NULL);
9991772Sjl139090 }
10001772Sjl139090
10011772Sjl139090 /* device specific new function will set unum */
10021772Sjl139090
10031772Sjl139090 bzero(&proto, sizeof (proto));
10041772Sjl139090 proto.type = drmach_name2type[i].type;
10051772Sjl139090 proto.bp = bp;
10061772Sjl139090 proto.node = node;
10071772Sjl139090 proto.portid = portid;
10081772Sjl139090
10091772Sjl139090 return (drmach_name2type[i].new(&proto, idp));
10101772Sjl139090 }
10111772Sjl139090
10121772Sjl139090 static void
drmach_device_dispose(drmachid_t id)10131772Sjl139090 drmach_device_dispose(drmachid_t id)
10141772Sjl139090 {
10151772Sjl139090 drmach_device_t *self = id;
10161772Sjl139090
10171772Sjl139090 self->cm.dispose(id);
10181772Sjl139090 }
10191772Sjl139090
10201772Sjl139090
10211772Sjl139090 static drmach_board_t *
drmach_board_new(int bnum,int boot_board)10221772Sjl139090 drmach_board_new(int bnum, int boot_board)
10231772Sjl139090 {
10241772Sjl139090 static sbd_error_t *drmach_board_release(drmachid_t);
10251772Sjl139090 static sbd_error_t *drmach_board_status(drmachid_t, drmach_status_t *);
10261772Sjl139090
10271772Sjl139090 drmach_board_t *bp;
10281772Sjl139090
10291772Sjl139090 bp = kmem_zalloc(sizeof (drmach_board_t), KM_SLEEP);
10301772Sjl139090
10311772Sjl139090 bp->cm.isa = (void *)drmach_board_new;
10321772Sjl139090 bp->cm.release = drmach_board_release;
10331772Sjl139090 bp->cm.status = drmach_board_status;
10341772Sjl139090
10351772Sjl139090 (void) drmach_board_name(bnum, bp->cm.name, sizeof (bp->cm.name));
10361772Sjl139090
10371772Sjl139090 bp->bnum = bnum;
10381772Sjl139090 bp->devices = NULL;
10391772Sjl139090 bp->connected = boot_board;
10401772Sjl139090 bp->tree = drmach_node_new();
10411772Sjl139090 bp->assigned = boot_board;
10421772Sjl139090 bp->powered = boot_board;
10431772Sjl139090 bp->boot_board = boot_board;
10441772Sjl139090
10451772Sjl139090 /*
10461772Sjl139090 * If this is not bootup initialization, we have to wait till
10471772Sjl139090 * IKP sets up the device nodes in drmach_board_connect().
10481772Sjl139090 */
10491772Sjl139090 if (boot_board)
10501772Sjl139090 drmach_setup_core_info(bp);
10511772Sjl139090
105211311SSurya.Prakki@Sun.COM (void) drmach_array_set(drmach_boards, bnum, bp);
10531772Sjl139090 return (bp);
10541772Sjl139090 }
10551772Sjl139090
10561772Sjl139090 static void
drmach_board_dispose(drmachid_t id)10571772Sjl139090 drmach_board_dispose(drmachid_t id)
10581772Sjl139090 {
10591772Sjl139090 drmach_board_t *bp;
10601772Sjl139090
10611772Sjl139090 ASSERT(DRMACH_IS_BOARD_ID(id));
10621772Sjl139090 bp = id;
10631772Sjl139090
10641772Sjl139090 if (bp->tree)
10651772Sjl139090 drmach_node_dispose(bp->tree);
10661772Sjl139090
10671772Sjl139090 if (bp->devices)
10681772Sjl139090 drmach_array_dispose(bp->devices, drmach_device_dispose);
10691772Sjl139090
10701772Sjl139090 kmem_free(bp, sizeof (*bp));
10711772Sjl139090 }
10721772Sjl139090
10731772Sjl139090 static sbd_error_t *
drmach_board_status(drmachid_t id,drmach_status_t * stat)10741772Sjl139090 drmach_board_status(drmachid_t id, drmach_status_t *stat)
10751772Sjl139090 {
10761772Sjl139090 sbd_error_t *err = NULL;
10771772Sjl139090 drmach_board_t *bp;
10781772Sjl139090
10791772Sjl139090 if (!DRMACH_IS_BOARD_ID(id))
10801772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
10811772Sjl139090 bp = id;
10821772Sjl139090
10831772Sjl139090 stat->assigned = bp->assigned;
10841772Sjl139090 stat->powered = bp->powered;
10851772Sjl139090 stat->busy = 0; /* assume not busy */
10861772Sjl139090 stat->configured = 0; /* assume not configured */
10871772Sjl139090 stat->empty = 0;
10881772Sjl139090 stat->cond = bp->cond = SBD_COND_OK;
108911311SSurya.Prakki@Sun.COM (void) strncpy(stat->type, "System Brd", sizeof (stat->type));
10901772Sjl139090 stat->info[0] = '\0';
10911772Sjl139090
10921772Sjl139090 if (bp->devices) {
10931772Sjl139090 int rv;
10941772Sjl139090 int d_idx;
10951772Sjl139090 drmachid_t d_id;
10961772Sjl139090
10971772Sjl139090 rv = drmach_array_first(bp->devices, &d_idx, &d_id);
10981772Sjl139090 while (rv == 0) {
10991772Sjl139090 drmach_status_t d_stat;
11001772Sjl139090
11011772Sjl139090 err = drmach_i_status(d_id, &d_stat);
11021772Sjl139090 if (err)
11031772Sjl139090 break;
11041772Sjl139090
11051772Sjl139090 stat->busy |= d_stat.busy;
11061772Sjl139090 stat->configured |= d_stat.configured;
11071772Sjl139090
11081772Sjl139090 rv = drmach_array_next(bp->devices, &d_idx, &d_id);
11091772Sjl139090 }
11101772Sjl139090 }
11111772Sjl139090
11121772Sjl139090 return (err);
11131772Sjl139090 }
11141772Sjl139090
11151772Sjl139090 int
drmach_board_is_floating(drmachid_t id)11161772Sjl139090 drmach_board_is_floating(drmachid_t id)
11171772Sjl139090 {
11181772Sjl139090 drmach_board_t *bp;
11191772Sjl139090
11201772Sjl139090 if (!DRMACH_IS_BOARD_ID(id))
11211772Sjl139090 return (0);
11221772Sjl139090
11231772Sjl139090 bp = (drmach_board_t *)id;
11241772Sjl139090
11251772Sjl139090 return ((drmach_domain.floating & (1 << bp->bnum)) ? 1 : 0);
11261772Sjl139090 }
11271772Sjl139090
11281772Sjl139090 static int
drmach_init(void)11291772Sjl139090 drmach_init(void)
11301772Sjl139090 {
11311772Sjl139090 dev_info_t *rdip;
11321772Sjl139090 int i, rv, len;
11331772Sjl139090 int *floating;
11341772Sjl139090
11351772Sjl139090 rw_init(&drmach_boards_rwlock, NULL, RW_DEFAULT, NULL);
11361772Sjl139090
11371772Sjl139090 drmach_boards = drmach_array_new(0, MAX_BOARDS - 1);
11381772Sjl139090
11391772Sjl139090 rdip = ddi_root_node();
11401772Sjl139090
11411772Sjl139090 if (ddi_getproplen(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
11425037Sjl139090 "floating-boards", &len) != DDI_PROP_SUCCESS) {
11431772Sjl139090 cmn_err(CE_WARN, "Cannot get floating-boards proplen\n");
11441772Sjl139090 } else {
11451772Sjl139090 floating = (int *)kmem_alloc(len, KM_SLEEP);
11465037Sjl139090 rv = ddi_prop_op(DDI_DEV_T_ANY, rdip, PROP_LEN_AND_VAL_BUF,
11475037Sjl139090 DDI_PROP_DONTPASS, "floating-boards", (caddr_t)floating,
11485037Sjl139090 &len);
11491772Sjl139090 if (rv != DDI_PROP_SUCCESS) {
11501772Sjl139090 cmn_err(CE_WARN, "Cannot get floating-boards prop\n");
11511772Sjl139090 } else {
11521772Sjl139090 drmach_domain.floating = 0;
11531772Sjl139090 for (i = 0; i < len / sizeof (int); i++) {
11541772Sjl139090 drmach_domain.floating |= (1 << floating[i]);
11551772Sjl139090 }
11561772Sjl139090 }
11571772Sjl139090 kmem_free(floating, len);
11581772Sjl139090 }
11591772Sjl139090 drmach_domain.allow_dr = opl_check_dr_status();
11601772Sjl139090
11611772Sjl139090 rdip = ddi_get_child(ddi_root_node());
11621772Sjl139090 do {
11631772Sjl139090 int bnum;
11641772Sjl139090 drmachid_t id;
11651772Sjl139090
11661772Sjl139090 bnum = -1;
11675037Sjl139090 bnum = ddi_getprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
11685037Sjl139090 OBP_BOARDNUM, -1);
11691772Sjl139090 if (bnum == -1)
11701772Sjl139090 continue;
11711772Sjl139090
11721772Sjl139090 if (drmach_array_get(drmach_boards, bnum, &id) == -1) {
11735037Sjl139090 cmn_err(CE_WARN, "Device node 0x%p has invalid "
117411311SSurya.Prakki@Sun.COM "property value, %s=%d", (void *)rdip,
117511311SSurya.Prakki@Sun.COM OBP_BOARDNUM, bnum);
11761772Sjl139090 goto error;
11771772Sjl139090 } else if (id == NULL) {
11781772Sjl139090 (void) drmach_board_new(bnum, 1);
11791772Sjl139090 }
11801772Sjl139090 } while ((rdip = ddi_get_next_sibling(rdip)) != NULL);
11811772Sjl139090
11821772Sjl139090 opl_hold_devtree();
11831772Sjl139090
11841772Sjl139090 /*
11851772Sjl139090 * Initialize the IKP feature.
11861772Sjl139090 *
11871772Sjl139090 * This can be done only after DR has acquired a hold on all the
11881772Sjl139090 * device nodes that are interesting to IKP.
11891772Sjl139090 */
11901772Sjl139090 if (opl_init_cfg() != 0) {
11911772Sjl139090 cmn_err(CE_WARN, "DR - IKP initialization failed");
11921772Sjl139090
11931772Sjl139090 opl_release_devtree();
11941772Sjl139090
11951772Sjl139090 goto error;
11961772Sjl139090 }
11971772Sjl139090
11981772Sjl139090 return (0);
11991772Sjl139090 error:
12001772Sjl139090 drmach_array_dispose(drmach_boards, drmach_board_dispose);
12011772Sjl139090 rw_destroy(&drmach_boards_rwlock);
12021772Sjl139090 return (ENXIO);
12031772Sjl139090 }
12041772Sjl139090
12051772Sjl139090 static void
drmach_fini(void)12061772Sjl139090 drmach_fini(void)
12071772Sjl139090 {
12081772Sjl139090 rw_enter(&drmach_boards_rwlock, RW_WRITER);
12091772Sjl139090 drmach_array_dispose(drmach_boards, drmach_board_dispose);
12101772Sjl139090 drmach_boards = NULL;
12111772Sjl139090 rw_exit(&drmach_boards_rwlock);
12121772Sjl139090
12131772Sjl139090 /*
12141772Sjl139090 * Walk immediate children of the root devinfo node
12151772Sjl139090 * releasing holds acquired on branches in drmach_init()
12161772Sjl139090 */
12171772Sjl139090
12181772Sjl139090 opl_release_devtree();
12191772Sjl139090
12201772Sjl139090 rw_destroy(&drmach_boards_rwlock);
12211772Sjl139090 }
12221772Sjl139090
12231772Sjl139090 /*
12241772Sjl139090 * Each system board contains 2 Oberon PCI bridge and
12251772Sjl139090 * 1 CMUCH.
12261772Sjl139090 * Each oberon has 2 channels.
12271772Sjl139090 * Each channel has 2 pci-ex leaf.
12281772Sjl139090 * Each CMUCH has 1 pci bus.
12291772Sjl139090 *
12301772Sjl139090 *
12311772Sjl139090 * Device Path:
12321772Sjl139090 * /pci@<portid>,reg
12331772Sjl139090 *
12341772Sjl139090 * where
12351772Sjl139090 * portid[10] = 0
12361772Sjl139090 * portid[9:0] = LLEAF_ID[9:0] of the Oberon Channel
12371772Sjl139090 *
12381772Sjl139090 * LLEAF_ID[9:8] = 0
12391772Sjl139090 * LLEAF_ID[8:4] = LSB_ID[4:0]
12401772Sjl139090 * LLEAF_ID[3:1] = IO Channel#[2:0] (0,1,2,3 for Oberon)
12411772Sjl139090 * channel 4 is pcicmu
12421772Sjl139090 * LLEAF_ID[0] = PCI Leaf Number (0 for leaf-A, 1 for leaf-B)
12431772Sjl139090 *
12441772Sjl139090 * Properties:
12451772Sjl139090 * name = pci
12461772Sjl139090 * device_type = "pciex"
12471772Sjl139090 * board# = LSBID
12481772Sjl139090 * reg = int32 * 2, Oberon CSR space of the leaf and the UBC space
12491772Sjl139090 * portid = Jupiter Bus Device ID ((LSB_ID << 3)|pciport#)
12501772Sjl139090 */
12511772Sjl139090
12521772Sjl139090 static sbd_error_t *
drmach_io_new(drmach_device_t * proto,drmachid_t * idp)12531772Sjl139090 drmach_io_new(drmach_device_t *proto, drmachid_t *idp)
12541772Sjl139090 {
12551772Sjl139090 drmach_io_t *ip;
12561772Sjl139090
12571772Sjl139090 int portid;
12581772Sjl139090
12591772Sjl139090 portid = proto->portid;
12601772Sjl139090 ASSERT(portid != -1);
12611772Sjl139090 proto->unum = portid & (MAX_IO_UNITS_PER_BOARD - 1);
12621772Sjl139090
12631772Sjl139090 ip = kmem_zalloc(sizeof (drmach_io_t), KM_SLEEP);
12641772Sjl139090 bcopy(proto, &ip->dev, sizeof (ip->dev));
12651772Sjl139090 ip->dev.node = drmach_node_dup(proto->node);
12661772Sjl139090 ip->dev.cm.isa = (void *)drmach_io_new;
12671772Sjl139090 ip->dev.cm.dispose = drmach_io_dispose;
12681772Sjl139090 ip->dev.cm.release = drmach_io_release;
12691772Sjl139090 ip->dev.cm.status = drmach_io_status;
12701772Sjl139090 ip->channel = (portid >> 1) & 0x7;
12711772Sjl139090 ip->leaf = (portid & 0x1);
12721772Sjl139090
127311311SSurya.Prakki@Sun.COM (void) snprintf(ip->dev.cm.name, sizeof (ip->dev.cm.name), "%s%d",
12745037Sjl139090 ip->dev.type, ip->dev.unum);
12751772Sjl139090
12761772Sjl139090 *idp = (drmachid_t)ip;
12771772Sjl139090 return (NULL);
12781772Sjl139090 }
12791772Sjl139090
12801772Sjl139090
12811772Sjl139090 static void
drmach_io_dispose(drmachid_t id)12821772Sjl139090 drmach_io_dispose(drmachid_t id)
12831772Sjl139090 {
12841772Sjl139090 drmach_io_t *self;
12851772Sjl139090
12861772Sjl139090 ASSERT(DRMACH_IS_IO_ID(id));
12871772Sjl139090
12881772Sjl139090 self = id;
12891772Sjl139090 if (self->dev.node)
12901772Sjl139090 drmach_node_dispose(self->dev.node);
12911772Sjl139090
12921772Sjl139090 kmem_free(self, sizeof (*self));
12931772Sjl139090 }
12941772Sjl139090
12951772Sjl139090 /*ARGSUSED*/
12961772Sjl139090 sbd_error_t *
drmach_pre_op(int cmd,drmachid_t id,drmach_opts_t * opts)12971772Sjl139090 drmach_pre_op(int cmd, drmachid_t id, drmach_opts_t *opts)
12981772Sjl139090 {
12991772Sjl139090 drmach_board_t *bp = (drmach_board_t *)id;
13001772Sjl139090 sbd_error_t *err = NULL;
13011772Sjl139090
13021772Sjl139090 /* allow status and ncm operations to always succeed */
13031772Sjl139090 if ((cmd == SBD_CMD_STATUS) || (cmd == SBD_CMD_GETNCM)) {
13041772Sjl139090 return (NULL);
13051772Sjl139090 }
13061772Sjl139090
13071772Sjl139090 /* check all other commands for the required option string */
13081772Sjl139090
13091772Sjl139090 if ((opts->size > 0) && (opts->copts != NULL)) {
13101772Sjl139090
13111772Sjl139090 DRMACH_PR("platform options: %s\n", opts->copts);
13121772Sjl139090
13131772Sjl139090 if (strstr(opts->copts, "opldr") == NULL) {
13141772Sjl139090 err = drerr_new(1, EOPL_SUPPORT, NULL);
13151772Sjl139090 }
13161772Sjl139090 } else {
13171772Sjl139090 err = drerr_new(1, EOPL_SUPPORT, NULL);
13181772Sjl139090 }
13191772Sjl139090
13201772Sjl139090 if (!err && id && DRMACH_IS_BOARD_ID(id)) {
13211772Sjl139090 switch (cmd) {
13221772Sjl139090 case SBD_CMD_TEST:
13231772Sjl139090 case SBD_CMD_STATUS:
13241772Sjl139090 case SBD_CMD_GETNCM:
13251772Sjl139090 break;
13261772Sjl139090 case SBD_CMD_CONNECT:
13271772Sjl139090 if (bp->connected)
13281772Sjl139090 err = drerr_new(0, ESBD_STATE, NULL);
13291772Sjl139090 else if (!drmach_domain.allow_dr)
13305037Sjl139090 err = drerr_new(1, EOPL_SUPPORT, NULL);
13311772Sjl139090 break;
13321772Sjl139090 case SBD_CMD_DISCONNECT:
13331772Sjl139090 if (!bp->connected)
13341772Sjl139090 err = drerr_new(0, ESBD_STATE, NULL);
13351772Sjl139090 else if (!drmach_domain.allow_dr)
13365037Sjl139090 err = drerr_new(1, EOPL_SUPPORT, NULL);
13371772Sjl139090 break;
13381772Sjl139090 default:
13391772Sjl139090 if (!drmach_domain.allow_dr)
13405037Sjl139090 err = drerr_new(1, EOPL_SUPPORT, NULL);
13411772Sjl139090 break;
13421772Sjl139090
13431772Sjl139090 }
13441772Sjl139090 }
13451772Sjl139090
13461772Sjl139090 return (err);
13471772Sjl139090 }
13481772Sjl139090
13491772Sjl139090 /*ARGSUSED*/
13501772Sjl139090 sbd_error_t *
drmach_post_op(int cmd,drmachid_t id,drmach_opts_t * opts)13511772Sjl139090 drmach_post_op(int cmd, drmachid_t id, drmach_opts_t *opts)
13521772Sjl139090 {
13531772Sjl139090 return (NULL);
13541772Sjl139090 }
13551772Sjl139090
13561772Sjl139090 sbd_error_t *
drmach_board_assign(int bnum,drmachid_t * id)13571772Sjl139090 drmach_board_assign(int bnum, drmachid_t *id)
13581772Sjl139090 {
13591772Sjl139090 sbd_error_t *err = NULL;
13601772Sjl139090
13611772Sjl139090 rw_enter(&drmach_boards_rwlock, RW_WRITER);
13621772Sjl139090
13631772Sjl139090 if (drmach_array_get(drmach_boards, bnum, id) == -1) {
13641772Sjl139090 err = drerr_new(1, EOPL_BNUM, "%d", bnum);
13651772Sjl139090 } else {
13661772Sjl139090 drmach_board_t *bp;
13671772Sjl139090
13681772Sjl139090 if (*id)
13691772Sjl139090 rw_downgrade(&drmach_boards_rwlock);
13701772Sjl139090
13711772Sjl139090 bp = *id;
13721772Sjl139090 if (!(*id))
13731772Sjl139090 bp = *id =
13745037Sjl139090 (drmachid_t)drmach_board_new(bnum, 0);
13751772Sjl139090 bp->assigned = 1;
13761772Sjl139090 }
13771772Sjl139090
13781772Sjl139090 rw_exit(&drmach_boards_rwlock);
13791772Sjl139090
13801772Sjl139090 return (err);
13811772Sjl139090 }
13821772Sjl139090
13831772Sjl139090 /*ARGSUSED*/
13841772Sjl139090 sbd_error_t *
drmach_board_connect(drmachid_t id,drmach_opts_t * opts)13851772Sjl139090 drmach_board_connect(drmachid_t id, drmach_opts_t *opts)
13861772Sjl139090 {
13875037Sjl139090 extern int cpu_alljupiter;
13881772Sjl139090 drmach_board_t *obj = (drmach_board_t *)id;
13895037Sjl139090 unsigned cpu_impl;
13901772Sjl139090
13911772Sjl139090 if (!DRMACH_IS_BOARD_ID(id))
13921772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
13931772Sjl139090
13945037Sjl139090 if (opl_probe_sb(obj->bnum, &cpu_impl) != 0)
13953400Sbm42561 return (drerr_new(1, EOPL_PROBE, NULL));
13961772Sjl139090
13975037Sjl139090 if (cpu_alljupiter) {
13985551Swh31274 if (cpu_impl & (1 << OLYMPUS_C_IMPL)) {
13995551Swh31274 (void) opl_unprobe_sb(obj->bnum);
14005037Sjl139090 return (drerr_new(1, EOPL_MIXED_CPU, NULL));
14015551Swh31274 }
14025037Sjl139090 }
14035037Sjl139090
14041772Sjl139090 (void) prom_attach_notice(obj->bnum);
14051772Sjl139090
14061772Sjl139090 drmach_setup_core_info(obj);
14071772Sjl139090
14081772Sjl139090 obj->connected = 1;
14091772Sjl139090
14101772Sjl139090 return (NULL);
14111772Sjl139090 }
14121772Sjl139090
14131772Sjl139090 static int drmach_cache_flush_flag[NCPU];
14141772Sjl139090
14151772Sjl139090 /*ARGSUSED*/
14161772Sjl139090 static void
drmach_flush_cache(uint64_t id,uint64_t dummy)14171772Sjl139090 drmach_flush_cache(uint64_t id, uint64_t dummy)
14181772Sjl139090 {
14191772Sjl139090 extern void cpu_flush_ecache(void);
14201772Sjl139090
14211772Sjl139090 cpu_flush_ecache();
14221772Sjl139090 drmach_cache_flush_flag[id] = 0;
14231772Sjl139090 }
14241772Sjl139090
14251772Sjl139090 static void
drmach_flush_all()14261772Sjl139090 drmach_flush_all()
14271772Sjl139090 {
14281772Sjl139090 cpuset_t xc_cpuset;
14291772Sjl139090 int i;
14301772Sjl139090
14311772Sjl139090 xc_cpuset = cpu_ready_set;
14321772Sjl139090 for (i = 0; i < NCPU; i++) {
14331772Sjl139090 if (CPU_IN_SET(xc_cpuset, i)) {
14341772Sjl139090 drmach_cache_flush_flag[i] = 1;
14351772Sjl139090 xc_one(i, drmach_flush_cache, i, 0);
14361772Sjl139090 while (drmach_cache_flush_flag[i]) {
14371772Sjl139090 DELAY(1000);
14381772Sjl139090 }
14391772Sjl139090 }
14401772Sjl139090 }
14411772Sjl139090 }
14421772Sjl139090
14431772Sjl139090 static int
drmach_disconnect_cpus(drmach_board_t * bp)14441772Sjl139090 drmach_disconnect_cpus(drmach_board_t *bp)
14451772Sjl139090 {
14461772Sjl139090 int i, bnum;
14471772Sjl139090
14481772Sjl139090 bnum = bp->bnum;
14491772Sjl139090
14501772Sjl139090 for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) {
14515037Sjl139090 if (bp->cores[i].core_present) {
14525037Sjl139090 if (bp->cores[i].core_started)
14535037Sjl139090 return (-1);
14545037Sjl139090 if (bp->cores[i].core_hotadded) {
14555037Sjl139090 if (drmach_add_remove_cpu(bnum, i,
14565037Sjl139090 HOTREMOVE_CPU)) {
14575037Sjl139090 cmn_err(CE_WARN, "Failed to remove "
14585037Sjl139090 "CMP %d on board %d\n", i, bnum);
14595037Sjl139090 return (-1);
14605037Sjl139090 }
14615037Sjl139090 }
14621772Sjl139090 }
14631772Sjl139090 }
14641772Sjl139090 return (0);
14651772Sjl139090 }
14661772Sjl139090
14671772Sjl139090 /*ARGSUSED*/
14681772Sjl139090 sbd_error_t *
drmach_board_disconnect(drmachid_t id,drmach_opts_t * opts)14691772Sjl139090 drmach_board_disconnect(drmachid_t id, drmach_opts_t *opts)
14701772Sjl139090 {
14711772Sjl139090 drmach_board_t *obj;
14721772Sjl139090 int rv = 0;
14731772Sjl139090 sbd_error_t *err = NULL;
14741772Sjl139090
14753493Sbm42561 if (DRMACH_NULL_ID(id))
14763493Sbm42561 return (NULL);
14771772Sjl139090
14781772Sjl139090 if (!DRMACH_IS_BOARD_ID(id))
14791772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
14801772Sjl139090
14811772Sjl139090 obj = (drmach_board_t *)id;
14821772Sjl139090
14831772Sjl139090 if (drmach_disconnect_cpus(obj)) {
14843400Sbm42561 err = drerr_new(1, EOPL_DEPROBE, obj->cm.name);
14851772Sjl139090 return (err);
14861772Sjl139090 }
14871772Sjl139090
14881772Sjl139090 rv = opl_unprobe_sb(obj->bnum);
14891772Sjl139090
14901772Sjl139090 if (rv == 0) {
149111311SSurya.Prakki@Sun.COM (void) prom_detach_notice(obj->bnum);
14921772Sjl139090 obj->connected = 0;
14931772Sjl139090
14941772Sjl139090 } else
14953400Sbm42561 err = drerr_new(1, EOPL_DEPROBE, obj->cm.name);
14961772Sjl139090
14971772Sjl139090 return (err);
14981772Sjl139090 }
14991772Sjl139090
15001772Sjl139090 static int
drmach_get_portid(drmach_node_t * np)15011772Sjl139090 drmach_get_portid(drmach_node_t *np)
15021772Sjl139090 {
15031772Sjl139090 int portid;
15041772Sjl139090 char type[OBP_MAXPROPNAME];
15051772Sjl139090
15061772Sjl139090 if (np->n_getprop(np, "portid", &portid, sizeof (portid)) == 0)
15071772Sjl139090 return (portid);
15081772Sjl139090
15091772Sjl139090 /*
15101772Sjl139090 * Get the device_type property to see if we should
15111772Sjl139090 * continue processing this node.
15121772Sjl139090 */
15131772Sjl139090 if (np->n_getprop(np, "device_type", &type, sizeof (type)) != 0)
15141772Sjl139090 return (-1);
15151772Sjl139090
15161772Sjl139090 if (strcmp(type, OPL_CPU_NODE) == 0) {
15171772Sjl139090 /*
15181772Sjl139090 * We return cpuid because it has no portid
15191772Sjl139090 */
15201772Sjl139090 if (np->n_getprop(np, "cpuid", &portid, sizeof (portid)) == 0)
15211772Sjl139090 return (portid);
15221772Sjl139090 }
15231772Sjl139090
15241772Sjl139090 return (-1);
15251772Sjl139090 }
15261772Sjl139090
15271772Sjl139090 /*
15281772Sjl139090 * This is a helper function to determine if a given
15291772Sjl139090 * node should be considered for a dr operation according
15301772Sjl139090 * to predefined dr type nodes and the node's name.
15311772Sjl139090 * Formal Parameter : The name of a device node.
15321772Sjl139090 * Return Value: -1, name does not map to a valid dr type.
15331772Sjl139090 * A value greater or equal to 0, name is a valid dr type.
15341772Sjl139090 */
15351772Sjl139090 static int
drmach_name2type_idx(char * name)15361772Sjl139090 drmach_name2type_idx(char *name)
15371772Sjl139090 {
15381772Sjl139090 int index, ntypes;
15391772Sjl139090
15401772Sjl139090 if (name == NULL)
15411772Sjl139090 return (-1);
15421772Sjl139090
15431772Sjl139090 /*
15441772Sjl139090 * Determine how many possible types are currently supported
15451772Sjl139090 * for dr.
15461772Sjl139090 */
15471772Sjl139090 ntypes = sizeof (drmach_name2type) / sizeof (drmach_name2type[0]);
15481772Sjl139090
15491772Sjl139090 /* Determine if the node's name correspond to a predefined type. */
15501772Sjl139090 for (index = 0; index < ntypes; index++) {
15511772Sjl139090 if (strcmp(drmach_name2type[index].name, name) == 0)
15521772Sjl139090 /* The node is an allowed type for dr. */
15531772Sjl139090 return (index);
15541772Sjl139090 }
15551772Sjl139090
15561772Sjl139090 /*
15571772Sjl139090 * If the name of the node does not map to any of the
15581772Sjl139090 * types in the array drmach_name2type then the node is not of
15591772Sjl139090 * interest to dr.
15601772Sjl139090 */
15611772Sjl139090 return (-1);
15621772Sjl139090 }
15631772Sjl139090
15641772Sjl139090 /*
15651772Sjl139090 * there is some complication on OPL:
15661772Sjl139090 * - pseudo-mc nodes do not have portid property
15671772Sjl139090 * - portid[9:5] of cmp node is LSB #, portid[7:3] of pci is LSB#
15681772Sjl139090 * - cmp has board#
15691772Sjl139090 * - core and cpu nodes do not have portid and board# properties
15701772Sjl139090 * starcat uses portid to derive the board# but that does not work
15711772Sjl139090 * for us. starfire reads board# property to filter the devices.
15721772Sjl139090 * That does not work either. So for these specific device,
15731772Sjl139090 * we use specific hard coded methods to get the board# -
15741772Sjl139090 * cpu: LSB# = CPUID[9:5]
15751772Sjl139090 */
15761772Sjl139090
15771772Sjl139090 static int
drmach_board_find_devices_cb(drmach_node_walk_args_t * args)15781772Sjl139090 drmach_board_find_devices_cb(drmach_node_walk_args_t *args)
15791772Sjl139090 {
15801772Sjl139090 drmach_node_t *node = args->node;
15811772Sjl139090 drmach_board_cb_data_t *data = args->data;
15821772Sjl139090 drmach_board_t *obj = data->obj;
15831772Sjl139090
15841772Sjl139090 int rv, portid;
15851772Sjl139090 int bnum;
15861772Sjl139090 drmachid_t id;
15871772Sjl139090 drmach_device_t *device;
15881772Sjl139090 char name[OBP_MAXDRVNAME];
15891772Sjl139090
15901772Sjl139090 portid = drmach_get_portid(node);
15911772Sjl139090 /*
15921772Sjl139090 * core, cpu and pseudo-mc do not have portid
15931772Sjl139090 * we use cpuid as the portid of the cpu node
15941772Sjl139090 * for pseudo-mc, we do not use portid info.
15951772Sjl139090 */
15961772Sjl139090
15971772Sjl139090 rv = node->n_getprop(node, "name", name, OBP_MAXDRVNAME);
15981772Sjl139090 if (rv)
15991772Sjl139090 return (0);
16001772Sjl139090
16011772Sjl139090
16021772Sjl139090 rv = node->n_getprop(node, OBP_BOARDNUM, &bnum, sizeof (bnum));
16031772Sjl139090
16041772Sjl139090 if (rv) {
16051772Sjl139090 /*
16061772Sjl139090 * cpu does not have board# property. We use
16071772Sjl139090 * CPUID[9:5]
16081772Sjl139090 */
16091772Sjl139090 if (strcmp("cpu", name) == 0) {
16101772Sjl139090 bnum = (portid >> 5) & 0x1f;
16111772Sjl139090 } else
16121772Sjl139090 return (0);
16131772Sjl139090 }
16141772Sjl139090
16151772Sjl139090
16161772Sjl139090 if (bnum != obj->bnum)
16171772Sjl139090 return (0);
16181772Sjl139090
16191772Sjl139090 if (drmach_name2type_idx(name) < 0) {
16201772Sjl139090 return (0);
16211772Sjl139090 }
16221772Sjl139090
16231772Sjl139090 /*
16241772Sjl139090 * Create a device data structure from this node data.
16251772Sjl139090 * The call may yield nothing if the node is not of interest
16261772Sjl139090 * to drmach.
16271772Sjl139090 */
16281772Sjl139090 data->err = drmach_device_new(node, obj, portid, &id);
16291772Sjl139090 if (data->err)
16301772Sjl139090 return (-1);
16311772Sjl139090 else if (!id) {
16321772Sjl139090 /*
16331772Sjl139090 * drmach_device_new examined the node we passed in
16341772Sjl139090 * and determined that it was one not of interest to
16351772Sjl139090 * drmach. So, it is skipped.
16361772Sjl139090 */
16371772Sjl139090 return (0);
16381772Sjl139090 }
16391772Sjl139090
16401772Sjl139090 rv = drmach_array_set(obj->devices, data->ndevs++, id);
16411772Sjl139090 if (rv) {
16421772Sjl139090 data->err = DRMACH_INTERNAL_ERROR();
16431772Sjl139090 return (-1);
16441772Sjl139090 }
16451772Sjl139090 device = id;
16461772Sjl139090
16471772Sjl139090 data->err = (*data->found)(data->a, device->type, device->unum, id);
16481772Sjl139090 return (data->err == NULL ? 0 : -1);
16491772Sjl139090 }
16501772Sjl139090
16511772Sjl139090 sbd_error_t *
drmach_board_find_devices(drmachid_t id,void * a,sbd_error_t * (* found)(void * a,const char *,int,drmachid_t))16521772Sjl139090 drmach_board_find_devices(drmachid_t id, void *a,
16531772Sjl139090 sbd_error_t *(*found)(void *a, const char *, int, drmachid_t))
16541772Sjl139090 {
16551772Sjl139090 drmach_board_t *bp = (drmach_board_t *)id;
16561772Sjl139090 sbd_error_t *err;
16571772Sjl139090 int max_devices;
16581772Sjl139090 int rv;
16591772Sjl139090 drmach_board_cb_data_t data;
16601772Sjl139090
16611772Sjl139090
16621772Sjl139090 if (!DRMACH_IS_BOARD_ID(id))
16631772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
16641772Sjl139090
16651772Sjl139090 max_devices = MAX_CPU_UNITS_PER_BOARD;
16661772Sjl139090 max_devices += MAX_MEM_UNITS_PER_BOARD;
16671772Sjl139090 max_devices += MAX_IO_UNITS_PER_BOARD;
16681772Sjl139090
16691772Sjl139090 bp->devices = drmach_array_new(0, max_devices);
16701772Sjl139090
16711772Sjl139090 if (bp->tree == NULL)
16721772Sjl139090 bp->tree = drmach_node_new();
16731772Sjl139090
16741772Sjl139090 data.obj = bp;
16751772Sjl139090 data.ndevs = 0;
16761772Sjl139090 data.found = found;
16771772Sjl139090 data.a = a;
16781772Sjl139090 data.err = NULL;
16791772Sjl139090
16801772Sjl139090 rv = drmach_node_walk(bp->tree, &data, drmach_board_find_devices_cb);
16811772Sjl139090 if (rv == 0)
16821772Sjl139090 err = NULL;
16831772Sjl139090 else {
16841772Sjl139090 drmach_array_dispose(bp->devices, drmach_device_dispose);
16851772Sjl139090 bp->devices = NULL;
16861772Sjl139090
16871772Sjl139090 if (data.err)
16881772Sjl139090 err = data.err;
16891772Sjl139090 else
16901772Sjl139090 err = DRMACH_INTERNAL_ERROR();
16911772Sjl139090 }
16921772Sjl139090
16931772Sjl139090 return (err);
16941772Sjl139090 }
16951772Sjl139090
16961772Sjl139090 int
drmach_board_lookup(int bnum,drmachid_t * id)16971772Sjl139090 drmach_board_lookup(int bnum, drmachid_t *id)
16981772Sjl139090 {
16991772Sjl139090 int rv = 0;
17001772Sjl139090
17011772Sjl139090 rw_enter(&drmach_boards_rwlock, RW_READER);
17021772Sjl139090 if (drmach_array_get(drmach_boards, bnum, id)) {
17031772Sjl139090 *id = 0;
17041772Sjl139090 rv = -1;
17051772Sjl139090 }
17061772Sjl139090 rw_exit(&drmach_boards_rwlock);
17071772Sjl139090 return (rv);
17081772Sjl139090 }
17091772Sjl139090
17101772Sjl139090 sbd_error_t *
drmach_board_name(int bnum,char * buf,int buflen)17111772Sjl139090 drmach_board_name(int bnum, char *buf, int buflen)
17121772Sjl139090 {
171311311SSurya.Prakki@Sun.COM (void) snprintf(buf, buflen, "SB%d", bnum);
17141772Sjl139090 return (NULL);
17151772Sjl139090 }
17161772Sjl139090
17171772Sjl139090 sbd_error_t *
drmach_board_poweroff(drmachid_t id)17181772Sjl139090 drmach_board_poweroff(drmachid_t id)
17191772Sjl139090 {
17201772Sjl139090 drmach_board_t *bp;
17211772Sjl139090 sbd_error_t *err;
17221772Sjl139090 drmach_status_t stat;
17231772Sjl139090
17243493Sbm42561 if (DRMACH_NULL_ID(id))
17253493Sbm42561 return (NULL);
17263493Sbm42561
17271772Sjl139090 if (!DRMACH_IS_BOARD_ID(id))
17281772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
17291772Sjl139090 bp = id;
17301772Sjl139090
17311772Sjl139090 err = drmach_board_status(id, &stat);
17321772Sjl139090
17331772Sjl139090 if (!err) {
17341772Sjl139090 if (stat.configured || stat.busy)
17351772Sjl139090 err = drerr_new(0, EOPL_CONFIGBUSY, bp->cm.name);
17361772Sjl139090 else {
17371772Sjl139090 bp->powered = 0;
17381772Sjl139090 }
17391772Sjl139090 }
17401772Sjl139090 return (err);
17411772Sjl139090 }
17421772Sjl139090
17431772Sjl139090 sbd_error_t *
drmach_board_poweron(drmachid_t id)17441772Sjl139090 drmach_board_poweron(drmachid_t id)
17451772Sjl139090 {
17461772Sjl139090 drmach_board_t *bp;
17471772Sjl139090
17481772Sjl139090 if (!DRMACH_IS_BOARD_ID(id))
17491772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
17501772Sjl139090 bp = id;
17511772Sjl139090
17521772Sjl139090 bp->powered = 1;
17531772Sjl139090
17541772Sjl139090 return (NULL);
17551772Sjl139090 }
17561772Sjl139090
17571772Sjl139090 static sbd_error_t *
drmach_board_release(drmachid_t id)17581772Sjl139090 drmach_board_release(drmachid_t id)
17591772Sjl139090 {
17601772Sjl139090 if (!DRMACH_IS_BOARD_ID(id))
17611772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
17621772Sjl139090 return (NULL);
17631772Sjl139090 }
17641772Sjl139090
17651772Sjl139090 /*ARGSUSED*/
17661772Sjl139090 sbd_error_t *
drmach_board_test(drmachid_t id,drmach_opts_t * opts,int force)17671772Sjl139090 drmach_board_test(drmachid_t id, drmach_opts_t *opts, int force)
17681772Sjl139090 {
17691772Sjl139090 return (NULL);
17701772Sjl139090 }
17711772Sjl139090
17721772Sjl139090 sbd_error_t *
drmach_board_unassign(drmachid_t id)17731772Sjl139090 drmach_board_unassign(drmachid_t id)
17741772Sjl139090 {
17751772Sjl139090 drmach_board_t *bp;
17761772Sjl139090 sbd_error_t *err;
17771772Sjl139090 drmach_status_t stat;
17781772Sjl139090
17793493Sbm42561 if (DRMACH_NULL_ID(id))
17803493Sbm42561 return (NULL);
17811772Sjl139090
17821772Sjl139090 if (!DRMACH_IS_BOARD_ID(id)) {
17831772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
17841772Sjl139090 }
17851772Sjl139090 bp = id;
17861772Sjl139090
17871772Sjl139090 rw_enter(&drmach_boards_rwlock, RW_WRITER);
17881772Sjl139090
17891772Sjl139090 err = drmach_board_status(id, &stat);
17901772Sjl139090 if (err) {
17911772Sjl139090 rw_exit(&drmach_boards_rwlock);
17921772Sjl139090 return (err);
17931772Sjl139090 }
17941772Sjl139090 if (stat.configured || stat.busy) {
17951772Sjl139090 err = drerr_new(0, EOPL_CONFIGBUSY, bp->cm.name);
17961772Sjl139090 } else {
17971772Sjl139090 if (drmach_array_set(drmach_boards, bp->bnum, 0) != 0)
17981772Sjl139090 err = DRMACH_INTERNAL_ERROR();
17991772Sjl139090 else
18001772Sjl139090 drmach_board_dispose(bp);
18011772Sjl139090 }
18021772Sjl139090 rw_exit(&drmach_boards_rwlock);
18031772Sjl139090 return (err);
18041772Sjl139090 }
18051772Sjl139090
18061772Sjl139090 /*
18071772Sjl139090 * We have to do more on OPL - e.g. set up sram tte, read cpuid, strand id,
18081772Sjl139090 * implementation #, etc
18091772Sjl139090 */
18101772Sjl139090
18111772Sjl139090 static sbd_error_t *
drmach_cpu_new(drmach_device_t * proto,drmachid_t * idp)18121772Sjl139090 drmach_cpu_new(drmach_device_t *proto, drmachid_t *idp)
18131772Sjl139090 {
18141772Sjl139090 static void drmach_cpu_dispose(drmachid_t);
18151772Sjl139090 static sbd_error_t *drmach_cpu_release(drmachid_t);
18161772Sjl139090 static sbd_error_t *drmach_cpu_status(drmachid_t, drmach_status_t *);
18171772Sjl139090
18181772Sjl139090 int portid;
18191772Sjl139090 drmach_cpu_t *cp = NULL;
18201772Sjl139090
18211772Sjl139090 /* portid is CPUID of the node */
18221772Sjl139090 portid = proto->portid;
18231772Sjl139090 ASSERT(portid != -1);
18241772Sjl139090
18251772Sjl139090 /* unum = (CMP/CHIP ID) + (ON_BOARD_CORE_NUM * MAX_CMPID_PER_BOARD) */
18261772Sjl139090 proto->unum = ((portid/OPL_MAX_CPUID_PER_CMP) &
18275037Sjl139090 (OPL_MAX_CMPID_PER_BOARD - 1)) +
18285037Sjl139090 ((portid & (OPL_MAX_CPUID_PER_CMP - 1)) *
18295037Sjl139090 (OPL_MAX_CMPID_PER_BOARD));
18301772Sjl139090
18311772Sjl139090 cp = kmem_zalloc(sizeof (drmach_cpu_t), KM_SLEEP);
18321772Sjl139090 bcopy(proto, &cp->dev, sizeof (cp->dev));
18331772Sjl139090 cp->dev.node = drmach_node_dup(proto->node);
18341772Sjl139090 cp->dev.cm.isa = (void *)drmach_cpu_new;
18351772Sjl139090 cp->dev.cm.dispose = drmach_cpu_dispose;
18361772Sjl139090 cp->dev.cm.release = drmach_cpu_release;
18371772Sjl139090 cp->dev.cm.status = drmach_cpu_status;
18381772Sjl139090
183911311SSurya.Prakki@Sun.COM (void) snprintf(cp->dev.cm.name, sizeof (cp->dev.cm.name), "%s%d",
18405037Sjl139090 cp->dev.type, cp->dev.unum);
18411772Sjl139090
18421772Sjl139090 /*
18431772Sjl139090 * CPU ID representation
18441772Sjl139090 * CPUID[9:5] = SB#
18451772Sjl139090 * CPUID[4:3] = Chip#
18461772Sjl139090 * CPUID[2:1] = Core# (Only 2 core for OPL)
18471772Sjl139090 * CPUID[0:0] = Strand#
18481772Sjl139090 */
18491772Sjl139090
18501772Sjl139090 /*
18511772Sjl139090 * reg property of the strand contains strand ID
18521772Sjl139090 * reg property of the parent node contains core ID
18531772Sjl139090 * We should use them.
18541772Sjl139090 */
18551772Sjl139090 cp->cpuid = portid;
18561772Sjl139090 cp->sb = (portid >> 5) & 0x1f;
18571772Sjl139090 cp->chipid = (portid >> 3) & 0x3;
18581772Sjl139090 cp->coreid = (portid >> 1) & 0x3;
18591772Sjl139090 cp->strandid = portid & 0x1;
18601772Sjl139090
18611772Sjl139090 *idp = (drmachid_t)cp;
18621772Sjl139090 return (NULL);
18631772Sjl139090 }
18641772Sjl139090
18651772Sjl139090
18661772Sjl139090 static void
drmach_cpu_dispose(drmachid_t id)18671772Sjl139090 drmach_cpu_dispose(drmachid_t id)
18681772Sjl139090 {
18691772Sjl139090 drmach_cpu_t *self;
18701772Sjl139090
18711772Sjl139090 ASSERT(DRMACH_IS_CPU_ID(id));
18721772Sjl139090
18731772Sjl139090 self = id;
18741772Sjl139090 if (self->dev.node)
18751772Sjl139090 drmach_node_dispose(self->dev.node);
18761772Sjl139090
18771772Sjl139090 kmem_free(self, sizeof (*self));
18781772Sjl139090 }
18791772Sjl139090
18801772Sjl139090 static int
drmach_cpu_start(struct cpu * cp)18811772Sjl139090 drmach_cpu_start(struct cpu *cp)
18821772Sjl139090 {
18831772Sjl139090 int cpuid = cp->cpu_id;
18841772Sjl139090 extern int restart_other_cpu(int);
18851772Sjl139090
18861772Sjl139090 ASSERT(MUTEX_HELD(&cpu_lock));
18871772Sjl139090 ASSERT(cpunodes[cpuid].nodeid != (pnode_t)0);
18881772Sjl139090
18891772Sjl139090 cp->cpu_flags &= ~CPU_POWEROFF;
18901772Sjl139090
18911772Sjl139090 /*
18921772Sjl139090 * NOTE: restart_other_cpu pauses cpus during the
18931772Sjl139090 * slave cpu start. This helps to quiesce the
18941772Sjl139090 * bus traffic a bit which makes the tick sync
18951772Sjl139090 * routine in the prom more robust.
18961772Sjl139090 */
18971772Sjl139090 DRMACH_PR("COLD START for cpu (%d)\n", cpuid);
18981772Sjl139090
189911311SSurya.Prakki@Sun.COM (void) restart_other_cpu(cpuid);
19001772Sjl139090
19011772Sjl139090 return (0);
19021772Sjl139090 }
19031772Sjl139090
19041772Sjl139090 static sbd_error_t *
drmach_cpu_release(drmachid_t id)19051772Sjl139090 drmach_cpu_release(drmachid_t id)
19061772Sjl139090 {
19071772Sjl139090 if (!DRMACH_IS_CPU_ID(id))
19081772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
19091772Sjl139090
19101772Sjl139090 return (NULL);
19111772Sjl139090 }
19121772Sjl139090
19131772Sjl139090 static sbd_error_t *
drmach_cpu_status(drmachid_t id,drmach_status_t * stat)19141772Sjl139090 drmach_cpu_status(drmachid_t id, drmach_status_t *stat)
19151772Sjl139090 {
19161772Sjl139090 drmach_cpu_t *cp;
19171772Sjl139090 drmach_device_t *dp;
19181772Sjl139090
19191772Sjl139090 ASSERT(DRMACH_IS_CPU_ID(id));
19201772Sjl139090 cp = (drmach_cpu_t *)id;
19211772Sjl139090 dp = &cp->dev;
19221772Sjl139090
19231772Sjl139090 stat->assigned = dp->bp->assigned;
19241772Sjl139090 stat->powered = dp->bp->powered;
19251772Sjl139090 mutex_enter(&cpu_lock);
19261772Sjl139090 stat->configured = (cpu_get(cp->cpuid) != NULL);
19271772Sjl139090 mutex_exit(&cpu_lock);
19281772Sjl139090 stat->busy = dp->busy;
192911311SSurya.Prakki@Sun.COM (void) strncpy(stat->type, dp->type, sizeof (stat->type));
19301772Sjl139090 stat->info[0] = '\0';
19311772Sjl139090
19321772Sjl139090 return (NULL);
19331772Sjl139090 }
19341772Sjl139090
19351772Sjl139090 sbd_error_t *
drmach_cpu_disconnect(drmachid_t id)19361772Sjl139090 drmach_cpu_disconnect(drmachid_t id)
19371772Sjl139090 {
19381772Sjl139090
19391772Sjl139090 if (!DRMACH_IS_CPU_ID(id))
19401772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
19411772Sjl139090
19421772Sjl139090 return (NULL);
19431772Sjl139090 }
19441772Sjl139090
19451772Sjl139090 sbd_error_t *
drmach_cpu_get_id(drmachid_t id,processorid_t * cpuid)19461772Sjl139090 drmach_cpu_get_id(drmachid_t id, processorid_t *cpuid)
19471772Sjl139090 {
19481772Sjl139090 drmach_cpu_t *cpu;
19491772Sjl139090
19501772Sjl139090 if (!DRMACH_IS_CPU_ID(id))
19511772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
19521772Sjl139090 cpu = (drmach_cpu_t *)id;
19531772Sjl139090
19541772Sjl139090 /* get from cpu directly on OPL */
19551772Sjl139090 *cpuid = cpu->cpuid;
19561772Sjl139090 return (NULL);
19571772Sjl139090 }
19581772Sjl139090
19591772Sjl139090 sbd_error_t *
drmach_cpu_get_impl(drmachid_t id,int * ip)19601772Sjl139090 drmach_cpu_get_impl(drmachid_t id, int *ip)
19611772Sjl139090 {
19621772Sjl139090 drmach_device_t *cpu;
19631772Sjl139090 drmach_node_t *np;
19641772Sjl139090 drmach_node_t pp;
19651772Sjl139090 int impl;
19661772Sjl139090 char type[OBP_MAXPROPNAME];
19671772Sjl139090
19681772Sjl139090 if (!DRMACH_IS_CPU_ID(id))
19691772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
19701772Sjl139090
19711772Sjl139090 cpu = id;
19721772Sjl139090 np = cpu->node;
19731772Sjl139090
19741772Sjl139090 if (np->get_parent(np, &pp) != 0) {
19751772Sjl139090 return (DRMACH_INTERNAL_ERROR());
19761772Sjl139090 }
19771772Sjl139090
19781772Sjl139090 /* the parent should be core */
19791772Sjl139090
19801772Sjl139090 if (pp.n_getprop(&pp, "device_type", &type, sizeof (type)) != 0) {
19811772Sjl139090 return (drerr_new(0, EOPL_GETPROP, NULL));
19821772Sjl139090 }
19831772Sjl139090
19841772Sjl139090 if (strcmp(type, OPL_CORE_NODE) == 0) {
19855037Sjl139090 if (pp.n_getprop(&pp, "implementation#", &impl,
19865037Sjl139090 sizeof (impl)) != 0) {
19871772Sjl139090 return (drerr_new(0, EOPL_GETPROP, NULL));
19881772Sjl139090 }
19891772Sjl139090 } else {
19901772Sjl139090 return (DRMACH_INTERNAL_ERROR());
19911772Sjl139090 }
19921772Sjl139090
19931772Sjl139090 *ip = impl;
19941772Sjl139090
19951772Sjl139090 return (NULL);
19961772Sjl139090 }
19971772Sjl139090
19981772Sjl139090 sbd_error_t *
drmach_get_dip(drmachid_t id,dev_info_t ** dip)19991772Sjl139090 drmach_get_dip(drmachid_t id, dev_info_t **dip)
20001772Sjl139090 {
20011772Sjl139090 drmach_device_t *dp;
20021772Sjl139090
20031772Sjl139090 if (!DRMACH_IS_DEVICE_ID(id))
20041772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
20051772Sjl139090 dp = id;
20061772Sjl139090
20071772Sjl139090 *dip = dp->node->n_getdip(dp->node);
20081772Sjl139090 return (NULL);
20091772Sjl139090 }
20101772Sjl139090
20111772Sjl139090 sbd_error_t *
drmach_io_is_attached(drmachid_t id,int * yes)20121772Sjl139090 drmach_io_is_attached(drmachid_t id, int *yes)
20131772Sjl139090 {
20141772Sjl139090 drmach_device_t *dp;
20151772Sjl139090 dev_info_t *dip;
20161772Sjl139090 int state;
20171772Sjl139090
20181772Sjl139090 if (!DRMACH_IS_IO_ID(id))
20191772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
20201772Sjl139090 dp = id;
20211772Sjl139090
20221772Sjl139090 dip = dp->node->n_getdip(dp->node);
20231772Sjl139090 if (dip == NULL) {
20241772Sjl139090 *yes = 0;
20251772Sjl139090 return (NULL);
20261772Sjl139090 }
20271772Sjl139090
20281772Sjl139090 state = ddi_get_devstate(dip);
20291772Sjl139090 *yes = ((i_ddi_node_state(dip) >= DS_ATTACHED) ||
20301772Sjl139090 (state == DDI_DEVSTATE_UP));
20311772Sjl139090
20321772Sjl139090 return (NULL);
20331772Sjl139090 }
20341772Sjl139090
20351772Sjl139090 struct drmach_io_cb {
20361772Sjl139090 char *name; /* name of the node */
20371772Sjl139090 int (*func)(dev_info_t *);
20381772Sjl139090 int rv;
20393354Sjl139090 dev_info_t *dip;
20401772Sjl139090 };
20411772Sjl139090
20421772Sjl139090 #define DRMACH_IO_POST_ATTACH 0
20431772Sjl139090 #define DRMACH_IO_PRE_RELEASE 1
20441772Sjl139090
20451772Sjl139090 static int
drmach_io_cb_check(dev_info_t * dip,void * arg)20461772Sjl139090 drmach_io_cb_check(dev_info_t *dip, void *arg)
20471772Sjl139090 {
20481772Sjl139090 struct drmach_io_cb *p = (struct drmach_io_cb *)arg;
20491772Sjl139090 char name[OBP_MAXDRVNAME];
20501772Sjl139090 int len = OBP_MAXDRVNAME;
20511772Sjl139090
20525037Sjl139090 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "name",
20531772Sjl139090 (caddr_t)name, &len) != DDI_PROP_SUCCESS) {
20541772Sjl139090 return (DDI_WALK_PRUNECHILD);
20551772Sjl139090 }
20561772Sjl139090
20571772Sjl139090 if (strcmp(name, p->name) == 0) {
20583354Sjl139090 ndi_hold_devi(dip);
20593354Sjl139090 p->dip = dip;
20601772Sjl139090 return (DDI_WALK_TERMINATE);
20611772Sjl139090 }
20621772Sjl139090
20631772Sjl139090 return (DDI_WALK_CONTINUE);
20641772Sjl139090 }
20651772Sjl139090
20661772Sjl139090
20671772Sjl139090 static int
drmach_console_ops(drmachid_t * id,int state)20681772Sjl139090 drmach_console_ops(drmachid_t *id, int state)
20691772Sjl139090 {
20701772Sjl139090 drmach_io_t *obj = (drmach_io_t *)id;
20711772Sjl139090 struct drmach_io_cb arg;
20721772Sjl139090 int (*msudetp)(dev_info_t *);
20731772Sjl139090 int (*msuattp)(dev_info_t *);
20741772Sjl139090 dev_info_t *dip, *pdip;
20751772Sjl139090 int circ;
20761772Sjl139090
20771772Sjl139090 /* 4 is pcicmu channel */
20781772Sjl139090 if (obj->channel != 4)
20791772Sjl139090 return (0);
20801772Sjl139090
20811772Sjl139090 arg.name = "serial";
20821772Sjl139090 arg.func = NULL;
20831772Sjl139090 if (state == DRMACH_IO_PRE_RELEASE) {
20841772Sjl139090 msudetp = (int (*)(dev_info_t *))
20851772Sjl139090 modgetsymvalue("oplmsu_dr_detach", 0);
20861772Sjl139090 if (msudetp != NULL)
20871772Sjl139090 arg.func = msudetp;
20881772Sjl139090 } else if (state == DRMACH_IO_POST_ATTACH) {
20891772Sjl139090 msuattp = (int (*)(dev_info_t *))
20901772Sjl139090 modgetsymvalue("oplmsu_dr_attach", 0);
20911772Sjl139090 if (msuattp != NULL)
20921772Sjl139090 arg.func = msuattp;
20933354Sjl139090 } else {
20943354Sjl139090 return (0);
20951772Sjl139090 }
20961772Sjl139090
20971772Sjl139090 if (arg.func == NULL) {
20981772Sjl139090 return (0);
20991772Sjl139090 }
21001772Sjl139090
21011772Sjl139090 arg.rv = 0;
21023354Sjl139090 arg.dip = NULL;
21031772Sjl139090
21041772Sjl139090 dip = obj->dev.node->n_getdip(obj->dev.node);
21051772Sjl139090 if (pdip = ddi_get_parent(dip)) {
21061772Sjl139090 ndi_hold_devi(pdip);
21071772Sjl139090 ndi_devi_enter(pdip, &circ);
21081772Sjl139090 } else {
21091772Sjl139090 /* this cannot happen unless something bad happens */
21101772Sjl139090 return (-1);
21111772Sjl139090 }
21121772Sjl139090
21131772Sjl139090 ddi_walk_devs(dip, drmach_io_cb_check, (void *)&arg);
21141772Sjl139090
21153354Sjl139090 ndi_devi_exit(pdip, circ);
21163354Sjl139090 ndi_rele_devi(pdip);
21173354Sjl139090
21183354Sjl139090 if (arg.dip) {
21193354Sjl139090 arg.rv = (*arg.func)(arg.dip);
21203354Sjl139090 ndi_rele_devi(arg.dip);
21213354Sjl139090 } else {
21223354Sjl139090 arg.rv = -1;
21231772Sjl139090 }
21241772Sjl139090
21251772Sjl139090 return (arg.rv);
21261772Sjl139090 }
21271772Sjl139090
21281772Sjl139090 sbd_error_t *
drmach_io_pre_release(drmachid_t id)21291772Sjl139090 drmach_io_pre_release(drmachid_t id)
21301772Sjl139090 {
21311772Sjl139090 int rv;
21321772Sjl139090
21331772Sjl139090 if (!DRMACH_IS_IO_ID(id))
21341772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
21351772Sjl139090
21361772Sjl139090 rv = drmach_console_ops(id, DRMACH_IO_PRE_RELEASE);
21371772Sjl139090
21381772Sjl139090 if (rv != 0)
21391772Sjl139090 cmn_err(CE_WARN, "IO callback failed in pre-release\n");
21401772Sjl139090
21411772Sjl139090 return (NULL);
21421772Sjl139090 }
21431772Sjl139090
21441772Sjl139090 static sbd_error_t *
drmach_io_release(drmachid_t id)21451772Sjl139090 drmach_io_release(drmachid_t id)
21461772Sjl139090 {
21471772Sjl139090 if (!DRMACH_IS_IO_ID(id))
21481772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
21491772Sjl139090 return (NULL);
21501772Sjl139090 }
21511772Sjl139090
21521772Sjl139090 sbd_error_t *
drmach_io_unrelease(drmachid_t id)21531772Sjl139090 drmach_io_unrelease(drmachid_t id)
21541772Sjl139090 {
21551772Sjl139090 if (!DRMACH_IS_IO_ID(id))
21561772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
21571772Sjl139090 return (NULL);
21581772Sjl139090 }
21591772Sjl139090
21601772Sjl139090 /*ARGSUSED*/
21611772Sjl139090 sbd_error_t *
drmach_io_post_release(drmachid_t id)21621772Sjl139090 drmach_io_post_release(drmachid_t id)
21631772Sjl139090 {
21641772Sjl139090 return (NULL);
21651772Sjl139090 }
21661772Sjl139090
21671772Sjl139090 /*ARGSUSED*/
21681772Sjl139090 sbd_error_t *
drmach_io_post_attach(drmachid_t id)21691772Sjl139090 drmach_io_post_attach(drmachid_t id)
21701772Sjl139090 {
21711772Sjl139090 int rv;
21721772Sjl139090
21731772Sjl139090 if (!DRMACH_IS_IO_ID(id))
21741772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
21751772Sjl139090
21761772Sjl139090 rv = drmach_console_ops(id, DRMACH_IO_POST_ATTACH);
21771772Sjl139090
21781772Sjl139090 if (rv != 0)
21791772Sjl139090 cmn_err(CE_WARN, "IO callback failed in post-attach\n");
21801772Sjl139090
21811772Sjl139090 return (0);
21821772Sjl139090 }
21831772Sjl139090
21841772Sjl139090 static sbd_error_t *
drmach_io_status(drmachid_t id,drmach_status_t * stat)21851772Sjl139090 drmach_io_status(drmachid_t id, drmach_status_t *stat)
21861772Sjl139090 {
21871772Sjl139090 drmach_device_t *dp;
21881772Sjl139090 sbd_error_t *err;
21891772Sjl139090 int configured;
21901772Sjl139090
21911772Sjl139090 ASSERT(DRMACH_IS_IO_ID(id));
21921772Sjl139090 dp = id;
21931772Sjl139090
21941772Sjl139090 err = drmach_io_is_attached(id, &configured);
21951772Sjl139090 if (err)
21961772Sjl139090 return (err);
21971772Sjl139090
21981772Sjl139090 stat->assigned = dp->bp->assigned;
21991772Sjl139090 stat->powered = dp->bp->powered;
22001772Sjl139090 stat->configured = (configured != 0);
22011772Sjl139090 stat->busy = dp->busy;
220211311SSurya.Prakki@Sun.COM (void) strncpy(stat->type, dp->type, sizeof (stat->type));
22031772Sjl139090 stat->info[0] = '\0';
22041772Sjl139090
22051772Sjl139090 return (NULL);
22061772Sjl139090 }
22071772Sjl139090
22081772Sjl139090 static sbd_error_t *
drmach_mem_new(drmach_device_t * proto,drmachid_t * idp)22091772Sjl139090 drmach_mem_new(drmach_device_t *proto, drmachid_t *idp)
22101772Sjl139090 {
22111772Sjl139090 static void drmach_mem_dispose(drmachid_t);
22121772Sjl139090 static sbd_error_t *drmach_mem_release(drmachid_t);
22131772Sjl139090 static sbd_error_t *drmach_mem_status(drmachid_t, drmach_status_t *);
22141772Sjl139090 dev_info_t *dip;
22153354Sjl139090 int rv;
22161772Sjl139090
22171772Sjl139090 drmach_mem_t *mp;
22181772Sjl139090
22193354Sjl139090 rv = 0;
22203354Sjl139090
22213354Sjl139090 if ((proto->node->n_getproplen(proto->node, "mc-addr", &rv) < 0) ||
22225037Sjl139090 (rv <= 0)) {
22233354Sjl139090 *idp = (drmachid_t)0;
22243354Sjl139090 return (NULL);
22253354Sjl139090 }
22263354Sjl139090
22271772Sjl139090 mp = kmem_zalloc(sizeof (drmach_mem_t), KM_SLEEP);
22281772Sjl139090 proto->unum = 0;
22291772Sjl139090
22301772Sjl139090 bcopy(proto, &mp->dev, sizeof (mp->dev));
22311772Sjl139090 mp->dev.node = drmach_node_dup(proto->node);
22321772Sjl139090 mp->dev.cm.isa = (void *)drmach_mem_new;
22331772Sjl139090 mp->dev.cm.dispose = drmach_mem_dispose;
22341772Sjl139090 mp->dev.cm.release = drmach_mem_release;
22351772Sjl139090 mp->dev.cm.status = drmach_mem_status;
22361772Sjl139090
223711311SSurya.Prakki@Sun.COM (void) snprintf(mp->dev.cm.name, sizeof (mp->dev.cm.name), "%s",
223811311SSurya.Prakki@Sun.COM mp->dev.type);
22391772Sjl139090
22401772Sjl139090 dip = mp->dev.node->n_getdip(mp->dev.node);
22411772Sjl139090 if (drmach_setup_mc_info(dip, mp) != 0) {
22423400Sbm42561 return (drerr_new(1, EOPL_MC_SETUP, NULL));
22431772Sjl139090 }
22441772Sjl139090
22453354Sjl139090 /* make sure we do not create memoryless nodes */
22463354Sjl139090 if (mp->nbytes == 0) {
22473354Sjl139090 *idp = (drmachid_t)NULL;
22483354Sjl139090 kmem_free(mp, sizeof (drmach_mem_t));
22493354Sjl139090 } else
22503354Sjl139090 *idp = (drmachid_t)mp;
22513354Sjl139090
22521772Sjl139090 return (NULL);
22531772Sjl139090 }
22541772Sjl139090
22551772Sjl139090 static void
drmach_mem_dispose(drmachid_t id)22561772Sjl139090 drmach_mem_dispose(drmachid_t id)
22571772Sjl139090 {
22581772Sjl139090 drmach_mem_t *mp;
22591772Sjl139090
22601772Sjl139090 ASSERT(DRMACH_IS_MEM_ID(id));
22611772Sjl139090
22621772Sjl139090
22631772Sjl139090 mp = id;
22641772Sjl139090
22651772Sjl139090 if (mp->dev.node)
22661772Sjl139090 drmach_node_dispose(mp->dev.node);
22671772Sjl139090
22681772Sjl139090 if (mp->memlist) {
22691772Sjl139090 memlist_delete(mp->memlist);
22701772Sjl139090 mp->memlist = NULL;
22711772Sjl139090 }
22723354Sjl139090
22733354Sjl139090 kmem_free(mp, sizeof (*mp));
22741772Sjl139090 }
22751772Sjl139090
22761772Sjl139090 sbd_error_t *
drmach_mem_add_span(drmachid_t id,uint64_t basepa,uint64_t size)22771772Sjl139090 drmach_mem_add_span(drmachid_t id, uint64_t basepa, uint64_t size)
22781772Sjl139090 {
22791772Sjl139090 pfn_t basepfn = (pfn_t)(basepa >> PAGESHIFT);
22801772Sjl139090 pgcnt_t npages = (pgcnt_t)(size >> PAGESHIFT);
22811772Sjl139090 int rv;
22821772Sjl139090
22831772Sjl139090 ASSERT(size != 0);
22841772Sjl139090
22851772Sjl139090 if (!DRMACH_IS_MEM_ID(id))
22861772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
22871772Sjl139090
22884266Sdp78419 rv = kcage_range_add(basepfn, npages, KCAGE_DOWN);
22891772Sjl139090 if (rv == ENOMEM) {
229011311SSurya.Prakki@Sun.COM cmn_err(CE_WARN, "%lu megabytes not available to kernel cage",
229111311SSurya.Prakki@Sun.COM (ulong_t)(size == 0 ? 0 : size / MBYTE));
22921772Sjl139090 } else if (rv != 0) {
22931772Sjl139090 /* catch this in debug kernels */
22941772Sjl139090 ASSERT(0);
22951772Sjl139090
22965037Sjl139090 cmn_err(CE_WARN, "unexpected kcage_range_add return value %d",
22975037Sjl139090 rv);
22981772Sjl139090 }
22991772Sjl139090
23001772Sjl139090 if (rv) {
23011772Sjl139090 return (DRMACH_INTERNAL_ERROR());
23021772Sjl139090 }
23031772Sjl139090 else
23041772Sjl139090 return (NULL);
23051772Sjl139090 }
23061772Sjl139090
23071772Sjl139090 sbd_error_t *
drmach_mem_del_span(drmachid_t id,uint64_t basepa,uint64_t size)23081772Sjl139090 drmach_mem_del_span(drmachid_t id, uint64_t basepa, uint64_t size)
23091772Sjl139090 {
23101772Sjl139090 pfn_t basepfn = (pfn_t)(basepa >> PAGESHIFT);
23111772Sjl139090 pgcnt_t npages = (pgcnt_t)(size >> PAGESHIFT);
23121772Sjl139090 int rv;
23131772Sjl139090
23141772Sjl139090 if (!DRMACH_IS_MEM_ID(id))
23151772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
23161772Sjl139090
23171772Sjl139090 if (size > 0) {
23181772Sjl139090 rv = kcage_range_delete_post_mem_del(basepfn, npages);
23191772Sjl139090 if (rv != 0) {
23201772Sjl139090 cmn_err(CE_WARN,
23211772Sjl139090 "unexpected kcage_range_delete_post_mem_del"
23221772Sjl139090 " return value %d", rv);
23231772Sjl139090 return (DRMACH_INTERNAL_ERROR());
23241772Sjl139090 }
23251772Sjl139090 }
23261772Sjl139090
23271772Sjl139090 return (NULL);
23281772Sjl139090 }
23291772Sjl139090
23301772Sjl139090 sbd_error_t *
drmach_mem_disable(drmachid_t id)23311772Sjl139090 drmach_mem_disable(drmachid_t id)
23321772Sjl139090 {
23331772Sjl139090 if (!DRMACH_IS_MEM_ID(id))
23341772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
23351772Sjl139090 else {
23361772Sjl139090 drmach_flush_all();
23371772Sjl139090 return (NULL);
23381772Sjl139090 }
23391772Sjl139090 }
23401772Sjl139090
23411772Sjl139090 sbd_error_t *
drmach_mem_enable(drmachid_t id)23421772Sjl139090 drmach_mem_enable(drmachid_t id)
23431772Sjl139090 {
23441772Sjl139090 if (!DRMACH_IS_MEM_ID(id))
23451772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
23461772Sjl139090 else
23471772Sjl139090 return (NULL);
23481772Sjl139090 }
23491772Sjl139090
23501772Sjl139090 sbd_error_t *
drmach_mem_get_info(drmachid_t id,drmach_mem_info_t * mem)23511772Sjl139090 drmach_mem_get_info(drmachid_t id, drmach_mem_info_t *mem)
23521772Sjl139090 {
23531772Sjl139090 drmach_mem_t *mp;
23541772Sjl139090
23551772Sjl139090 if (!DRMACH_IS_MEM_ID(id))
23561772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
23571772Sjl139090
23581772Sjl139090 mp = (drmach_mem_t *)id;
23591772Sjl139090
23601772Sjl139090 /*
23611772Sjl139090 * This is only used by dr to round up/down the memory
23621772Sjl139090 * for copying. Our unit of memory isolation is 64 MB.
23631772Sjl139090 */
23641772Sjl139090
23651772Sjl139090 mem->mi_alignment_mask = (64 * 1024 * 1024 - 1);
23661772Sjl139090 mem->mi_basepa = mp->base_pa;
23671772Sjl139090 mem->mi_size = mp->nbytes;
23681772Sjl139090 mem->mi_slice_size = mp->slice_size;
23691772Sjl139090
23701772Sjl139090 return (NULL);
23711772Sjl139090 }
23721772Sjl139090
23731772Sjl139090 sbd_error_t *
drmach_mem_get_base_physaddr(drmachid_t id,uint64_t * pa)23741772Sjl139090 drmach_mem_get_base_physaddr(drmachid_t id, uint64_t *pa)
23751772Sjl139090 {
23761772Sjl139090 drmach_mem_t *mp;
23771772Sjl139090
23781772Sjl139090 if (!DRMACH_IS_MEM_ID(id))
23791772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
23801772Sjl139090
23811772Sjl139090 mp = (drmach_mem_t *)id;
23821772Sjl139090
23831772Sjl139090 *pa = mp->base_pa;
23841772Sjl139090 return (NULL);
23851772Sjl139090 }
23861772Sjl139090
23871772Sjl139090 sbd_error_t *
drmach_mem_get_memlist(drmachid_t id,struct memlist ** ml)23881772Sjl139090 drmach_mem_get_memlist(drmachid_t id, struct memlist **ml)
23891772Sjl139090 {
23901772Sjl139090 drmach_mem_t *mem;
23913712Sbm42561 #ifdef DEBUG
23921772Sjl139090 int rv;
23933712Sbm42561 #endif
23941772Sjl139090 struct memlist *mlist;
23951772Sjl139090
23961772Sjl139090 if (!DRMACH_IS_MEM_ID(id))
23971772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
23981772Sjl139090
23991772Sjl139090 mem = (drmach_mem_t *)id;
24001772Sjl139090 mlist = memlist_dup(mem->memlist);
24011772Sjl139090
24021772Sjl139090 #ifdef DEBUG
24031772Sjl139090 /*
24041772Sjl139090 * Make sure the incoming memlist doesn't already
24051772Sjl139090 * intersect with what's present in the system (phys_install).
24061772Sjl139090 */
24071772Sjl139090 memlist_read_lock();
24081772Sjl139090 rv = memlist_intersect(phys_install, mlist);
24091772Sjl139090 memlist_read_unlock();
24101772Sjl139090 if (rv) {
24115037Sjl139090 DRMACH_PR("Derived memlist intersects with phys_install\n");
24121772Sjl139090 memlist_dump(mlist);
24131772Sjl139090
24141772Sjl139090 DRMACH_PR("phys_install memlist:\n");
24151772Sjl139090 memlist_dump(phys_install);
24161772Sjl139090
24171772Sjl139090 memlist_delete(mlist);
24181772Sjl139090 return (DRMACH_INTERNAL_ERROR());
24191772Sjl139090 }
24201772Sjl139090
24211772Sjl139090 DRMACH_PR("Derived memlist:");
24221772Sjl139090 memlist_dump(mlist);
24231772Sjl139090 #endif
24241772Sjl139090 *ml = mlist;
24251772Sjl139090
24261772Sjl139090 return (NULL);
24271772Sjl139090 }
24281772Sjl139090
24291772Sjl139090 sbd_error_t *
drmach_mem_get_slice_size(drmachid_t id,uint64_t * bytes)24301772Sjl139090 drmach_mem_get_slice_size(drmachid_t id, uint64_t *bytes)
24311772Sjl139090 {
24321772Sjl139090 drmach_mem_t *mem;
24331772Sjl139090
24341772Sjl139090 if (!DRMACH_IS_MEM_ID(id))
24351772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
24361772Sjl139090
24371772Sjl139090 mem = (drmach_mem_t *)id;
24381772Sjl139090
24391772Sjl139090 *bytes = mem->slice_size;
24401772Sjl139090
24411772Sjl139090 return (NULL);
24421772Sjl139090 }
24431772Sjl139090
24441772Sjl139090
24451772Sjl139090 /* ARGSUSED */
24461772Sjl139090 processorid_t
drmach_mem_cpu_affinity(drmachid_t id)24471772Sjl139090 drmach_mem_cpu_affinity(drmachid_t id)
24481772Sjl139090 {
24491772Sjl139090 return (CPU_CURRENT);
24501772Sjl139090 }
24511772Sjl139090
24521772Sjl139090 static sbd_error_t *
drmach_mem_release(drmachid_t id)24531772Sjl139090 drmach_mem_release(drmachid_t id)
24541772Sjl139090 {
24551772Sjl139090 if (!DRMACH_IS_MEM_ID(id))
24561772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
24571772Sjl139090 return (NULL);
24581772Sjl139090 }
24591772Sjl139090
24601772Sjl139090 static sbd_error_t *
drmach_mem_status(drmachid_t id,drmach_status_t * stat)24611772Sjl139090 drmach_mem_status(drmachid_t id, drmach_status_t *stat)
24621772Sjl139090 {
24631772Sjl139090 drmach_mem_t *dp;
24641772Sjl139090 uint64_t pa, slice_size;
24651772Sjl139090 struct memlist *ml;
24661772Sjl139090
24671772Sjl139090 ASSERT(DRMACH_IS_MEM_ID(id));
24681772Sjl139090 dp = id;
24691772Sjl139090
24701772Sjl139090 /* get starting physical address of target memory */
24711772Sjl139090 pa = dp->base_pa;
24721772Sjl139090
24731772Sjl139090 /* round down to slice boundary */
24741772Sjl139090 slice_size = dp->slice_size;
24751772Sjl139090 pa &= ~(slice_size - 1);
24761772Sjl139090
24771772Sjl139090 /* stop at first span that is in slice */
24781772Sjl139090 memlist_read_lock();
2479*11474SJonathan.Adams@Sun.COM for (ml = phys_install; ml; ml = ml->ml_next)
2480*11474SJonathan.Adams@Sun.COM if (ml->ml_address >= pa && ml->ml_address < pa + slice_size)
24811772Sjl139090 break;
24821772Sjl139090 memlist_read_unlock();
24831772Sjl139090
24841772Sjl139090 stat->assigned = dp->dev.bp->assigned;
24851772Sjl139090 stat->powered = dp->dev.bp->powered;
24861772Sjl139090 stat->configured = (ml != NULL);
24871772Sjl139090 stat->busy = dp->dev.busy;
248811311SSurya.Prakki@Sun.COM (void) strncpy(stat->type, dp->dev.type, sizeof (stat->type));
24891772Sjl139090 stat->info[0] = '\0';
24901772Sjl139090
24911772Sjl139090 return (NULL);
24921772Sjl139090 }
24931772Sjl139090
24941772Sjl139090
24951772Sjl139090 sbd_error_t *
drmach_board_deprobe(drmachid_t id)24961772Sjl139090 drmach_board_deprobe(drmachid_t id)
24971772Sjl139090 {
24981772Sjl139090 drmach_board_t *bp;
24991772Sjl139090
25001772Sjl139090 if (!DRMACH_IS_BOARD_ID(id))
25011772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
25021772Sjl139090
25031772Sjl139090 bp = id;
25041772Sjl139090
25053354Sjl139090 cmn_err(CE_CONT, "DR: detach board %d\n", bp->bnum);
25061772Sjl139090
25071772Sjl139090 if (bp->tree) {
25081772Sjl139090 drmach_node_dispose(bp->tree);
25091772Sjl139090 bp->tree = NULL;
25101772Sjl139090 }
25111772Sjl139090 if (bp->devices) {
25121772Sjl139090 drmach_array_dispose(bp->devices, drmach_device_dispose);
25131772Sjl139090 bp->devices = NULL;
25141772Sjl139090 }
25151772Sjl139090
25161772Sjl139090 bp->boot_board = 0;
25171772Sjl139090
25181772Sjl139090 return (NULL);
25191772Sjl139090 }
25201772Sjl139090
25211772Sjl139090 /*ARGSUSED*/
25221772Sjl139090 static sbd_error_t *
drmach_pt_ikprobe(drmachid_t id,drmach_opts_t * opts)25231772Sjl139090 drmach_pt_ikprobe(drmachid_t id, drmach_opts_t *opts)
25241772Sjl139090 {
25251772Sjl139090 drmach_board_t *bp = (drmach_board_t *)id;
25261772Sjl139090 sbd_error_t *err = NULL;
25271772Sjl139090 int rv;
25285037Sjl139090 unsigned cpu_impl;
25291772Sjl139090
25301772Sjl139090 if (!DRMACH_IS_BOARD_ID(id))
25311772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
25321772Sjl139090
25331772Sjl139090 DRMACH_PR("calling opl_probe_board for bnum=%d\n", bp->bnum);
25345037Sjl139090 rv = opl_probe_sb(bp->bnum, &cpu_impl);
25351772Sjl139090 if (rv != 0) {
25363400Sbm42561 err = drerr_new(1, EOPL_PROBE, bp->cm.name);
25371772Sjl139090 return (err);
25381772Sjl139090 }
25391772Sjl139090 return (err);
25401772Sjl139090 }
25411772Sjl139090
25421772Sjl139090 /*ARGSUSED*/
25431772Sjl139090 static sbd_error_t *
drmach_pt_ikdeprobe(drmachid_t id,drmach_opts_t * opts)25441772Sjl139090 drmach_pt_ikdeprobe(drmachid_t id, drmach_opts_t *opts)
25451772Sjl139090 {
25461772Sjl139090 drmach_board_t *bp;
25471772Sjl139090 sbd_error_t *err = NULL;
25481772Sjl139090 int rv;
25491772Sjl139090
25501772Sjl139090 if (!DRMACH_IS_BOARD_ID(id))
25511772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
25521772Sjl139090 bp = (drmach_board_t *)id;
25531772Sjl139090
25541772Sjl139090 cmn_err(CE_CONT, "DR: in-kernel unprobe board %d\n", bp->bnum);
25551772Sjl139090
25561772Sjl139090 rv = opl_unprobe_sb(bp->bnum);
25571772Sjl139090 if (rv != 0) {
25583400Sbm42561 err = drerr_new(1, EOPL_DEPROBE, bp->cm.name);
25591772Sjl139090 }
25601772Sjl139090
25611772Sjl139090 return (err);
25621772Sjl139090 }
25631772Sjl139090
25641772Sjl139090
25651772Sjl139090 /*ARGSUSED*/
25661772Sjl139090 sbd_error_t *
drmach_pt_readmem(drmachid_t id,drmach_opts_t * opts)25671772Sjl139090 drmach_pt_readmem(drmachid_t id, drmach_opts_t *opts)
25681772Sjl139090 {
25691772Sjl139090 struct memlist *ml;
25701772Sjl139090 uint64_t src_pa;
25711772Sjl139090 uint64_t dst_pa;
25721772Sjl139090 uint64_t dst;
25731772Sjl139090
25741772Sjl139090 dst_pa = va_to_pa(&dst);
25751772Sjl139090
25761772Sjl139090 memlist_read_lock();
2577*11474SJonathan.Adams@Sun.COM for (ml = phys_install; ml; ml = ml->ml_next) {
25781772Sjl139090 uint64_t nbytes;
25791772Sjl139090
2580*11474SJonathan.Adams@Sun.COM src_pa = ml->ml_address;
2581*11474SJonathan.Adams@Sun.COM nbytes = ml->ml_size;
25821772Sjl139090
25831772Sjl139090 while (nbytes != 0ull) {
25841772Sjl139090
25851772Sjl139090 /* copy 32 bytes at arc_pa to dst_pa */
25861772Sjl139090 bcopy32_il(src_pa, dst_pa);
25871772Sjl139090
25881772Sjl139090 /* increment by 32 bytes */
25891772Sjl139090 src_pa += (4 * sizeof (uint64_t));
25901772Sjl139090
25911772Sjl139090 /* decrement by 32 bytes */
25921772Sjl139090 nbytes -= (4 * sizeof (uint64_t));
25931772Sjl139090 }
25941772Sjl139090 }
25951772Sjl139090 memlist_read_unlock();
25961772Sjl139090
25971772Sjl139090 return (NULL);
25981772Sjl139090 }
25991772Sjl139090
26001772Sjl139090 static struct {
26011772Sjl139090 const char *name;
26021772Sjl139090 sbd_error_t *(*handler)(drmachid_t id, drmach_opts_t *opts);
26031772Sjl139090 } drmach_pt_arr[] = {
26041772Sjl139090 { "readmem", drmach_pt_readmem },
26051772Sjl139090 { "ikprobe", drmach_pt_ikprobe },
26061772Sjl139090 { "ikdeprobe", drmach_pt_ikdeprobe },
26071772Sjl139090
26081772Sjl139090 /* the following line must always be last */
26091772Sjl139090 { NULL, NULL }
26101772Sjl139090 };
26111772Sjl139090
26121772Sjl139090 /*ARGSUSED*/
26131772Sjl139090 sbd_error_t *
drmach_passthru(drmachid_t id,drmach_opts_t * opts)26141772Sjl139090 drmach_passthru(drmachid_t id, drmach_opts_t *opts)
26151772Sjl139090 {
26161772Sjl139090 int i;
26171772Sjl139090 sbd_error_t *err;
26181772Sjl139090
26191772Sjl139090 i = 0;
26201772Sjl139090 while (drmach_pt_arr[i].name != NULL) {
26211772Sjl139090 int len = strlen(drmach_pt_arr[i].name);
26221772Sjl139090
26231772Sjl139090 if (strncmp(drmach_pt_arr[i].name, opts->copts, len) == 0)
26241772Sjl139090 break;
26251772Sjl139090
26261772Sjl139090 i += 1;
26271772Sjl139090 }
26281772Sjl139090
26291772Sjl139090 if (drmach_pt_arr[i].name == NULL)
26301772Sjl139090 err = drerr_new(0, EOPL_UNKPTCMD, opts->copts);
26311772Sjl139090 else
26321772Sjl139090 err = (*drmach_pt_arr[i].handler)(id, opts);
26331772Sjl139090
26341772Sjl139090 return (err);
26351772Sjl139090 }
26361772Sjl139090
26371772Sjl139090 sbd_error_t *
drmach_release(drmachid_t id)26381772Sjl139090 drmach_release(drmachid_t id)
26391772Sjl139090 {
26401772Sjl139090 drmach_common_t *cp;
26411772Sjl139090
26421772Sjl139090 if (!DRMACH_IS_DEVICE_ID(id))
26431772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
26441772Sjl139090 cp = id;
26451772Sjl139090
26461772Sjl139090 return (cp->release(id));
26471772Sjl139090 }
26481772Sjl139090
26491772Sjl139090 sbd_error_t *
drmach_status(drmachid_t id,drmach_status_t * stat)26501772Sjl139090 drmach_status(drmachid_t id, drmach_status_t *stat)
26511772Sjl139090 {
26521772Sjl139090 drmach_common_t *cp;
26531772Sjl139090 sbd_error_t *err;
26541772Sjl139090
26551772Sjl139090 rw_enter(&drmach_boards_rwlock, RW_READER);
26561772Sjl139090
26571772Sjl139090 if (!DRMACH_IS_ID(id)) {
26581772Sjl139090 rw_exit(&drmach_boards_rwlock);
26591772Sjl139090 return (drerr_new(0, EOPL_NOTID, NULL));
26601772Sjl139090 }
26611772Sjl139090 cp = (drmach_common_t *)id;
26621772Sjl139090 err = cp->status(id, stat);
26631772Sjl139090
26641772Sjl139090 rw_exit(&drmach_boards_rwlock);
26651772Sjl139090
26661772Sjl139090 return (err);
26671772Sjl139090 }
26681772Sjl139090
26691772Sjl139090 static sbd_error_t *
drmach_i_status(drmachid_t id,drmach_status_t * stat)26701772Sjl139090 drmach_i_status(drmachid_t id, drmach_status_t *stat)
26711772Sjl139090 {
26721772Sjl139090 drmach_common_t *cp;
26731772Sjl139090
26741772Sjl139090 if (!DRMACH_IS_ID(id))
26751772Sjl139090 return (drerr_new(0, EOPL_NOTID, NULL));
26761772Sjl139090 cp = id;
26771772Sjl139090
26781772Sjl139090 return (cp->status(id, stat));
26791772Sjl139090 }
26801772Sjl139090
26811772Sjl139090 /*ARGSUSED*/
26821772Sjl139090 sbd_error_t *
drmach_unconfigure(drmachid_t id,int flags)26831772Sjl139090 drmach_unconfigure(drmachid_t id, int flags)
26841772Sjl139090 {
26851772Sjl139090 drmach_device_t *dp;
26861772Sjl139090 dev_info_t *rdip, *fdip = NULL;
26871772Sjl139090 char name[OBP_MAXDRVNAME];
26881772Sjl139090 int rv;
26891772Sjl139090
26901772Sjl139090 if (DRMACH_IS_CPU_ID(id))
26911772Sjl139090 return (NULL);
26921772Sjl139090
26931772Sjl139090 if (!DRMACH_IS_DEVICE_ID(id))
26941772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
26951772Sjl139090
26961772Sjl139090 dp = id;
26971772Sjl139090
26981772Sjl139090 rdip = dp->node->n_getdip(dp->node);
26991772Sjl139090
27001772Sjl139090 ASSERT(rdip);
27011772Sjl139090
27021772Sjl139090 rv = dp->node->n_getprop(dp->node, "name", name, OBP_MAXDRVNAME);
27031772Sjl139090
27041772Sjl139090 if (rv)
27051772Sjl139090 return (NULL);
27061772Sjl139090
27071772Sjl139090 /*
27081772Sjl139090 * Note: FORCE flag is no longer necessary under devfs
27091772Sjl139090 */
27101772Sjl139090
27111772Sjl139090 ASSERT(e_ddi_branch_held(rdip));
27121772Sjl139090 if (e_ddi_branch_unconfigure(rdip, &fdip, 0)) {
27131772Sjl139090 sbd_error_t *err;
27141772Sjl139090 char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
27151772Sjl139090
27161772Sjl139090 /*
27171772Sjl139090 * If non-NULL, fdip is returned held and must be released.
27181772Sjl139090 */
27191772Sjl139090 if (fdip != NULL) {
27201772Sjl139090 (void) ddi_pathname(fdip, path);
27211772Sjl139090 ndi_rele_devi(fdip);
27221772Sjl139090 } else {
27231772Sjl139090 (void) ddi_pathname(rdip, path);
27241772Sjl139090 }
27251772Sjl139090
27261772Sjl139090 err = drerr_new(1, EOPL_DRVFAIL, path);
27271772Sjl139090
27281772Sjl139090 kmem_free(path, MAXPATHLEN);
27291772Sjl139090
27301772Sjl139090 return (err);
27311772Sjl139090 }
27321772Sjl139090
27331772Sjl139090 return (NULL);
27341772Sjl139090 }
27351772Sjl139090
27361772Sjl139090
27371772Sjl139090 int
drmach_cpu_poweron(struct cpu * cp)27381772Sjl139090 drmach_cpu_poweron(struct cpu *cp)
27391772Sjl139090 {
27401772Sjl139090 int bnum, cpuid, onb_core_num, strand_id;
27411772Sjl139090 drmach_board_t *bp;
27421772Sjl139090
27431772Sjl139090 DRMACH_PR("drmach_cpu_poweron: starting cpuid %d\n", cp->cpu_id);
27441772Sjl139090
27451772Sjl139090 cpuid = cp->cpu_id;
27461772Sjl139090 bnum = LSB_ID(cpuid);
27471772Sjl139090 onb_core_num = ON_BOARD_CORE_NUM(cpuid);
27481772Sjl139090 strand_id = STRAND_ID(cpuid);
27491772Sjl139090 bp = drmach_get_board_by_bnum(bnum);
27501772Sjl139090
27511772Sjl139090 ASSERT(bp);
27521772Sjl139090 if (bp->cores[onb_core_num].core_hotadded == 0) {
27531772Sjl139090 if (drmach_add_remove_cpu(bnum, onb_core_num,
27545037Sjl139090 HOTADD_CPU) != 0) {
27551772Sjl139090 cmn_err(CE_WARN, "Failed to add CMP %d on board %d\n",
27565037Sjl139090 onb_core_num, bnum);
27571772Sjl139090 return (EIO);
27581772Sjl139090 }
27591772Sjl139090 }
27601772Sjl139090
27611772Sjl139090 ASSERT(MUTEX_HELD(&cpu_lock));
27621772Sjl139090
27631772Sjl139090 if (drmach_cpu_start(cp) != 0) {
27641772Sjl139090 if (bp->cores[onb_core_num].core_started == 0) {
27651772Sjl139090 /*
27661772Sjl139090 * we must undo the hotadd or no one will do that
27671772Sjl139090 * If this fails, we will do this again in
27681772Sjl139090 * drmach_board_disconnect.
27691772Sjl139090 */
27701772Sjl139090 if (drmach_add_remove_cpu(bnum, onb_core_num,
27715037Sjl139090 HOTREMOVE_CPU) != 0) {
27721772Sjl139090 cmn_err(CE_WARN, "Failed to remove CMP %d "
27735037Sjl139090 "on board %d\n", onb_core_num, bnum);
27741772Sjl139090 }
27751772Sjl139090 }
27761772Sjl139090 return (EBUSY);
27771772Sjl139090 } else {
27781772Sjl139090 bp->cores[onb_core_num].core_started |= (1 << strand_id);
27791772Sjl139090 return (0);
27801772Sjl139090 }
27811772Sjl139090 }
27821772Sjl139090
27831772Sjl139090 int
drmach_cpu_poweroff(struct cpu * cp)27841772Sjl139090 drmach_cpu_poweroff(struct cpu *cp)
27851772Sjl139090 {
27861772Sjl139090 int rv = 0;
27871772Sjl139090 processorid_t cpuid = cp->cpu_id;
27881772Sjl139090
27891772Sjl139090 DRMACH_PR("drmach_cpu_poweroff: stopping cpuid %d\n", cp->cpu_id);
27901772Sjl139090
27911772Sjl139090 ASSERT(MUTEX_HELD(&cpu_lock));
27921772Sjl139090
27931772Sjl139090 /*
27941772Sjl139090 * Capture all CPUs (except for detaching proc) to prevent
27951772Sjl139090 * crosscalls to the detaching proc until it has cleared its
27961772Sjl139090 * bit in cpu_ready_set.
27971772Sjl139090 *
27981772Sjl139090 * The CPU's remain paused and the prom_mutex is known to be free.
27991772Sjl139090 * This prevents the x-trap victim from blocking when doing prom
28001772Sjl139090 * IEEE-1275 calls at a high PIL level.
28011772Sjl139090 */
28021772Sjl139090
28031772Sjl139090 promsafe_pause_cpus();
28041772Sjl139090
28051772Sjl139090 /*
28061772Sjl139090 * Quiesce interrupts on the target CPU. We do this by setting
28071772Sjl139090 * the CPU 'not ready'- (i.e. removing the CPU from cpu_ready_set) to
28081772Sjl139090 * prevent it from receiving cross calls and cross traps.
28091772Sjl139090 * This prevents the processor from receiving any new soft interrupts.
28101772Sjl139090 */
28111772Sjl139090 mp_cpu_quiesce(cp);
28121772Sjl139090
28131772Sjl139090 rv = prom_stopcpu_bycpuid(cpuid);
28141772Sjl139090 if (rv == 0)
28151772Sjl139090 cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_POWEROFF;
28161772Sjl139090
28171772Sjl139090 start_cpus();
28181772Sjl139090
28191772Sjl139090 if (rv == 0) {
28201772Sjl139090 int bnum, onb_core_num, strand_id;
28211772Sjl139090 drmach_board_t *bp;
28221772Sjl139090
28231772Sjl139090 CPU_SIGNATURE(OS_SIG, SIGST_DETACHED, SIGSUBST_NULL, cpuid);
28241772Sjl139090
28251772Sjl139090 bnum = LSB_ID(cpuid);
28261772Sjl139090 onb_core_num = ON_BOARD_CORE_NUM(cpuid);
28271772Sjl139090 strand_id = STRAND_ID(cpuid);
28281772Sjl139090 bp = drmach_get_board_by_bnum(bnum);
28291772Sjl139090 ASSERT(bp);
28301772Sjl139090
28311772Sjl139090 bp->cores[onb_core_num].core_started &= ~(1 << strand_id);
28321772Sjl139090 if (bp->cores[onb_core_num].core_started == 0) {
28331772Sjl139090 if (drmach_add_remove_cpu(bnum, onb_core_num,
28345037Sjl139090 HOTREMOVE_CPU) != 0) {
28355037Sjl139090 cmn_err(CE_WARN, "Failed to remove CMP %d LSB "
28365037Sjl139090 "%d\n", onb_core_num, bnum);
28371772Sjl139090 return (EIO);
28381772Sjl139090 }
28391772Sjl139090 }
28401772Sjl139090 }
28411772Sjl139090
28421772Sjl139090 return (rv);
28431772Sjl139090 }
28441772Sjl139090
28451772Sjl139090 /*ARGSUSED*/
28461772Sjl139090 int
drmach_verify_sr(dev_info_t * dip,int sflag)28471772Sjl139090 drmach_verify_sr(dev_info_t *dip, int sflag)
28481772Sjl139090 {
28491772Sjl139090 return (0);
28501772Sjl139090 }
28511772Sjl139090
28521772Sjl139090 void
drmach_suspend_last(void)28531772Sjl139090 drmach_suspend_last(void)
28541772Sjl139090 {
28551772Sjl139090 }
28561772Sjl139090
28571772Sjl139090 void
drmach_resume_first(void)28581772Sjl139090 drmach_resume_first(void)
28591772Sjl139090 {
28601772Sjl139090 }
28611772Sjl139090
28621772Sjl139090 /*
28631772Sjl139090 * Log a DR sysevent.
28641772Sjl139090 * Return value: 0 success, non-zero failure.
28651772Sjl139090 */
28661772Sjl139090 int
drmach_log_sysevent(int board,char * hint,int flag,int verbose)28671772Sjl139090 drmach_log_sysevent(int board, char *hint, int flag, int verbose)
28681772Sjl139090 {
28691772Sjl139090 sysevent_t *ev;
28701772Sjl139090 sysevent_id_t eid;
28711772Sjl139090 int rv, km_flag;
28721772Sjl139090 sysevent_value_t evnt_val;
28731772Sjl139090 sysevent_attr_list_t *evnt_attr_list = NULL;
28741772Sjl139090 char attach_pnt[MAXNAMELEN];
28751772Sjl139090
28761772Sjl139090 km_flag = (flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
28771772Sjl139090 attach_pnt[0] = '\0';
28781772Sjl139090 if (drmach_board_name(board, attach_pnt, MAXNAMELEN)) {
28791772Sjl139090 rv = -1;
28801772Sjl139090 goto logexit;
28811772Sjl139090 }
28823712Sbm42561 if (verbose) {
28831772Sjl139090 DRMACH_PR("drmach_log_sysevent: %s %s, flag: %d, verbose: %d\n",
28845037Sjl139090 attach_pnt, hint, flag, verbose);
28853712Sbm42561 }
28861772Sjl139090
28871772Sjl139090 if ((ev = sysevent_alloc(EC_DR, ESC_DR_AP_STATE_CHANGE,
28885037Sjl139090 SUNW_KERN_PUB"dr", km_flag)) == NULL) {
28891772Sjl139090 rv = -2;
28901772Sjl139090 goto logexit;
28911772Sjl139090 }
28921772Sjl139090 evnt_val.value_type = SE_DATA_TYPE_STRING;
28931772Sjl139090 evnt_val.value.sv_string = attach_pnt;
28945037Sjl139090 if ((rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID, &evnt_val,
28955037Sjl139090 km_flag)) != 0)
28961772Sjl139090 goto logexit;
28971772Sjl139090
28981772Sjl139090 evnt_val.value_type = SE_DATA_TYPE_STRING;
28991772Sjl139090 evnt_val.value.sv_string = hint;
29005037Sjl139090 if ((rv = sysevent_add_attr(&evnt_attr_list, DR_HINT, &evnt_val,
29015037Sjl139090 km_flag)) != 0) {
29021772Sjl139090 sysevent_free_attr(evnt_attr_list);
29031772Sjl139090 goto logexit;
29041772Sjl139090 }
29051772Sjl139090
29061772Sjl139090 (void) sysevent_attach_attributes(ev, evnt_attr_list);
29071772Sjl139090
29081772Sjl139090 /*
29091772Sjl139090 * Log the event but do not sleep waiting for its
29101772Sjl139090 * delivery. This provides insulation from syseventd.
29111772Sjl139090 */
29121772Sjl139090 rv = log_sysevent(ev, SE_NOSLEEP, &eid);
29131772Sjl139090
29141772Sjl139090 logexit:
29151772Sjl139090 if (ev)
29161772Sjl139090 sysevent_free(ev);
29171772Sjl139090 if ((rv != 0) && verbose)
29185037Sjl139090 cmn_err(CE_WARN, "drmach_log_sysevent failed (rv %d) for %s "
29195037Sjl139090 " %s\n", rv, attach_pnt, hint);
29201772Sjl139090
29211772Sjl139090 return (rv);
29221772Sjl139090 }
29231772Sjl139090
29241772Sjl139090 #define OPL_DR_STATUS_PROP "dr-status"
29251772Sjl139090
29261772Sjl139090 static int
opl_check_dr_status()29271772Sjl139090 opl_check_dr_status()
29281772Sjl139090 {
29291772Sjl139090 pnode_t node;
29301772Sjl139090 int rtn, len;
29311772Sjl139090 char *str;
29321772Sjl139090
29331772Sjl139090 node = prom_rootnode();
29341772Sjl139090 if (node == OBP_BADNODE) {
29351772Sjl139090 return (1);
29361772Sjl139090 }
29371772Sjl139090
29381772Sjl139090 len = prom_getproplen(node, OPL_DR_STATUS_PROP);
29391772Sjl139090 if (len == -1) {
29401772Sjl139090 /*
29411772Sjl139090 * dr-status doesn't exist when DR is activated and
29421772Sjl139090 * any warning messages aren't needed.
29431772Sjl139090 */
29441772Sjl139090 return (1);
29451772Sjl139090 }
29461772Sjl139090
29471772Sjl139090 str = (char *)kmem_zalloc(len+1, KM_SLEEP);
29481772Sjl139090 rtn = prom_getprop(node, OPL_DR_STATUS_PROP, str);
29491772Sjl139090 kmem_free(str, len + 1);
29501772Sjl139090 if (rtn == -1) {
29511772Sjl139090 return (1);
29521772Sjl139090 } else {
29531772Sjl139090 return (0);
29541772Sjl139090 }
29551772Sjl139090 }
29561772Sjl139090
29571772Sjl139090 /* we are allocating memlist from TLB locked pages to avoid tlbmisses */
29581772Sjl139090
29591772Sjl139090 static struct memlist *
drmach_memlist_add_span(drmach_copy_rename_program_t * p,struct memlist * mlist,uint64_t base,uint64_t len)29601772Sjl139090 drmach_memlist_add_span(drmach_copy_rename_program_t *p,
29611772Sjl139090 struct memlist *mlist, uint64_t base, uint64_t len)
29621772Sjl139090 {
29631772Sjl139090 struct memlist *ml, *tl, *nl;
29641772Sjl139090
29651772Sjl139090 if (len == 0ull)
29661772Sjl139090 return (NULL);
29671772Sjl139090
29681772Sjl139090 if (mlist == NULL) {
29691772Sjl139090 mlist = p->free_mlist;
29701772Sjl139090 if (mlist == NULL)
29711772Sjl139090 return (NULL);
2972*11474SJonathan.Adams@Sun.COM p->free_mlist = mlist->ml_next;
2973*11474SJonathan.Adams@Sun.COM mlist->ml_address = base;
2974*11474SJonathan.Adams@Sun.COM mlist->ml_size = len;
2975*11474SJonathan.Adams@Sun.COM mlist->ml_next = mlist->ml_prev = NULL;
29761772Sjl139090
29771772Sjl139090 return (mlist);
29781772Sjl139090 }
29791772Sjl139090
2980*11474SJonathan.Adams@Sun.COM for (tl = ml = mlist; ml; tl = ml, ml = ml->ml_next) {
2981*11474SJonathan.Adams@Sun.COM if (base < ml->ml_address) {
2982*11474SJonathan.Adams@Sun.COM if ((base + len) < ml->ml_address) {
29831772Sjl139090 nl = p->free_mlist;
29841772Sjl139090 if (nl == NULL)
29851772Sjl139090 return (NULL);
2986*11474SJonathan.Adams@Sun.COM p->free_mlist = nl->ml_next;
2987*11474SJonathan.Adams@Sun.COM nl->ml_address = base;
2988*11474SJonathan.Adams@Sun.COM nl->ml_size = len;
2989*11474SJonathan.Adams@Sun.COM nl->ml_next = ml;
2990*11474SJonathan.Adams@Sun.COM if ((nl->ml_prev = ml->ml_prev) != NULL)
2991*11474SJonathan.Adams@Sun.COM nl->ml_prev->ml_next = nl;
2992*11474SJonathan.Adams@Sun.COM ml->ml_prev = nl;
29931772Sjl139090 if (mlist == ml)
29941772Sjl139090 mlist = nl;
29951772Sjl139090 } else {
2996*11474SJonathan.Adams@Sun.COM ml->ml_size = MAX((base + len),
2997*11474SJonathan.Adams@Sun.COM (ml->ml_address + ml->ml_size)) - base;
2998*11474SJonathan.Adams@Sun.COM ml->ml_address = base;
29991772Sjl139090 }
30001772Sjl139090 break;
30011772Sjl139090
3002*11474SJonathan.Adams@Sun.COM } else if (base <= (ml->ml_address + ml->ml_size)) {
3003*11474SJonathan.Adams@Sun.COM ml->ml_size =
3004*11474SJonathan.Adams@Sun.COM MAX((base + len), (ml->ml_address + ml->ml_size)) -
3005*11474SJonathan.Adams@Sun.COM MIN(ml->ml_address, base);
3006*11474SJonathan.Adams@Sun.COM ml->ml_address = MIN(ml->ml_address, base);
30071772Sjl139090 break;
30081772Sjl139090 }
30091772Sjl139090 }
30101772Sjl139090 if (ml == NULL) {
30111772Sjl139090 nl = p->free_mlist;
30121772Sjl139090 if (nl == NULL)
30131772Sjl139090 return (NULL);
3014*11474SJonathan.Adams@Sun.COM p->free_mlist = nl->ml_next;
3015*11474SJonathan.Adams@Sun.COM nl->ml_address = base;
3016*11474SJonathan.Adams@Sun.COM nl->ml_size = len;
3017*11474SJonathan.Adams@Sun.COM nl->ml_next = NULL;
3018*11474SJonathan.Adams@Sun.COM nl->ml_prev = tl;
3019*11474SJonathan.Adams@Sun.COM tl->ml_next = nl;
30201772Sjl139090 }
30211772Sjl139090
30221772Sjl139090 return (mlist);
30231772Sjl139090 }
30241772Sjl139090
30251772Sjl139090 /*
30261772Sjl139090 * The routine performs the necessary memory COPY and MC adr SWITCH.
30271772Sjl139090 * Both operations MUST be at the same "level" so that the stack is
30281772Sjl139090 * maintained correctly between the copy and switch. The switch
30291772Sjl139090 * portion implements a caching mechanism to guarantee the code text
30301772Sjl139090 * is cached prior to execution. This is to guard against possible
30311772Sjl139090 * memory access while the MC adr's are being modified.
30321772Sjl139090 *
30331772Sjl139090 * IMPORTANT: The _drmach_copy_rename_end() function must immediately
30341772Sjl139090 * follow drmach_copy_rename_prog__relocatable() so that the correct
30351772Sjl139090 * "length" of the drmach_copy_rename_prog__relocatable can be
30361772Sjl139090 * calculated. This routine MUST be a LEAF function, i.e. it can
30371772Sjl139090 * make NO function calls, primarily for two reasons:
30381772Sjl139090 *
30391772Sjl139090 * 1. We must keep the stack consistent across the "switch".
30401772Sjl139090 * 2. Function calls are compiled to relative offsets, and
30411772Sjl139090 * we execute this function we'll be executing it from
30421772Sjl139090 * a copied version in a different area of memory, thus
30431772Sjl139090 * the relative offsets will be bogus.
30441772Sjl139090 *
30451772Sjl139090 * Moreover, it must have the "__relocatable" suffix to inform DTrace
30461772Sjl139090 * providers (and anything else, for that matter) that this
30471772Sjl139090 * function's text is manually relocated elsewhere before it is
30481772Sjl139090 * executed. That is, it cannot be safely instrumented with any
30491772Sjl139090 * methodology that is PC-relative.
30501772Sjl139090 */
30511772Sjl139090
30521772Sjl139090 /*
30531772Sjl139090 * We multiply this to system_clock_frequency so we
30541772Sjl139090 * are setting a delay of fmem_timeout second for
30553712Sbm42561 * the rename command.
30563712Sbm42561 *
30573712Sbm42561 * FMEM command itself should complete within 15 sec.
30583712Sbm42561 * We add 2 more sec to be conservative.
30593712Sbm42561 *
30603712Sbm42561 * Note that there is also a SCF BUSY bit checking
30613712Sbm42561 * in drmach_asm.s right before FMEM command is
30623712Sbm42561 * issued. XSCF sets the SCF BUSY bit when the
30633712Sbm42561 * other domain on the same PSB reboots and it
30643712Sbm42561 * will not be able to service the FMEM command
30653712Sbm42561 * within 15 sec. After setting the SCF BUSY
30663712Sbm42561 * bit, XSCF will wait a while before servicing
30673712Sbm42561 * other reboot command so there is no race
30683712Sbm42561 * condition.
30691772Sjl139090 */
30703712Sbm42561
30711772Sjl139090 static int fmem_timeout = 17;
30723712Sbm42561
30733712Sbm42561 /*
30743712Sbm42561 * The empirical data on some OPL system shows that
30753712Sbm42561 * we can copy 250 MB per second. We set it to
30763712Sbm42561 * 80 MB to be conservative. In normal case,
30773712Sbm42561 * this timeout does not affect anything.
30783712Sbm42561 */
30793712Sbm42561
30803712Sbm42561 static int min_copy_size_per_sec = 80 * 1024 * 1024;
30813712Sbm42561
30823712Sbm42561 /*
30833712Sbm42561 * This is the timeout value for the xcall synchronization
30843712Sbm42561 * to get all the CPU ready to do the parallel copying.
30853712Sbm42561 * Even on a fully loaded system, 10 sec. should be long
30863712Sbm42561 * enough.
30873712Sbm42561 */
30883712Sbm42561
30893712Sbm42561 static int cpu_xcall_delay = 10;
30901772Sjl139090 int drmach_disable_mcopy = 0;
30911772Sjl139090
30923354Sjl139090 /*
30933354Sjl139090 * The following delay loop executes sleep instruction to yield the
30943354Sjl139090 * CPU to other strands. If this is not done, some strand will tie
30953354Sjl139090 * up the CPU in busy loops while the other strand cannot do useful
30963354Sjl139090 * work. The copy procedure will take a much longer time without this.
30973354Sjl139090 */
30981772Sjl139090 #define DR_DELAY_IL(ms, freq) \
30991772Sjl139090 { \
31001772Sjl139090 uint64_t start; \
31011772Sjl139090 uint64_t nstick; \
31021772Sjl139090 volatile uint64_t now; \
31031772Sjl139090 nstick = ((uint64_t)ms * freq)/1000; \
31041772Sjl139090 start = drmach_get_stick_il(); \
31051772Sjl139090 now = start; \
31061772Sjl139090 while ((now - start) <= nstick) { \
31071772Sjl139090 drmach_sleep_il(); \
31081772Sjl139090 now = drmach_get_stick_il(); \
31091772Sjl139090 } \
31101772Sjl139090 }
31111772Sjl139090
31126551Swh31274 /* Each loop is 2ms, timeout at 1000ms */
31136551Swh31274 static int drmach_copy_rename_timeout = 500;
31146551Swh31274
31151772Sjl139090 static int
drmach_copy_rename_prog__relocatable(drmach_copy_rename_program_t * prog,int cpuid)31161772Sjl139090 drmach_copy_rename_prog__relocatable(drmach_copy_rename_program_t *prog,
31171772Sjl139090 int cpuid)
31181772Sjl139090 {
31191772Sjl139090 struct memlist *ml;
31201772Sjl139090 register int rtn;
31211772Sjl139090 int i;
31221772Sjl139090 register uint64_t curr, limit;
31231772Sjl139090 extern uint64_t drmach_get_stick_il();
31241772Sjl139090 extern void membar_sync_il();
31251772Sjl139090 extern void flush_instr_mem_il(void*);
31263354Sjl139090 extern void flush_windows_il(void);
31271772Sjl139090 uint64_t copy_start;
31281772Sjl139090
31293354Sjl139090 /*
31303354Sjl139090 * flush_windows is moved here to make sure all
31313354Sjl139090 * registers used in the callers are flushed to
31323354Sjl139090 * memory before the copy.
31333354Sjl139090 *
31343354Sjl139090 * If flush_windows() is called too early in the
31353354Sjl139090 * calling function, the compiler might put some
31363354Sjl139090 * data in the local registers after flush_windows().
31373354Sjl139090 * After FMA, if there is any fill trap, the registers
31383354Sjl139090 * will contain stale data.
31393354Sjl139090 */
31403354Sjl139090
31413354Sjl139090 flush_windows_il();
31423354Sjl139090
31431772Sjl139090 prog->critical->stat[cpuid] = FMEM_LOOP_COPY_READY;
31441772Sjl139090 membar_sync_il();
31451772Sjl139090
31461772Sjl139090 if (prog->data->cpuid == cpuid) {
31471772Sjl139090 limit = drmach_get_stick_il();
31483712Sbm42561 limit += cpu_xcall_delay * system_clock_freq;
31491772Sjl139090 for (i = 0; i < NCPU; i++) {
31501772Sjl139090 if (CPU_IN_SET(prog->data->cpu_slave_set, i)) {
31515037Sjl139090 /* wait for all CPU's to be ready */
31525037Sjl139090 for (;;) {
31535037Sjl139090 if (prog->critical->stat[i] ==
31545037Sjl139090 FMEM_LOOP_COPY_READY) {
31555037Sjl139090 break;
31565037Sjl139090 }
31575037Sjl139090 DR_DELAY_IL(1, prog->data->stick_freq);
31581772Sjl139090 }
31595037Sjl139090 curr = drmach_get_stick_il();
31605037Sjl139090 if (curr > limit) {
31615037Sjl139090 prog->data->fmem_status.error =
31625037Sjl139090 EOPL_FMEM_XC_TIMEOUT;
31635037Sjl139090 return (EOPL_FMEM_XC_TIMEOUT);
31645037Sjl139090 }
31651772Sjl139090 }
31661772Sjl139090 }
31671772Sjl139090 prog->data->fmem_status.stat = FMEM_LOOP_COPY_READY;
31681772Sjl139090 membar_sync_il();
31691772Sjl139090 copy_start = drmach_get_stick_il();
31701772Sjl139090 } else {
31711772Sjl139090 for (;;) {
31721772Sjl139090 if (prog->data->fmem_status.stat ==
31735037Sjl139090 FMEM_LOOP_COPY_READY) {
31741772Sjl139090 break;
31751772Sjl139090 }
31761772Sjl139090 if (prog->data->fmem_status.error) {
31775037Sjl139090 prog->data->error[cpuid] = EOPL_FMEM_TERMINATE;
31783712Sbm42561 return (EOPL_FMEM_TERMINATE);
31791772Sjl139090 }
31803354Sjl139090 DR_DELAY_IL(1, prog->data->stick_freq);
31811772Sjl139090 }
31821772Sjl139090 }
31831772Sjl139090
31841772Sjl139090 /*
31851772Sjl139090 * DO COPY.
31861772Sjl139090 */
31871772Sjl139090 if (CPU_IN_SET(prog->data->cpu_copy_set, cpuid)) {
3188*11474SJonathan.Adams@Sun.COM for (ml = prog->data->cpu_ml[cpuid]; ml; ml = ml->ml_next) {
31895037Sjl139090 uint64_t s_pa, t_pa;
31905037Sjl139090 uint64_t nbytes;
31915037Sjl139090
3192*11474SJonathan.Adams@Sun.COM s_pa = prog->data->s_copybasepa + ml->ml_address;
3193*11474SJonathan.Adams@Sun.COM t_pa = prog->data->t_copybasepa + ml->ml_address;
3194*11474SJonathan.Adams@Sun.COM nbytes = ml->ml_size;
31955037Sjl139090
31965037Sjl139090 while (nbytes != 0ull) {
31975037Sjl139090 /*
31985037Sjl139090 * If the master has detected error, we just
31995037Sjl139090 * bail out
32005037Sjl139090 */
32015037Sjl139090 if (prog->data->fmem_status.error !=
32025037Sjl139090 ESBD_NOERROR) {
32035037Sjl139090 prog->data->error[cpuid] =
32045037Sjl139090 EOPL_FMEM_TERMINATE;
32055037Sjl139090 return (EOPL_FMEM_TERMINATE);
32065037Sjl139090 }
32075037Sjl139090 /*
32085037Sjl139090 * This copy does NOT use an ASI
32095037Sjl139090 * that avoids the Ecache, therefore
32105037Sjl139090 * the dst_pa addresses may remain
32115037Sjl139090 * in our Ecache after the dst_pa
32125037Sjl139090 * has been removed from the system.
32135037Sjl139090 * A subsequent write-back to memory
32145037Sjl139090 * will cause an ARB-stop because the
32155037Sjl139090 * physical address no longer exists
32165037Sjl139090 * in the system. Therefore we must
32175037Sjl139090 * flush out local Ecache after we
32185037Sjl139090 * finish the copy.
32195037Sjl139090 */
32205037Sjl139090
32215037Sjl139090 /* copy 32 bytes at src_pa to dst_pa */
32225037Sjl139090 bcopy32_il(s_pa, t_pa);
32235037Sjl139090
32245037Sjl139090 /*
32255037Sjl139090 * increment the counter to signal that we are
32265037Sjl139090 * alive
32275037Sjl139090 */
32285037Sjl139090 prog->stat->nbytes[cpuid] += 32;
32295037Sjl139090
32305037Sjl139090 /* increment by 32 bytes */
32315037Sjl139090 s_pa += (4 * sizeof (uint64_t));
32325037Sjl139090 t_pa += (4 * sizeof (uint64_t));
32335037Sjl139090
32345037Sjl139090 /* decrement by 32 bytes */
32355037Sjl139090 nbytes -= (4 * sizeof (uint64_t));
32361772Sjl139090 }
32371772Sjl139090 }
32385037Sjl139090 prog->critical->stat[cpuid] = FMEM_LOOP_COPY_DONE;
32395037Sjl139090 membar_sync_il();
32401772Sjl139090 }
32411772Sjl139090
32421772Sjl139090 /*
32431772Sjl139090 * Since bcopy32_il() does NOT use an ASI to bypass
32441772Sjl139090 * the Ecache, we need to flush our Ecache after
32451772Sjl139090 * the copy is complete.
32461772Sjl139090 */
32471772Sjl139090 flush_cache_il();
32481772Sjl139090
32491772Sjl139090 /*
32501772Sjl139090 * drmach_fmem_exec_script()
32511772Sjl139090 */
32521772Sjl139090 if (prog->data->cpuid == cpuid) {
32531772Sjl139090 uint64_t last, now;
32541772Sjl139090
32551772Sjl139090 limit = copy_start + prog->data->copy_delay;
32561772Sjl139090 for (i = 0; i < NCPU; i++) {
32575037Sjl139090 if (!CPU_IN_SET(prog->data->cpu_slave_set, i))
32585037Sjl139090 continue;
32595037Sjl139090
32605037Sjl139090 for (;;) {
32615037Sjl139090 /*
32625037Sjl139090 * we get FMEM_LOOP_FMEM_READY in
32635037Sjl139090 * normal case
32645037Sjl139090 */
32651772Sjl139090 if (prog->critical->stat[i] ==
32665037Sjl139090 FMEM_LOOP_FMEM_READY) {
32671772Sjl139090 break;
32681772Sjl139090 }
32691772Sjl139090 /* got error traps */
32703712Sbm42561 if (prog->data->error[i] ==
32715037Sjl139090 EOPL_FMEM_COPY_ERROR) {
32721772Sjl139090 prog->data->fmem_status.error =
32735037Sjl139090 EOPL_FMEM_COPY_ERROR;
32743712Sbm42561 return (EOPL_FMEM_COPY_ERROR);
32751772Sjl139090 }
32765037Sjl139090 /*
32775037Sjl139090 * if we have not reached limit, wait
32785037Sjl139090 * more
32795037Sjl139090 */
32801772Sjl139090 curr = drmach_get_stick_il();
32811772Sjl139090 if (curr <= limit)
32821772Sjl139090 continue;
32831772Sjl139090
32841772Sjl139090 prog->data->slowest_cpuid = i;
32855037Sjl139090 prog->data->copy_wait_time = curr - copy_start;
32861772Sjl139090
32871772Sjl139090 /* now check if slave is alive */
32881772Sjl139090 last = prog->stat->nbytes[i];
32891772Sjl139090
32901772Sjl139090 DR_DELAY_IL(1, prog->data->stick_freq);
32911772Sjl139090
32921772Sjl139090 now = prog->stat->nbytes[i];
32931772Sjl139090 if (now <= last) {
32945037Sjl139090 /*
32955037Sjl139090 * no progress, perhaps just
32965037Sjl139090 * finished
32975037Sjl139090 */
32981772Sjl139090 DR_DELAY_IL(1, prog->data->stick_freq);
32991772Sjl139090 if (prog->critical->stat[i] ==
33005037Sjl139090 FMEM_LOOP_FMEM_READY)
33011772Sjl139090 break;
33021772Sjl139090 /* copy error */
33033712Sbm42561 if (prog->data->error[i] ==
33045037Sjl139090 EOPL_FMEM_COPY_ERROR) {
33055037Sjl139090 prog->data-> fmem_status.error =
33065037Sjl139090 EOPL_FMEM_COPY_ERROR;
33073712Sbm42561 return (EOPL_FMEM_COPY_ERROR);
33081772Sjl139090 }
33096551Swh31274
33106551Swh31274 prog->data->copy_rename_count++;
33116551Swh31274 if (prog->data->copy_rename_count
33126551Swh31274 < drmach_copy_rename_timeout) {
33136551Swh31274 continue;
33146551Swh31274 } else {
33156551Swh31274 prog->data->fmem_status.error =
33166551Swh31274 EOPL_FMEM_COPY_TIMEOUT;
33176551Swh31274 return (EOPL_FMEM_COPY_TIMEOUT);
33186551Swh31274 }
33191772Sjl139090 }
33201772Sjl139090 }
33211772Sjl139090 }
33223712Sbm42561
33231772Sjl139090 prog->critical->stat[cpuid] = FMEM_LOOP_FMEM_READY;
33241772Sjl139090 prog->data->fmem_status.stat = FMEM_LOOP_FMEM_READY;
33251772Sjl139090
33261772Sjl139090 membar_sync_il();
33271772Sjl139090 flush_instr_mem_il((void*) (prog->critical));
33281772Sjl139090 /*
33291772Sjl139090 * drmach_fmem_exec_script()
33301772Sjl139090 */
33311772Sjl139090 rtn = prog->critical->fmem((void *)prog->critical, PAGESIZE);
33321772Sjl139090 return (rtn);
33331772Sjl139090 } else {
33341772Sjl139090 flush_instr_mem_il((void*) (prog->critical));
33351772Sjl139090 /*
33361772Sjl139090 * drmach_fmem_loop_script()
33371772Sjl139090 */
33385037Sjl139090 rtn = prog->critical->loop((void *)(prog->critical), PAGESIZE,
33395037Sjl139090 (void *)&(prog->critical->stat[cpuid]));
33401772Sjl139090 prog->data->error[cpuid] = rtn;
33411772Sjl139090 /* slave thread does not care the rv */
33421772Sjl139090 return (0);
33431772Sjl139090 }
33441772Sjl139090 }
33451772Sjl139090
33461772Sjl139090 static void
drmach_copy_rename_end(void)33471772Sjl139090 drmach_copy_rename_end(void)
33481772Sjl139090 {
33491772Sjl139090 /*
33501772Sjl139090 * IMPORTANT: This function's location MUST be located immediately
33511772Sjl139090 * following drmach_copy_rename_prog__relocatable to
33521772Sjl139090 * accurately estimate its size. Note that this assumes
33531772Sjl139090 * the compiler keeps these functions in the order in
33541772Sjl139090 * which they appear :-o
33551772Sjl139090 */
33561772Sjl139090 }
33571772Sjl139090
33581772Sjl139090
33596551Swh31274 static int
drmach_setup_memlist(drmach_copy_rename_program_t * p)33601772Sjl139090 drmach_setup_memlist(drmach_copy_rename_program_t *p)
33611772Sjl139090 {
33621772Sjl139090 struct memlist *ml;
33631772Sjl139090 caddr_t buf;
33646551Swh31274 int nbytes, s, n_elements;
33651772Sjl139090
33661772Sjl139090 nbytes = PAGESIZE;
33676551Swh31274 n_elements = 0;
33681772Sjl139090 s = roundup(sizeof (struct memlist), sizeof (void *));
33691772Sjl139090 p->free_mlist = NULL;
33701772Sjl139090 buf = p->memlist_buffer;
33711772Sjl139090 while (nbytes >= sizeof (struct memlist)) {
33721772Sjl139090 ml = (struct memlist *)buf;
3373*11474SJonathan.Adams@Sun.COM ml->ml_next = p->free_mlist;
33741772Sjl139090 p->free_mlist = ml;
33751772Sjl139090 buf += s;
33766551Swh31274 n_elements++;
33771772Sjl139090 nbytes -= s;
33781772Sjl139090 }
33796551Swh31274 return (n_elements);
33801772Sjl139090 }
33811772Sjl139090
33823354Sjl139090 static void
drmach_lock_critical(caddr_t va,caddr_t new_va)33833354Sjl139090 drmach_lock_critical(caddr_t va, caddr_t new_va)
33843354Sjl139090 {
33853354Sjl139090 tte_t tte;
33863354Sjl139090 int i;
33873354Sjl139090
33883354Sjl139090 kpreempt_disable();
33893354Sjl139090
33903354Sjl139090 for (i = 0; i < DRMACH_FMEM_LOCKED_PAGES; i++) {
33913354Sjl139090 vtag_flushpage(new_va, (uint64_t)ksfmmup);
33925037Sjl139090 sfmmu_memtte(&tte, va_to_pfn(va), PROC_DATA|HAT_NOSYNC, TTE8K);
33933354Sjl139090 tte.tte_intlo |= TTE_LCK_INT;
33943354Sjl139090 sfmmu_dtlb_ld_kva(new_va, &tte);
33953354Sjl139090 sfmmu_itlb_ld_kva(new_va, &tte);
33963354Sjl139090 va += PAGESIZE;
33973354Sjl139090 new_va += PAGESIZE;
33983354Sjl139090 }
33993354Sjl139090 }
34003354Sjl139090
34013354Sjl139090 static void
drmach_unlock_critical(caddr_t va)34023354Sjl139090 drmach_unlock_critical(caddr_t va)
34033354Sjl139090 {
34043354Sjl139090 int i;
34053354Sjl139090
34063354Sjl139090 for (i = 0; i < DRMACH_FMEM_LOCKED_PAGES; i++) {
34073354Sjl139090 vtag_flushpage(va, (uint64_t)ksfmmup);
34083354Sjl139090 va += PAGESIZE;
34093354Sjl139090 }
34103354Sjl139090
34113354Sjl139090 kpreempt_enable();
34123354Sjl139090 }
34133354Sjl139090
34141772Sjl139090 sbd_error_t *
drmach_copy_rename_init(drmachid_t t_id,drmachid_t s_id,struct memlist * c_ml,drmachid_t * pgm_id)34151772Sjl139090 drmach_copy_rename_init(drmachid_t t_id, drmachid_t s_id,
34161772Sjl139090 struct memlist *c_ml, drmachid_t *pgm_id)
34171772Sjl139090 {
34181772Sjl139090 drmach_mem_t *s_mem;
34191772Sjl139090 drmach_mem_t *t_mem;
34201772Sjl139090 struct memlist *x_ml;
34211772Sjl139090 uint64_t s_copybasepa, t_copybasepa;
34221772Sjl139090 uint_t len;
34231772Sjl139090 caddr_t bp, wp;
34246551Swh31274 int s_bd, t_bd, cpuid, active_cpus, i;
34256551Swh31274 int max_elms, mlist_size, rv;
34266551Swh31274 uint64_t c_addr;
34276551Swh31274 size_t c_size, copy_sz, sz;
34286551Swh31274 extern void drmach_fmem_loop_script();
34296551Swh31274 extern void drmach_fmem_loop_script_rtn();
34306551Swh31274 extern int drmach_fmem_exec_script();
34316551Swh31274 extern void drmach_fmem_exec_script_end();
34321772Sjl139090 sbd_error_t *err;
34333354Sjl139090 drmach_copy_rename_program_t *prog = NULL;
34343354Sjl139090 drmach_copy_rename_program_t *prog_kmem = NULL;
34351772Sjl139090 void (*mc_suspend)(void);
34361772Sjl139090 void (*mc_resume)(void);
34371772Sjl139090 int (*scf_fmem_start)(int, int);
34381772Sjl139090 int (*scf_fmem_end)(void);
34391772Sjl139090 int (*scf_fmem_cancel)(void);
34403354Sjl139090 uint64_t (*scf_get_base_addr)(void);
34411772Sjl139090
34421772Sjl139090 if (!DRMACH_IS_MEM_ID(s_id))
34431772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
34441772Sjl139090 if (!DRMACH_IS_MEM_ID(t_id))
34451772Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL));
34461772Sjl139090
34471772Sjl139090 for (i = 0; i < NCPU; i++) {
34481772Sjl139090 int lsb_id, onb_core_num, strand_id;
34491772Sjl139090 drmach_board_t *bp;
34501772Sjl139090
34511772Sjl139090 /*
34521772Sjl139090 * this kind of CPU will spin in cache
34531772Sjl139090 */
34541772Sjl139090 if (CPU_IN_SET(cpu_ready_set, i))
34551772Sjl139090 continue;
34561772Sjl139090
34571772Sjl139090 /*
34581772Sjl139090 * Now check for any inactive CPU's that
34591772Sjl139090 * have been hotadded. This can only occur in
34601772Sjl139090 * error condition in drmach_cpu_poweron().
34611772Sjl139090 */
34621772Sjl139090 lsb_id = LSB_ID(i);
34631772Sjl139090 onb_core_num = ON_BOARD_CORE_NUM(i);
34641772Sjl139090 strand_id = STRAND_ID(i);
34651772Sjl139090 bp = drmach_get_board_by_bnum(lsb_id);
34661772Sjl139090 if (bp == NULL)
34671772Sjl139090 continue;
34681772Sjl139090 if (bp->cores[onb_core_num].core_hotadded &
34691772Sjl139090 (1 << strand_id)) {
34705037Sjl139090 if (!(bp->cores[onb_core_num].core_started &
34715037Sjl139090 (1 << strand_id))) {
34725037Sjl139090 return (drerr_new(1, EOPL_CPU_STATE, NULL));
34735037Sjl139090 }
34741772Sjl139090 }
34751772Sjl139090 }
34761772Sjl139090
34771772Sjl139090 mc_suspend = (void (*)(void))
34781772Sjl139090 modgetsymvalue("opl_mc_suspend", 0);
34791772Sjl139090 mc_resume = (void (*)(void))
34801772Sjl139090 modgetsymvalue("opl_mc_resume", 0);
34811772Sjl139090
34821772Sjl139090 if (mc_suspend == NULL || mc_resume == NULL) {
34833400Sbm42561 return (drerr_new(1, EOPL_MC_OPL, NULL));
34841772Sjl139090 }
34851772Sjl139090
34861772Sjl139090 scf_fmem_start = (int (*)(int, int))
34871772Sjl139090 modgetsymvalue("scf_fmem_start", 0);
34881772Sjl139090 if (scf_fmem_start == NULL) {
34893400Sbm42561 return (drerr_new(1, EOPL_SCF_FMEM, NULL));
34901772Sjl139090 }
34911772Sjl139090 scf_fmem_end = (int (*)(void))
34921772Sjl139090 modgetsymvalue("scf_fmem_end", 0);
34931772Sjl139090 if (scf_fmem_end == NULL) {
34943400Sbm42561 return (drerr_new(1, EOPL_SCF_FMEM, NULL));
34951772Sjl139090 }
34961772Sjl139090 scf_fmem_cancel = (int (*)(void))
34971772Sjl139090 modgetsymvalue("scf_fmem_cancel", 0);
34981772Sjl139090 if (scf_fmem_cancel == NULL) {
34993400Sbm42561 return (drerr_new(1, EOPL_SCF_FMEM, NULL));
35003354Sjl139090 }
35013354Sjl139090 scf_get_base_addr = (uint64_t (*)(void))
35023354Sjl139090 modgetsymvalue("scf_get_base_addr", 0);
35033354Sjl139090 if (scf_get_base_addr == NULL) {
35043400Sbm42561 return (drerr_new(1, EOPL_SCF_FMEM, NULL));
35051772Sjl139090 }
35061772Sjl139090 s_mem = s_id;
35071772Sjl139090 t_mem = t_id;
35081772Sjl139090
35091772Sjl139090 s_bd = s_mem->dev.bp->bnum;
35101772Sjl139090 t_bd = t_mem->dev.bp->bnum;
35111772Sjl139090
35121772Sjl139090 /* calculate source and target base pa */
35131772Sjl139090
35141772Sjl139090 s_copybasepa = s_mem->slice_base;
35151772Sjl139090 t_copybasepa = t_mem->slice_base;
35161772Sjl139090
35171772Sjl139090 /* adjust copy memlist addresses to be relative to copy base pa */
35181772Sjl139090 x_ml = c_ml;
35196551Swh31274 mlist_size = 0;
35201772Sjl139090 while (x_ml != NULL) {
3521*11474SJonathan.Adams@Sun.COM x_ml->ml_address -= s_copybasepa;
3522*11474SJonathan.Adams@Sun.COM x_ml = x_ml->ml_next;
35236551Swh31274 mlist_size++;
35241772Sjl139090 }
35251772Sjl139090
35261772Sjl139090 /*
35271772Sjl139090 * bp will be page aligned, since we're calling
35281772Sjl139090 * kmem_zalloc() with an exact multiple of PAGESIZE.
35291772Sjl139090 */
35303354Sjl139090
35313354Sjl139090 prog_kmem = (drmach_copy_rename_program_t *)kmem_zalloc(
35325037Sjl139090 DRMACH_FMEM_LOCKED_PAGES * PAGESIZE, KM_SLEEP);
35333354Sjl139090
35343354Sjl139090 prog_kmem->prog = prog_kmem;
35353354Sjl139090
35363354Sjl139090 /*
35373354Sjl139090 * To avoid MTLB hit, we allocate a new VM space and remap
35383354Sjl139090 * the kmem_alloc buffer to that address. This solves
35393354Sjl139090 * 2 problems we found:
35403354Sjl139090 * - the kmem_alloc buffer can be just a chunk inside
35413354Sjl139090 * a much larger, e.g. 4MB buffer and MTLB will occur
35423354Sjl139090 * if there are both a 4MB and a 8K TLB mapping to
35433354Sjl139090 * the same VA range.
35443354Sjl139090 * - the kmem mapping got dropped into the TLB by other
35453354Sjl139090 * strands, unintentionally.
35463354Sjl139090 * Note that the pointers like data, critical, memlist_buffer,
35473354Sjl139090 * and stat inside the copy rename structure are mapped to this
35483354Sjl139090 * alternate VM space so we must make sure we lock the TLB mapping
35493354Sjl139090 * whenever we access data pointed to by these pointers.
35503354Sjl139090 */
35513354Sjl139090
35523354Sjl139090 prog = prog_kmem->locked_prog = vmem_alloc(heap_arena,
35535037Sjl139090 DRMACH_FMEM_LOCKED_PAGES * PAGESIZE, VM_SLEEP);
35543354Sjl139090 wp = bp = (caddr_t)prog;
35553354Sjl139090
35563354Sjl139090 /* Now remap prog_kmem to prog */
35573354Sjl139090 drmach_lock_critical((caddr_t)prog_kmem, (caddr_t)prog);
35583354Sjl139090
35593354Sjl139090 /* All pointers in prog are based on the alternate mapping */
35601772Sjl139090 prog->data = (drmach_copy_rename_data_t *)roundup(((uint64_t)prog +
35615037Sjl139090 sizeof (drmach_copy_rename_program_t)), sizeof (void *));
35621772Sjl139090
35631772Sjl139090 ASSERT(((uint64_t)prog->data + sizeof (drmach_copy_rename_data_t))
35645037Sjl139090 <= ((uint64_t)prog + PAGESIZE));
35651772Sjl139090
35661772Sjl139090 prog->critical = (drmach_copy_rename_critical_t *)
35675037Sjl139090 (wp + DRMACH_FMEM_CRITICAL_PAGE * PAGESIZE);
35685037Sjl139090
35695037Sjl139090 prog->memlist_buffer = (caddr_t)(wp + DRMACH_FMEM_MLIST_PAGE *
35705037Sjl139090 PAGESIZE);
35715037Sjl139090
35725037Sjl139090 prog->stat = (drmach_cr_stat_t *)(wp + DRMACH_FMEM_STAT_PAGE *
35735037Sjl139090 PAGESIZE);
35741772Sjl139090
35751772Sjl139090 /* LINTED */
35765037Sjl139090 ASSERT(sizeof (drmach_cr_stat_t) <= ((DRMACH_FMEM_LOCKED_PAGES -
35775037Sjl139090 DRMACH_FMEM_STAT_PAGE) * PAGESIZE));
35781772Sjl139090
35791772Sjl139090 prog->critical->scf_reg_base = (uint64_t)-1;
35801772Sjl139090 prog->critical->scf_td[0] = (s_bd & 0xff);
35811772Sjl139090 prog->critical->scf_td[1] = (t_bd & 0xff);
35821772Sjl139090 for (i = 2; i < 15; i++) {
35831772Sjl139090 prog->critical->scf_td[i] = 0;
35841772Sjl139090 }
35851772Sjl139090 prog->critical->scf_td[15] = ((0xaa + s_bd + t_bd) & 0xff);
35861772Sjl139090
35871772Sjl139090 bp = (caddr_t)prog->critical;
35881772Sjl139090 len = sizeof (drmach_copy_rename_critical_t);
35891772Sjl139090 wp = (caddr_t)roundup((uint64_t)bp + len, sizeof (void *));
35901772Sjl139090
35911772Sjl139090 len = (uint_t)((ulong_t)drmach_copy_rename_end -
35925037Sjl139090 (ulong_t)drmach_copy_rename_prog__relocatable);
35931772Sjl139090
35941772Sjl139090 /*
35951772Sjl139090 * We always leave 1K nop's to prevent the processor from
35961772Sjl139090 * speculative execution that causes memory access
35971772Sjl139090 */
35981772Sjl139090 wp = wp + len + 1024;
35991772Sjl139090
36001772Sjl139090 len = (uint_t)((ulong_t)drmach_fmem_exec_script_end -
36015037Sjl139090 (ulong_t)drmach_fmem_exec_script);
36021772Sjl139090 /* this is the entry point of the loop script */
36031772Sjl139090 wp = wp + len + 1024;
36041772Sjl139090
36051772Sjl139090 len = (uint_t)((ulong_t)drmach_fmem_exec_script -
36065037Sjl139090 (ulong_t)drmach_fmem_loop_script);
36071772Sjl139090 wp = wp + len + 1024;
36081772Sjl139090
36091772Sjl139090 /* now we make sure there is 1K extra */
36101772Sjl139090
36111772Sjl139090 if ((wp - bp) > PAGESIZE) {
36123400Sbm42561 err = drerr_new(1, EOPL_FMEM_SETUP, NULL);
36133354Sjl139090 goto out;
36141772Sjl139090 }
36151772Sjl139090
36161772Sjl139090 bp = (caddr_t)prog->critical;
36171772Sjl139090 len = sizeof (drmach_copy_rename_critical_t);
36181772Sjl139090 wp = (caddr_t)roundup((uint64_t)bp + len, sizeof (void *));
36191772Sjl139090
36201772Sjl139090 prog->critical->run = (int (*)())(wp);
36211772Sjl139090 len = (uint_t)((ulong_t)drmach_copy_rename_end -
36225037Sjl139090 (ulong_t)drmach_copy_rename_prog__relocatable);
36231772Sjl139090
36241772Sjl139090 bcopy((caddr_t)drmach_copy_rename_prog__relocatable, wp, len);
36251772Sjl139090
36261772Sjl139090 wp = (caddr_t)roundup((uint64_t)wp + len, 1024);
36271772Sjl139090
36281772Sjl139090 prog->critical->fmem = (int (*)())(wp);
36291772Sjl139090 len = (int)((ulong_t)drmach_fmem_exec_script_end -
36305037Sjl139090 (ulong_t)drmach_fmem_exec_script);
36311772Sjl139090 bcopy((caddr_t)drmach_fmem_exec_script, wp, len);
36321772Sjl139090
36331772Sjl139090 len = (int)((ulong_t)drmach_fmem_exec_script_end -
36345037Sjl139090 (ulong_t)drmach_fmem_exec_script);
36351772Sjl139090 wp = (caddr_t)roundup((uint64_t)wp + len, 1024);
36361772Sjl139090
36371772Sjl139090 prog->critical->loop = (int (*)())(wp);
36381772Sjl139090 len = (int)((ulong_t)drmach_fmem_exec_script -
36395037Sjl139090 (ulong_t)drmach_fmem_loop_script);
36401772Sjl139090 bcopy((caddr_t)drmach_fmem_loop_script, (void *)wp, len);
36411772Sjl139090 len = (int)((ulong_t)drmach_fmem_loop_script_rtn-
36425037Sjl139090 (ulong_t)drmach_fmem_loop_script);
36431772Sjl139090 prog->critical->loop_rtn = (void (*)()) (wp+len);
36441772Sjl139090
36453712Sbm42561 prog->data->fmem_status.error = ESBD_NOERROR;
36463712Sbm42561
36471772Sjl139090 /* now we are committed, call SCF, soft suspend mac patrol */
36481772Sjl139090 if ((*scf_fmem_start)(s_bd, t_bd)) {
36493400Sbm42561 err = drerr_new(1, EOPL_SCF_FMEM_START, NULL);
36503354Sjl139090 goto out;
36511772Sjl139090 }
36521772Sjl139090 prog->data->scf_fmem_end = scf_fmem_end;
36531772Sjl139090 prog->data->scf_fmem_cancel = scf_fmem_cancel;
36543354Sjl139090 prog->data->scf_get_base_addr = scf_get_base_addr;
36551772Sjl139090 prog->data->fmem_status.op |= OPL_FMEM_SCF_START;
36563712Sbm42561
36571772Sjl139090 /* soft suspend mac patrol */
36581772Sjl139090 (*mc_suspend)();
36591772Sjl139090 prog->data->fmem_status.op |= OPL_FMEM_MC_SUSPEND;
36601772Sjl139090 prog->data->mc_resume = mc_resume;
36611772Sjl139090
36621772Sjl139090 prog->critical->inst_loop_ret =
36635037Sjl139090 *(uint64_t *)(prog->critical->loop_rtn);
36641772Sjl139090
36651772Sjl139090 /*
36661772Sjl139090 * 0x30800000 is op code "ba,a +0"
36671772Sjl139090 */
36681772Sjl139090
36691772Sjl139090 *(uint_t *)(prog->critical->loop_rtn) = (uint_t)(0x30800000);
36701772Sjl139090
36711772Sjl139090 /*
36721772Sjl139090 * set the value of SCF FMEM TIMEOUT
36731772Sjl139090 */
36741772Sjl139090 prog->critical->delay = fmem_timeout * system_clock_freq;
36751772Sjl139090
36761772Sjl139090 prog->data->s_mem = (drmachid_t)s_mem;
36771772Sjl139090 prog->data->t_mem = (drmachid_t)t_mem;
36781772Sjl139090
36791772Sjl139090 cpuid = CPU->cpu_id;
36801772Sjl139090 prog->data->cpuid = cpuid;
36811772Sjl139090 prog->data->cpu_ready_set = cpu_ready_set;
36821772Sjl139090 prog->data->cpu_slave_set = cpu_ready_set;
36831772Sjl139090 prog->data->slowest_cpuid = (processorid_t)-1;
36841772Sjl139090 prog->data->copy_wait_time = 0;
36856551Swh31274 prog->data->copy_rename_count = 0;
36861772Sjl139090 CPUSET_DEL(prog->data->cpu_slave_set, cpuid);
36871772Sjl139090
36881772Sjl139090 for (i = 0; i < NCPU; i++) {
36891772Sjl139090 prog->data->cpu_ml[i] = NULL;
36901772Sjl139090 }
36911772Sjl139090
36926551Swh31274 /*
36936551Swh31274 * max_elms - max number of memlist structures that
36946551Swh31274 * may be allocated for the CPU memory list.
36956551Swh31274 * If there are too many memory span (because
36966551Swh31274 * of fragmentation) than number of memlist
36976551Swh31274 * available, we should return error.
36986551Swh31274 */
36996551Swh31274 max_elms = drmach_setup_memlist(prog);
37006551Swh31274 if (max_elms < mlist_size) {
37016551Swh31274 err = drerr_new(1, EOPL_FMEM_SETUP, NULL);
37026551Swh31274 goto err_out;
37036551Swh31274 }
37046551Swh31274
37051772Sjl139090 active_cpus = 0;
37061772Sjl139090 if (drmach_disable_mcopy) {
37071772Sjl139090 active_cpus = 1;
37081772Sjl139090 CPUSET_ADD(prog->data->cpu_copy_set, cpuid);
37091772Sjl139090 } else {
37106551Swh31274 int max_cpu_num;
37116551Swh31274 /*
37126551Swh31274 * The parallel copy procedure is going to split some
37136551Swh31274 * of the elements of the original memory copy list.
37146551Swh31274 * The number of added elements can be up to
37156551Swh31274 * (max_cpu_num - 1). It means that max_cpu_num
37166551Swh31274 * should satisfy the following condition:
37176551Swh31274 * (max_cpu_num - 1) + mlist_size <= max_elms.
37186551Swh31274 */
37196551Swh31274 max_cpu_num = max_elms - mlist_size + 1;
37206551Swh31274
37211772Sjl139090 for (i = 0; i < NCPU; i++) {
37221772Sjl139090 if (CPU_IN_SET(cpu_ready_set, i) &&
37235037Sjl139090 CPU_ACTIVE(cpu[i])) {
37246551Swh31274 /*
37256551Swh31274 * To reduce the level-2 cache contention only
37266551Swh31274 * one strand per core will participate
37276551Swh31274 * in the copy. If the strand with even cpu_id
37286551Swh31274 * number is present in the ready set, we will
37296551Swh31274 * include this strand in the copy set. If it
37306551Swh31274 * is not present in the ready set, we check for
37316551Swh31274 * the strand with the consecutive odd cpu_id
37326551Swh31274 * and include it, provided that it is
37336551Swh31274 * present in the ready set.
37346551Swh31274 */
37356551Swh31274 if (!(i & 0x1) ||
37366551Swh31274 !CPU_IN_SET(prog->data->cpu_copy_set,
37376551Swh31274 i - 1)) {
37386551Swh31274 CPUSET_ADD(prog->data->cpu_copy_set, i);
37396551Swh31274 active_cpus++;
37406551Swh31274 /*
37416551Swh31274 * We cannot have more than
37426551Swh31274 * max_cpu_num CPUs in the copy
37436551Swh31274 * set, because each CPU has to
37446551Swh31274 * have at least one element
37456551Swh31274 * long memory copy list.
37466551Swh31274 */
37476551Swh31274 if (active_cpus >= max_cpu_num)
37486551Swh31274 break;
37496551Swh31274
37506551Swh31274 }
37511772Sjl139090 }
37521772Sjl139090 }
37531772Sjl139090 }
37541772Sjl139090
37551772Sjl139090 x_ml = c_ml;
37561772Sjl139090 sz = 0;
37571772Sjl139090 while (x_ml != NULL) {
3758*11474SJonathan.Adams@Sun.COM sz += x_ml->ml_size;
3759*11474SJonathan.Adams@Sun.COM x_ml = x_ml->ml_next;
37601772Sjl139090 }
37611772Sjl139090
37621772Sjl139090 copy_sz = sz/active_cpus;
37631772Sjl139090 copy_sz = roundup(copy_sz, MMU_PAGESIZE4M);
37641772Sjl139090
37651772Sjl139090 while (sz > copy_sz*active_cpus) {
37661772Sjl139090 copy_sz += MMU_PAGESIZE4M;
37671772Sjl139090 }
37681772Sjl139090
37691772Sjl139090 prog->data->stick_freq = system_clock_freq;
37701772Sjl139090 prog->data->copy_delay = ((copy_sz / min_copy_size_per_sec) + 2) *
37715037Sjl139090 system_clock_freq;
37721772Sjl139090
37731772Sjl139090 x_ml = c_ml;
3774*11474SJonathan.Adams@Sun.COM c_addr = x_ml->ml_address;
3775*11474SJonathan.Adams@Sun.COM c_size = x_ml->ml_size;
37761772Sjl139090
37771772Sjl139090 for (i = 0; i < NCPU; i++) {
37781772Sjl139090 prog->stat->nbytes[i] = 0;
37791772Sjl139090 if (!CPU_IN_SET(prog->data->cpu_copy_set, i)) {
37801772Sjl139090 continue;
37811772Sjl139090 }
37821772Sjl139090 sz = copy_sz;
37831772Sjl139090
37841772Sjl139090 while (sz) {
37851772Sjl139090 if (c_size > sz) {
37866551Swh31274 if ((prog->data->cpu_ml[i] =
37875037Sjl139090 drmach_memlist_add_span(prog,
37886551Swh31274 prog->data->cpu_ml[i],
37896551Swh31274 c_addr, sz)) == NULL) {
37906551Swh31274 cmn_err(CE_WARN,
37916551Swh31274 "Unexpected drmach_memlist_add_span"
37926551Swh31274 " failure.");
37936551Swh31274 err = drerr_new(1, EOPL_FMEM_SETUP,
37946551Swh31274 NULL);
37956551Swh31274 mc_resume();
37966551Swh31274 goto out;
37976551Swh31274 }
37981772Sjl139090 c_addr += sz;
37991772Sjl139090 c_size -= sz;
38001772Sjl139090 break;
38011772Sjl139090 } else {
38021772Sjl139090 sz -= c_size;
38036551Swh31274 if ((prog->data->cpu_ml[i] =
38045037Sjl139090 drmach_memlist_add_span(prog,
38056551Swh31274 prog->data->cpu_ml[i],
38066551Swh31274 c_addr, c_size)) == NULL) {
38076551Swh31274 cmn_err(CE_WARN,
38086551Swh31274 "Unexpected drmach_memlist_add_span"
38096551Swh31274 " failure.");
38106551Swh31274 err = drerr_new(1, EOPL_FMEM_SETUP,
38116551Swh31274 NULL);
38126551Swh31274 mc_resume();
38136551Swh31274 goto out;
38146551Swh31274 }
38156551Swh31274
3816*11474SJonathan.Adams@Sun.COM x_ml = x_ml->ml_next;
38171772Sjl139090 if (x_ml != NULL) {
3818*11474SJonathan.Adams@Sun.COM c_addr = x_ml->ml_address;
3819*11474SJonathan.Adams@Sun.COM c_size = x_ml->ml_size;
38201772Sjl139090 } else {
38211772Sjl139090 goto end;
38221772Sjl139090 }
38231772Sjl139090 }
38241772Sjl139090 }
38251772Sjl139090 }
38261772Sjl139090 end:
38271772Sjl139090 prog->data->s_copybasepa = s_copybasepa;
38281772Sjl139090 prog->data->t_copybasepa = t_copybasepa;
38291772Sjl139090 prog->data->c_ml = c_ml;
38303354Sjl139090 *pgm_id = prog_kmem;
38313354Sjl139090
38323354Sjl139090 /* Unmap the alternate space. It will have to be remapped again */
38333354Sjl139090 drmach_unlock_critical((caddr_t)prog);
38341772Sjl139090 return (NULL);
38356551Swh31274
38366551Swh31274 err_out:
38376551Swh31274 mc_resume();
38386551Swh31274 rv = (*prog->data->scf_fmem_cancel)();
38396551Swh31274 if (rv) {
38406551Swh31274 cmn_err(CE_WARN, "scf_fmem_cancel() failed rv=0x%x", rv);
38416551Swh31274 }
38423354Sjl139090 out:
38433354Sjl139090 if (prog != NULL) {
38443354Sjl139090 drmach_unlock_critical((caddr_t)prog);
38455037Sjl139090 vmem_free(heap_arena, prog, DRMACH_FMEM_LOCKED_PAGES *
38465037Sjl139090 PAGESIZE);
38473354Sjl139090 }
38483354Sjl139090 if (prog_kmem != NULL) {
38493354Sjl139090 kmem_free(prog_kmem, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE);
38503354Sjl139090 }
38513354Sjl139090 return (err);
38521772Sjl139090 }
38531772Sjl139090
38541772Sjl139090 sbd_error_t *
drmach_copy_rename_fini(drmachid_t id)38551772Sjl139090 drmach_copy_rename_fini(drmachid_t id)
38561772Sjl139090 {
38571772Sjl139090 drmach_copy_rename_program_t *prog = id;
38581772Sjl139090 sbd_error_t *err = NULL;
38591772Sjl139090 int rv;
38603712Sbm42561 uint_t fmem_error;
38611772Sjl139090
38621772Sjl139090 /*
38631772Sjl139090 * Note that we have to delay calling SCF to find out the
38641772Sjl139090 * status of the FMEM operation here because SCF cannot
38651772Sjl139090 * respond while it is suspended.
38661772Sjl139090 * This create a small window when we are sure about the
38671772Sjl139090 * base address of the system board.
38681772Sjl139090 * If there is any call to mc-opl to get memory unum,
38691772Sjl139090 * mc-opl will return UNKNOWN as the unum.
38701772Sjl139090 */
38711772Sjl139090
38723354Sjl139090 /*
38733354Sjl139090 * we have to remap again because all the pointer like data,
38743354Sjl139090 * critical in prog are based on the alternate vmem space.
38753354Sjl139090 */
38763354Sjl139090 (void) drmach_lock_critical((caddr_t)prog, (caddr_t)prog->locked_prog);
38773354Sjl139090
38781772Sjl139090 if (prog->data->c_ml != NULL)
38791772Sjl139090 memlist_delete(prog->data->c_ml);
38801772Sjl139090
38811772Sjl139090 if ((prog->data->fmem_status.op &
38825037Sjl139090 (OPL_FMEM_SCF_START | OPL_FMEM_MC_SUSPEND)) !=
38835037Sjl139090 (OPL_FMEM_SCF_START | OPL_FMEM_MC_SUSPEND)) {
38845037Sjl139090 cmn_err(CE_PANIC, "drmach_copy_rename_fini: invalid op "
38855037Sjl139090 "code %x\n", prog->data->fmem_status.op);
38861772Sjl139090 }
38871772Sjl139090
38883712Sbm42561 fmem_error = prog->data->fmem_status.error;
38893712Sbm42561 if (fmem_error != ESBD_NOERROR) {
38903712Sbm42561 err = drerr_new(1, fmem_error, NULL);
38913712Sbm42561 }
38923712Sbm42561
38931772Sjl139090 /* possible ops are SCF_START, MC_SUSPEND */
38941772Sjl139090 if (prog->critical->fmem_issued) {
38953712Sbm42561 if (fmem_error != ESBD_NOERROR) {
38965037Sjl139090 cmn_err(CE_PANIC, "Irrecoverable FMEM error %d\n",
38975037Sjl139090 fmem_error);
38983712Sbm42561 }
38991772Sjl139090 rv = (*prog->data->scf_fmem_end)();
39001772Sjl139090 if (rv) {
39013354Sjl139090 cmn_err(CE_PANIC, "scf_fmem_end() failed rv=%d", rv);
39021772Sjl139090 }
39031772Sjl139090 /*
39041772Sjl139090 * If we get here, rename is successful.
39051772Sjl139090 * Do all the copy rename post processing.
39061772Sjl139090 */
39071772Sjl139090 drmach_swap_pa((drmach_mem_t *)prog->data->s_mem,
39085037Sjl139090 (drmach_mem_t *)prog->data->t_mem);
39091772Sjl139090 } else {
39101772Sjl139090 rv = (*prog->data->scf_fmem_cancel)();
39111772Sjl139090 if (rv) {
39125037Sjl139090 cmn_err(CE_WARN, "scf_fmem_cancel() failed rv=0x%x",
39135037Sjl139090 rv);
39145037Sjl139090 if (!err) {
39155037Sjl139090 err = drerr_new(1, EOPL_SCF_FMEM_CANCEL,
39165037Sjl139090 "scf_fmem_cancel() failed. rv = 0x%x", rv);
39175037Sjl139090 }
39181772Sjl139090 }
39191772Sjl139090 }
39201772Sjl139090 /* soft resume mac patrol */
39211772Sjl139090 (*prog->data->mc_resume)();
39221772Sjl139090
39233354Sjl139090 drmach_unlock_critical((caddr_t)prog->locked_prog);
39243354Sjl139090
39253354Sjl139090 vmem_free(heap_arena, prog->locked_prog,
39265037Sjl139090 DRMACH_FMEM_LOCKED_PAGES * PAGESIZE);
39271772Sjl139090 kmem_free(prog, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE);
39281772Sjl139090 return (err);
39291772Sjl139090 }
39301772Sjl139090
39311772Sjl139090 /*ARGSUSED*/
39321772Sjl139090 static void
drmach_copy_rename_slave(struct regs * rp,drmachid_t id)39331772Sjl139090 drmach_copy_rename_slave(struct regs *rp, drmachid_t id)
39341772Sjl139090 {
39353354Sjl139090 drmach_copy_rename_program_t *prog =
39365037Sjl139090 (drmach_copy_rename_program_t *)id;
39371772Sjl139090 register int cpuid;
39381772Sjl139090 extern void drmach_flush();
39391772Sjl139090 extern void membar_sync_il();
39401772Sjl139090 extern void drmach_flush_icache();
39411772Sjl139090 on_trap_data_t otd;
39421772Sjl139090
39431772Sjl139090 cpuid = CPU->cpu_id;
39441772Sjl139090
39451772Sjl139090 if (on_trap(&otd, OT_DATA_EC)) {
39461772Sjl139090 no_trap();
39473712Sbm42561 prog->data->error[cpuid] = EOPL_FMEM_COPY_ERROR;
39481772Sjl139090 prog->critical->stat[cpuid] = FMEM_LOOP_EXIT;
39493354Sjl139090 drmach_flush_icache();
39503354Sjl139090 membar_sync_il();
39511772Sjl139090 return;
39521772Sjl139090 }
39531772Sjl139090
39541772Sjl139090
39551772Sjl139090 /*
39561772Sjl139090 * jmp drmach_copy_rename_prog().
39571772Sjl139090 */
39581772Sjl139090
39591772Sjl139090 drmach_flush(prog->critical, PAGESIZE);
39601772Sjl139090 (void) prog->critical->run(prog, cpuid);
39611772Sjl139090 drmach_flush_icache();
39621772Sjl139090
39631772Sjl139090 no_trap();
39641772Sjl139090
39651772Sjl139090 prog->critical->stat[cpuid] = FMEM_LOOP_EXIT;
39663354Sjl139090
39671772Sjl139090 membar_sync_il();
39681772Sjl139090 }
39691772Sjl139090
39701772Sjl139090 static void
drmach_swap_pa(drmach_mem_t * s_mem,drmach_mem_t * t_mem)39711772Sjl139090 drmach_swap_pa(drmach_mem_t *s_mem, drmach_mem_t *t_mem)
39721772Sjl139090 {
39731772Sjl139090 uint64_t s_base, t_base;
39741772Sjl139090 drmach_board_t *s_board, *t_board;
39751772Sjl139090 struct memlist *ml;
39761772Sjl139090
39771772Sjl139090 s_board = s_mem->dev.bp;
39781772Sjl139090 t_board = t_mem->dev.bp;
39791772Sjl139090 if (s_board == NULL || t_board == NULL) {
39801772Sjl139090 cmn_err(CE_PANIC, "Cannot locate source or target board\n");
39811772Sjl139090 return;
39821772Sjl139090 }
39831772Sjl139090 s_base = s_mem->slice_base;
39841772Sjl139090 t_base = t_mem->slice_base;
39851772Sjl139090
39861772Sjl139090 s_mem->slice_base = t_base;
39871772Sjl139090 s_mem->base_pa = (s_mem->base_pa - s_base) + t_base;
39881772Sjl139090
3989*11474SJonathan.Adams@Sun.COM for (ml = s_mem->memlist; ml; ml = ml->ml_next) {
3990*11474SJonathan.Adams@Sun.COM ml->ml_address = ml->ml_address - s_base + t_base;
39911772Sjl139090 }
39921772Sjl139090
39931772Sjl139090 t_mem->slice_base = s_base;
39941772Sjl139090 t_mem->base_pa = (t_mem->base_pa - t_base) + s_base;
39951772Sjl139090
3996*11474SJonathan.Adams@Sun.COM for (ml = t_mem->memlist; ml; ml = ml->ml_next) {
3997*11474SJonathan.Adams@Sun.COM ml->ml_address = ml->ml_address - t_base + s_base;
39981772Sjl139090 }
39991772Sjl139090
40001772Sjl139090 /*
40011772Sjl139090 * IKP has to update the sb-mem-ranges for mac patrol driver
40021772Sjl139090 * when it resumes, it will re-read the sb-mem-range property
40031772Sjl139090 * to get the new base address
40041772Sjl139090 */
40051772Sjl139090 if (oplcfg_pa_swap(s_board->bnum, t_board->bnum) != 0)
40061772Sjl139090 cmn_err(CE_PANIC, "Could not update device nodes\n");
40071772Sjl139090 }
40081772Sjl139090
40091772Sjl139090 void
drmach_copy_rename(drmachid_t id)40101772Sjl139090 drmach_copy_rename(drmachid_t id)
40111772Sjl139090 {
40123354Sjl139090 drmach_copy_rename_program_t *prog_kmem = id;
40133354Sjl139090 drmach_copy_rename_program_t *prog;
40141772Sjl139090 cpuset_t cpuset;
40151772Sjl139090 int cpuid;
40161772Sjl139090 uint64_t inst;
40171772Sjl139090 register int rtn;
40181772Sjl139090 extern int in_sync;
40191772Sjl139090 int old_in_sync;
40201772Sjl139090 extern void drmach_sys_trap();
40211772Sjl139090 extern void drmach_flush();
40221772Sjl139090 extern void drmach_flush_icache();
40231772Sjl139090 extern uint64_t patch_inst(uint64_t *, uint64_t);
40241772Sjl139090 on_trap_data_t otd;
40251772Sjl139090
40263400Sbm42561
40273354Sjl139090 prog = prog_kmem->locked_prog;
40283354Sjl139090
40293400Sbm42561
40303354Sjl139090 /*
40313354Sjl139090 * We must immediately drop in the TLB because all pointers
40323354Sjl139090 * are based on the alternate vmem space.
40333354Sjl139090 */
40343354Sjl139090
40353354Sjl139090 (void) drmach_lock_critical((caddr_t)prog_kmem, (caddr_t)prog);
40363354Sjl139090
40373354Sjl139090 /*
40383354Sjl139090 * we call scf to get the base address here becuase if scf
40393354Sjl139090 * has not been suspended yet, the active path can be changing and
40403354Sjl139090 * sometimes it is not even mapped. We call the interface when
40413354Sjl139090 * the OS has been quiesced.
40423354Sjl139090 */
40433354Sjl139090 prog->critical->scf_reg_base = (*prog->data->scf_get_base_addr)();
40443354Sjl139090
40453354Sjl139090 if (prog->critical->scf_reg_base == (uint64_t)-1 ||
40465037Sjl139090 prog->critical->scf_reg_base == NULL) {
40473712Sbm42561 prog->data->fmem_status.error = EOPL_FMEM_SCF_ERR;
40483354Sjl139090 drmach_unlock_critical((caddr_t)prog);
40491772Sjl139090 return;
40501772Sjl139090 }
40511772Sjl139090
40521772Sjl139090 cpuset = prog->data->cpu_ready_set;
40531772Sjl139090
40541772Sjl139090 for (cpuid = 0; cpuid < NCPU; cpuid++) {
40551772Sjl139090 if (CPU_IN_SET(cpuset, cpuid)) {
40561772Sjl139090 prog->critical->stat[cpuid] = FMEM_LOOP_START;
40573712Sbm42561 prog->data->error[cpuid] = ESBD_NOERROR;
40581772Sjl139090 }
40591772Sjl139090 }
40601772Sjl139090
40611772Sjl139090 old_in_sync = in_sync;
40621772Sjl139090 in_sync = 1;
40631772Sjl139090 cpuid = CPU->cpu_id;
40641772Sjl139090
40651772Sjl139090 CPUSET_DEL(cpuset, cpuid);
40661772Sjl139090
40673354Sjl139090 for (cpuid = 0; cpuid < NCPU; cpuid++) {
40683354Sjl139090 if (CPU_IN_SET(cpuset, cpuid)) {
40693354Sjl139090 xc_one(cpuid, (xcfunc_t *)drmach_lock_critical,
40705037Sjl139090 (uint64_t)prog_kmem, (uint64_t)prog);
40713354Sjl139090 }
40723354Sjl139090 }
40733354Sjl139090
40743354Sjl139090 cpuid = CPU->cpu_id;
40751772Sjl139090
40761772Sjl139090 xt_some(cpuset, (xcfunc_t *)drmach_sys_trap,
40775037Sjl139090 (uint64_t)drmach_copy_rename_slave, (uint64_t)prog);
40781772Sjl139090 xt_sync(cpuset);
40791772Sjl139090
40801772Sjl139090 if (on_trap(&otd, OT_DATA_EC)) {
40813712Sbm42561 rtn = EOPL_FMEM_COPY_ERROR;
40823354Sjl139090 drmach_flush_icache();
40831772Sjl139090 goto done;
40841772Sjl139090 }
40851772Sjl139090
40861772Sjl139090 /*
40871772Sjl139090 * jmp drmach_copy_rename_prog().
40881772Sjl139090 */
40893400Sbm42561
40901772Sjl139090 drmach_flush(prog->critical, PAGESIZE);
40911772Sjl139090 rtn = prog->critical->run(prog, cpuid);
40925037Sjl139090
40931772Sjl139090 drmach_flush_icache();
40941772Sjl139090
40951772Sjl139090
40961772Sjl139090 done:
40971772Sjl139090 no_trap();
40983712Sbm42561 if (rtn == EOPL_FMEM_HW_ERROR) {
40991772Sjl139090 kpreempt_enable();
41005037Sjl139090 prom_panic("URGENT_ERROR_TRAP is detected during FMEM.\n");
41011772Sjl139090 }
41021772Sjl139090
41031772Sjl139090 /*
41041772Sjl139090 * In normal case, all slave CPU's are still spinning in
41051772Sjl139090 * the assembly code. The master has to patch the instruction
41061772Sjl139090 * to get them out.
41071772Sjl139090 * In error case, e.g. COPY_ERROR, some slave CPU's might
41081772Sjl139090 * have aborted and already returned and sset LOOP_EXIT status.
41091772Sjl139090 * Some CPU might still be copying.
41101772Sjl139090 * In any case, some delay is necessary to give them
41111772Sjl139090 * enough time to set the LOOP_EXIT status.
41121772Sjl139090 */
41131772Sjl139090
41141772Sjl139090 for (;;) {
41151772Sjl139090 inst = patch_inst((uint64_t *)prog->critical->loop_rtn,
41165037Sjl139090 prog->critical->inst_loop_ret);
41171772Sjl139090 if (prog->critical->inst_loop_ret == inst) {
41181772Sjl139090 break;
41191772Sjl139090 }
41201772Sjl139090 }
41211772Sjl139090
41221772Sjl139090 for (cpuid = 0; cpuid < NCPU; cpuid++) {
41231772Sjl139090 uint64_t last, now;
41241772Sjl139090 if (!CPU_IN_SET(cpuset, cpuid)) {
41251772Sjl139090 continue;
41261772Sjl139090 }
41271772Sjl139090 last = prog->stat->nbytes[cpuid];
41281772Sjl139090 /*
41291772Sjl139090 * Wait for all CPU to exit.
41301772Sjl139090 * However we do not want an infinite loop
41311772Sjl139090 * so we detect hangup situation here.
41321772Sjl139090 * If the slave CPU is still copying data,
41331772Sjl139090 * we will continue to wait.
41341772Sjl139090 * In error cases, the master has already set
41351772Sjl139090 * fmem_status.error to abort the copying.
41361772Sjl139090 * 1 m.s delay for them to abort copying and
41371772Sjl139090 * return to drmach_copy_rename_slave to set
41381772Sjl139090 * FMEM_LOOP_EXIT status should be enough.
41391772Sjl139090 */
41401772Sjl139090 for (;;) {
41411772Sjl139090 if (prog->critical->stat[cpuid] == FMEM_LOOP_EXIT)
41421772Sjl139090 break;
41431772Sjl139090 drmach_sleep_il();
41441772Sjl139090 drv_usecwait(1000);
41451772Sjl139090 now = prog->stat->nbytes[cpuid];
41461772Sjl139090 if (now <= last) {
41475037Sjl139090 drv_usecwait(1000);
41485037Sjl139090 if (prog->critical->stat[cpuid] ==
41495037Sjl139090 FMEM_LOOP_EXIT)
41505037Sjl139090 break;
41515037Sjl139090 cmn_err(CE_PANIC, "CPU %d hang during Copy "
41525037Sjl139090 "Rename", cpuid);
41531772Sjl139090 }
41541772Sjl139090 last = now;
41551772Sjl139090 }
41563712Sbm42561 if (prog->data->error[cpuid] == EOPL_FMEM_HW_ERROR) {
41575037Sjl139090 prom_panic("URGENT_ERROR_TRAP is detected during "
41585037Sjl139090 "FMEM.\n");
41591772Sjl139090 }
41601772Sjl139090 }
41613354Sjl139090
41623354Sjl139090 /*
41633354Sjl139090 * This must be done after all strands have exit.
41643354Sjl139090 * Removing the TLB entry will affect both strands
41653354Sjl139090 * in the same core.
41663354Sjl139090 */
41673354Sjl139090
41683354Sjl139090 for (cpuid = 0; cpuid < NCPU; cpuid++) {
41693354Sjl139090 if (CPU_IN_SET(cpuset, cpuid)) {
41703354Sjl139090 xc_one(cpuid, (xcfunc_t *)drmach_unlock_critical,
41715037Sjl139090 (uint64_t)prog, 0);
41723354Sjl139090 }
41733354Sjl139090 }
41741772Sjl139090
41751772Sjl139090 in_sync = old_in_sync;
41761772Sjl139090
41773354Sjl139090 /*
41783354Sjl139090 * we should unlock before the following lock to keep the kpreempt
41793354Sjl139090 * count correct.
41803354Sjl139090 */
41813354Sjl139090 (void) drmach_unlock_critical((caddr_t)prog);
41823354Sjl139090
41833354Sjl139090 /*
41843354Sjl139090 * we must remap again. TLB might have been removed in above xcall.
41853354Sjl139090 */
41863354Sjl139090
41873354Sjl139090 (void) drmach_lock_critical((caddr_t)prog_kmem, (caddr_t)prog);
41883354Sjl139090
41893712Sbm42561 if (prog->data->fmem_status.error == ESBD_NOERROR)
41901772Sjl139090 prog->data->fmem_status.error = rtn;
41911772Sjl139090
41921772Sjl139090 if (prog->data->copy_wait_time > 0) {
41931772Sjl139090 DRMACH_PR("Unexpected long wait time %ld seconds "
41945037Sjl139090 "during copy rename on CPU %d\n",
41955037Sjl139090 prog->data->copy_wait_time/prog->data->stick_freq,
41965037Sjl139090 prog->data->slowest_cpuid);
41971772Sjl139090 }
41983354Sjl139090 drmach_unlock_critical((caddr_t)prog);
41991772Sjl139090 }
4200