1*25cf1a30Sjl /* 2*25cf1a30Sjl * CDDL HEADER START 3*25cf1a30Sjl * 4*25cf1a30Sjl * The contents of this file are subject to the terms of the 5*25cf1a30Sjl * Common Development and Distribution License (the "License"). 6*25cf1a30Sjl * You may not use this file except in compliance with the License. 7*25cf1a30Sjl * 8*25cf1a30Sjl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*25cf1a30Sjl * or http://www.opensolaris.org/os/licensing. 10*25cf1a30Sjl * See the License for the specific language governing permissions 11*25cf1a30Sjl * and limitations under the License. 12*25cf1a30Sjl * 13*25cf1a30Sjl * When distributing Covered Code, include this CDDL HEADER in each 14*25cf1a30Sjl * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*25cf1a30Sjl * If applicable, add the following below this CDDL HEADER, with the 16*25cf1a30Sjl * fields enclosed by brackets "[]" replaced with your own identifying 17*25cf1a30Sjl * information: Portions Copyright [yyyy] [name of copyright owner] 18*25cf1a30Sjl * 19*25cf1a30Sjl * CDDL HEADER END 20*25cf1a30Sjl */ 21*25cf1a30Sjl /* 22*25cf1a30Sjl * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*25cf1a30Sjl * Use is subject to license terms. 24*25cf1a30Sjl */ 25*25cf1a30Sjl 26*25cf1a30Sjl #pragma ident "%Z%%M% %I% %E% SMI" 27*25cf1a30Sjl 28*25cf1a30Sjl #include <sys/debug.h> 29*25cf1a30Sjl #include <sys/types.h> 30*25cf1a30Sjl #include <sys/varargs.h> 31*25cf1a30Sjl #include <sys/errno.h> 32*25cf1a30Sjl #include <sys/cred.h> 33*25cf1a30Sjl #include <sys/dditypes.h> 34*25cf1a30Sjl #include <sys/devops.h> 35*25cf1a30Sjl #include <sys/modctl.h> 36*25cf1a30Sjl #include <sys/poll.h> 37*25cf1a30Sjl #include <sys/conf.h> 38*25cf1a30Sjl #include <sys/ddi.h> 39*25cf1a30Sjl #include <sys/sunddi.h> 40*25cf1a30Sjl #include <sys/sunndi.h> 41*25cf1a30Sjl #include <sys/ndi_impldefs.h> 42*25cf1a30Sjl #include <sys/stat.h> 43*25cf1a30Sjl #include <sys/kmem.h> 44*25cf1a30Sjl #include <sys/vmem.h> 45*25cf1a30Sjl #include <sys/opl_olympus_regs.h> 46*25cf1a30Sjl #include <sys/cpuvar.h> 47*25cf1a30Sjl #include <sys/cpupart.h> 48*25cf1a30Sjl #include <sys/mem_config.h> 49*25cf1a30Sjl #include <sys/ddi_impldefs.h> 50*25cf1a30Sjl #include <sys/systm.h> 51*25cf1a30Sjl #include <sys/machsystm.h> 52*25cf1a30Sjl #include <sys/autoconf.h> 53*25cf1a30Sjl #include <sys/cmn_err.h> 54*25cf1a30Sjl #include <sys/sysmacros.h> 55*25cf1a30Sjl #include <sys/x_call.h> 56*25cf1a30Sjl #include <sys/promif.h> 57*25cf1a30Sjl #include <sys/prom_plat.h> 58*25cf1a30Sjl #include <sys/membar.h> 59*25cf1a30Sjl #include <vm/seg_kmem.h> 60*25cf1a30Sjl #include <sys/mem_cage.h> 61*25cf1a30Sjl #include <sys/stack.h> 62*25cf1a30Sjl #include <sys/archsystm.h> 63*25cf1a30Sjl #include <vm/hat_sfmmu.h> 64*25cf1a30Sjl #include <sys/pte.h> 65*25cf1a30Sjl #include <sys/mmu.h> 66*25cf1a30Sjl #include <sys/cpu_module.h> 67*25cf1a30Sjl #include <sys/obpdefs.h> 68*25cf1a30Sjl #include <sys/note.h> 69*25cf1a30Sjl #include <sys/ontrap.h> 70*25cf1a30Sjl #include <sys/cpu_sgnblk_defs.h> 71*25cf1a30Sjl #include <sys/opl.h> 72*25cf1a30Sjl 73*25cf1a30Sjl 74*25cf1a30Sjl #include <sys/promimpl.h> 75*25cf1a30Sjl #include <sys/prom_plat.h> 76*25cf1a30Sjl #include <sys/kobj.h> 77*25cf1a30Sjl 78*25cf1a30Sjl #include <sys/sysevent.h> 79*25cf1a30Sjl #include <sys/sysevent/dr.h> 80*25cf1a30Sjl #include <sys/sysevent/eventdefs.h> 81*25cf1a30Sjl 82*25cf1a30Sjl #include <sys/drmach.h> 83*25cf1a30Sjl #include <sys/dr_util.h> 84*25cf1a30Sjl 85*25cf1a30Sjl #include <sys/fcode.h> 86*25cf1a30Sjl #include <sys/opl_cfg.h> 87*25cf1a30Sjl 88*25cf1a30Sjl extern void bcopy32_il(uint64_t, uint64_t); 89*25cf1a30Sjl extern void flush_cache_il(void); 90*25cf1a30Sjl extern void drmach_sleep_il(void); 91*25cf1a30Sjl 92*25cf1a30Sjl typedef struct { 93*25cf1a30Sjl struct drmach_node *node; 94*25cf1a30Sjl void *data; 95*25cf1a30Sjl } drmach_node_walk_args_t; 96*25cf1a30Sjl 97*25cf1a30Sjl typedef struct drmach_node { 98*25cf1a30Sjl void *here; 99*25cf1a30Sjl 100*25cf1a30Sjl pnode_t (*get_dnode)(struct drmach_node *node); 101*25cf1a30Sjl int (*walk)(struct drmach_node *node, void *data, 102*25cf1a30Sjl int (*cb)(drmach_node_walk_args_t *args)); 103*25cf1a30Sjl dev_info_t *(*n_getdip)(struct drmach_node *node); 104*25cf1a30Sjl int (*n_getproplen)(struct drmach_node *node, char *name, 105*25cf1a30Sjl int *len); 106*25cf1a30Sjl int (*n_getprop)(struct drmach_node *node, char *name, 107*25cf1a30Sjl void *buf, int len); 108*25cf1a30Sjl int (*get_parent)(struct drmach_node *node, 109*25cf1a30Sjl struct drmach_node *pnode); 110*25cf1a30Sjl } drmach_node_t; 111*25cf1a30Sjl 112*25cf1a30Sjl typedef struct { 113*25cf1a30Sjl int min_index; 114*25cf1a30Sjl int max_index; 115*25cf1a30Sjl int arr_sz; 116*25cf1a30Sjl drmachid_t *arr; 117*25cf1a30Sjl } drmach_array_t; 118*25cf1a30Sjl 119*25cf1a30Sjl typedef struct { 120*25cf1a30Sjl void *isa; 121*25cf1a30Sjl 122*25cf1a30Sjl void (*dispose)(drmachid_t); 123*25cf1a30Sjl sbd_error_t *(*release)(drmachid_t); 124*25cf1a30Sjl sbd_error_t *(*status)(drmachid_t, drmach_status_t *); 125*25cf1a30Sjl 126*25cf1a30Sjl char name[MAXNAMELEN]; 127*25cf1a30Sjl } drmach_common_t; 128*25cf1a30Sjl 129*25cf1a30Sjl typedef struct { 130*25cf1a30Sjl uint32_t core_present; 131*25cf1a30Sjl uint32_t core_hotadded; 132*25cf1a30Sjl uint32_t core_started; 133*25cf1a30Sjl } drmach_cmp_t; 134*25cf1a30Sjl 135*25cf1a30Sjl typedef struct { 136*25cf1a30Sjl drmach_common_t cm; 137*25cf1a30Sjl int bnum; 138*25cf1a30Sjl int assigned; 139*25cf1a30Sjl int powered; 140*25cf1a30Sjl int connected; 141*25cf1a30Sjl int cond; 142*25cf1a30Sjl drmach_node_t *tree; 143*25cf1a30Sjl drmach_array_t *devices; 144*25cf1a30Sjl int boot_board; /* if board exists on bootup */ 145*25cf1a30Sjl drmach_cmp_t cores[OPL_MAX_COREID_PER_BOARD]; 146*25cf1a30Sjl } drmach_board_t; 147*25cf1a30Sjl 148*25cf1a30Sjl typedef struct { 149*25cf1a30Sjl drmach_common_t cm; 150*25cf1a30Sjl drmach_board_t *bp; 151*25cf1a30Sjl int unum; 152*25cf1a30Sjl int portid; 153*25cf1a30Sjl int busy; 154*25cf1a30Sjl int powered; 155*25cf1a30Sjl const char *type; 156*25cf1a30Sjl drmach_node_t *node; 157*25cf1a30Sjl } drmach_device_t; 158*25cf1a30Sjl 159*25cf1a30Sjl typedef struct drmach_cpu { 160*25cf1a30Sjl drmach_device_t dev; 161*25cf1a30Sjl processorid_t cpuid; 162*25cf1a30Sjl int sb; 163*25cf1a30Sjl int chipid; 164*25cf1a30Sjl int coreid; 165*25cf1a30Sjl int strandid; 166*25cf1a30Sjl int status; 167*25cf1a30Sjl #define OPL_CPU_HOTADDED 1 168*25cf1a30Sjl } drmach_cpu_t; 169*25cf1a30Sjl 170*25cf1a30Sjl typedef struct drmach_mem { 171*25cf1a30Sjl drmach_device_t dev; 172*25cf1a30Sjl uint64_t slice_base; 173*25cf1a30Sjl uint64_t slice_size; 174*25cf1a30Sjl uint64_t base_pa; /* lowest installed memory base */ 175*25cf1a30Sjl uint64_t nbytes; /* size of installed memory */ 176*25cf1a30Sjl struct memlist *memlist; 177*25cf1a30Sjl } drmach_mem_t; 178*25cf1a30Sjl 179*25cf1a30Sjl typedef struct drmach_io { 180*25cf1a30Sjl drmach_device_t dev; 181*25cf1a30Sjl int channel; 182*25cf1a30Sjl int leaf; 183*25cf1a30Sjl } drmach_io_t; 184*25cf1a30Sjl 185*25cf1a30Sjl typedef struct drmach_domain_info { 186*25cf1a30Sjl uint32_t floating; 187*25cf1a30Sjl int allow_dr; 188*25cf1a30Sjl } drmach_domain_info_t; 189*25cf1a30Sjl 190*25cf1a30Sjl drmach_domain_info_t drmach_domain; 191*25cf1a30Sjl 192*25cf1a30Sjl typedef struct { 193*25cf1a30Sjl int flags; 194*25cf1a30Sjl drmach_device_t *dp; 195*25cf1a30Sjl sbd_error_t *err; 196*25cf1a30Sjl dev_info_t *dip; 197*25cf1a30Sjl } drmach_config_args_t; 198*25cf1a30Sjl 199*25cf1a30Sjl typedef struct { 200*25cf1a30Sjl drmach_board_t *obj; 201*25cf1a30Sjl int ndevs; 202*25cf1a30Sjl void *a; 203*25cf1a30Sjl sbd_error_t *(*found)(void *a, const char *, int, drmachid_t); 204*25cf1a30Sjl sbd_error_t *err; 205*25cf1a30Sjl } drmach_board_cb_data_t; 206*25cf1a30Sjl 207*25cf1a30Sjl static drmach_array_t *drmach_boards; 208*25cf1a30Sjl 209*25cf1a30Sjl static sbd_error_t *drmach_device_new(drmach_node_t *, 210*25cf1a30Sjl drmach_board_t *, int, drmachid_t *); 211*25cf1a30Sjl static sbd_error_t *drmach_cpu_new(drmach_device_t *, drmachid_t *); 212*25cf1a30Sjl static sbd_error_t *drmach_mem_new(drmach_device_t *, drmachid_t *); 213*25cf1a30Sjl static sbd_error_t *drmach_io_new(drmach_device_t *, drmachid_t *); 214*25cf1a30Sjl 215*25cf1a30Sjl static dev_info_t *drmach_node_ddi_get_dip(drmach_node_t *np); 216*25cf1a30Sjl static int drmach_node_ddi_get_prop(drmach_node_t *np, 217*25cf1a30Sjl char *name, void *buf, int len); 218*25cf1a30Sjl static int drmach_node_ddi_get_proplen(drmach_node_t *np, 219*25cf1a30Sjl char *name, int *len); 220*25cf1a30Sjl 221*25cf1a30Sjl static int drmach_get_portid(drmach_node_t *); 222*25cf1a30Sjl static sbd_error_t *drmach_i_status(drmachid_t, drmach_status_t *); 223*25cf1a30Sjl static int opl_check_dr_status(); 224*25cf1a30Sjl static void drmach_io_dispose(drmachid_t); 225*25cf1a30Sjl static sbd_error_t *drmach_io_release(drmachid_t); 226*25cf1a30Sjl static sbd_error_t *drmach_io_status(drmachid_t, drmach_status_t *); 227*25cf1a30Sjl static int drmach_init(void); 228*25cf1a30Sjl static void drmach_fini(void); 229*25cf1a30Sjl static void drmach_swap_pa(drmach_mem_t *, drmach_mem_t *); 230*25cf1a30Sjl static drmach_board_t *drmach_get_board_by_bnum(int); 231*25cf1a30Sjl 232*25cf1a30Sjl /* options for the second argument in drmach_add_remove_cpu() */ 233*25cf1a30Sjl #define HOTADD_CPU 1 234*25cf1a30Sjl #define HOTREMOVE_CPU 2 235*25cf1a30Sjl 236*25cf1a30Sjl #define ON_BOARD_CORE_NUM(x) (((uint_t)(x) / OPL_MAX_STRANDID_PER_CORE) & \ 237*25cf1a30Sjl (OPL_MAX_COREID_PER_BOARD - 1)) 238*25cf1a30Sjl 239*25cf1a30Sjl extern struct cpu *SIGBCPU; 240*25cf1a30Sjl 241*25cf1a30Sjl static int drmach_name2type_idx(char *); 242*25cf1a30Sjl static drmach_board_t *drmach_board_new(int, int); 243*25cf1a30Sjl 244*25cf1a30Sjl #ifdef DEBUG 245*25cf1a30Sjl 246*25cf1a30Sjl #define DRMACH_PR if (drmach_debug) printf 247*25cf1a30Sjl int drmach_debug = 1; /* set to non-zero to enable debug messages */ 248*25cf1a30Sjl #else 249*25cf1a30Sjl 250*25cf1a30Sjl #define DRMACH_PR _NOTE(CONSTANTCONDITION) if (0) printf 251*25cf1a30Sjl #endif /* DEBUG */ 252*25cf1a30Sjl 253*25cf1a30Sjl 254*25cf1a30Sjl #define DRMACH_OBJ(id) ((drmach_common_t *)id) 255*25cf1a30Sjl 256*25cf1a30Sjl #define DRMACH_IS_BOARD_ID(id) \ 257*25cf1a30Sjl ((id != 0) && \ 258*25cf1a30Sjl (DRMACH_OBJ(id)->isa == (void *)drmach_board_new)) 259*25cf1a30Sjl 260*25cf1a30Sjl #define DRMACH_IS_CPU_ID(id) \ 261*25cf1a30Sjl ((id != 0) && \ 262*25cf1a30Sjl (DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new)) 263*25cf1a30Sjl 264*25cf1a30Sjl #define DRMACH_IS_MEM_ID(id) \ 265*25cf1a30Sjl ((id != 0) && \ 266*25cf1a30Sjl (DRMACH_OBJ(id)->isa == (void *)drmach_mem_new)) 267*25cf1a30Sjl 268*25cf1a30Sjl #define DRMACH_IS_IO_ID(id) \ 269*25cf1a30Sjl ((id != 0) && \ 270*25cf1a30Sjl (DRMACH_OBJ(id)->isa == (void *)drmach_io_new)) 271*25cf1a30Sjl 272*25cf1a30Sjl #define DRMACH_IS_DEVICE_ID(id) \ 273*25cf1a30Sjl ((id != 0) && \ 274*25cf1a30Sjl (DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new || \ 275*25cf1a30Sjl DRMACH_OBJ(id)->isa == (void *)drmach_mem_new || \ 276*25cf1a30Sjl DRMACH_OBJ(id)->isa == (void *)drmach_io_new)) 277*25cf1a30Sjl 278*25cf1a30Sjl #define DRMACH_IS_ID(id) \ 279*25cf1a30Sjl ((id != 0) && \ 280*25cf1a30Sjl (DRMACH_OBJ(id)->isa == (void *)drmach_board_new || \ 281*25cf1a30Sjl DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new || \ 282*25cf1a30Sjl DRMACH_OBJ(id)->isa == (void *)drmach_mem_new || \ 283*25cf1a30Sjl DRMACH_OBJ(id)->isa == (void *)drmach_io_new)) 284*25cf1a30Sjl 285*25cf1a30Sjl #define DRMACH_INTERNAL_ERROR() \ 286*25cf1a30Sjl drerr_new(1, EOPL_INTERNAL, drmach_ie_fmt, __LINE__) 287*25cf1a30Sjl 288*25cf1a30Sjl static char *drmach_ie_fmt = "drmach.c %d"; 289*25cf1a30Sjl 290*25cf1a30Sjl static struct { 291*25cf1a30Sjl const char *name; 292*25cf1a30Sjl const char *type; 293*25cf1a30Sjl sbd_error_t *(*new)(drmach_device_t *, drmachid_t *); 294*25cf1a30Sjl } drmach_name2type[] = { 295*25cf1a30Sjl { "cpu", DRMACH_DEVTYPE_CPU, drmach_cpu_new }, 296*25cf1a30Sjl { "pseudo-mc", DRMACH_DEVTYPE_MEM, drmach_mem_new }, 297*25cf1a30Sjl { "pci", DRMACH_DEVTYPE_PCI, drmach_io_new }, 298*25cf1a30Sjl }; 299*25cf1a30Sjl 300*25cf1a30Sjl /* utility */ 301*25cf1a30Sjl #define MBYTE (1048576ull) 302*25cf1a30Sjl 303*25cf1a30Sjl /* 304*25cf1a30Sjl * drmach autoconfiguration data structures and interfaces 305*25cf1a30Sjl */ 306*25cf1a30Sjl 307*25cf1a30Sjl extern struct mod_ops mod_miscops; 308*25cf1a30Sjl 309*25cf1a30Sjl static struct modlmisc modlmisc = { 310*25cf1a30Sjl &mod_miscops, 311*25cf1a30Sjl "OPL DR 1.1" 312*25cf1a30Sjl }; 313*25cf1a30Sjl 314*25cf1a30Sjl static struct modlinkage modlinkage = { 315*25cf1a30Sjl MODREV_1, 316*25cf1a30Sjl (void *)&modlmisc, 317*25cf1a30Sjl NULL 318*25cf1a30Sjl }; 319*25cf1a30Sjl 320*25cf1a30Sjl static krwlock_t drmach_boards_rwlock; 321*25cf1a30Sjl 322*25cf1a30Sjl typedef const char *fn_t; 323*25cf1a30Sjl 324*25cf1a30Sjl int 325*25cf1a30Sjl _init(void) 326*25cf1a30Sjl { 327*25cf1a30Sjl int err; 328*25cf1a30Sjl 329*25cf1a30Sjl if ((err = drmach_init()) != 0) { 330*25cf1a30Sjl return (err); 331*25cf1a30Sjl } 332*25cf1a30Sjl 333*25cf1a30Sjl if ((err = mod_install(&modlinkage)) != 0) { 334*25cf1a30Sjl drmach_fini(); 335*25cf1a30Sjl } 336*25cf1a30Sjl 337*25cf1a30Sjl return (err); 338*25cf1a30Sjl } 339*25cf1a30Sjl 340*25cf1a30Sjl int 341*25cf1a30Sjl _fini(void) 342*25cf1a30Sjl { 343*25cf1a30Sjl int err; 344*25cf1a30Sjl 345*25cf1a30Sjl if ((err = mod_remove(&modlinkage)) == 0) 346*25cf1a30Sjl drmach_fini(); 347*25cf1a30Sjl 348*25cf1a30Sjl return (err); 349*25cf1a30Sjl } 350*25cf1a30Sjl 351*25cf1a30Sjl int 352*25cf1a30Sjl _info(struct modinfo *modinfop) 353*25cf1a30Sjl { 354*25cf1a30Sjl return (mod_info(&modlinkage, modinfop)); 355*25cf1a30Sjl } 356*25cf1a30Sjl 357*25cf1a30Sjl /* 358*25cf1a30Sjl * The following routines are used to set up the memory 359*25cf1a30Sjl * properties in the board structure. 360*25cf1a30Sjl */ 361*25cf1a30Sjl 362*25cf1a30Sjl struct drmach_mc_lookup { 363*25cf1a30Sjl int bnum; 364*25cf1a30Sjl drmach_board_t *bp; 365*25cf1a30Sjl dev_info_t *dip; /* rv - set if found */ 366*25cf1a30Sjl }; 367*25cf1a30Sjl 368*25cf1a30Sjl #define _ptob64(p) ((uint64_t)(p) << PAGESHIFT) 369*25cf1a30Sjl #define _b64top(b) ((pgcnt_t)((b) >> PAGESHIFT)) 370*25cf1a30Sjl 371*25cf1a30Sjl static int 372*25cf1a30Sjl drmach_setup_mc_info(dev_info_t *dip, drmach_mem_t *mp) 373*25cf1a30Sjl { 374*25cf1a30Sjl uint64_t memory_ranges[128]; 375*25cf1a30Sjl int len; 376*25cf1a30Sjl struct memlist *ml; 377*25cf1a30Sjl int rv; 378*25cf1a30Sjl hwd_sb_t *hwd; 379*25cf1a30Sjl hwd_memory_t *pm; 380*25cf1a30Sjl 381*25cf1a30Sjl len = sizeof (memory_ranges); 382*25cf1a30Sjl if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 383*25cf1a30Sjl DDI_PROP_DONTPASS, "sb-mem-ranges", 384*25cf1a30Sjl (caddr_t)&memory_ranges[0], &len) != DDI_PROP_SUCCESS) { 385*25cf1a30Sjl mp->slice_base = 0; 386*25cf1a30Sjl mp->slice_size = 0; 387*25cf1a30Sjl return (-1); 388*25cf1a30Sjl } 389*25cf1a30Sjl mp->slice_base = memory_ranges[0]; 390*25cf1a30Sjl mp->slice_size = memory_ranges[1]; 391*25cf1a30Sjl 392*25cf1a30Sjl if (!mp->dev.bp->boot_board) { 393*25cf1a30Sjl int i; 394*25cf1a30Sjl 395*25cf1a30Sjl rv = opl_read_hwd(mp->dev.bp->bnum, NULL, NULL, NULL, &hwd); 396*25cf1a30Sjl 397*25cf1a30Sjl if (rv != 0) { 398*25cf1a30Sjl return (-1); 399*25cf1a30Sjl } 400*25cf1a30Sjl 401*25cf1a30Sjl ml = NULL; 402*25cf1a30Sjl pm = &hwd->sb_cmu.cmu_memory; 403*25cf1a30Sjl for (i = 0; i < HWD_MAX_MEM_CHUNKS; i++) { 404*25cf1a30Sjl if (pm->mem_chunks[i].chnk_size > 0) { 405*25cf1a30Sjl ml = memlist_add_span(ml, 406*25cf1a30Sjl pm->mem_chunks[i].chnk_start_address, 407*25cf1a30Sjl pm->mem_chunks[i].chnk_size); 408*25cf1a30Sjl } 409*25cf1a30Sjl } 410*25cf1a30Sjl } else { 411*25cf1a30Sjl /* 412*25cf1a30Sjl * we intersect phys_install to get base_pa. 413*25cf1a30Sjl * This only works at bootup time. 414*25cf1a30Sjl */ 415*25cf1a30Sjl 416*25cf1a30Sjl memlist_read_lock(); 417*25cf1a30Sjl ml = memlist_dup(phys_install); 418*25cf1a30Sjl memlist_read_unlock(); 419*25cf1a30Sjl 420*25cf1a30Sjl ml = memlist_del_span(ml, 0ull, mp->slice_base); 421*25cf1a30Sjl if (ml) { 422*25cf1a30Sjl uint64_t basepa, endpa; 423*25cf1a30Sjl endpa = _ptob64(physmax + 1); 424*25cf1a30Sjl 425*25cf1a30Sjl basepa = mp->slice_base + mp->slice_size; 426*25cf1a30Sjl 427*25cf1a30Sjl ml = memlist_del_span(ml, basepa, endpa - basepa); 428*25cf1a30Sjl } 429*25cf1a30Sjl } 430*25cf1a30Sjl 431*25cf1a30Sjl if (ml) { 432*25cf1a30Sjl uint64_t nbytes = 0; 433*25cf1a30Sjl struct memlist *p; 434*25cf1a30Sjl for (p = ml; p; p = p->next) { 435*25cf1a30Sjl nbytes += p->size; 436*25cf1a30Sjl } 437*25cf1a30Sjl if ((mp->nbytes = nbytes) > 0) 438*25cf1a30Sjl mp->base_pa = ml->address; 439*25cf1a30Sjl else 440*25cf1a30Sjl mp->base_pa = 0; 441*25cf1a30Sjl mp->memlist = ml; 442*25cf1a30Sjl } else { 443*25cf1a30Sjl mp->base_pa = 0; 444*25cf1a30Sjl mp->nbytes = 0; 445*25cf1a30Sjl } 446*25cf1a30Sjl return (0); 447*25cf1a30Sjl } 448*25cf1a30Sjl 449*25cf1a30Sjl 450*25cf1a30Sjl struct drmach_hotcpu { 451*25cf1a30Sjl drmach_board_t *bp; 452*25cf1a30Sjl int bnum; 453*25cf1a30Sjl int core_id; 454*25cf1a30Sjl int rv; 455*25cf1a30Sjl int option; 456*25cf1a30Sjl }; 457*25cf1a30Sjl 458*25cf1a30Sjl static int 459*25cf1a30Sjl drmach_cpu_cb(dev_info_t *dip, void *arg) 460*25cf1a30Sjl { 461*25cf1a30Sjl struct drmach_hotcpu *p = (struct drmach_hotcpu *)arg; 462*25cf1a30Sjl char name[OBP_MAXDRVNAME]; 463*25cf1a30Sjl int len = OBP_MAXDRVNAME; 464*25cf1a30Sjl int bnum, core_id, strand_id; 465*25cf1a30Sjl drmach_board_t *bp; 466*25cf1a30Sjl 467*25cf1a30Sjl if (dip == ddi_root_node()) { 468*25cf1a30Sjl return (DDI_WALK_CONTINUE); 469*25cf1a30Sjl } 470*25cf1a30Sjl 471*25cf1a30Sjl if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 472*25cf1a30Sjl DDI_PROP_DONTPASS, "name", 473*25cf1a30Sjl (caddr_t)name, &len) != DDI_PROP_SUCCESS) { 474*25cf1a30Sjl return (DDI_WALK_PRUNECHILD); 475*25cf1a30Sjl } 476*25cf1a30Sjl 477*25cf1a30Sjl /* only cmp has board number */ 478*25cf1a30Sjl bnum = -1; 479*25cf1a30Sjl len = sizeof (bnum); 480*25cf1a30Sjl if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 481*25cf1a30Sjl DDI_PROP_DONTPASS, OBP_BOARDNUM, 482*25cf1a30Sjl (caddr_t)&bnum, &len) != DDI_PROP_SUCCESS) { 483*25cf1a30Sjl bnum = -1; 484*25cf1a30Sjl } 485*25cf1a30Sjl 486*25cf1a30Sjl if (strcmp(name, "cmp") == 0) { 487*25cf1a30Sjl if (bnum != p->bnum) 488*25cf1a30Sjl return (DDI_WALK_PRUNECHILD); 489*25cf1a30Sjl return (DDI_WALK_CONTINUE); 490*25cf1a30Sjl } 491*25cf1a30Sjl /* we have already pruned all unwanted cores and cpu's above */ 492*25cf1a30Sjl if (strcmp(name, "core") == 0) { 493*25cf1a30Sjl return (DDI_WALK_CONTINUE); 494*25cf1a30Sjl } 495*25cf1a30Sjl if (strcmp(name, "cpu") == 0) { 496*25cf1a30Sjl processorid_t cpuid; 497*25cf1a30Sjl len = sizeof (cpuid); 498*25cf1a30Sjl if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 499*25cf1a30Sjl DDI_PROP_DONTPASS, "cpuid", 500*25cf1a30Sjl (caddr_t)&cpuid, &len) != DDI_PROP_SUCCESS) { 501*25cf1a30Sjl p->rv = -1; 502*25cf1a30Sjl return (DDI_WALK_TERMINATE); 503*25cf1a30Sjl } 504*25cf1a30Sjl 505*25cf1a30Sjl core_id = p->core_id; 506*25cf1a30Sjl 507*25cf1a30Sjl bnum = LSB_ID(cpuid); 508*25cf1a30Sjl 509*25cf1a30Sjl if (ON_BOARD_CORE_NUM(cpuid) != core_id) 510*25cf1a30Sjl return (DDI_WALK_CONTINUE); 511*25cf1a30Sjl 512*25cf1a30Sjl bp = p->bp; 513*25cf1a30Sjl ASSERT(bnum == bp->bnum); 514*25cf1a30Sjl 515*25cf1a30Sjl if (p->option == HOTADD_CPU) { 516*25cf1a30Sjl if (prom_hotaddcpu(cpuid) != 0) { 517*25cf1a30Sjl p->rv = -1; 518*25cf1a30Sjl return (DDI_WALK_TERMINATE); 519*25cf1a30Sjl } 520*25cf1a30Sjl strand_id = STRAND_ID(cpuid); 521*25cf1a30Sjl bp->cores[core_id].core_hotadded |= (1 << strand_id); 522*25cf1a30Sjl } else if (p->option == HOTREMOVE_CPU) { 523*25cf1a30Sjl if (prom_hotremovecpu(cpuid) != 0) { 524*25cf1a30Sjl p->rv = -1; 525*25cf1a30Sjl return (DDI_WALK_TERMINATE); 526*25cf1a30Sjl } 527*25cf1a30Sjl strand_id = STRAND_ID(cpuid); 528*25cf1a30Sjl bp->cores[core_id].core_hotadded &= ~(1 << strand_id); 529*25cf1a30Sjl } 530*25cf1a30Sjl return (DDI_WALK_CONTINUE); 531*25cf1a30Sjl } 532*25cf1a30Sjl 533*25cf1a30Sjl return (DDI_WALK_PRUNECHILD); 534*25cf1a30Sjl } 535*25cf1a30Sjl 536*25cf1a30Sjl 537*25cf1a30Sjl static int 538*25cf1a30Sjl drmach_add_remove_cpu(int bnum, int core_id, int option) 539*25cf1a30Sjl { 540*25cf1a30Sjl struct drmach_hotcpu arg; 541*25cf1a30Sjl drmach_board_t *bp; 542*25cf1a30Sjl 543*25cf1a30Sjl bp = drmach_get_board_by_bnum(bnum); 544*25cf1a30Sjl ASSERT(bp); 545*25cf1a30Sjl 546*25cf1a30Sjl arg.bp = bp; 547*25cf1a30Sjl arg.bnum = bnum; 548*25cf1a30Sjl arg.core_id = core_id; 549*25cf1a30Sjl arg.rv = 0; 550*25cf1a30Sjl arg.option = option; 551*25cf1a30Sjl ddi_walk_devs(ddi_root_node(), drmach_cpu_cb, (void *)&arg); 552*25cf1a30Sjl return (arg.rv); 553*25cf1a30Sjl } 554*25cf1a30Sjl 555*25cf1a30Sjl struct drmach_setup_core_arg { 556*25cf1a30Sjl drmach_board_t *bp; 557*25cf1a30Sjl }; 558*25cf1a30Sjl 559*25cf1a30Sjl static int 560*25cf1a30Sjl drmach_setup_core_cb(dev_info_t *dip, void *arg) 561*25cf1a30Sjl { 562*25cf1a30Sjl struct drmach_setup_core_arg *p = (struct drmach_setup_core_arg *)arg; 563*25cf1a30Sjl char name[OBP_MAXDRVNAME]; 564*25cf1a30Sjl int len = OBP_MAXDRVNAME; 565*25cf1a30Sjl int bnum; 566*25cf1a30Sjl int core_id, strand_id; 567*25cf1a30Sjl 568*25cf1a30Sjl if (dip == ddi_root_node()) { 569*25cf1a30Sjl return (DDI_WALK_CONTINUE); 570*25cf1a30Sjl } 571*25cf1a30Sjl 572*25cf1a30Sjl if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 573*25cf1a30Sjl DDI_PROP_DONTPASS, "name", 574*25cf1a30Sjl (caddr_t)name, &len) != DDI_PROP_SUCCESS) { 575*25cf1a30Sjl return (DDI_WALK_PRUNECHILD); 576*25cf1a30Sjl } 577*25cf1a30Sjl 578*25cf1a30Sjl /* only cmp has board number */ 579*25cf1a30Sjl bnum = -1; 580*25cf1a30Sjl len = sizeof (bnum); 581*25cf1a30Sjl if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 582*25cf1a30Sjl DDI_PROP_DONTPASS, OBP_BOARDNUM, 583*25cf1a30Sjl (caddr_t)&bnum, &len) != DDI_PROP_SUCCESS) { 584*25cf1a30Sjl bnum = -1; 585*25cf1a30Sjl } 586*25cf1a30Sjl 587*25cf1a30Sjl if (strcmp(name, "cmp") == 0) { 588*25cf1a30Sjl if (bnum != p->bp->bnum) 589*25cf1a30Sjl return (DDI_WALK_PRUNECHILD); 590*25cf1a30Sjl return (DDI_WALK_CONTINUE); 591*25cf1a30Sjl } 592*25cf1a30Sjl /* we have already pruned all unwanted cores and cpu's above */ 593*25cf1a30Sjl if (strcmp(name, "core") == 0) { 594*25cf1a30Sjl return (DDI_WALK_CONTINUE); 595*25cf1a30Sjl } 596*25cf1a30Sjl if (strcmp(name, "cpu") == 0) { 597*25cf1a30Sjl processorid_t cpuid; 598*25cf1a30Sjl len = sizeof (cpuid); 599*25cf1a30Sjl if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 600*25cf1a30Sjl DDI_PROP_DONTPASS, "cpuid", 601*25cf1a30Sjl (caddr_t)&cpuid, &len) != DDI_PROP_SUCCESS) { 602*25cf1a30Sjl return (DDI_WALK_TERMINATE); 603*25cf1a30Sjl } 604*25cf1a30Sjl bnum = LSB_ID(cpuid); 605*25cf1a30Sjl ASSERT(bnum == p->bp->bnum); 606*25cf1a30Sjl core_id = ON_BOARD_CORE_NUM(cpuid); 607*25cf1a30Sjl strand_id = STRAND_ID(cpuid); 608*25cf1a30Sjl p->bp->cores[core_id].core_present |= (1 << strand_id); 609*25cf1a30Sjl return (DDI_WALK_CONTINUE); 610*25cf1a30Sjl } 611*25cf1a30Sjl 612*25cf1a30Sjl return (DDI_WALK_PRUNECHILD); 613*25cf1a30Sjl } 614*25cf1a30Sjl 615*25cf1a30Sjl 616*25cf1a30Sjl static void 617*25cf1a30Sjl drmach_setup_core_info(drmach_board_t *obj) 618*25cf1a30Sjl { 619*25cf1a30Sjl struct drmach_setup_core_arg arg; 620*25cf1a30Sjl int i; 621*25cf1a30Sjl 622*25cf1a30Sjl for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) { 623*25cf1a30Sjl obj->cores[i].core_present = 0; 624*25cf1a30Sjl obj->cores[i].core_hotadded = 0; 625*25cf1a30Sjl obj->cores[i].core_started = 0; 626*25cf1a30Sjl } 627*25cf1a30Sjl arg.bp = obj; 628*25cf1a30Sjl ddi_walk_devs(ddi_root_node(), drmach_setup_core_cb, (void *)&arg); 629*25cf1a30Sjl 630*25cf1a30Sjl for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) { 631*25cf1a30Sjl if (obj->boot_board) { 632*25cf1a30Sjl obj->cores[i].core_hotadded = 633*25cf1a30Sjl obj->cores[i].core_started = 634*25cf1a30Sjl obj->cores[i].core_present; 635*25cf1a30Sjl } 636*25cf1a30Sjl } 637*25cf1a30Sjl } 638*25cf1a30Sjl 639*25cf1a30Sjl /* 640*25cf1a30Sjl * drmach_node_* routines serve the purpose of separating the 641*25cf1a30Sjl * rest of the code from the device tree and OBP. This is necessary 642*25cf1a30Sjl * because of In-Kernel-Probing. Devices probed after stod, are probed 643*25cf1a30Sjl * by the in-kernel-prober, not OBP. These devices, therefore, do not 644*25cf1a30Sjl * have dnode ids. 645*25cf1a30Sjl */ 646*25cf1a30Sjl 647*25cf1a30Sjl typedef struct { 648*25cf1a30Sjl drmach_node_walk_args_t *nwargs; 649*25cf1a30Sjl int (*cb)(drmach_node_walk_args_t *args); 650*25cf1a30Sjl int err; 651*25cf1a30Sjl } drmach_node_ddi_walk_args_t; 652*25cf1a30Sjl 653*25cf1a30Sjl static int 654*25cf1a30Sjl drmach_node_ddi_walk_cb(dev_info_t *dip, void *arg) 655*25cf1a30Sjl { 656*25cf1a30Sjl drmach_node_ddi_walk_args_t *nargs; 657*25cf1a30Sjl 658*25cf1a30Sjl nargs = (drmach_node_ddi_walk_args_t *)arg; 659*25cf1a30Sjl 660*25cf1a30Sjl /* 661*25cf1a30Sjl * dip doesn't have to be held here as we are called 662*25cf1a30Sjl * from ddi_walk_devs() which holds the dip. 663*25cf1a30Sjl */ 664*25cf1a30Sjl nargs->nwargs->node->here = (void *)dip; 665*25cf1a30Sjl 666*25cf1a30Sjl nargs->err = nargs->cb(nargs->nwargs); 667*25cf1a30Sjl 668*25cf1a30Sjl 669*25cf1a30Sjl /* 670*25cf1a30Sjl * Set "here" to NULL so that unheld dip is not accessible 671*25cf1a30Sjl * outside ddi_walk_devs() 672*25cf1a30Sjl */ 673*25cf1a30Sjl nargs->nwargs->node->here = NULL; 674*25cf1a30Sjl 675*25cf1a30Sjl if (nargs->err) 676*25cf1a30Sjl return (DDI_WALK_TERMINATE); 677*25cf1a30Sjl else 678*25cf1a30Sjl return (DDI_WALK_CONTINUE); 679*25cf1a30Sjl } 680*25cf1a30Sjl 681*25cf1a30Sjl static int 682*25cf1a30Sjl drmach_node_ddi_walk(drmach_node_t *np, void *data, 683*25cf1a30Sjl int (*cb)(drmach_node_walk_args_t *args)) 684*25cf1a30Sjl { 685*25cf1a30Sjl drmach_node_walk_args_t args; 686*25cf1a30Sjl drmach_node_ddi_walk_args_t nargs; 687*25cf1a30Sjl 688*25cf1a30Sjl 689*25cf1a30Sjl /* initialized args structure for callback */ 690*25cf1a30Sjl args.node = np; 691*25cf1a30Sjl args.data = data; 692*25cf1a30Sjl 693*25cf1a30Sjl nargs.nwargs = &args; 694*25cf1a30Sjl nargs.cb = cb; 695*25cf1a30Sjl nargs.err = 0; 696*25cf1a30Sjl 697*25cf1a30Sjl /* 698*25cf1a30Sjl * Root node doesn't have to be held in any way. 699*25cf1a30Sjl */ 700*25cf1a30Sjl ddi_walk_devs(ddi_root_node(), drmach_node_ddi_walk_cb, 701*25cf1a30Sjl (void *)&nargs); 702*25cf1a30Sjl 703*25cf1a30Sjl return (nargs.err); 704*25cf1a30Sjl } 705*25cf1a30Sjl 706*25cf1a30Sjl static int 707*25cf1a30Sjl drmach_node_ddi_get_parent(drmach_node_t *np, drmach_node_t *pp) 708*25cf1a30Sjl { 709*25cf1a30Sjl dev_info_t *ndip; 710*25cf1a30Sjl static char *fn = "drmach_node_ddi_get_parent"; 711*25cf1a30Sjl 712*25cf1a30Sjl ndip = np->n_getdip(np); 713*25cf1a30Sjl if (ndip == NULL) { 714*25cf1a30Sjl cmn_err(CE_WARN, "%s: NULL dip", fn); 715*25cf1a30Sjl return (-1); 716*25cf1a30Sjl } 717*25cf1a30Sjl 718*25cf1a30Sjl bcopy(np, pp, sizeof (drmach_node_t)); 719*25cf1a30Sjl 720*25cf1a30Sjl pp->here = (void *)ddi_get_parent(ndip); 721*25cf1a30Sjl if (pp->here == NULL) { 722*25cf1a30Sjl cmn_err(CE_WARN, "%s: NULL parent dip", fn); 723*25cf1a30Sjl return (-1); 724*25cf1a30Sjl } 725*25cf1a30Sjl 726*25cf1a30Sjl return (0); 727*25cf1a30Sjl } 728*25cf1a30Sjl 729*25cf1a30Sjl /*ARGSUSED*/ 730*25cf1a30Sjl static pnode_t 731*25cf1a30Sjl drmach_node_ddi_get_dnode(drmach_node_t *np) 732*25cf1a30Sjl { 733*25cf1a30Sjl return ((pnode_t)NULL); 734*25cf1a30Sjl } 735*25cf1a30Sjl 736*25cf1a30Sjl static drmach_node_t * 737*25cf1a30Sjl drmach_node_new(void) 738*25cf1a30Sjl { 739*25cf1a30Sjl drmach_node_t *np; 740*25cf1a30Sjl 741*25cf1a30Sjl np = kmem_zalloc(sizeof (drmach_node_t), KM_SLEEP); 742*25cf1a30Sjl 743*25cf1a30Sjl np->get_dnode = drmach_node_ddi_get_dnode; 744*25cf1a30Sjl np->walk = drmach_node_ddi_walk; 745*25cf1a30Sjl np->n_getdip = drmach_node_ddi_get_dip; 746*25cf1a30Sjl np->n_getproplen = drmach_node_ddi_get_proplen; 747*25cf1a30Sjl np->n_getprop = drmach_node_ddi_get_prop; 748*25cf1a30Sjl np->get_parent = drmach_node_ddi_get_parent; 749*25cf1a30Sjl 750*25cf1a30Sjl return (np); 751*25cf1a30Sjl } 752*25cf1a30Sjl 753*25cf1a30Sjl static void 754*25cf1a30Sjl drmach_node_dispose(drmach_node_t *np) 755*25cf1a30Sjl { 756*25cf1a30Sjl kmem_free(np, sizeof (*np)); 757*25cf1a30Sjl } 758*25cf1a30Sjl 759*25cf1a30Sjl static dev_info_t * 760*25cf1a30Sjl drmach_node_ddi_get_dip(drmach_node_t *np) 761*25cf1a30Sjl { 762*25cf1a30Sjl return ((dev_info_t *)np->here); 763*25cf1a30Sjl } 764*25cf1a30Sjl 765*25cf1a30Sjl static int 766*25cf1a30Sjl drmach_node_walk(drmach_node_t *np, void *param, 767*25cf1a30Sjl int (*cb)(drmach_node_walk_args_t *args)) 768*25cf1a30Sjl { 769*25cf1a30Sjl return (np->walk(np, param, cb)); 770*25cf1a30Sjl } 771*25cf1a30Sjl 772*25cf1a30Sjl static int 773*25cf1a30Sjl drmach_node_ddi_get_prop(drmach_node_t *np, char *name, void *buf, int len) 774*25cf1a30Sjl { 775*25cf1a30Sjl int rv = 0; 776*25cf1a30Sjl dev_info_t *ndip; 777*25cf1a30Sjl static char *fn = "drmach_node_ddi_get_prop"; 778*25cf1a30Sjl 779*25cf1a30Sjl 780*25cf1a30Sjl ndip = np->n_getdip(np); 781*25cf1a30Sjl if (ndip == NULL) { 782*25cf1a30Sjl cmn_err(CE_WARN, "%s: NULL dip", fn); 783*25cf1a30Sjl rv = -1; 784*25cf1a30Sjl } else if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ndip, 785*25cf1a30Sjl DDI_PROP_DONTPASS, name, 786*25cf1a30Sjl (caddr_t)buf, &len) != DDI_PROP_SUCCESS) { 787*25cf1a30Sjl rv = -1; 788*25cf1a30Sjl } 789*25cf1a30Sjl 790*25cf1a30Sjl return (rv); 791*25cf1a30Sjl } 792*25cf1a30Sjl 793*25cf1a30Sjl static int 794*25cf1a30Sjl drmach_node_ddi_get_proplen(drmach_node_t *np, char *name, int *len) 795*25cf1a30Sjl { 796*25cf1a30Sjl int rv = 0; 797*25cf1a30Sjl dev_info_t *ndip; 798*25cf1a30Sjl 799*25cf1a30Sjl ndip = np->n_getdip(np); 800*25cf1a30Sjl if (ndip == NULL) { 801*25cf1a30Sjl rv = -1; 802*25cf1a30Sjl } else if (ddi_getproplen(DDI_DEV_T_ANY, ndip, DDI_PROP_DONTPASS, 803*25cf1a30Sjl name, len) != DDI_PROP_SUCCESS) { 804*25cf1a30Sjl rv = -1; 805*25cf1a30Sjl } 806*25cf1a30Sjl 807*25cf1a30Sjl return (rv); 808*25cf1a30Sjl } 809*25cf1a30Sjl 810*25cf1a30Sjl static drmachid_t 811*25cf1a30Sjl drmach_node_dup(drmach_node_t *np) 812*25cf1a30Sjl { 813*25cf1a30Sjl drmach_node_t *dup; 814*25cf1a30Sjl 815*25cf1a30Sjl dup = drmach_node_new(); 816*25cf1a30Sjl dup->here = np->here; 817*25cf1a30Sjl dup->get_dnode = np->get_dnode; 818*25cf1a30Sjl dup->walk = np->walk; 819*25cf1a30Sjl dup->n_getdip = np->n_getdip; 820*25cf1a30Sjl dup->n_getproplen = np->n_getproplen; 821*25cf1a30Sjl dup->n_getprop = np->n_getprop; 822*25cf1a30Sjl dup->get_parent = np->get_parent; 823*25cf1a30Sjl 824*25cf1a30Sjl return (dup); 825*25cf1a30Sjl } 826*25cf1a30Sjl 827*25cf1a30Sjl /* 828*25cf1a30Sjl * drmach_array provides convenient array construction, access, 829*25cf1a30Sjl * bounds checking and array destruction logic. 830*25cf1a30Sjl */ 831*25cf1a30Sjl 832*25cf1a30Sjl static drmach_array_t * 833*25cf1a30Sjl drmach_array_new(int min_index, int max_index) 834*25cf1a30Sjl { 835*25cf1a30Sjl drmach_array_t *arr; 836*25cf1a30Sjl 837*25cf1a30Sjl arr = kmem_zalloc(sizeof (drmach_array_t), KM_SLEEP); 838*25cf1a30Sjl 839*25cf1a30Sjl arr->arr_sz = (max_index - min_index + 1) * sizeof (void *); 840*25cf1a30Sjl if (arr->arr_sz > 0) { 841*25cf1a30Sjl arr->min_index = min_index; 842*25cf1a30Sjl arr->max_index = max_index; 843*25cf1a30Sjl 844*25cf1a30Sjl arr->arr = kmem_zalloc(arr->arr_sz, KM_SLEEP); 845*25cf1a30Sjl return (arr); 846*25cf1a30Sjl } else { 847*25cf1a30Sjl kmem_free(arr, sizeof (*arr)); 848*25cf1a30Sjl return (0); 849*25cf1a30Sjl } 850*25cf1a30Sjl } 851*25cf1a30Sjl 852*25cf1a30Sjl static int 853*25cf1a30Sjl drmach_array_set(drmach_array_t *arr, int idx, drmachid_t val) 854*25cf1a30Sjl { 855*25cf1a30Sjl if (idx < arr->min_index || idx > arr->max_index) 856*25cf1a30Sjl return (-1); 857*25cf1a30Sjl else { 858*25cf1a30Sjl arr->arr[idx - arr->min_index] = val; 859*25cf1a30Sjl return (0); 860*25cf1a30Sjl } 861*25cf1a30Sjl /*NOTREACHED*/ 862*25cf1a30Sjl } 863*25cf1a30Sjl 864*25cf1a30Sjl static int 865*25cf1a30Sjl drmach_array_get(drmach_array_t *arr, int idx, drmachid_t *val) 866*25cf1a30Sjl { 867*25cf1a30Sjl if (idx < arr->min_index || idx > arr->max_index) 868*25cf1a30Sjl return (-1); 869*25cf1a30Sjl else { 870*25cf1a30Sjl *val = arr->arr[idx - arr->min_index]; 871*25cf1a30Sjl return (0); 872*25cf1a30Sjl } 873*25cf1a30Sjl /*NOTREACHED*/ 874*25cf1a30Sjl } 875*25cf1a30Sjl 876*25cf1a30Sjl static int 877*25cf1a30Sjl drmach_array_first(drmach_array_t *arr, int *idx, drmachid_t *val) 878*25cf1a30Sjl { 879*25cf1a30Sjl int rv; 880*25cf1a30Sjl 881*25cf1a30Sjl *idx = arr->min_index; 882*25cf1a30Sjl while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL) 883*25cf1a30Sjl *idx += 1; 884*25cf1a30Sjl 885*25cf1a30Sjl return (rv); 886*25cf1a30Sjl } 887*25cf1a30Sjl 888*25cf1a30Sjl static int 889*25cf1a30Sjl drmach_array_next(drmach_array_t *arr, int *idx, drmachid_t *val) 890*25cf1a30Sjl { 891*25cf1a30Sjl int rv; 892*25cf1a30Sjl 893*25cf1a30Sjl *idx += 1; 894*25cf1a30Sjl while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL) 895*25cf1a30Sjl *idx += 1; 896*25cf1a30Sjl 897*25cf1a30Sjl return (rv); 898*25cf1a30Sjl } 899*25cf1a30Sjl 900*25cf1a30Sjl static void 901*25cf1a30Sjl drmach_array_dispose(drmach_array_t *arr, void (*disposer)(drmachid_t)) 902*25cf1a30Sjl { 903*25cf1a30Sjl drmachid_t val; 904*25cf1a30Sjl int idx; 905*25cf1a30Sjl int rv; 906*25cf1a30Sjl 907*25cf1a30Sjl rv = drmach_array_first(arr, &idx, &val); 908*25cf1a30Sjl while (rv == 0) { 909*25cf1a30Sjl (*disposer)(val); 910*25cf1a30Sjl rv = drmach_array_next(arr, &idx, &val); 911*25cf1a30Sjl } 912*25cf1a30Sjl 913*25cf1a30Sjl kmem_free(arr->arr, arr->arr_sz); 914*25cf1a30Sjl kmem_free(arr, sizeof (*arr)); 915*25cf1a30Sjl } 916*25cf1a30Sjl 917*25cf1a30Sjl static drmach_board_t * 918*25cf1a30Sjl drmach_get_board_by_bnum(int bnum) 919*25cf1a30Sjl { 920*25cf1a30Sjl drmachid_t id; 921*25cf1a30Sjl 922*25cf1a30Sjl if (drmach_array_get(drmach_boards, bnum, &id) == 0) 923*25cf1a30Sjl return ((drmach_board_t *)id); 924*25cf1a30Sjl else 925*25cf1a30Sjl return (NULL); 926*25cf1a30Sjl } 927*25cf1a30Sjl 928*25cf1a30Sjl static pnode_t 929*25cf1a30Sjl drmach_node_get_dnode(drmach_node_t *np) 930*25cf1a30Sjl { 931*25cf1a30Sjl return (np->get_dnode(np)); 932*25cf1a30Sjl } 933*25cf1a30Sjl 934*25cf1a30Sjl /*ARGSUSED*/ 935*25cf1a30Sjl sbd_error_t * 936*25cf1a30Sjl drmach_configure(drmachid_t id, int flags) 937*25cf1a30Sjl { 938*25cf1a30Sjl drmach_device_t *dp; 939*25cf1a30Sjl sbd_error_t *err = NULL; 940*25cf1a30Sjl dev_info_t *rdip; 941*25cf1a30Sjl dev_info_t *fdip = NULL; 942*25cf1a30Sjl 943*25cf1a30Sjl if (DRMACH_IS_CPU_ID(id)) { 944*25cf1a30Sjl return (NULL); 945*25cf1a30Sjl } 946*25cf1a30Sjl if (!DRMACH_IS_DEVICE_ID(id)) 947*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 948*25cf1a30Sjl dp = id; 949*25cf1a30Sjl rdip = dp->node->n_getdip(dp->node); 950*25cf1a30Sjl 951*25cf1a30Sjl ASSERT(rdip); 952*25cf1a30Sjl 953*25cf1a30Sjl ASSERT(e_ddi_branch_held(rdip)); 954*25cf1a30Sjl 955*25cf1a30Sjl if (e_ddi_branch_configure(rdip, &fdip, 0) != 0) { 956*25cf1a30Sjl char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 957*25cf1a30Sjl dev_info_t *dip = (fdip != NULL) ? fdip : rdip; 958*25cf1a30Sjl 959*25cf1a30Sjl (void) ddi_pathname(dip, path); 960*25cf1a30Sjl err = drerr_new(1, EOPL_DRVFAIL, path); 961*25cf1a30Sjl 962*25cf1a30Sjl kmem_free(path, MAXPATHLEN); 963*25cf1a30Sjl 964*25cf1a30Sjl /* If non-NULL, fdip is returned held and must be released */ 965*25cf1a30Sjl if (fdip != NULL) 966*25cf1a30Sjl ddi_release_devi(fdip); 967*25cf1a30Sjl } 968*25cf1a30Sjl 969*25cf1a30Sjl return (err); 970*25cf1a30Sjl } 971*25cf1a30Sjl 972*25cf1a30Sjl 973*25cf1a30Sjl static sbd_error_t * 974*25cf1a30Sjl drmach_device_new(drmach_node_t *node, 975*25cf1a30Sjl drmach_board_t *bp, int portid, drmachid_t *idp) 976*25cf1a30Sjl { 977*25cf1a30Sjl int i; 978*25cf1a30Sjl int rv; 979*25cf1a30Sjl drmach_device_t proto; 980*25cf1a30Sjl sbd_error_t *err; 981*25cf1a30Sjl char name[OBP_MAXDRVNAME]; 982*25cf1a30Sjl 983*25cf1a30Sjl rv = node->n_getprop(node, "name", name, OBP_MAXDRVNAME); 984*25cf1a30Sjl if (rv) { 985*25cf1a30Sjl /* every node is expected to have a name */ 986*25cf1a30Sjl err = drerr_new(1, EOPL_GETPROP, 987*25cf1a30Sjl "device node %s: property %s", 988*25cf1a30Sjl ddi_node_name(node->n_getdip(node)), "name"); 989*25cf1a30Sjl return (err); 990*25cf1a30Sjl } 991*25cf1a30Sjl 992*25cf1a30Sjl /* 993*25cf1a30Sjl * The node currently being examined is not listed in the name2type[] 994*25cf1a30Sjl * array. In this case, the node is no interest to drmach. Both 995*25cf1a30Sjl * dp and err are initialized here to yield nothing (no device or 996*25cf1a30Sjl * error structure) for this case. 997*25cf1a30Sjl */ 998*25cf1a30Sjl i = drmach_name2type_idx(name); 999*25cf1a30Sjl 1000*25cf1a30Sjl 1001*25cf1a30Sjl if (i < 0) { 1002*25cf1a30Sjl *idp = (drmachid_t)0; 1003*25cf1a30Sjl return (NULL); 1004*25cf1a30Sjl } 1005*25cf1a30Sjl 1006*25cf1a30Sjl /* device specific new function will set unum */ 1007*25cf1a30Sjl 1008*25cf1a30Sjl bzero(&proto, sizeof (proto)); 1009*25cf1a30Sjl proto.type = drmach_name2type[i].type; 1010*25cf1a30Sjl proto.bp = bp; 1011*25cf1a30Sjl proto.node = node; 1012*25cf1a30Sjl proto.portid = portid; 1013*25cf1a30Sjl 1014*25cf1a30Sjl return (drmach_name2type[i].new(&proto, idp)); 1015*25cf1a30Sjl } 1016*25cf1a30Sjl 1017*25cf1a30Sjl static void 1018*25cf1a30Sjl drmach_device_dispose(drmachid_t id) 1019*25cf1a30Sjl { 1020*25cf1a30Sjl drmach_device_t *self = id; 1021*25cf1a30Sjl 1022*25cf1a30Sjl self->cm.dispose(id); 1023*25cf1a30Sjl } 1024*25cf1a30Sjl 1025*25cf1a30Sjl 1026*25cf1a30Sjl static drmach_board_t * 1027*25cf1a30Sjl drmach_board_new(int bnum, int boot_board) 1028*25cf1a30Sjl { 1029*25cf1a30Sjl static sbd_error_t *drmach_board_release(drmachid_t); 1030*25cf1a30Sjl static sbd_error_t *drmach_board_status(drmachid_t, drmach_status_t *); 1031*25cf1a30Sjl 1032*25cf1a30Sjl drmach_board_t *bp; 1033*25cf1a30Sjl 1034*25cf1a30Sjl bp = kmem_zalloc(sizeof (drmach_board_t), KM_SLEEP); 1035*25cf1a30Sjl 1036*25cf1a30Sjl bp->cm.isa = (void *)drmach_board_new; 1037*25cf1a30Sjl bp->cm.release = drmach_board_release; 1038*25cf1a30Sjl bp->cm.status = drmach_board_status; 1039*25cf1a30Sjl 1040*25cf1a30Sjl (void) drmach_board_name(bnum, bp->cm.name, sizeof (bp->cm.name)); 1041*25cf1a30Sjl 1042*25cf1a30Sjl bp->bnum = bnum; 1043*25cf1a30Sjl bp->devices = NULL; 1044*25cf1a30Sjl bp->connected = boot_board; 1045*25cf1a30Sjl bp->tree = drmach_node_new(); 1046*25cf1a30Sjl bp->assigned = boot_board; 1047*25cf1a30Sjl bp->powered = boot_board; 1048*25cf1a30Sjl bp->boot_board = boot_board; 1049*25cf1a30Sjl 1050*25cf1a30Sjl /* 1051*25cf1a30Sjl * If this is not bootup initialization, we have to wait till 1052*25cf1a30Sjl * IKP sets up the device nodes in drmach_board_connect(). 1053*25cf1a30Sjl */ 1054*25cf1a30Sjl if (boot_board) 1055*25cf1a30Sjl drmach_setup_core_info(bp); 1056*25cf1a30Sjl 1057*25cf1a30Sjl drmach_array_set(drmach_boards, bnum, bp); 1058*25cf1a30Sjl return (bp); 1059*25cf1a30Sjl } 1060*25cf1a30Sjl 1061*25cf1a30Sjl static void 1062*25cf1a30Sjl drmach_board_dispose(drmachid_t id) 1063*25cf1a30Sjl { 1064*25cf1a30Sjl drmach_board_t *bp; 1065*25cf1a30Sjl 1066*25cf1a30Sjl ASSERT(DRMACH_IS_BOARD_ID(id)); 1067*25cf1a30Sjl bp = id; 1068*25cf1a30Sjl 1069*25cf1a30Sjl if (bp->tree) 1070*25cf1a30Sjl drmach_node_dispose(bp->tree); 1071*25cf1a30Sjl 1072*25cf1a30Sjl if (bp->devices) 1073*25cf1a30Sjl drmach_array_dispose(bp->devices, drmach_device_dispose); 1074*25cf1a30Sjl 1075*25cf1a30Sjl kmem_free(bp, sizeof (*bp)); 1076*25cf1a30Sjl } 1077*25cf1a30Sjl 1078*25cf1a30Sjl static sbd_error_t * 1079*25cf1a30Sjl drmach_board_status(drmachid_t id, drmach_status_t *stat) 1080*25cf1a30Sjl { 1081*25cf1a30Sjl sbd_error_t *err = NULL; 1082*25cf1a30Sjl drmach_board_t *bp; 1083*25cf1a30Sjl 1084*25cf1a30Sjl if (!DRMACH_IS_BOARD_ID(id)) 1085*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 1086*25cf1a30Sjl bp = id; 1087*25cf1a30Sjl 1088*25cf1a30Sjl stat->assigned = bp->assigned; 1089*25cf1a30Sjl stat->powered = bp->powered; 1090*25cf1a30Sjl stat->busy = 0; /* assume not busy */ 1091*25cf1a30Sjl stat->configured = 0; /* assume not configured */ 1092*25cf1a30Sjl stat->empty = 0; 1093*25cf1a30Sjl stat->cond = bp->cond = SBD_COND_OK; 1094*25cf1a30Sjl strncpy(stat->type, "System Brd", sizeof (stat->type)); 1095*25cf1a30Sjl stat->info[0] = '\0'; 1096*25cf1a30Sjl 1097*25cf1a30Sjl if (bp->devices) { 1098*25cf1a30Sjl int rv; 1099*25cf1a30Sjl int d_idx; 1100*25cf1a30Sjl drmachid_t d_id; 1101*25cf1a30Sjl 1102*25cf1a30Sjl rv = drmach_array_first(bp->devices, &d_idx, &d_id); 1103*25cf1a30Sjl while (rv == 0) { 1104*25cf1a30Sjl drmach_status_t d_stat; 1105*25cf1a30Sjl 1106*25cf1a30Sjl err = drmach_i_status(d_id, &d_stat); 1107*25cf1a30Sjl if (err) 1108*25cf1a30Sjl break; 1109*25cf1a30Sjl 1110*25cf1a30Sjl stat->busy |= d_stat.busy; 1111*25cf1a30Sjl stat->configured |= d_stat.configured; 1112*25cf1a30Sjl 1113*25cf1a30Sjl rv = drmach_array_next(bp->devices, &d_idx, &d_id); 1114*25cf1a30Sjl } 1115*25cf1a30Sjl } 1116*25cf1a30Sjl 1117*25cf1a30Sjl return (err); 1118*25cf1a30Sjl } 1119*25cf1a30Sjl 1120*25cf1a30Sjl int 1121*25cf1a30Sjl drmach_board_is_floating(drmachid_t id) 1122*25cf1a30Sjl { 1123*25cf1a30Sjl drmach_board_t *bp; 1124*25cf1a30Sjl 1125*25cf1a30Sjl if (!DRMACH_IS_BOARD_ID(id)) 1126*25cf1a30Sjl return (0); 1127*25cf1a30Sjl 1128*25cf1a30Sjl bp = (drmach_board_t *)id; 1129*25cf1a30Sjl 1130*25cf1a30Sjl return ((drmach_domain.floating & (1 << bp->bnum)) ? 1 : 0); 1131*25cf1a30Sjl } 1132*25cf1a30Sjl 1133*25cf1a30Sjl static int 1134*25cf1a30Sjl drmach_init(void) 1135*25cf1a30Sjl { 1136*25cf1a30Sjl dev_info_t *rdip; 1137*25cf1a30Sjl int i, rv, len; 1138*25cf1a30Sjl int *floating; 1139*25cf1a30Sjl 1140*25cf1a30Sjl rw_init(&drmach_boards_rwlock, NULL, RW_DEFAULT, NULL); 1141*25cf1a30Sjl 1142*25cf1a30Sjl drmach_boards = drmach_array_new(0, MAX_BOARDS - 1); 1143*25cf1a30Sjl 1144*25cf1a30Sjl rdip = ddi_root_node(); 1145*25cf1a30Sjl 1146*25cf1a30Sjl if (ddi_getproplen(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 1147*25cf1a30Sjl "floating-boards", &len) != DDI_PROP_SUCCESS) { 1148*25cf1a30Sjl cmn_err(CE_WARN, "Cannot get floating-boards proplen\n"); 1149*25cf1a30Sjl } else { 1150*25cf1a30Sjl floating = (int *)kmem_alloc(len, KM_SLEEP); 1151*25cf1a30Sjl rv = ddi_prop_op(DDI_DEV_T_ANY, rdip, 1152*25cf1a30Sjl PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, 1153*25cf1a30Sjl "floating-boards", (caddr_t)floating, &len); 1154*25cf1a30Sjl if (rv != DDI_PROP_SUCCESS) { 1155*25cf1a30Sjl cmn_err(CE_WARN, "Cannot get floating-boards prop\n"); 1156*25cf1a30Sjl } else { 1157*25cf1a30Sjl drmach_domain.floating = 0; 1158*25cf1a30Sjl for (i = 0; i < len / sizeof (int); i++) { 1159*25cf1a30Sjl drmach_domain.floating |= (1 << floating[i]); 1160*25cf1a30Sjl } 1161*25cf1a30Sjl } 1162*25cf1a30Sjl kmem_free(floating, len); 1163*25cf1a30Sjl } 1164*25cf1a30Sjl drmach_domain.allow_dr = opl_check_dr_status(); 1165*25cf1a30Sjl 1166*25cf1a30Sjl rdip = ddi_get_child(ddi_root_node()); 1167*25cf1a30Sjl do { 1168*25cf1a30Sjl int bnum; 1169*25cf1a30Sjl drmachid_t id; 1170*25cf1a30Sjl 1171*25cf1a30Sjl bnum = -1; 1172*25cf1a30Sjl bnum = ddi_getprop(DDI_DEV_T_ANY, rdip, 1173*25cf1a30Sjl DDI_PROP_DONTPASS, OBP_BOARDNUM, -1); 1174*25cf1a30Sjl if (bnum == -1) 1175*25cf1a30Sjl continue; 1176*25cf1a30Sjl 1177*25cf1a30Sjl if (drmach_array_get(drmach_boards, bnum, &id) == -1) { 1178*25cf1a30Sjl cmn_err(CE_WARN, "Device node 0x%p has" 1179*25cf1a30Sjl " invalid property value, %s=%d", 1180*25cf1a30Sjl rdip, OBP_BOARDNUM, bnum); 1181*25cf1a30Sjl goto error; 1182*25cf1a30Sjl } else if (id == NULL) { 1183*25cf1a30Sjl (void) drmach_board_new(bnum, 1); 1184*25cf1a30Sjl } 1185*25cf1a30Sjl } while ((rdip = ddi_get_next_sibling(rdip)) != NULL); 1186*25cf1a30Sjl 1187*25cf1a30Sjl opl_hold_devtree(); 1188*25cf1a30Sjl 1189*25cf1a30Sjl /* 1190*25cf1a30Sjl * Initialize the IKP feature. 1191*25cf1a30Sjl * 1192*25cf1a30Sjl * This can be done only after DR has acquired a hold on all the 1193*25cf1a30Sjl * device nodes that are interesting to IKP. 1194*25cf1a30Sjl */ 1195*25cf1a30Sjl if (opl_init_cfg() != 0) { 1196*25cf1a30Sjl cmn_err(CE_WARN, "DR - IKP initialization failed"); 1197*25cf1a30Sjl 1198*25cf1a30Sjl opl_release_devtree(); 1199*25cf1a30Sjl 1200*25cf1a30Sjl goto error; 1201*25cf1a30Sjl } 1202*25cf1a30Sjl 1203*25cf1a30Sjl return (0); 1204*25cf1a30Sjl error: 1205*25cf1a30Sjl drmach_array_dispose(drmach_boards, drmach_board_dispose); 1206*25cf1a30Sjl rw_destroy(&drmach_boards_rwlock); 1207*25cf1a30Sjl return (ENXIO); 1208*25cf1a30Sjl } 1209*25cf1a30Sjl 1210*25cf1a30Sjl static void 1211*25cf1a30Sjl drmach_fini(void) 1212*25cf1a30Sjl { 1213*25cf1a30Sjl rw_enter(&drmach_boards_rwlock, RW_WRITER); 1214*25cf1a30Sjl drmach_array_dispose(drmach_boards, drmach_board_dispose); 1215*25cf1a30Sjl drmach_boards = NULL; 1216*25cf1a30Sjl rw_exit(&drmach_boards_rwlock); 1217*25cf1a30Sjl 1218*25cf1a30Sjl /* 1219*25cf1a30Sjl * Walk immediate children of the root devinfo node 1220*25cf1a30Sjl * releasing holds acquired on branches in drmach_init() 1221*25cf1a30Sjl */ 1222*25cf1a30Sjl 1223*25cf1a30Sjl opl_release_devtree(); 1224*25cf1a30Sjl 1225*25cf1a30Sjl rw_destroy(&drmach_boards_rwlock); 1226*25cf1a30Sjl } 1227*25cf1a30Sjl 1228*25cf1a30Sjl /* 1229*25cf1a30Sjl * Each system board contains 2 Oberon PCI bridge and 1230*25cf1a30Sjl * 1 CMUCH. 1231*25cf1a30Sjl * Each oberon has 2 channels. 1232*25cf1a30Sjl * Each channel has 2 pci-ex leaf. 1233*25cf1a30Sjl * Each CMUCH has 1 pci bus. 1234*25cf1a30Sjl * 1235*25cf1a30Sjl * 1236*25cf1a30Sjl * Device Path: 1237*25cf1a30Sjl * /pci@<portid>,reg 1238*25cf1a30Sjl * 1239*25cf1a30Sjl * where 1240*25cf1a30Sjl * portid[10] = 0 1241*25cf1a30Sjl * portid[9:0] = LLEAF_ID[9:0] of the Oberon Channel 1242*25cf1a30Sjl * 1243*25cf1a30Sjl * LLEAF_ID[9:8] = 0 1244*25cf1a30Sjl * LLEAF_ID[8:4] = LSB_ID[4:0] 1245*25cf1a30Sjl * LLEAF_ID[3:1] = IO Channel#[2:0] (0,1,2,3 for Oberon) 1246*25cf1a30Sjl * channel 4 is pcicmu 1247*25cf1a30Sjl * LLEAF_ID[0] = PCI Leaf Number (0 for leaf-A, 1 for leaf-B) 1248*25cf1a30Sjl * 1249*25cf1a30Sjl * Properties: 1250*25cf1a30Sjl * name = pci 1251*25cf1a30Sjl * device_type = "pciex" 1252*25cf1a30Sjl * board# = LSBID 1253*25cf1a30Sjl * reg = int32 * 2, Oberon CSR space of the leaf and the UBC space 1254*25cf1a30Sjl * portid = Jupiter Bus Device ID ((LSB_ID << 3)|pciport#) 1255*25cf1a30Sjl */ 1256*25cf1a30Sjl 1257*25cf1a30Sjl static sbd_error_t * 1258*25cf1a30Sjl drmach_io_new(drmach_device_t *proto, drmachid_t *idp) 1259*25cf1a30Sjl { 1260*25cf1a30Sjl drmach_io_t *ip; 1261*25cf1a30Sjl 1262*25cf1a30Sjl int portid; 1263*25cf1a30Sjl 1264*25cf1a30Sjl portid = proto->portid; 1265*25cf1a30Sjl ASSERT(portid != -1); 1266*25cf1a30Sjl proto->unum = portid & (MAX_IO_UNITS_PER_BOARD - 1); 1267*25cf1a30Sjl 1268*25cf1a30Sjl ip = kmem_zalloc(sizeof (drmach_io_t), KM_SLEEP); 1269*25cf1a30Sjl bcopy(proto, &ip->dev, sizeof (ip->dev)); 1270*25cf1a30Sjl ip->dev.node = drmach_node_dup(proto->node); 1271*25cf1a30Sjl ip->dev.cm.isa = (void *)drmach_io_new; 1272*25cf1a30Sjl ip->dev.cm.dispose = drmach_io_dispose; 1273*25cf1a30Sjl ip->dev.cm.release = drmach_io_release; 1274*25cf1a30Sjl ip->dev.cm.status = drmach_io_status; 1275*25cf1a30Sjl ip->channel = (portid >> 1) & 0x7; 1276*25cf1a30Sjl ip->leaf = (portid & 0x1); 1277*25cf1a30Sjl 1278*25cf1a30Sjl snprintf(ip->dev.cm.name, sizeof (ip->dev.cm.name), "%s%d", 1279*25cf1a30Sjl ip->dev.type, ip->dev.unum); 1280*25cf1a30Sjl 1281*25cf1a30Sjl *idp = (drmachid_t)ip; 1282*25cf1a30Sjl return (NULL); 1283*25cf1a30Sjl } 1284*25cf1a30Sjl 1285*25cf1a30Sjl 1286*25cf1a30Sjl static void 1287*25cf1a30Sjl drmach_io_dispose(drmachid_t id) 1288*25cf1a30Sjl { 1289*25cf1a30Sjl drmach_io_t *self; 1290*25cf1a30Sjl 1291*25cf1a30Sjl ASSERT(DRMACH_IS_IO_ID(id)); 1292*25cf1a30Sjl 1293*25cf1a30Sjl self = id; 1294*25cf1a30Sjl if (self->dev.node) 1295*25cf1a30Sjl drmach_node_dispose(self->dev.node); 1296*25cf1a30Sjl 1297*25cf1a30Sjl kmem_free(self, sizeof (*self)); 1298*25cf1a30Sjl } 1299*25cf1a30Sjl 1300*25cf1a30Sjl /*ARGSUSED*/ 1301*25cf1a30Sjl sbd_error_t * 1302*25cf1a30Sjl drmach_pre_op(int cmd, drmachid_t id, drmach_opts_t *opts) 1303*25cf1a30Sjl { 1304*25cf1a30Sjl drmach_board_t *bp = (drmach_board_t *)id; 1305*25cf1a30Sjl sbd_error_t *err = NULL; 1306*25cf1a30Sjl 1307*25cf1a30Sjl /* allow status and ncm operations to always succeed */ 1308*25cf1a30Sjl if ((cmd == SBD_CMD_STATUS) || (cmd == SBD_CMD_GETNCM)) { 1309*25cf1a30Sjl return (NULL); 1310*25cf1a30Sjl } 1311*25cf1a30Sjl 1312*25cf1a30Sjl /* check all other commands for the required option string */ 1313*25cf1a30Sjl 1314*25cf1a30Sjl if ((opts->size > 0) && (opts->copts != NULL)) { 1315*25cf1a30Sjl 1316*25cf1a30Sjl DRMACH_PR("platform options: %s\n", opts->copts); 1317*25cf1a30Sjl 1318*25cf1a30Sjl if (strstr(opts->copts, "opldr") == NULL) { 1319*25cf1a30Sjl err = drerr_new(1, EOPL_SUPPORT, NULL); 1320*25cf1a30Sjl } 1321*25cf1a30Sjl } else { 1322*25cf1a30Sjl err = drerr_new(1, EOPL_SUPPORT, NULL); 1323*25cf1a30Sjl } 1324*25cf1a30Sjl 1325*25cf1a30Sjl if (!err && id && DRMACH_IS_BOARD_ID(id)) { 1326*25cf1a30Sjl switch (cmd) { 1327*25cf1a30Sjl case SBD_CMD_TEST: 1328*25cf1a30Sjl case SBD_CMD_STATUS: 1329*25cf1a30Sjl case SBD_CMD_GETNCM: 1330*25cf1a30Sjl break; 1331*25cf1a30Sjl case SBD_CMD_CONNECT: 1332*25cf1a30Sjl if (bp->connected) 1333*25cf1a30Sjl err = drerr_new(0, ESBD_STATE, NULL); 1334*25cf1a30Sjl else if (!drmach_domain.allow_dr) 1335*25cf1a30Sjl err = drerr_new(1, EOPL_SUPPORT, 1336*25cf1a30Sjl NULL); 1337*25cf1a30Sjl break; 1338*25cf1a30Sjl case SBD_CMD_DISCONNECT: 1339*25cf1a30Sjl if (!bp->connected) 1340*25cf1a30Sjl err = drerr_new(0, ESBD_STATE, NULL); 1341*25cf1a30Sjl else if (!drmach_domain.allow_dr) 1342*25cf1a30Sjl err = drerr_new(1, EOPL_SUPPORT, 1343*25cf1a30Sjl NULL); 1344*25cf1a30Sjl break; 1345*25cf1a30Sjl default: 1346*25cf1a30Sjl if (!drmach_domain.allow_dr) 1347*25cf1a30Sjl err = drerr_new(1, EOPL_SUPPORT, 1348*25cf1a30Sjl NULL); 1349*25cf1a30Sjl break; 1350*25cf1a30Sjl 1351*25cf1a30Sjl } 1352*25cf1a30Sjl } 1353*25cf1a30Sjl 1354*25cf1a30Sjl return (err); 1355*25cf1a30Sjl } 1356*25cf1a30Sjl 1357*25cf1a30Sjl /*ARGSUSED*/ 1358*25cf1a30Sjl sbd_error_t * 1359*25cf1a30Sjl drmach_post_op(int cmd, drmachid_t id, drmach_opts_t *opts) 1360*25cf1a30Sjl { 1361*25cf1a30Sjl return (NULL); 1362*25cf1a30Sjl } 1363*25cf1a30Sjl 1364*25cf1a30Sjl sbd_error_t * 1365*25cf1a30Sjl drmach_board_assign(int bnum, drmachid_t *id) 1366*25cf1a30Sjl { 1367*25cf1a30Sjl sbd_error_t *err = NULL; 1368*25cf1a30Sjl 1369*25cf1a30Sjl rw_enter(&drmach_boards_rwlock, RW_WRITER); 1370*25cf1a30Sjl 1371*25cf1a30Sjl if (drmach_array_get(drmach_boards, bnum, id) == -1) { 1372*25cf1a30Sjl err = drerr_new(1, EOPL_BNUM, "%d", bnum); 1373*25cf1a30Sjl } else { 1374*25cf1a30Sjl drmach_board_t *bp; 1375*25cf1a30Sjl 1376*25cf1a30Sjl if (*id) 1377*25cf1a30Sjl rw_downgrade(&drmach_boards_rwlock); 1378*25cf1a30Sjl 1379*25cf1a30Sjl bp = *id; 1380*25cf1a30Sjl if (!(*id)) 1381*25cf1a30Sjl bp = *id = 1382*25cf1a30Sjl (drmachid_t)drmach_board_new(bnum, 0); 1383*25cf1a30Sjl bp->assigned = 1; 1384*25cf1a30Sjl } 1385*25cf1a30Sjl 1386*25cf1a30Sjl rw_exit(&drmach_boards_rwlock); 1387*25cf1a30Sjl 1388*25cf1a30Sjl return (err); 1389*25cf1a30Sjl } 1390*25cf1a30Sjl 1391*25cf1a30Sjl /*ARGSUSED*/ 1392*25cf1a30Sjl sbd_error_t * 1393*25cf1a30Sjl drmach_board_connect(drmachid_t id, drmach_opts_t *opts) 1394*25cf1a30Sjl { 1395*25cf1a30Sjl drmach_board_t *obj = (drmach_board_t *)id; 1396*25cf1a30Sjl 1397*25cf1a30Sjl if (!DRMACH_IS_BOARD_ID(id)) 1398*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 1399*25cf1a30Sjl 1400*25cf1a30Sjl if (opl_probe_sb(obj->bnum) != 0) 1401*25cf1a30Sjl return (DRMACH_INTERNAL_ERROR()); 1402*25cf1a30Sjl 1403*25cf1a30Sjl (void) prom_attach_notice(obj->bnum); 1404*25cf1a30Sjl 1405*25cf1a30Sjl drmach_setup_core_info(obj); 1406*25cf1a30Sjl 1407*25cf1a30Sjl obj->connected = 1; 1408*25cf1a30Sjl 1409*25cf1a30Sjl return (NULL); 1410*25cf1a30Sjl } 1411*25cf1a30Sjl 1412*25cf1a30Sjl static int drmach_cache_flush_flag[NCPU]; 1413*25cf1a30Sjl 1414*25cf1a30Sjl /*ARGSUSED*/ 1415*25cf1a30Sjl static void 1416*25cf1a30Sjl drmach_flush_cache(uint64_t id, uint64_t dummy) 1417*25cf1a30Sjl { 1418*25cf1a30Sjl extern void cpu_flush_ecache(void); 1419*25cf1a30Sjl 1420*25cf1a30Sjl cpu_flush_ecache(); 1421*25cf1a30Sjl drmach_cache_flush_flag[id] = 0; 1422*25cf1a30Sjl } 1423*25cf1a30Sjl 1424*25cf1a30Sjl static void 1425*25cf1a30Sjl drmach_flush_all() 1426*25cf1a30Sjl { 1427*25cf1a30Sjl cpuset_t xc_cpuset; 1428*25cf1a30Sjl int i; 1429*25cf1a30Sjl 1430*25cf1a30Sjl xc_cpuset = cpu_ready_set; 1431*25cf1a30Sjl for (i = 0; i < NCPU; i++) { 1432*25cf1a30Sjl if (CPU_IN_SET(xc_cpuset, i)) { 1433*25cf1a30Sjl drmach_cache_flush_flag[i] = 1; 1434*25cf1a30Sjl xc_one(i, drmach_flush_cache, i, 0); 1435*25cf1a30Sjl while (drmach_cache_flush_flag[i]) { 1436*25cf1a30Sjl DELAY(1000); 1437*25cf1a30Sjl } 1438*25cf1a30Sjl } 1439*25cf1a30Sjl } 1440*25cf1a30Sjl } 1441*25cf1a30Sjl 1442*25cf1a30Sjl static int 1443*25cf1a30Sjl drmach_disconnect_cpus(drmach_board_t *bp) 1444*25cf1a30Sjl { 1445*25cf1a30Sjl int i, bnum; 1446*25cf1a30Sjl 1447*25cf1a30Sjl bnum = bp->bnum; 1448*25cf1a30Sjl 1449*25cf1a30Sjl for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) { 1450*25cf1a30Sjl if (bp->cores[i].core_present) { 1451*25cf1a30Sjl if (bp->cores[i].core_started) 1452*25cf1a30Sjl return (-1); 1453*25cf1a30Sjl if (bp->cores[i].core_hotadded) { 1454*25cf1a30Sjl if (drmach_add_remove_cpu(bnum, i, HOTREMOVE_CPU)) { 1455*25cf1a30Sjl cmn_err(CE_WARN, 1456*25cf1a30Sjl "Failed to remove CMP %d on board %d\n", 1457*25cf1a30Sjl i, bnum); 1458*25cf1a30Sjl return (-1); 1459*25cf1a30Sjl } 1460*25cf1a30Sjl } 1461*25cf1a30Sjl } 1462*25cf1a30Sjl } 1463*25cf1a30Sjl return (0); 1464*25cf1a30Sjl } 1465*25cf1a30Sjl 1466*25cf1a30Sjl /*ARGSUSED*/ 1467*25cf1a30Sjl sbd_error_t * 1468*25cf1a30Sjl drmach_board_disconnect(drmachid_t id, drmach_opts_t *opts) 1469*25cf1a30Sjl { 1470*25cf1a30Sjl drmach_board_t *obj; 1471*25cf1a30Sjl int rv = 0; 1472*25cf1a30Sjl sbd_error_t *err = NULL; 1473*25cf1a30Sjl 1474*25cf1a30Sjl 1475*25cf1a30Sjl if (!DRMACH_IS_BOARD_ID(id)) 1476*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 1477*25cf1a30Sjl 1478*25cf1a30Sjl 1479*25cf1a30Sjl 1480*25cf1a30Sjl obj = (drmach_board_t *)id; 1481*25cf1a30Sjl 1482*25cf1a30Sjl if (drmach_disconnect_cpus(obj)) { 1483*25cf1a30Sjl err = drerr_new(0, EOPL_DEPROBE, obj->cm.name); 1484*25cf1a30Sjl return (err); 1485*25cf1a30Sjl } 1486*25cf1a30Sjl 1487*25cf1a30Sjl rv = opl_unprobe_sb(obj->bnum); 1488*25cf1a30Sjl 1489*25cf1a30Sjl if (rv == 0) { 1490*25cf1a30Sjl prom_detach_notice(obj->bnum); 1491*25cf1a30Sjl obj->connected = 0; 1492*25cf1a30Sjl 1493*25cf1a30Sjl } else 1494*25cf1a30Sjl err = drerr_new(0, EOPL_DEPROBE, obj->cm.name); 1495*25cf1a30Sjl 1496*25cf1a30Sjl return (err); 1497*25cf1a30Sjl } 1498*25cf1a30Sjl 1499*25cf1a30Sjl static int 1500*25cf1a30Sjl drmach_get_portid(drmach_node_t *np) 1501*25cf1a30Sjl { 1502*25cf1a30Sjl int portid; 1503*25cf1a30Sjl char type[OBP_MAXPROPNAME]; 1504*25cf1a30Sjl 1505*25cf1a30Sjl if (np->n_getprop(np, "portid", &portid, sizeof (portid)) == 0) 1506*25cf1a30Sjl return (portid); 1507*25cf1a30Sjl 1508*25cf1a30Sjl /* 1509*25cf1a30Sjl * Get the device_type property to see if we should 1510*25cf1a30Sjl * continue processing this node. 1511*25cf1a30Sjl */ 1512*25cf1a30Sjl if (np->n_getprop(np, "device_type", &type, sizeof (type)) != 0) 1513*25cf1a30Sjl return (-1); 1514*25cf1a30Sjl 1515*25cf1a30Sjl if (strcmp(type, OPL_CPU_NODE) == 0) { 1516*25cf1a30Sjl /* 1517*25cf1a30Sjl * We return cpuid because it has no portid 1518*25cf1a30Sjl */ 1519*25cf1a30Sjl if (np->n_getprop(np, "cpuid", &portid, sizeof (portid)) == 0) 1520*25cf1a30Sjl return (portid); 1521*25cf1a30Sjl } 1522*25cf1a30Sjl 1523*25cf1a30Sjl return (-1); 1524*25cf1a30Sjl } 1525*25cf1a30Sjl 1526*25cf1a30Sjl /* 1527*25cf1a30Sjl * This is a helper function to determine if a given 1528*25cf1a30Sjl * node should be considered for a dr operation according 1529*25cf1a30Sjl * to predefined dr type nodes and the node's name. 1530*25cf1a30Sjl * Formal Parameter : The name of a device node. 1531*25cf1a30Sjl * Return Value: -1, name does not map to a valid dr type. 1532*25cf1a30Sjl * A value greater or equal to 0, name is a valid dr type. 1533*25cf1a30Sjl */ 1534*25cf1a30Sjl static int 1535*25cf1a30Sjl drmach_name2type_idx(char *name) 1536*25cf1a30Sjl { 1537*25cf1a30Sjl int index, ntypes; 1538*25cf1a30Sjl 1539*25cf1a30Sjl if (name == NULL) 1540*25cf1a30Sjl return (-1); 1541*25cf1a30Sjl 1542*25cf1a30Sjl /* 1543*25cf1a30Sjl * Determine how many possible types are currently supported 1544*25cf1a30Sjl * for dr. 1545*25cf1a30Sjl */ 1546*25cf1a30Sjl ntypes = sizeof (drmach_name2type) / sizeof (drmach_name2type[0]); 1547*25cf1a30Sjl 1548*25cf1a30Sjl /* Determine if the node's name correspond to a predefined type. */ 1549*25cf1a30Sjl for (index = 0; index < ntypes; index++) { 1550*25cf1a30Sjl if (strcmp(drmach_name2type[index].name, name) == 0) 1551*25cf1a30Sjl /* The node is an allowed type for dr. */ 1552*25cf1a30Sjl return (index); 1553*25cf1a30Sjl } 1554*25cf1a30Sjl 1555*25cf1a30Sjl /* 1556*25cf1a30Sjl * If the name of the node does not map to any of the 1557*25cf1a30Sjl * types in the array drmach_name2type then the node is not of 1558*25cf1a30Sjl * interest to dr. 1559*25cf1a30Sjl */ 1560*25cf1a30Sjl return (-1); 1561*25cf1a30Sjl } 1562*25cf1a30Sjl 1563*25cf1a30Sjl /* 1564*25cf1a30Sjl * there is some complication on OPL: 1565*25cf1a30Sjl * - pseudo-mc nodes do not have portid property 1566*25cf1a30Sjl * - portid[9:5] of cmp node is LSB #, portid[7:3] of pci is LSB# 1567*25cf1a30Sjl * - cmp has board# 1568*25cf1a30Sjl * - core and cpu nodes do not have portid and board# properties 1569*25cf1a30Sjl * starcat uses portid to derive the board# but that does not work 1570*25cf1a30Sjl * for us. starfire reads board# property to filter the devices. 1571*25cf1a30Sjl * That does not work either. So for these specific device, 1572*25cf1a30Sjl * we use specific hard coded methods to get the board# - 1573*25cf1a30Sjl * cpu: LSB# = CPUID[9:5] 1574*25cf1a30Sjl */ 1575*25cf1a30Sjl 1576*25cf1a30Sjl static int 1577*25cf1a30Sjl drmach_board_find_devices_cb(drmach_node_walk_args_t *args) 1578*25cf1a30Sjl { 1579*25cf1a30Sjl drmach_node_t *node = args->node; 1580*25cf1a30Sjl drmach_board_cb_data_t *data = args->data; 1581*25cf1a30Sjl drmach_board_t *obj = data->obj; 1582*25cf1a30Sjl 1583*25cf1a30Sjl int rv, portid; 1584*25cf1a30Sjl int bnum; 1585*25cf1a30Sjl drmachid_t id; 1586*25cf1a30Sjl drmach_device_t *device; 1587*25cf1a30Sjl char name[OBP_MAXDRVNAME]; 1588*25cf1a30Sjl 1589*25cf1a30Sjl portid = drmach_get_portid(node); 1590*25cf1a30Sjl /* 1591*25cf1a30Sjl * core, cpu and pseudo-mc do not have portid 1592*25cf1a30Sjl * we use cpuid as the portid of the cpu node 1593*25cf1a30Sjl * for pseudo-mc, we do not use portid info. 1594*25cf1a30Sjl */ 1595*25cf1a30Sjl 1596*25cf1a30Sjl rv = node->n_getprop(node, "name", name, OBP_MAXDRVNAME); 1597*25cf1a30Sjl if (rv) 1598*25cf1a30Sjl return (0); 1599*25cf1a30Sjl 1600*25cf1a30Sjl 1601*25cf1a30Sjl rv = node->n_getprop(node, OBP_BOARDNUM, &bnum, sizeof (bnum)); 1602*25cf1a30Sjl 1603*25cf1a30Sjl if (rv) { 1604*25cf1a30Sjl /* 1605*25cf1a30Sjl * cpu does not have board# property. We use 1606*25cf1a30Sjl * CPUID[9:5] 1607*25cf1a30Sjl */ 1608*25cf1a30Sjl if (strcmp("cpu", name) == 0) { 1609*25cf1a30Sjl bnum = (portid >> 5) & 0x1f; 1610*25cf1a30Sjl } else 1611*25cf1a30Sjl return (0); 1612*25cf1a30Sjl } 1613*25cf1a30Sjl 1614*25cf1a30Sjl 1615*25cf1a30Sjl if (bnum != obj->bnum) 1616*25cf1a30Sjl return (0); 1617*25cf1a30Sjl 1618*25cf1a30Sjl if (drmach_name2type_idx(name) < 0) { 1619*25cf1a30Sjl return (0); 1620*25cf1a30Sjl } 1621*25cf1a30Sjl 1622*25cf1a30Sjl /* 1623*25cf1a30Sjl * Create a device data structure from this node data. 1624*25cf1a30Sjl * The call may yield nothing if the node is not of interest 1625*25cf1a30Sjl * to drmach. 1626*25cf1a30Sjl */ 1627*25cf1a30Sjl data->err = drmach_device_new(node, obj, portid, &id); 1628*25cf1a30Sjl if (data->err) 1629*25cf1a30Sjl return (-1); 1630*25cf1a30Sjl else if (!id) { 1631*25cf1a30Sjl /* 1632*25cf1a30Sjl * drmach_device_new examined the node we passed in 1633*25cf1a30Sjl * and determined that it was one not of interest to 1634*25cf1a30Sjl * drmach. So, it is skipped. 1635*25cf1a30Sjl */ 1636*25cf1a30Sjl return (0); 1637*25cf1a30Sjl } 1638*25cf1a30Sjl 1639*25cf1a30Sjl rv = drmach_array_set(obj->devices, data->ndevs++, id); 1640*25cf1a30Sjl if (rv) { 1641*25cf1a30Sjl data->err = DRMACH_INTERNAL_ERROR(); 1642*25cf1a30Sjl return (-1); 1643*25cf1a30Sjl } 1644*25cf1a30Sjl device = id; 1645*25cf1a30Sjl 1646*25cf1a30Sjl data->err = (*data->found)(data->a, device->type, device->unum, id); 1647*25cf1a30Sjl return (data->err == NULL ? 0 : -1); 1648*25cf1a30Sjl } 1649*25cf1a30Sjl 1650*25cf1a30Sjl sbd_error_t * 1651*25cf1a30Sjl drmach_board_find_devices(drmachid_t id, void *a, 1652*25cf1a30Sjl sbd_error_t *(*found)(void *a, const char *, int, drmachid_t)) 1653*25cf1a30Sjl { 1654*25cf1a30Sjl drmach_board_t *bp = (drmach_board_t *)id; 1655*25cf1a30Sjl sbd_error_t *err; 1656*25cf1a30Sjl int max_devices; 1657*25cf1a30Sjl int rv; 1658*25cf1a30Sjl drmach_board_cb_data_t data; 1659*25cf1a30Sjl 1660*25cf1a30Sjl 1661*25cf1a30Sjl if (!DRMACH_IS_BOARD_ID(id)) 1662*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 1663*25cf1a30Sjl 1664*25cf1a30Sjl max_devices = MAX_CPU_UNITS_PER_BOARD; 1665*25cf1a30Sjl max_devices += MAX_MEM_UNITS_PER_BOARD; 1666*25cf1a30Sjl max_devices += MAX_IO_UNITS_PER_BOARD; 1667*25cf1a30Sjl 1668*25cf1a30Sjl bp->devices = drmach_array_new(0, max_devices); 1669*25cf1a30Sjl 1670*25cf1a30Sjl if (bp->tree == NULL) 1671*25cf1a30Sjl bp->tree = drmach_node_new(); 1672*25cf1a30Sjl 1673*25cf1a30Sjl data.obj = bp; 1674*25cf1a30Sjl data.ndevs = 0; 1675*25cf1a30Sjl data.found = found; 1676*25cf1a30Sjl data.a = a; 1677*25cf1a30Sjl data.err = NULL; 1678*25cf1a30Sjl 1679*25cf1a30Sjl rv = drmach_node_walk(bp->tree, &data, drmach_board_find_devices_cb); 1680*25cf1a30Sjl if (rv == 0) 1681*25cf1a30Sjl err = NULL; 1682*25cf1a30Sjl else { 1683*25cf1a30Sjl drmach_array_dispose(bp->devices, drmach_device_dispose); 1684*25cf1a30Sjl bp->devices = NULL; 1685*25cf1a30Sjl 1686*25cf1a30Sjl if (data.err) 1687*25cf1a30Sjl err = data.err; 1688*25cf1a30Sjl else 1689*25cf1a30Sjl err = DRMACH_INTERNAL_ERROR(); 1690*25cf1a30Sjl } 1691*25cf1a30Sjl 1692*25cf1a30Sjl return (err); 1693*25cf1a30Sjl } 1694*25cf1a30Sjl 1695*25cf1a30Sjl int 1696*25cf1a30Sjl drmach_board_lookup(int bnum, drmachid_t *id) 1697*25cf1a30Sjl { 1698*25cf1a30Sjl int rv = 0; 1699*25cf1a30Sjl 1700*25cf1a30Sjl rw_enter(&drmach_boards_rwlock, RW_READER); 1701*25cf1a30Sjl if (drmach_array_get(drmach_boards, bnum, id)) { 1702*25cf1a30Sjl *id = 0; 1703*25cf1a30Sjl rv = -1; 1704*25cf1a30Sjl } 1705*25cf1a30Sjl rw_exit(&drmach_boards_rwlock); 1706*25cf1a30Sjl return (rv); 1707*25cf1a30Sjl } 1708*25cf1a30Sjl 1709*25cf1a30Sjl sbd_error_t * 1710*25cf1a30Sjl drmach_board_name(int bnum, char *buf, int buflen) 1711*25cf1a30Sjl { 1712*25cf1a30Sjl snprintf(buf, buflen, "SB%d", bnum); 1713*25cf1a30Sjl return (NULL); 1714*25cf1a30Sjl } 1715*25cf1a30Sjl 1716*25cf1a30Sjl sbd_error_t * 1717*25cf1a30Sjl drmach_board_poweroff(drmachid_t id) 1718*25cf1a30Sjl { 1719*25cf1a30Sjl drmach_board_t *bp; 1720*25cf1a30Sjl sbd_error_t *err; 1721*25cf1a30Sjl drmach_status_t stat; 1722*25cf1a30Sjl 1723*25cf1a30Sjl if (!DRMACH_IS_BOARD_ID(id)) 1724*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 1725*25cf1a30Sjl bp = id; 1726*25cf1a30Sjl 1727*25cf1a30Sjl err = drmach_board_status(id, &stat); 1728*25cf1a30Sjl 1729*25cf1a30Sjl if (!err) { 1730*25cf1a30Sjl if (stat.configured || stat.busy) 1731*25cf1a30Sjl err = drerr_new(0, EOPL_CONFIGBUSY, bp->cm.name); 1732*25cf1a30Sjl else { 1733*25cf1a30Sjl bp->powered = 0; 1734*25cf1a30Sjl } 1735*25cf1a30Sjl } 1736*25cf1a30Sjl return (err); 1737*25cf1a30Sjl } 1738*25cf1a30Sjl 1739*25cf1a30Sjl sbd_error_t * 1740*25cf1a30Sjl drmach_board_poweron(drmachid_t id) 1741*25cf1a30Sjl { 1742*25cf1a30Sjl drmach_board_t *bp; 1743*25cf1a30Sjl 1744*25cf1a30Sjl if (!DRMACH_IS_BOARD_ID(id)) 1745*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 1746*25cf1a30Sjl bp = id; 1747*25cf1a30Sjl 1748*25cf1a30Sjl bp->powered = 1; 1749*25cf1a30Sjl 1750*25cf1a30Sjl return (NULL); 1751*25cf1a30Sjl } 1752*25cf1a30Sjl 1753*25cf1a30Sjl static sbd_error_t * 1754*25cf1a30Sjl drmach_board_release(drmachid_t id) 1755*25cf1a30Sjl { 1756*25cf1a30Sjl if (!DRMACH_IS_BOARD_ID(id)) 1757*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 1758*25cf1a30Sjl return (NULL); 1759*25cf1a30Sjl } 1760*25cf1a30Sjl 1761*25cf1a30Sjl /*ARGSUSED*/ 1762*25cf1a30Sjl sbd_error_t * 1763*25cf1a30Sjl drmach_board_test(drmachid_t id, drmach_opts_t *opts, int force) 1764*25cf1a30Sjl { 1765*25cf1a30Sjl return (NULL); 1766*25cf1a30Sjl } 1767*25cf1a30Sjl 1768*25cf1a30Sjl sbd_error_t * 1769*25cf1a30Sjl drmach_board_unassign(drmachid_t id) 1770*25cf1a30Sjl { 1771*25cf1a30Sjl drmach_board_t *bp; 1772*25cf1a30Sjl sbd_error_t *err; 1773*25cf1a30Sjl drmach_status_t stat; 1774*25cf1a30Sjl 1775*25cf1a30Sjl 1776*25cf1a30Sjl if (!DRMACH_IS_BOARD_ID(id)) { 1777*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 1778*25cf1a30Sjl } 1779*25cf1a30Sjl bp = id; 1780*25cf1a30Sjl 1781*25cf1a30Sjl rw_enter(&drmach_boards_rwlock, RW_WRITER); 1782*25cf1a30Sjl 1783*25cf1a30Sjl err = drmach_board_status(id, &stat); 1784*25cf1a30Sjl if (err) { 1785*25cf1a30Sjl rw_exit(&drmach_boards_rwlock); 1786*25cf1a30Sjl return (err); 1787*25cf1a30Sjl } 1788*25cf1a30Sjl if (stat.configured || stat.busy) { 1789*25cf1a30Sjl err = drerr_new(0, EOPL_CONFIGBUSY, bp->cm.name); 1790*25cf1a30Sjl } else { 1791*25cf1a30Sjl if (drmach_array_set(drmach_boards, bp->bnum, 0) != 0) 1792*25cf1a30Sjl err = DRMACH_INTERNAL_ERROR(); 1793*25cf1a30Sjl else 1794*25cf1a30Sjl drmach_board_dispose(bp); 1795*25cf1a30Sjl } 1796*25cf1a30Sjl rw_exit(&drmach_boards_rwlock); 1797*25cf1a30Sjl return (err); 1798*25cf1a30Sjl } 1799*25cf1a30Sjl 1800*25cf1a30Sjl /* 1801*25cf1a30Sjl * We have to do more on OPL - e.g. set up sram tte, read cpuid, strand id, 1802*25cf1a30Sjl * implementation #, etc 1803*25cf1a30Sjl */ 1804*25cf1a30Sjl 1805*25cf1a30Sjl static sbd_error_t * 1806*25cf1a30Sjl drmach_cpu_new(drmach_device_t *proto, drmachid_t *idp) 1807*25cf1a30Sjl { 1808*25cf1a30Sjl static void drmach_cpu_dispose(drmachid_t); 1809*25cf1a30Sjl static sbd_error_t *drmach_cpu_release(drmachid_t); 1810*25cf1a30Sjl static sbd_error_t *drmach_cpu_status(drmachid_t, drmach_status_t *); 1811*25cf1a30Sjl 1812*25cf1a30Sjl int portid; 1813*25cf1a30Sjl drmach_cpu_t *cp = NULL; 1814*25cf1a30Sjl 1815*25cf1a30Sjl /* portid is CPUID of the node */ 1816*25cf1a30Sjl portid = proto->portid; 1817*25cf1a30Sjl ASSERT(portid != -1); 1818*25cf1a30Sjl 1819*25cf1a30Sjl /* unum = (CMP/CHIP ID) + (ON_BOARD_CORE_NUM * MAX_CMPID_PER_BOARD) */ 1820*25cf1a30Sjl proto->unum = ((portid/OPL_MAX_CPUID_PER_CMP) & 1821*25cf1a30Sjl (OPL_MAX_CMPID_PER_BOARD - 1)) + 1822*25cf1a30Sjl ((portid & (OPL_MAX_CPUID_PER_CMP - 1)) * 1823*25cf1a30Sjl (OPL_MAX_CMPID_PER_BOARD)); 1824*25cf1a30Sjl 1825*25cf1a30Sjl cp = kmem_zalloc(sizeof (drmach_cpu_t), KM_SLEEP); 1826*25cf1a30Sjl bcopy(proto, &cp->dev, sizeof (cp->dev)); 1827*25cf1a30Sjl cp->dev.node = drmach_node_dup(proto->node); 1828*25cf1a30Sjl cp->dev.cm.isa = (void *)drmach_cpu_new; 1829*25cf1a30Sjl cp->dev.cm.dispose = drmach_cpu_dispose; 1830*25cf1a30Sjl cp->dev.cm.release = drmach_cpu_release; 1831*25cf1a30Sjl cp->dev.cm.status = drmach_cpu_status; 1832*25cf1a30Sjl 1833*25cf1a30Sjl snprintf(cp->dev.cm.name, sizeof (cp->dev.cm.name), "%s%d", 1834*25cf1a30Sjl cp->dev.type, cp->dev.unum); 1835*25cf1a30Sjl 1836*25cf1a30Sjl /* 1837*25cf1a30Sjl * CPU ID representation 1838*25cf1a30Sjl * CPUID[9:5] = SB# 1839*25cf1a30Sjl * CPUID[4:3] = Chip# 1840*25cf1a30Sjl * CPUID[2:1] = Core# (Only 2 core for OPL) 1841*25cf1a30Sjl * CPUID[0:0] = Strand# 1842*25cf1a30Sjl */ 1843*25cf1a30Sjl 1844*25cf1a30Sjl /* 1845*25cf1a30Sjl * reg property of the strand contains strand ID 1846*25cf1a30Sjl * reg property of the parent node contains core ID 1847*25cf1a30Sjl * We should use them. 1848*25cf1a30Sjl */ 1849*25cf1a30Sjl cp->cpuid = portid; 1850*25cf1a30Sjl cp->sb = (portid >> 5) & 0x1f; 1851*25cf1a30Sjl cp->chipid = (portid >> 3) & 0x3; 1852*25cf1a30Sjl cp->coreid = (portid >> 1) & 0x3; 1853*25cf1a30Sjl cp->strandid = portid & 0x1; 1854*25cf1a30Sjl 1855*25cf1a30Sjl *idp = (drmachid_t)cp; 1856*25cf1a30Sjl return (NULL); 1857*25cf1a30Sjl } 1858*25cf1a30Sjl 1859*25cf1a30Sjl 1860*25cf1a30Sjl static void 1861*25cf1a30Sjl drmach_cpu_dispose(drmachid_t id) 1862*25cf1a30Sjl { 1863*25cf1a30Sjl drmach_cpu_t *self; 1864*25cf1a30Sjl 1865*25cf1a30Sjl ASSERT(DRMACH_IS_CPU_ID(id)); 1866*25cf1a30Sjl 1867*25cf1a30Sjl self = id; 1868*25cf1a30Sjl if (self->dev.node) 1869*25cf1a30Sjl drmach_node_dispose(self->dev.node); 1870*25cf1a30Sjl 1871*25cf1a30Sjl kmem_free(self, sizeof (*self)); 1872*25cf1a30Sjl } 1873*25cf1a30Sjl 1874*25cf1a30Sjl static int 1875*25cf1a30Sjl drmach_cpu_start(struct cpu *cp) 1876*25cf1a30Sjl { 1877*25cf1a30Sjl int cpuid = cp->cpu_id; 1878*25cf1a30Sjl extern int restart_other_cpu(int); 1879*25cf1a30Sjl 1880*25cf1a30Sjl ASSERT(MUTEX_HELD(&cpu_lock)); 1881*25cf1a30Sjl ASSERT(cpunodes[cpuid].nodeid != (pnode_t)0); 1882*25cf1a30Sjl 1883*25cf1a30Sjl cp->cpu_flags &= ~CPU_POWEROFF; 1884*25cf1a30Sjl 1885*25cf1a30Sjl /* 1886*25cf1a30Sjl * NOTE: restart_other_cpu pauses cpus during the 1887*25cf1a30Sjl * slave cpu start. This helps to quiesce the 1888*25cf1a30Sjl * bus traffic a bit which makes the tick sync 1889*25cf1a30Sjl * routine in the prom more robust. 1890*25cf1a30Sjl */ 1891*25cf1a30Sjl DRMACH_PR("COLD START for cpu (%d)\n", cpuid); 1892*25cf1a30Sjl 1893*25cf1a30Sjl restart_other_cpu(cpuid); 1894*25cf1a30Sjl 1895*25cf1a30Sjl return (0); 1896*25cf1a30Sjl } 1897*25cf1a30Sjl 1898*25cf1a30Sjl static sbd_error_t * 1899*25cf1a30Sjl drmach_cpu_release(drmachid_t id) 1900*25cf1a30Sjl { 1901*25cf1a30Sjl if (!DRMACH_IS_CPU_ID(id)) 1902*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 1903*25cf1a30Sjl 1904*25cf1a30Sjl return (NULL); 1905*25cf1a30Sjl } 1906*25cf1a30Sjl 1907*25cf1a30Sjl static sbd_error_t * 1908*25cf1a30Sjl drmach_cpu_status(drmachid_t id, drmach_status_t *stat) 1909*25cf1a30Sjl { 1910*25cf1a30Sjl drmach_cpu_t *cp; 1911*25cf1a30Sjl drmach_device_t *dp; 1912*25cf1a30Sjl 1913*25cf1a30Sjl ASSERT(DRMACH_IS_CPU_ID(id)); 1914*25cf1a30Sjl cp = (drmach_cpu_t *)id; 1915*25cf1a30Sjl dp = &cp->dev; 1916*25cf1a30Sjl 1917*25cf1a30Sjl stat->assigned = dp->bp->assigned; 1918*25cf1a30Sjl stat->powered = dp->bp->powered; 1919*25cf1a30Sjl mutex_enter(&cpu_lock); 1920*25cf1a30Sjl stat->configured = (cpu_get(cp->cpuid) != NULL); 1921*25cf1a30Sjl mutex_exit(&cpu_lock); 1922*25cf1a30Sjl stat->busy = dp->busy; 1923*25cf1a30Sjl strncpy(stat->type, dp->type, sizeof (stat->type)); 1924*25cf1a30Sjl stat->info[0] = '\0'; 1925*25cf1a30Sjl 1926*25cf1a30Sjl return (NULL); 1927*25cf1a30Sjl } 1928*25cf1a30Sjl 1929*25cf1a30Sjl sbd_error_t * 1930*25cf1a30Sjl drmach_cpu_disconnect(drmachid_t id) 1931*25cf1a30Sjl { 1932*25cf1a30Sjl 1933*25cf1a30Sjl if (!DRMACH_IS_CPU_ID(id)) 1934*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 1935*25cf1a30Sjl 1936*25cf1a30Sjl return (NULL); 1937*25cf1a30Sjl } 1938*25cf1a30Sjl 1939*25cf1a30Sjl sbd_error_t * 1940*25cf1a30Sjl drmach_cpu_get_id(drmachid_t id, processorid_t *cpuid) 1941*25cf1a30Sjl { 1942*25cf1a30Sjl drmach_cpu_t *cpu; 1943*25cf1a30Sjl 1944*25cf1a30Sjl if (!DRMACH_IS_CPU_ID(id)) 1945*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 1946*25cf1a30Sjl cpu = (drmach_cpu_t *)id; 1947*25cf1a30Sjl 1948*25cf1a30Sjl /* get from cpu directly on OPL */ 1949*25cf1a30Sjl *cpuid = cpu->cpuid; 1950*25cf1a30Sjl return (NULL); 1951*25cf1a30Sjl } 1952*25cf1a30Sjl 1953*25cf1a30Sjl sbd_error_t * 1954*25cf1a30Sjl drmach_cpu_get_impl(drmachid_t id, int *ip) 1955*25cf1a30Sjl { 1956*25cf1a30Sjl drmach_device_t *cpu; 1957*25cf1a30Sjl drmach_node_t *np; 1958*25cf1a30Sjl drmach_node_t pp; 1959*25cf1a30Sjl int impl; 1960*25cf1a30Sjl char type[OBP_MAXPROPNAME]; 1961*25cf1a30Sjl 1962*25cf1a30Sjl if (!DRMACH_IS_CPU_ID(id)) 1963*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 1964*25cf1a30Sjl 1965*25cf1a30Sjl cpu = id; 1966*25cf1a30Sjl np = cpu->node; 1967*25cf1a30Sjl 1968*25cf1a30Sjl if (np->get_parent(np, &pp) != 0) { 1969*25cf1a30Sjl return (DRMACH_INTERNAL_ERROR()); 1970*25cf1a30Sjl } 1971*25cf1a30Sjl 1972*25cf1a30Sjl /* the parent should be core */ 1973*25cf1a30Sjl 1974*25cf1a30Sjl if (pp.n_getprop(&pp, "device_type", &type, sizeof (type)) != 0) { 1975*25cf1a30Sjl return (drerr_new(0, EOPL_GETPROP, NULL)); 1976*25cf1a30Sjl } 1977*25cf1a30Sjl 1978*25cf1a30Sjl if (strcmp(type, OPL_CORE_NODE) == 0) { 1979*25cf1a30Sjl if (pp.n_getprop(&pp, "implementation#", 1980*25cf1a30Sjl &impl, sizeof (impl)) != 0) { 1981*25cf1a30Sjl return (drerr_new(0, EOPL_GETPROP, NULL)); 1982*25cf1a30Sjl } 1983*25cf1a30Sjl } else { 1984*25cf1a30Sjl return (DRMACH_INTERNAL_ERROR()); 1985*25cf1a30Sjl } 1986*25cf1a30Sjl 1987*25cf1a30Sjl *ip = impl; 1988*25cf1a30Sjl 1989*25cf1a30Sjl return (NULL); 1990*25cf1a30Sjl } 1991*25cf1a30Sjl 1992*25cf1a30Sjl sbd_error_t * 1993*25cf1a30Sjl drmach_get_dip(drmachid_t id, dev_info_t **dip) 1994*25cf1a30Sjl { 1995*25cf1a30Sjl drmach_device_t *dp; 1996*25cf1a30Sjl 1997*25cf1a30Sjl if (!DRMACH_IS_DEVICE_ID(id)) 1998*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 1999*25cf1a30Sjl dp = id; 2000*25cf1a30Sjl 2001*25cf1a30Sjl *dip = dp->node->n_getdip(dp->node); 2002*25cf1a30Sjl return (NULL); 2003*25cf1a30Sjl } 2004*25cf1a30Sjl 2005*25cf1a30Sjl sbd_error_t * 2006*25cf1a30Sjl drmach_io_is_attached(drmachid_t id, int *yes) 2007*25cf1a30Sjl { 2008*25cf1a30Sjl drmach_device_t *dp; 2009*25cf1a30Sjl dev_info_t *dip; 2010*25cf1a30Sjl int state; 2011*25cf1a30Sjl 2012*25cf1a30Sjl if (!DRMACH_IS_IO_ID(id)) 2013*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2014*25cf1a30Sjl dp = id; 2015*25cf1a30Sjl 2016*25cf1a30Sjl dip = dp->node->n_getdip(dp->node); 2017*25cf1a30Sjl if (dip == NULL) { 2018*25cf1a30Sjl *yes = 0; 2019*25cf1a30Sjl return (NULL); 2020*25cf1a30Sjl } 2021*25cf1a30Sjl 2022*25cf1a30Sjl state = ddi_get_devstate(dip); 2023*25cf1a30Sjl *yes = ((i_ddi_node_state(dip) >= DS_ATTACHED) || 2024*25cf1a30Sjl (state == DDI_DEVSTATE_UP)); 2025*25cf1a30Sjl 2026*25cf1a30Sjl return (NULL); 2027*25cf1a30Sjl } 2028*25cf1a30Sjl 2029*25cf1a30Sjl struct drmach_io_cb { 2030*25cf1a30Sjl char *name; /* name of the node */ 2031*25cf1a30Sjl int (*func)(dev_info_t *); 2032*25cf1a30Sjl int rv; 2033*25cf1a30Sjl }; 2034*25cf1a30Sjl 2035*25cf1a30Sjl #define DRMACH_IO_POST_ATTACH 0 2036*25cf1a30Sjl #define DRMACH_IO_PRE_RELEASE 1 2037*25cf1a30Sjl 2038*25cf1a30Sjl static int 2039*25cf1a30Sjl drmach_io_cb_check(dev_info_t *dip, void *arg) 2040*25cf1a30Sjl { 2041*25cf1a30Sjl struct drmach_io_cb *p = (struct drmach_io_cb *)arg; 2042*25cf1a30Sjl char name[OBP_MAXDRVNAME]; 2043*25cf1a30Sjl int len = OBP_MAXDRVNAME; 2044*25cf1a30Sjl 2045*25cf1a30Sjl if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 2046*25cf1a30Sjl DDI_PROP_DONTPASS, "name", 2047*25cf1a30Sjl (caddr_t)name, &len) != DDI_PROP_SUCCESS) { 2048*25cf1a30Sjl return (DDI_WALK_PRUNECHILD); 2049*25cf1a30Sjl } 2050*25cf1a30Sjl 2051*25cf1a30Sjl if (strcmp(name, p->name) == 0) { 2052*25cf1a30Sjl p->rv = (*p->func)(dip); 2053*25cf1a30Sjl return (DDI_WALK_TERMINATE); 2054*25cf1a30Sjl } 2055*25cf1a30Sjl 2056*25cf1a30Sjl return (DDI_WALK_CONTINUE); 2057*25cf1a30Sjl } 2058*25cf1a30Sjl 2059*25cf1a30Sjl 2060*25cf1a30Sjl static int 2061*25cf1a30Sjl drmach_console_ops(drmachid_t *id, int state) 2062*25cf1a30Sjl { 2063*25cf1a30Sjl drmach_io_t *obj = (drmach_io_t *)id; 2064*25cf1a30Sjl struct drmach_io_cb arg; 2065*25cf1a30Sjl int (*msudetp)(dev_info_t *); 2066*25cf1a30Sjl int (*msuattp)(dev_info_t *); 2067*25cf1a30Sjl dev_info_t *dip, *pdip; 2068*25cf1a30Sjl int circ; 2069*25cf1a30Sjl 2070*25cf1a30Sjl /* 4 is pcicmu channel */ 2071*25cf1a30Sjl if (obj->channel != 4) 2072*25cf1a30Sjl return (0); 2073*25cf1a30Sjl 2074*25cf1a30Sjl arg.name = "serial"; 2075*25cf1a30Sjl arg.func = NULL; 2076*25cf1a30Sjl if (state == DRMACH_IO_PRE_RELEASE) { 2077*25cf1a30Sjl msudetp = (int (*)(dev_info_t *)) 2078*25cf1a30Sjl modgetsymvalue("oplmsu_dr_detach", 0); 2079*25cf1a30Sjl if (msudetp != NULL) 2080*25cf1a30Sjl arg.func = msudetp; 2081*25cf1a30Sjl } else if (state == DRMACH_IO_POST_ATTACH) { 2082*25cf1a30Sjl msuattp = (int (*)(dev_info_t *)) 2083*25cf1a30Sjl modgetsymvalue("oplmsu_dr_attach", 0); 2084*25cf1a30Sjl if (msuattp != NULL) 2085*25cf1a30Sjl arg.func = msuattp; 2086*25cf1a30Sjl } 2087*25cf1a30Sjl else 2088*25cf1a30Sjl return (0); 2089*25cf1a30Sjl 2090*25cf1a30Sjl if (arg.func == NULL) { 2091*25cf1a30Sjl return (0); 2092*25cf1a30Sjl } 2093*25cf1a30Sjl 2094*25cf1a30Sjl arg.rv = 0; 2095*25cf1a30Sjl 2096*25cf1a30Sjl dip = obj->dev.node->n_getdip(obj->dev.node); 2097*25cf1a30Sjl if (pdip = ddi_get_parent(dip)) { 2098*25cf1a30Sjl ndi_hold_devi(pdip); 2099*25cf1a30Sjl ndi_devi_enter(pdip, &circ); 2100*25cf1a30Sjl } else { 2101*25cf1a30Sjl /* this cannot happen unless something bad happens */ 2102*25cf1a30Sjl return (-1); 2103*25cf1a30Sjl } 2104*25cf1a30Sjl 2105*25cf1a30Sjl ddi_walk_devs(dip, drmach_io_cb_check, (void *)&arg); 2106*25cf1a30Sjl 2107*25cf1a30Sjl if (pdip) { 2108*25cf1a30Sjl ndi_devi_exit(pdip, circ); 2109*25cf1a30Sjl ndi_rele_devi(pdip); 2110*25cf1a30Sjl } 2111*25cf1a30Sjl 2112*25cf1a30Sjl return (arg.rv); 2113*25cf1a30Sjl } 2114*25cf1a30Sjl 2115*25cf1a30Sjl sbd_error_t * 2116*25cf1a30Sjl drmach_io_pre_release(drmachid_t id) 2117*25cf1a30Sjl { 2118*25cf1a30Sjl int rv; 2119*25cf1a30Sjl 2120*25cf1a30Sjl if (!DRMACH_IS_IO_ID(id)) 2121*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2122*25cf1a30Sjl 2123*25cf1a30Sjl rv = drmach_console_ops(id, DRMACH_IO_PRE_RELEASE); 2124*25cf1a30Sjl 2125*25cf1a30Sjl if (rv != 0) 2126*25cf1a30Sjl cmn_err(CE_WARN, "IO callback failed in pre-release\n"); 2127*25cf1a30Sjl 2128*25cf1a30Sjl return (NULL); 2129*25cf1a30Sjl } 2130*25cf1a30Sjl 2131*25cf1a30Sjl static sbd_error_t * 2132*25cf1a30Sjl drmach_io_release(drmachid_t id) 2133*25cf1a30Sjl { 2134*25cf1a30Sjl if (!DRMACH_IS_IO_ID(id)) 2135*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2136*25cf1a30Sjl return (NULL); 2137*25cf1a30Sjl } 2138*25cf1a30Sjl 2139*25cf1a30Sjl sbd_error_t * 2140*25cf1a30Sjl drmach_io_unrelease(drmachid_t id) 2141*25cf1a30Sjl { 2142*25cf1a30Sjl if (!DRMACH_IS_IO_ID(id)) 2143*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2144*25cf1a30Sjl return (NULL); 2145*25cf1a30Sjl } 2146*25cf1a30Sjl 2147*25cf1a30Sjl /*ARGSUSED*/ 2148*25cf1a30Sjl sbd_error_t * 2149*25cf1a30Sjl drmach_io_post_release(drmachid_t id) 2150*25cf1a30Sjl { 2151*25cf1a30Sjl return (NULL); 2152*25cf1a30Sjl } 2153*25cf1a30Sjl 2154*25cf1a30Sjl /*ARGSUSED*/ 2155*25cf1a30Sjl sbd_error_t * 2156*25cf1a30Sjl drmach_io_post_attach(drmachid_t id) 2157*25cf1a30Sjl { 2158*25cf1a30Sjl int rv; 2159*25cf1a30Sjl 2160*25cf1a30Sjl if (!DRMACH_IS_IO_ID(id)) 2161*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2162*25cf1a30Sjl 2163*25cf1a30Sjl rv = drmach_console_ops(id, DRMACH_IO_POST_ATTACH); 2164*25cf1a30Sjl 2165*25cf1a30Sjl if (rv != 0) 2166*25cf1a30Sjl cmn_err(CE_WARN, "IO callback failed in post-attach\n"); 2167*25cf1a30Sjl 2168*25cf1a30Sjl return (0); 2169*25cf1a30Sjl } 2170*25cf1a30Sjl 2171*25cf1a30Sjl static sbd_error_t * 2172*25cf1a30Sjl drmach_io_status(drmachid_t id, drmach_status_t *stat) 2173*25cf1a30Sjl { 2174*25cf1a30Sjl drmach_device_t *dp; 2175*25cf1a30Sjl sbd_error_t *err; 2176*25cf1a30Sjl int configured; 2177*25cf1a30Sjl 2178*25cf1a30Sjl ASSERT(DRMACH_IS_IO_ID(id)); 2179*25cf1a30Sjl dp = id; 2180*25cf1a30Sjl 2181*25cf1a30Sjl err = drmach_io_is_attached(id, &configured); 2182*25cf1a30Sjl if (err) 2183*25cf1a30Sjl return (err); 2184*25cf1a30Sjl 2185*25cf1a30Sjl stat->assigned = dp->bp->assigned; 2186*25cf1a30Sjl stat->powered = dp->bp->powered; 2187*25cf1a30Sjl stat->configured = (configured != 0); 2188*25cf1a30Sjl stat->busy = dp->busy; 2189*25cf1a30Sjl strncpy(stat->type, dp->type, sizeof (stat->type)); 2190*25cf1a30Sjl stat->info[0] = '\0'; 2191*25cf1a30Sjl 2192*25cf1a30Sjl return (NULL); 2193*25cf1a30Sjl } 2194*25cf1a30Sjl 2195*25cf1a30Sjl static sbd_error_t * 2196*25cf1a30Sjl drmach_mem_new(drmach_device_t *proto, drmachid_t *idp) 2197*25cf1a30Sjl { 2198*25cf1a30Sjl static void drmach_mem_dispose(drmachid_t); 2199*25cf1a30Sjl static sbd_error_t *drmach_mem_release(drmachid_t); 2200*25cf1a30Sjl static sbd_error_t *drmach_mem_status(drmachid_t, drmach_status_t *); 2201*25cf1a30Sjl dev_info_t *dip; 2202*25cf1a30Sjl 2203*25cf1a30Sjl drmach_mem_t *mp; 2204*25cf1a30Sjl 2205*25cf1a30Sjl mp = kmem_zalloc(sizeof (drmach_mem_t), KM_SLEEP); 2206*25cf1a30Sjl proto->unum = 0; 2207*25cf1a30Sjl 2208*25cf1a30Sjl bcopy(proto, &mp->dev, sizeof (mp->dev)); 2209*25cf1a30Sjl mp->dev.node = drmach_node_dup(proto->node); 2210*25cf1a30Sjl mp->dev.cm.isa = (void *)drmach_mem_new; 2211*25cf1a30Sjl mp->dev.cm.dispose = drmach_mem_dispose; 2212*25cf1a30Sjl mp->dev.cm.release = drmach_mem_release; 2213*25cf1a30Sjl mp->dev.cm.status = drmach_mem_status; 2214*25cf1a30Sjl 2215*25cf1a30Sjl snprintf(mp->dev.cm.name, 2216*25cf1a30Sjl sizeof (mp->dev.cm.name), "%s", mp->dev.type); 2217*25cf1a30Sjl 2218*25cf1a30Sjl dip = mp->dev.node->n_getdip(mp->dev.node); 2219*25cf1a30Sjl if (drmach_setup_mc_info(dip, mp) != 0) { 2220*25cf1a30Sjl return (DRMACH_INTERNAL_ERROR()); 2221*25cf1a30Sjl } 2222*25cf1a30Sjl 2223*25cf1a30Sjl *idp = (drmachid_t)mp; 2224*25cf1a30Sjl return (NULL); 2225*25cf1a30Sjl } 2226*25cf1a30Sjl 2227*25cf1a30Sjl static void 2228*25cf1a30Sjl drmach_mem_dispose(drmachid_t id) 2229*25cf1a30Sjl { 2230*25cf1a30Sjl drmach_mem_t *mp; 2231*25cf1a30Sjl 2232*25cf1a30Sjl ASSERT(DRMACH_IS_MEM_ID(id)); 2233*25cf1a30Sjl 2234*25cf1a30Sjl 2235*25cf1a30Sjl mp = id; 2236*25cf1a30Sjl 2237*25cf1a30Sjl if (mp->dev.node) 2238*25cf1a30Sjl drmach_node_dispose(mp->dev.node); 2239*25cf1a30Sjl 2240*25cf1a30Sjl if (mp->memlist) { 2241*25cf1a30Sjl memlist_delete(mp->memlist); 2242*25cf1a30Sjl mp->memlist = NULL; 2243*25cf1a30Sjl } 2244*25cf1a30Sjl } 2245*25cf1a30Sjl 2246*25cf1a30Sjl sbd_error_t * 2247*25cf1a30Sjl drmach_mem_add_span(drmachid_t id, uint64_t basepa, uint64_t size) 2248*25cf1a30Sjl { 2249*25cf1a30Sjl pfn_t basepfn = (pfn_t)(basepa >> PAGESHIFT); 2250*25cf1a30Sjl pgcnt_t npages = (pgcnt_t)(size >> PAGESHIFT); 2251*25cf1a30Sjl int rv; 2252*25cf1a30Sjl 2253*25cf1a30Sjl ASSERT(size != 0); 2254*25cf1a30Sjl 2255*25cf1a30Sjl if (!DRMACH_IS_MEM_ID(id)) 2256*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2257*25cf1a30Sjl 2258*25cf1a30Sjl kcage_range_lock(); 2259*25cf1a30Sjl rv = kcage_range_add(basepfn, npages, 1); 2260*25cf1a30Sjl kcage_range_unlock(); 2261*25cf1a30Sjl if (rv == ENOMEM) { 2262*25cf1a30Sjl cmn_err(CE_WARN, "%ld megabytes not available to kernel cage", 2263*25cf1a30Sjl (size == 0 ? 0 : size / MBYTE)); 2264*25cf1a30Sjl } else if (rv != 0) { 2265*25cf1a30Sjl /* catch this in debug kernels */ 2266*25cf1a30Sjl ASSERT(0); 2267*25cf1a30Sjl 2268*25cf1a30Sjl cmn_err(CE_WARN, "unexpected kcage_range_add" 2269*25cf1a30Sjl " return value %d", rv); 2270*25cf1a30Sjl } 2271*25cf1a30Sjl 2272*25cf1a30Sjl if (rv) { 2273*25cf1a30Sjl return (DRMACH_INTERNAL_ERROR()); 2274*25cf1a30Sjl } 2275*25cf1a30Sjl else 2276*25cf1a30Sjl return (NULL); 2277*25cf1a30Sjl } 2278*25cf1a30Sjl 2279*25cf1a30Sjl sbd_error_t * 2280*25cf1a30Sjl drmach_mem_del_span(drmachid_t id, uint64_t basepa, uint64_t size) 2281*25cf1a30Sjl { 2282*25cf1a30Sjl pfn_t basepfn = (pfn_t)(basepa >> PAGESHIFT); 2283*25cf1a30Sjl pgcnt_t npages = (pgcnt_t)(size >> PAGESHIFT); 2284*25cf1a30Sjl int rv; 2285*25cf1a30Sjl 2286*25cf1a30Sjl if (!DRMACH_IS_MEM_ID(id)) 2287*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2288*25cf1a30Sjl 2289*25cf1a30Sjl if (size > 0) { 2290*25cf1a30Sjl kcage_range_lock(); 2291*25cf1a30Sjl rv = kcage_range_delete_post_mem_del(basepfn, npages); 2292*25cf1a30Sjl kcage_range_unlock(); 2293*25cf1a30Sjl if (rv != 0) { 2294*25cf1a30Sjl cmn_err(CE_WARN, 2295*25cf1a30Sjl "unexpected kcage_range_delete_post_mem_del" 2296*25cf1a30Sjl " return value %d", rv); 2297*25cf1a30Sjl return (DRMACH_INTERNAL_ERROR()); 2298*25cf1a30Sjl } 2299*25cf1a30Sjl } 2300*25cf1a30Sjl 2301*25cf1a30Sjl return (NULL); 2302*25cf1a30Sjl } 2303*25cf1a30Sjl 2304*25cf1a30Sjl sbd_error_t * 2305*25cf1a30Sjl drmach_mem_disable(drmachid_t id) 2306*25cf1a30Sjl { 2307*25cf1a30Sjl if (!DRMACH_IS_MEM_ID(id)) 2308*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2309*25cf1a30Sjl else { 2310*25cf1a30Sjl drmach_flush_all(); 2311*25cf1a30Sjl return (NULL); 2312*25cf1a30Sjl } 2313*25cf1a30Sjl } 2314*25cf1a30Sjl 2315*25cf1a30Sjl sbd_error_t * 2316*25cf1a30Sjl drmach_mem_enable(drmachid_t id) 2317*25cf1a30Sjl { 2318*25cf1a30Sjl if (!DRMACH_IS_MEM_ID(id)) 2319*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2320*25cf1a30Sjl else 2321*25cf1a30Sjl return (NULL); 2322*25cf1a30Sjl } 2323*25cf1a30Sjl 2324*25cf1a30Sjl sbd_error_t * 2325*25cf1a30Sjl drmach_mem_get_info(drmachid_t id, drmach_mem_info_t *mem) 2326*25cf1a30Sjl { 2327*25cf1a30Sjl drmach_mem_t *mp; 2328*25cf1a30Sjl 2329*25cf1a30Sjl if (!DRMACH_IS_MEM_ID(id)) 2330*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2331*25cf1a30Sjl 2332*25cf1a30Sjl mp = (drmach_mem_t *)id; 2333*25cf1a30Sjl 2334*25cf1a30Sjl /* 2335*25cf1a30Sjl * This is only used by dr to round up/down the memory 2336*25cf1a30Sjl * for copying. Our unit of memory isolation is 64 MB. 2337*25cf1a30Sjl */ 2338*25cf1a30Sjl 2339*25cf1a30Sjl mem->mi_alignment_mask = (64 * 1024 * 1024 - 1); 2340*25cf1a30Sjl mem->mi_basepa = mp->base_pa; 2341*25cf1a30Sjl mem->mi_size = mp->nbytes; 2342*25cf1a30Sjl mem->mi_slice_size = mp->slice_size; 2343*25cf1a30Sjl 2344*25cf1a30Sjl return (NULL); 2345*25cf1a30Sjl } 2346*25cf1a30Sjl 2347*25cf1a30Sjl sbd_error_t * 2348*25cf1a30Sjl drmach_mem_get_base_physaddr(drmachid_t id, uint64_t *pa) 2349*25cf1a30Sjl { 2350*25cf1a30Sjl drmach_mem_t *mp; 2351*25cf1a30Sjl 2352*25cf1a30Sjl if (!DRMACH_IS_MEM_ID(id)) 2353*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2354*25cf1a30Sjl 2355*25cf1a30Sjl mp = (drmach_mem_t *)id; 2356*25cf1a30Sjl 2357*25cf1a30Sjl *pa = mp->base_pa; 2358*25cf1a30Sjl return (NULL); 2359*25cf1a30Sjl } 2360*25cf1a30Sjl 2361*25cf1a30Sjl sbd_error_t * 2362*25cf1a30Sjl drmach_mem_get_memlist(drmachid_t id, struct memlist **ml) 2363*25cf1a30Sjl { 2364*25cf1a30Sjl drmach_mem_t *mem; 2365*25cf1a30Sjl int rv; 2366*25cf1a30Sjl struct memlist *mlist; 2367*25cf1a30Sjl 2368*25cf1a30Sjl if (!DRMACH_IS_MEM_ID(id)) 2369*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2370*25cf1a30Sjl 2371*25cf1a30Sjl mem = (drmach_mem_t *)id; 2372*25cf1a30Sjl mlist = memlist_dup(mem->memlist); 2373*25cf1a30Sjl 2374*25cf1a30Sjl #ifdef DEBUG 2375*25cf1a30Sjl /* 2376*25cf1a30Sjl * Make sure the incoming memlist doesn't already 2377*25cf1a30Sjl * intersect with what's present in the system (phys_install). 2378*25cf1a30Sjl */ 2379*25cf1a30Sjl memlist_read_lock(); 2380*25cf1a30Sjl rv = memlist_intersect(phys_install, mlist); 2381*25cf1a30Sjl memlist_read_unlock(); 2382*25cf1a30Sjl if (rv) { 2383*25cf1a30Sjl DRMACH_PR("Derived memlist intersects" 2384*25cf1a30Sjl " with phys_install\n"); 2385*25cf1a30Sjl memlist_dump(mlist); 2386*25cf1a30Sjl 2387*25cf1a30Sjl DRMACH_PR("phys_install memlist:\n"); 2388*25cf1a30Sjl memlist_dump(phys_install); 2389*25cf1a30Sjl 2390*25cf1a30Sjl memlist_delete(mlist); 2391*25cf1a30Sjl return (DRMACH_INTERNAL_ERROR()); 2392*25cf1a30Sjl } 2393*25cf1a30Sjl 2394*25cf1a30Sjl DRMACH_PR("Derived memlist:"); 2395*25cf1a30Sjl memlist_dump(mlist); 2396*25cf1a30Sjl #endif 2397*25cf1a30Sjl 2398*25cf1a30Sjl *ml = mlist; 2399*25cf1a30Sjl 2400*25cf1a30Sjl return (NULL); 2401*25cf1a30Sjl } 2402*25cf1a30Sjl 2403*25cf1a30Sjl sbd_error_t * 2404*25cf1a30Sjl drmach_mem_get_slice_size(drmachid_t id, uint64_t *bytes) 2405*25cf1a30Sjl { 2406*25cf1a30Sjl drmach_mem_t *mem; 2407*25cf1a30Sjl 2408*25cf1a30Sjl if (!DRMACH_IS_MEM_ID(id)) 2409*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2410*25cf1a30Sjl 2411*25cf1a30Sjl mem = (drmach_mem_t *)id; 2412*25cf1a30Sjl 2413*25cf1a30Sjl *bytes = mem->slice_size; 2414*25cf1a30Sjl 2415*25cf1a30Sjl return (NULL); 2416*25cf1a30Sjl } 2417*25cf1a30Sjl 2418*25cf1a30Sjl 2419*25cf1a30Sjl /* ARGSUSED */ 2420*25cf1a30Sjl processorid_t 2421*25cf1a30Sjl drmach_mem_cpu_affinity(drmachid_t id) 2422*25cf1a30Sjl { 2423*25cf1a30Sjl return (CPU_CURRENT); 2424*25cf1a30Sjl } 2425*25cf1a30Sjl 2426*25cf1a30Sjl static sbd_error_t * 2427*25cf1a30Sjl drmach_mem_release(drmachid_t id) 2428*25cf1a30Sjl { 2429*25cf1a30Sjl if (!DRMACH_IS_MEM_ID(id)) 2430*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2431*25cf1a30Sjl return (NULL); 2432*25cf1a30Sjl } 2433*25cf1a30Sjl 2434*25cf1a30Sjl static sbd_error_t * 2435*25cf1a30Sjl drmach_mem_status(drmachid_t id, drmach_status_t *stat) 2436*25cf1a30Sjl { 2437*25cf1a30Sjl drmach_mem_t *dp; 2438*25cf1a30Sjl uint64_t pa, slice_size; 2439*25cf1a30Sjl struct memlist *ml; 2440*25cf1a30Sjl 2441*25cf1a30Sjl ASSERT(DRMACH_IS_MEM_ID(id)); 2442*25cf1a30Sjl dp = id; 2443*25cf1a30Sjl 2444*25cf1a30Sjl /* get starting physical address of target memory */ 2445*25cf1a30Sjl pa = dp->base_pa; 2446*25cf1a30Sjl 2447*25cf1a30Sjl /* round down to slice boundary */ 2448*25cf1a30Sjl slice_size = dp->slice_size; 2449*25cf1a30Sjl pa &= ~(slice_size - 1); 2450*25cf1a30Sjl 2451*25cf1a30Sjl /* stop at first span that is in slice */ 2452*25cf1a30Sjl memlist_read_lock(); 2453*25cf1a30Sjl for (ml = phys_install; ml; ml = ml->next) 2454*25cf1a30Sjl if (ml->address >= pa && ml->address < pa + slice_size) 2455*25cf1a30Sjl break; 2456*25cf1a30Sjl memlist_read_unlock(); 2457*25cf1a30Sjl 2458*25cf1a30Sjl stat->assigned = dp->dev.bp->assigned; 2459*25cf1a30Sjl stat->powered = dp->dev.bp->powered; 2460*25cf1a30Sjl stat->configured = (ml != NULL); 2461*25cf1a30Sjl stat->busy = dp->dev.busy; 2462*25cf1a30Sjl strncpy(stat->type, dp->dev.type, sizeof (stat->type)); 2463*25cf1a30Sjl stat->info[0] = '\0'; 2464*25cf1a30Sjl 2465*25cf1a30Sjl return (NULL); 2466*25cf1a30Sjl } 2467*25cf1a30Sjl 2468*25cf1a30Sjl 2469*25cf1a30Sjl sbd_error_t * 2470*25cf1a30Sjl drmach_board_deprobe(drmachid_t id) 2471*25cf1a30Sjl { 2472*25cf1a30Sjl drmach_board_t *bp; 2473*25cf1a30Sjl 2474*25cf1a30Sjl if (!DRMACH_IS_BOARD_ID(id)) 2475*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2476*25cf1a30Sjl 2477*25cf1a30Sjl bp = id; 2478*25cf1a30Sjl 2479*25cf1a30Sjl cmn_err(CE_CONT, "DR: PROM detach board %d\n", bp->bnum); 2480*25cf1a30Sjl 2481*25cf1a30Sjl if (bp->tree) { 2482*25cf1a30Sjl drmach_node_dispose(bp->tree); 2483*25cf1a30Sjl bp->tree = NULL; 2484*25cf1a30Sjl } 2485*25cf1a30Sjl if (bp->devices) { 2486*25cf1a30Sjl drmach_array_dispose(bp->devices, drmach_device_dispose); 2487*25cf1a30Sjl bp->devices = NULL; 2488*25cf1a30Sjl } 2489*25cf1a30Sjl 2490*25cf1a30Sjl bp->boot_board = 0; 2491*25cf1a30Sjl 2492*25cf1a30Sjl return (NULL); 2493*25cf1a30Sjl } 2494*25cf1a30Sjl 2495*25cf1a30Sjl /*ARGSUSED*/ 2496*25cf1a30Sjl static sbd_error_t * 2497*25cf1a30Sjl drmach_pt_ikprobe(drmachid_t id, drmach_opts_t *opts) 2498*25cf1a30Sjl { 2499*25cf1a30Sjl drmach_board_t *bp = (drmach_board_t *)id; 2500*25cf1a30Sjl sbd_error_t *err = NULL; 2501*25cf1a30Sjl int rv; 2502*25cf1a30Sjl 2503*25cf1a30Sjl if (!DRMACH_IS_BOARD_ID(id)) 2504*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2505*25cf1a30Sjl 2506*25cf1a30Sjl DRMACH_PR("calling opl_probe_board for bnum=%d\n", bp->bnum); 2507*25cf1a30Sjl rv = opl_probe_sb(bp->bnum); 2508*25cf1a30Sjl if (rv != 0) { 2509*25cf1a30Sjl err = drerr_new(0, EOPL_PROBE, bp->cm.name); 2510*25cf1a30Sjl return (err); 2511*25cf1a30Sjl } 2512*25cf1a30Sjl return (err); 2513*25cf1a30Sjl } 2514*25cf1a30Sjl 2515*25cf1a30Sjl /*ARGSUSED*/ 2516*25cf1a30Sjl static sbd_error_t * 2517*25cf1a30Sjl drmach_pt_ikdeprobe(drmachid_t id, drmach_opts_t *opts) 2518*25cf1a30Sjl { 2519*25cf1a30Sjl drmach_board_t *bp; 2520*25cf1a30Sjl sbd_error_t *err = NULL; 2521*25cf1a30Sjl int rv; 2522*25cf1a30Sjl 2523*25cf1a30Sjl if (!DRMACH_IS_BOARD_ID(id)) 2524*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2525*25cf1a30Sjl bp = (drmach_board_t *)id; 2526*25cf1a30Sjl 2527*25cf1a30Sjl cmn_err(CE_CONT, "DR: in-kernel unprobe board %d\n", bp->bnum); 2528*25cf1a30Sjl 2529*25cf1a30Sjl rv = opl_unprobe_sb(bp->bnum); 2530*25cf1a30Sjl if (rv != 0) { 2531*25cf1a30Sjl err = drerr_new(0, EOPL_DEPROBE, bp->cm.name); 2532*25cf1a30Sjl } 2533*25cf1a30Sjl 2534*25cf1a30Sjl return (err); 2535*25cf1a30Sjl } 2536*25cf1a30Sjl 2537*25cf1a30Sjl 2538*25cf1a30Sjl /*ARGSUSED*/ 2539*25cf1a30Sjl sbd_error_t * 2540*25cf1a30Sjl drmach_pt_readmem(drmachid_t id, drmach_opts_t *opts) 2541*25cf1a30Sjl { 2542*25cf1a30Sjl struct memlist *ml; 2543*25cf1a30Sjl uint64_t src_pa; 2544*25cf1a30Sjl uint64_t dst_pa; 2545*25cf1a30Sjl uint64_t dst; 2546*25cf1a30Sjl 2547*25cf1a30Sjl dst_pa = va_to_pa(&dst); 2548*25cf1a30Sjl 2549*25cf1a30Sjl memlist_read_lock(); 2550*25cf1a30Sjl for (ml = phys_install; ml; ml = ml->next) { 2551*25cf1a30Sjl uint64_t nbytes; 2552*25cf1a30Sjl 2553*25cf1a30Sjl src_pa = ml->address; 2554*25cf1a30Sjl nbytes = ml->size; 2555*25cf1a30Sjl 2556*25cf1a30Sjl while (nbytes != 0ull) { 2557*25cf1a30Sjl 2558*25cf1a30Sjl /* copy 32 bytes at arc_pa to dst_pa */ 2559*25cf1a30Sjl bcopy32_il(src_pa, dst_pa); 2560*25cf1a30Sjl 2561*25cf1a30Sjl /* increment by 32 bytes */ 2562*25cf1a30Sjl src_pa += (4 * sizeof (uint64_t)); 2563*25cf1a30Sjl 2564*25cf1a30Sjl /* decrement by 32 bytes */ 2565*25cf1a30Sjl nbytes -= (4 * sizeof (uint64_t)); 2566*25cf1a30Sjl } 2567*25cf1a30Sjl } 2568*25cf1a30Sjl memlist_read_unlock(); 2569*25cf1a30Sjl 2570*25cf1a30Sjl return (NULL); 2571*25cf1a30Sjl } 2572*25cf1a30Sjl 2573*25cf1a30Sjl static struct { 2574*25cf1a30Sjl const char *name; 2575*25cf1a30Sjl sbd_error_t *(*handler)(drmachid_t id, drmach_opts_t *opts); 2576*25cf1a30Sjl } drmach_pt_arr[] = { 2577*25cf1a30Sjl { "readmem", drmach_pt_readmem }, 2578*25cf1a30Sjl { "ikprobe", drmach_pt_ikprobe }, 2579*25cf1a30Sjl { "ikdeprobe", drmach_pt_ikdeprobe }, 2580*25cf1a30Sjl 2581*25cf1a30Sjl /* the following line must always be last */ 2582*25cf1a30Sjl { NULL, NULL } 2583*25cf1a30Sjl }; 2584*25cf1a30Sjl 2585*25cf1a30Sjl /*ARGSUSED*/ 2586*25cf1a30Sjl sbd_error_t * 2587*25cf1a30Sjl drmach_passthru(drmachid_t id, drmach_opts_t *opts) 2588*25cf1a30Sjl { 2589*25cf1a30Sjl int i; 2590*25cf1a30Sjl sbd_error_t *err; 2591*25cf1a30Sjl 2592*25cf1a30Sjl i = 0; 2593*25cf1a30Sjl while (drmach_pt_arr[i].name != NULL) { 2594*25cf1a30Sjl int len = strlen(drmach_pt_arr[i].name); 2595*25cf1a30Sjl 2596*25cf1a30Sjl if (strncmp(drmach_pt_arr[i].name, opts->copts, len) == 0) 2597*25cf1a30Sjl break; 2598*25cf1a30Sjl 2599*25cf1a30Sjl i += 1; 2600*25cf1a30Sjl } 2601*25cf1a30Sjl 2602*25cf1a30Sjl if (drmach_pt_arr[i].name == NULL) 2603*25cf1a30Sjl err = drerr_new(0, EOPL_UNKPTCMD, opts->copts); 2604*25cf1a30Sjl else 2605*25cf1a30Sjl err = (*drmach_pt_arr[i].handler)(id, opts); 2606*25cf1a30Sjl 2607*25cf1a30Sjl return (err); 2608*25cf1a30Sjl } 2609*25cf1a30Sjl 2610*25cf1a30Sjl sbd_error_t * 2611*25cf1a30Sjl drmach_release(drmachid_t id) 2612*25cf1a30Sjl { 2613*25cf1a30Sjl drmach_common_t *cp; 2614*25cf1a30Sjl 2615*25cf1a30Sjl if (!DRMACH_IS_DEVICE_ID(id)) 2616*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2617*25cf1a30Sjl cp = id; 2618*25cf1a30Sjl 2619*25cf1a30Sjl return (cp->release(id)); 2620*25cf1a30Sjl } 2621*25cf1a30Sjl 2622*25cf1a30Sjl sbd_error_t * 2623*25cf1a30Sjl drmach_status(drmachid_t id, drmach_status_t *stat) 2624*25cf1a30Sjl { 2625*25cf1a30Sjl drmach_common_t *cp; 2626*25cf1a30Sjl sbd_error_t *err; 2627*25cf1a30Sjl 2628*25cf1a30Sjl rw_enter(&drmach_boards_rwlock, RW_READER); 2629*25cf1a30Sjl 2630*25cf1a30Sjl if (!DRMACH_IS_ID(id)) { 2631*25cf1a30Sjl rw_exit(&drmach_boards_rwlock); 2632*25cf1a30Sjl return (drerr_new(0, EOPL_NOTID, NULL)); 2633*25cf1a30Sjl } 2634*25cf1a30Sjl cp = (drmach_common_t *)id; 2635*25cf1a30Sjl err = cp->status(id, stat); 2636*25cf1a30Sjl 2637*25cf1a30Sjl rw_exit(&drmach_boards_rwlock); 2638*25cf1a30Sjl 2639*25cf1a30Sjl return (err); 2640*25cf1a30Sjl } 2641*25cf1a30Sjl 2642*25cf1a30Sjl static sbd_error_t * 2643*25cf1a30Sjl drmach_i_status(drmachid_t id, drmach_status_t *stat) 2644*25cf1a30Sjl { 2645*25cf1a30Sjl drmach_common_t *cp; 2646*25cf1a30Sjl 2647*25cf1a30Sjl if (!DRMACH_IS_ID(id)) 2648*25cf1a30Sjl return (drerr_new(0, EOPL_NOTID, NULL)); 2649*25cf1a30Sjl cp = id; 2650*25cf1a30Sjl 2651*25cf1a30Sjl return (cp->status(id, stat)); 2652*25cf1a30Sjl } 2653*25cf1a30Sjl 2654*25cf1a30Sjl /*ARGSUSED*/ 2655*25cf1a30Sjl sbd_error_t * 2656*25cf1a30Sjl drmach_unconfigure(drmachid_t id, int flags) 2657*25cf1a30Sjl { 2658*25cf1a30Sjl drmach_device_t *dp; 2659*25cf1a30Sjl dev_info_t *rdip, *fdip = NULL; 2660*25cf1a30Sjl char name[OBP_MAXDRVNAME]; 2661*25cf1a30Sjl int rv; 2662*25cf1a30Sjl 2663*25cf1a30Sjl if (DRMACH_IS_CPU_ID(id)) 2664*25cf1a30Sjl return (NULL); 2665*25cf1a30Sjl 2666*25cf1a30Sjl if (!DRMACH_IS_DEVICE_ID(id)) 2667*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 2668*25cf1a30Sjl 2669*25cf1a30Sjl dp = id; 2670*25cf1a30Sjl 2671*25cf1a30Sjl rdip = dp->node->n_getdip(dp->node); 2672*25cf1a30Sjl 2673*25cf1a30Sjl ASSERT(rdip); 2674*25cf1a30Sjl 2675*25cf1a30Sjl rv = dp->node->n_getprop(dp->node, "name", name, OBP_MAXDRVNAME); 2676*25cf1a30Sjl 2677*25cf1a30Sjl if (rv) 2678*25cf1a30Sjl return (NULL); 2679*25cf1a30Sjl 2680*25cf1a30Sjl /* 2681*25cf1a30Sjl * Note: FORCE flag is no longer necessary under devfs 2682*25cf1a30Sjl */ 2683*25cf1a30Sjl 2684*25cf1a30Sjl ASSERT(e_ddi_branch_held(rdip)); 2685*25cf1a30Sjl if (e_ddi_branch_unconfigure(rdip, &fdip, 0)) { 2686*25cf1a30Sjl sbd_error_t *err; 2687*25cf1a30Sjl char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 2688*25cf1a30Sjl 2689*25cf1a30Sjl /* 2690*25cf1a30Sjl * If non-NULL, fdip is returned held and must be released. 2691*25cf1a30Sjl */ 2692*25cf1a30Sjl if (fdip != NULL) { 2693*25cf1a30Sjl (void) ddi_pathname(fdip, path); 2694*25cf1a30Sjl ndi_rele_devi(fdip); 2695*25cf1a30Sjl } else { 2696*25cf1a30Sjl (void) ddi_pathname(rdip, path); 2697*25cf1a30Sjl } 2698*25cf1a30Sjl 2699*25cf1a30Sjl err = drerr_new(1, EOPL_DRVFAIL, path); 2700*25cf1a30Sjl 2701*25cf1a30Sjl kmem_free(path, MAXPATHLEN); 2702*25cf1a30Sjl 2703*25cf1a30Sjl return (err); 2704*25cf1a30Sjl } 2705*25cf1a30Sjl 2706*25cf1a30Sjl return (NULL); 2707*25cf1a30Sjl } 2708*25cf1a30Sjl 2709*25cf1a30Sjl 2710*25cf1a30Sjl int 2711*25cf1a30Sjl drmach_cpu_poweron(struct cpu *cp) 2712*25cf1a30Sjl { 2713*25cf1a30Sjl int bnum, cpuid, onb_core_num, strand_id; 2714*25cf1a30Sjl drmach_board_t *bp; 2715*25cf1a30Sjl 2716*25cf1a30Sjl DRMACH_PR("drmach_cpu_poweron: starting cpuid %d\n", cp->cpu_id); 2717*25cf1a30Sjl 2718*25cf1a30Sjl cpuid = cp->cpu_id; 2719*25cf1a30Sjl bnum = LSB_ID(cpuid); 2720*25cf1a30Sjl onb_core_num = ON_BOARD_CORE_NUM(cpuid); 2721*25cf1a30Sjl strand_id = STRAND_ID(cpuid); 2722*25cf1a30Sjl bp = drmach_get_board_by_bnum(bnum); 2723*25cf1a30Sjl 2724*25cf1a30Sjl ASSERT(bp); 2725*25cf1a30Sjl if (bp->cores[onb_core_num].core_hotadded == 0) { 2726*25cf1a30Sjl if (drmach_add_remove_cpu(bnum, onb_core_num, 2727*25cf1a30Sjl HOTADD_CPU) != 0) { 2728*25cf1a30Sjl cmn_err(CE_WARN, "Failed to add CMP %d on board %d\n", 2729*25cf1a30Sjl onb_core_num, bnum); 2730*25cf1a30Sjl return (EIO); 2731*25cf1a30Sjl } 2732*25cf1a30Sjl } 2733*25cf1a30Sjl 2734*25cf1a30Sjl ASSERT(MUTEX_HELD(&cpu_lock)); 2735*25cf1a30Sjl 2736*25cf1a30Sjl if (drmach_cpu_start(cp) != 0) { 2737*25cf1a30Sjl if (bp->cores[onb_core_num].core_started == 0) { 2738*25cf1a30Sjl /* 2739*25cf1a30Sjl * we must undo the hotadd or no one will do that 2740*25cf1a30Sjl * If this fails, we will do this again in 2741*25cf1a30Sjl * drmach_board_disconnect. 2742*25cf1a30Sjl */ 2743*25cf1a30Sjl if (drmach_add_remove_cpu(bnum, onb_core_num, 2744*25cf1a30Sjl HOTREMOVE_CPU) != 0) { 2745*25cf1a30Sjl cmn_err(CE_WARN, "Failed to remove CMP %d " 2746*25cf1a30Sjl "on board %d\n", 2747*25cf1a30Sjl onb_core_num, bnum); 2748*25cf1a30Sjl } 2749*25cf1a30Sjl } 2750*25cf1a30Sjl return (EBUSY); 2751*25cf1a30Sjl } else { 2752*25cf1a30Sjl bp->cores[onb_core_num].core_started |= (1 << strand_id); 2753*25cf1a30Sjl return (0); 2754*25cf1a30Sjl } 2755*25cf1a30Sjl } 2756*25cf1a30Sjl 2757*25cf1a30Sjl int 2758*25cf1a30Sjl drmach_cpu_poweroff(struct cpu *cp) 2759*25cf1a30Sjl { 2760*25cf1a30Sjl int rv = 0; 2761*25cf1a30Sjl processorid_t cpuid = cp->cpu_id; 2762*25cf1a30Sjl 2763*25cf1a30Sjl DRMACH_PR("drmach_cpu_poweroff: stopping cpuid %d\n", cp->cpu_id); 2764*25cf1a30Sjl 2765*25cf1a30Sjl ASSERT(MUTEX_HELD(&cpu_lock)); 2766*25cf1a30Sjl 2767*25cf1a30Sjl /* 2768*25cf1a30Sjl * Capture all CPUs (except for detaching proc) to prevent 2769*25cf1a30Sjl * crosscalls to the detaching proc until it has cleared its 2770*25cf1a30Sjl * bit in cpu_ready_set. 2771*25cf1a30Sjl * 2772*25cf1a30Sjl * The CPU's remain paused and the prom_mutex is known to be free. 2773*25cf1a30Sjl * This prevents the x-trap victim from blocking when doing prom 2774*25cf1a30Sjl * IEEE-1275 calls at a high PIL level. 2775*25cf1a30Sjl */ 2776*25cf1a30Sjl 2777*25cf1a30Sjl promsafe_pause_cpus(); 2778*25cf1a30Sjl 2779*25cf1a30Sjl /* 2780*25cf1a30Sjl * Quiesce interrupts on the target CPU. We do this by setting 2781*25cf1a30Sjl * the CPU 'not ready'- (i.e. removing the CPU from cpu_ready_set) to 2782*25cf1a30Sjl * prevent it from receiving cross calls and cross traps. 2783*25cf1a30Sjl * This prevents the processor from receiving any new soft interrupts. 2784*25cf1a30Sjl */ 2785*25cf1a30Sjl mp_cpu_quiesce(cp); 2786*25cf1a30Sjl 2787*25cf1a30Sjl rv = prom_stopcpu_bycpuid(cpuid); 2788*25cf1a30Sjl if (rv == 0) 2789*25cf1a30Sjl cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_POWEROFF; 2790*25cf1a30Sjl 2791*25cf1a30Sjl start_cpus(); 2792*25cf1a30Sjl 2793*25cf1a30Sjl if (rv == 0) { 2794*25cf1a30Sjl int bnum, onb_core_num, strand_id; 2795*25cf1a30Sjl drmach_board_t *bp; 2796*25cf1a30Sjl 2797*25cf1a30Sjl CPU_SIGNATURE(OS_SIG, SIGST_DETACHED, SIGSUBST_NULL, cpuid); 2798*25cf1a30Sjl 2799*25cf1a30Sjl bnum = LSB_ID(cpuid); 2800*25cf1a30Sjl onb_core_num = ON_BOARD_CORE_NUM(cpuid); 2801*25cf1a30Sjl strand_id = STRAND_ID(cpuid); 2802*25cf1a30Sjl bp = drmach_get_board_by_bnum(bnum); 2803*25cf1a30Sjl ASSERT(bp); 2804*25cf1a30Sjl 2805*25cf1a30Sjl bp->cores[onb_core_num].core_started &= ~(1 << strand_id); 2806*25cf1a30Sjl if (bp->cores[onb_core_num].core_started == 0) { 2807*25cf1a30Sjl if (drmach_add_remove_cpu(bnum, onb_core_num, 2808*25cf1a30Sjl HOTREMOVE_CPU) != 0) { 2809*25cf1a30Sjl cmn_err(CE_WARN, 2810*25cf1a30Sjl "Failed to remove CMP %d LSB %d\n", 2811*25cf1a30Sjl onb_core_num, bnum); 2812*25cf1a30Sjl return (EIO); 2813*25cf1a30Sjl } 2814*25cf1a30Sjl } 2815*25cf1a30Sjl } 2816*25cf1a30Sjl 2817*25cf1a30Sjl return (rv); 2818*25cf1a30Sjl } 2819*25cf1a30Sjl 2820*25cf1a30Sjl /*ARGSUSED*/ 2821*25cf1a30Sjl int 2822*25cf1a30Sjl drmach_verify_sr(dev_info_t *dip, int sflag) 2823*25cf1a30Sjl { 2824*25cf1a30Sjl return (0); 2825*25cf1a30Sjl } 2826*25cf1a30Sjl 2827*25cf1a30Sjl void 2828*25cf1a30Sjl drmach_suspend_last(void) 2829*25cf1a30Sjl { 2830*25cf1a30Sjl } 2831*25cf1a30Sjl 2832*25cf1a30Sjl void 2833*25cf1a30Sjl drmach_resume_first(void) 2834*25cf1a30Sjl { 2835*25cf1a30Sjl } 2836*25cf1a30Sjl 2837*25cf1a30Sjl /* 2838*25cf1a30Sjl * Log a DR sysevent. 2839*25cf1a30Sjl * Return value: 0 success, non-zero failure. 2840*25cf1a30Sjl */ 2841*25cf1a30Sjl int 2842*25cf1a30Sjl drmach_log_sysevent(int board, char *hint, int flag, int verbose) 2843*25cf1a30Sjl { 2844*25cf1a30Sjl sysevent_t *ev; 2845*25cf1a30Sjl sysevent_id_t eid; 2846*25cf1a30Sjl int rv, km_flag; 2847*25cf1a30Sjl sysevent_value_t evnt_val; 2848*25cf1a30Sjl sysevent_attr_list_t *evnt_attr_list = NULL; 2849*25cf1a30Sjl char attach_pnt[MAXNAMELEN]; 2850*25cf1a30Sjl 2851*25cf1a30Sjl km_flag = (flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP; 2852*25cf1a30Sjl attach_pnt[0] = '\0'; 2853*25cf1a30Sjl if (drmach_board_name(board, attach_pnt, MAXNAMELEN)) { 2854*25cf1a30Sjl rv = -1; 2855*25cf1a30Sjl goto logexit; 2856*25cf1a30Sjl } 2857*25cf1a30Sjl if (verbose) 2858*25cf1a30Sjl DRMACH_PR("drmach_log_sysevent: %s %s, flag: %d, verbose: %d\n", 2859*25cf1a30Sjl attach_pnt, hint, flag, verbose); 2860*25cf1a30Sjl 2861*25cf1a30Sjl if ((ev = sysevent_alloc(EC_DR, ESC_DR_AP_STATE_CHANGE, 2862*25cf1a30Sjl SUNW_KERN_PUB"dr", km_flag)) == NULL) { 2863*25cf1a30Sjl rv = -2; 2864*25cf1a30Sjl goto logexit; 2865*25cf1a30Sjl } 2866*25cf1a30Sjl evnt_val.value_type = SE_DATA_TYPE_STRING; 2867*25cf1a30Sjl evnt_val.value.sv_string = attach_pnt; 2868*25cf1a30Sjl if ((rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID, 2869*25cf1a30Sjl &evnt_val, km_flag)) != 0) 2870*25cf1a30Sjl goto logexit; 2871*25cf1a30Sjl 2872*25cf1a30Sjl evnt_val.value_type = SE_DATA_TYPE_STRING; 2873*25cf1a30Sjl evnt_val.value.sv_string = hint; 2874*25cf1a30Sjl if ((rv = sysevent_add_attr(&evnt_attr_list, DR_HINT, 2875*25cf1a30Sjl &evnt_val, km_flag)) != 0) { 2876*25cf1a30Sjl sysevent_free_attr(evnt_attr_list); 2877*25cf1a30Sjl goto logexit; 2878*25cf1a30Sjl } 2879*25cf1a30Sjl 2880*25cf1a30Sjl (void) sysevent_attach_attributes(ev, evnt_attr_list); 2881*25cf1a30Sjl 2882*25cf1a30Sjl /* 2883*25cf1a30Sjl * Log the event but do not sleep waiting for its 2884*25cf1a30Sjl * delivery. This provides insulation from syseventd. 2885*25cf1a30Sjl */ 2886*25cf1a30Sjl rv = log_sysevent(ev, SE_NOSLEEP, &eid); 2887*25cf1a30Sjl 2888*25cf1a30Sjl logexit: 2889*25cf1a30Sjl if (ev) 2890*25cf1a30Sjl sysevent_free(ev); 2891*25cf1a30Sjl if ((rv != 0) && verbose) 2892*25cf1a30Sjl cmn_err(CE_WARN, 2893*25cf1a30Sjl "drmach_log_sysevent failed (rv %d) for %s %s\n", 2894*25cf1a30Sjl rv, attach_pnt, hint); 2895*25cf1a30Sjl 2896*25cf1a30Sjl return (rv); 2897*25cf1a30Sjl } 2898*25cf1a30Sjl 2899*25cf1a30Sjl #define OPL_DR_STATUS_PROP "dr-status" 2900*25cf1a30Sjl 2901*25cf1a30Sjl static int 2902*25cf1a30Sjl opl_check_dr_status() 2903*25cf1a30Sjl { 2904*25cf1a30Sjl pnode_t node; 2905*25cf1a30Sjl int rtn, len; 2906*25cf1a30Sjl char *str; 2907*25cf1a30Sjl 2908*25cf1a30Sjl node = prom_rootnode(); 2909*25cf1a30Sjl if (node == OBP_BADNODE) { 2910*25cf1a30Sjl return (1); 2911*25cf1a30Sjl } 2912*25cf1a30Sjl 2913*25cf1a30Sjl len = prom_getproplen(node, OPL_DR_STATUS_PROP); 2914*25cf1a30Sjl if (len == -1) { 2915*25cf1a30Sjl /* 2916*25cf1a30Sjl * dr-status doesn't exist when DR is activated and 2917*25cf1a30Sjl * any warning messages aren't needed. 2918*25cf1a30Sjl */ 2919*25cf1a30Sjl return (1); 2920*25cf1a30Sjl } 2921*25cf1a30Sjl 2922*25cf1a30Sjl str = (char *)kmem_zalloc(len+1, KM_SLEEP); 2923*25cf1a30Sjl rtn = prom_getprop(node, OPL_DR_STATUS_PROP, str); 2924*25cf1a30Sjl kmem_free(str, len + 1); 2925*25cf1a30Sjl if (rtn == -1) { 2926*25cf1a30Sjl return (1); 2927*25cf1a30Sjl } else { 2928*25cf1a30Sjl return (0); 2929*25cf1a30Sjl } 2930*25cf1a30Sjl } 2931*25cf1a30Sjl 2932*25cf1a30Sjl static sbd_error_t * 2933*25cf1a30Sjl drmach_get_scf_addr(uint64_t *addr) 2934*25cf1a30Sjl { 2935*25cf1a30Sjl caddr_t *scf_cmd_addr; 2936*25cf1a30Sjl uint64_t pa; 2937*25cf1a30Sjl scf_cmd_addr = (caddr_t *)modgetsymvalue("scf_avail_cmd_reg_vaddr", 0); 2938*25cf1a30Sjl if (scf_cmd_addr != NULL) { 2939*25cf1a30Sjl pa = (uint64_t)va_to_pa(*scf_cmd_addr); 2940*25cf1a30Sjl *addr = pa; 2941*25cf1a30Sjl return (NULL); 2942*25cf1a30Sjl } 2943*25cf1a30Sjl 2944*25cf1a30Sjl return (DRMACH_INTERNAL_ERROR()); 2945*25cf1a30Sjl } 2946*25cf1a30Sjl 2947*25cf1a30Sjl /* we are allocating memlist from TLB locked pages to avoid tlbmisses */ 2948*25cf1a30Sjl 2949*25cf1a30Sjl static struct memlist * 2950*25cf1a30Sjl drmach_memlist_add_span(drmach_copy_rename_program_t *p, 2951*25cf1a30Sjl struct memlist *mlist, uint64_t base, uint64_t len) 2952*25cf1a30Sjl { 2953*25cf1a30Sjl struct memlist *ml, *tl, *nl; 2954*25cf1a30Sjl 2955*25cf1a30Sjl if (len == 0ull) 2956*25cf1a30Sjl return (NULL); 2957*25cf1a30Sjl 2958*25cf1a30Sjl if (mlist == NULL) { 2959*25cf1a30Sjl mlist = p->free_mlist; 2960*25cf1a30Sjl if (mlist == NULL) 2961*25cf1a30Sjl return (NULL); 2962*25cf1a30Sjl p->free_mlist = mlist->next; 2963*25cf1a30Sjl mlist->address = base; 2964*25cf1a30Sjl mlist->size = len; 2965*25cf1a30Sjl mlist->next = mlist->prev = NULL; 2966*25cf1a30Sjl 2967*25cf1a30Sjl return (mlist); 2968*25cf1a30Sjl } 2969*25cf1a30Sjl 2970*25cf1a30Sjl for (tl = ml = mlist; ml; tl = ml, ml = ml->next) { 2971*25cf1a30Sjl if (base < ml->address) { 2972*25cf1a30Sjl if ((base + len) < ml->address) { 2973*25cf1a30Sjl nl = p->free_mlist; 2974*25cf1a30Sjl if (nl == NULL) 2975*25cf1a30Sjl return (NULL); 2976*25cf1a30Sjl p->free_mlist = nl->next; 2977*25cf1a30Sjl nl->address = base; 2978*25cf1a30Sjl nl->size = len; 2979*25cf1a30Sjl nl->next = ml; 2980*25cf1a30Sjl if ((nl->prev = ml->prev) != NULL) 2981*25cf1a30Sjl nl->prev->next = nl; 2982*25cf1a30Sjl ml->prev = nl; 2983*25cf1a30Sjl if (mlist == ml) 2984*25cf1a30Sjl mlist = nl; 2985*25cf1a30Sjl } else { 2986*25cf1a30Sjl ml->size = MAX((base + len), 2987*25cf1a30Sjl (ml->address + ml->size)) - 2988*25cf1a30Sjl base; 2989*25cf1a30Sjl ml->address = base; 2990*25cf1a30Sjl } 2991*25cf1a30Sjl break; 2992*25cf1a30Sjl 2993*25cf1a30Sjl } else if (base <= (ml->address + ml->size)) { 2994*25cf1a30Sjl ml->size = MAX((base + len), 2995*25cf1a30Sjl (ml->address + ml->size)) - 2996*25cf1a30Sjl MIN(ml->address, base); 2997*25cf1a30Sjl ml->address = MIN(ml->address, base); 2998*25cf1a30Sjl break; 2999*25cf1a30Sjl } 3000*25cf1a30Sjl } 3001*25cf1a30Sjl if (ml == NULL) { 3002*25cf1a30Sjl nl = p->free_mlist; 3003*25cf1a30Sjl if (nl == NULL) 3004*25cf1a30Sjl return (NULL); 3005*25cf1a30Sjl p->free_mlist = nl->next; 3006*25cf1a30Sjl nl->address = base; 3007*25cf1a30Sjl nl->size = len; 3008*25cf1a30Sjl nl->next = NULL; 3009*25cf1a30Sjl nl->prev = tl; 3010*25cf1a30Sjl tl->next = nl; 3011*25cf1a30Sjl } 3012*25cf1a30Sjl 3013*25cf1a30Sjl return (mlist); 3014*25cf1a30Sjl } 3015*25cf1a30Sjl 3016*25cf1a30Sjl /* 3017*25cf1a30Sjl * The routine performs the necessary memory COPY and MC adr SWITCH. 3018*25cf1a30Sjl * Both operations MUST be at the same "level" so that the stack is 3019*25cf1a30Sjl * maintained correctly between the copy and switch. The switch 3020*25cf1a30Sjl * portion implements a caching mechanism to guarantee the code text 3021*25cf1a30Sjl * is cached prior to execution. This is to guard against possible 3022*25cf1a30Sjl * memory access while the MC adr's are being modified. 3023*25cf1a30Sjl * 3024*25cf1a30Sjl * IMPORTANT: The _drmach_copy_rename_end() function must immediately 3025*25cf1a30Sjl * follow drmach_copy_rename_prog__relocatable() so that the correct 3026*25cf1a30Sjl * "length" of the drmach_copy_rename_prog__relocatable can be 3027*25cf1a30Sjl * calculated. This routine MUST be a LEAF function, i.e. it can 3028*25cf1a30Sjl * make NO function calls, primarily for two reasons: 3029*25cf1a30Sjl * 3030*25cf1a30Sjl * 1. We must keep the stack consistent across the "switch". 3031*25cf1a30Sjl * 2. Function calls are compiled to relative offsets, and 3032*25cf1a30Sjl * we execute this function we'll be executing it from 3033*25cf1a30Sjl * a copied version in a different area of memory, thus 3034*25cf1a30Sjl * the relative offsets will be bogus. 3035*25cf1a30Sjl * 3036*25cf1a30Sjl * Moreover, it must have the "__relocatable" suffix to inform DTrace 3037*25cf1a30Sjl * providers (and anything else, for that matter) that this 3038*25cf1a30Sjl * function's text is manually relocated elsewhere before it is 3039*25cf1a30Sjl * executed. That is, it cannot be safely instrumented with any 3040*25cf1a30Sjl * methodology that is PC-relative. 3041*25cf1a30Sjl */ 3042*25cf1a30Sjl 3043*25cf1a30Sjl /* 3044*25cf1a30Sjl * We multiply this to system_clock_frequency so we 3045*25cf1a30Sjl * are setting a delay of fmem_timeout second for 3046*25cf1a30Sjl * the rename command. The spec says 15 second is 3047*25cf1a30Sjl * enough but the Fujitsu HW team suggested 17 sec. 3048*25cf1a30Sjl */ 3049*25cf1a30Sjl static int fmem_timeout = 17; 3050*25cf1a30Sjl static int min_copy_size_per_sec = 20 * 1024 * 1024; 3051*25cf1a30Sjl int drmach_disable_mcopy = 0; 3052*25cf1a30Sjl 3053*25cf1a30Sjl #define DR_DELAY_IL(ms, freq) \ 3054*25cf1a30Sjl { \ 3055*25cf1a30Sjl uint64_t start; \ 3056*25cf1a30Sjl uint64_t nstick; \ 3057*25cf1a30Sjl volatile uint64_t now; \ 3058*25cf1a30Sjl nstick = ((uint64_t)ms * freq)/1000; \ 3059*25cf1a30Sjl start = drmach_get_stick_il(); \ 3060*25cf1a30Sjl now = start; \ 3061*25cf1a30Sjl while ((now - start) <= nstick) { \ 3062*25cf1a30Sjl drmach_sleep_il(); \ 3063*25cf1a30Sjl now = drmach_get_stick_il(); \ 3064*25cf1a30Sjl } \ 3065*25cf1a30Sjl } 3066*25cf1a30Sjl 3067*25cf1a30Sjl static int 3068*25cf1a30Sjl drmach_copy_rename_prog__relocatable(drmach_copy_rename_program_t *prog, 3069*25cf1a30Sjl int cpuid) 3070*25cf1a30Sjl { 3071*25cf1a30Sjl struct memlist *ml; 3072*25cf1a30Sjl register int rtn; 3073*25cf1a30Sjl int i; 3074*25cf1a30Sjl register uint64_t curr, limit; 3075*25cf1a30Sjl extern uint64_t drmach_get_stick_il(); 3076*25cf1a30Sjl extern void membar_sync_il(); 3077*25cf1a30Sjl extern void flush_instr_mem_il(void*); 3078*25cf1a30Sjl uint64_t copy_start; 3079*25cf1a30Sjl 3080*25cf1a30Sjl prog->critical->stat[cpuid] = FMEM_LOOP_COPY_READY; 3081*25cf1a30Sjl membar_sync_il(); 3082*25cf1a30Sjl 3083*25cf1a30Sjl if (prog->data->cpuid == cpuid) { 3084*25cf1a30Sjl limit = drmach_get_stick_il(); 3085*25cf1a30Sjl limit += prog->critical->delay; 3086*25cf1a30Sjl 3087*25cf1a30Sjl for (i = 0; i < NCPU; i++) { 3088*25cf1a30Sjl if (CPU_IN_SET(prog->data->cpu_slave_set, i)) { 3089*25cf1a30Sjl /* wait for all CPU's to be ready */ 3090*25cf1a30Sjl for (;;) { 3091*25cf1a30Sjl if (prog->critical->stat[i] == 3092*25cf1a30Sjl FMEM_LOOP_COPY_READY) { 3093*25cf1a30Sjl break; 3094*25cf1a30Sjl } 3095*25cf1a30Sjl } 3096*25cf1a30Sjl curr = drmach_get_stick_il(); 3097*25cf1a30Sjl if (curr > limit) { 3098*25cf1a30Sjl prog->data->fmem_status.error = 3099*25cf1a30Sjl FMEM_XC_TIMEOUT; 3100*25cf1a30Sjl return (FMEM_XC_TIMEOUT); 3101*25cf1a30Sjl } 3102*25cf1a30Sjl } 3103*25cf1a30Sjl } 3104*25cf1a30Sjl prog->data->fmem_status.stat = FMEM_LOOP_COPY_READY; 3105*25cf1a30Sjl membar_sync_il(); 3106*25cf1a30Sjl copy_start = drmach_get_stick_il(); 3107*25cf1a30Sjl } else { 3108*25cf1a30Sjl for (;;) { 3109*25cf1a30Sjl if (prog->data->fmem_status.stat == 3110*25cf1a30Sjl FMEM_LOOP_COPY_READY) { 3111*25cf1a30Sjl break; 3112*25cf1a30Sjl } 3113*25cf1a30Sjl if (prog->data->fmem_status.error) { 3114*25cf1a30Sjl prog->data->error[cpuid] = FMEM_TERMINATE; 3115*25cf1a30Sjl return (FMEM_TERMINATE); 3116*25cf1a30Sjl } 3117*25cf1a30Sjl } 3118*25cf1a30Sjl } 3119*25cf1a30Sjl 3120*25cf1a30Sjl /* 3121*25cf1a30Sjl * DO COPY. 3122*25cf1a30Sjl */ 3123*25cf1a30Sjl if (CPU_IN_SET(prog->data->cpu_copy_set, cpuid)) { 3124*25cf1a30Sjl for (ml = prog->data->cpu_ml[cpuid]; ml; ml = ml->next) { 3125*25cf1a30Sjl uint64_t s_pa, t_pa; 3126*25cf1a30Sjl uint64_t nbytes; 3127*25cf1a30Sjl 3128*25cf1a30Sjl s_pa = prog->data->s_copybasepa + ml->address; 3129*25cf1a30Sjl t_pa = prog->data->t_copybasepa + ml->address; 3130*25cf1a30Sjl nbytes = ml->size; 3131*25cf1a30Sjl 3132*25cf1a30Sjl while (nbytes != 0ull) { 3133*25cf1a30Sjl /* If the master has detected error, we just bail out */ 3134*25cf1a30Sjl if (prog->data->fmem_status.error) { 3135*25cf1a30Sjl prog->data->error[cpuid] = FMEM_TERMINATE; 3136*25cf1a30Sjl return (FMEM_TERMINATE); 3137*25cf1a30Sjl } 3138*25cf1a30Sjl /* 3139*25cf1a30Sjl * This copy does NOT use an ASI 3140*25cf1a30Sjl * that avoids the Ecache, therefore 3141*25cf1a30Sjl * the dst_pa addresses may remain 3142*25cf1a30Sjl * in our Ecache after the dst_pa 3143*25cf1a30Sjl * has been removed from the system. 3144*25cf1a30Sjl * A subsequent write-back to memory 3145*25cf1a30Sjl * will cause an ARB-stop because the 3146*25cf1a30Sjl * physical address no longer exists 3147*25cf1a30Sjl * in the system. Therefore we must 3148*25cf1a30Sjl * flush out local Ecache after we 3149*25cf1a30Sjl * finish the copy. 3150*25cf1a30Sjl */ 3151*25cf1a30Sjl 3152*25cf1a30Sjl /* copy 32 bytes at src_pa to dst_pa */ 3153*25cf1a30Sjl bcopy32_il(s_pa, t_pa); 3154*25cf1a30Sjl 3155*25cf1a30Sjl /* increment the counter to signal that we are alive */ 3156*25cf1a30Sjl prog->stat->nbytes[cpuid] += 32; 3157*25cf1a30Sjl 3158*25cf1a30Sjl /* increment by 32 bytes */ 3159*25cf1a30Sjl s_pa += (4 * sizeof (uint64_t)); 3160*25cf1a30Sjl t_pa += (4 * sizeof (uint64_t)); 3161*25cf1a30Sjl 3162*25cf1a30Sjl /* decrement by 32 bytes */ 3163*25cf1a30Sjl nbytes -= (4 * sizeof (uint64_t)); 3164*25cf1a30Sjl } 3165*25cf1a30Sjl } 3166*25cf1a30Sjl prog->critical->stat[cpuid] = FMEM_LOOP_COPY_DONE; 3167*25cf1a30Sjl membar_sync_il(); 3168*25cf1a30Sjl } 3169*25cf1a30Sjl 3170*25cf1a30Sjl /* 3171*25cf1a30Sjl * Since bcopy32_il() does NOT use an ASI to bypass 3172*25cf1a30Sjl * the Ecache, we need to flush our Ecache after 3173*25cf1a30Sjl * the copy is complete. 3174*25cf1a30Sjl */ 3175*25cf1a30Sjl flush_cache_il(); 3176*25cf1a30Sjl 3177*25cf1a30Sjl /* 3178*25cf1a30Sjl * drmach_fmem_exec_script() 3179*25cf1a30Sjl */ 3180*25cf1a30Sjl if (prog->data->cpuid == cpuid) { 3181*25cf1a30Sjl uint64_t last, now; 3182*25cf1a30Sjl 3183*25cf1a30Sjl limit = copy_start + prog->data->copy_delay; 3184*25cf1a30Sjl for (i = 0; i < NCPU; i++) { 3185*25cf1a30Sjl if (CPU_IN_SET(prog->data->cpu_slave_set, i)) { 3186*25cf1a30Sjl for (;;) { 3187*25cf1a30Sjl /* we get FMEM_LOOP_FMEM_READY in normal case */ 3188*25cf1a30Sjl if (prog->critical->stat[i] == 3189*25cf1a30Sjl FMEM_LOOP_FMEM_READY) { 3190*25cf1a30Sjl break; 3191*25cf1a30Sjl } 3192*25cf1a30Sjl /* got error traps */ 3193*25cf1a30Sjl if (prog->critical->stat[i] == 3194*25cf1a30Sjl FMEM_COPY_ERROR) { 3195*25cf1a30Sjl prog->data->fmem_status.error = 3196*25cf1a30Sjl FMEM_COPY_ERROR; 3197*25cf1a30Sjl return (FMEM_COPY_ERROR); 3198*25cf1a30Sjl } 3199*25cf1a30Sjl /* if we have not reached limit, wait more */ 3200*25cf1a30Sjl curr = drmach_get_stick_il(); 3201*25cf1a30Sjl if (curr <= limit) 3202*25cf1a30Sjl continue; 3203*25cf1a30Sjl 3204*25cf1a30Sjl prog->data->slowest_cpuid = i; 3205*25cf1a30Sjl prog->data->copy_wait_time = 3206*25cf1a30Sjl curr - copy_start; 3207*25cf1a30Sjl 3208*25cf1a30Sjl /* now check if slave is alive */ 3209*25cf1a30Sjl last = prog->stat->nbytes[i]; 3210*25cf1a30Sjl 3211*25cf1a30Sjl DR_DELAY_IL(1, prog->data->stick_freq); 3212*25cf1a30Sjl 3213*25cf1a30Sjl now = prog->stat->nbytes[i]; 3214*25cf1a30Sjl if (now <= last) { 3215*25cf1a30Sjl /* no progress, perhaps just finished */ 3216*25cf1a30Sjl DR_DELAY_IL(1, prog->data->stick_freq); 3217*25cf1a30Sjl if (prog->critical->stat[i] == 3218*25cf1a30Sjl FMEM_LOOP_FMEM_READY) 3219*25cf1a30Sjl break; 3220*25cf1a30Sjl /* copy error */ 3221*25cf1a30Sjl if (prog->critical->stat[i] == 3222*25cf1a30Sjl FMEM_COPY_ERROR) { 3223*25cf1a30Sjl prog->data->fmem_status.error = 3224*25cf1a30Sjl FMEM_COPY_ERROR; 3225*25cf1a30Sjl return (FMEM_COPY_ERROR); 3226*25cf1a30Sjl } 3227*25cf1a30Sjl prog->data->fmem_status.error = 3228*25cf1a30Sjl FMEM_COPY_TIMEOUT; 3229*25cf1a30Sjl return (FMEM_COPY_TIMEOUT); 3230*25cf1a30Sjl } 3231*25cf1a30Sjl } 3232*25cf1a30Sjl } 3233*25cf1a30Sjl } 3234*25cf1a30Sjl prog->critical->stat[cpuid] = FMEM_LOOP_FMEM_READY; 3235*25cf1a30Sjl prog->data->fmem_status.stat = FMEM_LOOP_FMEM_READY; 3236*25cf1a30Sjl 3237*25cf1a30Sjl membar_sync_il(); 3238*25cf1a30Sjl flush_instr_mem_il((void*) (prog->critical)); 3239*25cf1a30Sjl /* 3240*25cf1a30Sjl * drmach_fmem_exec_script() 3241*25cf1a30Sjl */ 3242*25cf1a30Sjl rtn = prog->critical->fmem((void *)prog->critical, PAGESIZE); 3243*25cf1a30Sjl return (rtn); 3244*25cf1a30Sjl } else { 3245*25cf1a30Sjl flush_instr_mem_il((void*) (prog->critical)); 3246*25cf1a30Sjl /* 3247*25cf1a30Sjl * drmach_fmem_loop_script() 3248*25cf1a30Sjl */ 3249*25cf1a30Sjl rtn = prog->critical->loop((void *)(prog->critical), 3250*25cf1a30Sjl PAGESIZE, (void *)&(prog->critical->stat[cpuid])); 3251*25cf1a30Sjl 3252*25cf1a30Sjl prog->data->error[cpuid] = rtn; 3253*25cf1a30Sjl /* slave thread does not care the rv */ 3254*25cf1a30Sjl return (0); 3255*25cf1a30Sjl } 3256*25cf1a30Sjl } 3257*25cf1a30Sjl 3258*25cf1a30Sjl static void 3259*25cf1a30Sjl drmach_copy_rename_end(void) 3260*25cf1a30Sjl { 3261*25cf1a30Sjl /* 3262*25cf1a30Sjl * IMPORTANT: This function's location MUST be located immediately 3263*25cf1a30Sjl * following drmach_copy_rename_prog__relocatable to 3264*25cf1a30Sjl * accurately estimate its size. Note that this assumes 3265*25cf1a30Sjl * the compiler keeps these functions in the order in 3266*25cf1a30Sjl * which they appear :-o 3267*25cf1a30Sjl */ 3268*25cf1a30Sjl } 3269*25cf1a30Sjl 3270*25cf1a30Sjl 3271*25cf1a30Sjl static void 3272*25cf1a30Sjl drmach_setup_memlist(drmach_copy_rename_program_t *p) 3273*25cf1a30Sjl { 3274*25cf1a30Sjl struct memlist *ml; 3275*25cf1a30Sjl caddr_t buf; 3276*25cf1a30Sjl int nbytes, s; 3277*25cf1a30Sjl 3278*25cf1a30Sjl nbytes = PAGESIZE; 3279*25cf1a30Sjl s = roundup(sizeof (struct memlist), sizeof (void *)); 3280*25cf1a30Sjl p->free_mlist = NULL; 3281*25cf1a30Sjl buf = p->memlist_buffer; 3282*25cf1a30Sjl while (nbytes >= sizeof (struct memlist)) { 3283*25cf1a30Sjl ml = (struct memlist *)buf; 3284*25cf1a30Sjl ml->next = p->free_mlist; 3285*25cf1a30Sjl p->free_mlist = ml; 3286*25cf1a30Sjl buf += s; 3287*25cf1a30Sjl nbytes -= s; 3288*25cf1a30Sjl } 3289*25cf1a30Sjl } 3290*25cf1a30Sjl 3291*25cf1a30Sjl sbd_error_t * 3292*25cf1a30Sjl drmach_copy_rename_init(drmachid_t t_id, drmachid_t s_id, 3293*25cf1a30Sjl struct memlist *c_ml, drmachid_t *pgm_id) 3294*25cf1a30Sjl { 3295*25cf1a30Sjl drmach_mem_t *s_mem; 3296*25cf1a30Sjl drmach_mem_t *t_mem; 3297*25cf1a30Sjl struct memlist *x_ml; 3298*25cf1a30Sjl uint64_t s_copybasepa, t_copybasepa; 3299*25cf1a30Sjl uint_t len; 3300*25cf1a30Sjl caddr_t bp, wp; 3301*25cf1a30Sjl int s_bd, t_bd, cpuid, active_cpus, i; 3302*25cf1a30Sjl uint64_t c_addr; 3303*25cf1a30Sjl size_t c_size, copy_sz, sz; 3304*25cf1a30Sjl static sbd_error_t *drmach_get_scf_addr(uint64_t *); 3305*25cf1a30Sjl extern void drmach_fmem_loop_script(); 3306*25cf1a30Sjl extern void drmach_fmem_loop_script_rtn(); 3307*25cf1a30Sjl extern int drmach_fmem_exec_script(); 3308*25cf1a30Sjl extern void drmach_fmem_exec_script_end(); 3309*25cf1a30Sjl sbd_error_t *err; 3310*25cf1a30Sjl drmach_copy_rename_program_t *prog; 3311*25cf1a30Sjl void (*mc_suspend)(void); 3312*25cf1a30Sjl void (*mc_resume)(void); 3313*25cf1a30Sjl int (*scf_fmem_start)(int, int); 3314*25cf1a30Sjl int (*scf_fmem_end)(void); 3315*25cf1a30Sjl int (*scf_fmem_cancel)(void); 3316*25cf1a30Sjl 3317*25cf1a30Sjl if (!DRMACH_IS_MEM_ID(s_id)) 3318*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 3319*25cf1a30Sjl if (!DRMACH_IS_MEM_ID(t_id)) 3320*25cf1a30Sjl return (drerr_new(0, EOPL_INAPPROP, NULL)); 3321*25cf1a30Sjl 3322*25cf1a30Sjl for (i = 0; i < NCPU; i++) { 3323*25cf1a30Sjl int lsb_id, onb_core_num, strand_id; 3324*25cf1a30Sjl drmach_board_t *bp; 3325*25cf1a30Sjl 3326*25cf1a30Sjl /* 3327*25cf1a30Sjl * this kind of CPU will spin in cache 3328*25cf1a30Sjl */ 3329*25cf1a30Sjl if (CPU_IN_SET(cpu_ready_set, i)) 3330*25cf1a30Sjl continue; 3331*25cf1a30Sjl 3332*25cf1a30Sjl /* 3333*25cf1a30Sjl * Now check for any inactive CPU's that 3334*25cf1a30Sjl * have been hotadded. This can only occur in 3335*25cf1a30Sjl * error condition in drmach_cpu_poweron(). 3336*25cf1a30Sjl */ 3337*25cf1a30Sjl lsb_id = LSB_ID(i); 3338*25cf1a30Sjl onb_core_num = ON_BOARD_CORE_NUM(i); 3339*25cf1a30Sjl strand_id = STRAND_ID(i); 3340*25cf1a30Sjl bp = drmach_get_board_by_bnum(lsb_id); 3341*25cf1a30Sjl if (bp == NULL) 3342*25cf1a30Sjl continue; 3343*25cf1a30Sjl if (bp->cores[onb_core_num].core_hotadded & 3344*25cf1a30Sjl (1 << strand_id)) { 3345*25cf1a30Sjl if (!(bp->cores[onb_core_num].core_started & 3346*25cf1a30Sjl (1 << strand_id))) { 3347*25cf1a30Sjl return (DRMACH_INTERNAL_ERROR()); 3348*25cf1a30Sjl } 3349*25cf1a30Sjl } 3350*25cf1a30Sjl } 3351*25cf1a30Sjl 3352*25cf1a30Sjl mc_suspend = (void (*)(void)) 3353*25cf1a30Sjl modgetsymvalue("opl_mc_suspend", 0); 3354*25cf1a30Sjl mc_resume = (void (*)(void)) 3355*25cf1a30Sjl modgetsymvalue("opl_mc_resume", 0); 3356*25cf1a30Sjl 3357*25cf1a30Sjl if (mc_suspend == NULL || mc_resume == NULL) { 3358*25cf1a30Sjl return (DRMACH_INTERNAL_ERROR()); 3359*25cf1a30Sjl } 3360*25cf1a30Sjl 3361*25cf1a30Sjl scf_fmem_start = (int (*)(int, int)) 3362*25cf1a30Sjl modgetsymvalue("scf_fmem_start", 0); 3363*25cf1a30Sjl if (scf_fmem_start == NULL) { 3364*25cf1a30Sjl return (DRMACH_INTERNAL_ERROR()); 3365*25cf1a30Sjl } 3366*25cf1a30Sjl scf_fmem_end = (int (*)(void)) 3367*25cf1a30Sjl modgetsymvalue("scf_fmem_end", 0); 3368*25cf1a30Sjl if (scf_fmem_end == NULL) { 3369*25cf1a30Sjl return (DRMACH_INTERNAL_ERROR()); 3370*25cf1a30Sjl } 3371*25cf1a30Sjl scf_fmem_cancel = (int (*)(void)) 3372*25cf1a30Sjl modgetsymvalue("scf_fmem_cancel", 0); 3373*25cf1a30Sjl if (scf_fmem_cancel == NULL) { 3374*25cf1a30Sjl return (DRMACH_INTERNAL_ERROR()); 3375*25cf1a30Sjl } 3376*25cf1a30Sjl s_mem = s_id; 3377*25cf1a30Sjl t_mem = t_id; 3378*25cf1a30Sjl 3379*25cf1a30Sjl s_bd = s_mem->dev.bp->bnum; 3380*25cf1a30Sjl t_bd = t_mem->dev.bp->bnum; 3381*25cf1a30Sjl 3382*25cf1a30Sjl /* calculate source and target base pa */ 3383*25cf1a30Sjl 3384*25cf1a30Sjl s_copybasepa = s_mem->slice_base; 3385*25cf1a30Sjl t_copybasepa = t_mem->slice_base; 3386*25cf1a30Sjl 3387*25cf1a30Sjl /* adjust copy memlist addresses to be relative to copy base pa */ 3388*25cf1a30Sjl x_ml = c_ml; 3389*25cf1a30Sjl while (x_ml != NULL) { 3390*25cf1a30Sjl x_ml->address -= s_copybasepa; 3391*25cf1a30Sjl x_ml = x_ml->next; 3392*25cf1a30Sjl } 3393*25cf1a30Sjl 3394*25cf1a30Sjl /* 3395*25cf1a30Sjl * bp will be page aligned, since we're calling 3396*25cf1a30Sjl * kmem_zalloc() with an exact multiple of PAGESIZE. 3397*25cf1a30Sjl */ 3398*25cf1a30Sjl wp = bp = kmem_zalloc(DRMACH_FMEM_LOCKED_PAGES * PAGESIZE, 3399*25cf1a30Sjl KM_SLEEP); 3400*25cf1a30Sjl 3401*25cf1a30Sjl prog = (drmach_copy_rename_program_t *)(wp + 3402*25cf1a30Sjl DRMACH_FMEM_DATA_PAGE * PAGESIZE); 3403*25cf1a30Sjl prog->data = (drmach_copy_rename_data_t *)roundup(((uint64_t)prog + 3404*25cf1a30Sjl sizeof (drmach_copy_rename_program_t)), sizeof (void *)); 3405*25cf1a30Sjl 3406*25cf1a30Sjl ASSERT(((uint64_t)prog->data + sizeof (drmach_copy_rename_data_t)) 3407*25cf1a30Sjl <= ((uint64_t)prog + PAGESIZE)); 3408*25cf1a30Sjl 3409*25cf1a30Sjl prog->critical = (drmach_copy_rename_critical_t *) 3410*25cf1a30Sjl (wp + DRMACH_FMEM_CRITICAL_PAGE * PAGESIZE); 3411*25cf1a30Sjl 3412*25cf1a30Sjl prog->memlist_buffer = (caddr_t)(wp + 3413*25cf1a30Sjl DRMACH_FMEM_MLIST_PAGE * PAGESIZE); 3414*25cf1a30Sjl 3415*25cf1a30Sjl prog->stat = (drmach_cr_stat_t *)(wp + 3416*25cf1a30Sjl DRMACH_FMEM_STAT_PAGE * PAGESIZE); 3417*25cf1a30Sjl 3418*25cf1a30Sjl /* LINTED */ 3419*25cf1a30Sjl ASSERT(sizeof (drmach_cr_stat_t) 3420*25cf1a30Sjl <= ((DRMACH_FMEM_LOCKED_PAGES - DRMACH_FMEM_STAT_PAGE) 3421*25cf1a30Sjl * PAGESIZE)); 3422*25cf1a30Sjl 3423*25cf1a30Sjl prog->critical->scf_reg_base = (uint64_t)-1; 3424*25cf1a30Sjl err = drmach_get_scf_addr(&(prog->critical->scf_reg_base)); 3425*25cf1a30Sjl if (err) { 3426*25cf1a30Sjl kmem_free(wp, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE); 3427*25cf1a30Sjl return (err); 3428*25cf1a30Sjl } 3429*25cf1a30Sjl 3430*25cf1a30Sjl prog->critical->scf_td[0] = (s_bd & 0xff); 3431*25cf1a30Sjl prog->critical->scf_td[1] = (t_bd & 0xff); 3432*25cf1a30Sjl for (i = 2; i < 15; i++) { 3433*25cf1a30Sjl prog->critical->scf_td[i] = 0; 3434*25cf1a30Sjl } 3435*25cf1a30Sjl prog->critical->scf_td[15] = ((0xaa + s_bd + t_bd) & 0xff); 3436*25cf1a30Sjl 3437*25cf1a30Sjl bp = (caddr_t)prog->critical; 3438*25cf1a30Sjl len = sizeof (drmach_copy_rename_critical_t); 3439*25cf1a30Sjl wp = (caddr_t)roundup((uint64_t)bp + len, sizeof (void *)); 3440*25cf1a30Sjl 3441*25cf1a30Sjl len = (uint_t)((ulong_t)drmach_copy_rename_end - 3442*25cf1a30Sjl (ulong_t)drmach_copy_rename_prog__relocatable); 3443*25cf1a30Sjl 3444*25cf1a30Sjl /* 3445*25cf1a30Sjl * We always leave 1K nop's to prevent the processor from 3446*25cf1a30Sjl * speculative execution that causes memory access 3447*25cf1a30Sjl */ 3448*25cf1a30Sjl wp = wp + len + 1024; 3449*25cf1a30Sjl 3450*25cf1a30Sjl len = (uint_t)((ulong_t)drmach_fmem_exec_script_end - 3451*25cf1a30Sjl (ulong_t)drmach_fmem_exec_script); 3452*25cf1a30Sjl /* this is the entry point of the loop script */ 3453*25cf1a30Sjl wp = wp + len + 1024; 3454*25cf1a30Sjl 3455*25cf1a30Sjl len = (uint_t)((ulong_t)drmach_fmem_exec_script - 3456*25cf1a30Sjl (ulong_t)drmach_fmem_loop_script); 3457*25cf1a30Sjl wp = wp + len + 1024; 3458*25cf1a30Sjl 3459*25cf1a30Sjl /* now we make sure there is 1K extra */ 3460*25cf1a30Sjl 3461*25cf1a30Sjl if ((wp - bp) > PAGESIZE) { 3462*25cf1a30Sjl kmem_free(prog, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE); 3463*25cf1a30Sjl return (DRMACH_INTERNAL_ERROR()); 3464*25cf1a30Sjl } 3465*25cf1a30Sjl 3466*25cf1a30Sjl bp = (caddr_t)prog->critical; 3467*25cf1a30Sjl len = sizeof (drmach_copy_rename_critical_t); 3468*25cf1a30Sjl wp = (caddr_t)roundup((uint64_t)bp + len, sizeof (void *)); 3469*25cf1a30Sjl 3470*25cf1a30Sjl prog->critical->run = (int (*)())(wp); 3471*25cf1a30Sjl len = (uint_t)((ulong_t)drmach_copy_rename_end - 3472*25cf1a30Sjl (ulong_t)drmach_copy_rename_prog__relocatable); 3473*25cf1a30Sjl 3474*25cf1a30Sjl bcopy((caddr_t)drmach_copy_rename_prog__relocatable, wp, len); 3475*25cf1a30Sjl 3476*25cf1a30Sjl wp = (caddr_t)roundup((uint64_t)wp + len, 1024); 3477*25cf1a30Sjl 3478*25cf1a30Sjl prog->critical->fmem = (int (*)())(wp); 3479*25cf1a30Sjl len = (int)((ulong_t)drmach_fmem_exec_script_end - 3480*25cf1a30Sjl (ulong_t)drmach_fmem_exec_script); 3481*25cf1a30Sjl bcopy((caddr_t)drmach_fmem_exec_script, wp, len); 3482*25cf1a30Sjl 3483*25cf1a30Sjl len = (int)((ulong_t)drmach_fmem_exec_script_end - 3484*25cf1a30Sjl (ulong_t)drmach_fmem_exec_script); 3485*25cf1a30Sjl wp = (caddr_t)roundup((uint64_t)wp + len, 1024); 3486*25cf1a30Sjl 3487*25cf1a30Sjl prog->critical->loop = (int (*)())(wp); 3488*25cf1a30Sjl len = (int)((ulong_t)drmach_fmem_exec_script - 3489*25cf1a30Sjl (ulong_t)drmach_fmem_loop_script); 3490*25cf1a30Sjl bcopy((caddr_t)drmach_fmem_loop_script, (void *)wp, len); 3491*25cf1a30Sjl len = (int)((ulong_t)drmach_fmem_loop_script_rtn- 3492*25cf1a30Sjl (ulong_t)drmach_fmem_loop_script); 3493*25cf1a30Sjl prog->critical->loop_rtn = (void (*)()) (wp+len); 3494*25cf1a30Sjl 3495*25cf1a30Sjl /* now we are committed, call SCF, soft suspend mac patrol */ 3496*25cf1a30Sjl if ((*scf_fmem_start)(s_bd, t_bd)) { 3497*25cf1a30Sjl kmem_free(prog, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE); 3498*25cf1a30Sjl return (DRMACH_INTERNAL_ERROR()); 3499*25cf1a30Sjl } 3500*25cf1a30Sjl prog->data->scf_fmem_end = scf_fmem_end; 3501*25cf1a30Sjl prog->data->scf_fmem_cancel = scf_fmem_cancel; 3502*25cf1a30Sjl prog->data->fmem_status.op |= OPL_FMEM_SCF_START; 3503*25cf1a30Sjl /* soft suspend mac patrol */ 3504*25cf1a30Sjl (*mc_suspend)(); 3505*25cf1a30Sjl prog->data->fmem_status.op |= OPL_FMEM_MC_SUSPEND; 3506*25cf1a30Sjl prog->data->mc_resume = mc_resume; 3507*25cf1a30Sjl 3508*25cf1a30Sjl prog->critical->inst_loop_ret = 3509*25cf1a30Sjl *(uint64_t *)(prog->critical->loop_rtn); 3510*25cf1a30Sjl 3511*25cf1a30Sjl /* 3512*25cf1a30Sjl * 0x30800000 is op code "ba,a +0" 3513*25cf1a30Sjl */ 3514*25cf1a30Sjl 3515*25cf1a30Sjl *(uint_t *)(prog->critical->loop_rtn) = (uint_t)(0x30800000); 3516*25cf1a30Sjl 3517*25cf1a30Sjl /* 3518*25cf1a30Sjl * set the value of SCF FMEM TIMEOUT 3519*25cf1a30Sjl */ 3520*25cf1a30Sjl prog->critical->delay = fmem_timeout * system_clock_freq; 3521*25cf1a30Sjl 3522*25cf1a30Sjl prog->data->s_mem = (drmachid_t)s_mem; 3523*25cf1a30Sjl prog->data->t_mem = (drmachid_t)t_mem; 3524*25cf1a30Sjl 3525*25cf1a30Sjl cpuid = CPU->cpu_id; 3526*25cf1a30Sjl prog->data->cpuid = cpuid; 3527*25cf1a30Sjl prog->data->cpu_ready_set = cpu_ready_set; 3528*25cf1a30Sjl prog->data->cpu_slave_set = cpu_ready_set; 3529*25cf1a30Sjl prog->data->slowest_cpuid = (processorid_t)-1; 3530*25cf1a30Sjl prog->data->copy_wait_time = 0; 3531*25cf1a30Sjl CPUSET_DEL(prog->data->cpu_slave_set, cpuid); 3532*25cf1a30Sjl 3533*25cf1a30Sjl for (i = 0; i < NCPU; i++) { 3534*25cf1a30Sjl prog->data->cpu_ml[i] = NULL; 3535*25cf1a30Sjl } 3536*25cf1a30Sjl 3537*25cf1a30Sjl active_cpus = 0; 3538*25cf1a30Sjl if (drmach_disable_mcopy) { 3539*25cf1a30Sjl active_cpus = 1; 3540*25cf1a30Sjl CPUSET_ADD(prog->data->cpu_copy_set, cpuid); 3541*25cf1a30Sjl } else { 3542*25cf1a30Sjl for (i = 0; i < NCPU; i++) { 3543*25cf1a30Sjl if (CPU_IN_SET(cpu_ready_set, i) && 3544*25cf1a30Sjl CPU_ACTIVE(cpu[i])) { 3545*25cf1a30Sjl CPUSET_ADD(prog->data->cpu_copy_set, i); 3546*25cf1a30Sjl active_cpus++; 3547*25cf1a30Sjl } 3548*25cf1a30Sjl } 3549*25cf1a30Sjl } 3550*25cf1a30Sjl 3551*25cf1a30Sjl drmach_setup_memlist(prog); 3552*25cf1a30Sjl 3553*25cf1a30Sjl x_ml = c_ml; 3554*25cf1a30Sjl sz = 0; 3555*25cf1a30Sjl while (x_ml != NULL) { 3556*25cf1a30Sjl sz += x_ml->size; 3557*25cf1a30Sjl x_ml = x_ml->next; 3558*25cf1a30Sjl } 3559*25cf1a30Sjl 3560*25cf1a30Sjl copy_sz = sz/active_cpus; 3561*25cf1a30Sjl copy_sz = roundup(copy_sz, MMU_PAGESIZE4M); 3562*25cf1a30Sjl 3563*25cf1a30Sjl while (sz > copy_sz*active_cpus) { 3564*25cf1a30Sjl copy_sz += MMU_PAGESIZE4M; 3565*25cf1a30Sjl } 3566*25cf1a30Sjl 3567*25cf1a30Sjl prog->data->stick_freq = system_clock_freq; 3568*25cf1a30Sjl prog->data->copy_delay = ((copy_sz / min_copy_size_per_sec) + 2) * 3569*25cf1a30Sjl system_clock_freq; 3570*25cf1a30Sjl 3571*25cf1a30Sjl x_ml = c_ml; 3572*25cf1a30Sjl c_addr = x_ml->address; 3573*25cf1a30Sjl c_size = x_ml->size; 3574*25cf1a30Sjl 3575*25cf1a30Sjl for (i = 0; i < NCPU; i++) { 3576*25cf1a30Sjl prog->stat->nbytes[i] = 0; 3577*25cf1a30Sjl if (!CPU_IN_SET(prog->data->cpu_copy_set, i)) { 3578*25cf1a30Sjl continue; 3579*25cf1a30Sjl } 3580*25cf1a30Sjl sz = copy_sz; 3581*25cf1a30Sjl 3582*25cf1a30Sjl while (sz) { 3583*25cf1a30Sjl if (c_size > sz) { 3584*25cf1a30Sjl prog->data->cpu_ml[i] = 3585*25cf1a30Sjl drmach_memlist_add_span(prog, 3586*25cf1a30Sjl prog->data->cpu_ml[i], 3587*25cf1a30Sjl c_addr, sz); 3588*25cf1a30Sjl c_addr += sz; 3589*25cf1a30Sjl c_size -= sz; 3590*25cf1a30Sjl break; 3591*25cf1a30Sjl } else { 3592*25cf1a30Sjl sz -= c_size; 3593*25cf1a30Sjl prog->data->cpu_ml[i] = drmach_memlist_add_span( 3594*25cf1a30Sjl prog, prog->data->cpu_ml[i], 3595*25cf1a30Sjl c_addr, c_size); 3596*25cf1a30Sjl x_ml = x_ml->next; 3597*25cf1a30Sjl if (x_ml != NULL) { 3598*25cf1a30Sjl c_addr = x_ml->address; 3599*25cf1a30Sjl c_size = x_ml->size; 3600*25cf1a30Sjl } else { 3601*25cf1a30Sjl goto end; 3602*25cf1a30Sjl } 3603*25cf1a30Sjl } 3604*25cf1a30Sjl } 3605*25cf1a30Sjl } 3606*25cf1a30Sjl end: 3607*25cf1a30Sjl prog->data->s_copybasepa = s_copybasepa; 3608*25cf1a30Sjl prog->data->t_copybasepa = t_copybasepa; 3609*25cf1a30Sjl prog->data->c_ml = c_ml; 3610*25cf1a30Sjl *pgm_id = prog; 3611*25cf1a30Sjl 3612*25cf1a30Sjl return (NULL); 3613*25cf1a30Sjl } 3614*25cf1a30Sjl 3615*25cf1a30Sjl sbd_error_t * 3616*25cf1a30Sjl drmach_copy_rename_fini(drmachid_t id) 3617*25cf1a30Sjl { 3618*25cf1a30Sjl drmach_copy_rename_program_t *prog = id; 3619*25cf1a30Sjl sbd_error_t *err = NULL; 3620*25cf1a30Sjl int rv; 3621*25cf1a30Sjl 3622*25cf1a30Sjl /* 3623*25cf1a30Sjl * Note that we have to delay calling SCF to find out the 3624*25cf1a30Sjl * status of the FMEM operation here because SCF cannot 3625*25cf1a30Sjl * respond while it is suspended. 3626*25cf1a30Sjl * This create a small window when we are sure about the 3627*25cf1a30Sjl * base address of the system board. 3628*25cf1a30Sjl * If there is any call to mc-opl to get memory unum, 3629*25cf1a30Sjl * mc-opl will return UNKNOWN as the unum. 3630*25cf1a30Sjl */ 3631*25cf1a30Sjl 3632*25cf1a30Sjl if (prog->data->c_ml != NULL) 3633*25cf1a30Sjl memlist_delete(prog->data->c_ml); 3634*25cf1a30Sjl 3635*25cf1a30Sjl if ((prog->data->fmem_status.op & 3636*25cf1a30Sjl (OPL_FMEM_SCF_START| OPL_FMEM_MC_SUSPEND)) != 3637*25cf1a30Sjl (OPL_FMEM_SCF_START | OPL_FMEM_MC_SUSPEND)) { 3638*25cf1a30Sjl cmn_err(CE_PANIC, "drmach_copy_rename_fini: " 3639*25cf1a30Sjl "invalid op code %x\n", 3640*25cf1a30Sjl prog->data->fmem_status.op); 3641*25cf1a30Sjl } 3642*25cf1a30Sjl 3643*25cf1a30Sjl /* possible ops are SCF_START, MC_SUSPEND */ 3644*25cf1a30Sjl if (prog->critical->fmem_issued) { 3645*25cf1a30Sjl if (prog->data->fmem_status.error != FMEM_NO_ERROR) 3646*25cf1a30Sjl cmn_err(CE_PANIC, "scf fmem request failed"); 3647*25cf1a30Sjl rv = (*prog->data->scf_fmem_end)(); 3648*25cf1a30Sjl if (rv) { 3649*25cf1a30Sjl cmn_err(CE_PANIC, "scf_fmem_end() failed"); 3650*25cf1a30Sjl } 3651*25cf1a30Sjl /* 3652*25cf1a30Sjl * If we get here, rename is successful. 3653*25cf1a30Sjl * Do all the copy rename post processing. 3654*25cf1a30Sjl */ 3655*25cf1a30Sjl drmach_swap_pa((drmach_mem_t *)prog->data->s_mem, 3656*25cf1a30Sjl (drmach_mem_t *)prog->data->t_mem); 3657*25cf1a30Sjl } else { 3658*25cf1a30Sjl if (prog->data->fmem_status.error != 0) { 3659*25cf1a30Sjl cmn_err(CE_WARN, "Kernel Migration fails. 0x%x", 3660*25cf1a30Sjl prog->data->fmem_status.error); 3661*25cf1a30Sjl err = DRMACH_INTERNAL_ERROR(); 3662*25cf1a30Sjl } 3663*25cf1a30Sjl rv = (*prog->data->scf_fmem_cancel)(); 3664*25cf1a30Sjl if (rv) { 3665*25cf1a30Sjl cmn_err(CE_WARN, "scf_fmem_cancel() failed"); 3666*25cf1a30Sjl if (!err) 3667*25cf1a30Sjl err = DRMACH_INTERNAL_ERROR(); 3668*25cf1a30Sjl } 3669*25cf1a30Sjl } 3670*25cf1a30Sjl /* soft resume mac patrol */ 3671*25cf1a30Sjl (*prog->data->mc_resume)(); 3672*25cf1a30Sjl 3673*25cf1a30Sjl kmem_free(prog, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE); 3674*25cf1a30Sjl return (err); 3675*25cf1a30Sjl } 3676*25cf1a30Sjl 3677*25cf1a30Sjl static void 3678*25cf1a30Sjl drmach_lock_critical(caddr_t va) 3679*25cf1a30Sjl { 3680*25cf1a30Sjl tte_t tte; 3681*25cf1a30Sjl int i; 3682*25cf1a30Sjl 3683*25cf1a30Sjl for (i = 0; i < DRMACH_FMEM_LOCKED_PAGES; i++) { 3684*25cf1a30Sjl vtag_flushpage(va, KCONTEXT); 3685*25cf1a30Sjl sfmmu_memtte(&tte, va_to_pfn(va), 3686*25cf1a30Sjl PROC_DATA|HAT_NOSYNC, TTE8K); 3687*25cf1a30Sjl tte.tte_intlo |= TTE_LCK_INT; 3688*25cf1a30Sjl sfmmu_dtlb_ld(va, KCONTEXT, &tte); 3689*25cf1a30Sjl sfmmu_itlb_ld(va, KCONTEXT, &tte); 3690*25cf1a30Sjl va += PAGESIZE; 3691*25cf1a30Sjl } 3692*25cf1a30Sjl } 3693*25cf1a30Sjl 3694*25cf1a30Sjl static void 3695*25cf1a30Sjl drmach_unlock_critical(caddr_t va) 3696*25cf1a30Sjl { 3697*25cf1a30Sjl int i; 3698*25cf1a30Sjl 3699*25cf1a30Sjl for (i = 0; i < DRMACH_FMEM_LOCKED_PAGES; i++) { 3700*25cf1a30Sjl vtag_flushpage(va, KCONTEXT); 3701*25cf1a30Sjl va += PAGESIZE; 3702*25cf1a30Sjl } 3703*25cf1a30Sjl } 3704*25cf1a30Sjl 3705*25cf1a30Sjl /*ARGSUSED*/ 3706*25cf1a30Sjl static void 3707*25cf1a30Sjl drmach_copy_rename_slave(struct regs *rp, drmachid_t id) 3708*25cf1a30Sjl { 3709*25cf1a30Sjl drmach_copy_rename_program_t *prog = id; 3710*25cf1a30Sjl register int cpuid; 3711*25cf1a30Sjl extern void drmach_flush(); 3712*25cf1a30Sjl extern void membar_sync_il(); 3713*25cf1a30Sjl extern void drmach_flush_icache(); 3714*25cf1a30Sjl on_trap_data_t otd; 3715*25cf1a30Sjl 3716*25cf1a30Sjl kpreempt_disable(); 3717*25cf1a30Sjl cpuid = CPU->cpu_id; 3718*25cf1a30Sjl 3719*25cf1a30Sjl if (on_trap(&otd, OT_DATA_EC)) { 3720*25cf1a30Sjl no_trap(); 3721*25cf1a30Sjl drmach_unlock_critical((caddr_t)prog); 3722*25cf1a30Sjl kpreempt_enable(); 3723*25cf1a30Sjl prog->data->error[cpuid] = FMEM_COPY_ERROR; 3724*25cf1a30Sjl prog->critical->stat[cpuid] = FMEM_LOOP_EXIT; 3725*25cf1a30Sjl return; 3726*25cf1a30Sjl } 3727*25cf1a30Sjl 3728*25cf1a30Sjl 3729*25cf1a30Sjl (void) drmach_lock_critical((caddr_t)prog); 3730*25cf1a30Sjl 3731*25cf1a30Sjl flush_windows(); 3732*25cf1a30Sjl 3733*25cf1a30Sjl /* 3734*25cf1a30Sjl * jmp drmach_copy_rename_prog(). 3735*25cf1a30Sjl */ 3736*25cf1a30Sjl 3737*25cf1a30Sjl drmach_flush(prog->critical, PAGESIZE); 3738*25cf1a30Sjl (void) prog->critical->run(prog, cpuid); 3739*25cf1a30Sjl drmach_flush_icache(); 3740*25cf1a30Sjl 3741*25cf1a30Sjl no_trap(); 3742*25cf1a30Sjl drmach_unlock_critical((caddr_t)prog); 3743*25cf1a30Sjl 3744*25cf1a30Sjl kpreempt_enable(); 3745*25cf1a30Sjl 3746*25cf1a30Sjl prog->critical->stat[cpuid] = FMEM_LOOP_EXIT; 3747*25cf1a30Sjl membar_sync_il(); 3748*25cf1a30Sjl } 3749*25cf1a30Sjl 3750*25cf1a30Sjl static void 3751*25cf1a30Sjl drmach_swap_pa(drmach_mem_t *s_mem, drmach_mem_t *t_mem) 3752*25cf1a30Sjl { 3753*25cf1a30Sjl uint64_t s_base, t_base; 3754*25cf1a30Sjl drmach_board_t *s_board, *t_board; 3755*25cf1a30Sjl struct memlist *ml; 3756*25cf1a30Sjl 3757*25cf1a30Sjl s_board = s_mem->dev.bp; 3758*25cf1a30Sjl t_board = t_mem->dev.bp; 3759*25cf1a30Sjl if (s_board == NULL || t_board == NULL) { 3760*25cf1a30Sjl cmn_err(CE_PANIC, "Cannot locate source or target board\n"); 3761*25cf1a30Sjl return; 3762*25cf1a30Sjl } 3763*25cf1a30Sjl s_base = s_mem->slice_base; 3764*25cf1a30Sjl t_base = t_mem->slice_base; 3765*25cf1a30Sjl 3766*25cf1a30Sjl s_mem->slice_base = t_base; 3767*25cf1a30Sjl s_mem->base_pa = (s_mem->base_pa - s_base) + t_base; 3768*25cf1a30Sjl 3769*25cf1a30Sjl for (ml = s_mem->memlist; ml; ml = ml->next) { 3770*25cf1a30Sjl ml->address = ml->address - s_base + t_base; 3771*25cf1a30Sjl } 3772*25cf1a30Sjl 3773*25cf1a30Sjl t_mem->slice_base = s_base; 3774*25cf1a30Sjl t_mem->base_pa = (t_mem->base_pa - t_base) + s_base; 3775*25cf1a30Sjl 3776*25cf1a30Sjl for (ml = t_mem->memlist; ml; ml = ml->next) { 3777*25cf1a30Sjl ml->address = ml->address - t_base + s_base; 3778*25cf1a30Sjl } 3779*25cf1a30Sjl 3780*25cf1a30Sjl /* 3781*25cf1a30Sjl * IKP has to update the sb-mem-ranges for mac patrol driver 3782*25cf1a30Sjl * when it resumes, it will re-read the sb-mem-range property 3783*25cf1a30Sjl * to get the new base address 3784*25cf1a30Sjl */ 3785*25cf1a30Sjl if (oplcfg_pa_swap(s_board->bnum, t_board->bnum) != 0) 3786*25cf1a30Sjl cmn_err(CE_PANIC, "Could not update device nodes\n"); 3787*25cf1a30Sjl } 3788*25cf1a30Sjl 3789*25cf1a30Sjl void 3790*25cf1a30Sjl drmach_copy_rename(drmachid_t id) 3791*25cf1a30Sjl { 3792*25cf1a30Sjl drmach_copy_rename_program_t *prog = id; 3793*25cf1a30Sjl cpuset_t cpuset; 3794*25cf1a30Sjl int cpuid; 3795*25cf1a30Sjl uint64_t inst; 3796*25cf1a30Sjl register int rtn; 3797*25cf1a30Sjl extern int in_sync; 3798*25cf1a30Sjl int old_in_sync; 3799*25cf1a30Sjl extern void drmach_sys_trap(); 3800*25cf1a30Sjl extern void drmach_flush(); 3801*25cf1a30Sjl extern void drmach_flush_icache(); 3802*25cf1a30Sjl extern uint64_t patch_inst(uint64_t *, uint64_t); 3803*25cf1a30Sjl on_trap_data_t otd; 3804*25cf1a30Sjl 3805*25cf1a30Sjl if (prog->critical->scf_reg_base == (uint64_t)-1) { 3806*25cf1a30Sjl prog->data->fmem_status.error = FMEM_SCF_ERR; 3807*25cf1a30Sjl return; 3808*25cf1a30Sjl } 3809*25cf1a30Sjl 3810*25cf1a30Sjl kpreempt_disable(); 3811*25cf1a30Sjl cpuset = prog->data->cpu_ready_set; 3812*25cf1a30Sjl 3813*25cf1a30Sjl for (cpuid = 0; cpuid < NCPU; cpuid++) { 3814*25cf1a30Sjl if (CPU_IN_SET(cpuset, cpuid)) { 3815*25cf1a30Sjl prog->critical->stat[cpuid] = FMEM_LOOP_START; 3816*25cf1a30Sjl prog->data->error[cpuid] = FMEM_NO_ERROR; 3817*25cf1a30Sjl } 3818*25cf1a30Sjl } 3819*25cf1a30Sjl 3820*25cf1a30Sjl old_in_sync = in_sync; 3821*25cf1a30Sjl in_sync = 1; 3822*25cf1a30Sjl cpuid = CPU->cpu_id; 3823*25cf1a30Sjl 3824*25cf1a30Sjl CPUSET_DEL(cpuset, cpuid); 3825*25cf1a30Sjl 3826*25cf1a30Sjl xc_some(cpuset, (xcfunc_t *)drmach_lock_critical, 3827*25cf1a30Sjl (uint64_t)prog, (uint64_t)0); 3828*25cf1a30Sjl 3829*25cf1a30Sjl xt_some(cpuset, (xcfunc_t *)drmach_sys_trap, 3830*25cf1a30Sjl (uint64_t)drmach_copy_rename_slave, (uint64_t)prog); 3831*25cf1a30Sjl xt_sync(cpuset); 3832*25cf1a30Sjl 3833*25cf1a30Sjl (void) drmach_lock_critical((caddr_t)prog); 3834*25cf1a30Sjl 3835*25cf1a30Sjl if (on_trap(&otd, OT_DATA_EC)) { 3836*25cf1a30Sjl rtn = FMEM_COPY_ERROR; 3837*25cf1a30Sjl goto done; 3838*25cf1a30Sjl } 3839*25cf1a30Sjl 3840*25cf1a30Sjl flush_windows(); 3841*25cf1a30Sjl 3842*25cf1a30Sjl /* 3843*25cf1a30Sjl * jmp drmach_copy_rename_prog(). 3844*25cf1a30Sjl */ 3845*25cf1a30Sjl drmach_flush(prog->critical, PAGESIZE); 3846*25cf1a30Sjl rtn = prog->critical->run(prog, cpuid); 3847*25cf1a30Sjl drmach_flush_icache(); 3848*25cf1a30Sjl 3849*25cf1a30Sjl 3850*25cf1a30Sjl done: 3851*25cf1a30Sjl no_trap(); 3852*25cf1a30Sjl if (rtn == FMEM_HW_ERROR) { 3853*25cf1a30Sjl kpreempt_enable(); 3854*25cf1a30Sjl prom_panic("URGENT_ERROR_TRAP is " 3855*25cf1a30Sjl "detected during FMEM.\n"); 3856*25cf1a30Sjl } 3857*25cf1a30Sjl 3858*25cf1a30Sjl /* 3859*25cf1a30Sjl * In normal case, all slave CPU's are still spinning in 3860*25cf1a30Sjl * the assembly code. The master has to patch the instruction 3861*25cf1a30Sjl * to get them out. 3862*25cf1a30Sjl * In error case, e.g. COPY_ERROR, some slave CPU's might 3863*25cf1a30Sjl * have aborted and already returned and sset LOOP_EXIT status. 3864*25cf1a30Sjl * Some CPU might still be copying. 3865*25cf1a30Sjl * In any case, some delay is necessary to give them 3866*25cf1a30Sjl * enough time to set the LOOP_EXIT status. 3867*25cf1a30Sjl */ 3868*25cf1a30Sjl 3869*25cf1a30Sjl for (;;) { 3870*25cf1a30Sjl inst = patch_inst((uint64_t *)prog->critical->loop_rtn, 3871*25cf1a30Sjl prog->critical->inst_loop_ret); 3872*25cf1a30Sjl if (prog->critical->inst_loop_ret == inst) { 3873*25cf1a30Sjl break; 3874*25cf1a30Sjl } 3875*25cf1a30Sjl } 3876*25cf1a30Sjl 3877*25cf1a30Sjl for (cpuid = 0; cpuid < NCPU; cpuid++) { 3878*25cf1a30Sjl uint64_t last, now; 3879*25cf1a30Sjl if (!CPU_IN_SET(cpuset, cpuid)) { 3880*25cf1a30Sjl continue; 3881*25cf1a30Sjl } 3882*25cf1a30Sjl last = prog->stat->nbytes[cpuid]; 3883*25cf1a30Sjl /* 3884*25cf1a30Sjl * Wait for all CPU to exit. 3885*25cf1a30Sjl * However we do not want an infinite loop 3886*25cf1a30Sjl * so we detect hangup situation here. 3887*25cf1a30Sjl * If the slave CPU is still copying data, 3888*25cf1a30Sjl * we will continue to wait. 3889*25cf1a30Sjl * In error cases, the master has already set 3890*25cf1a30Sjl * fmem_status.error to abort the copying. 3891*25cf1a30Sjl * 1 m.s delay for them to abort copying and 3892*25cf1a30Sjl * return to drmach_copy_rename_slave to set 3893*25cf1a30Sjl * FMEM_LOOP_EXIT status should be enough. 3894*25cf1a30Sjl */ 3895*25cf1a30Sjl for (;;) { 3896*25cf1a30Sjl if (prog->critical->stat[cpuid] == FMEM_LOOP_EXIT) 3897*25cf1a30Sjl break; 3898*25cf1a30Sjl drmach_sleep_il(); 3899*25cf1a30Sjl drv_usecwait(1000); 3900*25cf1a30Sjl now = prog->stat->nbytes[cpuid]; 3901*25cf1a30Sjl if (now <= last) { 3902*25cf1a30Sjl drv_usecwait(1000); 3903*25cf1a30Sjl if (prog->critical->stat[cpuid] == FMEM_LOOP_EXIT) 3904*25cf1a30Sjl break; 3905*25cf1a30Sjl cmn_err(CE_PANIC, 3906*25cf1a30Sjl "CPU %d hang during Copy Rename", cpuid); 3907*25cf1a30Sjl } 3908*25cf1a30Sjl last = now; 3909*25cf1a30Sjl } 3910*25cf1a30Sjl if (prog->data->error[cpuid] == FMEM_HW_ERROR) { 3911*25cf1a30Sjl prom_panic("URGENT_ERROR_TRAP is " 3912*25cf1a30Sjl "detected during FMEM.\n"); 3913*25cf1a30Sjl } 3914*25cf1a30Sjl } 3915*25cf1a30Sjl drmach_unlock_critical((caddr_t)prog); 3916*25cf1a30Sjl 3917*25cf1a30Sjl in_sync = old_in_sync; 3918*25cf1a30Sjl 3919*25cf1a30Sjl kpreempt_enable(); 3920*25cf1a30Sjl if (prog->data->fmem_status.error == 0) 3921*25cf1a30Sjl prog->data->fmem_status.error = rtn; 3922*25cf1a30Sjl 3923*25cf1a30Sjl if (prog->data->copy_wait_time > 0) { 3924*25cf1a30Sjl DRMACH_PR("Unexpected long wait time %ld seconds " 3925*25cf1a30Sjl "during copy rename on CPU %d\n", 3926*25cf1a30Sjl prog->data->copy_wait_time/prog->data->stick_freq, 3927*25cf1a30Sjl prog->data->slowest_cpuid); 3928*25cf1a30Sjl } 3929*25cf1a30Sjl } 3930