xref: /onnv-gate/usr/src/uts/sun4u/starfire/io/idn_xf.c (revision 11066:cebb50cbe4f9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*11066Srafael.vanoni@sun.com  * Common Development and Distribution License (the "License").
6*11066Srafael.vanoni@sun.com  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*11066Srafael.vanoni@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*11066Srafael.vanoni@sun.com  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/sysmacros.h>
280Sstevel@tonic-gate #include <sys/open.h>
290Sstevel@tonic-gate #include <sys/param.h>
300Sstevel@tonic-gate #include <sys/vm_machparam.h>
310Sstevel@tonic-gate #include <sys/machparam.h>
320Sstevel@tonic-gate #include <sys/systm.h>
330Sstevel@tonic-gate #include <sys/signal.h>
340Sstevel@tonic-gate #include <sys/cred.h>
350Sstevel@tonic-gate #include <sys/user.h>
360Sstevel@tonic-gate #include <sys/proc.h>
370Sstevel@tonic-gate #include <sys/vnode.h>
380Sstevel@tonic-gate #include <sys/uio.h>
390Sstevel@tonic-gate #include <sys/buf.h>
400Sstevel@tonic-gate #include <sys/file.h>
410Sstevel@tonic-gate #include <sys/kmem.h>
420Sstevel@tonic-gate #include <sys/stat.h>
430Sstevel@tonic-gate #include <sys/stream.h>
440Sstevel@tonic-gate #include <sys/stropts.h>
450Sstevel@tonic-gate #include <sys/strsubr.h>
460Sstevel@tonic-gate #include <sys/poll.h>
470Sstevel@tonic-gate #include <sys/debug.h>
480Sstevel@tonic-gate #include <sys/conf.h>
490Sstevel@tonic-gate #include <sys/ddi.h>
500Sstevel@tonic-gate #include <sys/sunddi.h>
510Sstevel@tonic-gate #include <sys/errno.h>
520Sstevel@tonic-gate #include <sys/modctl.h>
530Sstevel@tonic-gate #include <sys/x_call.h>
540Sstevel@tonic-gate #include <sys/cpuvar.h>
550Sstevel@tonic-gate #include <sys/machcpuvar.h>
560Sstevel@tonic-gate #include <sys/machsystm.h>
570Sstevel@tonic-gate 
580Sstevel@tonic-gate #include <sys/pda.h>
590Sstevel@tonic-gate #include <sys/starfire.h>
600Sstevel@tonic-gate #include <sys/idn.h>
610Sstevel@tonic-gate #include <sys/idn_xf.h>
620Sstevel@tonic-gate 
630Sstevel@tonic-gate kmutex_t	idn_xf_mutex;		/* to serialize hardware access */
640Sstevel@tonic-gate /*
650Sstevel@tonic-gate  * This data structure is referenced during the cross-call
660Sstevel@tonic-gate  * update of the CICs.  The semaphore is used for synchronization
670Sstevel@tonic-gate  * when waiting for completion of the respective operation.
680Sstevel@tonic-gate  * We want IDNCIC_TIMEOUT ticks for all the cpus to check-in
690Sstevel@tonic-gate  * before we bail out and fail the operation.
700Sstevel@tonic-gate  */
710Sstevel@tonic-gate #define	IDNCIC_TIMEOUT		(30*hz)
720Sstevel@tonic-gate #define	IDNCIC_TIMECHK		(hz/3)
730Sstevel@tonic-gate #define	IDNCIC_UNKNOWN		0
740Sstevel@tonic-gate #define	IDNCIC_OK		1	/* values for xf_errcic */
750Sstevel@tonic-gate #define	IDNCIC_ERR		2
760Sstevel@tonic-gate #define	IDNCIC_BUSY		3
770Sstevel@tonic-gate 
780Sstevel@tonic-gate #ifdef DEBUG
790Sstevel@tonic-gate #define	NCICREGS		3	/* smmask, smbar, smlar */
800Sstevel@tonic-gate #define	CICREG_SMMASK		0
810Sstevel@tonic-gate #define	CICREG_SMBAR		1
820Sstevel@tonic-gate #define	CICREG_SMLAR		2
830Sstevel@tonic-gate 
840Sstevel@tonic-gate #define	RESET_CIC_HISTORY() \
850Sstevel@tonic-gate 		(xf_cicboards = xf_cicbuses = 0, \
860Sstevel@tonic-gate 		bzero(xf_cicregs, sizeof (xf_cicregs)))
870Sstevel@tonic-gate 
880Sstevel@tonic-gate #define	UPDATE_CIC_HISTORY(reg, brd, bus, val) \
890Sstevel@tonic-gate 		(BOARDSET_ADD(xf_cicboards, (brd)), \
900Sstevel@tonic-gate 		BOARDSET_ADD(xf_cicbuses, (bus)), \
910Sstevel@tonic-gate 		xf_cicregs[brd][bus][reg] = (val))
920Sstevel@tonic-gate 
930Sstevel@tonic-gate #define	DUMP_CIC_HISTORY() \
940Sstevel@tonic-gate { \
950Sstevel@tonic-gate 	if (idn_debug & IDNDBG_XF) { \
960Sstevel@tonic-gate 		int	_bd, _bs; \
970Sstevel@tonic-gate 		procname_t	_proc = "dump_cic_history"; \
980Sstevel@tonic-gate 		for (_bd = 0; _bd < MAX_BOARDS; _bd++) { \
990Sstevel@tonic-gate 			if (!BOARD_IN_SET(xf_cicboards, _bd)) \
1000Sstevel@tonic-gate 				continue; \
1010Sstevel@tonic-gate 			for (_bs = 0; _bs < MAX_ABUSES; _bs++) { \
1020Sstevel@tonic-gate 				if (!BOARD_IN_SET(xf_cicbuses, _bs)) \
1030Sstevel@tonic-gate 					continue; \
1040Sstevel@tonic-gate 				printf("%s: (bd.bs = %d.%d) m/b/l = " \
1050Sstevel@tonic-gate 					"%x/%x/%x\n", _proc, _bd, _bs, \
1060Sstevel@tonic-gate 					xf_cicregs[_bd][_bs][CICREG_SMMASK], \
1070Sstevel@tonic-gate 					xf_cicregs[_bd][_bs][CICREG_SMBAR], \
1080Sstevel@tonic-gate 					xf_cicregs[_bd][_bs][CICREG_SMLAR]); \
1090Sstevel@tonic-gate 			} \
1100Sstevel@tonic-gate 		} \
1110Sstevel@tonic-gate 		DEBUG_DELAY(); \
1120Sstevel@tonic-gate 	} \
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate /*
1160Sstevel@tonic-gate  * Globally updated during CIC reg updates.  Everybody has
1170Sstevel@tonic-gate  * a unique location, so no concern about updates stepping
1180Sstevel@tonic-gate  * on each other.
1190Sstevel@tonic-gate  */
1200Sstevel@tonic-gate static ushort_t	xf_cicboards, xf_cicbuses;
1210Sstevel@tonic-gate static uint_t	xf_cicregs[MAX_BOARDS][MAX_ABUSES][NCICREGS];
1220Sstevel@tonic-gate #else /* DEBUG */
1230Sstevel@tonic-gate #define	RESET_CIC_HISTORY()
1240Sstevel@tonic-gate #define	UPDATE_CIC_HISTORY(reg, brd, bus, val)
1250Sstevel@tonic-gate #define	DUMP_CIC_HISTORY()
1260Sstevel@tonic-gate #endif /* DEBUG */
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate struct idnxf_cic_info {			/* protected by idn_xf_mutex */
1290Sstevel@tonic-gate /*  0 */	short		xf_abus_mask;
1300Sstevel@tonic-gate /*  2 */	boardset_t	xf_boardset;
1310Sstevel@tonic-gate /*  4 */	uint_t		xf_smbase;
1320Sstevel@tonic-gate /*  8 */	uint_t		xf_smlimit;
1330Sstevel@tonic-gate /*  c */	int		xf_doadd;
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate /* 10 */	int		xf_count;	/* atomically updated */
1360Sstevel@tonic-gate /* 14 */	time_t		xf_start_time;
1370Sstevel@tonic-gate /* 18 */	kcondvar_t	xf_cv;
1380Sstevel@tonic-gate /* 1a */	short		xf_errtimer;
1390Sstevel@tonic-gate /* 1c */	int		xf_errcnt;	/* atomically updated */
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate /* 20 */	uchar_t		xf_errcic[MAX_BOARDS][MAX_ABUSES];
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate /* 60 */	kmutex_t	xf_mutex;
1440Sstevel@tonic-gate };	/* sizeof = 0x68 = 104 (26X) */
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate static struct idnxf_cic_info	idnxf_cic_info;
1470Sstevel@tonic-gate #ifdef DEBUG
1480Sstevel@tonic-gate static uint_t			o_idn_debug;
1490Sstevel@tonic-gate #endif /* DEBUG */
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate int	idn_check_cpu_per_board = 1;
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate static int	pc_prep_cic_buffer(int cpuid, uint_t cicdata);
1540Sstevel@tonic-gate static int	cic_write_sm_mask(int board, int bus, boardset_t sm_mask);
1550Sstevel@tonic-gate static int	cic_write_sm_bar(int board, int bus, uint_t sm_bar);
1560Sstevel@tonic-gate static int	cic_write_sm_lar(int board, int bus, uint_t sm_lar);
1570Sstevel@tonic-gate static int	cic_get_smmask_bit(void);
1580Sstevel@tonic-gate static int	pc_write_madr(pda_handle_t ph,
1590Sstevel@tonic-gate 				int lboard, int rboard, uint_t madr);
1600Sstevel@tonic-gate static boardset_t	get_boardset(pda_handle_t ph, int *nboards);
1610Sstevel@tonic-gate static int	verify_smregs(int brd, int bus, boardset_t smmask,
1620Sstevel@tonic-gate 				uint_t smbase, uint_t smlimit);
1630Sstevel@tonic-gate static void	idnxf_shmem_wakeup(void *arg);
1640Sstevel@tonic-gate static void	idnxf_shmem_update_one(uint64_t arg1, uint64_t arg2);
1650Sstevel@tonic-gate static int	idnxf_shmem_update_all(pda_handle_t ph,
1660Sstevel@tonic-gate 				boardset_t boardset, uint_t smbase,
1670Sstevel@tonic-gate 				uint_t smlimit, int doadd);
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate #define	PHYSIO_ST(paddr, val)		(stphysio((paddr), (val)))
1700Sstevel@tonic-gate #define	PHYSIO_LD(paddr)		(ldphysio(paddr))
1710Sstevel@tonic-gate #define	PHYSIO_STH(paddr, val)		(sthphysio((paddr), (val)))
1720Sstevel@tonic-gate #define	PHYSIO_LDH(paddr)		(ldhphysio(paddr))
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate #ifdef DEBUG
1750Sstevel@tonic-gate #define	DEBUG_DELAY() 	(drv_usecwait(5000))	/* 5 ms */
1760Sstevel@tonic-gate #else /* DEBUG */
1770Sstevel@tonic-gate #define	DEBUG_DELAY()
1780Sstevel@tonic-gate #endif /* DEBUG */
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate /*
1820Sstevel@tonic-gate  * ---------------------------------------------------------------------
1830Sstevel@tonic-gate  */
1840Sstevel@tonic-gate boardset_t
cic_read_domain_mask(int board,int bus)1850Sstevel@tonic-gate cic_read_domain_mask(int board, int bus)
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate 	u_longlong_t	csr_addr;
1880Sstevel@tonic-gate 	boardset_t	domain_mask;
1890Sstevel@tonic-gate 	procname_t	proc = "cic_read_domain_mask";
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	ASSERT(CPUID_TO_BOARDID(CPU->cpu_id) == board);
1920Sstevel@tonic-gate 
193*11066Srafael.vanoni@sun.com 	csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_DOMAIN_MASK_ADDR,
194*11066Srafael.vanoni@sun.com 	    bus);
1950Sstevel@tonic-gate 	PR_XF("%s: (bd=%d, bs=%d) csr_addr = 0x%llx\n",
196*11066Srafael.vanoni@sun.com 	    proc, board, bus, csr_addr);
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	domain_mask = (boardset_t)PHYSIO_LDH(csr_addr);
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	return (domain_mask);
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate boardset_t
cic_read_sm_mask(int board,int bus)2040Sstevel@tonic-gate cic_read_sm_mask(int board, int bus)
2050Sstevel@tonic-gate {
2060Sstevel@tonic-gate 	u_longlong_t	csr_addr;
2070Sstevel@tonic-gate 	boardset_t	sm_mask;
2080Sstevel@tonic-gate 	procname_t	proc = "cic_read_sm_mask";
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	ASSERT(CPUID_TO_BOARDID(CPU->cpu_id) == board);
2110Sstevel@tonic-gate 
212*11066Srafael.vanoni@sun.com 	csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_MASK_ADDR,
213*11066Srafael.vanoni@sun.com 	    bus);
2140Sstevel@tonic-gate 	PR_XF("%s: (bd=%d, bs=%d) csr_addr = 0x%llx\n",
215*11066Srafael.vanoni@sun.com 	    proc, board, bus, csr_addr);
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	sm_mask = (boardset_t)PHYSIO_LDH(csr_addr);
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	return (sm_mask);
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate static int
cic_write_sm_mask(int board,int bus,boardset_t sm_mask)2230Sstevel@tonic-gate cic_write_sm_mask(int board, int bus, boardset_t sm_mask)
2240Sstevel@tonic-gate {
2250Sstevel@tonic-gate 	u_longlong_t	csr_addr;
2260Sstevel@tonic-gate 	int		cnt;
2270Sstevel@tonic-gate 	procname_t	proc = "cic_write_sm_mask";
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	ASSERT(CPUID_TO_BOARDID(CPU->cpu_id) == board);
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	sm_mask &= 0xffff;
2320Sstevel@tonic-gate 	/*
2330Sstevel@tonic-gate 	 * Before we can write to the CIC, we need to set
2340Sstevel@tonic-gate 	 * up the CIC write data buffer in the PC.
2350Sstevel@tonic-gate 	 */
2360Sstevel@tonic-gate 	if (pc_prep_cic_buffer(CPU->cpu_id, (uint_t)sm_mask) < 0)
2370Sstevel@tonic-gate 		return (-1);
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	/*
2400Sstevel@tonic-gate 	 * Now we can write to the CIC.
2410Sstevel@tonic-gate 	 */
242*11066Srafael.vanoni@sun.com 	csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_MASK_ADDR,
243*11066Srafael.vanoni@sun.com 	    bus);
2440Sstevel@tonic-gate 	PR_XF("%s: (bd=%d, bs=%d) csr_addr = 0x%llx\n",
245*11066Srafael.vanoni@sun.com 	    proc, board, bus, csr_addr);
2460Sstevel@tonic-gate 	PR_XF("%s: writing sm_mask = 0x%x\n",
247*11066Srafael.vanoni@sun.com 	    proc, (ushort_t)sm_mask);
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	UPDATE_CIC_HISTORY(CICREG_SMMASK, board, bus, sm_mask);
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	PHYSIO_STH(csr_addr, (ushort_t)sm_mask);
2520Sstevel@tonic-gate 	/*
2530Sstevel@tonic-gate 	 * Read back for verification.
2540Sstevel@tonic-gate 	 */
2550Sstevel@tonic-gate 	for (cnt = 0; (PHYSIO_LDH(csr_addr) != sm_mask) && (cnt < 10); cnt++)
2560Sstevel@tonic-gate 		;
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	return ((cnt == 10) ? -1 : 0);
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate uint_t
cic_read_sm_bar(int board,int bus)2620Sstevel@tonic-gate cic_read_sm_bar(int board, int bus)
2630Sstevel@tonic-gate {
2640Sstevel@tonic-gate 	u_longlong_t	csr_addr;
2650Sstevel@tonic-gate 	uint_t		sm_bar;
2660Sstevel@tonic-gate 	procname_t	proc = "cic_read_sm_bar";
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	ASSERT(CPUID_TO_BOARDID(CPU->cpu_id) == board);
2690Sstevel@tonic-gate 
270*11066Srafael.vanoni@sun.com 	csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_BAR_MSB_ADDR,
271*11066Srafael.vanoni@sun.com 	    bus);
2720Sstevel@tonic-gate 	PR_XF("%s:MSB: (bd=%d, bs=%d) csr_addr = 0x%llx\n",
273*11066Srafael.vanoni@sun.com 	    proc, board, bus, csr_addr);
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	sm_bar = (uint_t)PHYSIO_LDH(csr_addr);
2760Sstevel@tonic-gate 	sm_bar <<= 16;
2770Sstevel@tonic-gate 
278*11066Srafael.vanoni@sun.com 	csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_BAR_LSB_ADDR,
279*11066Srafael.vanoni@sun.com 	    bus);
2800Sstevel@tonic-gate 	PR_XF("%s:LSB: (bd=%d, bs=%d) csr_addr = 0x%llx\n",
281*11066Srafael.vanoni@sun.com 	    proc, board, bus, csr_addr);
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	sm_bar |= (uint_t)PHYSIO_LDH(csr_addr);
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	return (sm_bar);
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate static int
cic_write_sm_bar(int board,int bus,uint_t sm_bar)2890Sstevel@tonic-gate cic_write_sm_bar(int board, int bus, uint_t sm_bar)
2900Sstevel@tonic-gate {
2910Sstevel@tonic-gate 	int		cnt;
2920Sstevel@tonic-gate 	u_longlong_t	csr_addr;
2930Sstevel@tonic-gate 	uint_t		sm_bar_lsb, sm_bar_msb;
2940Sstevel@tonic-gate 	procname_t	proc = "cic_write_sm_bar";
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	ASSERT(CPUID_TO_BOARDID(CPU->cpu_id) == board);
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	sm_bar_lsb = sm_bar & 0xffff;
2990Sstevel@tonic-gate 	sm_bar_msb = (sm_bar >> 16) & 0xffff;
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	/*
3020Sstevel@tonic-gate 	 * Before we can write to the CIC, we need to set
3030Sstevel@tonic-gate 	 * up the CIC write data buffer in the PC.
3040Sstevel@tonic-gate 	 */
3050Sstevel@tonic-gate 	if (pc_prep_cic_buffer(CPU->cpu_id, sm_bar_msb) < 0)
3060Sstevel@tonic-gate 		return (-1);
3070Sstevel@tonic-gate 
308*11066Srafael.vanoni@sun.com 	csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_BAR_MSB_ADDR,
309*11066Srafael.vanoni@sun.com 	    bus);
3100Sstevel@tonic-gate 	PR_XF("%s:MSB: (bd=%d, bs=%d) csr_addr = 0x%llx\n",
311*11066Srafael.vanoni@sun.com 	    proc, board, bus, csr_addr);
3120Sstevel@tonic-gate 	PR_XF("%s:MSB: sm_bar[31:16] = 0x%x\n",
313*11066Srafael.vanoni@sun.com 	    proc, (ushort_t)sm_bar_msb);
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	UPDATE_CIC_HISTORY(CICREG_SMBAR, board, bus, sm_bar);
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	PHYSIO_STH(csr_addr, (ushort_t)sm_bar_msb);
3180Sstevel@tonic-gate 	for (cnt = 0;
3190Sstevel@tonic-gate 	    ((uint_t)PHYSIO_LDH(csr_addr) != sm_bar_msb) && (cnt < 10);
3200Sstevel@tonic-gate 	    cnt++)
3210Sstevel@tonic-gate 		;
3220Sstevel@tonic-gate 	if (cnt == 10) {
3230Sstevel@tonic-gate 		cmn_err(CE_WARN,
324*11066Srafael.vanoni@sun.com 		    "IDN: 500: failed to write sm_bar (msb) (0x%x)",
325*11066Srafael.vanoni@sun.com 		    (uint_t)sm_bar_msb);
3260Sstevel@tonic-gate 		return (-1);
3270Sstevel@tonic-gate 	}
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	/*
3300Sstevel@tonic-gate 	 * Now to LSB portion.
3310Sstevel@tonic-gate 	 */
3320Sstevel@tonic-gate 	if (pc_prep_cic_buffer(CPU->cpu_id, sm_bar_lsb) < 0)
3330Sstevel@tonic-gate 		return (-1);
3340Sstevel@tonic-gate 
335*11066Srafael.vanoni@sun.com 	csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_BAR_LSB_ADDR,
336*11066Srafael.vanoni@sun.com 	    bus);
3370Sstevel@tonic-gate 	PR_XF("%s:LSB: (bd=%d, bs=%d) csr_addr = 0x%llx\n",
338*11066Srafael.vanoni@sun.com 	    proc, board, bus, csr_addr);
3390Sstevel@tonic-gate 	PR_XF("%s:LSB: sm_bar[15:0] = 0x%x\n",
340*11066Srafael.vanoni@sun.com 	    proc, (ushort_t)sm_bar_lsb);
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	PHYSIO_STH(csr_addr, (ushort_t)sm_bar_lsb);
3430Sstevel@tonic-gate 	for (cnt = 0;
3440Sstevel@tonic-gate 	    ((uint_t)PHYSIO_LDH(csr_addr) != sm_bar_lsb) && (cnt < 10);
3450Sstevel@tonic-gate 	    cnt++)
3460Sstevel@tonic-gate 		;
3470Sstevel@tonic-gate 	if (cnt == 10) {
3480Sstevel@tonic-gate 		cmn_err(CE_WARN,
349*11066Srafael.vanoni@sun.com 		    "IDN: 500: failed to write sm_bar (lsb) (0x%x)",
350*11066Srafael.vanoni@sun.com 		    (uint_t)sm_bar_lsb);
3510Sstevel@tonic-gate 		return (-1);
3520Sstevel@tonic-gate 	}
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	return (0);
3550Sstevel@tonic-gate }
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate uint_t
cic_read_sm_lar(int board,int bus)3580Sstevel@tonic-gate cic_read_sm_lar(int board, int bus)
3590Sstevel@tonic-gate {
3600Sstevel@tonic-gate 	u_longlong_t	csr_addr;
3610Sstevel@tonic-gate 	uint_t		sm_lar;
3620Sstevel@tonic-gate 	procname_t	proc = "cic_read_sm_lar";
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	ASSERT(CPUID_TO_BOARDID(CPU->cpu_id) == board);
3650Sstevel@tonic-gate 
366*11066Srafael.vanoni@sun.com 	csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_LAR_MSB_ADDR,
367*11066Srafael.vanoni@sun.com 	    bus);
3680Sstevel@tonic-gate 	PR_XF("%s:MSB: (bd=%d, bs=%d) csr_addr = 0x%llx\n",
369*11066Srafael.vanoni@sun.com 	    proc, board, bus, csr_addr);
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	sm_lar = (uint_t)PHYSIO_LDH(csr_addr);
3720Sstevel@tonic-gate 	sm_lar <<= 16;
3730Sstevel@tonic-gate 
374*11066Srafael.vanoni@sun.com 	csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_LAR_LSB_ADDR,
375*11066Srafael.vanoni@sun.com 	    bus);
3760Sstevel@tonic-gate 	PR_XF("%s:LSB: (bd=%d, bs=%d) csr_addr = 0x%llx\n",
377*11066Srafael.vanoni@sun.com 	    proc, board, bus, csr_addr);
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	sm_lar |= (uint_t)PHYSIO_LDH(csr_addr);
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	return (sm_lar);
3820Sstevel@tonic-gate }
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate static int
cic_write_sm_lar(int board,int bus,uint_t sm_lar)3850Sstevel@tonic-gate cic_write_sm_lar(int board, int bus, uint_t sm_lar)
3860Sstevel@tonic-gate {
3870Sstevel@tonic-gate 	int		cnt;
3880Sstevel@tonic-gate 	u_longlong_t	csr_addr;
3890Sstevel@tonic-gate 	uint_t		sm_lar_lsb, sm_lar_msb;
3900Sstevel@tonic-gate 	procname_t	proc = "cic_write_sm_lar";
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	ASSERT(CPUID_TO_BOARDID(CPU->cpu_id) == board);
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	sm_lar_lsb = sm_lar & 0xffff;
3950Sstevel@tonic-gate 	sm_lar_msb = (sm_lar >> 16) & 0xffff;
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	/*
3980Sstevel@tonic-gate 	 * Before we can write to the CIC, we need to set
3990Sstevel@tonic-gate 	 * up the CIC write data buffer in the PC.
4000Sstevel@tonic-gate 	 */
4010Sstevel@tonic-gate 	if (pc_prep_cic_buffer(CPU->cpu_id, sm_lar_msb) < 0)
4020Sstevel@tonic-gate 		return (-1);
4030Sstevel@tonic-gate 
404*11066Srafael.vanoni@sun.com 	csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_LAR_MSB_ADDR,
405*11066Srafael.vanoni@sun.com 	    bus);
4060Sstevel@tonic-gate 	PR_XF("%s:MSB: (bd=%d, bs=%d) csr_addr = 0x%llx\n",
407*11066Srafael.vanoni@sun.com 	    proc, board, bus, csr_addr);
4080Sstevel@tonic-gate 	PR_XF("%s:MSB: sm_lar[31:16] = 0x%x\n",
409*11066Srafael.vanoni@sun.com 	    proc, (ushort_t)sm_lar_msb);
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	UPDATE_CIC_HISTORY(CICREG_SMLAR, board, bus, sm_lar);
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	PHYSIO_STH(csr_addr, (ushort_t)sm_lar_msb);
4140Sstevel@tonic-gate 	for (cnt = 0;
4150Sstevel@tonic-gate 	    ((uint_t)PHYSIO_LDH(csr_addr) != sm_lar_msb) && (cnt < 10);
4160Sstevel@tonic-gate 	    cnt++)
4170Sstevel@tonic-gate 		;
4180Sstevel@tonic-gate 	if (cnt == 10) {
4190Sstevel@tonic-gate 		cmn_err(CE_WARN,
420*11066Srafael.vanoni@sun.com 		    "IDN: 501: failed to write sm_lar (msb) (0x%x)",
421*11066Srafael.vanoni@sun.com 		    (uint_t)sm_lar_msb);
4220Sstevel@tonic-gate 		return (-1);
4230Sstevel@tonic-gate 	}
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	/*
4260Sstevel@tonic-gate 	 * Now to LSB portion.
4270Sstevel@tonic-gate 	 */
4280Sstevel@tonic-gate 	if (pc_prep_cic_buffer(CPU->cpu_id, sm_lar_lsb) < 0)
4290Sstevel@tonic-gate 		return (-1);
4300Sstevel@tonic-gate 
431*11066Srafael.vanoni@sun.com 	csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_SM_LAR_LSB_ADDR,
432*11066Srafael.vanoni@sun.com 	    bus);
4330Sstevel@tonic-gate 	PR_XF("%s:LSB: (bd=%d, bs=%d) csr_addr = 0x%llx\n",
434*11066Srafael.vanoni@sun.com 	    proc, board, bus, csr_addr);
4350Sstevel@tonic-gate 	PR_XF("%s:LSB: sm_lar[15:0] = 0x%x\n",
436*11066Srafael.vanoni@sun.com 	    proc, (ushort_t)sm_lar_lsb);
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	PHYSIO_STH(csr_addr, (ushort_t)sm_lar_lsb);
4390Sstevel@tonic-gate 	for (cnt = 0;
4400Sstevel@tonic-gate 	    ((uint_t)PHYSIO_LDH(csr_addr) != sm_lar_lsb) && (cnt < 10);
4410Sstevel@tonic-gate 	    cnt++)
4420Sstevel@tonic-gate 		;
4430Sstevel@tonic-gate 	if (cnt == 10) {
4440Sstevel@tonic-gate 		cmn_err(CE_WARN,
445*11066Srafael.vanoni@sun.com 		    "IDN: 501: failed to write sm_lar (lsb) (0x%x)",
446*11066Srafael.vanoni@sun.com 		    (uint_t)sm_lar_lsb);
4470Sstevel@tonic-gate 		return (-1);
4480Sstevel@tonic-gate 	}
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	return (0);
4510Sstevel@tonic-gate }
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate static int
cic_get_smmask_bit(void)4540Sstevel@tonic-gate cic_get_smmask_bit(void)
4550Sstevel@tonic-gate {
4560Sstevel@tonic-gate 	u_longlong_t	csr_addr;
4570Sstevel@tonic-gate 	int		board;
4580Sstevel@tonic-gate 	uint_t		config1;
4590Sstevel@tonic-gate 	procname_t	proc = "cic_get_smmask_bit";
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	affinity_set(CPU_CURRENT);
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	board = CPUID_TO_BOARDID(CPU->cpu_id);
4640Sstevel@tonic-gate 	/*
4650Sstevel@tonic-gate 	 * Now that I'm stuck on this cpu I can go look at this
4660Sstevel@tonic-gate 	 * board's CIC registers.
4670Sstevel@tonic-gate 	 */
468*11066Srafael.vanoni@sun.com 	csr_addr = MAKE_CIC_CSR_PA(board, CSR_TYPE_CIC, CIC_CONFIG1_ADDR, 0);
4690Sstevel@tonic-gate 	PR_XF("%s: (bd=%d) csr_addr = 0x%llx (via cpu %d)\n",
470*11066Srafael.vanoni@sun.com 	    proc, board, csr_addr, (int)CPU->cpu_id);
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	config1 = (uint_t)PHYSIO_LDH(csr_addr);
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	config1 = CIC_CONFIG1_SMMASK_BIT(config1);
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	affinity_clear();
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	return (config1);
4790Sstevel@tonic-gate }
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate static int
pc_prep_cic_buffer(int cpuid,uint_t cicdata)4820Sstevel@tonic-gate pc_prep_cic_buffer(int cpuid, uint_t cicdata)
4830Sstevel@tonic-gate {
4840Sstevel@tonic-gate 	int		rv;
4850Sstevel@tonic-gate 	int		brd, port;
4860Sstevel@tonic-gate 	u_longlong_t	csr_addr;
4870Sstevel@tonic-gate 	register int	cnt;
4880Sstevel@tonic-gate 	procname_t	proc = "pc_prep_cic_buffer";
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	ASSERT(CPU->cpu_id == cpuid);
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	port = cpuid % plat_max_cpu_units_per_board();
4940Sstevel@tonic-gate 	brd = CPUID_TO_BOARDID(cpuid);
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	csr_addr = STARFIRE_PC_CICBUF_ADDR(brd, port);
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	/*
4990Sstevel@tonic-gate 	 * csr_addr now points to CIC write buffer which resides
5000Sstevel@tonic-gate 	 * in PC register space.
5010Sstevel@tonic-gate 	 */
5020Sstevel@tonic-gate 	PR_XF("%s: (cpu=%d) csr_addr = 0x%llx\n", proc, cpuid, csr_addr);
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	PHYSIO_ST(csr_addr, cicdata);
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	/*
5070Sstevel@tonic-gate 	 * Now we need to read back the data to guarantee
5080Sstevel@tonic-gate 	 * it got there.  Part of the PC protocol.
5090Sstevel@tonic-gate 	 */
5100Sstevel@tonic-gate 	for (cnt = 0; (PHYSIO_LD(csr_addr) != cicdata) && (cnt < 10);
5110Sstevel@tonic-gate 	    cnt++)
5120Sstevel@tonic-gate 		;
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	rv = 0;
5150Sstevel@tonic-gate 	if (cnt == 10) {
5160Sstevel@tonic-gate 		cmn_err(CE_WARN,
517*11066Srafael.vanoni@sun.com 		    "IDN: 502: unable to store data (0x%x) to "
518*11066Srafael.vanoni@sun.com 		    "CIC buffer (0x%llx)",
519*11066Srafael.vanoni@sun.com 		    cicdata, csr_addr);
5200Sstevel@tonic-gate 		rv = -1;
5210Sstevel@tonic-gate 	} else if (cnt >= 1) {
5220Sstevel@tonic-gate 		PR_XF("%s: MULTIPLE READS (cpu=%d) cnt = %d\n",
523*11066Srafael.vanoni@sun.com 		    proc, cpuid, cnt);
5240Sstevel@tonic-gate 	}
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	return (rv);
5270Sstevel@tonic-gate }
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate /*
5300Sstevel@tonic-gate  * --------------------------------------------------
5310Sstevel@tonic-gate  * Write the given MC address decoding register contents (madr) of
5320Sstevel@tonic-gate  * the respective remote board (rboard) into all the PCs located on
5330Sstevel@tonic-gate  * the local board (lboard).
5340Sstevel@tonic-gate  * --------------------------------------------------
5350Sstevel@tonic-gate  */
5360Sstevel@tonic-gate static int
pc_write_madr(pda_handle_t ph,int lboard,int rboard,uint_t madr)5370Sstevel@tonic-gate pc_write_madr(pda_handle_t ph, int lboard, int rboard, uint_t madr)
5380Sstevel@tonic-gate {
5390Sstevel@tonic-gate 	u_longlong_t	pc_madr_addr;
5400Sstevel@tonic-gate 	register int	p, ioc;
5410Sstevel@tonic-gate 	register ushort_t	procset, iocset;
5420Sstevel@tonic-gate 	int		rv = 0;
5430Sstevel@tonic-gate 	uint_t		rd_madr;
5440Sstevel@tonic-gate 	board_desc_t	*lbp;
5450Sstevel@tonic-gate 	procname_t	proc = "pc_write_madr";
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	lbp = pda_get_board_info(ph, lboard);
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	ASSERT(lbp);
5500Sstevel@tonic-gate 	ASSERT((lbp->bda_board & BDAN_MASK) == BDAN_GOOD);
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	procset = lbp->bda_proc;
5530Sstevel@tonic-gate 	iocset  = lbp->bda_ioc;
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	/*
5560Sstevel@tonic-gate 	 * Update the PCs for the cpus.
5570Sstevel@tonic-gate 	 */
5580Sstevel@tonic-gate 	for (p = 0; p < MAX_PROCMODS; procset >>= 4, p++) {
5590Sstevel@tonic-gate 		int	i;
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 		if (!((procset & BDAN_MASK) == BDAN_GOOD))
5620Sstevel@tonic-gate 			continue;
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 		pc_madr_addr = (u_longlong_t)STARFIRE_PC_MADR_ADDR(lboard,
565*11066Srafael.vanoni@sun.com 		    rboard, p);
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 		/*
5680Sstevel@tonic-gate 		 * On this first iteration of updating the PC
5690Sstevel@tonic-gate 		 * we need to turn off the MADR VALID bit so that
5700Sstevel@tonic-gate 		 * there's no accidental usage of the entry before
5710Sstevel@tonic-gate 		 * all four bytes have been updated in the PC.
5720Sstevel@tonic-gate 		 */
5730Sstevel@tonic-gate 		if (madr != 0) {
5740Sstevel@tonic-gate 			/*
5750Sstevel@tonic-gate 			 * Need to clear valid bit on first
5760Sstevel@tonic-gate 			 * go around.
5770Sstevel@tonic-gate 			 */
5780Sstevel@tonic-gate 			madr &= ~STARFIRE_PC_MADR_VALIDBIT;
5790Sstevel@tonic-gate 		}
5800Sstevel@tonic-gate 		PR_XF("%s: write madr(0x%x) to pc_addr(0x%llx) "
581*11066Srafael.vanoni@sun.com 		    "[lb=%d, rb=%d, cpu=%d]\n",
582*11066Srafael.vanoni@sun.com 		    proc, madr, pc_madr_addr, lboard, rboard, p);
5830Sstevel@tonic-gate 		DEBUG_DELAY();
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 		for (i = 0; i < 20; i++) {
5860Sstevel@tonic-gate 			PHYSIO_ST(pc_madr_addr, madr);
5870Sstevel@tonic-gate 			/*
5880Sstevel@tonic-gate 			 * Read back for sanity check.
5890Sstevel@tonic-gate 			 */
5900Sstevel@tonic-gate 			rd_madr = PHYSIO_LD(pc_madr_addr);
5910Sstevel@tonic-gate 			if (madr == rd_madr)
5920Sstevel@tonic-gate 				break;
5930Sstevel@tonic-gate 		}
5940Sstevel@tonic-gate 		if (i > 0) {
5950Sstevel@tonic-gate 			PR_XF("%s: WARNING: (1) lb=%d, rb=%d, "
596*11066Srafael.vanoni@sun.com 			    "madr=0x%x (i=%d)\n",
597*11066Srafael.vanoni@sun.com 			    proc, lboard, rboard, madr, i);
5980Sstevel@tonic-gate 		}
5990Sstevel@tonic-gate 		if (rd_madr != madr) {
6000Sstevel@tonic-gate 			cmn_err(CE_WARN,
601*11066Srafael.vanoni@sun.com 			    "IDN: 503: (invalidate) failed to update "
602*11066Srafael.vanoni@sun.com 			    "PC madr (expected 0x%x, actual 0x%x)",
603*11066Srafael.vanoni@sun.com 			    madr, rd_madr);
6040Sstevel@tonic-gate 			rv++;
6050Sstevel@tonic-gate 			continue;
6060Sstevel@tonic-gate 		}
6070Sstevel@tonic-gate 		if (madr == 0) {
6080Sstevel@tonic-gate 			continue;
6090Sstevel@tonic-gate 		} else {
6100Sstevel@tonic-gate 			/*
6110Sstevel@tonic-gate 			 * Turn the valid bit back on.
6120Sstevel@tonic-gate 			 */
6130Sstevel@tonic-gate 			madr |= STARFIRE_PC_MADR_VALIDBIT;
6140Sstevel@tonic-gate 		}
6150Sstevel@tonic-gate 		PR_XF("%s: write madr(0x%x) to pc_addr(0x%llx) "
616*11066Srafael.vanoni@sun.com 		    "[lb=%d, rb=%d, cpu=%d]\n",
617*11066Srafael.vanoni@sun.com 		    proc, madr, pc_madr_addr, lboard, rboard, p);
6180Sstevel@tonic-gate 		DEBUG_DELAY();
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 		for (i = 0; i < 20; i++) {
6210Sstevel@tonic-gate 			PHYSIO_ST(pc_madr_addr, madr);
6220Sstevel@tonic-gate 			/*
6230Sstevel@tonic-gate 			 * Read back for sanity check.
6240Sstevel@tonic-gate 			 */
6250Sstevel@tonic-gate 			rd_madr = PHYSIO_LD(pc_madr_addr);
6260Sstevel@tonic-gate 			if (madr == rd_madr)
6270Sstevel@tonic-gate 				break;
6280Sstevel@tonic-gate 		}
6290Sstevel@tonic-gate 		if (i > 0) {
6300Sstevel@tonic-gate 			PR_XF("%s: WARNING: (2) lb=%d, rb=%d, "
631*11066Srafael.vanoni@sun.com 			    "madr=0x%x (i=%d)\n",
632*11066Srafael.vanoni@sun.com 			    proc, lboard, rboard, madr, i);
6330Sstevel@tonic-gate 		}
6340Sstevel@tonic-gate 		if (rd_madr != madr) {
6350Sstevel@tonic-gate 			cmn_err(CE_WARN,
636*11066Srafael.vanoni@sun.com 			    "IDN: 503: (validate) failed to update "
637*11066Srafael.vanoni@sun.com 			    "PC madr (expected 0x%x, actual 0x%x)",
638*11066Srafael.vanoni@sun.com 			    madr, rd_madr);
6390Sstevel@tonic-gate 			rv++;
6400Sstevel@tonic-gate 		}
6410Sstevel@tonic-gate 	}
6420Sstevel@tonic-gate 	/*
6430Sstevel@tonic-gate 	 * Update the PCs for the iocs.
6440Sstevel@tonic-gate 	 */
6450Sstevel@tonic-gate 	for (ioc = 0; ioc < MAX_IOCS; iocset >>= 4, ioc++) {
6460Sstevel@tonic-gate 		int	i;
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 		if (!((iocset & BDAN_MASK) == BDAN_GOOD))
6490Sstevel@tonic-gate 			continue;
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 		pc_madr_addr = (u_longlong_t)STARFIRE_PC_MADR_ADDR(lboard,
652*11066Srafael.vanoni@sun.com 		    rboard, ioc + 4);
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 		if (madr != 0) {
6550Sstevel@tonic-gate 			/*
6560Sstevel@tonic-gate 			 * Need to clear valid bit on first
6570Sstevel@tonic-gate 			 * go around.
6580Sstevel@tonic-gate 			 */
6590Sstevel@tonic-gate 			madr &= ~STARFIRE_PC_MADR_VALIDBIT;
6600Sstevel@tonic-gate 		}
6610Sstevel@tonic-gate 		PR_XF("%s: write madr(0x%x) to iopc_madr_addr(0x%llx) "
662*11066Srafael.vanoni@sun.com 		    "[lb=%d, rb=%d, ioc=%d]\n",
663*11066Srafael.vanoni@sun.com 		    proc, madr, pc_madr_addr, lboard, rboard, ioc);
6640Sstevel@tonic-gate 		DEBUG_DELAY();
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 		for (i = 0; i < 20; i++) {
6670Sstevel@tonic-gate 			PHYSIO_ST(pc_madr_addr, madr);
6680Sstevel@tonic-gate 			/*
6690Sstevel@tonic-gate 			 * Read back for sanity check.
6700Sstevel@tonic-gate 			 */
6710Sstevel@tonic-gate 			rd_madr = PHYSIO_LD(pc_madr_addr);
6720Sstevel@tonic-gate 			if (madr == rd_madr)
6730Sstevel@tonic-gate 				break;
6740Sstevel@tonic-gate 		}
6750Sstevel@tonic-gate 		if (i > 0) {
6760Sstevel@tonic-gate 			PR_XF("%s: WARNING: (3) lb=%d, rb=%d, "
677*11066Srafael.vanoni@sun.com 			    "madr=0x%x (i=%d)\n",
678*11066Srafael.vanoni@sun.com 			    proc, lboard, rboard, madr, i);
6790Sstevel@tonic-gate 		}
6800Sstevel@tonic-gate 		if (rd_madr != madr) {
6810Sstevel@tonic-gate 			cmn_err(CE_WARN,
682*11066Srafael.vanoni@sun.com 			    "IDN: 504: (invalidate) failed to update "
683*11066Srafael.vanoni@sun.com 			    "IOPC madr (expected 0x%x, actual 0x%x)",
684*11066Srafael.vanoni@sun.com 			    madr, rd_madr);
6850Sstevel@tonic-gate 			rv++;
6860Sstevel@tonic-gate 			continue;
6870Sstevel@tonic-gate 		}
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 		if (madr == 0) {
6900Sstevel@tonic-gate 			continue;
6910Sstevel@tonic-gate 		} else {
6920Sstevel@tonic-gate 			/*
6930Sstevel@tonic-gate 			 * Turn the valid bit back on.
6940Sstevel@tonic-gate 			 */
6950Sstevel@tonic-gate 			madr |= STARFIRE_PC_MADR_VALIDBIT;
6960Sstevel@tonic-gate 		}
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 		PR_XF("%s: write madr(0x%x) to iopc_madr_addr(0x%llx) "
699*11066Srafael.vanoni@sun.com 		    "[lb=%d, rb=%d, ioc=%d]\n",
700*11066Srafael.vanoni@sun.com 		    proc, madr, pc_madr_addr, lboard, rboard, ioc);
7010Sstevel@tonic-gate 		DEBUG_DELAY();
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 		for (i = 0; i < 20; i++) {
7040Sstevel@tonic-gate 			PHYSIO_ST(pc_madr_addr, madr);
7050Sstevel@tonic-gate 			/*
7060Sstevel@tonic-gate 			 * Read back for sanity check.
7070Sstevel@tonic-gate 			 */
7080Sstevel@tonic-gate 			rd_madr = PHYSIO_LD(pc_madr_addr);
7090Sstevel@tonic-gate 			if (madr == rd_madr)
7100Sstevel@tonic-gate 				break;
7110Sstevel@tonic-gate 		}
7120Sstevel@tonic-gate 		if (i > 0) {
7130Sstevel@tonic-gate 			PR_XF("%s: WARNING: (4) lb=%d, rb=%d, "
714*11066Srafael.vanoni@sun.com 			    "madr=0x%x (i=%d)\n",
715*11066Srafael.vanoni@sun.com 			    proc, lboard, rboard, madr, i);
7160Sstevel@tonic-gate 		}
7170Sstevel@tonic-gate 		if (rd_madr != madr) {
7180Sstevel@tonic-gate 			cmn_err(CE_WARN,
719*11066Srafael.vanoni@sun.com 			    "IDN: 504: (validate) failed to update "
720*11066Srafael.vanoni@sun.com 			    "IOPC madr (expected 0x%x, actual 0x%x)",
721*11066Srafael.vanoni@sun.com 			    madr, rd_madr);
7220Sstevel@tonic-gate 			rv++;
7230Sstevel@tonic-gate 		}
7240Sstevel@tonic-gate 	}
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	return (rv ? -1 : 0);
7270Sstevel@tonic-gate }
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate /*
7300Sstevel@tonic-gate  * --------------------------------------------------
7310Sstevel@tonic-gate  * Read the array of MC address decoding registers from one of the
7320Sstevel@tonic-gate  * PCs on the local board (lboard) into the given in array (mc_adr).
7330Sstevel@tonic-gate  * --------------------------------------------------
7340Sstevel@tonic-gate  */
7350Sstevel@tonic-gate void
pc_read_madr(pda_handle_t ph,int lboard,uint_t mc_adr[],int local_only)7360Sstevel@tonic-gate pc_read_madr(pda_handle_t ph, int lboard, uint_t mc_adr[], int local_only)
7370Sstevel@tonic-gate {
7380Sstevel@tonic-gate 	u_longlong_t	pc_madr_addr;
7390Sstevel@tonic-gate 	register int	p, ioc;
7400Sstevel@tonic-gate 	register ushort_t	procset, iocset;
7410Sstevel@tonic-gate 	int		brd;
7420Sstevel@tonic-gate 	board_desc_t	*lbp;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	lbp = pda_get_board_info(ph, lboard);
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	ASSERT(lbp);
7470Sstevel@tonic-gate 	ASSERT((lbp->bda_board & BDAN_MASK) == BDAN_GOOD);
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	procset = lbp->bda_proc;
7500Sstevel@tonic-gate 	iocset = lbp->bda_ioc;
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	for (p = 0; p < MAX_PROCMODS; procset >>= 4, p++)
7530Sstevel@tonic-gate 		if ((procset & BDAN_MASK) == BDAN_GOOD)
7540Sstevel@tonic-gate 			break;
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	if (p == MAX_PROCMODS) {
7570Sstevel@tonic-gate 		/*
7580Sstevel@tonic-gate 		 * Couldn't find a PC off a cpu, let's check the
7590Sstevel@tonic-gate 		 * IOCs.
7600Sstevel@tonic-gate 		 */
7610Sstevel@tonic-gate 		for (ioc = 0; ioc < MAX_IOCS; iocset >>= 4, ioc++)
7620Sstevel@tonic-gate 			if ((iocset & BDAN_MASK) == BDAN_GOOD)
7630Sstevel@tonic-gate 				break;
7640Sstevel@tonic-gate 		if (ioc == MAX_IOCS) {
7650Sstevel@tonic-gate 			cmn_err(CE_WARN,
766*11066Srafael.vanoni@sun.com 			    "IDN: 505: board %d missing any valid PCs",
767*11066Srafael.vanoni@sun.com 			    lboard);
7680Sstevel@tonic-gate 			return;
7690Sstevel@tonic-gate 		}
7700Sstevel@tonic-gate 		p = ioc + 4;
7710Sstevel@tonic-gate 	}
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 	pc_madr_addr = (u_longlong_t)STARFIRE_PC_MADR_ADDR(lboard, 0, p);
7740Sstevel@tonic-gate 	/*
7750Sstevel@tonic-gate 	 * pc_madr_addr = Starts at entry for board 0.
7760Sstevel@tonic-gate 	 */
7770Sstevel@tonic-gate 	for (brd = 0; brd < MAX_BOARDS; brd++) {
7780Sstevel@tonic-gate 		/*
7790Sstevel@tonic-gate 		 * It's possible our local PC may have old entries to
7800Sstevel@tonic-gate 		 * AWOL domains.  Only want to pay attention to PC
7810Sstevel@tonic-gate 		 * entries corresponding to our boards.
7820Sstevel@tonic-gate 		 */
7830Sstevel@tonic-gate 		lbp = pda_get_board_info(ph, brd);
784*11066Srafael.vanoni@sun.com 		if (!local_only || ((lbp->bda_board & BDAN_MASK) == BDAN_GOOD))
7850Sstevel@tonic-gate 			mc_adr[brd] = PHYSIO_LD(pc_madr_addr);
7860Sstevel@tonic-gate 		else
7870Sstevel@tonic-gate 			mc_adr[brd] = 0;
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 		pc_madr_addr += ((u_longlong_t)1 <<
790*11066Srafael.vanoni@sun.com 		    STARFIRE_PC_MADR_BOARD_SHIFT);
7910Sstevel@tonic-gate 	}
7920Sstevel@tonic-gate }
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate /*
7950Sstevel@tonic-gate  * --------------------------------------------------
7960Sstevel@tonic-gate  * Read the MC address decoding register contents for all
7970Sstevel@tonic-gate  * possible boards and store the results in their respective
7980Sstevel@tonic-gate  * slot in mc_adr.  Keep a count of non-zero MC ADRs and
7990Sstevel@tonic-gate  * return that.
8000Sstevel@tonic-gate  * --------------------------------------------------
8010Sstevel@tonic-gate  */
8020Sstevel@tonic-gate void
mc_get_adr_all(pda_handle_t ph,uint_t mc_adr[],int * nmcadr)8030Sstevel@tonic-gate mc_get_adr_all(pda_handle_t ph, uint_t mc_adr[], int *nmcadr)
8040Sstevel@tonic-gate {
8050Sstevel@tonic-gate 	int	brd;
8060Sstevel@tonic-gate 	uint_t	madr[MAX_BOARDS];
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	/*
8090Sstevel@tonic-gate 	 * Note that each PC has a complete copy of all MC contents
8100Sstevel@tonic-gate 	 * and so all we have to do is read one PC rather than
8110Sstevel@tonic-gate 	 * each of the MCs in the system.
8120Sstevel@tonic-gate 	 */
8130Sstevel@tonic-gate 	brd = CPUID_TO_BOARDID(CPU->cpu_id);
8140Sstevel@tonic-gate 	pc_read_madr(ph, brd, madr, 1);
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	*nmcadr = 0;
8170Sstevel@tonic-gate 	for (brd = 0; brd < MAX_BOARDS; brd++)
8180Sstevel@tonic-gate 		if ((mc_adr[brd] = madr[brd]) != 0)
8190Sstevel@tonic-gate 			(*nmcadr)++;
8200Sstevel@tonic-gate }
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate static boardset_t
get_boardset(pda_handle_t ph,int * nboards)8230Sstevel@tonic-gate get_boardset(pda_handle_t ph, int *nboards)
8240Sstevel@tonic-gate {
8250Sstevel@tonic-gate 	int		brd;
8260Sstevel@tonic-gate 	int		nbrds = 0;
8270Sstevel@tonic-gate 	boardset_t	bmask;
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 	if (nboards != NULL)
8300Sstevel@tonic-gate 		*nboards = 0;
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 	bmask = 0;
8330Sstevel@tonic-gate 	for (brd = 0; brd < MAX_BOARDS; brd++) {
8340Sstevel@tonic-gate 		if (pda_board_present(ph, brd)) {
8350Sstevel@tonic-gate 			bmask |= 1 << brd;
8360Sstevel@tonic-gate 			nbrds++;
8370Sstevel@tonic-gate 		}
8380Sstevel@tonic-gate 	}
8390Sstevel@tonic-gate 	if (nboards != NULL)
8400Sstevel@tonic-gate 		*nboards = (short)nbrds;
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 	return (bmask);
8430Sstevel@tonic-gate }
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate int
update_local_hw_config(idn_domain_t * ldp,struct hwconfig * loc_hw)8460Sstevel@tonic-gate update_local_hw_config(idn_domain_t *ldp, struct hwconfig *loc_hw)
8470Sstevel@tonic-gate {
8480Sstevel@tonic-gate 	procname_t	proc = "update_local_hw_config";
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	ASSERT(IDN_DLOCK_IS_EXCL(ldp->domid));
8510Sstevel@tonic-gate 	ASSERT(IDN_GLOCK_IS_EXCL());
8520Sstevel@tonic-gate 	ASSERT(ldp == &idn_domain[idn.localid]);
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	if (ldp->dhw.dh_boardset != loc_hw->dh_boardset) {
8550Sstevel@tonic-gate 		int	c;
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 		PR_PROTO("%s: NEW HW CONFIG (old_bset = 0x%x, "
858*11066Srafael.vanoni@sun.com 		    "new_bset = 0x%x)\n",
859*11066Srafael.vanoni@sun.com 		    proc, ldp->dhw.dh_boardset, loc_hw->dh_boardset);
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 		PR_PROTO("%s: clearing boardset 0x%x\n", proc,
862*11066Srafael.vanoni@sun.com 		    ldp->dhw.dh_boardset & ~loc_hw->dh_boardset);
8630Sstevel@tonic-gate 		PR_PROTO("%s: setting boardset  0x%x\n", proc,
864*11066Srafael.vanoni@sun.com 		    loc_hw->dh_boardset & ~ldp->dhw.dh_boardset);
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 		idn.dc_boardset &= ~ldp->dhw.dh_boardset;
8670Sstevel@tonic-gate 		idn.dc_boardset |= loc_hw->dh_boardset;
8680Sstevel@tonic-gate 		for (c = 0; c < NCPU; c++) {
8690Sstevel@tonic-gate 			if (CPU_IN_SET(ldp->dcpuset, c)) {
8700Sstevel@tonic-gate 				CPUSET_DEL(idn.dc_cpuset, c);
8710Sstevel@tonic-gate 			}
8720Sstevel@tonic-gate 		}
8730Sstevel@tonic-gate 		CPUSET_OR(idn.dc_cpuset, cpu_ready_set);
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 		bcopy(loc_hw, &ldp->dhw, sizeof (ldp->dhw));
8760Sstevel@tonic-gate 		ldp->dcpuset = cpu_ready_set;
8770Sstevel@tonic-gate 		ldp->dcpu    = cpu0.cpu_id;
8780Sstevel@tonic-gate 		ldp->dncpus  = (int)ncpus;
8790Sstevel@tonic-gate 		ldp->dvote.v.nmembrds = ldp->dhw.dh_nmcadr - 1;
8800Sstevel@tonic-gate 		ldp->dvote.v.ncpus    = (int)ldp->dncpus - 1;
8810Sstevel@tonic-gate 		ldp->dvote.v.board    = CPUID_TO_BOARDID(CPU->cpu_id);
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 		return (1);
8840Sstevel@tonic-gate 	} else {
8850Sstevel@tonic-gate 		PR_PROTO("%s: NO change detected\n", proc);
8860Sstevel@tonic-gate 		return (0);
8870Sstevel@tonic-gate 	}
8880Sstevel@tonic-gate }
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate int
get_hw_config(struct hwconfig * loc_hw)8910Sstevel@tonic-gate get_hw_config(struct hwconfig *loc_hw)
8920Sstevel@tonic-gate {
8930Sstevel@tonic-gate 	pda_handle_t	ph;
8940Sstevel@tonic-gate 	boardset_t	domainset;
8950Sstevel@tonic-gate 	int		bd;
8960Sstevel@tonic-gate 	int		nmcadr;
8970Sstevel@tonic-gate 	int		nboards;
8980Sstevel@tonic-gate 	procname_t	proc = "get_hw_config";
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	ASSERT(loc_hw != NULL);
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	bzero(loc_hw, sizeof (*loc_hw));
9030Sstevel@tonic-gate 	/*
9040Sstevel@tonic-gate 	 * See if sm_mask is writable.
9050Sstevel@tonic-gate 	 * XXX - Should be the same for all CIC's.  Do we
9060Sstevel@tonic-gate 	 *	 we need to verify?
9070Sstevel@tonic-gate 	 */
9080Sstevel@tonic-gate 	if (cic_get_smmask_bit() == 0) {
9090Sstevel@tonic-gate 		/*
9100Sstevel@tonic-gate 		 * If smmask is not writable, we can not allow
9110Sstevel@tonic-gate 		 * IDN operations.
9120Sstevel@tonic-gate 		 */
9130Sstevel@tonic-gate 		cmn_err(CE_WARN,
914*11066Srafael.vanoni@sun.com 		    "IDN: 506: cic sm_mask is not writeable");
9150Sstevel@tonic-gate 		return (-1);
9160Sstevel@tonic-gate 	}
9170Sstevel@tonic-gate 	/*
9180Sstevel@tonic-gate 	 * Map in the post2obp structure so we can find
9190Sstevel@tonic-gate 	 * valid boards and hardware asics.
9200Sstevel@tonic-gate 	 */
9210Sstevel@tonic-gate 	ph = pda_open();
9220Sstevel@tonic-gate 	if (ph == (pda_handle_t)NULL) {
9230Sstevel@tonic-gate 		cmn_err(CE_WARN,
924*11066Srafael.vanoni@sun.com 		    "IDN: 507: failed to map-in post2obp structure");
9250Sstevel@tonic-gate 		return (-1);
9260Sstevel@tonic-gate 	} else if (!pda_is_valid(ph)) {
9270Sstevel@tonic-gate 		cmn_err(CE_WARN, "IDN: 508: post2obp checksum invalid");
9280Sstevel@tonic-gate 		pda_close(ph);
9290Sstevel@tonic-gate 		return (-1);
9300Sstevel@tonic-gate 	}
9310Sstevel@tonic-gate 	/*
9320Sstevel@tonic-gate 	 * Need to read the MC address decoding registers
9330Sstevel@tonic-gate 	 * so that they can be given to other domains.
9340Sstevel@tonic-gate 	 */
9350Sstevel@tonic-gate 	loc_hw->dh_boardset = get_boardset(ph, &nboards);
9360Sstevel@tonic-gate 	loc_hw->dh_nboards = (short)nboards;
9370Sstevel@tonic-gate 	ASSERT(loc_hw->dh_boardset & (1 << CPUID_TO_BOARDID(CPU->cpu_id)));
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 	mc_get_adr_all(ph, loc_hw->dh_mcadr, &nmcadr);
9400Sstevel@tonic-gate 	loc_hw->dh_nmcadr = (short)nmcadr;
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 	affinity_set(CPU_CURRENT);
9430Sstevel@tonic-gate 	/*
9440Sstevel@tonic-gate 	 * There will always be a bus 0 (logical).
9450Sstevel@tonic-gate 	 */
9460Sstevel@tonic-gate 	bd = CPUID_TO_BOARDID(CPU->cpu_id);
9470Sstevel@tonic-gate 	domainset = (boardset_t)cic_read_domain_mask(bd, 0);
9480Sstevel@tonic-gate 	affinity_clear();
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	if (!idn_cpu_per_board(ph, cpu_ready_set, loc_hw)) {
9510Sstevel@tonic-gate 		pda_close(ph);
9520Sstevel@tonic-gate 		return (-1);
9530Sstevel@tonic-gate 	}
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	pda_close(ph);
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate #ifdef DEBUG
9590Sstevel@tonic-gate 	{
9600Sstevel@tonic-gate 		int	brd;
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 		for (brd = 0; brd < MAX_BOARDS; brd++)
9630Sstevel@tonic-gate 			if (loc_hw->dh_mcadr[brd] != 0) {
9640Sstevel@tonic-gate 				PR_XF("%s: brd %d, mc = 0x%x\n",
965*11066Srafael.vanoni@sun.com 				    proc, brd, loc_hw->dh_mcadr[brd]);
9660Sstevel@tonic-gate 			}
9670Sstevel@tonic-gate 	}
9680Sstevel@tonic-gate #endif /* DEBUG */
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 	if ((loc_hw->dh_boardset != domainset) || (loc_hw->dh_nmcadr < 1))
9710Sstevel@tonic-gate 		return (-1);
9720Sstevel@tonic-gate 	else
9730Sstevel@tonic-gate 		return (0);
9740Sstevel@tonic-gate }
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate /*
9770Sstevel@tonic-gate  * Function called via timeout() to wakeup a possibly stuck
9780Sstevel@tonic-gate  * idnxf_shmem_update_all() should not all cpus check-in after a
9790Sstevel@tonic-gate  * x-call to update their respective CICs.
9800Sstevel@tonic-gate  */
9810Sstevel@tonic-gate /*ARGSUSED0*/
9820Sstevel@tonic-gate static void
idnxf_shmem_wakeup(void * arg)9830Sstevel@tonic-gate idnxf_shmem_wakeup(void *arg)
9840Sstevel@tonic-gate {
9850Sstevel@tonic-gate 	struct idnxf_cic_info	*idnxfp = (struct idnxf_cic_info *)arg;
9860Sstevel@tonic-gate 	int		count;
9870Sstevel@tonic-gate 	int		expired;
9880Sstevel@tonic-gate 	procname_t	proc = "idnxf_shmem_wakeup";
9890Sstevel@tonic-gate 
990*11066Srafael.vanoni@sun.com 	expired = ((ddi_get_lbolt() - idnxfp->xf_start_time) >=
991*11066Srafael.vanoni@sun.com 	    IDNCIC_TIMEOUT) ? 1 : 0;
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate 	if ((count = idnxfp->xf_count) == 0) {
9940Sstevel@tonic-gate 		/*
9950Sstevel@tonic-gate 		 * Everybody has finished.  Wakeup the requester.
9960Sstevel@tonic-gate 		 */
9970Sstevel@tonic-gate 		mutex_enter(&idnxfp->xf_mutex);
9980Sstevel@tonic-gate 		cv_signal(&idnxfp->xf_cv);
9990Sstevel@tonic-gate 		mutex_exit(&idnxfp->xf_mutex);
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 	} else if ((count > 0) && expired) {
10020Sstevel@tonic-gate 		/*
10030Sstevel@tonic-gate 		 * There are still active cic updaters and time
10040Sstevel@tonic-gate 		 * has expired.  Bail on them.
10050Sstevel@tonic-gate 		 */
10060Sstevel@tonic-gate 		idnxfp->xf_errtimer = 1;
10070Sstevel@tonic-gate #ifdef DEBUG
10080Sstevel@tonic-gate 		/*
10090Sstevel@tonic-gate 		 * Special debug case since idn_debug
10100Sstevel@tonic-gate 		 * may have been temporarily cleared
10110Sstevel@tonic-gate 		 * during xc_some.
10120Sstevel@tonic-gate 		 */
10130Sstevel@tonic-gate 		if ((idn_debug | o_idn_debug) & IDNDBG_REGS)
10140Sstevel@tonic-gate 			printf("%s: TIMEOUT...bailing on %d lost CIC "
1015*11066Srafael.vanoni@sun.com 			    "updates...\n", proc, count);
10160Sstevel@tonic-gate #endif /* DEBUG */
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 		ATOMIC_SUB(idnxfp->xf_count, count);
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate 		mutex_enter(&idnxfp->xf_mutex);
10210Sstevel@tonic-gate 		cv_signal(&idnxfp->xf_cv);
10220Sstevel@tonic-gate 		mutex_exit(&idnxfp->xf_mutex);
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	} else {
10250Sstevel@tonic-gate 		(void) timeout(idnxf_shmem_wakeup, (caddr_t)idnxfp,
1026*11066Srafael.vanoni@sun.com 		    (clock_t)IDNCIC_TIMECHK);
10270Sstevel@tonic-gate 	}
10280Sstevel@tonic-gate }
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate /*
10310Sstevel@tonic-gate  * Called indirectly from idnxf_shmem_update_all() via a xcall
10320Sstevel@tonic-gate  * for the recepient cpu to update the CICs on its respective
10330Sstevel@tonic-gate  * board.
10340Sstevel@tonic-gate  * IMPORTANT: NO console output from this routine!!
10350Sstevel@tonic-gate  */
10360Sstevel@tonic-gate static void
idnxf_shmem_update_one(uint64_t arg1,uint64_t arg2)10370Sstevel@tonic-gate idnxf_shmem_update_one(uint64_t arg1, uint64_t arg2)
10380Sstevel@tonic-gate {
10390Sstevel@tonic-gate 	struct idnxf_cic_info	*idnxfp = (struct idnxf_cic_info *)arg1;
10400Sstevel@tonic-gate 	time_t		start_time = (time_t)arg2;
10410Sstevel@tonic-gate 	int		rv, cpuid, brd, bus;
10420Sstevel@tonic-gate 	boardset_t	smmask;
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 	cpuid = CPU->cpu_id;
10460Sstevel@tonic-gate 	brd   = CPUID_TO_BOARDID(cpuid);
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 	if (idnxfp->xf_start_time != start_time) {
10490Sstevel@tonic-gate 		/*
10500Sstevel@tonic-gate 		 * Ooops!  Not my place to intrude.
10510Sstevel@tonic-gate 		 */
10520Sstevel@tonic-gate 		idnxf_cic_info.xf_errcic[brd][0] = IDNCIC_BUSY;
10530Sstevel@tonic-gate 		ATOMIC_INC(idnxf_cic_info.xf_errcnt);
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 		goto done;
10560Sstevel@tonic-gate 	}
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 	/*
10590Sstevel@tonic-gate 	 * We're executing out of the context of a cross-call
10600Sstevel@tonic-gate 	 * so we're effectively bound! :)
10610Sstevel@tonic-gate 	 */
10620Sstevel@tonic-gate 	for (bus = 0; bus < MAX_ABUSES; bus++) {
10630Sstevel@tonic-gate 		/*
10640Sstevel@tonic-gate 		 * XXX - need to worry about shuffle??
10650Sstevel@tonic-gate 		 */
10660Sstevel@tonic-gate 		if (!(idnxfp->xf_abus_mask & (1 << bus)))
10670Sstevel@tonic-gate 			continue;
10680Sstevel@tonic-gate 		smmask = cic_read_sm_mask(brd, bus);
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 		if (idnxfp->xf_doadd) {
10710Sstevel@tonic-gate 			smmask |= idnxfp->xf_boardset;
10720Sstevel@tonic-gate 			(void) cic_write_sm_mask(brd, bus, smmask);
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 			if (idnxfp->xf_smbase != (uint_t)-1) {
10750Sstevel@tonic-gate 				(void) cic_write_sm_bar(brd, bus,
1076*11066Srafael.vanoni@sun.com 				    idnxfp->xf_smbase);
10770Sstevel@tonic-gate 				(void) cic_write_sm_lar(brd, bus,
1078*11066Srafael.vanoni@sun.com 				    idnxfp->xf_smlimit);
10790Sstevel@tonic-gate 			}
10800Sstevel@tonic-gate 			/*
10810Sstevel@tonic-gate 			 * Verify data got there!
10820Sstevel@tonic-gate 			 */
10830Sstevel@tonic-gate 			rv = verify_smregs(brd, bus, smmask, idnxfp->xf_smbase,
1084*11066Srafael.vanoni@sun.com 			    idnxfp->xf_smlimit);
10850Sstevel@tonic-gate 		} else {
10860Sstevel@tonic-gate 			smmask &= ~idnxfp->xf_boardset;
10870Sstevel@tonic-gate 			(void) cic_write_sm_mask(brd, bus, smmask);
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 			if (!smmask) {
10900Sstevel@tonic-gate 				/*
10910Sstevel@tonic-gate 				 * Update the LAR first so that we effectively
10920Sstevel@tonic-gate 				 * disable the register without possibly
10930Sstevel@tonic-gate 				 * opening the window to transaction we
10940Sstevel@tonic-gate 				 * don't care about.  Updating the LAR first
10950Sstevel@tonic-gate 				 * will guarantee we effectively turn it
10960Sstevel@tonic-gate 				 * off immediately.
10970Sstevel@tonic-gate 				 */
10980Sstevel@tonic-gate 				(void) cic_write_sm_lar(brd, bus, 0);
10990Sstevel@tonic-gate 				(void) cic_write_sm_bar(brd, bus, 1);
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 				rv = verify_smregs(brd, bus, smmask, 1, 0);
11020Sstevel@tonic-gate 			} else {
11030Sstevel@tonic-gate 				rv = verify_smregs(brd, bus, smmask,
1104*11066Srafael.vanoni@sun.com 				    (uint_t)-1, (uint_t)-1);
11050Sstevel@tonic-gate 			}
11060Sstevel@tonic-gate 		}
11070Sstevel@tonic-gate 		if (rv) {
11080Sstevel@tonic-gate 			idnxf_cic_info.xf_errcic[brd][bus] = IDNCIC_ERR;
11090Sstevel@tonic-gate 			ATOMIC_INC(idnxf_cic_info.xf_errcnt);
11100Sstevel@tonic-gate 		} else {
11110Sstevel@tonic-gate 			idnxf_cic_info.xf_errcic[brd][bus] = IDNCIC_OK;
11120Sstevel@tonic-gate 		}
11130Sstevel@tonic-gate 	}
11140Sstevel@tonic-gate 
11150Sstevel@tonic-gate done:
11160Sstevel@tonic-gate 	ATOMIC_DEC(idnxf_cic_info.xf_count);
11170Sstevel@tonic-gate }
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate static int
idnxf_shmem_update_all(pda_handle_t ph,boardset_t boardset,uint_t smbase,uint_t smlimit,int doadd)11200Sstevel@tonic-gate idnxf_shmem_update_all(pda_handle_t ph, boardset_t boardset,
11210Sstevel@tonic-gate 			uint_t smbase, uint_t smlimit, int doadd)
11220Sstevel@tonic-gate {
11230Sstevel@tonic-gate 	cpuset_t	target_cpuset;
11240Sstevel@tonic-gate 	int		target_count;
11250Sstevel@tonic-gate 	int		rv = 0;
11260Sstevel@tonic-gate 	int		c, brd, bus;
11270Sstevel@tonic-gate 	short		abus_mask;
11280Sstevel@tonic-gate 	time_t		start_time;
11290Sstevel@tonic-gate 	procname_t	proc = "idnxf_shmem_update_all";
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&idn_xf_mutex));
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	pda_get_busmask(ph, &abus_mask, NULL);
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	CPUSET_ZERO(target_cpuset);
11370Sstevel@tonic-gate 	target_count = 0;
11380Sstevel@tonic-gate 	/*
11390Sstevel@tonic-gate 	 * Build a cpuset of target cpus (one per board) to
11400Sstevel@tonic-gate 	 * be used to send the CIC update xcall.
11410Sstevel@tonic-gate 	 */
11420Sstevel@tonic-gate 	for (brd = 0; brd < MAX_BOARDS; brd++) {
11430Sstevel@tonic-gate 		/*
11440Sstevel@tonic-gate 		 * Need to target an available cpu on the target board
11450Sstevel@tonic-gate 		 * so that we can look at the CICs on that board.
11460Sstevel@tonic-gate 		 */
11470Sstevel@tonic-gate 		c = board_to_ready_cpu(brd, cpu_ready_set);
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 		if (c == -1) {
11500Sstevel@tonic-gate 			/*
11510Sstevel@tonic-gate 			 * If there's no cpu on this board, no
11520Sstevel@tonic-gate 			 * need to update the CICs.
11530Sstevel@tonic-gate 			 */
11540Sstevel@tonic-gate 			continue;
11550Sstevel@tonic-gate 		}
11560Sstevel@tonic-gate 		CPUSET_ADD(target_cpuset, c);
11570Sstevel@tonic-gate 		target_count++;
11580Sstevel@tonic-gate 	}
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 	if (CPUSET_ISNULL(target_cpuset)) {
11610Sstevel@tonic-gate 		PR_REGS("%s: NO target cpus to update!!\n", proc);
11620Sstevel@tonic-gate 		return (0);
11630Sstevel@tonic-gate 	}
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 	RESET_CIC_HISTORY();
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate 	/*
11680Sstevel@tonic-gate 	 * Broadcast out the CIC update request and then
11690Sstevel@tonic-gate 	 * sit back and wait for dinner to arrive!
11700Sstevel@tonic-gate 	 * Let's set up the global structure all the xcall
11710Sstevel@tonic-gate 	 * recepients will read.
11720Sstevel@tonic-gate 	 */
1173*11066Srafael.vanoni@sun.com 	start_time = ddi_get_lbolt();
11740Sstevel@tonic-gate 	/*
11750Sstevel@tonic-gate 	 * Set the start time.  Make sure it's different
11760Sstevel@tonic-gate 	 * then the previous run.
11770Sstevel@tonic-gate 	 */
11780Sstevel@tonic-gate 	if (start_time <= idnxf_cic_info.xf_start_time)
11790Sstevel@tonic-gate 		start_time++;
11800Sstevel@tonic-gate 	idnxf_cic_info.xf_start_time = start_time;
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate 	idnxf_cic_info.xf_abus_mask = abus_mask;
11830Sstevel@tonic-gate 	idnxf_cic_info.xf_boardset = boardset;
11840Sstevel@tonic-gate 	idnxf_cic_info.xf_smbase = smbase;
11850Sstevel@tonic-gate 	idnxf_cic_info.xf_smlimit = smlimit;
11860Sstevel@tonic-gate 	idnxf_cic_info.xf_doadd = doadd;
11870Sstevel@tonic-gate 	idnxf_cic_info.xf_count = target_count;
11880Sstevel@tonic-gate 	idnxf_cic_info.xf_errcnt = 0;
11890Sstevel@tonic-gate 	idnxf_cic_info.xf_errtimer = 0;
11900Sstevel@tonic-gate 	bzero(&idnxf_cic_info.xf_errcic, sizeof (idnxf_cic_info.xf_errcic));
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 	/*
11930Sstevel@tonic-gate 	 * Broadcast out the xcall to do the task.
11940Sstevel@tonic-gate 	 */
11950Sstevel@tonic-gate #ifdef DEBUG
11960Sstevel@tonic-gate 	{
11970Sstevel@tonic-gate 		uint_t	tu32, tl32;
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 		tu32 = UPPER32_CPUMASK(target_cpuset);
12000Sstevel@tonic-gate 		tl32 = LOWER32_CPUMASK(target_cpuset);
12010Sstevel@tonic-gate 		PR_REGS("%s: (start %ld) broadcasting CIC - "
1202*11066Srafael.vanoni@sun.com 		    "%s to cpus 0x%x.%0x\n",
1203*11066Srafael.vanoni@sun.com 		    proc, start_time, doadd ? "LINK" : "UNLINK",
1204*11066Srafael.vanoni@sun.com 		    tu32, tl32);
12050Sstevel@tonic-gate 	}
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 	/*
12080Sstevel@tonic-gate 	 * Can't dump debug during cross-calls.
12090Sstevel@tonic-gate 	 */
12100Sstevel@tonic-gate 	o_idn_debug = idn_debug;
12110Sstevel@tonic-gate 	idn_debug = 0;
12120Sstevel@tonic-gate #endif /* DEBUG */
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 	xc_attention(target_cpuset);
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 	xc_some(target_cpuset, idnxf_shmem_update_one,
1217*11066Srafael.vanoni@sun.com 	    (uint64_t)&idnxf_cic_info, (uint64_t)start_time);
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 	xc_dismissed(target_cpuset);
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate 	ASSERT(idnxf_cic_info.xf_count == 0);
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate #ifdef DEBUG
12240Sstevel@tonic-gate 	idn_debug = o_idn_debug;
12250Sstevel@tonic-gate 	o_idn_debug = 0;
12260Sstevel@tonic-gate #endif /* DEBUG */
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate 	PR_REGS("%s: waiting for completion of %d CIC - %s...\n",
1229*11066Srafael.vanoni@sun.com 	    proc, idnxf_cic_info.xf_count, doadd ? "LINKS" : "UNLINKS");
12300Sstevel@tonic-gate 	PR_REGS("%s: CIC - %s have checked IN.\n",
1231*11066Srafael.vanoni@sun.com 	    proc, doadd ? "LINKS" : "UNLINKS");
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate 	/*
12340Sstevel@tonic-gate 	 * Modifying xf_start_time effectively disables any
12350Sstevel@tonic-gate 	 * possible outstanding xcall's since they don't touch
12360Sstevel@tonic-gate 	 * idnxf_cic_info unless their given start_time matches
12370Sstevel@tonic-gate 	 * that in the idnxf_cic_info structure.
12380Sstevel@tonic-gate 	 */
12390Sstevel@tonic-gate 	idnxf_cic_info.xf_start_time++;
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate 	PR_REGS("%s: xf_errcnt = %d, xf_errtimer = %d\n",
1242*11066Srafael.vanoni@sun.com 	    proc, idnxf_cic_info.xf_errcnt, idnxf_cic_info.xf_errtimer);
12430Sstevel@tonic-gate 	DUMP_CIC_HISTORY();
12440Sstevel@tonic-gate 	/*
12450Sstevel@tonic-gate 	 * Should errors be fatal? (panic).
12460Sstevel@tonic-gate 	 */
12470Sstevel@tonic-gate 	rv = 0;
12480Sstevel@tonic-gate 	for (c = 0; c < NCPU; c++) {
12490Sstevel@tonic-gate 		if (!CPU_IN_SET(target_cpuset, c))
12500Sstevel@tonic-gate 			continue;
12510Sstevel@tonic-gate 		brd = CPUID_TO_BOARDID(c);
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate 		for (bus = 0; bus < MAX_ABUSES; bus++) {
12540Sstevel@tonic-gate 
12550Sstevel@tonic-gate 			if (!(abus_mask & (1 << bus)))
12560Sstevel@tonic-gate 				continue;
12570Sstevel@tonic-gate 
12580Sstevel@tonic-gate 			switch (idnxf_cic_info.xf_errcic[brd][bus]) {
12590Sstevel@tonic-gate 			case IDNCIC_UNKNOWN:
12600Sstevel@tonic-gate 				/*
12610Sstevel@tonic-gate 				 * Unknown is only an error if the
12620Sstevel@tonic-gate 				 * timer expired.
12630Sstevel@tonic-gate 				 */
12640Sstevel@tonic-gate 				if (!idnxf_cic_info.xf_errtimer)
12650Sstevel@tonic-gate 					break;
12660Sstevel@tonic-gate 				cmn_err(CE_WARN,
1267*11066Srafael.vanoni@sun.com 				    "IDN: 509: CPU %d never responded "
1268*11066Srafael.vanoni@sun.com 				    "to CIC update", c);
12690Sstevel@tonic-gate 				/*FALLTHROUGH*/
12700Sstevel@tonic-gate 
12710Sstevel@tonic-gate 			case IDNCIC_ERR:
12720Sstevel@tonic-gate 				cmn_err(CE_WARN,
1273*11066Srafael.vanoni@sun.com 				    "IDN: 510: failed write-smregs "
1274*11066Srafael.vanoni@sun.com 				    "(bd=%d, bs=%d, sm(bar=0x%x, "
1275*11066Srafael.vanoni@sun.com 				    "lar=0x%x))",
1276*11066Srafael.vanoni@sun.com 				    brd, bus, smbase, smlimit);
12770Sstevel@tonic-gate 				rv++;
12780Sstevel@tonic-gate 				break;
12790Sstevel@tonic-gate 
12800Sstevel@tonic-gate 			case IDNCIC_BUSY:
12810Sstevel@tonic-gate 				cmn_err(CE_WARN, "IDN: 511: update-one "
1282*11066Srafael.vanoni@sun.com 				    "(cpu=%d, bd=%d) time conflict",
1283*11066Srafael.vanoni@sun.com 				    c, brd);
12840Sstevel@tonic-gate 				/*
12850Sstevel@tonic-gate 				 * Should never occur.  Not fatal,
12860Sstevel@tonic-gate 				 * just continue.
12870Sstevel@tonic-gate 				 */
12880Sstevel@tonic-gate 				break;
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate 			default:
12910Sstevel@tonic-gate 				PR_REGS("%s: board %d, bus %d "
1292*11066Srafael.vanoni@sun.com 				    "(bar=0x%x,lar=0x%x) - update OK\n",
1293*11066Srafael.vanoni@sun.com 				    proc, brd, bus, smbase, smlimit);
12940Sstevel@tonic-gate 				break;
12950Sstevel@tonic-gate 			}
12960Sstevel@tonic-gate 		}
12970Sstevel@tonic-gate 	}
12980Sstevel@tonic-gate 
12990Sstevel@tonic-gate 	return (rv ? -1 : 0);
13000Sstevel@tonic-gate }
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate /*
13030Sstevel@tonic-gate  * Add the respective boardset/base/limit/mcadr's to the local
13040Sstevel@tonic-gate  * domain's hardware configuration with respect to the SMR.
13050Sstevel@tonic-gate  *
13060Sstevel@tonic-gate  * is_master	Indicates remote domain is a master.
13070Sstevel@tonic-gate  */
13080Sstevel@tonic-gate int
idnxf_shmem_add(int is_master,boardset_t boardset,pfn_t pfnbase,pfn_t pfnlimit,uint_t * mcadr)1309*11066Srafael.vanoni@sun.com idnxf_shmem_add(int is_master, boardset_t boardset, pfn_t pfnbase,
1310*11066Srafael.vanoni@sun.com     pfn_t pfnlimit, uint_t *mcadr)
13110Sstevel@tonic-gate {
13120Sstevel@tonic-gate 	int		rv = 0;
13130Sstevel@tonic-gate 	register int	brd, rbrd;
13140Sstevel@tonic-gate 	register boardset_t	localboardset;
13150Sstevel@tonic-gate 	uint_t		madr;
13160Sstevel@tonic-gate 	uint_t		smbase, smlimit;
13170Sstevel@tonic-gate 	pda_handle_t	ph;
13180Sstevel@tonic-gate 	procname_t	proc = "idnxf_shmem_add";
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate 	localboardset = idn_domain[idn.localid].dhw.dh_boardset;
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 	ASSERT(localboardset && boardset && ((localboardset & boardset) == 0));
13240Sstevel@tonic-gate 	ASSERT(is_master ? (pfnbase && pfnlimit && mcadr) : 1);
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate 	if (pfnbase != PFN_INVALID) {
13270Sstevel@tonic-gate 		smbase  = (uint_t)PFN_TO_SMADDR(pfnbase);
13280Sstevel@tonic-gate 		smlimit = (uint_t)PFN_TO_SMADDR(pfnlimit);
13290Sstevel@tonic-gate 	} else {
13300Sstevel@tonic-gate 		smbase = smlimit = (uint_t)-1;
13310Sstevel@tonic-gate 	}
13320Sstevel@tonic-gate 	PR_REGS("%s: is_master=%d, boardset=0x%x, smbase=0x%x, smlimit=%x\n",
1333*11066Srafael.vanoni@sun.com 	    proc, is_master, boardset, smbase, smlimit);
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 	/*
13360Sstevel@tonic-gate 	 * Need to serialize hardware access so we don't have multiple
13370Sstevel@tonic-gate 	 * threads attempting to access hardware regs simulataneously.
13380Sstevel@tonic-gate 	 * This should not be a significant performance penalty since
13390Sstevel@tonic-gate 	 * the hardware is only touched when domains are linking or
13400Sstevel@tonic-gate 	 * unlinking.
13410Sstevel@tonic-gate 	 */
13420Sstevel@tonic-gate 	mutex_enter(&idn_xf_mutex);
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate 	/*
13450Sstevel@tonic-gate 	 * Map in the post2obp structure so we can find
13460Sstevel@tonic-gate 	 * bus config information.
13470Sstevel@tonic-gate 	 */
13480Sstevel@tonic-gate 	ph = pda_open();
13490Sstevel@tonic-gate 	if (ph == (pda_handle_t)NULL) {
13500Sstevel@tonic-gate 		cmn_err(CE_WARN,
1351*11066Srafael.vanoni@sun.com 		    "IDN: 507: failed to map-in post2obp structure");
13520Sstevel@tonic-gate 		rv = -1;
13530Sstevel@tonic-gate 		goto done;
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 	} else if (!pda_is_valid(ph)) {
13560Sstevel@tonic-gate 		cmn_err(CE_WARN, "IDN: 508: post2obp checksum invalid");
13570Sstevel@tonic-gate 		rv = -1;
13580Sstevel@tonic-gate 		goto done;
13590Sstevel@tonic-gate 	}
13600Sstevel@tonic-gate 	/*
13610Sstevel@tonic-gate 	 * Take a checkpoint in bbsram for diagnostic purposes.
13620Sstevel@tonic-gate 	 */
13630Sstevel@tonic-gate 	CHECKPOINT_OPENED(IDNSB_CHKPT_SMR, boardset, 1);
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 	rv = idnxf_shmem_update_all(ph, boardset, smbase, smlimit, 1);
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 	if (rv || (is_master == 0))
13680Sstevel@tonic-gate 		goto done;
13690Sstevel@tonic-gate 
13700Sstevel@tonic-gate 	/*
13710Sstevel@tonic-gate 	 * If this is a slave (i.e. remote domain is_master),
13720Sstevel@tonic-gate 	 * then we need to deprogram our PCs.
13730Sstevel@tonic-gate 	 */
13740Sstevel@tonic-gate 	PR_REGS("%s: updating PC regs (lboardset=0x%x, rboardset=0x%x)\n",
1375*11066Srafael.vanoni@sun.com 	    proc, localboardset, boardset);
13760Sstevel@tonic-gate 
13770Sstevel@tonic-gate 	for (brd = 0; brd < MAX_BOARDS; brd++) {
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 		if (!BOARD_IN_SET(localboardset, brd))
13800Sstevel@tonic-gate 			continue;
13810Sstevel@tonic-gate 		/*
13820Sstevel@tonic-gate 		 * If this is a slave (i.e. remote domain is_master),
13830Sstevel@tonic-gate 		 * then we need to program our PCs.
13840Sstevel@tonic-gate 		 */
13850Sstevel@tonic-gate 		for (rbrd = 0; rbrd < MAX_BOARDS; rbrd++) {
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 			if ((madr = mcadr[rbrd]) == 0)
13880Sstevel@tonic-gate 				continue;
13890Sstevel@tonic-gate 
13900Sstevel@tonic-gate 			ASSERT(BOARD_IN_SET(boardset, rbrd));
13910Sstevel@tonic-gate 			/*
13920Sstevel@tonic-gate 			 * Write the MC adr for the respective
13930Sstevel@tonic-gate 			 * remote board (rbrd) into the PCs of
13940Sstevel@tonic-gate 			 * the given local board (brd).
13950Sstevel@tonic-gate 			 */
13960Sstevel@tonic-gate 			if (pc_write_madr(ph, brd, rbrd, madr) < 0) {
13970Sstevel@tonic-gate 				cmn_err(CE_WARN,
1398*11066Srafael.vanoni@sun.com 				    "IDN: 512: failed [add] write-madr "
1399*11066Srafael.vanoni@sun.com 				    "(bd=%d, rbd=%d, madr=0x%x)",
1400*11066Srafael.vanoni@sun.com 				    brd, rbrd, madr);
14010Sstevel@tonic-gate 				rv = -1;
14020Sstevel@tonic-gate 				goto done;
14030Sstevel@tonic-gate 			}
14040Sstevel@tonic-gate 		}
14050Sstevel@tonic-gate 	}
14060Sstevel@tonic-gate 
14070Sstevel@tonic-gate done:
14080Sstevel@tonic-gate 	if (ph)
14090Sstevel@tonic-gate 		pda_close(ph);
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	mutex_exit(&idn_xf_mutex);
14120Sstevel@tonic-gate 	/*
14130Sstevel@tonic-gate 	 * XXX
14140Sstevel@tonic-gate 	 *
14150Sstevel@tonic-gate 	 * Failure here is fatal.  Disable IDN?
14160Sstevel@tonic-gate 	 * NOn-zero return value will at least prevent
14170Sstevel@tonic-gate 	 * linkage with domain - probably sufficient.
14180Sstevel@tonic-gate 	 */
14190Sstevel@tonic-gate 	return (rv);
14200Sstevel@tonic-gate }
14210Sstevel@tonic-gate 
14220Sstevel@tonic-gate /*
14230Sstevel@tonic-gate  * Remove the respective boardset from the local domain's
14240Sstevel@tonic-gate  * hardware configuration with respect to the SMR.
14250Sstevel@tonic-gate  *
14260Sstevel@tonic-gate  * is_master	Indicates remote domain is a master.
14270Sstevel@tonic-gate  */
14280Sstevel@tonic-gate int
idnxf_shmem_sub(int is_master,boardset_t boardset)14290Sstevel@tonic-gate idnxf_shmem_sub(int is_master, boardset_t boardset)
14300Sstevel@tonic-gate {
14310Sstevel@tonic-gate 	int		rv = 0;
14320Sstevel@tonic-gate 	register int	brd, rbrd;
14330Sstevel@tonic-gate 	register boardset_t	localboardset;
14340Sstevel@tonic-gate 	pda_handle_t	ph;
14350Sstevel@tonic-gate 	procname_t	proc = "idnxf_shmem_sub";
14360Sstevel@tonic-gate 
14370Sstevel@tonic-gate 	localboardset = idn_domain[idn.localid].dhw.dh_boardset;
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate 	ASSERT(localboardset && boardset && ((localboardset & boardset) == 0));
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 	PR_REGS("%s: is_master=%d, boardset=0x%x\n",
1442*11066Srafael.vanoni@sun.com 	    proc, is_master, boardset);
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 	/*
14450Sstevel@tonic-gate 	 * Need to serialize hardware access so we don't have multiple
14460Sstevel@tonic-gate 	 * threads attempting to access hardware regs simulataneously.
14470Sstevel@tonic-gate 	 * This should not be a significant performance penalty since
14480Sstevel@tonic-gate 	 * the hardware is only touched when domains are linking or
14490Sstevel@tonic-gate 	 * unlinking.
14500Sstevel@tonic-gate 	 */
14510Sstevel@tonic-gate 	mutex_enter(&idn_xf_mutex);
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate 	/*
14540Sstevel@tonic-gate 	 * Map in the post2obp structure so we can find
14550Sstevel@tonic-gate 	 * bus config information.
14560Sstevel@tonic-gate 	 */
14570Sstevel@tonic-gate 	ph = pda_open();
14580Sstevel@tonic-gate 	if (ph == (pda_handle_t)NULL) {
14590Sstevel@tonic-gate 		cmn_err(CE_WARN,
1460*11066Srafael.vanoni@sun.com 		    "IDN: 507: failed to map-in post2obp structure");
14610Sstevel@tonic-gate 		rv = -1;
14620Sstevel@tonic-gate 		goto done;
14630Sstevel@tonic-gate 
14640Sstevel@tonic-gate 	} else if (!pda_is_valid(ph)) {
14650Sstevel@tonic-gate 		cmn_err(CE_WARN, "IDN: 508: post2obp checksum invalid");
14660Sstevel@tonic-gate 		rv = -1;
14670Sstevel@tonic-gate 		goto done;
14680Sstevel@tonic-gate 	}
14690Sstevel@tonic-gate 	/*
14700Sstevel@tonic-gate 	 * Take a checkpoint in bbsram for diagnostic purposes.
14710Sstevel@tonic-gate 	 */
14720Sstevel@tonic-gate 	CHECKPOINT_CLOSED(IDNSB_CHKPT_SMR, boardset, 2);
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate 	rv = idnxf_shmem_update_all(ph, boardset, (uint_t)-1, (uint_t)-1, 0);
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 	if (rv || (is_master == 0))
14770Sstevel@tonic-gate 		goto done;
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate 	/*
14800Sstevel@tonic-gate 	 * If this is a slave (i.e. remote domain is_master),
14810Sstevel@tonic-gate 	 * then we need to deprogram our PCs.
14820Sstevel@tonic-gate 	 */
14830Sstevel@tonic-gate 	PR_REGS("%s: reseting PC regs (lboardset=0x%x, rboardset=0x%x)\n",
1484*11066Srafael.vanoni@sun.com 	    proc, localboardset, boardset);
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 	for (brd = 0; brd < MAX_BOARDS; brd++) {
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 		if (!BOARD_IN_SET(localboardset, brd))
14890Sstevel@tonic-gate 			continue;
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 		for (rbrd = 0; rbrd < MAX_BOARDS; rbrd++) {
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 			if (!BOARD_IN_SET(boardset, rbrd))
14940Sstevel@tonic-gate 				continue;
14950Sstevel@tonic-gate 			/*
14960Sstevel@tonic-gate 			 * Clear the MC adr for the respective
14970Sstevel@tonic-gate 			 * remote board (rbrd) into the PCs of
14980Sstevel@tonic-gate 			 * the given local board (brd).
14990Sstevel@tonic-gate 			 */
15000Sstevel@tonic-gate 			if (pc_write_madr(ph, brd, rbrd, 0) < 0) {
15010Sstevel@tonic-gate 				cmn_err(CE_WARN,
1502*11066Srafael.vanoni@sun.com 				    "IDN: 512: failed [del] write-madr "
1503*11066Srafael.vanoni@sun.com 				    "(bd=%d, rbd=%d, madr=0x%x)",
1504*11066Srafael.vanoni@sun.com 				    brd, rbrd, 0);
15050Sstevel@tonic-gate 				rv = -1;
15060Sstevel@tonic-gate 				goto done;
15070Sstevel@tonic-gate 			}
15080Sstevel@tonic-gate 		}
15090Sstevel@tonic-gate 	}
15100Sstevel@tonic-gate 
15110Sstevel@tonic-gate done:
15120Sstevel@tonic-gate 	if (ph)
15130Sstevel@tonic-gate 		pda_close(ph);
15140Sstevel@tonic-gate 	mutex_exit(&idn_xf_mutex);
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate 	return (rv);
15170Sstevel@tonic-gate }
15180Sstevel@tonic-gate 
15190Sstevel@tonic-gate /*
15200Sstevel@tonic-gate  * We cannot cross-trap cpu_flush_ecache since it references
15210Sstevel@tonic-gate  * %g7 via CPU.  It's possible that %g7 may not be set up
15220Sstevel@tonic-gate  * when the trap comes in, and could thus cause a crash.
15230Sstevel@tonic-gate  * Well...at least that's what has been happening when I
15240Sstevel@tonic-gate  * tried x-calls within an xc_attention (KMISS) panic.
15250Sstevel@tonic-gate  * Instead we use cross-calls.  However, since we can't
15260Sstevel@tonic-gate  * xc_attention around a cross-call, we have not guaranteed
15270Sstevel@tonic-gate  * way of knowing the operation succeeded.  To synchronize
15280Sstevel@tonic-gate  * this flush operation across cpus, we use a semaphore
15290Sstevel@tonic-gate  * which is V'd by the receiving cpus and P'd by the caller
15300Sstevel@tonic-gate  * initiating the all-cpus flush.
15310Sstevel@tonic-gate  */
15320Sstevel@tonic-gate /*ARGSUSED0*/
15330Sstevel@tonic-gate void
idn_flush_ecache(uint64_t arg1,uint64_t arg2)15340Sstevel@tonic-gate idn_flush_ecache(uint64_t arg1, uint64_t arg2)
15350Sstevel@tonic-gate {
15360Sstevel@tonic-gate 	extern void	cpu_flush_ecache(void);
15370Sstevel@tonic-gate 
15380Sstevel@tonic-gate 	cpu_flush_ecache();
15390Sstevel@tonic-gate 	/*
15400Sstevel@tonic-gate 	 * Paranoia...Give things a chance to drain.
15410Sstevel@tonic-gate 	 */
15420Sstevel@tonic-gate 	drv_usecwait(500000);	/* 500 msec */
15430Sstevel@tonic-gate }
15440Sstevel@tonic-gate /*
15450Sstevel@tonic-gate  * Flush the ecache's of all the cpus within this domain of
15460Sstevel@tonic-gate  * any possible SMR references.
15470Sstevel@tonic-gate  * This logic is borrowed from ecc.c:cpu_flush_ecache().
15480Sstevel@tonic-gate  */
15490Sstevel@tonic-gate void
idnxf_flushall_ecache()15500Sstevel@tonic-gate idnxf_flushall_ecache()
15510Sstevel@tonic-gate {
15520Sstevel@tonic-gate 	cpuset_t	local_cpuset;
15530Sstevel@tonic-gate 	procname_t	proc = "idnxf_flushall_ecache";
15540Sstevel@tonic-gate 
15550Sstevel@tonic-gate 
1556*11066Srafael.vanoni@sun.com 	PR_XF("%s: flushing ecache (cpu_ready_set = 0x%x.%x)\n", proc,
1557*11066Srafael.vanoni@sun.com 	    UPPER32_CPUMASK(cpu_ready_set), LOWER32_CPUMASK(cpu_ready_set));
15580Sstevel@tonic-gate 
15590Sstevel@tonic-gate 	CHECKPOINT_CACHE_CLEAR_DEBUG(1);
15600Sstevel@tonic-gate 	CHECKPOINT_CACHE_STEP_DEBUG(0x1, 2);
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 	local_cpuset = cpu_ready_set;
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate 	xc_attention(local_cpuset);
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate 	/*
15670Sstevel@tonic-gate 	 * We tell each cpu to do a flush and then we hit
15680Sstevel@tonic-gate 	 * a semaphore to synchronize with all of them
15690Sstevel@tonic-gate 	 * to guarantee they have completed the flush before
15700Sstevel@tonic-gate 	 * we continue on.  We have to do this type of
15710Sstevel@tonic-gate 	 * sychronization since we can't xc_attention around
15720Sstevel@tonic-gate 	 * a cross-call.
15730Sstevel@tonic-gate 	 */
15740Sstevel@tonic-gate 	CHECKPOINT_CACHE_STEP_DEBUG(0x2, 3);
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate 	xc_all(idn_flush_ecache, 0, 0);
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 	CHECKPOINT_CACHE_STEP_DEBUG(0x4, 4);
15790Sstevel@tonic-gate 
15800Sstevel@tonic-gate 	xc_dismissed(local_cpuset);
15810Sstevel@tonic-gate 
15820Sstevel@tonic-gate 	CHECKPOINT_CACHE_STEP_DEBUG(0x8, 5);
15830Sstevel@tonic-gate }
15840Sstevel@tonic-gate 
15850Sstevel@tonic-gate /*
15860Sstevel@tonic-gate  * --------------------------------------------------
15870Sstevel@tonic-gate  */
15880Sstevel@tonic-gate static int
verify_smregs(int brd,int bus,boardset_t smmask,uint_t smbase,uint_t smlimit)1589*11066Srafael.vanoni@sun.com verify_smregs(int brd, int bus, boardset_t smmask, uint_t smbase, uint_t
1590*11066Srafael.vanoni@sun.com     smlimit)
15910Sstevel@tonic-gate {
15920Sstevel@tonic-gate 	int		rv = 0;
15930Sstevel@tonic-gate 	uint_t		smreg;
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate 	if (smmask != (boardset_t)-1) {
15960Sstevel@tonic-gate 		smreg = (uint_t)cic_read_sm_mask(brd, bus);
15970Sstevel@tonic-gate 		if (smreg != (uint_t)smmask) {
15980Sstevel@tonic-gate 			cmn_err(CE_WARN,
1599*11066Srafael.vanoni@sun.com 			    "IDN: 513: sm-mask error "
1600*11066Srafael.vanoni@sun.com 			    "(expected = 0x%x, actual = 0x%x)",
1601*11066Srafael.vanoni@sun.com 			    (uint_t)smmask, smreg);
16020Sstevel@tonic-gate 			rv++;
16030Sstevel@tonic-gate 		}
16040Sstevel@tonic-gate 	}
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate 	if (smbase != (uint_t)-1) {
16070Sstevel@tonic-gate 		smreg = cic_read_sm_bar(brd, bus);
16080Sstevel@tonic-gate 		if (smreg != smbase) {
16090Sstevel@tonic-gate 			cmn_err(CE_WARN,
1610*11066Srafael.vanoni@sun.com 			    "IDN: 514: sm-base error "
1611*11066Srafael.vanoni@sun.com 			    "(expected = 0x%x, actual = 0x%x)",
1612*11066Srafael.vanoni@sun.com 			    smbase, smreg);
16130Sstevel@tonic-gate 			rv++;
16140Sstevel@tonic-gate 		}
16150Sstevel@tonic-gate 	}
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate 	if (smlimit != (uint_t)-1) {
16180Sstevel@tonic-gate 		smreg = cic_read_sm_lar(brd, bus);
16190Sstevel@tonic-gate 		if (smreg != smlimit) {
16200Sstevel@tonic-gate 			cmn_err(CE_WARN,
1621*11066Srafael.vanoni@sun.com 			    "IDN: 515: sm-limit error "
1622*11066Srafael.vanoni@sun.com 			    "(expected = 0x%x, actual = 0x%x)",
1623*11066Srafael.vanoni@sun.com 			    smlimit, smreg);
16240Sstevel@tonic-gate 			rv++;
16250Sstevel@tonic-gate 		}
16260Sstevel@tonic-gate 	}
16270Sstevel@tonic-gate 
16280Sstevel@tonic-gate 	return (rv ? -1 : 0);
16290Sstevel@tonic-gate }
16300Sstevel@tonic-gate 
16310Sstevel@tonic-gate /*
16320Sstevel@tonic-gate  * -------------------------------------------------------------
16330Sstevel@tonic-gate  */
16340Sstevel@tonic-gate int
idn_cpu_per_board(pda_handle_t ph,cpuset_t cset,struct hwconfig * hwp)16350Sstevel@tonic-gate idn_cpu_per_board(pda_handle_t ph, cpuset_t cset, struct hwconfig *hwp)
16360Sstevel@tonic-gate {
16370Sstevel@tonic-gate 	int		b, err = 0;
16380Sstevel@tonic-gate 	boardset_t	bset, cpu_bset;
16390Sstevel@tonic-gate 	board_desc_t	*lbp;
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 	if (!idn_check_cpu_per_board)
16420Sstevel@tonic-gate 		return (1);
16430Sstevel@tonic-gate 
16440Sstevel@tonic-gate 	bset = hwp->dh_boardset;
16450Sstevel@tonic-gate 	CPUSET_TO_BOARDSET(cset, cpu_bset);
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 	/*
16480Sstevel@tonic-gate 	 * Every board has at least one cpu, we're happy.
16490Sstevel@tonic-gate 	 */
16500Sstevel@tonic-gate 	if (cpu_bset == bset)
16510Sstevel@tonic-gate 		return (1);
16520Sstevel@tonic-gate 
16530Sstevel@tonic-gate 	/*
16540Sstevel@tonic-gate 	 * Well, not all boards had cpus.  That's okay so
16550Sstevel@tonic-gate 	 * long as they don't have memory also.
16560Sstevel@tonic-gate 	 * Get rid of the boards that have a cpu.
16570Sstevel@tonic-gate 	 */
16580Sstevel@tonic-gate 	bset &= ~cpu_bset;
16590Sstevel@tonic-gate 	/*
16600Sstevel@tonic-gate 	 * None of the remaining boards in the set shold have mem.
16610Sstevel@tonic-gate 	 */
16620Sstevel@tonic-gate 	err = 0;
16630Sstevel@tonic-gate 
16640Sstevel@tonic-gate 	/*
16650Sstevel@tonic-gate 	 * A NULL post2obp pointer indicates we're checking
16660Sstevel@tonic-gate 	 * the config of a remote domain.  Since we can't
16670Sstevel@tonic-gate 	 * look at the post2obp of the remote domain, we'll
16680Sstevel@tonic-gate 	 * have to trust what he passed us in his config.
16690Sstevel@tonic-gate 	 */
16700Sstevel@tonic-gate 	if (ph && !pda_is_valid(ph)) {
16710Sstevel@tonic-gate 		cmn_err(CE_WARN, "IDN: 508: post2obp checksum invalid");
16720Sstevel@tonic-gate 		return (0);
16730Sstevel@tonic-gate 	}
16740Sstevel@tonic-gate 
16750Sstevel@tonic-gate 	for (b = 0; b < MAX_BOARDS; b++) {
16760Sstevel@tonic-gate 		if (!BOARD_IN_SET(bset, b))
16770Sstevel@tonic-gate 			continue;
16780Sstevel@tonic-gate 
16790Sstevel@tonic-gate 		lbp = ph ? pda_get_board_info(ph, b) : NULL;
16800Sstevel@tonic-gate 
16810Sstevel@tonic-gate 		if ((lbp &&
1682*11066Srafael.vanoni@sun.com 		    (BDA_NBL(lbp->bda_board, BDA_MC_NBL) == BDAN_GOOD)) ||
1683*11066Srafael.vanoni@sun.com 		    (!lbp && hwp->dh_mcadr[b])) {
16840Sstevel@tonic-gate 			err++;
16850Sstevel@tonic-gate 			cmn_err(CE_WARN,
1686*11066Srafael.vanoni@sun.com 			    "IDN: 516: (%s) board %d has memory, "
1687*11066Srafael.vanoni@sun.com 			    "but no CPUs - CPU per memory board REQUIRED",
1688*11066Srafael.vanoni@sun.com 			    ph ? "local" : "remote", b);
16890Sstevel@tonic-gate 		}
16900Sstevel@tonic-gate 	}
16910Sstevel@tonic-gate 
16920Sstevel@tonic-gate 	return (err ? 0 : 1);
16930Sstevel@tonic-gate }
1694