125cf1a30Sjl139090 /* 225cf1a30Sjl139090 * CDDL HEADER START 325cf1a30Sjl139090 * 425cf1a30Sjl139090 * The contents of this file are subject to the terms of the 525cf1a30Sjl139090 * Common Development and Distribution License (the "License"). 625cf1a30Sjl139090 * You may not use this file except in compliance with the License. 725cf1a30Sjl139090 * 825cf1a30Sjl139090 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 925cf1a30Sjl139090 * or http://www.opensolaris.org/os/licensing. 1025cf1a30Sjl139090 * See the License for the specific language governing permissions 1125cf1a30Sjl139090 * and limitations under the License. 1225cf1a30Sjl139090 * 1325cf1a30Sjl139090 * When distributing Covered Code, include this CDDL HEADER in each 1425cf1a30Sjl139090 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1525cf1a30Sjl139090 * If applicable, add the following below this CDDL HEADER, with the 1625cf1a30Sjl139090 * fields enclosed by brackets "[]" replaced with your own identifying 1725cf1a30Sjl139090 * information: Portions Copyright [yyyy] [name of copyright owner] 1825cf1a30Sjl139090 * 1925cf1a30Sjl139090 * CDDL HEADER END 2025cf1a30Sjl139090 */ 2107d06da5SSurya Prakki 2225cf1a30Sjl139090 /* 2356f33205SJonathan Adams * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 2425cf1a30Sjl139090 * Use is subject to license terms. 2525cf1a30Sjl139090 */ 2625cf1a30Sjl139090 2725cf1a30Sjl139090 #include <sys/debug.h> 2825cf1a30Sjl139090 #include <sys/types.h> 2925cf1a30Sjl139090 #include <sys/varargs.h> 3025cf1a30Sjl139090 #include <sys/errno.h> 3125cf1a30Sjl139090 #include <sys/cred.h> 3225cf1a30Sjl139090 #include <sys/dditypes.h> 3325cf1a30Sjl139090 #include <sys/devops.h> 3425cf1a30Sjl139090 #include <sys/modctl.h> 3525cf1a30Sjl139090 #include <sys/poll.h> 3625cf1a30Sjl139090 #include <sys/conf.h> 3725cf1a30Sjl139090 #include <sys/ddi.h> 3825cf1a30Sjl139090 #include <sys/sunddi.h> 3925cf1a30Sjl139090 #include <sys/sunndi.h> 4025cf1a30Sjl139090 #include <sys/ndi_impldefs.h> 4125cf1a30Sjl139090 #include <sys/stat.h> 4225cf1a30Sjl139090 #include <sys/kmem.h> 4325cf1a30Sjl139090 #include <sys/vmem.h> 4425cf1a30Sjl139090 #include <sys/opl_olympus_regs.h> 4525cf1a30Sjl139090 #include <sys/cpuvar.h> 4625cf1a30Sjl139090 #include <sys/cpupart.h> 4725cf1a30Sjl139090 #include <sys/mem_config.h> 4825cf1a30Sjl139090 #include <sys/ddi_impldefs.h> 4925cf1a30Sjl139090 #include <sys/systm.h> 5025cf1a30Sjl139090 #include <sys/machsystm.h> 5125cf1a30Sjl139090 #include <sys/autoconf.h> 5225cf1a30Sjl139090 #include <sys/cmn_err.h> 5325cf1a30Sjl139090 #include <sys/sysmacros.h> 5425cf1a30Sjl139090 #include <sys/x_call.h> 5525cf1a30Sjl139090 #include <sys/promif.h> 5625cf1a30Sjl139090 #include <sys/prom_plat.h> 5725cf1a30Sjl139090 #include <sys/membar.h> 5825cf1a30Sjl139090 #include <vm/seg_kmem.h> 5925cf1a30Sjl139090 #include <sys/mem_cage.h> 6025cf1a30Sjl139090 #include <sys/stack.h> 6125cf1a30Sjl139090 #include <sys/archsystm.h> 6225cf1a30Sjl139090 #include <vm/hat_sfmmu.h> 6325cf1a30Sjl139090 #include <sys/pte.h> 6425cf1a30Sjl139090 #include <sys/mmu.h> 6525cf1a30Sjl139090 #include <sys/cpu_module.h> 6625cf1a30Sjl139090 #include <sys/obpdefs.h> 6725cf1a30Sjl139090 #include <sys/note.h> 6825cf1a30Sjl139090 #include <sys/ontrap.h> 6925cf1a30Sjl139090 #include <sys/cpu_sgnblk_defs.h> 7025cf1a30Sjl139090 #include <sys/opl.h> 71e98fafb9Sjl139090 #include <sys/cpu_impl.h> 7225cf1a30Sjl139090 7325cf1a30Sjl139090 7425cf1a30Sjl139090 #include <sys/promimpl.h> 7525cf1a30Sjl139090 #include <sys/prom_plat.h> 7625cf1a30Sjl139090 #include <sys/kobj.h> 7725cf1a30Sjl139090 7825cf1a30Sjl139090 #include <sys/sysevent.h> 7925cf1a30Sjl139090 #include <sys/sysevent/dr.h> 8025cf1a30Sjl139090 #include <sys/sysevent/eventdefs.h> 8125cf1a30Sjl139090 8225cf1a30Sjl139090 #include <sys/drmach.h> 8325cf1a30Sjl139090 #include <sys/dr_util.h> 8425cf1a30Sjl139090 8525cf1a30Sjl139090 #include <sys/fcode.h> 8625cf1a30Sjl139090 #include <sys/opl_cfg.h> 8725cf1a30Sjl139090 8825cf1a30Sjl139090 extern void bcopy32_il(uint64_t, uint64_t); 8925cf1a30Sjl139090 extern void flush_cache_il(void); 9025cf1a30Sjl139090 extern void drmach_sleep_il(void); 9125cf1a30Sjl139090 9225cf1a30Sjl139090 typedef struct { 9325cf1a30Sjl139090 struct drmach_node *node; 9425cf1a30Sjl139090 void *data; 9525cf1a30Sjl139090 } drmach_node_walk_args_t; 9625cf1a30Sjl139090 9725cf1a30Sjl139090 typedef struct drmach_node { 9825cf1a30Sjl139090 void *here; 9925cf1a30Sjl139090 10025cf1a30Sjl139090 pnode_t (*get_dnode)(struct drmach_node *node); 10125cf1a30Sjl139090 int (*walk)(struct drmach_node *node, void *data, 10225cf1a30Sjl139090 int (*cb)(drmach_node_walk_args_t *args)); 10325cf1a30Sjl139090 dev_info_t *(*n_getdip)(struct drmach_node *node); 10425cf1a30Sjl139090 int (*n_getproplen)(struct drmach_node *node, char *name, 10525cf1a30Sjl139090 int *len); 10625cf1a30Sjl139090 int (*n_getprop)(struct drmach_node *node, char *name, 10725cf1a30Sjl139090 void *buf, int len); 10825cf1a30Sjl139090 int (*get_parent)(struct drmach_node *node, 10925cf1a30Sjl139090 struct drmach_node *pnode); 11025cf1a30Sjl139090 } drmach_node_t; 11125cf1a30Sjl139090 11225cf1a30Sjl139090 typedef struct { 11325cf1a30Sjl139090 int min_index; 11425cf1a30Sjl139090 int max_index; 11525cf1a30Sjl139090 int arr_sz; 11625cf1a30Sjl139090 drmachid_t *arr; 11725cf1a30Sjl139090 } drmach_array_t; 11825cf1a30Sjl139090 11925cf1a30Sjl139090 typedef struct { 12025cf1a30Sjl139090 void *isa; 12125cf1a30Sjl139090 12225cf1a30Sjl139090 void (*dispose)(drmachid_t); 12325cf1a30Sjl139090 sbd_error_t *(*release)(drmachid_t); 12425cf1a30Sjl139090 sbd_error_t *(*status)(drmachid_t, drmach_status_t *); 12525cf1a30Sjl139090 12625cf1a30Sjl139090 char name[MAXNAMELEN]; 12725cf1a30Sjl139090 } drmach_common_t; 12825cf1a30Sjl139090 12925cf1a30Sjl139090 typedef struct { 13025cf1a30Sjl139090 uint32_t core_present; 13125cf1a30Sjl139090 uint32_t core_hotadded; 13225cf1a30Sjl139090 uint32_t core_started; 13325cf1a30Sjl139090 } drmach_cmp_t; 13425cf1a30Sjl139090 13525cf1a30Sjl139090 typedef struct { 13625cf1a30Sjl139090 drmach_common_t cm; 13725cf1a30Sjl139090 int bnum; 13825cf1a30Sjl139090 int assigned; 13925cf1a30Sjl139090 int powered; 14025cf1a30Sjl139090 int connected; 14125cf1a30Sjl139090 int cond; 14225cf1a30Sjl139090 drmach_node_t *tree; 14325cf1a30Sjl139090 drmach_array_t *devices; 14425cf1a30Sjl139090 int boot_board; /* if board exists on bootup */ 14525cf1a30Sjl139090 drmach_cmp_t cores[OPL_MAX_COREID_PER_BOARD]; 14625cf1a30Sjl139090 } drmach_board_t; 14725cf1a30Sjl139090 14825cf1a30Sjl139090 typedef struct { 14925cf1a30Sjl139090 drmach_common_t cm; 15025cf1a30Sjl139090 drmach_board_t *bp; 15125cf1a30Sjl139090 int unum; 15225cf1a30Sjl139090 int portid; 15325cf1a30Sjl139090 int busy; 15425cf1a30Sjl139090 int powered; 15525cf1a30Sjl139090 const char *type; 15625cf1a30Sjl139090 drmach_node_t *node; 15725cf1a30Sjl139090 } drmach_device_t; 15825cf1a30Sjl139090 15925cf1a30Sjl139090 typedef struct drmach_cpu { 16025cf1a30Sjl139090 drmach_device_t dev; 16125cf1a30Sjl139090 processorid_t cpuid; 16225cf1a30Sjl139090 int sb; 16325cf1a30Sjl139090 int chipid; 16425cf1a30Sjl139090 int coreid; 16525cf1a30Sjl139090 int strandid; 16625cf1a30Sjl139090 int status; 16725cf1a30Sjl139090 #define OPL_CPU_HOTADDED 1 16825cf1a30Sjl139090 } drmach_cpu_t; 16925cf1a30Sjl139090 17025cf1a30Sjl139090 typedef struct drmach_mem { 17125cf1a30Sjl139090 drmach_device_t dev; 17225cf1a30Sjl139090 uint64_t slice_base; 17325cf1a30Sjl139090 uint64_t slice_size; 17425cf1a30Sjl139090 uint64_t base_pa; /* lowest installed memory base */ 17525cf1a30Sjl139090 uint64_t nbytes; /* size of installed memory */ 17625cf1a30Sjl139090 struct memlist *memlist; 17725cf1a30Sjl139090 } drmach_mem_t; 17825cf1a30Sjl139090 17925cf1a30Sjl139090 typedef struct drmach_io { 18025cf1a30Sjl139090 drmach_device_t dev; 18125cf1a30Sjl139090 int channel; 18225cf1a30Sjl139090 int leaf; 18325cf1a30Sjl139090 } drmach_io_t; 18425cf1a30Sjl139090 18525cf1a30Sjl139090 typedef struct drmach_domain_info { 18625cf1a30Sjl139090 uint32_t floating; 18725cf1a30Sjl139090 int allow_dr; 18825cf1a30Sjl139090 } drmach_domain_info_t; 18925cf1a30Sjl139090 19025cf1a30Sjl139090 drmach_domain_info_t drmach_domain; 19125cf1a30Sjl139090 19225cf1a30Sjl139090 typedef struct { 19325cf1a30Sjl139090 int flags; 19425cf1a30Sjl139090 drmach_device_t *dp; 19525cf1a30Sjl139090 sbd_error_t *err; 19625cf1a30Sjl139090 dev_info_t *dip; 19725cf1a30Sjl139090 } drmach_config_args_t; 19825cf1a30Sjl139090 19925cf1a30Sjl139090 typedef struct { 20025cf1a30Sjl139090 drmach_board_t *obj; 20125cf1a30Sjl139090 int ndevs; 20225cf1a30Sjl139090 void *a; 20325cf1a30Sjl139090 sbd_error_t *(*found)(void *a, const char *, int, drmachid_t); 20425cf1a30Sjl139090 sbd_error_t *err; 20525cf1a30Sjl139090 } drmach_board_cb_data_t; 20625cf1a30Sjl139090 20725cf1a30Sjl139090 static drmach_array_t *drmach_boards; 20825cf1a30Sjl139090 20925cf1a30Sjl139090 static sbd_error_t *drmach_device_new(drmach_node_t *, 21025cf1a30Sjl139090 drmach_board_t *, int, drmachid_t *); 21125cf1a30Sjl139090 static sbd_error_t *drmach_cpu_new(drmach_device_t *, drmachid_t *); 21225cf1a30Sjl139090 static sbd_error_t *drmach_mem_new(drmach_device_t *, drmachid_t *); 21325cf1a30Sjl139090 static sbd_error_t *drmach_io_new(drmach_device_t *, drmachid_t *); 21425cf1a30Sjl139090 21525cf1a30Sjl139090 static dev_info_t *drmach_node_ddi_get_dip(drmach_node_t *np); 21625cf1a30Sjl139090 static int drmach_node_ddi_get_prop(drmach_node_t *np, 21725cf1a30Sjl139090 char *name, void *buf, int len); 21825cf1a30Sjl139090 static int drmach_node_ddi_get_proplen(drmach_node_t *np, 21925cf1a30Sjl139090 char *name, int *len); 22025cf1a30Sjl139090 22125cf1a30Sjl139090 static int drmach_get_portid(drmach_node_t *); 22225cf1a30Sjl139090 static sbd_error_t *drmach_i_status(drmachid_t, drmach_status_t *); 22325cf1a30Sjl139090 static int opl_check_dr_status(); 22425cf1a30Sjl139090 static void drmach_io_dispose(drmachid_t); 22525cf1a30Sjl139090 static sbd_error_t *drmach_io_release(drmachid_t); 22625cf1a30Sjl139090 static sbd_error_t *drmach_io_status(drmachid_t, drmach_status_t *); 22725cf1a30Sjl139090 static int drmach_init(void); 22825cf1a30Sjl139090 static void drmach_fini(void); 22925cf1a30Sjl139090 static void drmach_swap_pa(drmach_mem_t *, drmach_mem_t *); 23025cf1a30Sjl139090 static drmach_board_t *drmach_get_board_by_bnum(int); 23125cf1a30Sjl139090 232*8682d1efSRichard Lowe static sbd_error_t *drmach_board_release(drmachid_t); 233*8682d1efSRichard Lowe static sbd_error_t *drmach_board_status(drmachid_t, drmach_status_t *); 234*8682d1efSRichard Lowe static void drmach_cpu_dispose(drmachid_t); 235*8682d1efSRichard Lowe static sbd_error_t *drmach_cpu_release(drmachid_t); 236*8682d1efSRichard Lowe static sbd_error_t *drmach_cpu_status(drmachid_t, drmach_status_t *); 237*8682d1efSRichard Lowe static void drmach_mem_dispose(drmachid_t); 238*8682d1efSRichard Lowe static sbd_error_t *drmach_mem_release(drmachid_t); 239*8682d1efSRichard Lowe static sbd_error_t *drmach_mem_status(drmachid_t, drmach_status_t *); 240*8682d1efSRichard Lowe 24125cf1a30Sjl139090 /* options for the second argument in drmach_add_remove_cpu() */ 24225cf1a30Sjl139090 #define HOTADD_CPU 1 24325cf1a30Sjl139090 #define HOTREMOVE_CPU 2 24425cf1a30Sjl139090 24525cf1a30Sjl139090 #define ON_BOARD_CORE_NUM(x) (((uint_t)(x) / OPL_MAX_STRANDID_PER_CORE) & \ 24625cf1a30Sjl139090 (OPL_MAX_COREID_PER_BOARD - 1)) 24725cf1a30Sjl139090 24825cf1a30Sjl139090 extern struct cpu *SIGBCPU; 24925cf1a30Sjl139090 25025cf1a30Sjl139090 static int drmach_name2type_idx(char *); 25125cf1a30Sjl139090 static drmach_board_t *drmach_board_new(int, int); 25225cf1a30Sjl139090 25325cf1a30Sjl139090 #ifdef DEBUG 25425cf1a30Sjl139090 25525cf1a30Sjl139090 #define DRMACH_PR if (drmach_debug) printf 25625cf1a30Sjl139090 int drmach_debug = 1; /* set to non-zero to enable debug messages */ 25725cf1a30Sjl139090 #else 25825cf1a30Sjl139090 25925cf1a30Sjl139090 #define DRMACH_PR _NOTE(CONSTANTCONDITION) if (0) printf 26025cf1a30Sjl139090 #endif /* DEBUG */ 26125cf1a30Sjl139090 26225cf1a30Sjl139090 26325cf1a30Sjl139090 #define DRMACH_OBJ(id) ((drmach_common_t *)id) 26425cf1a30Sjl139090 265ddf95635Sbm42561 #define DRMACH_NULL_ID(id) ((id) == 0) 266ddf95635Sbm42561 26725cf1a30Sjl139090 #define DRMACH_IS_BOARD_ID(id) \ 26825cf1a30Sjl139090 ((id != 0) && \ 26925cf1a30Sjl139090 (DRMACH_OBJ(id)->isa == (void *)drmach_board_new)) 27025cf1a30Sjl139090 27125cf1a30Sjl139090 #define DRMACH_IS_CPU_ID(id) \ 27225cf1a30Sjl139090 ((id != 0) && \ 27325cf1a30Sjl139090 (DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new)) 27425cf1a30Sjl139090 27525cf1a30Sjl139090 #define DRMACH_IS_MEM_ID(id) \ 27625cf1a30Sjl139090 ((id != 0) && \ 27725cf1a30Sjl139090 (DRMACH_OBJ(id)->isa == (void *)drmach_mem_new)) 27825cf1a30Sjl139090 27925cf1a30Sjl139090 #define DRMACH_IS_IO_ID(id) \ 28025cf1a30Sjl139090 ((id != 0) && \ 28125cf1a30Sjl139090 (DRMACH_OBJ(id)->isa == (void *)drmach_io_new)) 28225cf1a30Sjl139090 28325cf1a30Sjl139090 #define DRMACH_IS_DEVICE_ID(id) \ 28425cf1a30Sjl139090 ((id != 0) && \ 28525cf1a30Sjl139090 (DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new || \ 28625cf1a30Sjl139090 DRMACH_OBJ(id)->isa == (void *)drmach_mem_new || \ 28725cf1a30Sjl139090 DRMACH_OBJ(id)->isa == (void *)drmach_io_new)) 28825cf1a30Sjl139090 28925cf1a30Sjl139090 #define DRMACH_IS_ID(id) \ 29025cf1a30Sjl139090 ((id != 0) && \ 29125cf1a30Sjl139090 (DRMACH_OBJ(id)->isa == (void *)drmach_board_new || \ 29225cf1a30Sjl139090 DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new || \ 29325cf1a30Sjl139090 DRMACH_OBJ(id)->isa == (void *)drmach_mem_new || \ 29425cf1a30Sjl139090 DRMACH_OBJ(id)->isa == (void *)drmach_io_new)) 29525cf1a30Sjl139090 29625cf1a30Sjl139090 #define DRMACH_INTERNAL_ERROR() \ 29725cf1a30Sjl139090 drerr_new(1, EOPL_INTERNAL, drmach_ie_fmt, __LINE__) 29825cf1a30Sjl139090 29925cf1a30Sjl139090 static char *drmach_ie_fmt = "drmach.c %d"; 30025cf1a30Sjl139090 30125cf1a30Sjl139090 static struct { 30225cf1a30Sjl139090 const char *name; 30325cf1a30Sjl139090 const char *type; 30425cf1a30Sjl139090 sbd_error_t *(*new)(drmach_device_t *, drmachid_t *); 30525cf1a30Sjl139090 } drmach_name2type[] = { 30625cf1a30Sjl139090 { "cpu", DRMACH_DEVTYPE_CPU, drmach_cpu_new }, 30725cf1a30Sjl139090 { "pseudo-mc", DRMACH_DEVTYPE_MEM, drmach_mem_new }, 30825cf1a30Sjl139090 { "pci", DRMACH_DEVTYPE_PCI, drmach_io_new }, 30925cf1a30Sjl139090 }; 31025cf1a30Sjl139090 31125cf1a30Sjl139090 /* utility */ 31225cf1a30Sjl139090 #define MBYTE (1048576ull) 31325cf1a30Sjl139090 31425cf1a30Sjl139090 /* 31525cf1a30Sjl139090 * drmach autoconfiguration data structures and interfaces 31625cf1a30Sjl139090 */ 31725cf1a30Sjl139090 31825cf1a30Sjl139090 extern struct mod_ops mod_miscops; 31925cf1a30Sjl139090 32025cf1a30Sjl139090 static struct modlmisc modlmisc = { 32125cf1a30Sjl139090 &mod_miscops, 32225cf1a30Sjl139090 "OPL DR 1.1" 32325cf1a30Sjl139090 }; 32425cf1a30Sjl139090 32525cf1a30Sjl139090 static struct modlinkage modlinkage = { 32625cf1a30Sjl139090 MODREV_1, 32725cf1a30Sjl139090 (void *)&modlmisc, 32825cf1a30Sjl139090 NULL 32925cf1a30Sjl139090 }; 33025cf1a30Sjl139090 33125cf1a30Sjl139090 static krwlock_t drmach_boards_rwlock; 33225cf1a30Sjl139090 33325cf1a30Sjl139090 typedef const char *fn_t; 33425cf1a30Sjl139090 33525cf1a30Sjl139090 int 33625cf1a30Sjl139090 _init(void) 33725cf1a30Sjl139090 { 33825cf1a30Sjl139090 int err; 33925cf1a30Sjl139090 34025cf1a30Sjl139090 if ((err = drmach_init()) != 0) { 34125cf1a30Sjl139090 return (err); 34225cf1a30Sjl139090 } 34325cf1a30Sjl139090 34425cf1a30Sjl139090 if ((err = mod_install(&modlinkage)) != 0) { 34525cf1a30Sjl139090 drmach_fini(); 34625cf1a30Sjl139090 } 34725cf1a30Sjl139090 34825cf1a30Sjl139090 return (err); 34925cf1a30Sjl139090 } 35025cf1a30Sjl139090 35125cf1a30Sjl139090 int 35225cf1a30Sjl139090 _fini(void) 35325cf1a30Sjl139090 { 35425cf1a30Sjl139090 int err; 35525cf1a30Sjl139090 35625cf1a30Sjl139090 if ((err = mod_remove(&modlinkage)) == 0) 35725cf1a30Sjl139090 drmach_fini(); 35825cf1a30Sjl139090 35925cf1a30Sjl139090 return (err); 36025cf1a30Sjl139090 } 36125cf1a30Sjl139090 36225cf1a30Sjl139090 int 36325cf1a30Sjl139090 _info(struct modinfo *modinfop) 36425cf1a30Sjl139090 { 36525cf1a30Sjl139090 return (mod_info(&modlinkage, modinfop)); 36625cf1a30Sjl139090 } 36725cf1a30Sjl139090 36825cf1a30Sjl139090 struct drmach_mc_lookup { 36925cf1a30Sjl139090 int bnum; 37025cf1a30Sjl139090 drmach_board_t *bp; 37125cf1a30Sjl139090 dev_info_t *dip; /* rv - set if found */ 37225cf1a30Sjl139090 }; 37325cf1a30Sjl139090 37425cf1a30Sjl139090 #define _ptob64(p) ((uint64_t)(p) << PAGESHIFT) 37525cf1a30Sjl139090 #define _b64top(b) ((pgcnt_t)((b) >> PAGESHIFT)) 37625cf1a30Sjl139090 37725cf1a30Sjl139090 static int 37825cf1a30Sjl139090 drmach_setup_mc_info(dev_info_t *dip, drmach_mem_t *mp) 37925cf1a30Sjl139090 { 38025cf1a30Sjl139090 uint64_t memory_ranges[128]; 38125cf1a30Sjl139090 int len; 38225cf1a30Sjl139090 struct memlist *ml; 38325cf1a30Sjl139090 int rv; 38425cf1a30Sjl139090 hwd_sb_t *hwd; 38525cf1a30Sjl139090 hwd_memory_t *pm; 38625cf1a30Sjl139090 38725cf1a30Sjl139090 len = sizeof (memory_ranges); 388e98fafb9Sjl139090 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 389e98fafb9Sjl139090 "sb-mem-ranges", (caddr_t)&memory_ranges[0], &len) != 390e98fafb9Sjl139090 DDI_PROP_SUCCESS) { 39125cf1a30Sjl139090 mp->slice_base = 0; 39225cf1a30Sjl139090 mp->slice_size = 0; 39325cf1a30Sjl139090 return (-1); 39425cf1a30Sjl139090 } 39525cf1a30Sjl139090 mp->slice_base = memory_ranges[0]; 39625cf1a30Sjl139090 mp->slice_size = memory_ranges[1]; 39725cf1a30Sjl139090 39825cf1a30Sjl139090 if (!mp->dev.bp->boot_board) { 39925cf1a30Sjl139090 int i; 40025cf1a30Sjl139090 40125cf1a30Sjl139090 rv = opl_read_hwd(mp->dev.bp->bnum, NULL, NULL, NULL, &hwd); 40225cf1a30Sjl139090 40325cf1a30Sjl139090 if (rv != 0) { 40425cf1a30Sjl139090 return (-1); 40525cf1a30Sjl139090 } 40625cf1a30Sjl139090 40725cf1a30Sjl139090 ml = NULL; 40825cf1a30Sjl139090 pm = &hwd->sb_cmu.cmu_memory; 40925cf1a30Sjl139090 for (i = 0; i < HWD_MAX_MEM_CHUNKS; i++) { 41025cf1a30Sjl139090 if (pm->mem_chunks[i].chnk_size > 0) { 41125cf1a30Sjl139090 ml = memlist_add_span(ml, 41225cf1a30Sjl139090 pm->mem_chunks[i].chnk_start_address, 41325cf1a30Sjl139090 pm->mem_chunks[i].chnk_size); 41425cf1a30Sjl139090 } 41525cf1a30Sjl139090 } 41625cf1a30Sjl139090 } else { 41725cf1a30Sjl139090 /* 41825cf1a30Sjl139090 * we intersect phys_install to get base_pa. 41925cf1a30Sjl139090 * This only works at bootup time. 42025cf1a30Sjl139090 */ 42125cf1a30Sjl139090 42225cf1a30Sjl139090 memlist_read_lock(); 42325cf1a30Sjl139090 ml = memlist_dup(phys_install); 42425cf1a30Sjl139090 memlist_read_unlock(); 42525cf1a30Sjl139090 42625cf1a30Sjl139090 ml = memlist_del_span(ml, 0ull, mp->slice_base); 42725cf1a30Sjl139090 if (ml) { 42825cf1a30Sjl139090 uint64_t basepa, endpa; 42925cf1a30Sjl139090 endpa = _ptob64(physmax + 1); 43025cf1a30Sjl139090 43125cf1a30Sjl139090 basepa = mp->slice_base + mp->slice_size; 43225cf1a30Sjl139090 43325cf1a30Sjl139090 ml = memlist_del_span(ml, basepa, endpa - basepa); 43425cf1a30Sjl139090 } 43525cf1a30Sjl139090 } 43625cf1a30Sjl139090 43725cf1a30Sjl139090 if (ml) { 43825cf1a30Sjl139090 uint64_t nbytes = 0; 43925cf1a30Sjl139090 struct memlist *p; 44056f33205SJonathan Adams for (p = ml; p; p = p->ml_next) { 44156f33205SJonathan Adams nbytes += p->ml_size; 44225cf1a30Sjl139090 } 44325cf1a30Sjl139090 if ((mp->nbytes = nbytes) > 0) 44456f33205SJonathan Adams mp->base_pa = ml->ml_address; 44525cf1a30Sjl139090 else 44625cf1a30Sjl139090 mp->base_pa = 0; 44725cf1a30Sjl139090 mp->memlist = ml; 44825cf1a30Sjl139090 } else { 44925cf1a30Sjl139090 mp->base_pa = 0; 45025cf1a30Sjl139090 mp->nbytes = 0; 45125cf1a30Sjl139090 } 45225cf1a30Sjl139090 return (0); 45325cf1a30Sjl139090 } 45425cf1a30Sjl139090 45525cf1a30Sjl139090 45625cf1a30Sjl139090 struct drmach_hotcpu { 45725cf1a30Sjl139090 drmach_board_t *bp; 45825cf1a30Sjl139090 int bnum; 45925cf1a30Sjl139090 int core_id; 46025cf1a30Sjl139090 int rv; 46125cf1a30Sjl139090 int option; 46225cf1a30Sjl139090 }; 46325cf1a30Sjl139090 46425cf1a30Sjl139090 static int 46525cf1a30Sjl139090 drmach_cpu_cb(dev_info_t *dip, void *arg) 46625cf1a30Sjl139090 { 46725cf1a30Sjl139090 struct drmach_hotcpu *p = (struct drmach_hotcpu *)arg; 46825cf1a30Sjl139090 char name[OBP_MAXDRVNAME]; 46925cf1a30Sjl139090 int len = OBP_MAXDRVNAME; 47025cf1a30Sjl139090 int bnum, core_id, strand_id; 47125cf1a30Sjl139090 drmach_board_t *bp; 47225cf1a30Sjl139090 47325cf1a30Sjl139090 if (dip == ddi_root_node()) { 47425cf1a30Sjl139090 return (DDI_WALK_CONTINUE); 47525cf1a30Sjl139090 } 47625cf1a30Sjl139090 47725cf1a30Sjl139090 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 47825cf1a30Sjl139090 DDI_PROP_DONTPASS, "name", 47925cf1a30Sjl139090 (caddr_t)name, &len) != DDI_PROP_SUCCESS) { 48025cf1a30Sjl139090 return (DDI_WALK_PRUNECHILD); 48125cf1a30Sjl139090 } 48225cf1a30Sjl139090 48325cf1a30Sjl139090 /* only cmp has board number */ 48425cf1a30Sjl139090 bnum = -1; 48525cf1a30Sjl139090 len = sizeof (bnum); 48625cf1a30Sjl139090 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 48725cf1a30Sjl139090 DDI_PROP_DONTPASS, OBP_BOARDNUM, 48825cf1a30Sjl139090 (caddr_t)&bnum, &len) != DDI_PROP_SUCCESS) { 48925cf1a30Sjl139090 bnum = -1; 49025cf1a30Sjl139090 } 49125cf1a30Sjl139090 49225cf1a30Sjl139090 if (strcmp(name, "cmp") == 0) { 49325cf1a30Sjl139090 if (bnum != p->bnum) 49425cf1a30Sjl139090 return (DDI_WALK_PRUNECHILD); 49525cf1a30Sjl139090 return (DDI_WALK_CONTINUE); 49625cf1a30Sjl139090 } 49725cf1a30Sjl139090 /* we have already pruned all unwanted cores and cpu's above */ 49825cf1a30Sjl139090 if (strcmp(name, "core") == 0) { 49925cf1a30Sjl139090 return (DDI_WALK_CONTINUE); 50025cf1a30Sjl139090 } 50125cf1a30Sjl139090 if (strcmp(name, "cpu") == 0) { 50225cf1a30Sjl139090 processorid_t cpuid; 50325cf1a30Sjl139090 len = sizeof (cpuid); 50425cf1a30Sjl139090 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 50525cf1a30Sjl139090 DDI_PROP_DONTPASS, "cpuid", 50625cf1a30Sjl139090 (caddr_t)&cpuid, &len) != DDI_PROP_SUCCESS) { 50725cf1a30Sjl139090 p->rv = -1; 50825cf1a30Sjl139090 return (DDI_WALK_TERMINATE); 50925cf1a30Sjl139090 } 51025cf1a30Sjl139090 51125cf1a30Sjl139090 core_id = p->core_id; 51225cf1a30Sjl139090 51325cf1a30Sjl139090 bnum = LSB_ID(cpuid); 51425cf1a30Sjl139090 51525cf1a30Sjl139090 if (ON_BOARD_CORE_NUM(cpuid) != core_id) 51625cf1a30Sjl139090 return (DDI_WALK_CONTINUE); 51725cf1a30Sjl139090 51825cf1a30Sjl139090 bp = p->bp; 51925cf1a30Sjl139090 ASSERT(bnum == bp->bnum); 52025cf1a30Sjl139090 52125cf1a30Sjl139090 if (p->option == HOTADD_CPU) { 52225cf1a30Sjl139090 if (prom_hotaddcpu(cpuid) != 0) { 52325cf1a30Sjl139090 p->rv = -1; 52425cf1a30Sjl139090 return (DDI_WALK_TERMINATE); 52525cf1a30Sjl139090 } 52625cf1a30Sjl139090 strand_id = STRAND_ID(cpuid); 52725cf1a30Sjl139090 bp->cores[core_id].core_hotadded |= (1 << strand_id); 52825cf1a30Sjl139090 } else if (p->option == HOTREMOVE_CPU) { 52925cf1a30Sjl139090 if (prom_hotremovecpu(cpuid) != 0) { 53025cf1a30Sjl139090 p->rv = -1; 53125cf1a30Sjl139090 return (DDI_WALK_TERMINATE); 53225cf1a30Sjl139090 } 53325cf1a30Sjl139090 strand_id = STRAND_ID(cpuid); 53425cf1a30Sjl139090 bp->cores[core_id].core_hotadded &= ~(1 << strand_id); 53525cf1a30Sjl139090 } 53625cf1a30Sjl139090 return (DDI_WALK_CONTINUE); 53725cf1a30Sjl139090 } 53825cf1a30Sjl139090 53925cf1a30Sjl139090 return (DDI_WALK_PRUNECHILD); 54025cf1a30Sjl139090 } 54125cf1a30Sjl139090 54225cf1a30Sjl139090 54325cf1a30Sjl139090 static int 54425cf1a30Sjl139090 drmach_add_remove_cpu(int bnum, int core_id, int option) 54525cf1a30Sjl139090 { 54625cf1a30Sjl139090 struct drmach_hotcpu arg; 54725cf1a30Sjl139090 drmach_board_t *bp; 54825cf1a30Sjl139090 54925cf1a30Sjl139090 bp = drmach_get_board_by_bnum(bnum); 55025cf1a30Sjl139090 ASSERT(bp); 55125cf1a30Sjl139090 55225cf1a30Sjl139090 arg.bp = bp; 55325cf1a30Sjl139090 arg.bnum = bnum; 55425cf1a30Sjl139090 arg.core_id = core_id; 55525cf1a30Sjl139090 arg.rv = 0; 55625cf1a30Sjl139090 arg.option = option; 55725cf1a30Sjl139090 ddi_walk_devs(ddi_root_node(), drmach_cpu_cb, (void *)&arg); 55825cf1a30Sjl139090 return (arg.rv); 55925cf1a30Sjl139090 } 56025cf1a30Sjl139090 56125cf1a30Sjl139090 struct drmach_setup_core_arg { 56225cf1a30Sjl139090 drmach_board_t *bp; 56325cf1a30Sjl139090 }; 56425cf1a30Sjl139090 56525cf1a30Sjl139090 static int 56625cf1a30Sjl139090 drmach_setup_core_cb(dev_info_t *dip, void *arg) 56725cf1a30Sjl139090 { 56825cf1a30Sjl139090 struct drmach_setup_core_arg *p = (struct drmach_setup_core_arg *)arg; 56925cf1a30Sjl139090 char name[OBP_MAXDRVNAME]; 57025cf1a30Sjl139090 int len = OBP_MAXDRVNAME; 57125cf1a30Sjl139090 int bnum; 57225cf1a30Sjl139090 int core_id, strand_id; 57325cf1a30Sjl139090 57425cf1a30Sjl139090 if (dip == ddi_root_node()) { 57525cf1a30Sjl139090 return (DDI_WALK_CONTINUE); 57625cf1a30Sjl139090 } 57725cf1a30Sjl139090 57825cf1a30Sjl139090 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 57925cf1a30Sjl139090 DDI_PROP_DONTPASS, "name", 58025cf1a30Sjl139090 (caddr_t)name, &len) != DDI_PROP_SUCCESS) { 58125cf1a30Sjl139090 return (DDI_WALK_PRUNECHILD); 58225cf1a30Sjl139090 } 58325cf1a30Sjl139090 58425cf1a30Sjl139090 /* only cmp has board number */ 58525cf1a30Sjl139090 bnum = -1; 58625cf1a30Sjl139090 len = sizeof (bnum); 58725cf1a30Sjl139090 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 58825cf1a30Sjl139090 DDI_PROP_DONTPASS, OBP_BOARDNUM, 58925cf1a30Sjl139090 (caddr_t)&bnum, &len) != DDI_PROP_SUCCESS) { 59025cf1a30Sjl139090 bnum = -1; 59125cf1a30Sjl139090 } 59225cf1a30Sjl139090 59325cf1a30Sjl139090 if (strcmp(name, "cmp") == 0) { 59425cf1a30Sjl139090 if (bnum != p->bp->bnum) 59525cf1a30Sjl139090 return (DDI_WALK_PRUNECHILD); 59625cf1a30Sjl139090 return (DDI_WALK_CONTINUE); 59725cf1a30Sjl139090 } 59825cf1a30Sjl139090 /* we have already pruned all unwanted cores and cpu's above */ 59925cf1a30Sjl139090 if (strcmp(name, "core") == 0) { 60025cf1a30Sjl139090 return (DDI_WALK_CONTINUE); 60125cf1a30Sjl139090 } 60225cf1a30Sjl139090 if (strcmp(name, "cpu") == 0) { 60325cf1a30Sjl139090 processorid_t cpuid; 60425cf1a30Sjl139090 len = sizeof (cpuid); 60525cf1a30Sjl139090 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 60625cf1a30Sjl139090 DDI_PROP_DONTPASS, "cpuid", 60725cf1a30Sjl139090 (caddr_t)&cpuid, &len) != DDI_PROP_SUCCESS) { 60825cf1a30Sjl139090 return (DDI_WALK_TERMINATE); 60925cf1a30Sjl139090 } 61025cf1a30Sjl139090 bnum = LSB_ID(cpuid); 61125cf1a30Sjl139090 ASSERT(bnum == p->bp->bnum); 61225cf1a30Sjl139090 core_id = ON_BOARD_CORE_NUM(cpuid); 61325cf1a30Sjl139090 strand_id = STRAND_ID(cpuid); 61425cf1a30Sjl139090 p->bp->cores[core_id].core_present |= (1 << strand_id); 61525cf1a30Sjl139090 return (DDI_WALK_CONTINUE); 61625cf1a30Sjl139090 } 61725cf1a30Sjl139090 61825cf1a30Sjl139090 return (DDI_WALK_PRUNECHILD); 61925cf1a30Sjl139090 } 62025cf1a30Sjl139090 62125cf1a30Sjl139090 62225cf1a30Sjl139090 static void 62325cf1a30Sjl139090 drmach_setup_core_info(drmach_board_t *obj) 62425cf1a30Sjl139090 { 62525cf1a30Sjl139090 struct drmach_setup_core_arg arg; 62625cf1a30Sjl139090 int i; 62725cf1a30Sjl139090 62825cf1a30Sjl139090 for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) { 62925cf1a30Sjl139090 obj->cores[i].core_present = 0; 63025cf1a30Sjl139090 obj->cores[i].core_hotadded = 0; 63125cf1a30Sjl139090 obj->cores[i].core_started = 0; 63225cf1a30Sjl139090 } 63325cf1a30Sjl139090 arg.bp = obj; 63425cf1a30Sjl139090 ddi_walk_devs(ddi_root_node(), drmach_setup_core_cb, (void *)&arg); 63525cf1a30Sjl139090 63625cf1a30Sjl139090 for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) { 63725cf1a30Sjl139090 if (obj->boot_board) { 63825cf1a30Sjl139090 obj->cores[i].core_hotadded = 63925cf1a30Sjl139090 obj->cores[i].core_started = 64025cf1a30Sjl139090 obj->cores[i].core_present; 64125cf1a30Sjl139090 } 64225cf1a30Sjl139090 } 64325cf1a30Sjl139090 } 64425cf1a30Sjl139090 64525cf1a30Sjl139090 /* 64625cf1a30Sjl139090 * drmach_node_* routines serve the purpose of separating the 64725cf1a30Sjl139090 * rest of the code from the device tree and OBP. This is necessary 64825cf1a30Sjl139090 * because of In-Kernel-Probing. Devices probed after stod, are probed 64925cf1a30Sjl139090 * by the in-kernel-prober, not OBP. These devices, therefore, do not 65025cf1a30Sjl139090 * have dnode ids. 65125cf1a30Sjl139090 */ 65225cf1a30Sjl139090 65325cf1a30Sjl139090 typedef struct { 65425cf1a30Sjl139090 drmach_node_walk_args_t *nwargs; 65525cf1a30Sjl139090 int (*cb)(drmach_node_walk_args_t *args); 65625cf1a30Sjl139090 int err; 65725cf1a30Sjl139090 } drmach_node_ddi_walk_args_t; 65825cf1a30Sjl139090 65925cf1a30Sjl139090 static int 66025cf1a30Sjl139090 drmach_node_ddi_walk_cb(dev_info_t *dip, void *arg) 66125cf1a30Sjl139090 { 66225cf1a30Sjl139090 drmach_node_ddi_walk_args_t *nargs; 66325cf1a30Sjl139090 66425cf1a30Sjl139090 nargs = (drmach_node_ddi_walk_args_t *)arg; 66525cf1a30Sjl139090 66625cf1a30Sjl139090 /* 66725cf1a30Sjl139090 * dip doesn't have to be held here as we are called 66825cf1a30Sjl139090 * from ddi_walk_devs() which holds the dip. 66925cf1a30Sjl139090 */ 67025cf1a30Sjl139090 nargs->nwargs->node->here = (void *)dip; 67125cf1a30Sjl139090 67225cf1a30Sjl139090 nargs->err = nargs->cb(nargs->nwargs); 67325cf1a30Sjl139090 67425cf1a30Sjl139090 67525cf1a30Sjl139090 /* 67625cf1a30Sjl139090 * Set "here" to NULL so that unheld dip is not accessible 67725cf1a30Sjl139090 * outside ddi_walk_devs() 67825cf1a30Sjl139090 */ 67925cf1a30Sjl139090 nargs->nwargs->node->here = NULL; 68025cf1a30Sjl139090 68125cf1a30Sjl139090 if (nargs->err) 68225cf1a30Sjl139090 return (DDI_WALK_TERMINATE); 68325cf1a30Sjl139090 else 68425cf1a30Sjl139090 return (DDI_WALK_CONTINUE); 68525cf1a30Sjl139090 } 68625cf1a30Sjl139090 68725cf1a30Sjl139090 static int 68825cf1a30Sjl139090 drmach_node_ddi_walk(drmach_node_t *np, void *data, 68925cf1a30Sjl139090 int (*cb)(drmach_node_walk_args_t *args)) 69025cf1a30Sjl139090 { 69125cf1a30Sjl139090 drmach_node_walk_args_t args; 69225cf1a30Sjl139090 drmach_node_ddi_walk_args_t nargs; 69325cf1a30Sjl139090 69425cf1a30Sjl139090 69525cf1a30Sjl139090 /* initialized args structure for callback */ 69625cf1a30Sjl139090 args.node = np; 69725cf1a30Sjl139090 args.data = data; 69825cf1a30Sjl139090 69925cf1a30Sjl139090 nargs.nwargs = &args; 70025cf1a30Sjl139090 nargs.cb = cb; 70125cf1a30Sjl139090 nargs.err = 0; 70225cf1a30Sjl139090 70325cf1a30Sjl139090 /* 70425cf1a30Sjl139090 * Root node doesn't have to be held in any way. 70525cf1a30Sjl139090 */ 706e98fafb9Sjl139090 ddi_walk_devs(ddi_root_node(), drmach_node_ddi_walk_cb, (void *)&nargs); 70725cf1a30Sjl139090 70825cf1a30Sjl139090 return (nargs.err); 70925cf1a30Sjl139090 } 71025cf1a30Sjl139090 71125cf1a30Sjl139090 static int 71225cf1a30Sjl139090 drmach_node_ddi_get_parent(drmach_node_t *np, drmach_node_t *pp) 71325cf1a30Sjl139090 { 71425cf1a30Sjl139090 dev_info_t *ndip; 71525cf1a30Sjl139090 static char *fn = "drmach_node_ddi_get_parent"; 71625cf1a30Sjl139090 71725cf1a30Sjl139090 ndip = np->n_getdip(np); 71825cf1a30Sjl139090 if (ndip == NULL) { 71925cf1a30Sjl139090 cmn_err(CE_WARN, "%s: NULL dip", fn); 72025cf1a30Sjl139090 return (-1); 72125cf1a30Sjl139090 } 72225cf1a30Sjl139090 72325cf1a30Sjl139090 bcopy(np, pp, sizeof (drmach_node_t)); 72425cf1a30Sjl139090 72525cf1a30Sjl139090 pp->here = (void *)ddi_get_parent(ndip); 72625cf1a30Sjl139090 if (pp->here == NULL) { 72725cf1a30Sjl139090 cmn_err(CE_WARN, "%s: NULL parent dip", fn); 72825cf1a30Sjl139090 return (-1); 72925cf1a30Sjl139090 } 73025cf1a30Sjl139090 73125cf1a30Sjl139090 return (0); 73225cf1a30Sjl139090 } 73325cf1a30Sjl139090 73425cf1a30Sjl139090 /*ARGSUSED*/ 73525cf1a30Sjl139090 static pnode_t 73625cf1a30Sjl139090 drmach_node_ddi_get_dnode(drmach_node_t *np) 73725cf1a30Sjl139090 { 73825cf1a30Sjl139090 return ((pnode_t)NULL); 73925cf1a30Sjl139090 } 74025cf1a30Sjl139090 74125cf1a30Sjl139090 static drmach_node_t * 74225cf1a30Sjl139090 drmach_node_new(void) 74325cf1a30Sjl139090 { 74425cf1a30Sjl139090 drmach_node_t *np; 74525cf1a30Sjl139090 74625cf1a30Sjl139090 np = kmem_zalloc(sizeof (drmach_node_t), KM_SLEEP); 74725cf1a30Sjl139090 74825cf1a30Sjl139090 np->get_dnode = drmach_node_ddi_get_dnode; 74925cf1a30Sjl139090 np->walk = drmach_node_ddi_walk; 75025cf1a30Sjl139090 np->n_getdip = drmach_node_ddi_get_dip; 75125cf1a30Sjl139090 np->n_getproplen = drmach_node_ddi_get_proplen; 75225cf1a30Sjl139090 np->n_getprop = drmach_node_ddi_get_prop; 75325cf1a30Sjl139090 np->get_parent = drmach_node_ddi_get_parent; 75425cf1a30Sjl139090 75525cf1a30Sjl139090 return (np); 75625cf1a30Sjl139090 } 75725cf1a30Sjl139090 75825cf1a30Sjl139090 static void 75925cf1a30Sjl139090 drmach_node_dispose(drmach_node_t *np) 76025cf1a30Sjl139090 { 76125cf1a30Sjl139090 kmem_free(np, sizeof (*np)); 76225cf1a30Sjl139090 } 76325cf1a30Sjl139090 76425cf1a30Sjl139090 static dev_info_t * 76525cf1a30Sjl139090 drmach_node_ddi_get_dip(drmach_node_t *np) 76625cf1a30Sjl139090 { 76725cf1a30Sjl139090 return ((dev_info_t *)np->here); 76825cf1a30Sjl139090 } 76925cf1a30Sjl139090 77025cf1a30Sjl139090 static int 77125cf1a30Sjl139090 drmach_node_walk(drmach_node_t *np, void *param, 77225cf1a30Sjl139090 int (*cb)(drmach_node_walk_args_t *args)) 77325cf1a30Sjl139090 { 77425cf1a30Sjl139090 return (np->walk(np, param, cb)); 77525cf1a30Sjl139090 } 77625cf1a30Sjl139090 77725cf1a30Sjl139090 static int 77825cf1a30Sjl139090 drmach_node_ddi_get_prop(drmach_node_t *np, char *name, void *buf, int len) 77925cf1a30Sjl139090 { 78025cf1a30Sjl139090 int rv = 0; 78125cf1a30Sjl139090 dev_info_t *ndip; 78225cf1a30Sjl139090 static char *fn = "drmach_node_ddi_get_prop"; 78325cf1a30Sjl139090 78425cf1a30Sjl139090 78525cf1a30Sjl139090 ndip = np->n_getdip(np); 78625cf1a30Sjl139090 if (ndip == NULL) { 78725cf1a30Sjl139090 cmn_err(CE_WARN, "%s: NULL dip", fn); 78825cf1a30Sjl139090 rv = -1; 78925cf1a30Sjl139090 } else if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ndip, 79025cf1a30Sjl139090 DDI_PROP_DONTPASS, name, 79125cf1a30Sjl139090 (caddr_t)buf, &len) != DDI_PROP_SUCCESS) { 79225cf1a30Sjl139090 rv = -1; 79325cf1a30Sjl139090 } 79425cf1a30Sjl139090 79525cf1a30Sjl139090 return (rv); 79625cf1a30Sjl139090 } 79725cf1a30Sjl139090 79825cf1a30Sjl139090 static int 79925cf1a30Sjl139090 drmach_node_ddi_get_proplen(drmach_node_t *np, char *name, int *len) 80025cf1a30Sjl139090 { 80125cf1a30Sjl139090 int rv = 0; 80225cf1a30Sjl139090 dev_info_t *ndip; 80325cf1a30Sjl139090 80425cf1a30Sjl139090 ndip = np->n_getdip(np); 80525cf1a30Sjl139090 if (ndip == NULL) { 80625cf1a30Sjl139090 rv = -1; 807e98fafb9Sjl139090 } else if (ddi_getproplen(DDI_DEV_T_ANY, ndip, DDI_PROP_DONTPASS, name, 808e98fafb9Sjl139090 len) != DDI_PROP_SUCCESS) { 80925cf1a30Sjl139090 rv = -1; 81025cf1a30Sjl139090 } 81125cf1a30Sjl139090 81225cf1a30Sjl139090 return (rv); 81325cf1a30Sjl139090 } 81425cf1a30Sjl139090 81525cf1a30Sjl139090 static drmachid_t 81625cf1a30Sjl139090 drmach_node_dup(drmach_node_t *np) 81725cf1a30Sjl139090 { 81825cf1a30Sjl139090 drmach_node_t *dup; 81925cf1a30Sjl139090 82025cf1a30Sjl139090 dup = drmach_node_new(); 82125cf1a30Sjl139090 dup->here = np->here; 82225cf1a30Sjl139090 dup->get_dnode = np->get_dnode; 82325cf1a30Sjl139090 dup->walk = np->walk; 82425cf1a30Sjl139090 dup->n_getdip = np->n_getdip; 82525cf1a30Sjl139090 dup->n_getproplen = np->n_getproplen; 82625cf1a30Sjl139090 dup->n_getprop = np->n_getprop; 82725cf1a30Sjl139090 dup->get_parent = np->get_parent; 82825cf1a30Sjl139090 82925cf1a30Sjl139090 return (dup); 83025cf1a30Sjl139090 } 83125cf1a30Sjl139090 83225cf1a30Sjl139090 /* 83325cf1a30Sjl139090 * drmach_array provides convenient array construction, access, 83425cf1a30Sjl139090 * bounds checking and array destruction logic. 83525cf1a30Sjl139090 */ 83625cf1a30Sjl139090 83725cf1a30Sjl139090 static drmach_array_t * 83825cf1a30Sjl139090 drmach_array_new(int min_index, int max_index) 83925cf1a30Sjl139090 { 84025cf1a30Sjl139090 drmach_array_t *arr; 84125cf1a30Sjl139090 84225cf1a30Sjl139090 arr = kmem_zalloc(sizeof (drmach_array_t), KM_SLEEP); 84325cf1a30Sjl139090 84425cf1a30Sjl139090 arr->arr_sz = (max_index - min_index + 1) * sizeof (void *); 84525cf1a30Sjl139090 if (arr->arr_sz > 0) { 84625cf1a30Sjl139090 arr->min_index = min_index; 84725cf1a30Sjl139090 arr->max_index = max_index; 84825cf1a30Sjl139090 84925cf1a30Sjl139090 arr->arr = kmem_zalloc(arr->arr_sz, KM_SLEEP); 85025cf1a30Sjl139090 return (arr); 85125cf1a30Sjl139090 } else { 85225cf1a30Sjl139090 kmem_free(arr, sizeof (*arr)); 85325cf1a30Sjl139090 return (0); 85425cf1a30Sjl139090 } 85525cf1a30Sjl139090 } 85625cf1a30Sjl139090 85725cf1a30Sjl139090 static int 85825cf1a30Sjl139090 drmach_array_set(drmach_array_t *arr, int idx, drmachid_t val) 85925cf1a30Sjl139090 { 86025cf1a30Sjl139090 if (idx < arr->min_index || idx > arr->max_index) 86125cf1a30Sjl139090 return (-1); 86225cf1a30Sjl139090 else { 86325cf1a30Sjl139090 arr->arr[idx - arr->min_index] = val; 86425cf1a30Sjl139090 return (0); 86525cf1a30Sjl139090 } 86625cf1a30Sjl139090 /*NOTREACHED*/ 86725cf1a30Sjl139090 } 86825cf1a30Sjl139090 86925cf1a30Sjl139090 static int 87025cf1a30Sjl139090 drmach_array_get(drmach_array_t *arr, int idx, drmachid_t *val) 87125cf1a30Sjl139090 { 87225cf1a30Sjl139090 if (idx < arr->min_index || idx > arr->max_index) 87325cf1a30Sjl139090 return (-1); 87425cf1a30Sjl139090 else { 87525cf1a30Sjl139090 *val = arr->arr[idx - arr->min_index]; 87625cf1a30Sjl139090 return (0); 87725cf1a30Sjl139090 } 87825cf1a30Sjl139090 /*NOTREACHED*/ 87925cf1a30Sjl139090 } 88025cf1a30Sjl139090 88125cf1a30Sjl139090 static int 88225cf1a30Sjl139090 drmach_array_first(drmach_array_t *arr, int *idx, drmachid_t *val) 88325cf1a30Sjl139090 { 88425cf1a30Sjl139090 int rv; 88525cf1a30Sjl139090 88625cf1a30Sjl139090 *idx = arr->min_index; 88725cf1a30Sjl139090 while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL) 88825cf1a30Sjl139090 *idx += 1; 88925cf1a30Sjl139090 89025cf1a30Sjl139090 return (rv); 89125cf1a30Sjl139090 } 89225cf1a30Sjl139090 89325cf1a30Sjl139090 static int 89425cf1a30Sjl139090 drmach_array_next(drmach_array_t *arr, int *idx, drmachid_t *val) 89525cf1a30Sjl139090 { 89625cf1a30Sjl139090 int rv; 89725cf1a30Sjl139090 89825cf1a30Sjl139090 *idx += 1; 89925cf1a30Sjl139090 while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL) 90025cf1a30Sjl139090 *idx += 1; 90125cf1a30Sjl139090 90225cf1a30Sjl139090 return (rv); 90325cf1a30Sjl139090 } 90425cf1a30Sjl139090 90525cf1a30Sjl139090 static void 90625cf1a30Sjl139090 drmach_array_dispose(drmach_array_t *arr, void (*disposer)(drmachid_t)) 90725cf1a30Sjl139090 { 90825cf1a30Sjl139090 drmachid_t val; 90925cf1a30Sjl139090 int idx; 91025cf1a30Sjl139090 int rv; 91125cf1a30Sjl139090 91225cf1a30Sjl139090 rv = drmach_array_first(arr, &idx, &val); 91325cf1a30Sjl139090 while (rv == 0) { 91425cf1a30Sjl139090 (*disposer)(val); 91525cf1a30Sjl139090 rv = drmach_array_next(arr, &idx, &val); 91625cf1a30Sjl139090 } 91725cf1a30Sjl139090 91825cf1a30Sjl139090 kmem_free(arr->arr, arr->arr_sz); 91925cf1a30Sjl139090 kmem_free(arr, sizeof (*arr)); 92025cf1a30Sjl139090 } 92125cf1a30Sjl139090 92225cf1a30Sjl139090 static drmach_board_t * 92325cf1a30Sjl139090 drmach_get_board_by_bnum(int bnum) 92425cf1a30Sjl139090 { 92525cf1a30Sjl139090 drmachid_t id; 92625cf1a30Sjl139090 92725cf1a30Sjl139090 if (drmach_array_get(drmach_boards, bnum, &id) == 0) 92825cf1a30Sjl139090 return ((drmach_board_t *)id); 92925cf1a30Sjl139090 else 93025cf1a30Sjl139090 return (NULL); 93125cf1a30Sjl139090 } 93225cf1a30Sjl139090 93325cf1a30Sjl139090 static pnode_t 93425cf1a30Sjl139090 drmach_node_get_dnode(drmach_node_t *np) 93525cf1a30Sjl139090 { 93625cf1a30Sjl139090 return (np->get_dnode(np)); 93725cf1a30Sjl139090 } 93825cf1a30Sjl139090 93925cf1a30Sjl139090 /*ARGSUSED*/ 94025cf1a30Sjl139090 sbd_error_t * 94125cf1a30Sjl139090 drmach_configure(drmachid_t id, int flags) 94225cf1a30Sjl139090 { 94325cf1a30Sjl139090 drmach_device_t *dp; 94425cf1a30Sjl139090 sbd_error_t *err = NULL; 94525cf1a30Sjl139090 dev_info_t *rdip; 94625cf1a30Sjl139090 dev_info_t *fdip = NULL; 94725cf1a30Sjl139090 94825cf1a30Sjl139090 if (DRMACH_IS_CPU_ID(id)) { 94925cf1a30Sjl139090 return (NULL); 95025cf1a30Sjl139090 } 95125cf1a30Sjl139090 if (!DRMACH_IS_DEVICE_ID(id)) 95225cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 95325cf1a30Sjl139090 dp = id; 95425cf1a30Sjl139090 rdip = dp->node->n_getdip(dp->node); 95525cf1a30Sjl139090 95625cf1a30Sjl139090 ASSERT(rdip); 95725cf1a30Sjl139090 95825cf1a30Sjl139090 ASSERT(e_ddi_branch_held(rdip)); 95925cf1a30Sjl139090 96025cf1a30Sjl139090 if (e_ddi_branch_configure(rdip, &fdip, 0) != 0) { 96125cf1a30Sjl139090 char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 96225cf1a30Sjl139090 dev_info_t *dip = (fdip != NULL) ? fdip : rdip; 96325cf1a30Sjl139090 96425cf1a30Sjl139090 (void) ddi_pathname(dip, path); 96525cf1a30Sjl139090 err = drerr_new(1, EOPL_DRVFAIL, path); 96625cf1a30Sjl139090 96725cf1a30Sjl139090 kmem_free(path, MAXPATHLEN); 96825cf1a30Sjl139090 96925cf1a30Sjl139090 /* If non-NULL, fdip is returned held and must be released */ 97025cf1a30Sjl139090 if (fdip != NULL) 97125cf1a30Sjl139090 ddi_release_devi(fdip); 97225cf1a30Sjl139090 } 97325cf1a30Sjl139090 97425cf1a30Sjl139090 return (err); 97525cf1a30Sjl139090 } 97625cf1a30Sjl139090 97725cf1a30Sjl139090 97825cf1a30Sjl139090 static sbd_error_t * 97925cf1a30Sjl139090 drmach_device_new(drmach_node_t *node, 98025cf1a30Sjl139090 drmach_board_t *bp, int portid, drmachid_t *idp) 98125cf1a30Sjl139090 { 98225cf1a30Sjl139090 int i; 98325cf1a30Sjl139090 int rv; 98425cf1a30Sjl139090 drmach_device_t proto; 98525cf1a30Sjl139090 sbd_error_t *err; 98625cf1a30Sjl139090 char name[OBP_MAXDRVNAME]; 98725cf1a30Sjl139090 98825cf1a30Sjl139090 rv = node->n_getprop(node, "name", name, OBP_MAXDRVNAME); 98925cf1a30Sjl139090 if (rv) { 99025cf1a30Sjl139090 /* every node is expected to have a name */ 991e98fafb9Sjl139090 err = drerr_new(1, EOPL_GETPROP, "device node %s: property %s", 99225cf1a30Sjl139090 ddi_node_name(node->n_getdip(node)), "name"); 99325cf1a30Sjl139090 return (err); 99425cf1a30Sjl139090 } 99525cf1a30Sjl139090 99625cf1a30Sjl139090 /* 99725cf1a30Sjl139090 * The node currently being examined is not listed in the name2type[] 99825cf1a30Sjl139090 * array. In this case, the node is no interest to drmach. Both 99925cf1a30Sjl139090 * dp and err are initialized here to yield nothing (no device or 100025cf1a30Sjl139090 * error structure) for this case. 100125cf1a30Sjl139090 */ 100225cf1a30Sjl139090 i = drmach_name2type_idx(name); 100325cf1a30Sjl139090 100425cf1a30Sjl139090 100525cf1a30Sjl139090 if (i < 0) { 100625cf1a30Sjl139090 *idp = (drmachid_t)0; 100725cf1a30Sjl139090 return (NULL); 100825cf1a30Sjl139090 } 100925cf1a30Sjl139090 101025cf1a30Sjl139090 /* device specific new function will set unum */ 101125cf1a30Sjl139090 101225cf1a30Sjl139090 bzero(&proto, sizeof (proto)); 101325cf1a30Sjl139090 proto.type = drmach_name2type[i].type; 101425cf1a30Sjl139090 proto.bp = bp; 101525cf1a30Sjl139090 proto.node = node; 101625cf1a30Sjl139090 proto.portid = portid; 101725cf1a30Sjl139090 101825cf1a30Sjl139090 return (drmach_name2type[i].new(&proto, idp)); 101925cf1a30Sjl139090 } 102025cf1a30Sjl139090 102125cf1a30Sjl139090 static void 102225cf1a30Sjl139090 drmach_device_dispose(drmachid_t id) 102325cf1a30Sjl139090 { 102425cf1a30Sjl139090 drmach_device_t *self = id; 102525cf1a30Sjl139090 102625cf1a30Sjl139090 self->cm.dispose(id); 102725cf1a30Sjl139090 } 102825cf1a30Sjl139090 102925cf1a30Sjl139090 103025cf1a30Sjl139090 static drmach_board_t * 103125cf1a30Sjl139090 drmach_board_new(int bnum, int boot_board) 103225cf1a30Sjl139090 { 103325cf1a30Sjl139090 drmach_board_t *bp; 103425cf1a30Sjl139090 103525cf1a30Sjl139090 bp = kmem_zalloc(sizeof (drmach_board_t), KM_SLEEP); 103625cf1a30Sjl139090 103725cf1a30Sjl139090 bp->cm.isa = (void *)drmach_board_new; 103825cf1a30Sjl139090 bp->cm.release = drmach_board_release; 103925cf1a30Sjl139090 bp->cm.status = drmach_board_status; 104025cf1a30Sjl139090 104125cf1a30Sjl139090 (void) drmach_board_name(bnum, bp->cm.name, sizeof (bp->cm.name)); 104225cf1a30Sjl139090 104325cf1a30Sjl139090 bp->bnum = bnum; 104425cf1a30Sjl139090 bp->devices = NULL; 104525cf1a30Sjl139090 bp->connected = boot_board; 104625cf1a30Sjl139090 bp->tree = drmach_node_new(); 104725cf1a30Sjl139090 bp->assigned = boot_board; 104825cf1a30Sjl139090 bp->powered = boot_board; 104925cf1a30Sjl139090 bp->boot_board = boot_board; 105025cf1a30Sjl139090 105125cf1a30Sjl139090 /* 105225cf1a30Sjl139090 * If this is not bootup initialization, we have to wait till 105325cf1a30Sjl139090 * IKP sets up the device nodes in drmach_board_connect(). 105425cf1a30Sjl139090 */ 105525cf1a30Sjl139090 if (boot_board) 105625cf1a30Sjl139090 drmach_setup_core_info(bp); 105725cf1a30Sjl139090 105807d06da5SSurya Prakki (void) drmach_array_set(drmach_boards, bnum, bp); 105925cf1a30Sjl139090 return (bp); 106025cf1a30Sjl139090 } 106125cf1a30Sjl139090 106225cf1a30Sjl139090 static void 106325cf1a30Sjl139090 drmach_board_dispose(drmachid_t id) 106425cf1a30Sjl139090 { 106525cf1a30Sjl139090 drmach_board_t *bp; 106625cf1a30Sjl139090 106725cf1a30Sjl139090 ASSERT(DRMACH_IS_BOARD_ID(id)); 106825cf1a30Sjl139090 bp = id; 106925cf1a30Sjl139090 107025cf1a30Sjl139090 if (bp->tree) 107125cf1a30Sjl139090 drmach_node_dispose(bp->tree); 107225cf1a30Sjl139090 107325cf1a30Sjl139090 if (bp->devices) 107425cf1a30Sjl139090 drmach_array_dispose(bp->devices, drmach_device_dispose); 107525cf1a30Sjl139090 107625cf1a30Sjl139090 kmem_free(bp, sizeof (*bp)); 107725cf1a30Sjl139090 } 107825cf1a30Sjl139090 107925cf1a30Sjl139090 static sbd_error_t * 108025cf1a30Sjl139090 drmach_board_status(drmachid_t id, drmach_status_t *stat) 108125cf1a30Sjl139090 { 108225cf1a30Sjl139090 sbd_error_t *err = NULL; 108325cf1a30Sjl139090 drmach_board_t *bp; 108425cf1a30Sjl139090 108525cf1a30Sjl139090 if (!DRMACH_IS_BOARD_ID(id)) 108625cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 108725cf1a30Sjl139090 bp = id; 108825cf1a30Sjl139090 108925cf1a30Sjl139090 stat->assigned = bp->assigned; 109025cf1a30Sjl139090 stat->powered = bp->powered; 109125cf1a30Sjl139090 stat->busy = 0; /* assume not busy */ 109225cf1a30Sjl139090 stat->configured = 0; /* assume not configured */ 109325cf1a30Sjl139090 stat->empty = 0; 109425cf1a30Sjl139090 stat->cond = bp->cond = SBD_COND_OK; 109507d06da5SSurya Prakki (void) strncpy(stat->type, "System Brd", sizeof (stat->type)); 109625cf1a30Sjl139090 stat->info[0] = '\0'; 109725cf1a30Sjl139090 109825cf1a30Sjl139090 if (bp->devices) { 109925cf1a30Sjl139090 int rv; 110025cf1a30Sjl139090 int d_idx; 110125cf1a30Sjl139090 drmachid_t d_id; 110225cf1a30Sjl139090 110325cf1a30Sjl139090 rv = drmach_array_first(bp->devices, &d_idx, &d_id); 110425cf1a30Sjl139090 while (rv == 0) { 110525cf1a30Sjl139090 drmach_status_t d_stat; 110625cf1a30Sjl139090 110725cf1a30Sjl139090 err = drmach_i_status(d_id, &d_stat); 110825cf1a30Sjl139090 if (err) 110925cf1a30Sjl139090 break; 111025cf1a30Sjl139090 111125cf1a30Sjl139090 stat->busy |= d_stat.busy; 111225cf1a30Sjl139090 stat->configured |= d_stat.configured; 111325cf1a30Sjl139090 111425cf1a30Sjl139090 rv = drmach_array_next(bp->devices, &d_idx, &d_id); 111525cf1a30Sjl139090 } 111625cf1a30Sjl139090 } 111725cf1a30Sjl139090 111825cf1a30Sjl139090 return (err); 111925cf1a30Sjl139090 } 112025cf1a30Sjl139090 112125cf1a30Sjl139090 int 112225cf1a30Sjl139090 drmach_board_is_floating(drmachid_t id) 112325cf1a30Sjl139090 { 112425cf1a30Sjl139090 drmach_board_t *bp; 112525cf1a30Sjl139090 112625cf1a30Sjl139090 if (!DRMACH_IS_BOARD_ID(id)) 112725cf1a30Sjl139090 return (0); 112825cf1a30Sjl139090 112925cf1a30Sjl139090 bp = (drmach_board_t *)id; 113025cf1a30Sjl139090 113125cf1a30Sjl139090 return ((drmach_domain.floating & (1 << bp->bnum)) ? 1 : 0); 113225cf1a30Sjl139090 } 113325cf1a30Sjl139090 113425cf1a30Sjl139090 static int 113525cf1a30Sjl139090 drmach_init(void) 113625cf1a30Sjl139090 { 113725cf1a30Sjl139090 dev_info_t *rdip; 113825cf1a30Sjl139090 int i, rv, len; 113925cf1a30Sjl139090 int *floating; 114025cf1a30Sjl139090 114125cf1a30Sjl139090 rw_init(&drmach_boards_rwlock, NULL, RW_DEFAULT, NULL); 114225cf1a30Sjl139090 114325cf1a30Sjl139090 drmach_boards = drmach_array_new(0, MAX_BOARDS - 1); 114425cf1a30Sjl139090 114525cf1a30Sjl139090 rdip = ddi_root_node(); 114625cf1a30Sjl139090 114725cf1a30Sjl139090 if (ddi_getproplen(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 114825cf1a30Sjl139090 "floating-boards", &len) != DDI_PROP_SUCCESS) { 114925cf1a30Sjl139090 cmn_err(CE_WARN, "Cannot get floating-boards proplen\n"); 115025cf1a30Sjl139090 } else { 115125cf1a30Sjl139090 floating = (int *)kmem_alloc(len, KM_SLEEP); 1152e98fafb9Sjl139090 rv = ddi_prop_op(DDI_DEV_T_ANY, rdip, PROP_LEN_AND_VAL_BUF, 1153e98fafb9Sjl139090 DDI_PROP_DONTPASS, "floating-boards", (caddr_t)floating, 1154e98fafb9Sjl139090 &len); 115525cf1a30Sjl139090 if (rv != DDI_PROP_SUCCESS) { 115625cf1a30Sjl139090 cmn_err(CE_WARN, "Cannot get floating-boards prop\n"); 115725cf1a30Sjl139090 } else { 115825cf1a30Sjl139090 drmach_domain.floating = 0; 115925cf1a30Sjl139090 for (i = 0; i < len / sizeof (int); i++) { 116025cf1a30Sjl139090 drmach_domain.floating |= (1 << floating[i]); 116125cf1a30Sjl139090 } 116225cf1a30Sjl139090 } 116325cf1a30Sjl139090 kmem_free(floating, len); 116425cf1a30Sjl139090 } 116525cf1a30Sjl139090 drmach_domain.allow_dr = opl_check_dr_status(); 116625cf1a30Sjl139090 116725cf1a30Sjl139090 rdip = ddi_get_child(ddi_root_node()); 116825cf1a30Sjl139090 do { 116925cf1a30Sjl139090 int bnum; 117025cf1a30Sjl139090 drmachid_t id; 117125cf1a30Sjl139090 117225cf1a30Sjl139090 bnum = -1; 1173e98fafb9Sjl139090 bnum = ddi_getprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 1174e98fafb9Sjl139090 OBP_BOARDNUM, -1); 117525cf1a30Sjl139090 if (bnum == -1) 117625cf1a30Sjl139090 continue; 117725cf1a30Sjl139090 117825cf1a30Sjl139090 if (drmach_array_get(drmach_boards, bnum, &id) == -1) { 1179e98fafb9Sjl139090 cmn_err(CE_WARN, "Device node 0x%p has invalid " 118007d06da5SSurya Prakki "property value, %s=%d", (void *)rdip, 118107d06da5SSurya Prakki OBP_BOARDNUM, bnum); 118225cf1a30Sjl139090 goto error; 118325cf1a30Sjl139090 } else if (id == NULL) { 118425cf1a30Sjl139090 (void) drmach_board_new(bnum, 1); 118525cf1a30Sjl139090 } 118625cf1a30Sjl139090 } while ((rdip = ddi_get_next_sibling(rdip)) != NULL); 118725cf1a30Sjl139090 118825cf1a30Sjl139090 opl_hold_devtree(); 118925cf1a30Sjl139090 119025cf1a30Sjl139090 /* 119125cf1a30Sjl139090 * Initialize the IKP feature. 119225cf1a30Sjl139090 * 119325cf1a30Sjl139090 * This can be done only after DR has acquired a hold on all the 119425cf1a30Sjl139090 * device nodes that are interesting to IKP. 119525cf1a30Sjl139090 */ 119625cf1a30Sjl139090 if (opl_init_cfg() != 0) { 119725cf1a30Sjl139090 cmn_err(CE_WARN, "DR - IKP initialization failed"); 119825cf1a30Sjl139090 119925cf1a30Sjl139090 opl_release_devtree(); 120025cf1a30Sjl139090 120125cf1a30Sjl139090 goto error; 120225cf1a30Sjl139090 } 120325cf1a30Sjl139090 120425cf1a30Sjl139090 return (0); 120525cf1a30Sjl139090 error: 120625cf1a30Sjl139090 drmach_array_dispose(drmach_boards, drmach_board_dispose); 120725cf1a30Sjl139090 rw_destroy(&drmach_boards_rwlock); 120825cf1a30Sjl139090 return (ENXIO); 120925cf1a30Sjl139090 } 121025cf1a30Sjl139090 121125cf1a30Sjl139090 static void 121225cf1a30Sjl139090 drmach_fini(void) 121325cf1a30Sjl139090 { 121425cf1a30Sjl139090 rw_enter(&drmach_boards_rwlock, RW_WRITER); 121525cf1a30Sjl139090 drmach_array_dispose(drmach_boards, drmach_board_dispose); 121625cf1a30Sjl139090 drmach_boards = NULL; 121725cf1a30Sjl139090 rw_exit(&drmach_boards_rwlock); 121825cf1a30Sjl139090 121925cf1a30Sjl139090 /* 122025cf1a30Sjl139090 * Walk immediate children of the root devinfo node 122125cf1a30Sjl139090 * releasing holds acquired on branches in drmach_init() 122225cf1a30Sjl139090 */ 122325cf1a30Sjl139090 122425cf1a30Sjl139090 opl_release_devtree(); 122525cf1a30Sjl139090 122625cf1a30Sjl139090 rw_destroy(&drmach_boards_rwlock); 122725cf1a30Sjl139090 } 122825cf1a30Sjl139090 122925cf1a30Sjl139090 /* 123025cf1a30Sjl139090 * Each system board contains 2 Oberon PCI bridge and 123125cf1a30Sjl139090 * 1 CMUCH. 123225cf1a30Sjl139090 * Each oberon has 2 channels. 123325cf1a30Sjl139090 * Each channel has 2 pci-ex leaf. 123425cf1a30Sjl139090 * Each CMUCH has 1 pci bus. 123525cf1a30Sjl139090 * 123625cf1a30Sjl139090 * 123725cf1a30Sjl139090 * Device Path: 123825cf1a30Sjl139090 * /pci@<portid>,reg 123925cf1a30Sjl139090 * 124025cf1a30Sjl139090 * where 124125cf1a30Sjl139090 * portid[10] = 0 124225cf1a30Sjl139090 * portid[9:0] = LLEAF_ID[9:0] of the Oberon Channel 124325cf1a30Sjl139090 * 124425cf1a30Sjl139090 * LLEAF_ID[9:8] = 0 124525cf1a30Sjl139090 * LLEAF_ID[8:4] = LSB_ID[4:0] 124625cf1a30Sjl139090 * LLEAF_ID[3:1] = IO Channel#[2:0] (0,1,2,3 for Oberon) 124725cf1a30Sjl139090 * channel 4 is pcicmu 124825cf1a30Sjl139090 * LLEAF_ID[0] = PCI Leaf Number (0 for leaf-A, 1 for leaf-B) 124925cf1a30Sjl139090 * 125025cf1a30Sjl139090 * Properties: 125125cf1a30Sjl139090 * name = pci 125225cf1a30Sjl139090 * device_type = "pciex" 125325cf1a30Sjl139090 * board# = LSBID 125425cf1a30Sjl139090 * reg = int32 * 2, Oberon CSR space of the leaf and the UBC space 125525cf1a30Sjl139090 * portid = Jupiter Bus Device ID ((LSB_ID << 3)|pciport#) 125625cf1a30Sjl139090 */ 125725cf1a30Sjl139090 125825cf1a30Sjl139090 static sbd_error_t * 125925cf1a30Sjl139090 drmach_io_new(drmach_device_t *proto, drmachid_t *idp) 126025cf1a30Sjl139090 { 126125cf1a30Sjl139090 drmach_io_t *ip; 126225cf1a30Sjl139090 126325cf1a30Sjl139090 int portid; 126425cf1a30Sjl139090 126525cf1a30Sjl139090 portid = proto->portid; 126625cf1a30Sjl139090 ASSERT(portid != -1); 126725cf1a30Sjl139090 proto->unum = portid & (MAX_IO_UNITS_PER_BOARD - 1); 126825cf1a30Sjl139090 126925cf1a30Sjl139090 ip = kmem_zalloc(sizeof (drmach_io_t), KM_SLEEP); 127025cf1a30Sjl139090 bcopy(proto, &ip->dev, sizeof (ip->dev)); 127125cf1a30Sjl139090 ip->dev.node = drmach_node_dup(proto->node); 127225cf1a30Sjl139090 ip->dev.cm.isa = (void *)drmach_io_new; 127325cf1a30Sjl139090 ip->dev.cm.dispose = drmach_io_dispose; 127425cf1a30Sjl139090 ip->dev.cm.release = drmach_io_release; 127525cf1a30Sjl139090 ip->dev.cm.status = drmach_io_status; 127625cf1a30Sjl139090 ip->channel = (portid >> 1) & 0x7; 127725cf1a30Sjl139090 ip->leaf = (portid & 0x1); 127825cf1a30Sjl139090 127907d06da5SSurya Prakki (void) snprintf(ip->dev.cm.name, sizeof (ip->dev.cm.name), "%s%d", 128025cf1a30Sjl139090 ip->dev.type, ip->dev.unum); 128125cf1a30Sjl139090 128225cf1a30Sjl139090 *idp = (drmachid_t)ip; 128325cf1a30Sjl139090 return (NULL); 128425cf1a30Sjl139090 } 128525cf1a30Sjl139090 128625cf1a30Sjl139090 128725cf1a30Sjl139090 static void 128825cf1a30Sjl139090 drmach_io_dispose(drmachid_t id) 128925cf1a30Sjl139090 { 129025cf1a30Sjl139090 drmach_io_t *self; 129125cf1a30Sjl139090 129225cf1a30Sjl139090 ASSERT(DRMACH_IS_IO_ID(id)); 129325cf1a30Sjl139090 129425cf1a30Sjl139090 self = id; 129525cf1a30Sjl139090 if (self->dev.node) 129625cf1a30Sjl139090 drmach_node_dispose(self->dev.node); 129725cf1a30Sjl139090 129825cf1a30Sjl139090 kmem_free(self, sizeof (*self)); 129925cf1a30Sjl139090 } 130025cf1a30Sjl139090 130125cf1a30Sjl139090 /*ARGSUSED*/ 130225cf1a30Sjl139090 sbd_error_t * 130325cf1a30Sjl139090 drmach_pre_op(int cmd, drmachid_t id, drmach_opts_t *opts) 130425cf1a30Sjl139090 { 130525cf1a30Sjl139090 drmach_board_t *bp = (drmach_board_t *)id; 130625cf1a30Sjl139090 sbd_error_t *err = NULL; 130725cf1a30Sjl139090 130825cf1a30Sjl139090 /* allow status and ncm operations to always succeed */ 130925cf1a30Sjl139090 if ((cmd == SBD_CMD_STATUS) || (cmd == SBD_CMD_GETNCM)) { 131025cf1a30Sjl139090 return (NULL); 131125cf1a30Sjl139090 } 131225cf1a30Sjl139090 131325cf1a30Sjl139090 /* check all other commands for the required option string */ 131425cf1a30Sjl139090 131525cf1a30Sjl139090 if ((opts->size > 0) && (opts->copts != NULL)) { 131625cf1a30Sjl139090 131725cf1a30Sjl139090 DRMACH_PR("platform options: %s\n", opts->copts); 131825cf1a30Sjl139090 131925cf1a30Sjl139090 if (strstr(opts->copts, "opldr") == NULL) { 132025cf1a30Sjl139090 err = drerr_new(1, EOPL_SUPPORT, NULL); 132125cf1a30Sjl139090 } 132225cf1a30Sjl139090 } else { 132325cf1a30Sjl139090 err = drerr_new(1, EOPL_SUPPORT, NULL); 132425cf1a30Sjl139090 } 132525cf1a30Sjl139090 132625cf1a30Sjl139090 if (!err && id && DRMACH_IS_BOARD_ID(id)) { 132725cf1a30Sjl139090 switch (cmd) { 132825cf1a30Sjl139090 case SBD_CMD_TEST: 132925cf1a30Sjl139090 case SBD_CMD_STATUS: 133025cf1a30Sjl139090 case SBD_CMD_GETNCM: 133125cf1a30Sjl139090 break; 133225cf1a30Sjl139090 case SBD_CMD_CONNECT: 133325cf1a30Sjl139090 if (bp->connected) 133425cf1a30Sjl139090 err = drerr_new(0, ESBD_STATE, NULL); 133525cf1a30Sjl139090 else if (!drmach_domain.allow_dr) 1336e98fafb9Sjl139090 err = drerr_new(1, EOPL_SUPPORT, NULL); 133725cf1a30Sjl139090 break; 133825cf1a30Sjl139090 case SBD_CMD_DISCONNECT: 133925cf1a30Sjl139090 if (!bp->connected) 134025cf1a30Sjl139090 err = drerr_new(0, ESBD_STATE, NULL); 134125cf1a30Sjl139090 else if (!drmach_domain.allow_dr) 1342e98fafb9Sjl139090 err = drerr_new(1, EOPL_SUPPORT, NULL); 134325cf1a30Sjl139090 break; 134425cf1a30Sjl139090 default: 134525cf1a30Sjl139090 if (!drmach_domain.allow_dr) 1346e98fafb9Sjl139090 err = drerr_new(1, EOPL_SUPPORT, NULL); 134725cf1a30Sjl139090 break; 134825cf1a30Sjl139090 134925cf1a30Sjl139090 } 135025cf1a30Sjl139090 } 135125cf1a30Sjl139090 135225cf1a30Sjl139090 return (err); 135325cf1a30Sjl139090 } 135425cf1a30Sjl139090 135525cf1a30Sjl139090 /*ARGSUSED*/ 135625cf1a30Sjl139090 sbd_error_t * 135725cf1a30Sjl139090 drmach_post_op(int cmd, drmachid_t id, drmach_opts_t *opts) 135825cf1a30Sjl139090 { 135925cf1a30Sjl139090 return (NULL); 136025cf1a30Sjl139090 } 136125cf1a30Sjl139090 136225cf1a30Sjl139090 sbd_error_t * 136325cf1a30Sjl139090 drmach_board_assign(int bnum, drmachid_t *id) 136425cf1a30Sjl139090 { 136525cf1a30Sjl139090 sbd_error_t *err = NULL; 136625cf1a30Sjl139090 136725cf1a30Sjl139090 rw_enter(&drmach_boards_rwlock, RW_WRITER); 136825cf1a30Sjl139090 136925cf1a30Sjl139090 if (drmach_array_get(drmach_boards, bnum, id) == -1) { 137025cf1a30Sjl139090 err = drerr_new(1, EOPL_BNUM, "%d", bnum); 137125cf1a30Sjl139090 } else { 137225cf1a30Sjl139090 drmach_board_t *bp; 137325cf1a30Sjl139090 137425cf1a30Sjl139090 if (*id) 137525cf1a30Sjl139090 rw_downgrade(&drmach_boards_rwlock); 137625cf1a30Sjl139090 137725cf1a30Sjl139090 bp = *id; 137825cf1a30Sjl139090 if (!(*id)) 137925cf1a30Sjl139090 bp = *id = 138025cf1a30Sjl139090 (drmachid_t)drmach_board_new(bnum, 0); 138125cf1a30Sjl139090 bp->assigned = 1; 138225cf1a30Sjl139090 } 138325cf1a30Sjl139090 138425cf1a30Sjl139090 rw_exit(&drmach_boards_rwlock); 138525cf1a30Sjl139090 138625cf1a30Sjl139090 return (err); 138725cf1a30Sjl139090 } 138825cf1a30Sjl139090 138925cf1a30Sjl139090 /*ARGSUSED*/ 139025cf1a30Sjl139090 sbd_error_t * 139125cf1a30Sjl139090 drmach_board_connect(drmachid_t id, drmach_opts_t *opts) 139225cf1a30Sjl139090 { 1393e98fafb9Sjl139090 extern int cpu_alljupiter; 139425cf1a30Sjl139090 drmach_board_t *obj = (drmach_board_t *)id; 1395e98fafb9Sjl139090 unsigned cpu_impl; 139625cf1a30Sjl139090 139725cf1a30Sjl139090 if (!DRMACH_IS_BOARD_ID(id)) 139825cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 139925cf1a30Sjl139090 1400e98fafb9Sjl139090 if (opl_probe_sb(obj->bnum, &cpu_impl) != 0) 14018eafe49bSbm42561 return (drerr_new(1, EOPL_PROBE, NULL)); 140225cf1a30Sjl139090 1403e98fafb9Sjl139090 if (cpu_alljupiter) { 14048a040953Swh31274 if (cpu_impl & (1 << OLYMPUS_C_IMPL)) { 14058a040953Swh31274 (void) opl_unprobe_sb(obj->bnum); 1406e98fafb9Sjl139090 return (drerr_new(1, EOPL_MIXED_CPU, NULL)); 1407e98fafb9Sjl139090 } 14088a040953Swh31274 } 1409e98fafb9Sjl139090 141025cf1a30Sjl139090 (void) prom_attach_notice(obj->bnum); 141125cf1a30Sjl139090 141225cf1a30Sjl139090 drmach_setup_core_info(obj); 141325cf1a30Sjl139090 141425cf1a30Sjl139090 obj->connected = 1; 141525cf1a30Sjl139090 141625cf1a30Sjl139090 return (NULL); 141725cf1a30Sjl139090 } 141825cf1a30Sjl139090 141925cf1a30Sjl139090 static int drmach_cache_flush_flag[NCPU]; 142025cf1a30Sjl139090 142125cf1a30Sjl139090 /*ARGSUSED*/ 142225cf1a30Sjl139090 static void 142325cf1a30Sjl139090 drmach_flush_cache(uint64_t id, uint64_t dummy) 142425cf1a30Sjl139090 { 142525cf1a30Sjl139090 extern void cpu_flush_ecache(void); 142625cf1a30Sjl139090 142725cf1a30Sjl139090 cpu_flush_ecache(); 142825cf1a30Sjl139090 drmach_cache_flush_flag[id] = 0; 142925cf1a30Sjl139090 } 143025cf1a30Sjl139090 143125cf1a30Sjl139090 static void 143225cf1a30Sjl139090 drmach_flush_all() 143325cf1a30Sjl139090 { 143425cf1a30Sjl139090 cpuset_t xc_cpuset; 143525cf1a30Sjl139090 int i; 143625cf1a30Sjl139090 143725cf1a30Sjl139090 xc_cpuset = cpu_ready_set; 143825cf1a30Sjl139090 for (i = 0; i < NCPU; i++) { 143925cf1a30Sjl139090 if (CPU_IN_SET(xc_cpuset, i)) { 144025cf1a30Sjl139090 drmach_cache_flush_flag[i] = 1; 144125cf1a30Sjl139090 xc_one(i, drmach_flush_cache, i, 0); 144225cf1a30Sjl139090 while (drmach_cache_flush_flag[i]) { 144325cf1a30Sjl139090 DELAY(1000); 144425cf1a30Sjl139090 } 144525cf1a30Sjl139090 } 144625cf1a30Sjl139090 } 144725cf1a30Sjl139090 } 144825cf1a30Sjl139090 144925cf1a30Sjl139090 static int 145025cf1a30Sjl139090 drmach_disconnect_cpus(drmach_board_t *bp) 145125cf1a30Sjl139090 { 145225cf1a30Sjl139090 int i, bnum; 145325cf1a30Sjl139090 145425cf1a30Sjl139090 bnum = bp->bnum; 145525cf1a30Sjl139090 145625cf1a30Sjl139090 for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) { 145725cf1a30Sjl139090 if (bp->cores[i].core_present) { 145825cf1a30Sjl139090 if (bp->cores[i].core_started) 145925cf1a30Sjl139090 return (-1); 146025cf1a30Sjl139090 if (bp->cores[i].core_hotadded) { 1461e98fafb9Sjl139090 if (drmach_add_remove_cpu(bnum, i, 1462e98fafb9Sjl139090 HOTREMOVE_CPU)) { 1463e98fafb9Sjl139090 cmn_err(CE_WARN, "Failed to remove " 1464e98fafb9Sjl139090 "CMP %d on board %d\n", i, bnum); 146525cf1a30Sjl139090 return (-1); 146625cf1a30Sjl139090 } 146725cf1a30Sjl139090 } 146825cf1a30Sjl139090 } 146925cf1a30Sjl139090 } 147025cf1a30Sjl139090 return (0); 147125cf1a30Sjl139090 } 147225cf1a30Sjl139090 147325cf1a30Sjl139090 /*ARGSUSED*/ 147425cf1a30Sjl139090 sbd_error_t * 147525cf1a30Sjl139090 drmach_board_disconnect(drmachid_t id, drmach_opts_t *opts) 147625cf1a30Sjl139090 { 147725cf1a30Sjl139090 drmach_board_t *obj; 147825cf1a30Sjl139090 int rv = 0; 147925cf1a30Sjl139090 sbd_error_t *err = NULL; 148025cf1a30Sjl139090 1481ddf95635Sbm42561 if (DRMACH_NULL_ID(id)) 1482ddf95635Sbm42561 return (NULL); 148325cf1a30Sjl139090 148425cf1a30Sjl139090 if (!DRMACH_IS_BOARD_ID(id)) 148525cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 148625cf1a30Sjl139090 148725cf1a30Sjl139090 obj = (drmach_board_t *)id; 148825cf1a30Sjl139090 148925cf1a30Sjl139090 if (drmach_disconnect_cpus(obj)) { 14908eafe49bSbm42561 err = drerr_new(1, EOPL_DEPROBE, obj->cm.name); 149125cf1a30Sjl139090 return (err); 149225cf1a30Sjl139090 } 149325cf1a30Sjl139090 149425cf1a30Sjl139090 rv = opl_unprobe_sb(obj->bnum); 149525cf1a30Sjl139090 149625cf1a30Sjl139090 if (rv == 0) { 149707d06da5SSurya Prakki (void) prom_detach_notice(obj->bnum); 149825cf1a30Sjl139090 obj->connected = 0; 149925cf1a30Sjl139090 150025cf1a30Sjl139090 } else 15018eafe49bSbm42561 err = drerr_new(1, EOPL_DEPROBE, obj->cm.name); 150225cf1a30Sjl139090 150325cf1a30Sjl139090 return (err); 150425cf1a30Sjl139090 } 150525cf1a30Sjl139090 150625cf1a30Sjl139090 static int 150725cf1a30Sjl139090 drmach_get_portid(drmach_node_t *np) 150825cf1a30Sjl139090 { 150925cf1a30Sjl139090 int portid; 151025cf1a30Sjl139090 char type[OBP_MAXPROPNAME]; 151125cf1a30Sjl139090 151225cf1a30Sjl139090 if (np->n_getprop(np, "portid", &portid, sizeof (portid)) == 0) 151325cf1a30Sjl139090 return (portid); 151425cf1a30Sjl139090 151525cf1a30Sjl139090 /* 151625cf1a30Sjl139090 * Get the device_type property to see if we should 151725cf1a30Sjl139090 * continue processing this node. 151825cf1a30Sjl139090 */ 151925cf1a30Sjl139090 if (np->n_getprop(np, "device_type", &type, sizeof (type)) != 0) 152025cf1a30Sjl139090 return (-1); 152125cf1a30Sjl139090 152225cf1a30Sjl139090 if (strcmp(type, OPL_CPU_NODE) == 0) { 152325cf1a30Sjl139090 /* 152425cf1a30Sjl139090 * We return cpuid because it has no portid 152525cf1a30Sjl139090 */ 152625cf1a30Sjl139090 if (np->n_getprop(np, "cpuid", &portid, sizeof (portid)) == 0) 152725cf1a30Sjl139090 return (portid); 152825cf1a30Sjl139090 } 152925cf1a30Sjl139090 153025cf1a30Sjl139090 return (-1); 153125cf1a30Sjl139090 } 153225cf1a30Sjl139090 153325cf1a30Sjl139090 /* 153425cf1a30Sjl139090 * This is a helper function to determine if a given 153525cf1a30Sjl139090 * node should be considered for a dr operation according 153625cf1a30Sjl139090 * to predefined dr type nodes and the node's name. 153725cf1a30Sjl139090 * Formal Parameter : The name of a device node. 153825cf1a30Sjl139090 * Return Value: -1, name does not map to a valid dr type. 153925cf1a30Sjl139090 * A value greater or equal to 0, name is a valid dr type. 154025cf1a30Sjl139090 */ 154125cf1a30Sjl139090 static int 154225cf1a30Sjl139090 drmach_name2type_idx(char *name) 154325cf1a30Sjl139090 { 154425cf1a30Sjl139090 int index, ntypes; 154525cf1a30Sjl139090 154625cf1a30Sjl139090 if (name == NULL) 154725cf1a30Sjl139090 return (-1); 154825cf1a30Sjl139090 154925cf1a30Sjl139090 /* 155025cf1a30Sjl139090 * Determine how many possible types are currently supported 155125cf1a30Sjl139090 * for dr. 155225cf1a30Sjl139090 */ 155325cf1a30Sjl139090 ntypes = sizeof (drmach_name2type) / sizeof (drmach_name2type[0]); 155425cf1a30Sjl139090 155525cf1a30Sjl139090 /* Determine if the node's name correspond to a predefined type. */ 155625cf1a30Sjl139090 for (index = 0; index < ntypes; index++) { 155725cf1a30Sjl139090 if (strcmp(drmach_name2type[index].name, name) == 0) 155825cf1a30Sjl139090 /* The node is an allowed type for dr. */ 155925cf1a30Sjl139090 return (index); 156025cf1a30Sjl139090 } 156125cf1a30Sjl139090 156225cf1a30Sjl139090 /* 156325cf1a30Sjl139090 * If the name of the node does not map to any of the 156425cf1a30Sjl139090 * types in the array drmach_name2type then the node is not of 156525cf1a30Sjl139090 * interest to dr. 156625cf1a30Sjl139090 */ 156725cf1a30Sjl139090 return (-1); 156825cf1a30Sjl139090 } 156925cf1a30Sjl139090 157025cf1a30Sjl139090 /* 157125cf1a30Sjl139090 * there is some complication on OPL: 157225cf1a30Sjl139090 * - pseudo-mc nodes do not have portid property 157325cf1a30Sjl139090 * - portid[9:5] of cmp node is LSB #, portid[7:3] of pci is LSB# 157425cf1a30Sjl139090 * - cmp has board# 157525cf1a30Sjl139090 * - core and cpu nodes do not have portid and board# properties 157625cf1a30Sjl139090 * starcat uses portid to derive the board# but that does not work 157725cf1a30Sjl139090 * for us. starfire reads board# property to filter the devices. 157825cf1a30Sjl139090 * That does not work either. So for these specific device, 157925cf1a30Sjl139090 * we use specific hard coded methods to get the board# - 158025cf1a30Sjl139090 * cpu: LSB# = CPUID[9:5] 158125cf1a30Sjl139090 */ 158225cf1a30Sjl139090 158325cf1a30Sjl139090 static int 158425cf1a30Sjl139090 drmach_board_find_devices_cb(drmach_node_walk_args_t *args) 158525cf1a30Sjl139090 { 158625cf1a30Sjl139090 drmach_node_t *node = args->node; 158725cf1a30Sjl139090 drmach_board_cb_data_t *data = args->data; 158825cf1a30Sjl139090 drmach_board_t *obj = data->obj; 158925cf1a30Sjl139090 159025cf1a30Sjl139090 int rv, portid; 159125cf1a30Sjl139090 int bnum; 159225cf1a30Sjl139090 drmachid_t id; 159325cf1a30Sjl139090 drmach_device_t *device; 159425cf1a30Sjl139090 char name[OBP_MAXDRVNAME]; 159525cf1a30Sjl139090 159625cf1a30Sjl139090 portid = drmach_get_portid(node); 159725cf1a30Sjl139090 /* 159825cf1a30Sjl139090 * core, cpu and pseudo-mc do not have portid 159925cf1a30Sjl139090 * we use cpuid as the portid of the cpu node 160025cf1a30Sjl139090 * for pseudo-mc, we do not use portid info. 160125cf1a30Sjl139090 */ 160225cf1a30Sjl139090 160325cf1a30Sjl139090 rv = node->n_getprop(node, "name", name, OBP_MAXDRVNAME); 160425cf1a30Sjl139090 if (rv) 160525cf1a30Sjl139090 return (0); 160625cf1a30Sjl139090 160725cf1a30Sjl139090 160825cf1a30Sjl139090 rv = node->n_getprop(node, OBP_BOARDNUM, &bnum, sizeof (bnum)); 160925cf1a30Sjl139090 161025cf1a30Sjl139090 if (rv) { 161125cf1a30Sjl139090 /* 161225cf1a30Sjl139090 * cpu does not have board# property. We use 161325cf1a30Sjl139090 * CPUID[9:5] 161425cf1a30Sjl139090 */ 161525cf1a30Sjl139090 if (strcmp("cpu", name) == 0) { 161625cf1a30Sjl139090 bnum = (portid >> 5) & 0x1f; 161725cf1a30Sjl139090 } else 161825cf1a30Sjl139090 return (0); 161925cf1a30Sjl139090 } 162025cf1a30Sjl139090 162125cf1a30Sjl139090 162225cf1a30Sjl139090 if (bnum != obj->bnum) 162325cf1a30Sjl139090 return (0); 162425cf1a30Sjl139090 162525cf1a30Sjl139090 if (drmach_name2type_idx(name) < 0) { 162625cf1a30Sjl139090 return (0); 162725cf1a30Sjl139090 } 162825cf1a30Sjl139090 162925cf1a30Sjl139090 /* 163025cf1a30Sjl139090 * Create a device data structure from this node data. 163125cf1a30Sjl139090 * The call may yield nothing if the node is not of interest 163225cf1a30Sjl139090 * to drmach. 163325cf1a30Sjl139090 */ 163425cf1a30Sjl139090 data->err = drmach_device_new(node, obj, portid, &id); 163525cf1a30Sjl139090 if (data->err) 163625cf1a30Sjl139090 return (-1); 163725cf1a30Sjl139090 else if (!id) { 163825cf1a30Sjl139090 /* 163925cf1a30Sjl139090 * drmach_device_new examined the node we passed in 164025cf1a30Sjl139090 * and determined that it was one not of interest to 164125cf1a30Sjl139090 * drmach. So, it is skipped. 164225cf1a30Sjl139090 */ 164325cf1a30Sjl139090 return (0); 164425cf1a30Sjl139090 } 164525cf1a30Sjl139090 164625cf1a30Sjl139090 rv = drmach_array_set(obj->devices, data->ndevs++, id); 164725cf1a30Sjl139090 if (rv) { 164825cf1a30Sjl139090 data->err = DRMACH_INTERNAL_ERROR(); 164925cf1a30Sjl139090 return (-1); 165025cf1a30Sjl139090 } 165125cf1a30Sjl139090 device = id; 165225cf1a30Sjl139090 165325cf1a30Sjl139090 data->err = (*data->found)(data->a, device->type, device->unum, id); 165425cf1a30Sjl139090 return (data->err == NULL ? 0 : -1); 165525cf1a30Sjl139090 } 165625cf1a30Sjl139090 165725cf1a30Sjl139090 sbd_error_t * 165825cf1a30Sjl139090 drmach_board_find_devices(drmachid_t id, void *a, 165925cf1a30Sjl139090 sbd_error_t *(*found)(void *a, const char *, int, drmachid_t)) 166025cf1a30Sjl139090 { 166125cf1a30Sjl139090 drmach_board_t *bp = (drmach_board_t *)id; 166225cf1a30Sjl139090 sbd_error_t *err; 166325cf1a30Sjl139090 int max_devices; 166425cf1a30Sjl139090 int rv; 166525cf1a30Sjl139090 drmach_board_cb_data_t data; 166625cf1a30Sjl139090 166725cf1a30Sjl139090 166825cf1a30Sjl139090 if (!DRMACH_IS_BOARD_ID(id)) 166925cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 167025cf1a30Sjl139090 167125cf1a30Sjl139090 max_devices = MAX_CPU_UNITS_PER_BOARD; 167225cf1a30Sjl139090 max_devices += MAX_MEM_UNITS_PER_BOARD; 167325cf1a30Sjl139090 max_devices += MAX_IO_UNITS_PER_BOARD; 167425cf1a30Sjl139090 167525cf1a30Sjl139090 bp->devices = drmach_array_new(0, max_devices); 167625cf1a30Sjl139090 167725cf1a30Sjl139090 if (bp->tree == NULL) 167825cf1a30Sjl139090 bp->tree = drmach_node_new(); 167925cf1a30Sjl139090 168025cf1a30Sjl139090 data.obj = bp; 168125cf1a30Sjl139090 data.ndevs = 0; 168225cf1a30Sjl139090 data.found = found; 168325cf1a30Sjl139090 data.a = a; 168425cf1a30Sjl139090 data.err = NULL; 168525cf1a30Sjl139090 168625cf1a30Sjl139090 rv = drmach_node_walk(bp->tree, &data, drmach_board_find_devices_cb); 168725cf1a30Sjl139090 if (rv == 0) 168825cf1a30Sjl139090 err = NULL; 168925cf1a30Sjl139090 else { 169025cf1a30Sjl139090 drmach_array_dispose(bp->devices, drmach_device_dispose); 169125cf1a30Sjl139090 bp->devices = NULL; 169225cf1a30Sjl139090 169325cf1a30Sjl139090 if (data.err) 169425cf1a30Sjl139090 err = data.err; 169525cf1a30Sjl139090 else 169625cf1a30Sjl139090 err = DRMACH_INTERNAL_ERROR(); 169725cf1a30Sjl139090 } 169825cf1a30Sjl139090 169925cf1a30Sjl139090 return (err); 170025cf1a30Sjl139090 } 170125cf1a30Sjl139090 170225cf1a30Sjl139090 int 170325cf1a30Sjl139090 drmach_board_lookup(int bnum, drmachid_t *id) 170425cf1a30Sjl139090 { 170525cf1a30Sjl139090 int rv = 0; 170625cf1a30Sjl139090 170725cf1a30Sjl139090 rw_enter(&drmach_boards_rwlock, RW_READER); 170825cf1a30Sjl139090 if (drmach_array_get(drmach_boards, bnum, id)) { 170925cf1a30Sjl139090 *id = 0; 171025cf1a30Sjl139090 rv = -1; 171125cf1a30Sjl139090 } 171225cf1a30Sjl139090 rw_exit(&drmach_boards_rwlock); 171325cf1a30Sjl139090 return (rv); 171425cf1a30Sjl139090 } 171525cf1a30Sjl139090 171625cf1a30Sjl139090 sbd_error_t * 171725cf1a30Sjl139090 drmach_board_name(int bnum, char *buf, int buflen) 171825cf1a30Sjl139090 { 171907d06da5SSurya Prakki (void) snprintf(buf, buflen, "SB%d", bnum); 172025cf1a30Sjl139090 return (NULL); 172125cf1a30Sjl139090 } 172225cf1a30Sjl139090 172325cf1a30Sjl139090 sbd_error_t * 172425cf1a30Sjl139090 drmach_board_poweroff(drmachid_t id) 172525cf1a30Sjl139090 { 172625cf1a30Sjl139090 drmach_board_t *bp; 172725cf1a30Sjl139090 sbd_error_t *err; 172825cf1a30Sjl139090 drmach_status_t stat; 172925cf1a30Sjl139090 1730ddf95635Sbm42561 if (DRMACH_NULL_ID(id)) 1731ddf95635Sbm42561 return (NULL); 1732ddf95635Sbm42561 173325cf1a30Sjl139090 if (!DRMACH_IS_BOARD_ID(id)) 173425cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 173525cf1a30Sjl139090 bp = id; 173625cf1a30Sjl139090 173725cf1a30Sjl139090 err = drmach_board_status(id, &stat); 173825cf1a30Sjl139090 173925cf1a30Sjl139090 if (!err) { 174025cf1a30Sjl139090 if (stat.configured || stat.busy) 174125cf1a30Sjl139090 err = drerr_new(0, EOPL_CONFIGBUSY, bp->cm.name); 174225cf1a30Sjl139090 else { 174325cf1a30Sjl139090 bp->powered = 0; 174425cf1a30Sjl139090 } 174525cf1a30Sjl139090 } 174625cf1a30Sjl139090 return (err); 174725cf1a30Sjl139090 } 174825cf1a30Sjl139090 174925cf1a30Sjl139090 sbd_error_t * 175025cf1a30Sjl139090 drmach_board_poweron(drmachid_t id) 175125cf1a30Sjl139090 { 175225cf1a30Sjl139090 drmach_board_t *bp; 175325cf1a30Sjl139090 175425cf1a30Sjl139090 if (!DRMACH_IS_BOARD_ID(id)) 175525cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 175625cf1a30Sjl139090 bp = id; 175725cf1a30Sjl139090 175825cf1a30Sjl139090 bp->powered = 1; 175925cf1a30Sjl139090 176025cf1a30Sjl139090 return (NULL); 176125cf1a30Sjl139090 } 176225cf1a30Sjl139090 176325cf1a30Sjl139090 static sbd_error_t * 176425cf1a30Sjl139090 drmach_board_release(drmachid_t id) 176525cf1a30Sjl139090 { 176625cf1a30Sjl139090 if (!DRMACH_IS_BOARD_ID(id)) 176725cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 176825cf1a30Sjl139090 return (NULL); 176925cf1a30Sjl139090 } 177025cf1a30Sjl139090 177125cf1a30Sjl139090 /*ARGSUSED*/ 177225cf1a30Sjl139090 sbd_error_t * 177325cf1a30Sjl139090 drmach_board_test(drmachid_t id, drmach_opts_t *opts, int force) 177425cf1a30Sjl139090 { 177525cf1a30Sjl139090 return (NULL); 177625cf1a30Sjl139090 } 177725cf1a30Sjl139090 177825cf1a30Sjl139090 sbd_error_t * 177925cf1a30Sjl139090 drmach_board_unassign(drmachid_t id) 178025cf1a30Sjl139090 { 178125cf1a30Sjl139090 drmach_board_t *bp; 178225cf1a30Sjl139090 sbd_error_t *err; 178325cf1a30Sjl139090 drmach_status_t stat; 178425cf1a30Sjl139090 1785ddf95635Sbm42561 if (DRMACH_NULL_ID(id)) 1786ddf95635Sbm42561 return (NULL); 178725cf1a30Sjl139090 178825cf1a30Sjl139090 if (!DRMACH_IS_BOARD_ID(id)) { 178925cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 179025cf1a30Sjl139090 } 179125cf1a30Sjl139090 bp = id; 179225cf1a30Sjl139090 179325cf1a30Sjl139090 rw_enter(&drmach_boards_rwlock, RW_WRITER); 179425cf1a30Sjl139090 179525cf1a30Sjl139090 err = drmach_board_status(id, &stat); 179625cf1a30Sjl139090 if (err) { 179725cf1a30Sjl139090 rw_exit(&drmach_boards_rwlock); 179825cf1a30Sjl139090 return (err); 179925cf1a30Sjl139090 } 180025cf1a30Sjl139090 if (stat.configured || stat.busy) { 180125cf1a30Sjl139090 err = drerr_new(0, EOPL_CONFIGBUSY, bp->cm.name); 180225cf1a30Sjl139090 } else { 180325cf1a30Sjl139090 if (drmach_array_set(drmach_boards, bp->bnum, 0) != 0) 180425cf1a30Sjl139090 err = DRMACH_INTERNAL_ERROR(); 180525cf1a30Sjl139090 else 180625cf1a30Sjl139090 drmach_board_dispose(bp); 180725cf1a30Sjl139090 } 180825cf1a30Sjl139090 rw_exit(&drmach_boards_rwlock); 180925cf1a30Sjl139090 return (err); 181025cf1a30Sjl139090 } 181125cf1a30Sjl139090 181225cf1a30Sjl139090 /* 181325cf1a30Sjl139090 * We have to do more on OPL - e.g. set up sram tte, read cpuid, strand id, 181425cf1a30Sjl139090 * implementation #, etc 181525cf1a30Sjl139090 */ 181625cf1a30Sjl139090 181725cf1a30Sjl139090 static sbd_error_t * 181825cf1a30Sjl139090 drmach_cpu_new(drmach_device_t *proto, drmachid_t *idp) 181925cf1a30Sjl139090 { 182025cf1a30Sjl139090 int portid; 182125cf1a30Sjl139090 drmach_cpu_t *cp = NULL; 182225cf1a30Sjl139090 182325cf1a30Sjl139090 /* portid is CPUID of the node */ 182425cf1a30Sjl139090 portid = proto->portid; 182525cf1a30Sjl139090 ASSERT(portid != -1); 182625cf1a30Sjl139090 182725cf1a30Sjl139090 /* unum = (CMP/CHIP ID) + (ON_BOARD_CORE_NUM * MAX_CMPID_PER_BOARD) */ 182825cf1a30Sjl139090 proto->unum = ((portid/OPL_MAX_CPUID_PER_CMP) & 182925cf1a30Sjl139090 (OPL_MAX_CMPID_PER_BOARD - 1)) + 183025cf1a30Sjl139090 ((portid & (OPL_MAX_CPUID_PER_CMP - 1)) * 183125cf1a30Sjl139090 (OPL_MAX_CMPID_PER_BOARD)); 183225cf1a30Sjl139090 183325cf1a30Sjl139090 cp = kmem_zalloc(sizeof (drmach_cpu_t), KM_SLEEP); 183425cf1a30Sjl139090 bcopy(proto, &cp->dev, sizeof (cp->dev)); 183525cf1a30Sjl139090 cp->dev.node = drmach_node_dup(proto->node); 183625cf1a30Sjl139090 cp->dev.cm.isa = (void *)drmach_cpu_new; 183725cf1a30Sjl139090 cp->dev.cm.dispose = drmach_cpu_dispose; 183825cf1a30Sjl139090 cp->dev.cm.release = drmach_cpu_release; 183925cf1a30Sjl139090 cp->dev.cm.status = drmach_cpu_status; 184025cf1a30Sjl139090 184107d06da5SSurya Prakki (void) snprintf(cp->dev.cm.name, sizeof (cp->dev.cm.name), "%s%d", 184225cf1a30Sjl139090 cp->dev.type, cp->dev.unum); 184325cf1a30Sjl139090 184425cf1a30Sjl139090 /* 184525cf1a30Sjl139090 * CPU ID representation 184625cf1a30Sjl139090 * CPUID[9:5] = SB# 184725cf1a30Sjl139090 * CPUID[4:3] = Chip# 184825cf1a30Sjl139090 * CPUID[2:1] = Core# (Only 2 core for OPL) 184925cf1a30Sjl139090 * CPUID[0:0] = Strand# 185025cf1a30Sjl139090 */ 185125cf1a30Sjl139090 185225cf1a30Sjl139090 /* 185325cf1a30Sjl139090 * reg property of the strand contains strand ID 185425cf1a30Sjl139090 * reg property of the parent node contains core ID 185525cf1a30Sjl139090 * We should use them. 185625cf1a30Sjl139090 */ 185725cf1a30Sjl139090 cp->cpuid = portid; 185825cf1a30Sjl139090 cp->sb = (portid >> 5) & 0x1f; 185925cf1a30Sjl139090 cp->chipid = (portid >> 3) & 0x3; 186025cf1a30Sjl139090 cp->coreid = (portid >> 1) & 0x3; 186125cf1a30Sjl139090 cp->strandid = portid & 0x1; 186225cf1a30Sjl139090 186325cf1a30Sjl139090 *idp = (drmachid_t)cp; 186425cf1a30Sjl139090 return (NULL); 186525cf1a30Sjl139090 } 186625cf1a30Sjl139090 186725cf1a30Sjl139090 186825cf1a30Sjl139090 static void 186925cf1a30Sjl139090 drmach_cpu_dispose(drmachid_t id) 187025cf1a30Sjl139090 { 187125cf1a30Sjl139090 drmach_cpu_t *self; 187225cf1a30Sjl139090 187325cf1a30Sjl139090 ASSERT(DRMACH_IS_CPU_ID(id)); 187425cf1a30Sjl139090 187525cf1a30Sjl139090 self = id; 187625cf1a30Sjl139090 if (self->dev.node) 187725cf1a30Sjl139090 drmach_node_dispose(self->dev.node); 187825cf1a30Sjl139090 187925cf1a30Sjl139090 kmem_free(self, sizeof (*self)); 188025cf1a30Sjl139090 } 188125cf1a30Sjl139090 188225cf1a30Sjl139090 static int 188325cf1a30Sjl139090 drmach_cpu_start(struct cpu *cp) 188425cf1a30Sjl139090 { 188525cf1a30Sjl139090 int cpuid = cp->cpu_id; 188625cf1a30Sjl139090 extern int restart_other_cpu(int); 188725cf1a30Sjl139090 188825cf1a30Sjl139090 ASSERT(MUTEX_HELD(&cpu_lock)); 188925cf1a30Sjl139090 ASSERT(cpunodes[cpuid].nodeid != (pnode_t)0); 189025cf1a30Sjl139090 189125cf1a30Sjl139090 cp->cpu_flags &= ~CPU_POWEROFF; 189225cf1a30Sjl139090 189325cf1a30Sjl139090 /* 189425cf1a30Sjl139090 * NOTE: restart_other_cpu pauses cpus during the 189525cf1a30Sjl139090 * slave cpu start. This helps to quiesce the 189625cf1a30Sjl139090 * bus traffic a bit which makes the tick sync 189725cf1a30Sjl139090 * routine in the prom more robust. 189825cf1a30Sjl139090 */ 189925cf1a30Sjl139090 DRMACH_PR("COLD START for cpu (%d)\n", cpuid); 190025cf1a30Sjl139090 190107d06da5SSurya Prakki (void) restart_other_cpu(cpuid); 190225cf1a30Sjl139090 190325cf1a30Sjl139090 return (0); 190425cf1a30Sjl139090 } 190525cf1a30Sjl139090 190625cf1a30Sjl139090 static sbd_error_t * 190725cf1a30Sjl139090 drmach_cpu_release(drmachid_t id) 190825cf1a30Sjl139090 { 190925cf1a30Sjl139090 if (!DRMACH_IS_CPU_ID(id)) 191025cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 191125cf1a30Sjl139090 191225cf1a30Sjl139090 return (NULL); 191325cf1a30Sjl139090 } 191425cf1a30Sjl139090 191525cf1a30Sjl139090 static sbd_error_t * 191625cf1a30Sjl139090 drmach_cpu_status(drmachid_t id, drmach_status_t *stat) 191725cf1a30Sjl139090 { 191825cf1a30Sjl139090 drmach_cpu_t *cp; 191925cf1a30Sjl139090 drmach_device_t *dp; 192025cf1a30Sjl139090 192125cf1a30Sjl139090 ASSERT(DRMACH_IS_CPU_ID(id)); 192225cf1a30Sjl139090 cp = (drmach_cpu_t *)id; 192325cf1a30Sjl139090 dp = &cp->dev; 192425cf1a30Sjl139090 192525cf1a30Sjl139090 stat->assigned = dp->bp->assigned; 192625cf1a30Sjl139090 stat->powered = dp->bp->powered; 192725cf1a30Sjl139090 mutex_enter(&cpu_lock); 192825cf1a30Sjl139090 stat->configured = (cpu_get(cp->cpuid) != NULL); 192925cf1a30Sjl139090 mutex_exit(&cpu_lock); 193025cf1a30Sjl139090 stat->busy = dp->busy; 193107d06da5SSurya Prakki (void) strncpy(stat->type, dp->type, sizeof (stat->type)); 193225cf1a30Sjl139090 stat->info[0] = '\0'; 193325cf1a30Sjl139090 193425cf1a30Sjl139090 return (NULL); 193525cf1a30Sjl139090 } 193625cf1a30Sjl139090 193725cf1a30Sjl139090 sbd_error_t * 193825cf1a30Sjl139090 drmach_cpu_disconnect(drmachid_t id) 193925cf1a30Sjl139090 { 194025cf1a30Sjl139090 194125cf1a30Sjl139090 if (!DRMACH_IS_CPU_ID(id)) 194225cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 194325cf1a30Sjl139090 194425cf1a30Sjl139090 return (NULL); 194525cf1a30Sjl139090 } 194625cf1a30Sjl139090 194725cf1a30Sjl139090 sbd_error_t * 194825cf1a30Sjl139090 drmach_cpu_get_id(drmachid_t id, processorid_t *cpuid) 194925cf1a30Sjl139090 { 195025cf1a30Sjl139090 drmach_cpu_t *cpu; 195125cf1a30Sjl139090 195225cf1a30Sjl139090 if (!DRMACH_IS_CPU_ID(id)) 195325cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 195425cf1a30Sjl139090 cpu = (drmach_cpu_t *)id; 195525cf1a30Sjl139090 195625cf1a30Sjl139090 /* get from cpu directly on OPL */ 195725cf1a30Sjl139090 *cpuid = cpu->cpuid; 195825cf1a30Sjl139090 return (NULL); 195925cf1a30Sjl139090 } 196025cf1a30Sjl139090 196125cf1a30Sjl139090 sbd_error_t * 196225cf1a30Sjl139090 drmach_cpu_get_impl(drmachid_t id, int *ip) 196325cf1a30Sjl139090 { 196425cf1a30Sjl139090 drmach_device_t *cpu; 196525cf1a30Sjl139090 drmach_node_t *np; 196625cf1a30Sjl139090 drmach_node_t pp; 196725cf1a30Sjl139090 int impl; 196825cf1a30Sjl139090 char type[OBP_MAXPROPNAME]; 196925cf1a30Sjl139090 197025cf1a30Sjl139090 if (!DRMACH_IS_CPU_ID(id)) 197125cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 197225cf1a30Sjl139090 197325cf1a30Sjl139090 cpu = id; 197425cf1a30Sjl139090 np = cpu->node; 197525cf1a30Sjl139090 197625cf1a30Sjl139090 if (np->get_parent(np, &pp) != 0) { 197725cf1a30Sjl139090 return (DRMACH_INTERNAL_ERROR()); 197825cf1a30Sjl139090 } 197925cf1a30Sjl139090 198025cf1a30Sjl139090 /* the parent should be core */ 198125cf1a30Sjl139090 198225cf1a30Sjl139090 if (pp.n_getprop(&pp, "device_type", &type, sizeof (type)) != 0) { 198325cf1a30Sjl139090 return (drerr_new(0, EOPL_GETPROP, NULL)); 198425cf1a30Sjl139090 } 198525cf1a30Sjl139090 198625cf1a30Sjl139090 if (strcmp(type, OPL_CORE_NODE) == 0) { 1987e98fafb9Sjl139090 if (pp.n_getprop(&pp, "implementation#", &impl, 1988e98fafb9Sjl139090 sizeof (impl)) != 0) { 198925cf1a30Sjl139090 return (drerr_new(0, EOPL_GETPROP, NULL)); 199025cf1a30Sjl139090 } 199125cf1a30Sjl139090 } else { 199225cf1a30Sjl139090 return (DRMACH_INTERNAL_ERROR()); 199325cf1a30Sjl139090 } 199425cf1a30Sjl139090 199525cf1a30Sjl139090 *ip = impl; 199625cf1a30Sjl139090 199725cf1a30Sjl139090 return (NULL); 199825cf1a30Sjl139090 } 199925cf1a30Sjl139090 200025cf1a30Sjl139090 sbd_error_t * 200125cf1a30Sjl139090 drmach_get_dip(drmachid_t id, dev_info_t **dip) 200225cf1a30Sjl139090 { 200325cf1a30Sjl139090 drmach_device_t *dp; 200425cf1a30Sjl139090 200525cf1a30Sjl139090 if (!DRMACH_IS_DEVICE_ID(id)) 200625cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 200725cf1a30Sjl139090 dp = id; 200825cf1a30Sjl139090 200925cf1a30Sjl139090 *dip = dp->node->n_getdip(dp->node); 201025cf1a30Sjl139090 return (NULL); 201125cf1a30Sjl139090 } 201225cf1a30Sjl139090 201325cf1a30Sjl139090 sbd_error_t * 201425cf1a30Sjl139090 drmach_io_is_attached(drmachid_t id, int *yes) 201525cf1a30Sjl139090 { 201625cf1a30Sjl139090 drmach_device_t *dp; 201725cf1a30Sjl139090 dev_info_t *dip; 201825cf1a30Sjl139090 int state; 201925cf1a30Sjl139090 202025cf1a30Sjl139090 if (!DRMACH_IS_IO_ID(id)) 202125cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 202225cf1a30Sjl139090 dp = id; 202325cf1a30Sjl139090 202425cf1a30Sjl139090 dip = dp->node->n_getdip(dp->node); 202525cf1a30Sjl139090 if (dip == NULL) { 202625cf1a30Sjl139090 *yes = 0; 202725cf1a30Sjl139090 return (NULL); 202825cf1a30Sjl139090 } 202925cf1a30Sjl139090 203025cf1a30Sjl139090 state = ddi_get_devstate(dip); 203125cf1a30Sjl139090 *yes = ((i_ddi_node_state(dip) >= DS_ATTACHED) || 203225cf1a30Sjl139090 (state == DDI_DEVSTATE_UP)); 203325cf1a30Sjl139090 203425cf1a30Sjl139090 return (NULL); 203525cf1a30Sjl139090 } 203625cf1a30Sjl139090 203725cf1a30Sjl139090 struct drmach_io_cb { 203825cf1a30Sjl139090 char *name; /* name of the node */ 203925cf1a30Sjl139090 int (*func)(dev_info_t *); 204025cf1a30Sjl139090 int rv; 204168ac2337Sjl139090 dev_info_t *dip; 204225cf1a30Sjl139090 }; 204325cf1a30Sjl139090 204425cf1a30Sjl139090 #define DRMACH_IO_POST_ATTACH 0 204525cf1a30Sjl139090 #define DRMACH_IO_PRE_RELEASE 1 204625cf1a30Sjl139090 204725cf1a30Sjl139090 static int 204825cf1a30Sjl139090 drmach_io_cb_check(dev_info_t *dip, void *arg) 204925cf1a30Sjl139090 { 205025cf1a30Sjl139090 struct drmach_io_cb *p = (struct drmach_io_cb *)arg; 205125cf1a30Sjl139090 char name[OBP_MAXDRVNAME]; 205225cf1a30Sjl139090 int len = OBP_MAXDRVNAME; 205325cf1a30Sjl139090 2054e98fafb9Sjl139090 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "name", 205525cf1a30Sjl139090 (caddr_t)name, &len) != DDI_PROP_SUCCESS) { 205625cf1a30Sjl139090 return (DDI_WALK_PRUNECHILD); 205725cf1a30Sjl139090 } 205825cf1a30Sjl139090 205925cf1a30Sjl139090 if (strcmp(name, p->name) == 0) { 206068ac2337Sjl139090 ndi_hold_devi(dip); 206168ac2337Sjl139090 p->dip = dip; 206225cf1a30Sjl139090 return (DDI_WALK_TERMINATE); 206325cf1a30Sjl139090 } 206425cf1a30Sjl139090 206525cf1a30Sjl139090 return (DDI_WALK_CONTINUE); 206625cf1a30Sjl139090 } 206725cf1a30Sjl139090 206825cf1a30Sjl139090 206925cf1a30Sjl139090 static int 207025cf1a30Sjl139090 drmach_console_ops(drmachid_t *id, int state) 207125cf1a30Sjl139090 { 207225cf1a30Sjl139090 drmach_io_t *obj = (drmach_io_t *)id; 207325cf1a30Sjl139090 struct drmach_io_cb arg; 207425cf1a30Sjl139090 int (*msudetp)(dev_info_t *); 207525cf1a30Sjl139090 int (*msuattp)(dev_info_t *); 207625cf1a30Sjl139090 dev_info_t *dip, *pdip; 207725cf1a30Sjl139090 int circ; 207825cf1a30Sjl139090 207925cf1a30Sjl139090 /* 4 is pcicmu channel */ 208025cf1a30Sjl139090 if (obj->channel != 4) 208125cf1a30Sjl139090 return (0); 208225cf1a30Sjl139090 208325cf1a30Sjl139090 arg.name = "serial"; 208425cf1a30Sjl139090 arg.func = NULL; 208525cf1a30Sjl139090 if (state == DRMACH_IO_PRE_RELEASE) { 208625cf1a30Sjl139090 msudetp = (int (*)(dev_info_t *)) 208725cf1a30Sjl139090 modgetsymvalue("oplmsu_dr_detach", 0); 208825cf1a30Sjl139090 if (msudetp != NULL) 208925cf1a30Sjl139090 arg.func = msudetp; 209025cf1a30Sjl139090 } else if (state == DRMACH_IO_POST_ATTACH) { 209125cf1a30Sjl139090 msuattp = (int (*)(dev_info_t *)) 209225cf1a30Sjl139090 modgetsymvalue("oplmsu_dr_attach", 0); 209325cf1a30Sjl139090 if (msuattp != NULL) 209425cf1a30Sjl139090 arg.func = msuattp; 209568ac2337Sjl139090 } else { 209625cf1a30Sjl139090 return (0); 209768ac2337Sjl139090 } 209825cf1a30Sjl139090 209925cf1a30Sjl139090 if (arg.func == NULL) { 210025cf1a30Sjl139090 return (0); 210125cf1a30Sjl139090 } 210225cf1a30Sjl139090 210325cf1a30Sjl139090 arg.rv = 0; 210468ac2337Sjl139090 arg.dip = NULL; 210525cf1a30Sjl139090 210625cf1a30Sjl139090 dip = obj->dev.node->n_getdip(obj->dev.node); 210725cf1a30Sjl139090 if (pdip = ddi_get_parent(dip)) { 210825cf1a30Sjl139090 ndi_hold_devi(pdip); 210925cf1a30Sjl139090 ndi_devi_enter(pdip, &circ); 211025cf1a30Sjl139090 } else { 211125cf1a30Sjl139090 /* this cannot happen unless something bad happens */ 211225cf1a30Sjl139090 return (-1); 211325cf1a30Sjl139090 } 211425cf1a30Sjl139090 211525cf1a30Sjl139090 ddi_walk_devs(dip, drmach_io_cb_check, (void *)&arg); 211625cf1a30Sjl139090 211725cf1a30Sjl139090 ndi_devi_exit(pdip, circ); 211825cf1a30Sjl139090 ndi_rele_devi(pdip); 211968ac2337Sjl139090 212068ac2337Sjl139090 if (arg.dip) { 212168ac2337Sjl139090 arg.rv = (*arg.func)(arg.dip); 212268ac2337Sjl139090 ndi_rele_devi(arg.dip); 212368ac2337Sjl139090 } else { 212468ac2337Sjl139090 arg.rv = -1; 212525cf1a30Sjl139090 } 212625cf1a30Sjl139090 212725cf1a30Sjl139090 return (arg.rv); 212825cf1a30Sjl139090 } 212925cf1a30Sjl139090 213025cf1a30Sjl139090 sbd_error_t * 213125cf1a30Sjl139090 drmach_io_pre_release(drmachid_t id) 213225cf1a30Sjl139090 { 213325cf1a30Sjl139090 int rv; 213425cf1a30Sjl139090 213525cf1a30Sjl139090 if (!DRMACH_IS_IO_ID(id)) 213625cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 213725cf1a30Sjl139090 213825cf1a30Sjl139090 rv = drmach_console_ops(id, DRMACH_IO_PRE_RELEASE); 213925cf1a30Sjl139090 214025cf1a30Sjl139090 if (rv != 0) 214125cf1a30Sjl139090 cmn_err(CE_WARN, "IO callback failed in pre-release\n"); 214225cf1a30Sjl139090 214325cf1a30Sjl139090 return (NULL); 214425cf1a30Sjl139090 } 214525cf1a30Sjl139090 214625cf1a30Sjl139090 static sbd_error_t * 214725cf1a30Sjl139090 drmach_io_release(drmachid_t id) 214825cf1a30Sjl139090 { 214925cf1a30Sjl139090 if (!DRMACH_IS_IO_ID(id)) 215025cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 215125cf1a30Sjl139090 return (NULL); 215225cf1a30Sjl139090 } 215325cf1a30Sjl139090 215425cf1a30Sjl139090 sbd_error_t * 215525cf1a30Sjl139090 drmach_io_unrelease(drmachid_t id) 215625cf1a30Sjl139090 { 215725cf1a30Sjl139090 if (!DRMACH_IS_IO_ID(id)) 215825cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 215925cf1a30Sjl139090 return (NULL); 216025cf1a30Sjl139090 } 216125cf1a30Sjl139090 216225cf1a30Sjl139090 /*ARGSUSED*/ 216325cf1a30Sjl139090 sbd_error_t * 216425cf1a30Sjl139090 drmach_io_post_release(drmachid_t id) 216525cf1a30Sjl139090 { 216625cf1a30Sjl139090 return (NULL); 216725cf1a30Sjl139090 } 216825cf1a30Sjl139090 216925cf1a30Sjl139090 /*ARGSUSED*/ 217025cf1a30Sjl139090 sbd_error_t * 217125cf1a30Sjl139090 drmach_io_post_attach(drmachid_t id) 217225cf1a30Sjl139090 { 217325cf1a30Sjl139090 int rv; 217425cf1a30Sjl139090 217525cf1a30Sjl139090 if (!DRMACH_IS_IO_ID(id)) 217625cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 217725cf1a30Sjl139090 217825cf1a30Sjl139090 rv = drmach_console_ops(id, DRMACH_IO_POST_ATTACH); 217925cf1a30Sjl139090 218025cf1a30Sjl139090 if (rv != 0) 218125cf1a30Sjl139090 cmn_err(CE_WARN, "IO callback failed in post-attach\n"); 218225cf1a30Sjl139090 218325cf1a30Sjl139090 return (0); 218425cf1a30Sjl139090 } 218525cf1a30Sjl139090 218625cf1a30Sjl139090 static sbd_error_t * 218725cf1a30Sjl139090 drmach_io_status(drmachid_t id, drmach_status_t *stat) 218825cf1a30Sjl139090 { 218925cf1a30Sjl139090 drmach_device_t *dp; 219025cf1a30Sjl139090 sbd_error_t *err; 219125cf1a30Sjl139090 int configured; 219225cf1a30Sjl139090 219325cf1a30Sjl139090 ASSERT(DRMACH_IS_IO_ID(id)); 219425cf1a30Sjl139090 dp = id; 219525cf1a30Sjl139090 219625cf1a30Sjl139090 err = drmach_io_is_attached(id, &configured); 219725cf1a30Sjl139090 if (err) 219825cf1a30Sjl139090 return (err); 219925cf1a30Sjl139090 220025cf1a30Sjl139090 stat->assigned = dp->bp->assigned; 220125cf1a30Sjl139090 stat->powered = dp->bp->powered; 220225cf1a30Sjl139090 stat->configured = (configured != 0); 220325cf1a30Sjl139090 stat->busy = dp->busy; 220407d06da5SSurya Prakki (void) strncpy(stat->type, dp->type, sizeof (stat->type)); 220525cf1a30Sjl139090 stat->info[0] = '\0'; 220625cf1a30Sjl139090 220725cf1a30Sjl139090 return (NULL); 220825cf1a30Sjl139090 } 220925cf1a30Sjl139090 221025cf1a30Sjl139090 static sbd_error_t * 221125cf1a30Sjl139090 drmach_mem_new(drmach_device_t *proto, drmachid_t *idp) 221225cf1a30Sjl139090 { 221325cf1a30Sjl139090 dev_info_t *dip; 221468ac2337Sjl139090 int rv; 221525cf1a30Sjl139090 221625cf1a30Sjl139090 drmach_mem_t *mp; 221725cf1a30Sjl139090 221868ac2337Sjl139090 rv = 0; 221968ac2337Sjl139090 222068ac2337Sjl139090 if ((proto->node->n_getproplen(proto->node, "mc-addr", &rv) < 0) || 222168ac2337Sjl139090 (rv <= 0)) { 222268ac2337Sjl139090 *idp = (drmachid_t)0; 222368ac2337Sjl139090 return (NULL); 222468ac2337Sjl139090 } 222568ac2337Sjl139090 222625cf1a30Sjl139090 mp = kmem_zalloc(sizeof (drmach_mem_t), KM_SLEEP); 222725cf1a30Sjl139090 proto->unum = 0; 222825cf1a30Sjl139090 222925cf1a30Sjl139090 bcopy(proto, &mp->dev, sizeof (mp->dev)); 223025cf1a30Sjl139090 mp->dev.node = drmach_node_dup(proto->node); 223125cf1a30Sjl139090 mp->dev.cm.isa = (void *)drmach_mem_new; 223225cf1a30Sjl139090 mp->dev.cm.dispose = drmach_mem_dispose; 223325cf1a30Sjl139090 mp->dev.cm.release = drmach_mem_release; 223425cf1a30Sjl139090 mp->dev.cm.status = drmach_mem_status; 223525cf1a30Sjl139090 223607d06da5SSurya Prakki (void) snprintf(mp->dev.cm.name, sizeof (mp->dev.cm.name), "%s", 223707d06da5SSurya Prakki mp->dev.type); 223825cf1a30Sjl139090 223925cf1a30Sjl139090 dip = mp->dev.node->n_getdip(mp->dev.node); 224025cf1a30Sjl139090 if (drmach_setup_mc_info(dip, mp) != 0) { 22418eafe49bSbm42561 return (drerr_new(1, EOPL_MC_SETUP, NULL)); 224225cf1a30Sjl139090 } 224325cf1a30Sjl139090 224468ac2337Sjl139090 /* make sure we do not create memoryless nodes */ 224568ac2337Sjl139090 if (mp->nbytes == 0) { 224668ac2337Sjl139090 *idp = (drmachid_t)NULL; 224768ac2337Sjl139090 kmem_free(mp, sizeof (drmach_mem_t)); 224868ac2337Sjl139090 } else 224925cf1a30Sjl139090 *idp = (drmachid_t)mp; 225068ac2337Sjl139090 225125cf1a30Sjl139090 return (NULL); 225225cf1a30Sjl139090 } 225325cf1a30Sjl139090 225425cf1a30Sjl139090 static void 225525cf1a30Sjl139090 drmach_mem_dispose(drmachid_t id) 225625cf1a30Sjl139090 { 225725cf1a30Sjl139090 drmach_mem_t *mp; 225825cf1a30Sjl139090 225925cf1a30Sjl139090 ASSERT(DRMACH_IS_MEM_ID(id)); 226025cf1a30Sjl139090 226125cf1a30Sjl139090 226225cf1a30Sjl139090 mp = id; 226325cf1a30Sjl139090 226425cf1a30Sjl139090 if (mp->dev.node) 226525cf1a30Sjl139090 drmach_node_dispose(mp->dev.node); 226625cf1a30Sjl139090 226725cf1a30Sjl139090 if (mp->memlist) { 226825cf1a30Sjl139090 memlist_delete(mp->memlist); 226925cf1a30Sjl139090 mp->memlist = NULL; 227025cf1a30Sjl139090 } 227168ac2337Sjl139090 227268ac2337Sjl139090 kmem_free(mp, sizeof (*mp)); 227325cf1a30Sjl139090 } 227425cf1a30Sjl139090 227525cf1a30Sjl139090 sbd_error_t * 227625cf1a30Sjl139090 drmach_mem_add_span(drmachid_t id, uint64_t basepa, uint64_t size) 227725cf1a30Sjl139090 { 227825cf1a30Sjl139090 pfn_t basepfn = (pfn_t)(basepa >> PAGESHIFT); 227925cf1a30Sjl139090 pgcnt_t npages = (pgcnt_t)(size >> PAGESHIFT); 228025cf1a30Sjl139090 int rv; 228125cf1a30Sjl139090 228225cf1a30Sjl139090 ASSERT(size != 0); 228325cf1a30Sjl139090 228425cf1a30Sjl139090 if (!DRMACH_IS_MEM_ID(id)) 228525cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 228625cf1a30Sjl139090 228785f58038Sdp78419 rv = kcage_range_add(basepfn, npages, KCAGE_DOWN); 228825cf1a30Sjl139090 if (rv == ENOMEM) { 228907d06da5SSurya Prakki cmn_err(CE_WARN, "%lu megabytes not available to kernel cage", 229007d06da5SSurya Prakki (ulong_t)(size == 0 ? 0 : size / MBYTE)); 229125cf1a30Sjl139090 } else if (rv != 0) { 229225cf1a30Sjl139090 /* catch this in debug kernels */ 229325cf1a30Sjl139090 ASSERT(0); 229425cf1a30Sjl139090 2295e98fafb9Sjl139090 cmn_err(CE_WARN, "unexpected kcage_range_add return value %d", 2296e98fafb9Sjl139090 rv); 229725cf1a30Sjl139090 } 229825cf1a30Sjl139090 229925cf1a30Sjl139090 if (rv) { 230025cf1a30Sjl139090 return (DRMACH_INTERNAL_ERROR()); 230125cf1a30Sjl139090 } 230225cf1a30Sjl139090 else 230325cf1a30Sjl139090 return (NULL); 230425cf1a30Sjl139090 } 230525cf1a30Sjl139090 230625cf1a30Sjl139090 sbd_error_t * 230725cf1a30Sjl139090 drmach_mem_del_span(drmachid_t id, uint64_t basepa, uint64_t size) 230825cf1a30Sjl139090 { 230925cf1a30Sjl139090 pfn_t basepfn = (pfn_t)(basepa >> PAGESHIFT); 231025cf1a30Sjl139090 pgcnt_t npages = (pgcnt_t)(size >> PAGESHIFT); 231125cf1a30Sjl139090 int rv; 231225cf1a30Sjl139090 231325cf1a30Sjl139090 if (!DRMACH_IS_MEM_ID(id)) 231425cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 231525cf1a30Sjl139090 231625cf1a30Sjl139090 if (size > 0) { 231725cf1a30Sjl139090 rv = kcage_range_delete_post_mem_del(basepfn, npages); 231825cf1a30Sjl139090 if (rv != 0) { 231925cf1a30Sjl139090 cmn_err(CE_WARN, 232025cf1a30Sjl139090 "unexpected kcage_range_delete_post_mem_del" 232125cf1a30Sjl139090 " return value %d", rv); 232225cf1a30Sjl139090 return (DRMACH_INTERNAL_ERROR()); 232325cf1a30Sjl139090 } 232425cf1a30Sjl139090 } 232525cf1a30Sjl139090 232625cf1a30Sjl139090 return (NULL); 232725cf1a30Sjl139090 } 232825cf1a30Sjl139090 232925cf1a30Sjl139090 sbd_error_t * 233025cf1a30Sjl139090 drmach_mem_disable(drmachid_t id) 233125cf1a30Sjl139090 { 233225cf1a30Sjl139090 if (!DRMACH_IS_MEM_ID(id)) 233325cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 233425cf1a30Sjl139090 else { 233525cf1a30Sjl139090 drmach_flush_all(); 233625cf1a30Sjl139090 return (NULL); 233725cf1a30Sjl139090 } 233825cf1a30Sjl139090 } 233925cf1a30Sjl139090 234025cf1a30Sjl139090 sbd_error_t * 234125cf1a30Sjl139090 drmach_mem_enable(drmachid_t id) 234225cf1a30Sjl139090 { 234325cf1a30Sjl139090 if (!DRMACH_IS_MEM_ID(id)) 234425cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 234525cf1a30Sjl139090 else 234625cf1a30Sjl139090 return (NULL); 234725cf1a30Sjl139090 } 234825cf1a30Sjl139090 234925cf1a30Sjl139090 sbd_error_t * 235025cf1a30Sjl139090 drmach_mem_get_info(drmachid_t id, drmach_mem_info_t *mem) 235125cf1a30Sjl139090 { 235225cf1a30Sjl139090 drmach_mem_t *mp; 235325cf1a30Sjl139090 235425cf1a30Sjl139090 if (!DRMACH_IS_MEM_ID(id)) 235525cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 235625cf1a30Sjl139090 235725cf1a30Sjl139090 mp = (drmach_mem_t *)id; 235825cf1a30Sjl139090 235925cf1a30Sjl139090 /* 236025cf1a30Sjl139090 * This is only used by dr to round up/down the memory 236125cf1a30Sjl139090 * for copying. Our unit of memory isolation is 64 MB. 236225cf1a30Sjl139090 */ 236325cf1a30Sjl139090 236425cf1a30Sjl139090 mem->mi_alignment_mask = (64 * 1024 * 1024 - 1); 236525cf1a30Sjl139090 mem->mi_basepa = mp->base_pa; 236625cf1a30Sjl139090 mem->mi_size = mp->nbytes; 236725cf1a30Sjl139090 mem->mi_slice_size = mp->slice_size; 236825cf1a30Sjl139090 236925cf1a30Sjl139090 return (NULL); 237025cf1a30Sjl139090 } 237125cf1a30Sjl139090 237225cf1a30Sjl139090 sbd_error_t * 237325cf1a30Sjl139090 drmach_mem_get_base_physaddr(drmachid_t id, uint64_t *pa) 237425cf1a30Sjl139090 { 237525cf1a30Sjl139090 drmach_mem_t *mp; 237625cf1a30Sjl139090 237725cf1a30Sjl139090 if (!DRMACH_IS_MEM_ID(id)) 237825cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 237925cf1a30Sjl139090 238025cf1a30Sjl139090 mp = (drmach_mem_t *)id; 238125cf1a30Sjl139090 238225cf1a30Sjl139090 *pa = mp->base_pa; 238325cf1a30Sjl139090 return (NULL); 238425cf1a30Sjl139090 } 238525cf1a30Sjl139090 238625cf1a30Sjl139090 sbd_error_t * 238725cf1a30Sjl139090 drmach_mem_get_memlist(drmachid_t id, struct memlist **ml) 238825cf1a30Sjl139090 { 238925cf1a30Sjl139090 drmach_mem_t *mem; 2390b307f191Sbm42561 #ifdef DEBUG 239125cf1a30Sjl139090 int rv; 2392b307f191Sbm42561 #endif 239325cf1a30Sjl139090 struct memlist *mlist; 239425cf1a30Sjl139090 239525cf1a30Sjl139090 if (!DRMACH_IS_MEM_ID(id)) 239625cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 239725cf1a30Sjl139090 239825cf1a30Sjl139090 mem = (drmach_mem_t *)id; 239925cf1a30Sjl139090 mlist = memlist_dup(mem->memlist); 240025cf1a30Sjl139090 240125cf1a30Sjl139090 #ifdef DEBUG 240225cf1a30Sjl139090 /* 240325cf1a30Sjl139090 * Make sure the incoming memlist doesn't already 240425cf1a30Sjl139090 * intersect with what's present in the system (phys_install). 240525cf1a30Sjl139090 */ 240625cf1a30Sjl139090 memlist_read_lock(); 240725cf1a30Sjl139090 rv = memlist_intersect(phys_install, mlist); 240825cf1a30Sjl139090 memlist_read_unlock(); 240925cf1a30Sjl139090 if (rv) { 2410e98fafb9Sjl139090 DRMACH_PR("Derived memlist intersects with phys_install\n"); 241125cf1a30Sjl139090 memlist_dump(mlist); 241225cf1a30Sjl139090 241325cf1a30Sjl139090 DRMACH_PR("phys_install memlist:\n"); 241425cf1a30Sjl139090 memlist_dump(phys_install); 241525cf1a30Sjl139090 241625cf1a30Sjl139090 memlist_delete(mlist); 241725cf1a30Sjl139090 return (DRMACH_INTERNAL_ERROR()); 241825cf1a30Sjl139090 } 241925cf1a30Sjl139090 242025cf1a30Sjl139090 DRMACH_PR("Derived memlist:"); 242125cf1a30Sjl139090 memlist_dump(mlist); 242225cf1a30Sjl139090 #endif 242325cf1a30Sjl139090 *ml = mlist; 242425cf1a30Sjl139090 242525cf1a30Sjl139090 return (NULL); 242625cf1a30Sjl139090 } 242725cf1a30Sjl139090 242825cf1a30Sjl139090 sbd_error_t * 242925cf1a30Sjl139090 drmach_mem_get_slice_size(drmachid_t id, uint64_t *bytes) 243025cf1a30Sjl139090 { 243125cf1a30Sjl139090 drmach_mem_t *mem; 243225cf1a30Sjl139090 243325cf1a30Sjl139090 if (!DRMACH_IS_MEM_ID(id)) 243425cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 243525cf1a30Sjl139090 243625cf1a30Sjl139090 mem = (drmach_mem_t *)id; 243725cf1a30Sjl139090 243825cf1a30Sjl139090 *bytes = mem->slice_size; 243925cf1a30Sjl139090 244025cf1a30Sjl139090 return (NULL); 244125cf1a30Sjl139090 } 244225cf1a30Sjl139090 244325cf1a30Sjl139090 244425cf1a30Sjl139090 /* ARGSUSED */ 244525cf1a30Sjl139090 processorid_t 244625cf1a30Sjl139090 drmach_mem_cpu_affinity(drmachid_t id) 244725cf1a30Sjl139090 { 244825cf1a30Sjl139090 return (CPU_CURRENT); 244925cf1a30Sjl139090 } 245025cf1a30Sjl139090 245125cf1a30Sjl139090 static sbd_error_t * 245225cf1a30Sjl139090 drmach_mem_release(drmachid_t id) 245325cf1a30Sjl139090 { 245425cf1a30Sjl139090 if (!DRMACH_IS_MEM_ID(id)) 245525cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 245625cf1a30Sjl139090 return (NULL); 245725cf1a30Sjl139090 } 245825cf1a30Sjl139090 245925cf1a30Sjl139090 static sbd_error_t * 246025cf1a30Sjl139090 drmach_mem_status(drmachid_t id, drmach_status_t *stat) 246125cf1a30Sjl139090 { 246225cf1a30Sjl139090 drmach_mem_t *dp; 246325cf1a30Sjl139090 uint64_t pa, slice_size; 246425cf1a30Sjl139090 struct memlist *ml; 246525cf1a30Sjl139090 246625cf1a30Sjl139090 ASSERT(DRMACH_IS_MEM_ID(id)); 246725cf1a30Sjl139090 dp = id; 246825cf1a30Sjl139090 246925cf1a30Sjl139090 /* get starting physical address of target memory */ 247025cf1a30Sjl139090 pa = dp->base_pa; 247125cf1a30Sjl139090 247225cf1a30Sjl139090 /* round down to slice boundary */ 247325cf1a30Sjl139090 slice_size = dp->slice_size; 247425cf1a30Sjl139090 pa &= ~(slice_size - 1); 247525cf1a30Sjl139090 247625cf1a30Sjl139090 /* stop at first span that is in slice */ 247725cf1a30Sjl139090 memlist_read_lock(); 247856f33205SJonathan Adams for (ml = phys_install; ml; ml = ml->ml_next) 247956f33205SJonathan Adams if (ml->ml_address >= pa && ml->ml_address < pa + slice_size) 248025cf1a30Sjl139090 break; 248125cf1a30Sjl139090 memlist_read_unlock(); 248225cf1a30Sjl139090 248325cf1a30Sjl139090 stat->assigned = dp->dev.bp->assigned; 248425cf1a30Sjl139090 stat->powered = dp->dev.bp->powered; 248525cf1a30Sjl139090 stat->configured = (ml != NULL); 248625cf1a30Sjl139090 stat->busy = dp->dev.busy; 248707d06da5SSurya Prakki (void) strncpy(stat->type, dp->dev.type, sizeof (stat->type)); 248825cf1a30Sjl139090 stat->info[0] = '\0'; 248925cf1a30Sjl139090 249025cf1a30Sjl139090 return (NULL); 249125cf1a30Sjl139090 } 249225cf1a30Sjl139090 249325cf1a30Sjl139090 249425cf1a30Sjl139090 sbd_error_t * 249525cf1a30Sjl139090 drmach_board_deprobe(drmachid_t id) 249625cf1a30Sjl139090 { 249725cf1a30Sjl139090 drmach_board_t *bp; 249825cf1a30Sjl139090 249925cf1a30Sjl139090 if (!DRMACH_IS_BOARD_ID(id)) 250025cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 250125cf1a30Sjl139090 250225cf1a30Sjl139090 bp = id; 250325cf1a30Sjl139090 250468ac2337Sjl139090 cmn_err(CE_CONT, "DR: detach board %d\n", bp->bnum); 250525cf1a30Sjl139090 250625cf1a30Sjl139090 if (bp->tree) { 250725cf1a30Sjl139090 drmach_node_dispose(bp->tree); 250825cf1a30Sjl139090 bp->tree = NULL; 250925cf1a30Sjl139090 } 251025cf1a30Sjl139090 if (bp->devices) { 251125cf1a30Sjl139090 drmach_array_dispose(bp->devices, drmach_device_dispose); 251225cf1a30Sjl139090 bp->devices = NULL; 251325cf1a30Sjl139090 } 251425cf1a30Sjl139090 251525cf1a30Sjl139090 bp->boot_board = 0; 251625cf1a30Sjl139090 251725cf1a30Sjl139090 return (NULL); 251825cf1a30Sjl139090 } 251925cf1a30Sjl139090 252025cf1a30Sjl139090 /*ARGSUSED*/ 252125cf1a30Sjl139090 static sbd_error_t * 252225cf1a30Sjl139090 drmach_pt_ikprobe(drmachid_t id, drmach_opts_t *opts) 252325cf1a30Sjl139090 { 252425cf1a30Sjl139090 drmach_board_t *bp = (drmach_board_t *)id; 252525cf1a30Sjl139090 sbd_error_t *err = NULL; 252625cf1a30Sjl139090 int rv; 2527e98fafb9Sjl139090 unsigned cpu_impl; 252825cf1a30Sjl139090 252925cf1a30Sjl139090 if (!DRMACH_IS_BOARD_ID(id)) 253025cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 253125cf1a30Sjl139090 253225cf1a30Sjl139090 DRMACH_PR("calling opl_probe_board for bnum=%d\n", bp->bnum); 2533e98fafb9Sjl139090 rv = opl_probe_sb(bp->bnum, &cpu_impl); 253425cf1a30Sjl139090 if (rv != 0) { 25358eafe49bSbm42561 err = drerr_new(1, EOPL_PROBE, bp->cm.name); 253625cf1a30Sjl139090 return (err); 253725cf1a30Sjl139090 } 253825cf1a30Sjl139090 return (err); 253925cf1a30Sjl139090 } 254025cf1a30Sjl139090 254125cf1a30Sjl139090 /*ARGSUSED*/ 254225cf1a30Sjl139090 static sbd_error_t * 254325cf1a30Sjl139090 drmach_pt_ikdeprobe(drmachid_t id, drmach_opts_t *opts) 254425cf1a30Sjl139090 { 254525cf1a30Sjl139090 drmach_board_t *bp; 254625cf1a30Sjl139090 sbd_error_t *err = NULL; 254725cf1a30Sjl139090 int rv; 254825cf1a30Sjl139090 254925cf1a30Sjl139090 if (!DRMACH_IS_BOARD_ID(id)) 255025cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 255125cf1a30Sjl139090 bp = (drmach_board_t *)id; 255225cf1a30Sjl139090 255325cf1a30Sjl139090 cmn_err(CE_CONT, "DR: in-kernel unprobe board %d\n", bp->bnum); 255425cf1a30Sjl139090 255525cf1a30Sjl139090 rv = opl_unprobe_sb(bp->bnum); 255625cf1a30Sjl139090 if (rv != 0) { 25578eafe49bSbm42561 err = drerr_new(1, EOPL_DEPROBE, bp->cm.name); 255825cf1a30Sjl139090 } 255925cf1a30Sjl139090 256025cf1a30Sjl139090 return (err); 256125cf1a30Sjl139090 } 256225cf1a30Sjl139090 256325cf1a30Sjl139090 256425cf1a30Sjl139090 /*ARGSUSED*/ 256525cf1a30Sjl139090 sbd_error_t * 256625cf1a30Sjl139090 drmach_pt_readmem(drmachid_t id, drmach_opts_t *opts) 256725cf1a30Sjl139090 { 256825cf1a30Sjl139090 struct memlist *ml; 256925cf1a30Sjl139090 uint64_t src_pa; 257025cf1a30Sjl139090 uint64_t dst_pa; 257125cf1a30Sjl139090 uint64_t dst; 257225cf1a30Sjl139090 257325cf1a30Sjl139090 dst_pa = va_to_pa(&dst); 257425cf1a30Sjl139090 257525cf1a30Sjl139090 memlist_read_lock(); 257656f33205SJonathan Adams for (ml = phys_install; ml; ml = ml->ml_next) { 257725cf1a30Sjl139090 uint64_t nbytes; 257825cf1a30Sjl139090 257956f33205SJonathan Adams src_pa = ml->ml_address; 258056f33205SJonathan Adams nbytes = ml->ml_size; 258125cf1a30Sjl139090 258225cf1a30Sjl139090 while (nbytes != 0ull) { 258325cf1a30Sjl139090 258425cf1a30Sjl139090 /* copy 32 bytes at arc_pa to dst_pa */ 258525cf1a30Sjl139090 bcopy32_il(src_pa, dst_pa); 258625cf1a30Sjl139090 258725cf1a30Sjl139090 /* increment by 32 bytes */ 258825cf1a30Sjl139090 src_pa += (4 * sizeof (uint64_t)); 258925cf1a30Sjl139090 259025cf1a30Sjl139090 /* decrement by 32 bytes */ 259125cf1a30Sjl139090 nbytes -= (4 * sizeof (uint64_t)); 259225cf1a30Sjl139090 } 259325cf1a30Sjl139090 } 259425cf1a30Sjl139090 memlist_read_unlock(); 259525cf1a30Sjl139090 259625cf1a30Sjl139090 return (NULL); 259725cf1a30Sjl139090 } 259825cf1a30Sjl139090 259925cf1a30Sjl139090 static struct { 260025cf1a30Sjl139090 const char *name; 260125cf1a30Sjl139090 sbd_error_t *(*handler)(drmachid_t id, drmach_opts_t *opts); 260225cf1a30Sjl139090 } drmach_pt_arr[] = { 260325cf1a30Sjl139090 { "readmem", drmach_pt_readmem }, 260425cf1a30Sjl139090 { "ikprobe", drmach_pt_ikprobe }, 260525cf1a30Sjl139090 { "ikdeprobe", drmach_pt_ikdeprobe }, 260625cf1a30Sjl139090 260725cf1a30Sjl139090 /* the following line must always be last */ 260825cf1a30Sjl139090 { NULL, NULL } 260925cf1a30Sjl139090 }; 261025cf1a30Sjl139090 261125cf1a30Sjl139090 /*ARGSUSED*/ 261225cf1a30Sjl139090 sbd_error_t * 261325cf1a30Sjl139090 drmach_passthru(drmachid_t id, drmach_opts_t *opts) 261425cf1a30Sjl139090 { 261525cf1a30Sjl139090 int i; 261625cf1a30Sjl139090 sbd_error_t *err; 261725cf1a30Sjl139090 261825cf1a30Sjl139090 i = 0; 261925cf1a30Sjl139090 while (drmach_pt_arr[i].name != NULL) { 262025cf1a30Sjl139090 int len = strlen(drmach_pt_arr[i].name); 262125cf1a30Sjl139090 262225cf1a30Sjl139090 if (strncmp(drmach_pt_arr[i].name, opts->copts, len) == 0) 262325cf1a30Sjl139090 break; 262425cf1a30Sjl139090 262525cf1a30Sjl139090 i += 1; 262625cf1a30Sjl139090 } 262725cf1a30Sjl139090 262825cf1a30Sjl139090 if (drmach_pt_arr[i].name == NULL) 262925cf1a30Sjl139090 err = drerr_new(0, EOPL_UNKPTCMD, opts->copts); 263025cf1a30Sjl139090 else 263125cf1a30Sjl139090 err = (*drmach_pt_arr[i].handler)(id, opts); 263225cf1a30Sjl139090 263325cf1a30Sjl139090 return (err); 263425cf1a30Sjl139090 } 263525cf1a30Sjl139090 263625cf1a30Sjl139090 sbd_error_t * 263725cf1a30Sjl139090 drmach_release(drmachid_t id) 263825cf1a30Sjl139090 { 263925cf1a30Sjl139090 drmach_common_t *cp; 264025cf1a30Sjl139090 264125cf1a30Sjl139090 if (!DRMACH_IS_DEVICE_ID(id)) 264225cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 264325cf1a30Sjl139090 cp = id; 264425cf1a30Sjl139090 264525cf1a30Sjl139090 return (cp->release(id)); 264625cf1a30Sjl139090 } 264725cf1a30Sjl139090 264825cf1a30Sjl139090 sbd_error_t * 264925cf1a30Sjl139090 drmach_status(drmachid_t id, drmach_status_t *stat) 265025cf1a30Sjl139090 { 265125cf1a30Sjl139090 drmach_common_t *cp; 265225cf1a30Sjl139090 sbd_error_t *err; 265325cf1a30Sjl139090 265425cf1a30Sjl139090 rw_enter(&drmach_boards_rwlock, RW_READER); 265525cf1a30Sjl139090 265625cf1a30Sjl139090 if (!DRMACH_IS_ID(id)) { 265725cf1a30Sjl139090 rw_exit(&drmach_boards_rwlock); 265825cf1a30Sjl139090 return (drerr_new(0, EOPL_NOTID, NULL)); 265925cf1a30Sjl139090 } 266025cf1a30Sjl139090 cp = (drmach_common_t *)id; 266125cf1a30Sjl139090 err = cp->status(id, stat); 266225cf1a30Sjl139090 266325cf1a30Sjl139090 rw_exit(&drmach_boards_rwlock); 266425cf1a30Sjl139090 266525cf1a30Sjl139090 return (err); 266625cf1a30Sjl139090 } 266725cf1a30Sjl139090 266825cf1a30Sjl139090 static sbd_error_t * 266925cf1a30Sjl139090 drmach_i_status(drmachid_t id, drmach_status_t *stat) 267025cf1a30Sjl139090 { 267125cf1a30Sjl139090 drmach_common_t *cp; 267225cf1a30Sjl139090 267325cf1a30Sjl139090 if (!DRMACH_IS_ID(id)) 267425cf1a30Sjl139090 return (drerr_new(0, EOPL_NOTID, NULL)); 267525cf1a30Sjl139090 cp = id; 267625cf1a30Sjl139090 267725cf1a30Sjl139090 return (cp->status(id, stat)); 267825cf1a30Sjl139090 } 267925cf1a30Sjl139090 268025cf1a30Sjl139090 /*ARGSUSED*/ 268125cf1a30Sjl139090 sbd_error_t * 268225cf1a30Sjl139090 drmach_unconfigure(drmachid_t id, int flags) 268325cf1a30Sjl139090 { 268425cf1a30Sjl139090 drmach_device_t *dp; 268525cf1a30Sjl139090 dev_info_t *rdip, *fdip = NULL; 268625cf1a30Sjl139090 char name[OBP_MAXDRVNAME]; 268725cf1a30Sjl139090 int rv; 268825cf1a30Sjl139090 268925cf1a30Sjl139090 if (DRMACH_IS_CPU_ID(id)) 269025cf1a30Sjl139090 return (NULL); 269125cf1a30Sjl139090 269225cf1a30Sjl139090 if (!DRMACH_IS_DEVICE_ID(id)) 269325cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 269425cf1a30Sjl139090 269525cf1a30Sjl139090 dp = id; 269625cf1a30Sjl139090 269725cf1a30Sjl139090 rdip = dp->node->n_getdip(dp->node); 269825cf1a30Sjl139090 269925cf1a30Sjl139090 ASSERT(rdip); 270025cf1a30Sjl139090 270125cf1a30Sjl139090 rv = dp->node->n_getprop(dp->node, "name", name, OBP_MAXDRVNAME); 270225cf1a30Sjl139090 270325cf1a30Sjl139090 if (rv) 270425cf1a30Sjl139090 return (NULL); 270525cf1a30Sjl139090 270625cf1a30Sjl139090 /* 270725cf1a30Sjl139090 * Note: FORCE flag is no longer necessary under devfs 270825cf1a30Sjl139090 */ 270925cf1a30Sjl139090 271025cf1a30Sjl139090 ASSERT(e_ddi_branch_held(rdip)); 271125cf1a30Sjl139090 if (e_ddi_branch_unconfigure(rdip, &fdip, 0)) { 271225cf1a30Sjl139090 sbd_error_t *err; 271325cf1a30Sjl139090 char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 271425cf1a30Sjl139090 271525cf1a30Sjl139090 /* 271625cf1a30Sjl139090 * If non-NULL, fdip is returned held and must be released. 271725cf1a30Sjl139090 */ 271825cf1a30Sjl139090 if (fdip != NULL) { 271925cf1a30Sjl139090 (void) ddi_pathname(fdip, path); 272025cf1a30Sjl139090 ndi_rele_devi(fdip); 272125cf1a30Sjl139090 } else { 272225cf1a30Sjl139090 (void) ddi_pathname(rdip, path); 272325cf1a30Sjl139090 } 272425cf1a30Sjl139090 272525cf1a30Sjl139090 err = drerr_new(1, EOPL_DRVFAIL, path); 272625cf1a30Sjl139090 272725cf1a30Sjl139090 kmem_free(path, MAXPATHLEN); 272825cf1a30Sjl139090 272925cf1a30Sjl139090 return (err); 273025cf1a30Sjl139090 } 273125cf1a30Sjl139090 273225cf1a30Sjl139090 return (NULL); 273325cf1a30Sjl139090 } 273425cf1a30Sjl139090 273525cf1a30Sjl139090 273625cf1a30Sjl139090 int 273725cf1a30Sjl139090 drmach_cpu_poweron(struct cpu *cp) 273825cf1a30Sjl139090 { 273925cf1a30Sjl139090 int bnum, cpuid, onb_core_num, strand_id; 274025cf1a30Sjl139090 drmach_board_t *bp; 274125cf1a30Sjl139090 274225cf1a30Sjl139090 DRMACH_PR("drmach_cpu_poweron: starting cpuid %d\n", cp->cpu_id); 274325cf1a30Sjl139090 274425cf1a30Sjl139090 cpuid = cp->cpu_id; 274525cf1a30Sjl139090 bnum = LSB_ID(cpuid); 274625cf1a30Sjl139090 onb_core_num = ON_BOARD_CORE_NUM(cpuid); 274725cf1a30Sjl139090 strand_id = STRAND_ID(cpuid); 274825cf1a30Sjl139090 bp = drmach_get_board_by_bnum(bnum); 274925cf1a30Sjl139090 275025cf1a30Sjl139090 ASSERT(bp); 275125cf1a30Sjl139090 if (bp->cores[onb_core_num].core_hotadded == 0) { 275225cf1a30Sjl139090 if (drmach_add_remove_cpu(bnum, onb_core_num, 275325cf1a30Sjl139090 HOTADD_CPU) != 0) { 275425cf1a30Sjl139090 cmn_err(CE_WARN, "Failed to add CMP %d on board %d\n", 275525cf1a30Sjl139090 onb_core_num, bnum); 275625cf1a30Sjl139090 return (EIO); 275725cf1a30Sjl139090 } 275825cf1a30Sjl139090 } 275925cf1a30Sjl139090 276025cf1a30Sjl139090 ASSERT(MUTEX_HELD(&cpu_lock)); 276125cf1a30Sjl139090 276225cf1a30Sjl139090 if (drmach_cpu_start(cp) != 0) { 276325cf1a30Sjl139090 if (bp->cores[onb_core_num].core_started == 0) { 276425cf1a30Sjl139090 /* 276525cf1a30Sjl139090 * we must undo the hotadd or no one will do that 276625cf1a30Sjl139090 * If this fails, we will do this again in 276725cf1a30Sjl139090 * drmach_board_disconnect. 276825cf1a30Sjl139090 */ 276925cf1a30Sjl139090 if (drmach_add_remove_cpu(bnum, onb_core_num, 277025cf1a30Sjl139090 HOTREMOVE_CPU) != 0) { 277125cf1a30Sjl139090 cmn_err(CE_WARN, "Failed to remove CMP %d " 2772e98fafb9Sjl139090 "on board %d\n", onb_core_num, bnum); 277325cf1a30Sjl139090 } 277425cf1a30Sjl139090 } 277525cf1a30Sjl139090 return (EBUSY); 277625cf1a30Sjl139090 } else { 277725cf1a30Sjl139090 bp->cores[onb_core_num].core_started |= (1 << strand_id); 277825cf1a30Sjl139090 return (0); 277925cf1a30Sjl139090 } 278025cf1a30Sjl139090 } 278125cf1a30Sjl139090 278225cf1a30Sjl139090 int 278325cf1a30Sjl139090 drmach_cpu_poweroff(struct cpu *cp) 278425cf1a30Sjl139090 { 278525cf1a30Sjl139090 int rv = 0; 278625cf1a30Sjl139090 processorid_t cpuid = cp->cpu_id; 278725cf1a30Sjl139090 278825cf1a30Sjl139090 DRMACH_PR("drmach_cpu_poweroff: stopping cpuid %d\n", cp->cpu_id); 278925cf1a30Sjl139090 279025cf1a30Sjl139090 ASSERT(MUTEX_HELD(&cpu_lock)); 279125cf1a30Sjl139090 279225cf1a30Sjl139090 /* 279325cf1a30Sjl139090 * Capture all CPUs (except for detaching proc) to prevent 279425cf1a30Sjl139090 * crosscalls to the detaching proc until it has cleared its 279525cf1a30Sjl139090 * bit in cpu_ready_set. 279625cf1a30Sjl139090 * 279725cf1a30Sjl139090 * The CPU's remain paused and the prom_mutex is known to be free. 279825cf1a30Sjl139090 * This prevents the x-trap victim from blocking when doing prom 279925cf1a30Sjl139090 * IEEE-1275 calls at a high PIL level. 280025cf1a30Sjl139090 */ 280125cf1a30Sjl139090 280225cf1a30Sjl139090 promsafe_pause_cpus(); 280325cf1a30Sjl139090 280425cf1a30Sjl139090 /* 280525cf1a30Sjl139090 * Quiesce interrupts on the target CPU. We do this by setting 280625cf1a30Sjl139090 * the CPU 'not ready'- (i.e. removing the CPU from cpu_ready_set) to 280725cf1a30Sjl139090 * prevent it from receiving cross calls and cross traps. 280825cf1a30Sjl139090 * This prevents the processor from receiving any new soft interrupts. 280925cf1a30Sjl139090 */ 281025cf1a30Sjl139090 mp_cpu_quiesce(cp); 281125cf1a30Sjl139090 281225cf1a30Sjl139090 rv = prom_stopcpu_bycpuid(cpuid); 281325cf1a30Sjl139090 if (rv == 0) 281425cf1a30Sjl139090 cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_POWEROFF; 281525cf1a30Sjl139090 281625cf1a30Sjl139090 start_cpus(); 281725cf1a30Sjl139090 281825cf1a30Sjl139090 if (rv == 0) { 281925cf1a30Sjl139090 int bnum, onb_core_num, strand_id; 282025cf1a30Sjl139090 drmach_board_t *bp; 282125cf1a30Sjl139090 282225cf1a30Sjl139090 CPU_SIGNATURE(OS_SIG, SIGST_DETACHED, SIGSUBST_NULL, cpuid); 282325cf1a30Sjl139090 282425cf1a30Sjl139090 bnum = LSB_ID(cpuid); 282525cf1a30Sjl139090 onb_core_num = ON_BOARD_CORE_NUM(cpuid); 282625cf1a30Sjl139090 strand_id = STRAND_ID(cpuid); 282725cf1a30Sjl139090 bp = drmach_get_board_by_bnum(bnum); 282825cf1a30Sjl139090 ASSERT(bp); 282925cf1a30Sjl139090 283025cf1a30Sjl139090 bp->cores[onb_core_num].core_started &= ~(1 << strand_id); 283125cf1a30Sjl139090 if (bp->cores[onb_core_num].core_started == 0) { 283225cf1a30Sjl139090 if (drmach_add_remove_cpu(bnum, onb_core_num, 283325cf1a30Sjl139090 HOTREMOVE_CPU) != 0) { 2834e98fafb9Sjl139090 cmn_err(CE_WARN, "Failed to remove CMP %d LSB " 2835e98fafb9Sjl139090 "%d\n", onb_core_num, bnum); 283625cf1a30Sjl139090 return (EIO); 283725cf1a30Sjl139090 } 283825cf1a30Sjl139090 } 283925cf1a30Sjl139090 } 284025cf1a30Sjl139090 284125cf1a30Sjl139090 return (rv); 284225cf1a30Sjl139090 } 284325cf1a30Sjl139090 284425cf1a30Sjl139090 /*ARGSUSED*/ 284525cf1a30Sjl139090 int 284625cf1a30Sjl139090 drmach_verify_sr(dev_info_t *dip, int sflag) 284725cf1a30Sjl139090 { 284825cf1a30Sjl139090 return (0); 284925cf1a30Sjl139090 } 285025cf1a30Sjl139090 285125cf1a30Sjl139090 void 285225cf1a30Sjl139090 drmach_suspend_last(void) 285325cf1a30Sjl139090 { 285425cf1a30Sjl139090 } 285525cf1a30Sjl139090 285625cf1a30Sjl139090 void 285725cf1a30Sjl139090 drmach_resume_first(void) 285825cf1a30Sjl139090 { 285925cf1a30Sjl139090 } 286025cf1a30Sjl139090 286125cf1a30Sjl139090 /* 286225cf1a30Sjl139090 * Log a DR sysevent. 286325cf1a30Sjl139090 * Return value: 0 success, non-zero failure. 286425cf1a30Sjl139090 */ 286525cf1a30Sjl139090 int 286625cf1a30Sjl139090 drmach_log_sysevent(int board, char *hint, int flag, int verbose) 286725cf1a30Sjl139090 { 286825cf1a30Sjl139090 sysevent_t *ev; 286925cf1a30Sjl139090 sysevent_id_t eid; 287025cf1a30Sjl139090 int rv, km_flag; 287125cf1a30Sjl139090 sysevent_value_t evnt_val; 287225cf1a30Sjl139090 sysevent_attr_list_t *evnt_attr_list = NULL; 287325cf1a30Sjl139090 char attach_pnt[MAXNAMELEN]; 287425cf1a30Sjl139090 287525cf1a30Sjl139090 km_flag = (flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP; 287625cf1a30Sjl139090 attach_pnt[0] = '\0'; 287725cf1a30Sjl139090 if (drmach_board_name(board, attach_pnt, MAXNAMELEN)) { 287825cf1a30Sjl139090 rv = -1; 287925cf1a30Sjl139090 goto logexit; 288025cf1a30Sjl139090 } 2881b307f191Sbm42561 if (verbose) { 288225cf1a30Sjl139090 DRMACH_PR("drmach_log_sysevent: %s %s, flag: %d, verbose: %d\n", 288325cf1a30Sjl139090 attach_pnt, hint, flag, verbose); 2884b307f191Sbm42561 } 288525cf1a30Sjl139090 288625cf1a30Sjl139090 if ((ev = sysevent_alloc(EC_DR, ESC_DR_AP_STATE_CHANGE, 288725cf1a30Sjl139090 SUNW_KERN_PUB"dr", km_flag)) == NULL) { 288825cf1a30Sjl139090 rv = -2; 288925cf1a30Sjl139090 goto logexit; 289025cf1a30Sjl139090 } 289125cf1a30Sjl139090 evnt_val.value_type = SE_DATA_TYPE_STRING; 289225cf1a30Sjl139090 evnt_val.value.sv_string = attach_pnt; 2893e98fafb9Sjl139090 if ((rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID, &evnt_val, 2894e98fafb9Sjl139090 km_flag)) != 0) 289525cf1a30Sjl139090 goto logexit; 289625cf1a30Sjl139090 289725cf1a30Sjl139090 evnt_val.value_type = SE_DATA_TYPE_STRING; 289825cf1a30Sjl139090 evnt_val.value.sv_string = hint; 2899e98fafb9Sjl139090 if ((rv = sysevent_add_attr(&evnt_attr_list, DR_HINT, &evnt_val, 2900e98fafb9Sjl139090 km_flag)) != 0) { 290125cf1a30Sjl139090 sysevent_free_attr(evnt_attr_list); 290225cf1a30Sjl139090 goto logexit; 290325cf1a30Sjl139090 } 290425cf1a30Sjl139090 290525cf1a30Sjl139090 (void) sysevent_attach_attributes(ev, evnt_attr_list); 290625cf1a30Sjl139090 290725cf1a30Sjl139090 /* 290825cf1a30Sjl139090 * Log the event but do not sleep waiting for its 290925cf1a30Sjl139090 * delivery. This provides insulation from syseventd. 291025cf1a30Sjl139090 */ 291125cf1a30Sjl139090 rv = log_sysevent(ev, SE_NOSLEEP, &eid); 291225cf1a30Sjl139090 291325cf1a30Sjl139090 logexit: 291425cf1a30Sjl139090 if (ev) 291525cf1a30Sjl139090 sysevent_free(ev); 291625cf1a30Sjl139090 if ((rv != 0) && verbose) 2917e98fafb9Sjl139090 cmn_err(CE_WARN, "drmach_log_sysevent failed (rv %d) for %s " 2918e98fafb9Sjl139090 " %s\n", rv, attach_pnt, hint); 291925cf1a30Sjl139090 292025cf1a30Sjl139090 return (rv); 292125cf1a30Sjl139090 } 292225cf1a30Sjl139090 292325cf1a30Sjl139090 #define OPL_DR_STATUS_PROP "dr-status" 292425cf1a30Sjl139090 292525cf1a30Sjl139090 static int 292625cf1a30Sjl139090 opl_check_dr_status() 292725cf1a30Sjl139090 { 292825cf1a30Sjl139090 pnode_t node; 292925cf1a30Sjl139090 int rtn, len; 293025cf1a30Sjl139090 char *str; 293125cf1a30Sjl139090 293225cf1a30Sjl139090 node = prom_rootnode(); 293325cf1a30Sjl139090 if (node == OBP_BADNODE) { 293425cf1a30Sjl139090 return (1); 293525cf1a30Sjl139090 } 293625cf1a30Sjl139090 293725cf1a30Sjl139090 len = prom_getproplen(node, OPL_DR_STATUS_PROP); 293825cf1a30Sjl139090 if (len == -1) { 293925cf1a30Sjl139090 /* 294025cf1a30Sjl139090 * dr-status doesn't exist when DR is activated and 294125cf1a30Sjl139090 * any warning messages aren't needed. 294225cf1a30Sjl139090 */ 294325cf1a30Sjl139090 return (1); 294425cf1a30Sjl139090 } 294525cf1a30Sjl139090 294625cf1a30Sjl139090 str = (char *)kmem_zalloc(len+1, KM_SLEEP); 294725cf1a30Sjl139090 rtn = prom_getprop(node, OPL_DR_STATUS_PROP, str); 294825cf1a30Sjl139090 kmem_free(str, len + 1); 294925cf1a30Sjl139090 if (rtn == -1) { 295025cf1a30Sjl139090 return (1); 295125cf1a30Sjl139090 } else { 295225cf1a30Sjl139090 return (0); 295325cf1a30Sjl139090 } 295425cf1a30Sjl139090 } 295525cf1a30Sjl139090 295625cf1a30Sjl139090 /* we are allocating memlist from TLB locked pages to avoid tlbmisses */ 295725cf1a30Sjl139090 295825cf1a30Sjl139090 static struct memlist * 295925cf1a30Sjl139090 drmach_memlist_add_span(drmach_copy_rename_program_t *p, 296025cf1a30Sjl139090 struct memlist *mlist, uint64_t base, uint64_t len) 296125cf1a30Sjl139090 { 296225cf1a30Sjl139090 struct memlist *ml, *tl, *nl; 296325cf1a30Sjl139090 296425cf1a30Sjl139090 if (len == 0ull) 296525cf1a30Sjl139090 return (NULL); 296625cf1a30Sjl139090 296725cf1a30Sjl139090 if (mlist == NULL) { 296825cf1a30Sjl139090 mlist = p->free_mlist; 296925cf1a30Sjl139090 if (mlist == NULL) 297025cf1a30Sjl139090 return (NULL); 297156f33205SJonathan Adams p->free_mlist = mlist->ml_next; 297256f33205SJonathan Adams mlist->ml_address = base; 297356f33205SJonathan Adams mlist->ml_size = len; 297456f33205SJonathan Adams mlist->ml_next = mlist->ml_prev = NULL; 297525cf1a30Sjl139090 297625cf1a30Sjl139090 return (mlist); 297725cf1a30Sjl139090 } 297825cf1a30Sjl139090 297956f33205SJonathan Adams for (tl = ml = mlist; ml; tl = ml, ml = ml->ml_next) { 298056f33205SJonathan Adams if (base < ml->ml_address) { 298156f33205SJonathan Adams if ((base + len) < ml->ml_address) { 298225cf1a30Sjl139090 nl = p->free_mlist; 298325cf1a30Sjl139090 if (nl == NULL) 298425cf1a30Sjl139090 return (NULL); 298556f33205SJonathan Adams p->free_mlist = nl->ml_next; 298656f33205SJonathan Adams nl->ml_address = base; 298756f33205SJonathan Adams nl->ml_size = len; 298856f33205SJonathan Adams nl->ml_next = ml; 298956f33205SJonathan Adams if ((nl->ml_prev = ml->ml_prev) != NULL) 299056f33205SJonathan Adams nl->ml_prev->ml_next = nl; 299156f33205SJonathan Adams ml->ml_prev = nl; 299225cf1a30Sjl139090 if (mlist == ml) 299325cf1a30Sjl139090 mlist = nl; 299425cf1a30Sjl139090 } else { 299556f33205SJonathan Adams ml->ml_size = MAX((base + len), 299656f33205SJonathan Adams (ml->ml_address + ml->ml_size)) - base; 299756f33205SJonathan Adams ml->ml_address = base; 299825cf1a30Sjl139090 } 299925cf1a30Sjl139090 break; 300025cf1a30Sjl139090 300156f33205SJonathan Adams } else if (base <= (ml->ml_address + ml->ml_size)) { 300256f33205SJonathan Adams ml->ml_size = 300356f33205SJonathan Adams MAX((base + len), (ml->ml_address + ml->ml_size)) - 300456f33205SJonathan Adams MIN(ml->ml_address, base); 300556f33205SJonathan Adams ml->ml_address = MIN(ml->ml_address, base); 300625cf1a30Sjl139090 break; 300725cf1a30Sjl139090 } 300825cf1a30Sjl139090 } 300925cf1a30Sjl139090 if (ml == NULL) { 301025cf1a30Sjl139090 nl = p->free_mlist; 301125cf1a30Sjl139090 if (nl == NULL) 301225cf1a30Sjl139090 return (NULL); 301356f33205SJonathan Adams p->free_mlist = nl->ml_next; 301456f33205SJonathan Adams nl->ml_address = base; 301556f33205SJonathan Adams nl->ml_size = len; 301656f33205SJonathan Adams nl->ml_next = NULL; 301756f33205SJonathan Adams nl->ml_prev = tl; 301856f33205SJonathan Adams tl->ml_next = nl; 301925cf1a30Sjl139090 } 302025cf1a30Sjl139090 302125cf1a30Sjl139090 return (mlist); 302225cf1a30Sjl139090 } 302325cf1a30Sjl139090 302425cf1a30Sjl139090 /* 302525cf1a30Sjl139090 * The routine performs the necessary memory COPY and MC adr SWITCH. 302625cf1a30Sjl139090 * Both operations MUST be at the same "level" so that the stack is 302725cf1a30Sjl139090 * maintained correctly between the copy and switch. The switch 302825cf1a30Sjl139090 * portion implements a caching mechanism to guarantee the code text 302925cf1a30Sjl139090 * is cached prior to execution. This is to guard against possible 303025cf1a30Sjl139090 * memory access while the MC adr's are being modified. 303125cf1a30Sjl139090 * 303225cf1a30Sjl139090 * IMPORTANT: The _drmach_copy_rename_end() function must immediately 303325cf1a30Sjl139090 * follow drmach_copy_rename_prog__relocatable() so that the correct 303425cf1a30Sjl139090 * "length" of the drmach_copy_rename_prog__relocatable can be 303525cf1a30Sjl139090 * calculated. This routine MUST be a LEAF function, i.e. it can 303625cf1a30Sjl139090 * make NO function calls, primarily for two reasons: 303725cf1a30Sjl139090 * 303825cf1a30Sjl139090 * 1. We must keep the stack consistent across the "switch". 303925cf1a30Sjl139090 * 2. Function calls are compiled to relative offsets, and 304025cf1a30Sjl139090 * we execute this function we'll be executing it from 304125cf1a30Sjl139090 * a copied version in a different area of memory, thus 304225cf1a30Sjl139090 * the relative offsets will be bogus. 304325cf1a30Sjl139090 * 304425cf1a30Sjl139090 * Moreover, it must have the "__relocatable" suffix to inform DTrace 304525cf1a30Sjl139090 * providers (and anything else, for that matter) that this 304625cf1a30Sjl139090 * function's text is manually relocated elsewhere before it is 304725cf1a30Sjl139090 * executed. That is, it cannot be safely instrumented with any 304825cf1a30Sjl139090 * methodology that is PC-relative. 304925cf1a30Sjl139090 */ 305025cf1a30Sjl139090 305125cf1a30Sjl139090 /* 305225cf1a30Sjl139090 * We multiply this to system_clock_frequency so we 305325cf1a30Sjl139090 * are setting a delay of fmem_timeout second for 3054b307f191Sbm42561 * the rename command. 3055b307f191Sbm42561 * 3056b307f191Sbm42561 * FMEM command itself should complete within 15 sec. 3057b307f191Sbm42561 * We add 2 more sec to be conservative. 3058b307f191Sbm42561 * 3059b307f191Sbm42561 * Note that there is also a SCF BUSY bit checking 3060b307f191Sbm42561 * in drmach_asm.s right before FMEM command is 3061b307f191Sbm42561 * issued. XSCF sets the SCF BUSY bit when the 3062b307f191Sbm42561 * other domain on the same PSB reboots and it 3063b307f191Sbm42561 * will not be able to service the FMEM command 3064b307f191Sbm42561 * within 15 sec. After setting the SCF BUSY 3065b307f191Sbm42561 * bit, XSCF will wait a while before servicing 3066b307f191Sbm42561 * other reboot command so there is no race 3067b307f191Sbm42561 * condition. 306825cf1a30Sjl139090 */ 3069b307f191Sbm42561 307025cf1a30Sjl139090 static int fmem_timeout = 17; 3071b307f191Sbm42561 3072b307f191Sbm42561 /* 3073b307f191Sbm42561 * The empirical data on some OPL system shows that 3074b307f191Sbm42561 * we can copy 250 MB per second. We set it to 3075b307f191Sbm42561 * 80 MB to be conservative. In normal case, 3076b307f191Sbm42561 * this timeout does not affect anything. 3077b307f191Sbm42561 */ 3078b307f191Sbm42561 3079b307f191Sbm42561 static int min_copy_size_per_sec = 80 * 1024 * 1024; 3080b307f191Sbm42561 3081b307f191Sbm42561 /* 3082b307f191Sbm42561 * This is the timeout value for the xcall synchronization 3083b307f191Sbm42561 * to get all the CPU ready to do the parallel copying. 3084b307f191Sbm42561 * Even on a fully loaded system, 10 sec. should be long 3085b307f191Sbm42561 * enough. 3086b307f191Sbm42561 */ 3087b307f191Sbm42561 3088b307f191Sbm42561 static int cpu_xcall_delay = 10; 308925cf1a30Sjl139090 int drmach_disable_mcopy = 0; 309025cf1a30Sjl139090 309168ac2337Sjl139090 /* 309268ac2337Sjl139090 * The following delay loop executes sleep instruction to yield the 309368ac2337Sjl139090 * CPU to other strands. If this is not done, some strand will tie 309468ac2337Sjl139090 * up the CPU in busy loops while the other strand cannot do useful 309568ac2337Sjl139090 * work. The copy procedure will take a much longer time without this. 309668ac2337Sjl139090 */ 309725cf1a30Sjl139090 #define DR_DELAY_IL(ms, freq) \ 309825cf1a30Sjl139090 { \ 309925cf1a30Sjl139090 uint64_t start; \ 310025cf1a30Sjl139090 uint64_t nstick; \ 310125cf1a30Sjl139090 volatile uint64_t now; \ 310225cf1a30Sjl139090 nstick = ((uint64_t)ms * freq)/1000; \ 310325cf1a30Sjl139090 start = drmach_get_stick_il(); \ 310425cf1a30Sjl139090 now = start; \ 310525cf1a30Sjl139090 while ((now - start) <= nstick) { \ 310625cf1a30Sjl139090 drmach_sleep_il(); \ 310725cf1a30Sjl139090 now = drmach_get_stick_il(); \ 310825cf1a30Sjl139090 } \ 310925cf1a30Sjl139090 } 311025cf1a30Sjl139090 31116534c6f0Swh31274 /* Each loop is 2ms, timeout at 1000ms */ 31126534c6f0Swh31274 static int drmach_copy_rename_timeout = 500; 31136534c6f0Swh31274 311425cf1a30Sjl139090 static int 311525cf1a30Sjl139090 drmach_copy_rename_prog__relocatable(drmach_copy_rename_program_t *prog, 311625cf1a30Sjl139090 int cpuid) 311725cf1a30Sjl139090 { 311825cf1a30Sjl139090 struct memlist *ml; 311925cf1a30Sjl139090 register int rtn; 312025cf1a30Sjl139090 int i; 312125cf1a30Sjl139090 register uint64_t curr, limit; 312225cf1a30Sjl139090 extern uint64_t drmach_get_stick_il(); 312325cf1a30Sjl139090 extern void membar_sync_il(); 312425cf1a30Sjl139090 extern void flush_instr_mem_il(void*); 312568ac2337Sjl139090 extern void flush_windows_il(void); 312625cf1a30Sjl139090 uint64_t copy_start; 312725cf1a30Sjl139090 312868ac2337Sjl139090 /* 312968ac2337Sjl139090 * flush_windows is moved here to make sure all 313068ac2337Sjl139090 * registers used in the callers are flushed to 313168ac2337Sjl139090 * memory before the copy. 313268ac2337Sjl139090 * 313368ac2337Sjl139090 * If flush_windows() is called too early in the 313468ac2337Sjl139090 * calling function, the compiler might put some 313568ac2337Sjl139090 * data in the local registers after flush_windows(). 313668ac2337Sjl139090 * After FMA, if there is any fill trap, the registers 313768ac2337Sjl139090 * will contain stale data. 313868ac2337Sjl139090 */ 313968ac2337Sjl139090 314068ac2337Sjl139090 flush_windows_il(); 314168ac2337Sjl139090 314225cf1a30Sjl139090 prog->critical->stat[cpuid] = FMEM_LOOP_COPY_READY; 314325cf1a30Sjl139090 membar_sync_il(); 314425cf1a30Sjl139090 314525cf1a30Sjl139090 if (prog->data->cpuid == cpuid) { 314625cf1a30Sjl139090 limit = drmach_get_stick_il(); 3147b307f191Sbm42561 limit += cpu_xcall_delay * system_clock_freq; 314825cf1a30Sjl139090 for (i = 0; i < NCPU; i++) { 314925cf1a30Sjl139090 if (CPU_IN_SET(prog->data->cpu_slave_set, i)) { 315025cf1a30Sjl139090 /* wait for all CPU's to be ready */ 315125cf1a30Sjl139090 for (;;) { 315225cf1a30Sjl139090 if (prog->critical->stat[i] == 315325cf1a30Sjl139090 FMEM_LOOP_COPY_READY) { 315425cf1a30Sjl139090 break; 315525cf1a30Sjl139090 } 315668ac2337Sjl139090 DR_DELAY_IL(1, prog->data->stick_freq); 315725cf1a30Sjl139090 } 315825cf1a30Sjl139090 curr = drmach_get_stick_il(); 315925cf1a30Sjl139090 if (curr > limit) { 316025cf1a30Sjl139090 prog->data->fmem_status.error = 3161b307f191Sbm42561 EOPL_FMEM_XC_TIMEOUT; 3162b307f191Sbm42561 return (EOPL_FMEM_XC_TIMEOUT); 316325cf1a30Sjl139090 } 316425cf1a30Sjl139090 } 316525cf1a30Sjl139090 } 316625cf1a30Sjl139090 prog->data->fmem_status.stat = FMEM_LOOP_COPY_READY; 316725cf1a30Sjl139090 membar_sync_il(); 316825cf1a30Sjl139090 copy_start = drmach_get_stick_il(); 316925cf1a30Sjl139090 } else { 317025cf1a30Sjl139090 for (;;) { 317125cf1a30Sjl139090 if (prog->data->fmem_status.stat == 317225cf1a30Sjl139090 FMEM_LOOP_COPY_READY) { 317325cf1a30Sjl139090 break; 317425cf1a30Sjl139090 } 317525cf1a30Sjl139090 if (prog->data->fmem_status.error) { 3176e98fafb9Sjl139090 prog->data->error[cpuid] = EOPL_FMEM_TERMINATE; 3177b307f191Sbm42561 return (EOPL_FMEM_TERMINATE); 317825cf1a30Sjl139090 } 317968ac2337Sjl139090 DR_DELAY_IL(1, prog->data->stick_freq); 318025cf1a30Sjl139090 } 318125cf1a30Sjl139090 } 318225cf1a30Sjl139090 318325cf1a30Sjl139090 /* 318425cf1a30Sjl139090 * DO COPY. 318525cf1a30Sjl139090 */ 318625cf1a30Sjl139090 if (CPU_IN_SET(prog->data->cpu_copy_set, cpuid)) { 318756f33205SJonathan Adams for (ml = prog->data->cpu_ml[cpuid]; ml; ml = ml->ml_next) { 318825cf1a30Sjl139090 uint64_t s_pa, t_pa; 318925cf1a30Sjl139090 uint64_t nbytes; 319025cf1a30Sjl139090 319156f33205SJonathan Adams s_pa = prog->data->s_copybasepa + ml->ml_address; 319256f33205SJonathan Adams t_pa = prog->data->t_copybasepa + ml->ml_address; 319356f33205SJonathan Adams nbytes = ml->ml_size; 319425cf1a30Sjl139090 319525cf1a30Sjl139090 while (nbytes != 0ull) { 3196e98fafb9Sjl139090 /* 3197e98fafb9Sjl139090 * If the master has detected error, we just 3198e98fafb9Sjl139090 * bail out 3199e98fafb9Sjl139090 */ 3200e98fafb9Sjl139090 if (prog->data->fmem_status.error != 3201e98fafb9Sjl139090 ESBD_NOERROR) { 3202b307f191Sbm42561 prog->data->error[cpuid] = 3203b307f191Sbm42561 EOPL_FMEM_TERMINATE; 3204b307f191Sbm42561 return (EOPL_FMEM_TERMINATE); 320525cf1a30Sjl139090 } 320625cf1a30Sjl139090 /* 320725cf1a30Sjl139090 * This copy does NOT use an ASI 320825cf1a30Sjl139090 * that avoids the Ecache, therefore 320925cf1a30Sjl139090 * the dst_pa addresses may remain 321025cf1a30Sjl139090 * in our Ecache after the dst_pa 321125cf1a30Sjl139090 * has been removed from the system. 321225cf1a30Sjl139090 * A subsequent write-back to memory 321325cf1a30Sjl139090 * will cause an ARB-stop because the 321425cf1a30Sjl139090 * physical address no longer exists 321525cf1a30Sjl139090 * in the system. Therefore we must 321625cf1a30Sjl139090 * flush out local Ecache after we 321725cf1a30Sjl139090 * finish the copy. 321825cf1a30Sjl139090 */ 321925cf1a30Sjl139090 322025cf1a30Sjl139090 /* copy 32 bytes at src_pa to dst_pa */ 322125cf1a30Sjl139090 bcopy32_il(s_pa, t_pa); 322225cf1a30Sjl139090 3223e98fafb9Sjl139090 /* 3224e98fafb9Sjl139090 * increment the counter to signal that we are 3225e98fafb9Sjl139090 * alive 3226e98fafb9Sjl139090 */ 322725cf1a30Sjl139090 prog->stat->nbytes[cpuid] += 32; 322825cf1a30Sjl139090 322925cf1a30Sjl139090 /* increment by 32 bytes */ 323025cf1a30Sjl139090 s_pa += (4 * sizeof (uint64_t)); 323125cf1a30Sjl139090 t_pa += (4 * sizeof (uint64_t)); 323225cf1a30Sjl139090 323325cf1a30Sjl139090 /* decrement by 32 bytes */ 323425cf1a30Sjl139090 nbytes -= (4 * sizeof (uint64_t)); 323525cf1a30Sjl139090 } 323625cf1a30Sjl139090 } 323725cf1a30Sjl139090 prog->critical->stat[cpuid] = FMEM_LOOP_COPY_DONE; 323825cf1a30Sjl139090 membar_sync_il(); 323925cf1a30Sjl139090 } 324025cf1a30Sjl139090 324125cf1a30Sjl139090 /* 324225cf1a30Sjl139090 * Since bcopy32_il() does NOT use an ASI to bypass 324325cf1a30Sjl139090 * the Ecache, we need to flush our Ecache after 324425cf1a30Sjl139090 * the copy is complete. 324525cf1a30Sjl139090 */ 324625cf1a30Sjl139090 flush_cache_il(); 324725cf1a30Sjl139090 324825cf1a30Sjl139090 /* 324925cf1a30Sjl139090 * drmach_fmem_exec_script() 325025cf1a30Sjl139090 */ 325125cf1a30Sjl139090 if (prog->data->cpuid == cpuid) { 325225cf1a30Sjl139090 uint64_t last, now; 325325cf1a30Sjl139090 325425cf1a30Sjl139090 limit = copy_start + prog->data->copy_delay; 325525cf1a30Sjl139090 for (i = 0; i < NCPU; i++) { 3256e98fafb9Sjl139090 if (!CPU_IN_SET(prog->data->cpu_slave_set, i)) 3257e98fafb9Sjl139090 continue; 3258e98fafb9Sjl139090 325925cf1a30Sjl139090 for (;;) { 3260e98fafb9Sjl139090 /* 3261e98fafb9Sjl139090 * we get FMEM_LOOP_FMEM_READY in 3262e98fafb9Sjl139090 * normal case 3263e98fafb9Sjl139090 */ 326425cf1a30Sjl139090 if (prog->critical->stat[i] == 326525cf1a30Sjl139090 FMEM_LOOP_FMEM_READY) { 326625cf1a30Sjl139090 break; 326725cf1a30Sjl139090 } 326825cf1a30Sjl139090 /* got error traps */ 3269b307f191Sbm42561 if (prog->data->error[i] == 3270b307f191Sbm42561 EOPL_FMEM_COPY_ERROR) { 327125cf1a30Sjl139090 prog->data->fmem_status.error = 3272b307f191Sbm42561 EOPL_FMEM_COPY_ERROR; 3273b307f191Sbm42561 return (EOPL_FMEM_COPY_ERROR); 327425cf1a30Sjl139090 } 3275e98fafb9Sjl139090 /* 3276e98fafb9Sjl139090 * if we have not reached limit, wait 3277e98fafb9Sjl139090 * more 3278e98fafb9Sjl139090 */ 327925cf1a30Sjl139090 curr = drmach_get_stick_il(); 328025cf1a30Sjl139090 if (curr <= limit) 328125cf1a30Sjl139090 continue; 328225cf1a30Sjl139090 328325cf1a30Sjl139090 prog->data->slowest_cpuid = i; 3284e98fafb9Sjl139090 prog->data->copy_wait_time = curr - copy_start; 328525cf1a30Sjl139090 328625cf1a30Sjl139090 /* now check if slave is alive */ 328725cf1a30Sjl139090 last = prog->stat->nbytes[i]; 328825cf1a30Sjl139090 328925cf1a30Sjl139090 DR_DELAY_IL(1, prog->data->stick_freq); 329025cf1a30Sjl139090 329125cf1a30Sjl139090 now = prog->stat->nbytes[i]; 329225cf1a30Sjl139090 if (now <= last) { 3293e98fafb9Sjl139090 /* 3294e98fafb9Sjl139090 * no progress, perhaps just 3295e98fafb9Sjl139090 * finished 3296e98fafb9Sjl139090 */ 329725cf1a30Sjl139090 DR_DELAY_IL(1, prog->data->stick_freq); 329825cf1a30Sjl139090 if (prog->critical->stat[i] == 329925cf1a30Sjl139090 FMEM_LOOP_FMEM_READY) 330025cf1a30Sjl139090 break; 330125cf1a30Sjl139090 /* copy error */ 3302b307f191Sbm42561 if (prog->data->error[i] == 3303b307f191Sbm42561 EOPL_FMEM_COPY_ERROR) { 330425cf1a30Sjl139090 prog->data-> fmem_status.error = 3305b307f191Sbm42561 EOPL_FMEM_COPY_ERROR; 3306b307f191Sbm42561 return (EOPL_FMEM_COPY_ERROR); 330725cf1a30Sjl139090 } 33086534c6f0Swh31274 33096534c6f0Swh31274 prog->data->copy_rename_count++; 33106534c6f0Swh31274 if (prog->data->copy_rename_count 33116534c6f0Swh31274 < drmach_copy_rename_timeout) { 33126534c6f0Swh31274 continue; 33136534c6f0Swh31274 } else { 331425cf1a30Sjl139090 prog->data->fmem_status.error = 3315b307f191Sbm42561 EOPL_FMEM_COPY_TIMEOUT; 3316b307f191Sbm42561 return (EOPL_FMEM_COPY_TIMEOUT); 331725cf1a30Sjl139090 } 331825cf1a30Sjl139090 } 331925cf1a30Sjl139090 } 33206534c6f0Swh31274 } 3321b307f191Sbm42561 332225cf1a30Sjl139090 prog->critical->stat[cpuid] = FMEM_LOOP_FMEM_READY; 332325cf1a30Sjl139090 prog->data->fmem_status.stat = FMEM_LOOP_FMEM_READY; 332425cf1a30Sjl139090 332525cf1a30Sjl139090 membar_sync_il(); 332625cf1a30Sjl139090 flush_instr_mem_il((void*) (prog->critical)); 332725cf1a30Sjl139090 /* 332825cf1a30Sjl139090 * drmach_fmem_exec_script() 332925cf1a30Sjl139090 */ 333025cf1a30Sjl139090 rtn = prog->critical->fmem((void *)prog->critical, PAGESIZE); 333125cf1a30Sjl139090 return (rtn); 333225cf1a30Sjl139090 } else { 333325cf1a30Sjl139090 flush_instr_mem_il((void*) (prog->critical)); 333425cf1a30Sjl139090 /* 333525cf1a30Sjl139090 * drmach_fmem_loop_script() 333625cf1a30Sjl139090 */ 3337e98fafb9Sjl139090 rtn = prog->critical->loop((void *)(prog->critical), PAGESIZE, 3338e98fafb9Sjl139090 (void *)&(prog->critical->stat[cpuid])); 333925cf1a30Sjl139090 prog->data->error[cpuid] = rtn; 334025cf1a30Sjl139090 /* slave thread does not care the rv */ 334125cf1a30Sjl139090 return (0); 334225cf1a30Sjl139090 } 334325cf1a30Sjl139090 } 334425cf1a30Sjl139090 334525cf1a30Sjl139090 static void 334625cf1a30Sjl139090 drmach_copy_rename_end(void) 334725cf1a30Sjl139090 { 334825cf1a30Sjl139090 /* 334925cf1a30Sjl139090 * IMPORTANT: This function's location MUST be located immediately 335025cf1a30Sjl139090 * following drmach_copy_rename_prog__relocatable to 335125cf1a30Sjl139090 * accurately estimate its size. Note that this assumes 335225cf1a30Sjl139090 * the compiler keeps these functions in the order in 335325cf1a30Sjl139090 * which they appear :-o 335425cf1a30Sjl139090 */ 335525cf1a30Sjl139090 } 335625cf1a30Sjl139090 335725cf1a30Sjl139090 33586534c6f0Swh31274 static int 335925cf1a30Sjl139090 drmach_setup_memlist(drmach_copy_rename_program_t *p) 336025cf1a30Sjl139090 { 336125cf1a30Sjl139090 struct memlist *ml; 336225cf1a30Sjl139090 caddr_t buf; 33636534c6f0Swh31274 int nbytes, s, n_elements; 336425cf1a30Sjl139090 336525cf1a30Sjl139090 nbytes = PAGESIZE; 33666534c6f0Swh31274 n_elements = 0; 336725cf1a30Sjl139090 s = roundup(sizeof (struct memlist), sizeof (void *)); 336825cf1a30Sjl139090 p->free_mlist = NULL; 336925cf1a30Sjl139090 buf = p->memlist_buffer; 337025cf1a30Sjl139090 while (nbytes >= sizeof (struct memlist)) { 337125cf1a30Sjl139090 ml = (struct memlist *)buf; 337256f33205SJonathan Adams ml->ml_next = p->free_mlist; 337325cf1a30Sjl139090 p->free_mlist = ml; 337425cf1a30Sjl139090 buf += s; 33756534c6f0Swh31274 n_elements++; 337625cf1a30Sjl139090 nbytes -= s; 337725cf1a30Sjl139090 } 33786534c6f0Swh31274 return (n_elements); 337925cf1a30Sjl139090 } 338025cf1a30Sjl139090 338168ac2337Sjl139090 static void 338268ac2337Sjl139090 drmach_lock_critical(caddr_t va, caddr_t new_va) 338368ac2337Sjl139090 { 338468ac2337Sjl139090 tte_t tte; 338568ac2337Sjl139090 int i; 338668ac2337Sjl139090 338768ac2337Sjl139090 kpreempt_disable(); 338868ac2337Sjl139090 338968ac2337Sjl139090 for (i = 0; i < DRMACH_FMEM_LOCKED_PAGES; i++) { 339068ac2337Sjl139090 vtag_flushpage(new_va, (uint64_t)ksfmmup); 3391e98fafb9Sjl139090 sfmmu_memtte(&tte, va_to_pfn(va), PROC_DATA|HAT_NOSYNC, TTE8K); 339268ac2337Sjl139090 tte.tte_intlo |= TTE_LCK_INT; 339368ac2337Sjl139090 sfmmu_dtlb_ld_kva(new_va, &tte); 339468ac2337Sjl139090 sfmmu_itlb_ld_kva(new_va, &tte); 339568ac2337Sjl139090 va += PAGESIZE; 339668ac2337Sjl139090 new_va += PAGESIZE; 339768ac2337Sjl139090 } 339868ac2337Sjl139090 } 339968ac2337Sjl139090 340068ac2337Sjl139090 static void 340168ac2337Sjl139090 drmach_unlock_critical(caddr_t va) 340268ac2337Sjl139090 { 340368ac2337Sjl139090 int i; 340468ac2337Sjl139090 340568ac2337Sjl139090 for (i = 0; i < DRMACH_FMEM_LOCKED_PAGES; i++) { 340668ac2337Sjl139090 vtag_flushpage(va, (uint64_t)ksfmmup); 340768ac2337Sjl139090 va += PAGESIZE; 340868ac2337Sjl139090 } 340968ac2337Sjl139090 341068ac2337Sjl139090 kpreempt_enable(); 341168ac2337Sjl139090 } 341268ac2337Sjl139090 341325cf1a30Sjl139090 sbd_error_t * 341425cf1a30Sjl139090 drmach_copy_rename_init(drmachid_t t_id, drmachid_t s_id, 341525cf1a30Sjl139090 struct memlist *c_ml, drmachid_t *pgm_id) 341625cf1a30Sjl139090 { 341725cf1a30Sjl139090 drmach_mem_t *s_mem; 341825cf1a30Sjl139090 drmach_mem_t *t_mem; 341925cf1a30Sjl139090 struct memlist *x_ml; 342025cf1a30Sjl139090 uint64_t s_copybasepa, t_copybasepa; 342125cf1a30Sjl139090 uint_t len; 342225cf1a30Sjl139090 caddr_t bp, wp; 342325cf1a30Sjl139090 int s_bd, t_bd, cpuid, active_cpus, i; 34246534c6f0Swh31274 int max_elms, mlist_size, rv; 342525cf1a30Sjl139090 uint64_t c_addr; 342625cf1a30Sjl139090 size_t c_size, copy_sz, sz; 342725cf1a30Sjl139090 extern void drmach_fmem_loop_script(); 342825cf1a30Sjl139090 extern void drmach_fmem_loop_script_rtn(); 342925cf1a30Sjl139090 extern int drmach_fmem_exec_script(); 343025cf1a30Sjl139090 extern void drmach_fmem_exec_script_end(); 343125cf1a30Sjl139090 sbd_error_t *err; 343268ac2337Sjl139090 drmach_copy_rename_program_t *prog = NULL; 343368ac2337Sjl139090 drmach_copy_rename_program_t *prog_kmem = NULL; 343425cf1a30Sjl139090 void (*mc_suspend)(void); 343525cf1a30Sjl139090 void (*mc_resume)(void); 343625cf1a30Sjl139090 int (*scf_fmem_start)(int, int); 343725cf1a30Sjl139090 int (*scf_fmem_end)(void); 343825cf1a30Sjl139090 int (*scf_fmem_cancel)(void); 343968ac2337Sjl139090 uint64_t (*scf_get_base_addr)(void); 344025cf1a30Sjl139090 344125cf1a30Sjl139090 if (!DRMACH_IS_MEM_ID(s_id)) 344225cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 344325cf1a30Sjl139090 if (!DRMACH_IS_MEM_ID(t_id)) 344425cf1a30Sjl139090 return (drerr_new(0, EOPL_INAPPROP, NULL)); 344525cf1a30Sjl139090 344625cf1a30Sjl139090 for (i = 0; i < NCPU; i++) { 344725cf1a30Sjl139090 int lsb_id, onb_core_num, strand_id; 344825cf1a30Sjl139090 drmach_board_t *bp; 344925cf1a30Sjl139090 345025cf1a30Sjl139090 /* 345125cf1a30Sjl139090 * this kind of CPU will spin in cache 345225cf1a30Sjl139090 */ 345325cf1a30Sjl139090 if (CPU_IN_SET(cpu_ready_set, i)) 345425cf1a30Sjl139090 continue; 345525cf1a30Sjl139090 345625cf1a30Sjl139090 /* 345725cf1a30Sjl139090 * Now check for any inactive CPU's that 345825cf1a30Sjl139090 * have been hotadded. This can only occur in 345925cf1a30Sjl139090 * error condition in drmach_cpu_poweron(). 346025cf1a30Sjl139090 */ 346125cf1a30Sjl139090 lsb_id = LSB_ID(i); 346225cf1a30Sjl139090 onb_core_num = ON_BOARD_CORE_NUM(i); 346325cf1a30Sjl139090 strand_id = STRAND_ID(i); 346425cf1a30Sjl139090 bp = drmach_get_board_by_bnum(lsb_id); 346525cf1a30Sjl139090 if (bp == NULL) 346625cf1a30Sjl139090 continue; 346725cf1a30Sjl139090 if (bp->cores[onb_core_num].core_hotadded & 346825cf1a30Sjl139090 (1 << strand_id)) { 346925cf1a30Sjl139090 if (!(bp->cores[onb_core_num].core_started & 347025cf1a30Sjl139090 (1 << strand_id))) { 34718eafe49bSbm42561 return (drerr_new(1, EOPL_CPU_STATE, NULL)); 347225cf1a30Sjl139090 } 347325cf1a30Sjl139090 } 347425cf1a30Sjl139090 } 347525cf1a30Sjl139090 347625cf1a30Sjl139090 mc_suspend = (void (*)(void)) 347725cf1a30Sjl139090 modgetsymvalue("opl_mc_suspend", 0); 347825cf1a30Sjl139090 mc_resume = (void (*)(void)) 347925cf1a30Sjl139090 modgetsymvalue("opl_mc_resume", 0); 348025cf1a30Sjl139090 348125cf1a30Sjl139090 if (mc_suspend == NULL || mc_resume == NULL) { 34828eafe49bSbm42561 return (drerr_new(1, EOPL_MC_OPL, NULL)); 348325cf1a30Sjl139090 } 348425cf1a30Sjl139090 348525cf1a30Sjl139090 scf_fmem_start = (int (*)(int, int)) 348625cf1a30Sjl139090 modgetsymvalue("scf_fmem_start", 0); 348725cf1a30Sjl139090 if (scf_fmem_start == NULL) { 34888eafe49bSbm42561 return (drerr_new(1, EOPL_SCF_FMEM, NULL)); 348925cf1a30Sjl139090 } 349025cf1a30Sjl139090 scf_fmem_end = (int (*)(void)) 349125cf1a30Sjl139090 modgetsymvalue("scf_fmem_end", 0); 349225cf1a30Sjl139090 if (scf_fmem_end == NULL) { 34938eafe49bSbm42561 return (drerr_new(1, EOPL_SCF_FMEM, NULL)); 349425cf1a30Sjl139090 } 349525cf1a30Sjl139090 scf_fmem_cancel = (int (*)(void)) 349625cf1a30Sjl139090 modgetsymvalue("scf_fmem_cancel", 0); 349725cf1a30Sjl139090 if (scf_fmem_cancel == NULL) { 34988eafe49bSbm42561 return (drerr_new(1, EOPL_SCF_FMEM, NULL)); 349968ac2337Sjl139090 } 350068ac2337Sjl139090 scf_get_base_addr = (uint64_t (*)(void)) 350168ac2337Sjl139090 modgetsymvalue("scf_get_base_addr", 0); 350268ac2337Sjl139090 if (scf_get_base_addr == NULL) { 35038eafe49bSbm42561 return (drerr_new(1, EOPL_SCF_FMEM, NULL)); 350425cf1a30Sjl139090 } 350525cf1a30Sjl139090 s_mem = s_id; 350625cf1a30Sjl139090 t_mem = t_id; 350725cf1a30Sjl139090 350825cf1a30Sjl139090 s_bd = s_mem->dev.bp->bnum; 350925cf1a30Sjl139090 t_bd = t_mem->dev.bp->bnum; 351025cf1a30Sjl139090 351125cf1a30Sjl139090 /* calculate source and target base pa */ 351225cf1a30Sjl139090 351325cf1a30Sjl139090 s_copybasepa = s_mem->slice_base; 351425cf1a30Sjl139090 t_copybasepa = t_mem->slice_base; 351525cf1a30Sjl139090 351625cf1a30Sjl139090 /* adjust copy memlist addresses to be relative to copy base pa */ 351725cf1a30Sjl139090 x_ml = c_ml; 35186534c6f0Swh31274 mlist_size = 0; 351925cf1a30Sjl139090 while (x_ml != NULL) { 352056f33205SJonathan Adams x_ml->ml_address -= s_copybasepa; 352156f33205SJonathan Adams x_ml = x_ml->ml_next; 35226534c6f0Swh31274 mlist_size++; 352325cf1a30Sjl139090 } 352425cf1a30Sjl139090 352525cf1a30Sjl139090 /* 352625cf1a30Sjl139090 * bp will be page aligned, since we're calling 352725cf1a30Sjl139090 * kmem_zalloc() with an exact multiple of PAGESIZE. 352825cf1a30Sjl139090 */ 352925cf1a30Sjl139090 353068ac2337Sjl139090 prog_kmem = (drmach_copy_rename_program_t *)kmem_zalloc( 353168ac2337Sjl139090 DRMACH_FMEM_LOCKED_PAGES * PAGESIZE, KM_SLEEP); 353268ac2337Sjl139090 353368ac2337Sjl139090 prog_kmem->prog = prog_kmem; 353468ac2337Sjl139090 353568ac2337Sjl139090 /* 353668ac2337Sjl139090 * To avoid MTLB hit, we allocate a new VM space and remap 353768ac2337Sjl139090 * the kmem_alloc buffer to that address. This solves 353868ac2337Sjl139090 * 2 problems we found: 353968ac2337Sjl139090 * - the kmem_alloc buffer can be just a chunk inside 354068ac2337Sjl139090 * a much larger, e.g. 4MB buffer and MTLB will occur 354168ac2337Sjl139090 * if there are both a 4MB and a 8K TLB mapping to 354268ac2337Sjl139090 * the same VA range. 354368ac2337Sjl139090 * - the kmem mapping got dropped into the TLB by other 354468ac2337Sjl139090 * strands, unintentionally. 354568ac2337Sjl139090 * Note that the pointers like data, critical, memlist_buffer, 354668ac2337Sjl139090 * and stat inside the copy rename structure are mapped to this 354768ac2337Sjl139090 * alternate VM space so we must make sure we lock the TLB mapping 354868ac2337Sjl139090 * whenever we access data pointed to by these pointers. 354968ac2337Sjl139090 */ 355068ac2337Sjl139090 355168ac2337Sjl139090 prog = prog_kmem->locked_prog = vmem_alloc(heap_arena, 355268ac2337Sjl139090 DRMACH_FMEM_LOCKED_PAGES * PAGESIZE, VM_SLEEP); 355368ac2337Sjl139090 wp = bp = (caddr_t)prog; 355468ac2337Sjl139090 355568ac2337Sjl139090 /* Now remap prog_kmem to prog */ 355668ac2337Sjl139090 drmach_lock_critical((caddr_t)prog_kmem, (caddr_t)prog); 355768ac2337Sjl139090 355868ac2337Sjl139090 /* All pointers in prog are based on the alternate mapping */ 355925cf1a30Sjl139090 prog->data = (drmach_copy_rename_data_t *)roundup(((uint64_t)prog + 356025cf1a30Sjl139090 sizeof (drmach_copy_rename_program_t)), sizeof (void *)); 356125cf1a30Sjl139090 356225cf1a30Sjl139090 ASSERT(((uint64_t)prog->data + sizeof (drmach_copy_rename_data_t)) 356325cf1a30Sjl139090 <= ((uint64_t)prog + PAGESIZE)); 356425cf1a30Sjl139090 356525cf1a30Sjl139090 prog->critical = (drmach_copy_rename_critical_t *) 356625cf1a30Sjl139090 (wp + DRMACH_FMEM_CRITICAL_PAGE * PAGESIZE); 356725cf1a30Sjl139090 3568e98fafb9Sjl139090 prog->memlist_buffer = (caddr_t)(wp + DRMACH_FMEM_MLIST_PAGE * 3569e98fafb9Sjl139090 PAGESIZE); 357025cf1a30Sjl139090 3571e98fafb9Sjl139090 prog->stat = (drmach_cr_stat_t *)(wp + DRMACH_FMEM_STAT_PAGE * 3572e98fafb9Sjl139090 PAGESIZE); 357325cf1a30Sjl139090 357425cf1a30Sjl139090 /* LINTED */ 3575e98fafb9Sjl139090 ASSERT(sizeof (drmach_cr_stat_t) <= ((DRMACH_FMEM_LOCKED_PAGES - 3576e98fafb9Sjl139090 DRMACH_FMEM_STAT_PAGE) * PAGESIZE)); 357725cf1a30Sjl139090 357825cf1a30Sjl139090 prog->critical->scf_reg_base = (uint64_t)-1; 357925cf1a30Sjl139090 prog->critical->scf_td[0] = (s_bd & 0xff); 358025cf1a30Sjl139090 prog->critical->scf_td[1] = (t_bd & 0xff); 358125cf1a30Sjl139090 for (i = 2; i < 15; i++) { 358225cf1a30Sjl139090 prog->critical->scf_td[i] = 0; 358325cf1a30Sjl139090 } 358425cf1a30Sjl139090 prog->critical->scf_td[15] = ((0xaa + s_bd + t_bd) & 0xff); 358525cf1a30Sjl139090 358625cf1a30Sjl139090 bp = (caddr_t)prog->critical; 358725cf1a30Sjl139090 len = sizeof (drmach_copy_rename_critical_t); 358825cf1a30Sjl139090 wp = (caddr_t)roundup((uint64_t)bp + len, sizeof (void *)); 358925cf1a30Sjl139090 359025cf1a30Sjl139090 len = (uint_t)((ulong_t)drmach_copy_rename_end - 359125cf1a30Sjl139090 (ulong_t)drmach_copy_rename_prog__relocatable); 359225cf1a30Sjl139090 359325cf1a30Sjl139090 /* 359425cf1a30Sjl139090 * We always leave 1K nop's to prevent the processor from 359525cf1a30Sjl139090 * speculative execution that causes memory access 359625cf1a30Sjl139090 */ 359725cf1a30Sjl139090 wp = wp + len + 1024; 359825cf1a30Sjl139090 359925cf1a30Sjl139090 len = (uint_t)((ulong_t)drmach_fmem_exec_script_end - 360025cf1a30Sjl139090 (ulong_t)drmach_fmem_exec_script); 360125cf1a30Sjl139090 /* this is the entry point of the loop script */ 360225cf1a30Sjl139090 wp = wp + len + 1024; 360325cf1a30Sjl139090 360425cf1a30Sjl139090 len = (uint_t)((ulong_t)drmach_fmem_exec_script - 360525cf1a30Sjl139090 (ulong_t)drmach_fmem_loop_script); 360625cf1a30Sjl139090 wp = wp + len + 1024; 360725cf1a30Sjl139090 360825cf1a30Sjl139090 /* now we make sure there is 1K extra */ 360925cf1a30Sjl139090 361025cf1a30Sjl139090 if ((wp - bp) > PAGESIZE) { 36118eafe49bSbm42561 err = drerr_new(1, EOPL_FMEM_SETUP, NULL); 361268ac2337Sjl139090 goto out; 361325cf1a30Sjl139090 } 361425cf1a30Sjl139090 361525cf1a30Sjl139090 bp = (caddr_t)prog->critical; 361625cf1a30Sjl139090 len = sizeof (drmach_copy_rename_critical_t); 361725cf1a30Sjl139090 wp = (caddr_t)roundup((uint64_t)bp + len, sizeof (void *)); 361825cf1a30Sjl139090 361925cf1a30Sjl139090 prog->critical->run = (int (*)())(wp); 362025cf1a30Sjl139090 len = (uint_t)((ulong_t)drmach_copy_rename_end - 362125cf1a30Sjl139090 (ulong_t)drmach_copy_rename_prog__relocatable); 362225cf1a30Sjl139090 362325cf1a30Sjl139090 bcopy((caddr_t)drmach_copy_rename_prog__relocatable, wp, len); 362425cf1a30Sjl139090 362525cf1a30Sjl139090 wp = (caddr_t)roundup((uint64_t)wp + len, 1024); 362625cf1a30Sjl139090 362725cf1a30Sjl139090 prog->critical->fmem = (int (*)())(wp); 362825cf1a30Sjl139090 len = (int)((ulong_t)drmach_fmem_exec_script_end - 362925cf1a30Sjl139090 (ulong_t)drmach_fmem_exec_script); 363025cf1a30Sjl139090 bcopy((caddr_t)drmach_fmem_exec_script, wp, len); 363125cf1a30Sjl139090 363225cf1a30Sjl139090 len = (int)((ulong_t)drmach_fmem_exec_script_end - 363325cf1a30Sjl139090 (ulong_t)drmach_fmem_exec_script); 363425cf1a30Sjl139090 wp = (caddr_t)roundup((uint64_t)wp + len, 1024); 363525cf1a30Sjl139090 363625cf1a30Sjl139090 prog->critical->loop = (int (*)())(wp); 363725cf1a30Sjl139090 len = (int)((ulong_t)drmach_fmem_exec_script - 363825cf1a30Sjl139090 (ulong_t)drmach_fmem_loop_script); 363925cf1a30Sjl139090 bcopy((caddr_t)drmach_fmem_loop_script, (void *)wp, len); 364025cf1a30Sjl139090 len = (int)((ulong_t)drmach_fmem_loop_script_rtn- 364125cf1a30Sjl139090 (ulong_t)drmach_fmem_loop_script); 364225cf1a30Sjl139090 prog->critical->loop_rtn = (void (*)()) (wp+len); 364325cf1a30Sjl139090 3644b307f191Sbm42561 prog->data->fmem_status.error = ESBD_NOERROR; 3645b307f191Sbm42561 364625cf1a30Sjl139090 /* now we are committed, call SCF, soft suspend mac patrol */ 364725cf1a30Sjl139090 if ((*scf_fmem_start)(s_bd, t_bd)) { 36488eafe49bSbm42561 err = drerr_new(1, EOPL_SCF_FMEM_START, NULL); 364968ac2337Sjl139090 goto out; 365025cf1a30Sjl139090 } 365125cf1a30Sjl139090 prog->data->scf_fmem_end = scf_fmem_end; 365225cf1a30Sjl139090 prog->data->scf_fmem_cancel = scf_fmem_cancel; 365368ac2337Sjl139090 prog->data->scf_get_base_addr = scf_get_base_addr; 365425cf1a30Sjl139090 prog->data->fmem_status.op |= OPL_FMEM_SCF_START; 3655b307f191Sbm42561 365625cf1a30Sjl139090 /* soft suspend mac patrol */ 365725cf1a30Sjl139090 (*mc_suspend)(); 365825cf1a30Sjl139090 prog->data->fmem_status.op |= OPL_FMEM_MC_SUSPEND; 365925cf1a30Sjl139090 prog->data->mc_resume = mc_resume; 366025cf1a30Sjl139090 366125cf1a30Sjl139090 prog->critical->inst_loop_ret = 366225cf1a30Sjl139090 *(uint64_t *)(prog->critical->loop_rtn); 366325cf1a30Sjl139090 366425cf1a30Sjl139090 /* 366525cf1a30Sjl139090 * 0x30800000 is op code "ba,a +0" 366625cf1a30Sjl139090 */ 366725cf1a30Sjl139090 366825cf1a30Sjl139090 *(uint_t *)(prog->critical->loop_rtn) = (uint_t)(0x30800000); 366925cf1a30Sjl139090 367025cf1a30Sjl139090 /* 367125cf1a30Sjl139090 * set the value of SCF FMEM TIMEOUT 367225cf1a30Sjl139090 */ 367325cf1a30Sjl139090 prog->critical->delay = fmem_timeout * system_clock_freq; 367425cf1a30Sjl139090 367525cf1a30Sjl139090 prog->data->s_mem = (drmachid_t)s_mem; 367625cf1a30Sjl139090 prog->data->t_mem = (drmachid_t)t_mem; 367725cf1a30Sjl139090 367825cf1a30Sjl139090 cpuid = CPU->cpu_id; 367925cf1a30Sjl139090 prog->data->cpuid = cpuid; 368025cf1a30Sjl139090 prog->data->cpu_ready_set = cpu_ready_set; 368125cf1a30Sjl139090 prog->data->cpu_slave_set = cpu_ready_set; 368225cf1a30Sjl139090 prog->data->slowest_cpuid = (processorid_t)-1; 368325cf1a30Sjl139090 prog->data->copy_wait_time = 0; 36846534c6f0Swh31274 prog->data->copy_rename_count = 0; 368525cf1a30Sjl139090 CPUSET_DEL(prog->data->cpu_slave_set, cpuid); 368625cf1a30Sjl139090 368725cf1a30Sjl139090 for (i = 0; i < NCPU; i++) { 368825cf1a30Sjl139090 prog->data->cpu_ml[i] = NULL; 368925cf1a30Sjl139090 } 369025cf1a30Sjl139090 36916534c6f0Swh31274 /* 36926534c6f0Swh31274 * max_elms - max number of memlist structures that 36936534c6f0Swh31274 * may be allocated for the CPU memory list. 36946534c6f0Swh31274 * If there are too many memory span (because 36956534c6f0Swh31274 * of fragmentation) than number of memlist 36966534c6f0Swh31274 * available, we should return error. 36976534c6f0Swh31274 */ 36986534c6f0Swh31274 max_elms = drmach_setup_memlist(prog); 36996534c6f0Swh31274 if (max_elms < mlist_size) { 37006534c6f0Swh31274 err = drerr_new(1, EOPL_FMEM_SETUP, NULL); 37016534c6f0Swh31274 goto err_out; 37026534c6f0Swh31274 } 37036534c6f0Swh31274 370425cf1a30Sjl139090 active_cpus = 0; 370525cf1a30Sjl139090 if (drmach_disable_mcopy) { 370625cf1a30Sjl139090 active_cpus = 1; 370725cf1a30Sjl139090 CPUSET_ADD(prog->data->cpu_copy_set, cpuid); 370825cf1a30Sjl139090 } else { 37096534c6f0Swh31274 int max_cpu_num; 37106534c6f0Swh31274 /* 37116534c6f0Swh31274 * The parallel copy procedure is going to split some 37126534c6f0Swh31274 * of the elements of the original memory copy list. 37136534c6f0Swh31274 * The number of added elements can be up to 37146534c6f0Swh31274 * (max_cpu_num - 1). It means that max_cpu_num 37156534c6f0Swh31274 * should satisfy the following condition: 37166534c6f0Swh31274 * (max_cpu_num - 1) + mlist_size <= max_elms. 37176534c6f0Swh31274 */ 37186534c6f0Swh31274 max_cpu_num = max_elms - mlist_size + 1; 37196534c6f0Swh31274 372025cf1a30Sjl139090 for (i = 0; i < NCPU; i++) { 372125cf1a30Sjl139090 if (CPU_IN_SET(cpu_ready_set, i) && 372225cf1a30Sjl139090 CPU_ACTIVE(cpu[i])) { 37236534c6f0Swh31274 /* 37246534c6f0Swh31274 * To reduce the level-2 cache contention only 37256534c6f0Swh31274 * one strand per core will participate 37266534c6f0Swh31274 * in the copy. If the strand with even cpu_id 37276534c6f0Swh31274 * number is present in the ready set, we will 37286534c6f0Swh31274 * include this strand in the copy set. If it 37296534c6f0Swh31274 * is not present in the ready set, we check for 37306534c6f0Swh31274 * the strand with the consecutive odd cpu_id 37316534c6f0Swh31274 * and include it, provided that it is 37326534c6f0Swh31274 * present in the ready set. 37336534c6f0Swh31274 */ 37346534c6f0Swh31274 if (!(i & 0x1) || 37356534c6f0Swh31274 !CPU_IN_SET(prog->data->cpu_copy_set, 37366534c6f0Swh31274 i - 1)) { 373725cf1a30Sjl139090 CPUSET_ADD(prog->data->cpu_copy_set, i); 373825cf1a30Sjl139090 active_cpus++; 37396534c6f0Swh31274 /* 37406534c6f0Swh31274 * We cannot have more than 37416534c6f0Swh31274 * max_cpu_num CPUs in the copy 37426534c6f0Swh31274 * set, because each CPU has to 37436534c6f0Swh31274 * have at least one element 37446534c6f0Swh31274 * long memory copy list. 37456534c6f0Swh31274 */ 37466534c6f0Swh31274 if (active_cpus >= max_cpu_num) 37476534c6f0Swh31274 break; 374825cf1a30Sjl139090 37496534c6f0Swh31274 } 37506534c6f0Swh31274 } 37516534c6f0Swh31274 } 37526534c6f0Swh31274 } 375325cf1a30Sjl139090 375425cf1a30Sjl139090 x_ml = c_ml; 375525cf1a30Sjl139090 sz = 0; 375625cf1a30Sjl139090 while (x_ml != NULL) { 375756f33205SJonathan Adams sz += x_ml->ml_size; 375856f33205SJonathan Adams x_ml = x_ml->ml_next; 375925cf1a30Sjl139090 } 376025cf1a30Sjl139090 376125cf1a30Sjl139090 copy_sz = sz/active_cpus; 376225cf1a30Sjl139090 copy_sz = roundup(copy_sz, MMU_PAGESIZE4M); 376325cf1a30Sjl139090 376425cf1a30Sjl139090 while (sz > copy_sz*active_cpus) { 376525cf1a30Sjl139090 copy_sz += MMU_PAGESIZE4M; 376625cf1a30Sjl139090 } 376725cf1a30Sjl139090 376825cf1a30Sjl139090 prog->data->stick_freq = system_clock_freq; 376925cf1a30Sjl139090 prog->data->copy_delay = ((copy_sz / min_copy_size_per_sec) + 2) * 377025cf1a30Sjl139090 system_clock_freq; 377125cf1a30Sjl139090 377225cf1a30Sjl139090 x_ml = c_ml; 377356f33205SJonathan Adams c_addr = x_ml->ml_address; 377456f33205SJonathan Adams c_size = x_ml->ml_size; 377525cf1a30Sjl139090 377625cf1a30Sjl139090 for (i = 0; i < NCPU; i++) { 377725cf1a30Sjl139090 prog->stat->nbytes[i] = 0; 377825cf1a30Sjl139090 if (!CPU_IN_SET(prog->data->cpu_copy_set, i)) { 377925cf1a30Sjl139090 continue; 378025cf1a30Sjl139090 } 378125cf1a30Sjl139090 sz = copy_sz; 378225cf1a30Sjl139090 378325cf1a30Sjl139090 while (sz) { 378425cf1a30Sjl139090 if (c_size > sz) { 37856534c6f0Swh31274 if ((prog->data->cpu_ml[i] = 378625cf1a30Sjl139090 drmach_memlist_add_span(prog, 37876534c6f0Swh31274 prog->data->cpu_ml[i], 37886534c6f0Swh31274 c_addr, sz)) == NULL) { 37896534c6f0Swh31274 cmn_err(CE_WARN, 37906534c6f0Swh31274 "Unexpected drmach_memlist_add_span" 37916534c6f0Swh31274 " failure."); 37926534c6f0Swh31274 err = drerr_new(1, EOPL_FMEM_SETUP, 37936534c6f0Swh31274 NULL); 37946534c6f0Swh31274 mc_resume(); 37956534c6f0Swh31274 goto out; 37966534c6f0Swh31274 } 379725cf1a30Sjl139090 c_addr += sz; 379825cf1a30Sjl139090 c_size -= sz; 379925cf1a30Sjl139090 break; 380025cf1a30Sjl139090 } else { 380125cf1a30Sjl139090 sz -= c_size; 38026534c6f0Swh31274 if ((prog->data->cpu_ml[i] = 3803e98fafb9Sjl139090 drmach_memlist_add_span(prog, 38046534c6f0Swh31274 prog->data->cpu_ml[i], 38056534c6f0Swh31274 c_addr, c_size)) == NULL) { 38066534c6f0Swh31274 cmn_err(CE_WARN, 38076534c6f0Swh31274 "Unexpected drmach_memlist_add_span" 38086534c6f0Swh31274 " failure."); 38096534c6f0Swh31274 err = drerr_new(1, EOPL_FMEM_SETUP, 38106534c6f0Swh31274 NULL); 38116534c6f0Swh31274 mc_resume(); 38126534c6f0Swh31274 goto out; 38136534c6f0Swh31274 } 38146534c6f0Swh31274 381556f33205SJonathan Adams x_ml = x_ml->ml_next; 381625cf1a30Sjl139090 if (x_ml != NULL) { 381756f33205SJonathan Adams c_addr = x_ml->ml_address; 381856f33205SJonathan Adams c_size = x_ml->ml_size; 381925cf1a30Sjl139090 } else { 382025cf1a30Sjl139090 goto end; 382125cf1a30Sjl139090 } 382225cf1a30Sjl139090 } 382325cf1a30Sjl139090 } 382425cf1a30Sjl139090 } 382525cf1a30Sjl139090 end: 382625cf1a30Sjl139090 prog->data->s_copybasepa = s_copybasepa; 382725cf1a30Sjl139090 prog->data->t_copybasepa = t_copybasepa; 382825cf1a30Sjl139090 prog->data->c_ml = c_ml; 382968ac2337Sjl139090 *pgm_id = prog_kmem; 383025cf1a30Sjl139090 383168ac2337Sjl139090 /* Unmap the alternate space. It will have to be remapped again */ 383268ac2337Sjl139090 drmach_unlock_critical((caddr_t)prog); 383325cf1a30Sjl139090 return (NULL); 38346534c6f0Swh31274 38356534c6f0Swh31274 err_out: 38366534c6f0Swh31274 mc_resume(); 38376534c6f0Swh31274 rv = (*prog->data->scf_fmem_cancel)(); 38386534c6f0Swh31274 if (rv) { 38396534c6f0Swh31274 cmn_err(CE_WARN, "scf_fmem_cancel() failed rv=0x%x", rv); 38406534c6f0Swh31274 } 384168ac2337Sjl139090 out: 384268ac2337Sjl139090 if (prog != NULL) { 384368ac2337Sjl139090 drmach_unlock_critical((caddr_t)prog); 3844e98fafb9Sjl139090 vmem_free(heap_arena, prog, DRMACH_FMEM_LOCKED_PAGES * 3845e98fafb9Sjl139090 PAGESIZE); 384668ac2337Sjl139090 } 384768ac2337Sjl139090 if (prog_kmem != NULL) { 384868ac2337Sjl139090 kmem_free(prog_kmem, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE); 384968ac2337Sjl139090 } 385068ac2337Sjl139090 return (err); 385125cf1a30Sjl139090 } 385225cf1a30Sjl139090 385325cf1a30Sjl139090 sbd_error_t * 385425cf1a30Sjl139090 drmach_copy_rename_fini(drmachid_t id) 385525cf1a30Sjl139090 { 385625cf1a30Sjl139090 drmach_copy_rename_program_t *prog = id; 385725cf1a30Sjl139090 sbd_error_t *err = NULL; 385825cf1a30Sjl139090 int rv; 3859b307f191Sbm42561 uint_t fmem_error; 386025cf1a30Sjl139090 386125cf1a30Sjl139090 /* 386225cf1a30Sjl139090 * Note that we have to delay calling SCF to find out the 386325cf1a30Sjl139090 * status of the FMEM operation here because SCF cannot 386425cf1a30Sjl139090 * respond while it is suspended. 386525cf1a30Sjl139090 * This create a small window when we are sure about the 386625cf1a30Sjl139090 * base address of the system board. 386725cf1a30Sjl139090 * If there is any call to mc-opl to get memory unum, 386825cf1a30Sjl139090 * mc-opl will return UNKNOWN as the unum. 386925cf1a30Sjl139090 */ 387025cf1a30Sjl139090 387168ac2337Sjl139090 /* 387268ac2337Sjl139090 * we have to remap again because all the pointer like data, 387368ac2337Sjl139090 * critical in prog are based on the alternate vmem space. 387468ac2337Sjl139090 */ 387568ac2337Sjl139090 (void) drmach_lock_critical((caddr_t)prog, (caddr_t)prog->locked_prog); 387668ac2337Sjl139090 387725cf1a30Sjl139090 if (prog->data->c_ml != NULL) 387825cf1a30Sjl139090 memlist_delete(prog->data->c_ml); 387925cf1a30Sjl139090 388025cf1a30Sjl139090 if ((prog->data->fmem_status.op & 388125cf1a30Sjl139090 (OPL_FMEM_SCF_START | OPL_FMEM_MC_SUSPEND)) != 388225cf1a30Sjl139090 (OPL_FMEM_SCF_START | OPL_FMEM_MC_SUSPEND)) { 3883e98fafb9Sjl139090 cmn_err(CE_PANIC, "drmach_copy_rename_fini: invalid op " 3884e98fafb9Sjl139090 "code %x\n", prog->data->fmem_status.op); 388525cf1a30Sjl139090 } 388625cf1a30Sjl139090 3887b307f191Sbm42561 fmem_error = prog->data->fmem_status.error; 3888b307f191Sbm42561 if (fmem_error != ESBD_NOERROR) { 3889b307f191Sbm42561 err = drerr_new(1, fmem_error, NULL); 3890b307f191Sbm42561 } 3891b307f191Sbm42561 389225cf1a30Sjl139090 /* possible ops are SCF_START, MC_SUSPEND */ 389325cf1a30Sjl139090 if (prog->critical->fmem_issued) { 3894b307f191Sbm42561 if (fmem_error != ESBD_NOERROR) { 3895b307f191Sbm42561 cmn_err(CE_PANIC, "Irrecoverable FMEM error %d\n", 3896b307f191Sbm42561 fmem_error); 3897b307f191Sbm42561 } 389825cf1a30Sjl139090 rv = (*prog->data->scf_fmem_end)(); 389925cf1a30Sjl139090 if (rv) { 390068ac2337Sjl139090 cmn_err(CE_PANIC, "scf_fmem_end() failed rv=%d", rv); 390125cf1a30Sjl139090 } 390225cf1a30Sjl139090 /* 390325cf1a30Sjl139090 * If we get here, rename is successful. 390425cf1a30Sjl139090 * Do all the copy rename post processing. 390525cf1a30Sjl139090 */ 390625cf1a30Sjl139090 drmach_swap_pa((drmach_mem_t *)prog->data->s_mem, 390725cf1a30Sjl139090 (drmach_mem_t *)prog->data->t_mem); 390825cf1a30Sjl139090 } else { 390925cf1a30Sjl139090 rv = (*prog->data->scf_fmem_cancel)(); 391025cf1a30Sjl139090 if (rv) { 3911e98fafb9Sjl139090 cmn_err(CE_WARN, "scf_fmem_cancel() failed rv=0x%x", 3912e98fafb9Sjl139090 rv); 3913e98fafb9Sjl139090 if (!err) { 391468ac2337Sjl139090 err = drerr_new(1, EOPL_SCF_FMEM_CANCEL, 3915b307f191Sbm42561 "scf_fmem_cancel() failed. rv = 0x%x", rv); 391625cf1a30Sjl139090 } 391725cf1a30Sjl139090 } 3918e98fafb9Sjl139090 } 391925cf1a30Sjl139090 /* soft resume mac patrol */ 392025cf1a30Sjl139090 (*prog->data->mc_resume)(); 392125cf1a30Sjl139090 392268ac2337Sjl139090 drmach_unlock_critical((caddr_t)prog->locked_prog); 392368ac2337Sjl139090 392468ac2337Sjl139090 vmem_free(heap_arena, prog->locked_prog, 392568ac2337Sjl139090 DRMACH_FMEM_LOCKED_PAGES * PAGESIZE); 392625cf1a30Sjl139090 kmem_free(prog, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE); 392725cf1a30Sjl139090 return (err); 392825cf1a30Sjl139090 } 392925cf1a30Sjl139090 393025cf1a30Sjl139090 /*ARGSUSED*/ 393125cf1a30Sjl139090 static void 393225cf1a30Sjl139090 drmach_copy_rename_slave(struct regs *rp, drmachid_t id) 393325cf1a30Sjl139090 { 393468ac2337Sjl139090 drmach_copy_rename_program_t *prog = 393568ac2337Sjl139090 (drmach_copy_rename_program_t *)id; 393625cf1a30Sjl139090 register int cpuid; 393725cf1a30Sjl139090 extern void drmach_flush(); 393825cf1a30Sjl139090 extern void membar_sync_il(); 393925cf1a30Sjl139090 extern void drmach_flush_icache(); 394025cf1a30Sjl139090 on_trap_data_t otd; 394125cf1a30Sjl139090 394225cf1a30Sjl139090 cpuid = CPU->cpu_id; 394325cf1a30Sjl139090 394425cf1a30Sjl139090 if (on_trap(&otd, OT_DATA_EC)) { 394525cf1a30Sjl139090 no_trap(); 3946b307f191Sbm42561 prog->data->error[cpuid] = EOPL_FMEM_COPY_ERROR; 394725cf1a30Sjl139090 prog->critical->stat[cpuid] = FMEM_LOOP_EXIT; 394868ac2337Sjl139090 drmach_flush_icache(); 394968ac2337Sjl139090 membar_sync_il(); 395025cf1a30Sjl139090 return; 395125cf1a30Sjl139090 } 395225cf1a30Sjl139090 395325cf1a30Sjl139090 395425cf1a30Sjl139090 /* 395525cf1a30Sjl139090 * jmp drmach_copy_rename_prog(). 395625cf1a30Sjl139090 */ 395725cf1a30Sjl139090 395825cf1a30Sjl139090 drmach_flush(prog->critical, PAGESIZE); 395925cf1a30Sjl139090 (void) prog->critical->run(prog, cpuid); 396025cf1a30Sjl139090 drmach_flush_icache(); 396125cf1a30Sjl139090 396225cf1a30Sjl139090 no_trap(); 396325cf1a30Sjl139090 396425cf1a30Sjl139090 prog->critical->stat[cpuid] = FMEM_LOOP_EXIT; 396568ac2337Sjl139090 396625cf1a30Sjl139090 membar_sync_il(); 396725cf1a30Sjl139090 } 396825cf1a30Sjl139090 396925cf1a30Sjl139090 static void 397025cf1a30Sjl139090 drmach_swap_pa(drmach_mem_t *s_mem, drmach_mem_t *t_mem) 397125cf1a30Sjl139090 { 397225cf1a30Sjl139090 uint64_t s_base, t_base; 397325cf1a30Sjl139090 drmach_board_t *s_board, *t_board; 397425cf1a30Sjl139090 struct memlist *ml; 397525cf1a30Sjl139090 397625cf1a30Sjl139090 s_board = s_mem->dev.bp; 397725cf1a30Sjl139090 t_board = t_mem->dev.bp; 397825cf1a30Sjl139090 if (s_board == NULL || t_board == NULL) { 397925cf1a30Sjl139090 cmn_err(CE_PANIC, "Cannot locate source or target board\n"); 398025cf1a30Sjl139090 return; 398125cf1a30Sjl139090 } 398225cf1a30Sjl139090 s_base = s_mem->slice_base; 398325cf1a30Sjl139090 t_base = t_mem->slice_base; 398425cf1a30Sjl139090 398525cf1a30Sjl139090 s_mem->slice_base = t_base; 398625cf1a30Sjl139090 s_mem->base_pa = (s_mem->base_pa - s_base) + t_base; 398725cf1a30Sjl139090 398856f33205SJonathan Adams for (ml = s_mem->memlist; ml; ml = ml->ml_next) { 398956f33205SJonathan Adams ml->ml_address = ml->ml_address - s_base + t_base; 399025cf1a30Sjl139090 } 399125cf1a30Sjl139090 399225cf1a30Sjl139090 t_mem->slice_base = s_base; 399325cf1a30Sjl139090 t_mem->base_pa = (t_mem->base_pa - t_base) + s_base; 399425cf1a30Sjl139090 399556f33205SJonathan Adams for (ml = t_mem->memlist; ml; ml = ml->ml_next) { 399656f33205SJonathan Adams ml->ml_address = ml->ml_address - t_base + s_base; 399725cf1a30Sjl139090 } 399825cf1a30Sjl139090 399925cf1a30Sjl139090 /* 400025cf1a30Sjl139090 * IKP has to update the sb-mem-ranges for mac patrol driver 400125cf1a30Sjl139090 * when it resumes, it will re-read the sb-mem-range property 400225cf1a30Sjl139090 * to get the new base address 400325cf1a30Sjl139090 */ 400425cf1a30Sjl139090 if (oplcfg_pa_swap(s_board->bnum, t_board->bnum) != 0) 400525cf1a30Sjl139090 cmn_err(CE_PANIC, "Could not update device nodes\n"); 400625cf1a30Sjl139090 } 400725cf1a30Sjl139090 400825cf1a30Sjl139090 void 400925cf1a30Sjl139090 drmach_copy_rename(drmachid_t id) 401025cf1a30Sjl139090 { 401168ac2337Sjl139090 drmach_copy_rename_program_t *prog_kmem = id; 401268ac2337Sjl139090 drmach_copy_rename_program_t *prog; 401325cf1a30Sjl139090 cpuset_t cpuset; 401425cf1a30Sjl139090 int cpuid; 401525cf1a30Sjl139090 uint64_t inst; 401625cf1a30Sjl139090 register int rtn; 401725cf1a30Sjl139090 extern int in_sync; 401825cf1a30Sjl139090 int old_in_sync; 401925cf1a30Sjl139090 extern void drmach_sys_trap(); 402025cf1a30Sjl139090 extern void drmach_flush(); 402125cf1a30Sjl139090 extern void drmach_flush_icache(); 402225cf1a30Sjl139090 extern uint64_t patch_inst(uint64_t *, uint64_t); 402325cf1a30Sjl139090 on_trap_data_t otd; 402425cf1a30Sjl139090 40258eafe49bSbm42561 402668ac2337Sjl139090 prog = prog_kmem->locked_prog; 402768ac2337Sjl139090 40288eafe49bSbm42561 402968ac2337Sjl139090 /* 403068ac2337Sjl139090 * We must immediately drop in the TLB because all pointers 403168ac2337Sjl139090 * are based on the alternate vmem space. 403268ac2337Sjl139090 */ 403368ac2337Sjl139090 403468ac2337Sjl139090 (void) drmach_lock_critical((caddr_t)prog_kmem, (caddr_t)prog); 403568ac2337Sjl139090 403668ac2337Sjl139090 /* 403768ac2337Sjl139090 * we call scf to get the base address here becuase if scf 403868ac2337Sjl139090 * has not been suspended yet, the active path can be changing and 403968ac2337Sjl139090 * sometimes it is not even mapped. We call the interface when 404068ac2337Sjl139090 * the OS has been quiesced. 404168ac2337Sjl139090 */ 404268ac2337Sjl139090 prog->critical->scf_reg_base = (*prog->data->scf_get_base_addr)(); 404368ac2337Sjl139090 404468ac2337Sjl139090 if (prog->critical->scf_reg_base == (uint64_t)-1 || 404568ac2337Sjl139090 prog->critical->scf_reg_base == NULL) { 4046b307f191Sbm42561 prog->data->fmem_status.error = EOPL_FMEM_SCF_ERR; 404768ac2337Sjl139090 drmach_unlock_critical((caddr_t)prog); 404825cf1a30Sjl139090 return; 404925cf1a30Sjl139090 } 405025cf1a30Sjl139090 405125cf1a30Sjl139090 cpuset = prog->data->cpu_ready_set; 405225cf1a30Sjl139090 405325cf1a30Sjl139090 for (cpuid = 0; cpuid < NCPU; cpuid++) { 405425cf1a30Sjl139090 if (CPU_IN_SET(cpuset, cpuid)) { 405525cf1a30Sjl139090 prog->critical->stat[cpuid] = FMEM_LOOP_START; 4056b307f191Sbm42561 prog->data->error[cpuid] = ESBD_NOERROR; 405725cf1a30Sjl139090 } 405825cf1a30Sjl139090 } 405925cf1a30Sjl139090 406025cf1a30Sjl139090 old_in_sync = in_sync; 406125cf1a30Sjl139090 in_sync = 1; 406225cf1a30Sjl139090 cpuid = CPU->cpu_id; 406325cf1a30Sjl139090 406425cf1a30Sjl139090 CPUSET_DEL(cpuset, cpuid); 406525cf1a30Sjl139090 406668ac2337Sjl139090 for (cpuid = 0; cpuid < NCPU; cpuid++) { 406768ac2337Sjl139090 if (CPU_IN_SET(cpuset, cpuid)) { 406868ac2337Sjl139090 xc_one(cpuid, (xcfunc_t *)drmach_lock_critical, 406968ac2337Sjl139090 (uint64_t)prog_kmem, (uint64_t)prog); 407068ac2337Sjl139090 } 407168ac2337Sjl139090 } 407268ac2337Sjl139090 407368ac2337Sjl139090 cpuid = CPU->cpu_id; 407425cf1a30Sjl139090 407525cf1a30Sjl139090 xt_some(cpuset, (xcfunc_t *)drmach_sys_trap, 4076e98fafb9Sjl139090 (uint64_t)drmach_copy_rename_slave, (uint64_t)prog); 407725cf1a30Sjl139090 xt_sync(cpuset); 407825cf1a30Sjl139090 407925cf1a30Sjl139090 if (on_trap(&otd, OT_DATA_EC)) { 4080b307f191Sbm42561 rtn = EOPL_FMEM_COPY_ERROR; 408168ac2337Sjl139090 drmach_flush_icache(); 408225cf1a30Sjl139090 goto done; 408325cf1a30Sjl139090 } 408425cf1a30Sjl139090 408525cf1a30Sjl139090 /* 408625cf1a30Sjl139090 * jmp drmach_copy_rename_prog(). 408725cf1a30Sjl139090 */ 40888eafe49bSbm42561 408925cf1a30Sjl139090 drmach_flush(prog->critical, PAGESIZE); 409025cf1a30Sjl139090 rtn = prog->critical->run(prog, cpuid); 4091e98fafb9Sjl139090 409225cf1a30Sjl139090 drmach_flush_icache(); 409325cf1a30Sjl139090 409425cf1a30Sjl139090 409525cf1a30Sjl139090 done: 409625cf1a30Sjl139090 no_trap(); 4097b307f191Sbm42561 if (rtn == EOPL_FMEM_HW_ERROR) { 409825cf1a30Sjl139090 kpreempt_enable(); 4099e98fafb9Sjl139090 prom_panic("URGENT_ERROR_TRAP is detected during FMEM.\n"); 410025cf1a30Sjl139090 } 410125cf1a30Sjl139090 410225cf1a30Sjl139090 /* 410325cf1a30Sjl139090 * In normal case, all slave CPU's are still spinning in 410425cf1a30Sjl139090 * the assembly code. The master has to patch the instruction 410525cf1a30Sjl139090 * to get them out. 410625cf1a30Sjl139090 * In error case, e.g. COPY_ERROR, some slave CPU's might 410725cf1a30Sjl139090 * have aborted and already returned and sset LOOP_EXIT status. 410825cf1a30Sjl139090 * Some CPU might still be copying. 410925cf1a30Sjl139090 * In any case, some delay is necessary to give them 411025cf1a30Sjl139090 * enough time to set the LOOP_EXIT status. 411125cf1a30Sjl139090 */ 411225cf1a30Sjl139090 411325cf1a30Sjl139090 for (;;) { 411425cf1a30Sjl139090 inst = patch_inst((uint64_t *)prog->critical->loop_rtn, 411525cf1a30Sjl139090 prog->critical->inst_loop_ret); 411625cf1a30Sjl139090 if (prog->critical->inst_loop_ret == inst) { 411725cf1a30Sjl139090 break; 411825cf1a30Sjl139090 } 411925cf1a30Sjl139090 } 412025cf1a30Sjl139090 412125cf1a30Sjl139090 for (cpuid = 0; cpuid < NCPU; cpuid++) { 412225cf1a30Sjl139090 uint64_t last, now; 412325cf1a30Sjl139090 if (!CPU_IN_SET(cpuset, cpuid)) { 412425cf1a30Sjl139090 continue; 412525cf1a30Sjl139090 } 412625cf1a30Sjl139090 last = prog->stat->nbytes[cpuid]; 412725cf1a30Sjl139090 /* 412825cf1a30Sjl139090 * Wait for all CPU to exit. 412925cf1a30Sjl139090 * However we do not want an infinite loop 413025cf1a30Sjl139090 * so we detect hangup situation here. 413125cf1a30Sjl139090 * If the slave CPU is still copying data, 413225cf1a30Sjl139090 * we will continue to wait. 413325cf1a30Sjl139090 * In error cases, the master has already set 413425cf1a30Sjl139090 * fmem_status.error to abort the copying. 413525cf1a30Sjl139090 * 1 m.s delay for them to abort copying and 413625cf1a30Sjl139090 * return to drmach_copy_rename_slave to set 413725cf1a30Sjl139090 * FMEM_LOOP_EXIT status should be enough. 413825cf1a30Sjl139090 */ 413925cf1a30Sjl139090 for (;;) { 414025cf1a30Sjl139090 if (prog->critical->stat[cpuid] == FMEM_LOOP_EXIT) 414125cf1a30Sjl139090 break; 414225cf1a30Sjl139090 drmach_sleep_il(); 414325cf1a30Sjl139090 drv_usecwait(1000); 414425cf1a30Sjl139090 now = prog->stat->nbytes[cpuid]; 414525cf1a30Sjl139090 if (now <= last) { 414625cf1a30Sjl139090 drv_usecwait(1000); 4147e98fafb9Sjl139090 if (prog->critical->stat[cpuid] == 4148e98fafb9Sjl139090 FMEM_LOOP_EXIT) 414925cf1a30Sjl139090 break; 4150e98fafb9Sjl139090 cmn_err(CE_PANIC, "CPU %d hang during Copy " 4151e98fafb9Sjl139090 "Rename", cpuid); 415225cf1a30Sjl139090 } 415325cf1a30Sjl139090 last = now; 415425cf1a30Sjl139090 } 4155b307f191Sbm42561 if (prog->data->error[cpuid] == EOPL_FMEM_HW_ERROR) { 4156e98fafb9Sjl139090 prom_panic("URGENT_ERROR_TRAP is detected during " 4157e98fafb9Sjl139090 "FMEM.\n"); 415825cf1a30Sjl139090 } 415925cf1a30Sjl139090 } 416068ac2337Sjl139090 416168ac2337Sjl139090 /* 416268ac2337Sjl139090 * This must be done after all strands have exit. 416368ac2337Sjl139090 * Removing the TLB entry will affect both strands 416468ac2337Sjl139090 * in the same core. 416568ac2337Sjl139090 */ 416668ac2337Sjl139090 416768ac2337Sjl139090 for (cpuid = 0; cpuid < NCPU; cpuid++) { 416868ac2337Sjl139090 if (CPU_IN_SET(cpuset, cpuid)) { 416968ac2337Sjl139090 xc_one(cpuid, (xcfunc_t *)drmach_unlock_critical, 417068ac2337Sjl139090 (uint64_t)prog, 0); 417168ac2337Sjl139090 } 417268ac2337Sjl139090 } 417325cf1a30Sjl139090 417425cf1a30Sjl139090 in_sync = old_in_sync; 417525cf1a30Sjl139090 417668ac2337Sjl139090 /* 417768ac2337Sjl139090 * we should unlock before the following lock to keep the kpreempt 417868ac2337Sjl139090 * count correct. 417968ac2337Sjl139090 */ 418068ac2337Sjl139090 (void) drmach_unlock_critical((caddr_t)prog); 418168ac2337Sjl139090 418268ac2337Sjl139090 /* 418368ac2337Sjl139090 * we must remap again. TLB might have been removed in above xcall. 418468ac2337Sjl139090 */ 418568ac2337Sjl139090 418668ac2337Sjl139090 (void) drmach_lock_critical((caddr_t)prog_kmem, (caddr_t)prog); 418768ac2337Sjl139090 4188b307f191Sbm42561 if (prog->data->fmem_status.error == ESBD_NOERROR) 418925cf1a30Sjl139090 prog->data->fmem_status.error = rtn; 419025cf1a30Sjl139090 419125cf1a30Sjl139090 if (prog->data->copy_wait_time > 0) { 419225cf1a30Sjl139090 DRMACH_PR("Unexpected long wait time %ld seconds " 419325cf1a30Sjl139090 "during copy rename on CPU %d\n", 419425cf1a30Sjl139090 prog->data->copy_wait_time/prog->data->stick_freq, 419525cf1a30Sjl139090 prog->data->slowest_cpuid); 419625cf1a30Sjl139090 } 419768ac2337Sjl139090 drmach_unlock_critical((caddr_t)prog); 419825cf1a30Sjl139090 } 4199