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