xref: /onnv-gate/usr/src/uts/sun4u/io/opl_cfg.c (revision 7696:21f5c73c0c15)
11772Sjl139090 /*
21772Sjl139090  * CDDL HEADER START
31772Sjl139090  *
41772Sjl139090  * The contents of this file are subject to the terms of the
51772Sjl139090  * Common Development and Distribution License (the "License").
61772Sjl139090  * You may not use this file except in compliance with the License.
71772Sjl139090  *
81772Sjl139090  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91772Sjl139090  * or http://www.opensolaris.org/os/licensing.
101772Sjl139090  * See the License for the specific language governing permissions
111772Sjl139090  * and limitations under the License.
121772Sjl139090  *
131772Sjl139090  * When distributing Covered Code, include this CDDL HEADER in each
141772Sjl139090  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151772Sjl139090  * If applicable, add the following below this CDDL HEADER, with the
161772Sjl139090  * fields enclosed by brackets "[]" replaced with your own identifying
171772Sjl139090  * information: Portions Copyright [yyyy] [name of copyright owner]
181772Sjl139090  *
191772Sjl139090  * CDDL HEADER END
201772Sjl139090  */
211772Sjl139090 /*
22*7696SRichard.Bean@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
231772Sjl139090  * Use is subject to license terms.
241772Sjl139090  */
251772Sjl139090 
261772Sjl139090 #include <sys/conf.h>
271772Sjl139090 #include <sys/kmem.h>
281772Sjl139090 #include <sys/debug.h>
291772Sjl139090 #include <sys/modctl.h>
301772Sjl139090 #include <sys/autoconf.h>
311772Sjl139090 #include <sys/hwconf.h>
321772Sjl139090 #include <sys/ddi_impldefs.h>
331772Sjl139090 #include <sys/ddi.h>
341772Sjl139090 #include <sys/sunddi.h>
351772Sjl139090 #include <sys/sunndi.h>
361772Sjl139090 #include <sys/ndi_impldefs.h>
371772Sjl139090 #include <sys/machsystm.h>
381772Sjl139090 #include <sys/fcode.h>
391772Sjl139090 #include <sys/promif.h>
401772Sjl139090 #include <sys/promimpl.h>
411772Sjl139090 #include <sys/opl_cfg.h>
421772Sjl139090 #include <sys/scfd/scfostoescf.h>
431772Sjl139090 
441772Sjl139090 static unsigned int		opl_cfg_inited;
451772Sjl139090 static opl_board_cfg_t		opl_boards[HWD_SBS_PER_DOMAIN];
461772Sjl139090 
471772Sjl139090 /*
481772Sjl139090  * Module control operations
491772Sjl139090  */
501772Sjl139090 
511772Sjl139090 extern struct mod_ops mod_miscops;
521772Sjl139090 
531772Sjl139090 static struct modlmisc modlmisc = {
541772Sjl139090 	&mod_miscops,				/* Type of module */
55*7696SRichard.Bean@Sun.COM 	"OPL opl_cfg"
561772Sjl139090 };
571772Sjl139090 
581772Sjl139090 static struct modlinkage modlinkage = {
591772Sjl139090 	MODREV_1, (void *)&modlmisc, NULL
601772Sjl139090 };
611772Sjl139090 
621772Sjl139090 static int	opl_map_in(dev_info_t *, fco_handle_t, fc_ci_t *);
631772Sjl139090 static int	opl_map_out(dev_info_t *, fco_handle_t, fc_ci_t *);
641772Sjl139090 static int	opl_register_fetch(dev_info_t *, fco_handle_t, fc_ci_t *);
651772Sjl139090 static int	opl_register_store(dev_info_t *, fco_handle_t, fc_ci_t *);
661772Sjl139090 
671772Sjl139090 static int	opl_claim_memory(dev_info_t *, fco_handle_t, fc_ci_t *);
681772Sjl139090 static int	opl_release_memory(dev_info_t *, fco_handle_t, fc_ci_t *);
691772Sjl139090 static int	opl_vtop(dev_info_t *, fco_handle_t, fc_ci_t *);
701772Sjl139090 
711772Sjl139090 static int	opl_config_child(dev_info_t *, fco_handle_t, fc_ci_t *);
721772Sjl139090 
731772Sjl139090 static int	opl_get_fcode_size(dev_info_t *, fco_handle_t, fc_ci_t *);
741772Sjl139090 static int	opl_get_fcode(dev_info_t *, fco_handle_t, fc_ci_t *);
751772Sjl139090 
761772Sjl139090 static int	opl_map_phys(dev_info_t *, struct regspec *,  caddr_t *,
771772Sjl139090 				ddi_device_acc_attr_t *, ddi_acc_handle_t *);
781772Sjl139090 static void	opl_unmap_phys(ddi_acc_handle_t *);
791772Sjl139090 static int	opl_get_hwd_va(dev_info_t *, fco_handle_t, fc_ci_t *);
801982Smv143129 static int	opl_master_interrupt(dev_info_t *, fco_handle_t, fc_ci_t *);
811772Sjl139090 
821772Sjl139090 extern int	prom_get_fcode_size(char *);
831772Sjl139090 extern int	prom_get_fcode(char *, char *);
841772Sjl139090 
851982Smv143129 static int	master_interrupt_init(uint32_t, uint32_t);
861982Smv143129 
871772Sjl139090 #define	PROBE_STR_SIZE	64
881772Sjl139090 #define	UNIT_ADDR_SIZE	64
891772Sjl139090 
901772Sjl139090 opl_fc_ops_t	opl_fc_ops[] = {
911772Sjl139090 
921772Sjl139090 	{	FC_MAP_IN,		opl_map_in},
931772Sjl139090 	{	FC_MAP_OUT,		opl_map_out},
941772Sjl139090 	{	"rx@",			opl_register_fetch},
951772Sjl139090 	{	FC_RL_FETCH,		opl_register_fetch},
961772Sjl139090 	{	FC_RW_FETCH,		opl_register_fetch},
971772Sjl139090 	{	FC_RB_FETCH,		opl_register_fetch},
981772Sjl139090 	{	"rx!",			opl_register_store},
991772Sjl139090 	{	FC_RL_STORE,		opl_register_store},
1001772Sjl139090 	{	FC_RW_STORE,		opl_register_store},
1011772Sjl139090 	{	FC_RB_STORE,		opl_register_store},
1021772Sjl139090 	{	"claim-memory",		opl_claim_memory},
1031772Sjl139090 	{	"release-memory",	opl_release_memory},
1041772Sjl139090 	{	"vtop",			opl_vtop},
1051772Sjl139090 	{	FC_CONFIG_CHILD,	opl_config_child},
1061772Sjl139090 	{	FC_GET_FCODE_SIZE,	opl_get_fcode_size},
1071772Sjl139090 	{	FC_GET_FCODE,		opl_get_fcode},
1081772Sjl139090 	{	"get-hwd-va",		opl_get_hwd_va},
1091982Smv143129 	{	"master-interrupt",	opl_master_interrupt},
1101772Sjl139090 	{	NULL,			NULL}
1111772Sjl139090 
1121772Sjl139090 };
1131772Sjl139090 
1141772Sjl139090 extern caddr_t	efcode_vaddr;
1151772Sjl139090 extern int	efcode_size;
1161772Sjl139090 
1171772Sjl139090 #ifdef DEBUG
1181772Sjl139090 #define	HWDDUMP_OFFSETS		1
1191772Sjl139090 #define	HWDDUMP_ALL_STATUS	2
1201772Sjl139090 #define	HWDDUMP_CHUNKS		3
1211772Sjl139090 #define	HWDDUMP_SBP		4
1221772Sjl139090 
1231772Sjl139090 int		hwddump_flags = HWDDUMP_SBP | HWDDUMP_CHUNKS;
1241772Sjl139090 #endif
1251772Sjl139090 
1261982Smv143129 static int	master_interrupt_inited = 0;
1271982Smv143129 
1281772Sjl139090 int
_init()1291772Sjl139090 _init()
1301772Sjl139090 {
1311772Sjl139090 	int	err = 0;
1321772Sjl139090 
1331772Sjl139090 	/*
1341772Sjl139090 	 * Create a resource map for the contiguous memory allocated
1351772Sjl139090 	 * at start-of-day in startup.c
1361772Sjl139090 	 */
1371772Sjl139090 	err = ndi_ra_map_setup(ddi_root_node(), "opl-fcodemem");
1381772Sjl139090 	if (err == NDI_FAILURE) {
1391772Sjl139090 		cmn_err(CE_WARN, "Cannot setup resource map opl-fcodemem\n");
1401772Sjl139090 		return (1);
1411772Sjl139090 	}
1421772Sjl139090 
1431772Sjl139090 	/*
1441772Sjl139090 	 * Put the allocated memory into the pool.
1451772Sjl139090 	 */
1461772Sjl139090 	(void) ndi_ra_free(ddi_root_node(), (uint64_t)efcode_vaddr,
1475037Sjl139090 	    (uint64_t)efcode_size, "opl-fcodemem", 0);
1481772Sjl139090 
1491772Sjl139090 	if ((err = mod_install(&modlinkage)) != 0) {
1501772Sjl139090 		cmn_err(CE_WARN, "opl_cfg failed to load, error=%d", err);
1511772Sjl139090 		(void) ndi_ra_map_destroy(ddi_root_node(), "opl-fcodemem");
1521772Sjl139090 	}
1531772Sjl139090 
1541772Sjl139090 	return (err);
1551772Sjl139090 }
1561772Sjl139090 
1571772Sjl139090 int
_fini(void)1581772Sjl139090 _fini(void)
1591772Sjl139090 {
1601772Sjl139090 	int ret;
1611772Sjl139090 
1621772Sjl139090 	ret = (mod_remove(&modlinkage));
1631772Sjl139090 	if (ret != 0)
1641772Sjl139090 		return (ret);
1651772Sjl139090 
1661772Sjl139090 	(void) ndi_ra_map_destroy(ddi_root_node(), "opl-fcodemem");
1671772Sjl139090 
1681772Sjl139090 	return (ret);
1691772Sjl139090 }
1701772Sjl139090 
1711772Sjl139090 int
_info(modinfop)1721772Sjl139090 _info(modinfop)
1731772Sjl139090 struct modinfo *modinfop;
1741772Sjl139090 {
1751772Sjl139090 	return (mod_info(&modlinkage, modinfop));
1761772Sjl139090 }
1771772Sjl139090 
1781772Sjl139090 #ifdef DEBUG
1791772Sjl139090 static void
opl_dump_hwd(opl_probe_t * probe)1801772Sjl139090 opl_dump_hwd(opl_probe_t *probe)
1811772Sjl139090 {
1821772Sjl139090 	hwd_header_t		*hdrp;
1831772Sjl139090 	hwd_sb_status_t		*statp;
1841772Sjl139090 	hwd_domain_info_t	*dinfop;
1851772Sjl139090 	hwd_sb_t		*sbp;
1861772Sjl139090 	hwd_cpu_chip_t		*chips;
1871772Sjl139090 	hwd_pci_ch_t		*channels;
1881772Sjl139090 	int			board, i, status;
1891772Sjl139090 
1901772Sjl139090 	board = probe->pr_board;
1911772Sjl139090 
1921772Sjl139090 	hdrp = probe->pr_hdr;
1931772Sjl139090 	statp = probe->pr_sb_status;
1941772Sjl139090 	dinfop = probe->pr_dinfo;
1951772Sjl139090 	sbp = probe->pr_sb;
1961772Sjl139090 
1971772Sjl139090 	printf("HWD: board %d\n", board);
1981772Sjl139090 	printf("HWD:magic = 0x%x\n", hdrp->hdr_magic);
1991772Sjl139090 	printf("HWD:version = 0x%x.%x\n", hdrp->hdr_version.major,
2001772Sjl139090 	    hdrp->hdr_version.minor);
2011772Sjl139090 
2021772Sjl139090 	if (hwddump_flags & HWDDUMP_OFFSETS) {
2031772Sjl139090 		printf("HWD:status offset = 0x%x\n",
2041772Sjl139090 		    hdrp->hdr_sb_status_offset);
2051772Sjl139090 		printf("HWD:domain offset = 0x%x\n",
2061772Sjl139090 		    hdrp->hdr_domain_info_offset);
2071772Sjl139090 		printf("HWD:board offset = 0x%x\n", hdrp->hdr_sb_info_offset);
2081772Sjl139090 	}
2091772Sjl139090 
2101772Sjl139090 	if (hwddump_flags & HWDDUMP_SBP)
2111772Sjl139090 		printf("HWD:sb_t ptr = 0x%p\n", (void *)probe->pr_sb);
2121772Sjl139090 
2131772Sjl139090 	if (hwddump_flags & HWDDUMP_ALL_STATUS) {
2141772Sjl139090 		int bd;
2151772Sjl139090 		printf("HWD:board status =");
2161772Sjl139090 		for (bd = 0; bd < HWD_SBS_PER_DOMAIN; bd++)
2171772Sjl139090 			printf("%x ", statp->sb_status[bd]);
2181772Sjl139090 		printf("\n");
2191772Sjl139090 	} else {
2201772Sjl139090 		printf("HWD:board status = %d\n", statp->sb_status[board]);
2211772Sjl139090 	}
2221772Sjl139090 
2231772Sjl139090 	printf("HWD:banner name = %s\n", dinfop->dinf_banner_name);
2241772Sjl139090 	printf("HWD:platform = %s\n", dinfop->dinf_platform_token);
2251772Sjl139090 
2261772Sjl139090 	printf("HWD:chip status:\n");
2271772Sjl139090 	chips = &sbp->sb_cmu.cmu_cpu_chips[0];
2281772Sjl139090 	for (i = 0; i < HWD_CPU_CHIPS_PER_CMU; i++) {
2291772Sjl139090 
2301772Sjl139090 		status = chips[i].chip_status;
2311772Sjl139090 		printf("chip[%d] = ", i);
2321772Sjl139090 		if (HWD_STATUS_NONE(status))
2331772Sjl139090 			printf("none");
2341772Sjl139090 		else if (HWD_STATUS_FAILED(status))
2351772Sjl139090 			printf("fail");
2361772Sjl139090 		else if (HWD_STATUS_OK(status))
2371772Sjl139090 			printf("ok");
2381772Sjl139090 		printf("\n");
2391772Sjl139090 	}
2401772Sjl139090 
2411772Sjl139090 	if (hwddump_flags & HWDDUMP_CHUNKS) {
2421772Sjl139090 		int chunk;
2431772Sjl139090 		hwd_memory_t *mem = &sbp->sb_cmu.cmu_memory;
2441772Sjl139090 		printf("HWD:chunks:\n");
2451772Sjl139090 		for (chunk = 0; chunk < HWD_MAX_MEM_CHUNKS; chunk++)
2461772Sjl139090 			printf("\t%d 0x%lx 0x%lx\n", chunk,
2471772Sjl139090 			    mem->mem_chunks[chunk].chnk_start_address,
2481772Sjl139090 			    mem->mem_chunks[chunk].chnk_size);
2491772Sjl139090 	}
2501772Sjl139090 
2511772Sjl139090 	printf("HWD:channel status:\n");
2521772Sjl139090 	channels = &sbp->sb_pci_ch[0];
2531772Sjl139090 	for (i = 0; i < HWD_PCI_CHANNELS_PER_SB; i++) {
2541772Sjl139090 
2551772Sjl139090 		status = channels[i].pci_status;
2561772Sjl139090 		printf("channels[%d] = ", i);
2571772Sjl139090 		if (HWD_STATUS_NONE(status))
2581772Sjl139090 			printf("none");
2591772Sjl139090 		else if (HWD_STATUS_FAILED(status))
2601772Sjl139090 			printf("fail");
2611772Sjl139090 		else if (HWD_STATUS_OK(status))
2621772Sjl139090 			printf("ok");
2631772Sjl139090 		printf("\n");
2641772Sjl139090 	}
2651772Sjl139090 	printf("channels[%d] = ", i);
2661772Sjl139090 	status = sbp->sb_cmu.cmu_ch.chan_status;
2671772Sjl139090 	if (HWD_STATUS_NONE(status))
2681772Sjl139090 		printf("none");
2691772Sjl139090 	else if (HWD_STATUS_FAILED(status))
2701772Sjl139090 		printf("fail");
2711772Sjl139090 	else if (HWD_STATUS_OK(status))
2721772Sjl139090 		printf("ok");
2731772Sjl139090 	printf("\n");
2741772Sjl139090 }
2751772Sjl139090 #endif /* DEBUG */
2761772Sjl139090 
2771772Sjl139090 #ifdef UCTEST
2781772Sjl139090 	/*
2791772Sjl139090 	 * For SesamI debugging, just map the SRAM directly to a kernel
2801772Sjl139090 	 * VA and read it out from there
2811772Sjl139090 	 */
2821772Sjl139090 
2831772Sjl139090 #include <sys/vmem.h>
2841772Sjl139090 #include <vm/seg_kmem.h>
2851772Sjl139090 
2861772Sjl139090 /*
2871772Sjl139090  * 0x4081F1323000LL is the HWD base address for LSB 0. But we need to map
2881772Sjl139090  * at page boundaries. So, we use a base address of 0x4081F1322000LL.
2891772Sjl139090  * Note that this has to match the HWD base pa set in .sesami-common-defs.
2901772Sjl139090  *
2911772Sjl139090  * The size specified for the HWD in the SCF spec is 36K. But since
2921772Sjl139090  * we adjusted the base address by 4K, we need to use 40K for the
2931772Sjl139090  * mapping size to cover the HWD. And 40K is also a multiple of the
2941772Sjl139090  * base page size.
2951772Sjl139090  */
2961772Sjl139090 #define	OPL_HWD_BASE(lsb)       \
2971772Sjl139090 (0x4081F1322000LL | (((uint64_t)(lsb)) << 40))
2981772Sjl139090 
2991772Sjl139090 	void    *opl_hwd_vaddr;
3001772Sjl139090 #endif /* UCTEST */
3011772Sjl139090 
3021772Sjl139090 /*
3031772Sjl139090  * Get the hardware descriptor from SCF.
3041772Sjl139090  */
3051772Sjl139090 
3061772Sjl139090 /*ARGSUSED*/
3071772Sjl139090 int
opl_read_hwd(int board,hwd_header_t ** hdrp,hwd_sb_status_t ** statp,hwd_domain_info_t ** dinfop,hwd_sb_t ** sbp)3081772Sjl139090 opl_read_hwd(int board, hwd_header_t **hdrp, hwd_sb_status_t **statp,
3091772Sjl139090 	hwd_domain_info_t **dinfop, hwd_sb_t **sbp)
3101772Sjl139090 {
3111772Sjl139090 	static int (*getinfop)(uint32_t, uint8_t, uint32_t, uint32_t *,
3121772Sjl139090 	    void *) = NULL;
3131772Sjl139090 	void *hwdp;
3141772Sjl139090 
3151772Sjl139090 	uint32_t key = KEY_ESCF;	/* required value */
3161772Sjl139090 	uint8_t  type = 0x40;		/* SUB_OS_RECEIVE_HWD */
3171772Sjl139090 	uint32_t transid = board;
3181772Sjl139090 	uint32_t datasize = HWD_DATA_SIZE;
3191772Sjl139090 
3201772Sjl139090 	hwd_header_t		*hd;
3211772Sjl139090 	hwd_sb_status_t		*st;
3221772Sjl139090 	hwd_domain_info_t	*di;
3231772Sjl139090 	hwd_sb_t		*sb;
3241772Sjl139090 
3251772Sjl139090 	int	ret;
3261772Sjl139090 
3271772Sjl139090 	if (opl_boards[board].cfg_hwd == NULL) {
3281772Sjl139090 #ifdef UCTEST
3291772Sjl139090 		/*
3301772Sjl139090 		 * Just map the HWD in SRAM to a kernel VA
3311772Sjl139090 		 */
3321772Sjl139090 
3331772Sjl139090 		size_t			size;
3341772Sjl139090 		pfn_t			pfn;
3351772Sjl139090 
3361772Sjl139090 		size = 0xA000;
3371772Sjl139090 
3381772Sjl139090 		opl_hwd_vaddr = vmem_alloc(heap_arena, size, VM_SLEEP);
3391772Sjl139090 		if (opl_hwd_vaddr == NULL) {
3401772Sjl139090 			cmn_err(CE_NOTE, "No space for HWD");
3411772Sjl139090 			return (-1);
3421772Sjl139090 		}
3431772Sjl139090 
3441772Sjl139090 		pfn = btop(OPL_HWD_BASE(board));
3451772Sjl139090 		hat_devload(kas.a_hat, opl_hwd_vaddr, size, pfn, PROT_READ,
3461772Sjl139090 		    HAT_LOAD_NOCONSIST | HAT_LOAD_LOCK);
3471772Sjl139090 
3481772Sjl139090 		hwdp = (void *)((char *)opl_hwd_vaddr + 0x1000);
3491772Sjl139090 		opl_boards[board].cfg_hwd = hwdp;
3501772Sjl139090 		ret = 0;
3511772Sjl139090 #else
3521772Sjl139090 
3531772Sjl139090 		/* find the scf_service_getinfo() function */
3541772Sjl139090 		if (getinfop == NULL)
3551772Sjl139090 			getinfop = (int (*)(uint32_t, uint8_t, uint32_t,
3561772Sjl139090 			    uint32_t *,
3571772Sjl139090 			    void *))modgetsymvalue("scf_service_getinfo", 0);
3581772Sjl139090 
3591772Sjl139090 		if (getinfop == NULL)
3601772Sjl139090 			return (-1);
3611772Sjl139090 
3621772Sjl139090 		/* allocate memory to receive the data */
3631772Sjl139090 		hwdp = kmem_alloc(HWD_DATA_SIZE, KM_SLEEP);
3641772Sjl139090 
3651772Sjl139090 		/* get the HWD */
3661772Sjl139090 		ret = (*getinfop)(key, type, transid, &datasize, hwdp);
3671772Sjl139090 		if (ret == 0)
3681772Sjl139090 			opl_boards[board].cfg_hwd = hwdp;
3691772Sjl139090 		else
3701772Sjl139090 			kmem_free(hwdp, HWD_DATA_SIZE);
3711772Sjl139090 #endif
3721772Sjl139090 	} else {
3731772Sjl139090 		hwdp = opl_boards[board].cfg_hwd;
3741772Sjl139090 		ret = 0;
3751772Sjl139090 	}
3761772Sjl139090 
3771772Sjl139090 	/* copy the data to the destination */
3781772Sjl139090 	if (ret == 0) {
3791772Sjl139090 		hd = (hwd_header_t *)hwdp;
3801772Sjl139090 		st = (hwd_sb_status_t *)
3811772Sjl139090 		    ((char *)hwdp + hd->hdr_sb_status_offset);
3821772Sjl139090 		di = (hwd_domain_info_t *)
3831772Sjl139090 		    ((char *)hwdp + hd->hdr_domain_info_offset);
3841772Sjl139090 		sb = (hwd_sb_t *)
3851772Sjl139090 		    ((char *)hwdp + hd->hdr_sb_info_offset);
3861772Sjl139090 		if (hdrp != NULL)
3871772Sjl139090 			*hdrp = hd;
3881772Sjl139090 		if (statp != NULL)
3891772Sjl139090 			*statp = st;
3901772Sjl139090 		if (dinfop != NULL)
3911772Sjl139090 			*dinfop = di;
3921772Sjl139090 		if (sbp != NULL)
3931772Sjl139090 			*sbp = sb;
3941772Sjl139090 	}
3951772Sjl139090 
3961772Sjl139090 	return (ret);
3971772Sjl139090 }
3981772Sjl139090 
3991772Sjl139090 /*
4001772Sjl139090  * The opl_probe_t probe structure is used to pass all sorts of parameters
4011772Sjl139090  * to callback functions during probing. It also contains a snapshot of
4021772Sjl139090  * the hardware descriptor that is taken at the beginning of a probe.
4031772Sjl139090  */
4041772Sjl139090 static int
opl_probe_init(opl_probe_t * probe)4051772Sjl139090 opl_probe_init(opl_probe_t *probe)
4061772Sjl139090 {
4071772Sjl139090 	hwd_header_t		**hdrp;
4081772Sjl139090 	hwd_sb_status_t		**statp;
4091772Sjl139090 	hwd_domain_info_t	**dinfop;
4101772Sjl139090 	hwd_sb_t		**sbp;
4111772Sjl139090 	int			board, ret;
4121772Sjl139090 
4131772Sjl139090 	board = probe->pr_board;
4141772Sjl139090 
4151772Sjl139090 	hdrp = &probe->pr_hdr;
4161772Sjl139090 	statp = &probe->pr_sb_status;
4171772Sjl139090 	dinfop = &probe->pr_dinfo;
4181772Sjl139090 	sbp = &probe->pr_sb;
4191772Sjl139090 
4201772Sjl139090 	/*
4211772Sjl139090 	 * Read the hardware descriptor.
4221772Sjl139090 	 */
4231772Sjl139090 	ret = opl_read_hwd(board, hdrp, statp, dinfop, sbp);
4241772Sjl139090 	if (ret != 0) {
4251772Sjl139090 
4261772Sjl139090 		cmn_err(CE_WARN, "IKP: failed to read HWD header");
4271772Sjl139090 		return (-1);
4281772Sjl139090 	}
4291772Sjl139090 
4301772Sjl139090 #ifdef DEBUG
4311772Sjl139090 	opl_dump_hwd(probe);
4321772Sjl139090 #endif
4331772Sjl139090 	return (0);
4341772Sjl139090 }
4351772Sjl139090 
4361772Sjl139090 /*
4371772Sjl139090  * This function is used to obtain pointers to relevant device nodes
4381772Sjl139090  * which are created by Solaris at boot time.
4391772Sjl139090  *
4401772Sjl139090  * This function walks the child nodes of a given node, extracts
4411772Sjl139090  * the "name" property, if it exists, and passes the node to a
4421772Sjl139090  * callback init function. The callback determines if this node is
4431772Sjl139090  * interesting or not. If it is, then a pointer to the node is
4441772Sjl139090  * stored away by the callback for use during unprobe.
4451772Sjl139090  *
4461772Sjl139090  * The DDI get property function allocates storage for the name
4471772Sjl139090  * property. That needs to be freed within this function.
4481772Sjl139090  */
4491772Sjl139090 static int
opl_init_nodes(dev_info_t * parent,opl_init_func_t init)4501772Sjl139090 opl_init_nodes(dev_info_t *parent, opl_init_func_t init)
4511772Sjl139090 {
4521772Sjl139090 	dev_info_t	*node;
4531772Sjl139090 	char		*name;
4541772Sjl139090 	int 		circ, ret;
4551772Sjl139090 	int		len;
4561772Sjl139090 
4571772Sjl139090 	ASSERT(parent != NULL);
4581772Sjl139090 
4591772Sjl139090 	/*
4601772Sjl139090 	 * Hold parent node busy to walk its child list
4611772Sjl139090 	 */
4621772Sjl139090 	ndi_devi_enter(parent, &circ);
4631772Sjl139090 	node = ddi_get_child(parent);
4641772Sjl139090 
4651772Sjl139090 	while (node != NULL) {
4661772Sjl139090 
4671772Sjl139090 		ret = OPL_GET_PROP(string, node, "name", &name, &len);
4681772Sjl139090 		if (ret != DDI_PROP_SUCCESS) {
4691772Sjl139090 			/*
4701772Sjl139090 			 * The property does not exist for this node.
4711772Sjl139090 			 */
4721772Sjl139090 			node = ddi_get_next_sibling(node);
4731772Sjl139090 			continue;
4741772Sjl139090 		}
4751772Sjl139090 
4761772Sjl139090 		ret = init(node, name, len);
4771772Sjl139090 		kmem_free(name, len);
4781772Sjl139090 		if (ret != 0) {
4791772Sjl139090 
4801772Sjl139090 			ndi_devi_exit(parent, circ);
4811772Sjl139090 			return (-1);
4821772Sjl139090 		}
4831772Sjl139090 
4841772Sjl139090 		node = ddi_get_next_sibling(node);
4851772Sjl139090 	}
4861772Sjl139090 
4871772Sjl139090 	ndi_devi_exit(parent, circ);
4881772Sjl139090 
4891772Sjl139090 	return (0);
4901772Sjl139090 }
4911772Sjl139090 
4921772Sjl139090 /*
4931772Sjl139090  * This init function finds all the interesting nodes under the
4941772Sjl139090  * root node and stores pointers to them. The following nodes
4951772Sjl139090  * are considered interesting by this implementation:
4961772Sjl139090  *
4971772Sjl139090  *	"cmp"
4981772Sjl139090  *		These are nodes that represent processor chips.
4991772Sjl139090  *
5001772Sjl139090  *	"pci"
5011772Sjl139090  *		These are nodes that represent PCI leaves.
5021772Sjl139090  *
5031772Sjl139090  *	"pseudo-mc"
5041772Sjl139090  *		These are nodes that contain memory information.
5051772Sjl139090  */
5061772Sjl139090 static int
opl_init_root_nodes(dev_info_t * node,char * name,int len)5071772Sjl139090 opl_init_root_nodes(dev_info_t *node, char *name, int len)
5081772Sjl139090 {
5091772Sjl139090 	int		portid, board, chip, channel, leaf;
5101772Sjl139090 	int		ret;
5111772Sjl139090 
5121772Sjl139090 	if (strncmp(name, OPL_CPU_CHIP_NODE, len) == 0) {
5131772Sjl139090 
5141772Sjl139090 		ret = OPL_GET_PROP(int, node, "portid", &portid, -1);
5151772Sjl139090 		if (ret != DDI_PROP_SUCCESS)
5161772Sjl139090 			return (-1);
5171772Sjl139090 
5181772Sjl139090 		ret = OPL_GET_PROP(int, node, "board#", &board, -1);
5191772Sjl139090 		if (ret != DDI_PROP_SUCCESS)
5201772Sjl139090 			return (-1);
5211772Sjl139090 
5221772Sjl139090 		chip = OPL_CPU_CHIP(portid);
5231772Sjl139090 		opl_boards[board].cfg_cpu_chips[chip] = node;
5241772Sjl139090 
5251772Sjl139090 	} else if (strncmp(name, OPL_PCI_LEAF_NODE, len) == 0) {
5261772Sjl139090 
5271772Sjl139090 		ret = OPL_GET_PROP(int, node, "portid", &portid, -1);
5281772Sjl139090 		if (ret != DDI_PROP_SUCCESS)
5291772Sjl139090 			return (-1);
5301772Sjl139090 
5311772Sjl139090 		board = OPL_IO_PORTID_TO_LSB(portid);
5321772Sjl139090 		channel = OPL_PORTID_TO_CHANNEL(portid);
5331772Sjl139090 
5341772Sjl139090 		if (channel == OPL_CMU_CHANNEL) {
5351772Sjl139090 
5361772Sjl139090 			opl_boards[board].cfg_cmuch_leaf = node;
5371772Sjl139090 
5381772Sjl139090 		} else {
5391772Sjl139090 
5401772Sjl139090 			leaf = OPL_PORTID_TO_LEAF(portid);
5411772Sjl139090 			opl_boards[board].cfg_pcich_leaf[channel][leaf] = node;
5421772Sjl139090 		}
5431772Sjl139090 	} else if (strncmp(name, OPL_PSEUDO_MC_NODE, len) == 0) {
5441772Sjl139090 
5451772Sjl139090 		ret = OPL_GET_PROP(int, node, "board#", &board, -1);
5461772Sjl139090 		if (ret != DDI_PROP_SUCCESS)
5471772Sjl139090 			return (-1);
5481772Sjl139090 
5491772Sjl139090 		ASSERT((board >= 0) && (board < HWD_SBS_PER_DOMAIN));
5501772Sjl139090 
5511772Sjl139090 		opl_boards[board].cfg_pseudo_mc = node;
5521772Sjl139090 	}
5531772Sjl139090 
5541772Sjl139090 	return (0);
5551772Sjl139090 }
5561772Sjl139090 
5571772Sjl139090 /*
5581772Sjl139090  * This function initializes the OPL IKP feature. Currently, all it does
5591772Sjl139090  * is find the interesting nodes that Solaris has created at boot time
5601772Sjl139090  * for boards present at boot time and store pointers to them. This
5611772Sjl139090  * is useful if those boards are unprobed by DR.
5621772Sjl139090  */
5631772Sjl139090 int
opl_init_cfg()5641772Sjl139090 opl_init_cfg()
5651772Sjl139090 {
5661772Sjl139090 	dev_info_t	*root;
5671772Sjl139090 
5681772Sjl139090 	if (opl_cfg_inited == 0) {
5691772Sjl139090 
5701772Sjl139090 		root = ddi_root_node();
5711772Sjl139090 		if ((opl_init_nodes(root, opl_init_root_nodes) != 0)) {
5721772Sjl139090 			cmn_err(CE_WARN, "IKP: init failed");
5731772Sjl139090 			return (1);
5741772Sjl139090 		}
5751772Sjl139090 
5761772Sjl139090 		opl_cfg_inited = 1;
5771772Sjl139090 	}
5781772Sjl139090 
5791772Sjl139090 	return (0);
5801772Sjl139090 }
5811772Sjl139090 
5821772Sjl139090 /*
5831772Sjl139090  * When DR is initialized, we walk the device tree and acquire a hold on
5841772Sjl139090  * all the nodes that are interesting to IKP. This is so that the corresponding
5851772Sjl139090  * branches cannot be deleted.
5861772Sjl139090  *
5871772Sjl139090  * The following function informs the walk about which nodes are interesting
5881772Sjl139090  * so that it can hold the corresponding branches.
5891772Sjl139090  */
5901772Sjl139090 static int
opl_hold_node(char * name)5911772Sjl139090 opl_hold_node(char *name)
5921772Sjl139090 {
5931772Sjl139090 	/*
5941772Sjl139090 	 * We only need to hold/release the following nodes which
5951772Sjl139090 	 * represent separate branches that must be managed.
5961772Sjl139090 	 */
5971772Sjl139090 	return ((strcmp(name, OPL_CPU_CHIP_NODE) == 0) ||
5985037Sjl139090 	    (strcmp(name, OPL_PSEUDO_MC_NODE) == 0) ||
5995037Sjl139090 	    (strcmp(name, OPL_PCI_LEAF_NODE) == 0));
6001772Sjl139090 }
6011772Sjl139090 
6021772Sjl139090 static int
opl_hold_rele_devtree(dev_info_t * rdip,void * arg)6031772Sjl139090 opl_hold_rele_devtree(dev_info_t *rdip, void *arg)
6041772Sjl139090 {
6051772Sjl139090 
6061772Sjl139090 	int	*holdp = (int *)arg;
6071772Sjl139090 	char	*name = ddi_node_name(rdip);
6081772Sjl139090 
6091772Sjl139090 	/*
6101772Sjl139090 	 * We only need to hold/release the following nodes which
6111772Sjl139090 	 * represent separate branches that must be managed.
6121772Sjl139090 	 */
6131772Sjl139090 	if (opl_hold_node(name) == 0) {
6141772Sjl139090 		/* Not of interest to us */
6151772Sjl139090 		return (DDI_WALK_PRUNECHILD);
6161772Sjl139090 	}
6171772Sjl139090 	if (*holdp) {
6181772Sjl139090 		ASSERT(!e_ddi_branch_held(rdip));
6191772Sjl139090 		e_ddi_branch_hold(rdip);
6201772Sjl139090 	} else {
6211772Sjl139090 		ASSERT(e_ddi_branch_held(rdip));
6221772Sjl139090 		e_ddi_branch_rele(rdip);
6231772Sjl139090 	}
6241772Sjl139090 
6251772Sjl139090 	return (DDI_WALK_PRUNECHILD);
6261772Sjl139090 }
6271772Sjl139090 
6281772Sjl139090 void
opl_hold_devtree()6291772Sjl139090 opl_hold_devtree()
6301772Sjl139090 {
6311772Sjl139090 	dev_info_t *dip;
6321772Sjl139090 	int circ;
6331772Sjl139090 	int hold = 1;
6341772Sjl139090 
6351772Sjl139090 	dip = ddi_root_node();
6361772Sjl139090 	ndi_devi_enter(dip, &circ);
6371772Sjl139090 	ddi_walk_devs(ddi_get_child(dip), opl_hold_rele_devtree, &hold);
6381772Sjl139090 	ndi_devi_exit(dip, circ);
6391772Sjl139090 }
6401772Sjl139090 
6411772Sjl139090 void
opl_release_devtree()6421772Sjl139090 opl_release_devtree()
6431772Sjl139090 {
6441772Sjl139090 	dev_info_t *dip;
6451772Sjl139090 	int circ;
6461772Sjl139090 	int hold = 0;
6471772Sjl139090 
6481772Sjl139090 	dip = ddi_root_node();
6491772Sjl139090 	ndi_devi_enter(dip, &circ);
6501772Sjl139090 	ddi_walk_devs(ddi_get_child(dip), opl_hold_rele_devtree, &hold);
6511772Sjl139090 	ndi_devi_exit(dip, circ);
6521772Sjl139090 }
6531772Sjl139090 
6541772Sjl139090 /*
6551772Sjl139090  * This is a helper function that allows opl_create_node() to return a
6561772Sjl139090  * pointer to a newly created node to its caller.
6571772Sjl139090  */
6581772Sjl139090 /*ARGSUSED*/
6591772Sjl139090 static void
opl_set_node(dev_info_t * node,void * arg,uint_t flags)6601772Sjl139090 opl_set_node(dev_info_t *node, void *arg, uint_t flags)
6611772Sjl139090 {
6621772Sjl139090 	opl_probe_t	*probe;
6631772Sjl139090 
6641772Sjl139090 	probe = arg;
6651772Sjl139090 	probe->pr_node = node;
6661772Sjl139090 }
6671772Sjl139090 
6681772Sjl139090 /*
6691772Sjl139090  * Function to create a node in the device tree under a specified parent.
6701772Sjl139090  *
6711772Sjl139090  * e_ddi_branch_create() allows the creation of a whole branch with a
6721772Sjl139090  * single call of the function. However, we only use it to create one node
6731772Sjl139090  * at a time in the case of non-I/O device nodes. In other words, we
6741772Sjl139090  * create branches by repeatedly using this function. This makes the
6751772Sjl139090  * code more readable.
6761772Sjl139090  *
6771772Sjl139090  * The branch descriptor passed to e_ddi_branch_create() takes two
6781772Sjl139090  * callbacks. The create() callback is used to set the properties of a
6791772Sjl139090  * newly created node. The other callback is used to return a pointer
6801772Sjl139090  * to the newly created node. The create() callback is passed by the
6811772Sjl139090  * caller of this function based on the kind of node he wishes to
6821772Sjl139090  * create.
6831772Sjl139090  *
6841772Sjl139090  * e_ddi_branch_create() returns with the newly created node held. We
6851772Sjl139090  * only need to hold the top nodes of the branches we create. We release
6861772Sjl139090  * the hold for the others. E.g., the "cmp" node needs to be held. Since
6871772Sjl139090  * we hold the "cmp" node, there is no need to hold the "core" and "cpu"
6881772Sjl139090  * nodes below it.
6891772Sjl139090  */
6901772Sjl139090 static dev_info_t *
opl_create_node(opl_probe_t * probe)6911772Sjl139090 opl_create_node(opl_probe_t *probe)
6921772Sjl139090 {
6931772Sjl139090 	devi_branch_t	branch;
6941772Sjl139090 
6951772Sjl139090 	probe->pr_node = NULL;
6961772Sjl139090 
6971772Sjl139090 	branch.arg = probe;
6981772Sjl139090 	branch.type = DEVI_BRANCH_SID;
6991772Sjl139090 	branch.create.sid_branch_create = probe->pr_create;
7001772Sjl139090 	branch.devi_branch_callback = opl_set_node;
7011772Sjl139090 
7021772Sjl139090 	if (e_ddi_branch_create(probe->pr_parent, &branch, NULL, 0) != 0)
7031772Sjl139090 		return (NULL);
7041772Sjl139090 
7051772Sjl139090 	ASSERT(probe->pr_node != NULL);
7061772Sjl139090 
7071772Sjl139090 	if (probe->pr_hold == 0)
7081772Sjl139090 		e_ddi_branch_rele(probe->pr_node);
7091772Sjl139090 
7101772Sjl139090 	return (probe->pr_node);
7111772Sjl139090 }
7121772Sjl139090 
7131772Sjl139090 /*
7141772Sjl139090  * Function to tear down a whole branch rooted at the specified node.
7151772Sjl139090  *
7161772Sjl139090  * Although we create each node of a branch individually, we destroy
7171772Sjl139090  * a whole branch in one call. This is more efficient.
7181772Sjl139090  */
7191772Sjl139090 static int
opl_destroy_node(dev_info_t * node)7201772Sjl139090 opl_destroy_node(dev_info_t *node)
7211772Sjl139090 {
7223354Sjl139090 	if (e_ddi_branch_destroy(node, NULL, 0) != 0) {
7233354Sjl139090 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
7243354Sjl139090 		(void) ddi_pathname(node, path);
7255037Sjl139090 		cmn_err(CE_WARN, "OPL node removal failed: %s (%p)", path,
7265037Sjl139090 		    (void *)node);
7273354Sjl139090 		kmem_free(path, MAXPATHLEN);
7281772Sjl139090 		return (-1);
7293354Sjl139090 	}
7301772Sjl139090 
7311772Sjl139090 	return (0);
7321772Sjl139090 }
7331772Sjl139090 
7341772Sjl139090 /*
7351772Sjl139090  * Set the properties for a "cpu" node.
7361772Sjl139090  */
7371772Sjl139090 /*ARGSUSED*/
7381772Sjl139090 static int
opl_create_cpu(dev_info_t * node,void * arg,uint_t flags)7391772Sjl139090 opl_create_cpu(dev_info_t *node, void *arg, uint_t flags)
7401772Sjl139090 {
7411772Sjl139090 	opl_probe_t	*probe;
7421772Sjl139090 	hwd_cpu_chip_t	*chip;
7431772Sjl139090 	hwd_core_t	*core;
7441772Sjl139090 	hwd_cpu_t	*cpu;
7451772Sjl139090 	int		ret;
7461772Sjl139090 
7471772Sjl139090 	probe = arg;
7481772Sjl139090 	chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip];
7491772Sjl139090 	core = &chip->chip_cores[probe->pr_core];
7501772Sjl139090 	cpu = &core->core_cpus[probe->pr_cpu];
7511772Sjl139090 	OPL_UPDATE_PROP(string, node, "name", OPL_CPU_NODE);
7521772Sjl139090 	OPL_UPDATE_PROP(string, node, "device_type", OPL_CPU_NODE);
7531772Sjl139090 
7541772Sjl139090 	OPL_UPDATE_PROP(int, node, "cpuid", cpu->cpu_cpuid);
7551772Sjl139090 	OPL_UPDATE_PROP(int, node, "reg", probe->pr_cpu);
7561772Sjl139090 
7571772Sjl139090 	OPL_UPDATE_PROP(string, node, "status", "okay");
7581772Sjl139090 
7591772Sjl139090 	return (DDI_WALK_TERMINATE);
7601772Sjl139090 }
7611772Sjl139090 
7621772Sjl139090 /*
7631772Sjl139090  * Create "cpu" nodes as child nodes of a given "core" node.
7641772Sjl139090  */
7651772Sjl139090 static int
opl_probe_cpus(opl_probe_t * probe)7661772Sjl139090 opl_probe_cpus(opl_probe_t *probe)
7671772Sjl139090 {
7681772Sjl139090 	int		i;
7691772Sjl139090 	hwd_cpu_chip_t	*chip;
7701772Sjl139090 	hwd_core_t	*core;
7711772Sjl139090 	hwd_cpu_t	*cpus;
7721772Sjl139090 
7731772Sjl139090 	chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip];
7741772Sjl139090 	core = &chip->chip_cores[probe->pr_core];
7751772Sjl139090 	cpus = &core->core_cpus[0];
7761772Sjl139090 
7771772Sjl139090 	for (i = 0; i < HWD_CPUS_PER_CORE; i++) {
7781772Sjl139090 
7791772Sjl139090 		/*
7801772Sjl139090 		 * Olympus-C has 2 cpus per core.
7811772Sjl139090 		 * Jupiter has 4 cpus per core.
7821772Sjl139090 		 * For the Olympus-C based platform, we expect the cpu_status
7831772Sjl139090 		 * of the non-existent cpus to be set to missing.
7841772Sjl139090 		 */
7851772Sjl139090 		if (!HWD_STATUS_OK(cpus[i].cpu_status))
7861772Sjl139090 			continue;
7871772Sjl139090 
7881772Sjl139090 		probe->pr_create = opl_create_cpu;
7891772Sjl139090 		probe->pr_cpu = i;
7901772Sjl139090 		if (opl_create_node(probe) == NULL) {
7911772Sjl139090 
7921772Sjl139090 			cmn_err(CE_WARN, "IKP: create cpu (%d-%d-%d-%d) failed",
7935037Sjl139090 			    probe->pr_board, probe->pr_cpu_chip, probe->pr_core,
7945037Sjl139090 			    probe->pr_cpu);
7951772Sjl139090 			return (-1);
7961772Sjl139090 		}
7971772Sjl139090 	}
7981772Sjl139090 
7991772Sjl139090 	return (0);
8001772Sjl139090 }
8011772Sjl139090 
8021772Sjl139090 /*
8031772Sjl139090  * Set the properties for a "core" node.
8041772Sjl139090  */
8051772Sjl139090 /*ARGSUSED*/
8061772Sjl139090 static int
opl_create_core(dev_info_t * node,void * arg,uint_t flags)8071772Sjl139090 opl_create_core(dev_info_t *node, void *arg, uint_t flags)
8081772Sjl139090 {
8091772Sjl139090 	opl_probe_t	*probe;
8101772Sjl139090 	hwd_cpu_chip_t	*chip;
8111772Sjl139090 	hwd_core_t	*core;
8121772Sjl139090 	int		sharing[2];
8131772Sjl139090 	int		ret;
8141772Sjl139090 
8151772Sjl139090 	probe = arg;
8161772Sjl139090 	chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip];
8171772Sjl139090 	core = &chip->chip_cores[probe->pr_core];
8181772Sjl139090 
8191772Sjl139090 	OPL_UPDATE_PROP(string, node, "name", OPL_CORE_NODE);
8201772Sjl139090 	OPL_UPDATE_PROP(string, node, "device_type", OPL_CORE_NODE);
8211772Sjl139090 	OPL_UPDATE_PROP(string, node, "compatible", chip->chip_compatible);
8221772Sjl139090 
8231772Sjl139090 	OPL_UPDATE_PROP(int, node, "reg", probe->pr_core);
8241772Sjl139090 	OPL_UPDATE_PROP(int, node, "manufacturer#", core->core_manufacturer);
8251772Sjl139090 	OPL_UPDATE_PROP(int, node, "implementation#",
8261772Sjl139090 	    core->core_implementation);
8271772Sjl139090 	OPL_UPDATE_PROP(int, node, "mask#", core->core_mask);
8281772Sjl139090 
8293659Sjimand 	OPL_UPDATE_PROP(int, node, "sparc-version", 9);
8301772Sjl139090 	OPL_UPDATE_PROP(int, node, "clock-frequency", core->core_frequency);
8311772Sjl139090 
8321772Sjl139090 	OPL_UPDATE_PROP(int, node, "l1-icache-size", core->core_l1_icache_size);
8331772Sjl139090 	OPL_UPDATE_PROP(int, node, "l1-icache-line-size",
8341772Sjl139090 	    core->core_l1_icache_line_size);
8351772Sjl139090 	OPL_UPDATE_PROP(int, node, "l1-icache-associativity",
8361772Sjl139090 	    core->core_l1_icache_associativity);
8371772Sjl139090 	OPL_UPDATE_PROP(int, node, "#itlb-entries",
8381772Sjl139090 	    core->core_num_itlb_entries);
8391772Sjl139090 
8401772Sjl139090 	OPL_UPDATE_PROP(int, node, "l1-dcache-size", core->core_l1_dcache_size);
8411772Sjl139090 	OPL_UPDATE_PROP(int, node, "l1-dcache-line-size",
8421772Sjl139090 	    core->core_l1_dcache_line_size);
8431772Sjl139090 	OPL_UPDATE_PROP(int, node, "l1-dcache-associativity",
8441772Sjl139090 	    core->core_l1_dcache_associativity);
8451772Sjl139090 	OPL_UPDATE_PROP(int, node, "#dtlb-entries",
8461772Sjl139090 	    core->core_num_dtlb_entries);
8471772Sjl139090 
8481772Sjl139090 	OPL_UPDATE_PROP(int, node, "l2-cache-size", core->core_l2_cache_size);
8491772Sjl139090 	OPL_UPDATE_PROP(int, node, "l2-cache-line-size",
8501772Sjl139090 	    core->core_l2_cache_line_size);
8511772Sjl139090 	OPL_UPDATE_PROP(int, node, "l2-cache-associativity",
8521772Sjl139090 	    core->core_l2_cache_associativity);
8531772Sjl139090 	sharing[0] = 0;
8541772Sjl139090 	sharing[1] = core->core_l2_cache_sharing;
8551772Sjl139090 	OPL_UPDATE_PROP_ARRAY(int, node, "l2-cache-sharing", sharing, 2);
8561772Sjl139090 
8571772Sjl139090 	OPL_UPDATE_PROP(string, node, "status", "okay");
8581772Sjl139090 
8591772Sjl139090 	return (DDI_WALK_TERMINATE);
8601772Sjl139090 }
8611772Sjl139090 
8621772Sjl139090 /*
8631772Sjl139090  * Create "core" nodes as child nodes of a given "cmp" node.
8641772Sjl139090  *
8651772Sjl139090  * Create the branch below each "core" node".
8661772Sjl139090  */
8671772Sjl139090 static int
opl_probe_cores(opl_probe_t * probe)8681772Sjl139090 opl_probe_cores(opl_probe_t *probe)
8691772Sjl139090 {
8701772Sjl139090 	int		i;
8711772Sjl139090 	hwd_cpu_chip_t	*chip;
8721772Sjl139090 	hwd_core_t	*cores;
8731772Sjl139090 	dev_info_t	*parent, *node;
8741772Sjl139090 
8751772Sjl139090 	chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip];
8761772Sjl139090 	cores = &chip->chip_cores[0];
8771772Sjl139090 	parent = probe->pr_parent;
8781772Sjl139090 
8791772Sjl139090 	for (i = 0; i < HWD_CORES_PER_CPU_CHIP; i++) {
8801772Sjl139090 
8811772Sjl139090 		if (!HWD_STATUS_OK(cores[i].core_status))
8821772Sjl139090 			continue;
8831772Sjl139090 
8841772Sjl139090 		probe->pr_parent = parent;
8851772Sjl139090 		probe->pr_create = opl_create_core;
8861772Sjl139090 		probe->pr_core = i;
8871772Sjl139090 		node = opl_create_node(probe);
8881772Sjl139090 		if (node == NULL) {
8891772Sjl139090 
8901772Sjl139090 			cmn_err(CE_WARN, "IKP: create core (%d-%d-%d) failed",
8915037Sjl139090 			    probe->pr_board, probe->pr_cpu_chip,
8925037Sjl139090 			    probe->pr_core);
8931772Sjl139090 			return (-1);
8941772Sjl139090 		}
8951772Sjl139090 
8961772Sjl139090 		/*
8971772Sjl139090 		 * Create "cpu" nodes below "core".
8981772Sjl139090 		 */
8991772Sjl139090 		probe->pr_parent = node;
9001772Sjl139090 		if (opl_probe_cpus(probe) != 0)
9011772Sjl139090 			return (-1);
9025037Sjl139090 		probe->pr_cpu_impl |= (1 << cores[i].core_implementation);
9031772Sjl139090 	}
9041772Sjl139090 
9051772Sjl139090 	return (0);
9061772Sjl139090 }
9071772Sjl139090 
9081772Sjl139090 /*
9091772Sjl139090  * Set the properties for a "cmp" node.
9101772Sjl139090  */
9111772Sjl139090 /*ARGSUSED*/
9121772Sjl139090 static int
opl_create_cpu_chip(dev_info_t * node,void * arg,uint_t flags)9131772Sjl139090 opl_create_cpu_chip(dev_info_t *node, void *arg, uint_t flags)
9141772Sjl139090 {
9151772Sjl139090 	opl_probe_t	*probe;
9161772Sjl139090 	hwd_cpu_chip_t	*chip;
9171772Sjl139090 	opl_range_t	range;
9181772Sjl139090 	uint64_t	dummy_addr;
9191772Sjl139090 	int		ret;
9201772Sjl139090 
9211772Sjl139090 	probe = arg;
9221772Sjl139090 	chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip];
9231772Sjl139090 
9241772Sjl139090 	OPL_UPDATE_PROP(string, node, "name", OPL_CPU_CHIP_NODE);
9251772Sjl139090 
9261772Sjl139090 	OPL_UPDATE_PROP(int, node, "portid", chip->chip_portid);
9271772Sjl139090 	OPL_UPDATE_PROP(int, node, "board#", probe->pr_board);
9281772Sjl139090 
9291772Sjl139090 	dummy_addr = OPL_PROC_AS(probe->pr_board, probe->pr_cpu_chip);
9301772Sjl139090 	range.rg_addr_hi = OPL_HI(dummy_addr);
9311772Sjl139090 	range.rg_addr_lo = OPL_LO(dummy_addr);
9321772Sjl139090 	range.rg_size_hi = 0;
9331772Sjl139090 	range.rg_size_lo = 0;
9341772Sjl139090 	OPL_UPDATE_PROP_ARRAY(int, node, "reg", (int *)&range, 4);
9351772Sjl139090 
9361772Sjl139090 	OPL_UPDATE_PROP(int, node, "#address-cells", 1);
9371772Sjl139090 	OPL_UPDATE_PROP(int, node, "#size-cells", 0);
9381772Sjl139090 
9391772Sjl139090 	OPL_UPDATE_PROP(string, node, "status", "okay");
9401772Sjl139090 
9411772Sjl139090 	return (DDI_WALK_TERMINATE);
9421772Sjl139090 }
9431772Sjl139090 
9441772Sjl139090 /*
9451772Sjl139090  * Create "cmp" nodes as child nodes of the root node.
9461772Sjl139090  *
9471772Sjl139090  * Create the branch below each "cmp" node.
9481772Sjl139090  */
9491772Sjl139090 static int
opl_probe_cpu_chips(opl_probe_t * probe)9501772Sjl139090 opl_probe_cpu_chips(opl_probe_t *probe)
9511772Sjl139090 {
9521772Sjl139090 	int		i;
9531772Sjl139090 	dev_info_t	**cfg_cpu_chips;
9541772Sjl139090 	hwd_cpu_chip_t	*chips;
9551772Sjl139090 	dev_info_t	*node;
9561772Sjl139090 
9571772Sjl139090 	cfg_cpu_chips = opl_boards[probe->pr_board].cfg_cpu_chips;
9581772Sjl139090 	chips = &probe->pr_sb->sb_cmu.cmu_cpu_chips[0];
9591772Sjl139090 
9601772Sjl139090 	for (i = 0; i < HWD_CPU_CHIPS_PER_CMU; i++) {
9611772Sjl139090 
9621772Sjl139090 		ASSERT(cfg_cpu_chips[i] == NULL);
9631772Sjl139090 
9641772Sjl139090 		if (!HWD_STATUS_OK(chips[i].chip_status))
9651772Sjl139090 			continue;
9661772Sjl139090 
9671772Sjl139090 		probe->pr_parent = ddi_root_node();
9681772Sjl139090 		probe->pr_create = opl_create_cpu_chip;
9691772Sjl139090 		probe->pr_cpu_chip = i;
9701772Sjl139090 		probe->pr_hold = 1;
9711772Sjl139090 		node = opl_create_node(probe);
9721772Sjl139090 		if (node == NULL) {
9731772Sjl139090 
9741772Sjl139090 			cmn_err(CE_WARN, "IKP: create chip (%d-%d) failed",
9755037Sjl139090 			    probe->pr_board, probe->pr_cpu_chip);
9761772Sjl139090 			return (-1);
9771772Sjl139090 		}
9781772Sjl139090 
9791772Sjl139090 		cfg_cpu_chips[i] = node;
9801772Sjl139090 
9811772Sjl139090 		/*
9821772Sjl139090 		 * Create "core" nodes below "cmp".
9831772Sjl139090 		 * We hold the "cmp" node. So, there is no need to hold
9841772Sjl139090 		 * the "core" and "cpu" nodes below it.
9851772Sjl139090 		 */
9861772Sjl139090 		probe->pr_parent = node;
9871772Sjl139090 		probe->pr_hold = 0;
9881772Sjl139090 		if (opl_probe_cores(probe) != 0)
9891772Sjl139090 			return (-1);
9901772Sjl139090 	}
9911772Sjl139090 
9921772Sjl139090 	return (0);
9931772Sjl139090 }
9941772Sjl139090 
9951772Sjl139090 /*
9961772Sjl139090  * Set the properties for a "pseudo-mc" node.
9971772Sjl139090  */
9981772Sjl139090 /*ARGSUSED*/
9991772Sjl139090 static int
opl_create_pseudo_mc(dev_info_t * node,void * arg,uint_t flags)10001772Sjl139090 opl_create_pseudo_mc(dev_info_t *node, void *arg, uint_t flags)
10011772Sjl139090 {
10021772Sjl139090 	opl_probe_t	*probe;
10031772Sjl139090 	int		board, portid;
10041772Sjl139090 	hwd_bank_t	*bank;
10051772Sjl139090 	hwd_memory_t	*mem;
10061772Sjl139090 	opl_range_t	range;
10071772Sjl139090 	opl_mc_addr_t	mc[HWD_BANKS_PER_CMU];
10081772Sjl139090 	int		status[2][7];
10091772Sjl139090 	int		i, j;
10101772Sjl139090 	int		ret;
10111772Sjl139090 
10121772Sjl139090 	probe = arg;
10131772Sjl139090 	board = probe->pr_board;
10141772Sjl139090 
10151772Sjl139090 	OPL_UPDATE_PROP(string, node, "name", OPL_PSEUDO_MC_NODE);
10161772Sjl139090 	OPL_UPDATE_PROP(string, node, "device_type", "memory-controller");
10171772Sjl139090 	OPL_UPDATE_PROP(string, node, "compatible", "FJSV,oplmc");
10181772Sjl139090 
10191772Sjl139090 	portid = OPL_LSB_TO_PSEUDOMC_PORTID(board);
10201772Sjl139090 	OPL_UPDATE_PROP(int, node, "portid", portid);
10211772Sjl139090 
10221772Sjl139090 	range.rg_addr_hi = OPL_HI(OPL_MC_AS(board));
10231772Sjl139090 	range.rg_addr_lo = 0x200;
10241772Sjl139090 	range.rg_size_hi = 0;
10251772Sjl139090 	range.rg_size_lo = 0;
10261772Sjl139090 	OPL_UPDATE_PROP_ARRAY(int, node, "reg", (int *)&range, 4);
10271772Sjl139090 
10281772Sjl139090 	OPL_UPDATE_PROP(int, node, "board#", board);
10291772Sjl139090 	OPL_UPDATE_PROP(int, node, "physical-board#",
10301772Sjl139090 	    probe->pr_sb->sb_psb_number);
10311772Sjl139090 
10321772Sjl139090 	OPL_UPDATE_PROP(int, node, "#address-cells", 1);
10331772Sjl139090 	OPL_UPDATE_PROP(int, node, "#size-cells", 2);
10341772Sjl139090 
10351772Sjl139090 	mem = &probe->pr_sb->sb_cmu.cmu_memory;
10361772Sjl139090 
10371772Sjl139090 	range.rg_addr_hi = OPL_HI(mem->mem_start_address);
10381772Sjl139090 	range.rg_addr_lo = OPL_LO(mem->mem_start_address);
10391772Sjl139090 	range.rg_size_hi = OPL_HI(mem->mem_size);
10401772Sjl139090 	range.rg_size_lo = OPL_LO(mem->mem_size);
10411772Sjl139090 	OPL_UPDATE_PROP_ARRAY(int, node, "sb-mem-ranges", (int *)&range, 4);
10421772Sjl139090 
10431772Sjl139090 	bank = probe->pr_sb->sb_cmu.cmu_memory.mem_banks;
10441772Sjl139090 	for (i = 0, j = 0; i < HWD_BANKS_PER_CMU; i++) {
10451772Sjl139090 
10461772Sjl139090 		if (!HWD_STATUS_OK(bank[i].bank_status))
10471772Sjl139090 			continue;
10481772Sjl139090 
10491772Sjl139090 		mc[j].mc_bank = i;
10501772Sjl139090 		mc[j].mc_hi = OPL_HI(bank[i].bank_register_address);
10511772Sjl139090 		mc[j].mc_lo = OPL_LO(bank[i].bank_register_address);
10521772Sjl139090 		j++;
10531772Sjl139090 	}
10543354Sjl139090 
10553354Sjl139090 	if (j > 0) {
10563354Sjl139090 		OPL_UPDATE_PROP_ARRAY(int, node, "mc-addr", (int *)mc, j*3);
10573354Sjl139090 	} else {
10583354Sjl139090 		/*
10593354Sjl139090 		 * If there is no memory, we need the mc-addr property, but
10603354Sjl139090 		 * it is length 0.  The only way to do this using ndi seems
10613354Sjl139090 		 * to be by creating a boolean property.
10623354Sjl139090 		 */
10633354Sjl139090 		ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, node, "mc-addr");
10643354Sjl139090 		OPL_UPDATE_PROP_ERR(ret, "mc-addr");
10653354Sjl139090 	}
10661772Sjl139090 
10671772Sjl139090 	OPL_UPDATE_PROP_ARRAY(byte, node, "cs0-mc-pa-trans-table",
10681772Sjl139090 	    mem->mem_cs[0].cs_pa_mac_table, 64);
10691772Sjl139090 	OPL_UPDATE_PROP_ARRAY(byte, node, "cs1-mc-pa-trans-table",
10701772Sjl139090 	    mem->mem_cs[1].cs_pa_mac_table, 64);
10711772Sjl139090 
10721772Sjl139090 #define	CS_PER_MEM 2
10731772Sjl139090 
10741772Sjl139090 	for (i = 0, j = 0; i < CS_PER_MEM; i++) {
10751772Sjl139090 		if (HWD_STATUS_OK(mem->mem_cs[i].cs_status) ||
10765037Sjl139090 		    HWD_STATUS_FAILED(mem->mem_cs[i].cs_status)) {
10771772Sjl139090 			status[j][0] = i;
10781772Sjl139090 			if (HWD_STATUS_OK(mem->mem_cs[i].cs_status))
10791772Sjl139090 				status[j][1] = 0;
10801772Sjl139090 			else
10811772Sjl139090 				status[j][1] = 1;
10821772Sjl139090 			status[j][2] =
10831772Sjl139090 			    OPL_HI(mem->mem_cs[i].cs_available_capacity);
10841772Sjl139090 			status[j][3] =
10851772Sjl139090 			    OPL_LO(mem->mem_cs[i].cs_available_capacity);
10861772Sjl139090 			status[j][4] = OPL_HI(mem->mem_cs[i].cs_dimm_capacity);
10871772Sjl139090 			status[j][5] = OPL_LO(mem->mem_cs[i].cs_dimm_capacity);
10881772Sjl139090 			status[j][6] = mem->mem_cs[i].cs_number_of_dimms;
10891772Sjl139090 			j++;
10901772Sjl139090 		}
10911772Sjl139090 	}
10923354Sjl139090 
10933354Sjl139090 	if (j > 0) {
10943354Sjl139090 		OPL_UPDATE_PROP_ARRAY(int, node, "cs-status", (int *)status,
10953354Sjl139090 		    j*7);
10963354Sjl139090 	} else {
10973354Sjl139090 		/*
10983354Sjl139090 		 * If there is no memory, we need the cs-status property, but
10993354Sjl139090 		 * it is length 0.  The only way to do this using ndi seems
11003354Sjl139090 		 * to be by creating a boolean property.
11013354Sjl139090 		 */
11023354Sjl139090 		ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, node,
11033354Sjl139090 		    "cs-status");
11043354Sjl139090 		OPL_UPDATE_PROP_ERR(ret, "cs-status");
11053354Sjl139090 	}
11061772Sjl139090 
11071772Sjl139090 	return (DDI_WALK_TERMINATE);
11081772Sjl139090 }
11091772Sjl139090 
11101772Sjl139090 /*
11111772Sjl139090  * Create "pseudo-mc" nodes
11121772Sjl139090  */
11131772Sjl139090 static int
opl_probe_memory(opl_probe_t * probe)11141772Sjl139090 opl_probe_memory(opl_probe_t *probe)
11151772Sjl139090 {
11161772Sjl139090 	int		board;
11171772Sjl139090 	opl_board_cfg_t	*board_cfg;
11181772Sjl139090 	dev_info_t	*node;
11191772Sjl139090 
11201772Sjl139090 	board = probe->pr_board;
11211772Sjl139090 	board_cfg = &opl_boards[board];
11221772Sjl139090 
11231772Sjl139090 	ASSERT(board_cfg->cfg_pseudo_mc == NULL);
11241772Sjl139090 
11251772Sjl139090 	probe->pr_parent = ddi_root_node();
11261772Sjl139090 	probe->pr_create = opl_create_pseudo_mc;
11271772Sjl139090 	probe->pr_hold = 1;
11281772Sjl139090 	node = opl_create_node(probe);
11291772Sjl139090 	if (node == NULL) {
11301772Sjl139090 
11311772Sjl139090 		cmn_err(CE_WARN, "IKP: create pseudo-mc (%d) failed", board);
11321772Sjl139090 		return (-1);
11331772Sjl139090 	}
11341772Sjl139090 
11351772Sjl139090 	board_cfg->cfg_pseudo_mc = node;
11361772Sjl139090 
11371772Sjl139090 	return (0);
11381772Sjl139090 }
11391772Sjl139090 
11401772Sjl139090 /*
11411772Sjl139090  * Allocate the fcode ops handle.
11421772Sjl139090  */
11431772Sjl139090 /*ARGSUSED*/
11441772Sjl139090 static
11451772Sjl139090 fco_handle_t
opl_fc_ops_alloc_handle(dev_info_t * parent,dev_info_t * child,void * fcode,size_t fcode_size,char * unit_address,char * my_args)11461772Sjl139090 opl_fc_ops_alloc_handle(dev_info_t *parent, dev_info_t *child,
11471772Sjl139090 			void *fcode, size_t fcode_size, char *unit_address,
11481772Sjl139090 			char *my_args)
11491772Sjl139090 {
11501772Sjl139090 	fco_handle_t	rp;
11511772Sjl139090 	phandle_t	h;
11521772Sjl139090 	char		*buf;
11531772Sjl139090 
11541772Sjl139090 	rp = kmem_zalloc(sizeof (struct fc_resource_list), KM_SLEEP);
11551772Sjl139090 	rp->next_handle = fc_ops_alloc_handle(parent, child, fcode, fcode_size,
11561772Sjl139090 	    unit_address, NULL);
11571772Sjl139090 	rp->ap = parent;
11581772Sjl139090 	rp->child = child;
11591772Sjl139090 	rp->fcode = fcode;
11601772Sjl139090 	rp->fcode_size = fcode_size;
11611772Sjl139090 	rp->my_args = my_args;
11621772Sjl139090 
11631772Sjl139090 	if (unit_address) {
11641772Sjl139090 		buf = kmem_zalloc(UNIT_ADDR_SIZE, KM_SLEEP);
11651772Sjl139090 		(void) strcpy(buf, unit_address);
11661772Sjl139090 		rp->unit_address = buf;
11671772Sjl139090 	}
11681772Sjl139090 
11691772Sjl139090 	/*
11701772Sjl139090 	 * Add the child's nodeid to our table...
11711772Sjl139090 	 */
11721772Sjl139090 	h = ddi_get_nodeid(rp->child);
11731772Sjl139090 	fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child, h);
11741772Sjl139090 
11751772Sjl139090 	return (rp);
11761772Sjl139090 }
11771772Sjl139090 
11781772Sjl139090 
11791772Sjl139090 static void
opl_fc_ops_free_handle(fco_handle_t rp)11801772Sjl139090 opl_fc_ops_free_handle(fco_handle_t rp)
11811772Sjl139090 {
11821772Sjl139090 	struct fc_resource	*resp, *nresp;
11831772Sjl139090 
11841772Sjl139090 	ASSERT(rp);
11851772Sjl139090 
11861772Sjl139090 	if (rp->next_handle)
11871772Sjl139090 		fc_ops_free_handle(rp->next_handle);
11881772Sjl139090 	if (rp->unit_address)
11891772Sjl139090 		kmem_free(rp->unit_address, UNIT_ADDR_SIZE);
11901772Sjl139090 
11911772Sjl139090 	/*
11921772Sjl139090 	 * Release all the resources from the resource list
11931772Sjl139090 	 */
11941772Sjl139090 	for (resp = rp->head; resp != NULL; resp = nresp) {
11951772Sjl139090 		nresp = resp->next;
11961772Sjl139090 		switch (resp->type) {
11971772Sjl139090 
11981772Sjl139090 		case RT_MAP:
11993354Sjl139090 			/*
12003354Sjl139090 			 * If this is still mapped, we'd better unmap it now,
12013354Sjl139090 			 * or all our structures that are tracking it will
12023354Sjl139090 			 * be leaked.
12033354Sjl139090 			 */
12043354Sjl139090 			if (resp->fc_map_handle != NULL)
12053354Sjl139090 				opl_unmap_phys(&resp->fc_map_handle);
12061772Sjl139090 			break;
12071772Sjl139090 
12081772Sjl139090 		case RT_DMA:
12091772Sjl139090 			/*
12101772Sjl139090 			 * DMA has to be freed up at exit time.
12111772Sjl139090 			 */
12121772Sjl139090 			cmn_err(CE_CONT,
12131772Sjl139090 			    "opl_fc_ops_free_handle: Unexpected DMA seen!");
12141772Sjl139090 			break;
12151772Sjl139090 
12161772Sjl139090 		case RT_CONTIGIOUS:
12171772Sjl139090 			FC_DEBUG2(1, CE_CONT, "opl_fc_ops_free: "
12181772Sjl139090 			    "Free claim-memory resource 0x%lx size 0x%x\n",
12191772Sjl139090 			    resp->fc_contig_virt, resp->fc_contig_len);
12201772Sjl139090 
12211772Sjl139090 			(void) ndi_ra_free(ddi_root_node(),
12221772Sjl139090 			    (uint64_t)resp->fc_contig_virt,
12231772Sjl139090 			    resp->fc_contig_len, "opl-fcodemem",
12241772Sjl139090 			    NDI_RA_PASS);
12251772Sjl139090 
12261772Sjl139090 			break;
12271772Sjl139090 
12281772Sjl139090 		default:
12291772Sjl139090 			cmn_err(CE_CONT, "opl_fc_ops_free: "
12301772Sjl139090 			    "unknown resource type %d", resp->type);
12311772Sjl139090 			break;
12321772Sjl139090 		}
12331772Sjl139090 		fc_rem_resource(rp, resp);
12341772Sjl139090 		kmem_free(resp, sizeof (struct fc_resource));
12351772Sjl139090 	}
12361772Sjl139090 
12371772Sjl139090 	kmem_free(rp, sizeof (struct fc_resource_list));
12381772Sjl139090 }
12391772Sjl139090 
12401772Sjl139090 int
opl_fc_do_op(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)12411772Sjl139090 opl_fc_do_op(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
12421772Sjl139090 {
12431772Sjl139090 	opl_fc_ops_t	*op;
12441772Sjl139090 	char		*service = fc_cell2ptr(cp->svc_name);
12451772Sjl139090 
12461772Sjl139090 	ASSERT(rp);
12471772Sjl139090 
12481772Sjl139090 	FC_DEBUG1(1, CE_CONT, "opl_fc_do_op: <%s>\n", service);
12491772Sjl139090 
12501772Sjl139090 	/*
12511772Sjl139090 	 * First try the generic fc_ops.
12521772Sjl139090 	 */
12531772Sjl139090 	if (fc_ops(ap, rp->next_handle, cp) == 0)
12541772Sjl139090 		return (0);
12551772Sjl139090 
12561772Sjl139090 	/*
12571772Sjl139090 	 * Now try the Jupiter-specific ops.
12581772Sjl139090 	 */
12591772Sjl139090 	for (op = opl_fc_ops; op->fc_service != NULL; ++op)
12601772Sjl139090 		if (strcmp(op->fc_service, service) == 0)
12611772Sjl139090 			return (op->fc_op(ap, rp, cp));
12621772Sjl139090 
12631772Sjl139090 	FC_DEBUG1(9, CE_CONT, "opl_fc_do_op: <%s> not serviced\n", service);
12641772Sjl139090 
12651772Sjl139090 	return (-1);
12661772Sjl139090 }
12671772Sjl139090 
12681772Sjl139090 /*
12691772Sjl139090  * map-in  (phys.lo phys.hi size -- virt)
12701772Sjl139090  */
12711772Sjl139090 static int
opl_map_in(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)12721772Sjl139090 opl_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
12731772Sjl139090 {
12741772Sjl139090 	size_t			len;
12751772Sjl139090 	int			error;
12761772Sjl139090 	caddr_t			virt;
12771772Sjl139090 	struct fc_resource	*resp;
12781772Sjl139090 	struct regspec		rspec;
12791772Sjl139090 	ddi_device_acc_attr_t	acc;
12801772Sjl139090 	ddi_acc_handle_t	h;
12811772Sjl139090 
12821772Sjl139090 	if (fc_cell2int(cp->nargs) != 3)
12831772Sjl139090 		return (fc_syntax_error(cp, "nargs must be 3"));
12841772Sjl139090 
12851772Sjl139090 	if (fc_cell2int(cp->nresults) < 1)
12861772Sjl139090 		return (fc_syntax_error(cp, "nresults must be >= 1"));
12871772Sjl139090 
12881772Sjl139090 	rspec.regspec_size = len = fc_cell2size(fc_arg(cp, 0));
12891772Sjl139090 	rspec.regspec_bustype = fc_cell2uint(fc_arg(cp, 1));
12901772Sjl139090 	rspec.regspec_addr = fc_cell2uint(fc_arg(cp, 2));
12911772Sjl139090 
12921772Sjl139090 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
12931772Sjl139090 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
12941772Sjl139090 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
12951772Sjl139090 
12961772Sjl139090 	FC_DEBUG3(1, CE_CONT, "opl_map_in: attempting map in "
12971772Sjl139090 	    "address 0x%08x.%08x length %x\n", rspec.regspec_bustype,
12981772Sjl139090 	    rspec.regspec_addr, rspec.regspec_size);
12991772Sjl139090 
13001772Sjl139090 	error = opl_map_phys(rp->child, &rspec, &virt, &acc, &h);
13011772Sjl139090 
13021772Sjl139090 	if (error)  {
13031772Sjl139090 		FC_DEBUG3(1, CE_CONT, "opl_map_in: map in failed - "
13041772Sjl139090 		    "address 0x%08x.%08x length %x\n", rspec.regspec_bustype,
13051772Sjl139090 		    rspec.regspec_addr, rspec.regspec_size);
13061772Sjl139090 
13071772Sjl139090 		return (fc_priv_error(cp, "opl map-in failed"));
13081772Sjl139090 	}
13091772Sjl139090 
13101772Sjl139090 	FC_DEBUG1(3, CE_CONT, "opl_map_in: returning virt %p\n", virt);
13111772Sjl139090 
13121772Sjl139090 	cp->nresults = fc_int2cell(1);
13131772Sjl139090 	fc_result(cp, 0) = fc_ptr2cell(virt);
13141772Sjl139090 
13151772Sjl139090 	/*
13161772Sjl139090 	 * Log this resource ...
13171772Sjl139090 	 */
13181772Sjl139090 	resp = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP);
13191772Sjl139090 	resp->type = RT_MAP;
13201772Sjl139090 	resp->fc_map_virt = virt;
13211772Sjl139090 	resp->fc_map_len = len;
13221772Sjl139090 	resp->fc_map_handle = h;
13231772Sjl139090 	fc_add_resource(rp, resp);
13241772Sjl139090 
13251772Sjl139090 	return (fc_success_op(ap, rp, cp));
13261772Sjl139090 }
13271772Sjl139090 
13281772Sjl139090 /*
13291772Sjl139090  * map-out (virt size -- )
13301772Sjl139090  */
13311772Sjl139090 static int
opl_map_out(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)13321772Sjl139090 opl_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
13331772Sjl139090 {
13341772Sjl139090 	caddr_t			virt;
13351772Sjl139090 	size_t			len;
13361772Sjl139090 	struct fc_resource	*resp;
13371772Sjl139090 
13381772Sjl139090 	if (fc_cell2int(cp->nargs) != 2)
13391772Sjl139090 		return (fc_syntax_error(cp, "nargs must be 2"));
13401772Sjl139090 
13411772Sjl139090 	virt = fc_cell2ptr(fc_arg(cp, 1));
13421772Sjl139090 
13431772Sjl139090 	len = fc_cell2size(fc_arg(cp, 0));
13441772Sjl139090 
13451772Sjl139090 	FC_DEBUG2(1, CE_CONT, "opl_map_out: attempting map out %p %x\n",
13461772Sjl139090 	    virt, len);
13471772Sjl139090 
13481772Sjl139090 	/*
13491772Sjl139090 	 * Find if this request matches a mapping resource we set up.
13501772Sjl139090 	 */
13511772Sjl139090 	fc_lock_resource_list(rp);
13521772Sjl139090 	for (resp = rp->head; resp != NULL; resp = resp->next) {
13531772Sjl139090 		if (resp->type != RT_MAP)
13541772Sjl139090 			continue;
13551772Sjl139090 		if (resp->fc_map_virt != virt)
13561772Sjl139090 			continue;
13571772Sjl139090 		if (resp->fc_map_len == len)
13581772Sjl139090 			break;
13591772Sjl139090 	}
13601772Sjl139090 	fc_unlock_resource_list(rp);
13611772Sjl139090 
13621772Sjl139090 	if (resp == NULL)
13631772Sjl139090 		return (fc_priv_error(cp, "request doesn't match a "
13641772Sjl139090 		    "known mapping"));
13651772Sjl139090 
13661772Sjl139090 	opl_unmap_phys(&resp->fc_map_handle);
13671772Sjl139090 
13681772Sjl139090 	/*
13691772Sjl139090 	 * remove the resource from the list and release it.
13701772Sjl139090 	 */
13711772Sjl139090 	fc_rem_resource(rp, resp);
13721772Sjl139090 	kmem_free(resp, sizeof (struct fc_resource));
13731772Sjl139090 
13741772Sjl139090 	cp->nresults = fc_int2cell(0);
13751772Sjl139090 	return (fc_success_op(ap, rp, cp));
13761772Sjl139090 }
13771772Sjl139090 
13781772Sjl139090 static int
opl_register_fetch(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)13791772Sjl139090 opl_register_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
13801772Sjl139090 {
13811772Sjl139090 	size_t			len;
13821772Sjl139090 	caddr_t			virt;
13831772Sjl139090 	int			error = 0;
13841772Sjl139090 	uint64_t		v;
13851772Sjl139090 	uint64_t		x;
13861772Sjl139090 	uint32_t		l;
13871772Sjl139090 	uint16_t		w;
13881772Sjl139090 	uint8_t			b;
13891772Sjl139090 	char			*service = fc_cell2ptr(cp->svc_name);
13901772Sjl139090 	struct fc_resource	*resp;
13911772Sjl139090 
13921772Sjl139090 	if (fc_cell2int(cp->nargs) != 1)
13931772Sjl139090 		return (fc_syntax_error(cp, "nargs must be 1"));
13941772Sjl139090 
13951772Sjl139090 	if (fc_cell2int(cp->nresults) < 1)
13961772Sjl139090 		return (fc_syntax_error(cp, "nresults must be >= 1"));
13971772Sjl139090 
13981772Sjl139090 	virt = fc_cell2ptr(fc_arg(cp, 0));
13991772Sjl139090 
14001772Sjl139090 	/*
14011772Sjl139090 	 * Determine the access width .. we can switch on the 2nd
14021772Sjl139090 	 * character of the name which is "rx@", "rl@", "rb@" or "rw@"
14031772Sjl139090 	 */
14041772Sjl139090 	switch (*(service + 1)) {
14051772Sjl139090 	case 'x':	len = sizeof (x); break;
14061772Sjl139090 	case 'l':	len = sizeof (l); break;
14071772Sjl139090 	case 'w':	len = sizeof (w); break;
14081772Sjl139090 	case 'b':	len = sizeof (b); break;
14091772Sjl139090 	}
14101772Sjl139090 
14111772Sjl139090 	/*
14121772Sjl139090 	 * Check the alignment ...
14131772Sjl139090 	 */
14141772Sjl139090 	if (((intptr_t)virt & (len - 1)) != 0)
14151772Sjl139090 		return (fc_priv_error(cp, "unaligned access"));
14161772Sjl139090 
14171772Sjl139090 	/*
14181772Sjl139090 	 * Find if this virt is 'within' a request we know about
14191772Sjl139090 	 */
14201772Sjl139090 	fc_lock_resource_list(rp);
14211772Sjl139090 	for (resp = rp->head; resp != NULL; resp = resp->next) {
14221772Sjl139090 		if (resp->type == RT_MAP) {
14231772Sjl139090 			if ((virt >= (caddr_t)resp->fc_map_virt) &&
14241772Sjl139090 			    ((virt + len) <=
14251772Sjl139090 			    ((caddr_t)resp->fc_map_virt + resp->fc_map_len)))
14261772Sjl139090 				break;
14271772Sjl139090 		} else if (resp->type == RT_CONTIGIOUS) {
14285037Sjl139090 			if ((virt >= (caddr_t)resp->fc_contig_virt) &&
14295037Sjl139090 			    ((virt + len) <= ((caddr_t)resp->fc_contig_virt +
14301772Sjl139090 			    resp->fc_contig_len)))
14311772Sjl139090 				break;
14321772Sjl139090 		}
14331772Sjl139090 	}
14341772Sjl139090 	fc_unlock_resource_list(rp);
14351772Sjl139090 
14361772Sjl139090 	if (resp == NULL) {
14371772Sjl139090 		return (fc_priv_error(cp, "request not within "
14381772Sjl139090 		    "known mappings"));
14391772Sjl139090 	}
14401772Sjl139090 
14411772Sjl139090 	switch (len) {
14421772Sjl139090 	case sizeof (x):
14431772Sjl139090 		if (resp->type == RT_MAP)
14445037Sjl139090 			error = ddi_peek64(rp->child, (int64_t *)virt,
14455037Sjl139090 			    (int64_t *)&x);
14461772Sjl139090 		else /* RT_CONTIGIOUS */
14471772Sjl139090 			x = *(int64_t *)virt;
14481772Sjl139090 		v = x;
14491772Sjl139090 		break;
14501772Sjl139090 	case sizeof (l):
14511772Sjl139090 		if (resp->type == RT_MAP)
14525037Sjl139090 			error = ddi_peek32(rp->child, (int32_t *)virt,
14535037Sjl139090 			    (int32_t *)&l);
14541772Sjl139090 		else /* RT_CONTIGIOUS */
14551772Sjl139090 			l = *(int32_t *)virt;
14561772Sjl139090 		v = l;
14571772Sjl139090 		break;
14581772Sjl139090 	case sizeof (w):
14591772Sjl139090 		if (resp->type == RT_MAP)
14605037Sjl139090 			error = ddi_peek16(rp->child, (int16_t *)virt,
14615037Sjl139090 			    (int16_t *)&w);
14621772Sjl139090 		else /* RT_CONTIGIOUS */
14631772Sjl139090 			w = *(int16_t *)virt;
14641772Sjl139090 		v = w;
14651772Sjl139090 		break;
14661772Sjl139090 	case sizeof (b):
14671772Sjl139090 		if (resp->type == RT_MAP)
14685037Sjl139090 			error = ddi_peek8(rp->child, (int8_t *)virt,
14695037Sjl139090 			    (int8_t *)&b);
14701772Sjl139090 		else /* RT_CONTIGIOUS */
14711772Sjl139090 			b = *(int8_t *)virt;
14721772Sjl139090 		v = b;
14731772Sjl139090 		break;
14741772Sjl139090 	}
14751772Sjl139090 
14761772Sjl139090 	if (error == DDI_FAILURE) {
14771772Sjl139090 		FC_DEBUG2(1, CE_CONT, "opl_register_fetch: access error "
14781772Sjl139090 		    "accessing virt %p len %d\n", virt, len);
14791772Sjl139090 		return (fc_priv_error(cp, "access error"));
14801772Sjl139090 	}
14811772Sjl139090 
14821772Sjl139090 	FC_DEBUG3(1, CE_CONT, "register_fetch (%s) %llx %llx\n",
14831772Sjl139090 	    service, virt, v);
14841772Sjl139090 
14851772Sjl139090 	cp->nresults = fc_int2cell(1);
14861772Sjl139090 	switch (len) {
14871772Sjl139090 	case sizeof (x): fc_result(cp, 0) = x; break;
14881772Sjl139090 	case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break;
14891772Sjl139090 	case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break;
14901772Sjl139090 	case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break;
14911772Sjl139090 	}
14921772Sjl139090 	return (fc_success_op(ap, rp, cp));
14931772Sjl139090 }
14941772Sjl139090 
14951772Sjl139090 static int
opl_register_store(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)14961772Sjl139090 opl_register_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
14971772Sjl139090 {
14981772Sjl139090 	size_t			len;
14991772Sjl139090 	caddr_t			virt;
15001772Sjl139090 	uint64_t		v;
15011772Sjl139090 	uint64_t		x;
15021772Sjl139090 	uint32_t		l;
15031772Sjl139090 	uint16_t		w;
15041772Sjl139090 	uint8_t			b;
15051772Sjl139090 	char			*service = fc_cell2ptr(cp->svc_name);
15061772Sjl139090 	struct fc_resource	*resp;
15071772Sjl139090 	int			error = 0;
15081772Sjl139090 
15091772Sjl139090 	if (fc_cell2int(cp->nargs) != 2)
15101772Sjl139090 		return (fc_syntax_error(cp, "nargs must be 2"));
15111772Sjl139090 
15121772Sjl139090 	virt = fc_cell2ptr(fc_arg(cp, 0));
15131772Sjl139090 
15141772Sjl139090 	/*
15151772Sjl139090 	 * Determine the access width .. we can switch on the 2nd
15161772Sjl139090 	 * character of the name which is "rx!", "rl!", "rb!" or "rw!"
15171772Sjl139090 	 */
15181772Sjl139090 	switch (*(service + 1)) {
15191772Sjl139090 	case 'x':
15201772Sjl139090 		len = sizeof (x);
15211772Sjl139090 		x = fc_arg(cp, 1);
15221772Sjl139090 		v = x;
15231772Sjl139090 		break;
15241772Sjl139090 	case 'l':
15251772Sjl139090 		len = sizeof (l);
15261772Sjl139090 		l = fc_cell2uint32_t(fc_arg(cp, 1));
15271772Sjl139090 		v = l;
15281772Sjl139090 		break;
15291772Sjl139090 	case 'w':
15301772Sjl139090 		len = sizeof (w);
15311772Sjl139090 		w = fc_cell2uint16_t(fc_arg(cp, 1));
15321772Sjl139090 		v = w;
15331772Sjl139090 		break;
15341772Sjl139090 	case 'b':
15351772Sjl139090 		len = sizeof (b);
15361772Sjl139090 		b = fc_cell2uint8_t(fc_arg(cp, 1));
15371772Sjl139090 		v = b;
15381772Sjl139090 		break;
15391772Sjl139090 	}
15401772Sjl139090 
15411772Sjl139090 	FC_DEBUG3(1, CE_CONT, "register_store (%s) %llx %llx\n",
15421772Sjl139090 	    service, virt, v);
15431772Sjl139090 
15441772Sjl139090 	/*
15451772Sjl139090 	 * Check the alignment ...
15461772Sjl139090 	 */
15471772Sjl139090 	if (((intptr_t)virt & (len - 1)) != 0)
15481772Sjl139090 		return (fc_priv_error(cp, "unaligned access"));
15491772Sjl139090 
15501772Sjl139090 	/*
15511772Sjl139090 	 * Find if this virt is 'within' a request we know about
15521772Sjl139090 	 */
15531772Sjl139090 	fc_lock_resource_list(rp);
15541772Sjl139090 	for (resp = rp->head; resp != NULL; resp = resp->next) {
15551772Sjl139090 		if (resp->type == RT_MAP) {
15561772Sjl139090 			if ((virt >= (caddr_t)resp->fc_map_virt) &&
15571772Sjl139090 			    ((virt + len) <=
15581772Sjl139090 			    ((caddr_t)resp->fc_map_virt + resp->fc_map_len)))
15591772Sjl139090 				break;
15601772Sjl139090 		} else if (resp->type == RT_CONTIGIOUS) {
15615037Sjl139090 			if ((virt >= (caddr_t)resp->fc_contig_virt) &&
15625037Sjl139090 			    ((virt + len) <= ((caddr_t)resp->fc_contig_virt +
15631772Sjl139090 			    resp->fc_contig_len)))
15641772Sjl139090 				break;
15651772Sjl139090 		}
15661772Sjl139090 	}
15671772Sjl139090 	fc_unlock_resource_list(rp);
15681772Sjl139090 
15691772Sjl139090 	if (resp == NULL)
15701772Sjl139090 		return (fc_priv_error(cp, "request not within"
15711772Sjl139090 		    "known mappings"));
15721772Sjl139090 
15731772Sjl139090 	switch (len) {
15741772Sjl139090 	case sizeof (x):
15751772Sjl139090 		if (resp->type == RT_MAP)
15761772Sjl139090 			error = ddi_poke64(rp->child, (int64_t *)virt, x);
15771772Sjl139090 		else if (resp->type == RT_CONTIGIOUS)
15781772Sjl139090 			*(uint64_t *)virt = x;
15791772Sjl139090 		break;
15801772Sjl139090 	case sizeof (l):
15811772Sjl139090 		if (resp->type == RT_MAP)
15821772Sjl139090 			error = ddi_poke32(rp->child, (int32_t *)virt, l);
15831772Sjl139090 		else if (resp->type == RT_CONTIGIOUS)
15841772Sjl139090 			*(uint32_t *)virt = l;
15851772Sjl139090 		break;
15861772Sjl139090 	case sizeof (w):
15871772Sjl139090 		if (resp->type == RT_MAP)
15881772Sjl139090 			error = ddi_poke16(rp->child, (int16_t *)virt, w);
15891772Sjl139090 		else if (resp->type == RT_CONTIGIOUS)
15901772Sjl139090 			*(uint16_t *)virt = w;
15911772Sjl139090 		break;
15921772Sjl139090 	case sizeof (b):
15931772Sjl139090 		if (resp->type == RT_MAP)
15941772Sjl139090 			error = ddi_poke8(rp->child, (int8_t *)virt, b);
15951772Sjl139090 		else if (resp->type == RT_CONTIGIOUS)
15961772Sjl139090 			*(uint8_t *)virt = b;
15971772Sjl139090 		break;
15981772Sjl139090 	}
15991772Sjl139090 
16001772Sjl139090 	if (error == DDI_FAILURE) {
16011772Sjl139090 		FC_DEBUG2(1, CE_CONT, "opl_register_store: access error "
16021772Sjl139090 		    "accessing virt %p len %d\n", virt, len);
16031772Sjl139090 		return (fc_priv_error(cp, "access error"));
16041772Sjl139090 	}
16051772Sjl139090 
16061772Sjl139090 	cp->nresults = fc_int2cell(0);
16071772Sjl139090 	return (fc_success_op(ap, rp, cp));
16081772Sjl139090 }
16091772Sjl139090 
16101772Sjl139090 /*
16111772Sjl139090  * opl_claim_memory
16121772Sjl139090  *
16131772Sjl139090  * claim-memory (align size vhint -- vaddr)
16141772Sjl139090  */
16151772Sjl139090 static int
opl_claim_memory(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)16161772Sjl139090 opl_claim_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
16171772Sjl139090 {
16181772Sjl139090 	int			align, size, vhint;
16191772Sjl139090 	uint64_t		answer, alen;
16201772Sjl139090 	ndi_ra_request_t	request;
16211772Sjl139090 	struct fc_resource	*resp;
16221772Sjl139090 
16231772Sjl139090 	if (fc_cell2int(cp->nargs) != 3)
16241772Sjl139090 		return (fc_syntax_error(cp, "nargs must be 3"));
16251772Sjl139090 
16261772Sjl139090 	if (fc_cell2int(cp->nresults) < 1)
16271772Sjl139090 		return (fc_syntax_error(cp, "nresults must be >= 1"));
16281772Sjl139090 
16291772Sjl139090 	vhint = fc_cell2int(fc_arg(cp, 2));
16301772Sjl139090 	size  = fc_cell2int(fc_arg(cp, 1));
16311772Sjl139090 	align = fc_cell2int(fc_arg(cp, 0));
16321772Sjl139090 
16331772Sjl139090 	FC_DEBUG3(1, CE_CONT, "opl_claim_memory: align=0x%x size=0x%x "
16341772Sjl139090 	    "vhint=0x%x\n", align, size, vhint);
16351772Sjl139090 
16361772Sjl139090 	if (size == 0) {
16371772Sjl139090 		cmn_err(CE_WARN, "opl_claim_memory - unable to allocate "
16381772Sjl139090 		    "contiguous memory of size zero\n");
16391772Sjl139090 		return (fc_priv_error(cp, "allocation error"));
16401772Sjl139090 	}
16411772Sjl139090 
16421772Sjl139090 	if (vhint) {
16431772Sjl139090 		cmn_err(CE_WARN, "opl_claim_memory - vhint is not zero "
16441772Sjl139090 		    "vhint=0x%x - Ignoring Argument\n", vhint);
16451772Sjl139090 	}
16461772Sjl139090 
16471772Sjl139090 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
16481772Sjl139090 	request.ra_flags	= NDI_RA_ALLOC_BOUNDED;
16491772Sjl139090 	request.ra_boundbase	= 0;
16501772Sjl139090 	request.ra_boundlen	= 0xffffffff;
16511772Sjl139090 	request.ra_len		= size;
16521772Sjl139090 	request.ra_align_mask	= align - 1;
16531772Sjl139090 
16541772Sjl139090 	if (ndi_ra_alloc(ddi_root_node(), &request, &answer, &alen,
16551772Sjl139090 	    "opl-fcodemem", NDI_RA_PASS) != NDI_SUCCESS) {
16561772Sjl139090 		cmn_err(CE_WARN, "opl_claim_memory - unable to allocate "
16571772Sjl139090 		    "contiguous memory\n");
16581772Sjl139090 		return (fc_priv_error(cp, "allocation error"));
16591772Sjl139090 	}
16601772Sjl139090 
16611772Sjl139090 	FC_DEBUG2(1, CE_CONT, "opl_claim_memory: address allocated=0x%lx "
16621772Sjl139090 	    "size=0x%x\n", answer, alen);
16631772Sjl139090 
16641772Sjl139090 	cp->nresults = fc_int2cell(1);
16651772Sjl139090 	fc_result(cp, 0) = answer;
16661772Sjl139090 
16671772Sjl139090 	/*
16681772Sjl139090 	 * Log this resource ...
16691772Sjl139090 	 */
16701772Sjl139090 	resp = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP);
16711772Sjl139090 	resp->type = RT_CONTIGIOUS;
16721772Sjl139090 	resp->fc_contig_virt = (void *)answer;
16731772Sjl139090 	resp->fc_contig_len = size;
16741772Sjl139090 	fc_add_resource(rp, resp);
16751772Sjl139090 
16761772Sjl139090 	return (fc_success_op(ap, rp, cp));
16771772Sjl139090 }
16781772Sjl139090 
16791772Sjl139090 /*
16801772Sjl139090  * opl_release_memory
16811772Sjl139090  *
16821772Sjl139090  * release-memory (size vaddr -- )
16831772Sjl139090  */
16841772Sjl139090 static int
opl_release_memory(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)16851772Sjl139090 opl_release_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
16861772Sjl139090 {
16871772Sjl139090 	int32_t			vaddr, size;
16881772Sjl139090 	struct fc_resource	*resp;
16891772Sjl139090 
16901772Sjl139090 	if (fc_cell2int(cp->nargs) != 2)
16911772Sjl139090 		return (fc_syntax_error(cp, "nargs must be 2"));
16921772Sjl139090 
16931772Sjl139090 	if (fc_cell2int(cp->nresults) != 0)
16941772Sjl139090 		return (fc_syntax_error(cp, "nresults must be 0"));
16951772Sjl139090 
16961772Sjl139090 	vaddr = fc_cell2int(fc_arg(cp, 1));
16971772Sjl139090 	size  = fc_cell2int(fc_arg(cp, 0));
16981772Sjl139090 
16991772Sjl139090 	FC_DEBUG2(1, CE_CONT, "opl_release_memory: vaddr=0x%x size=0x%x\n",
17001772Sjl139090 	    vaddr, size);
17011772Sjl139090 
17021772Sjl139090 	/*
17031772Sjl139090 	 * Find if this request matches a mapping resource we set up.
17041772Sjl139090 	 */
17051772Sjl139090 	fc_lock_resource_list(rp);
17061772Sjl139090 	for (resp = rp->head; resp != NULL; resp = resp->next) {
17071772Sjl139090 		if (resp->type != RT_CONTIGIOUS)
17081772Sjl139090 			continue;
17091772Sjl139090 		if (resp->fc_contig_virt != (void *)(uintptr_t)vaddr)
17101772Sjl139090 			continue;
17111772Sjl139090 		if (resp->fc_contig_len == size)
17121772Sjl139090 			break;
17131772Sjl139090 	}
17141772Sjl139090 	fc_unlock_resource_list(rp);
17151772Sjl139090 
17161772Sjl139090 	if (resp == NULL)
17171772Sjl139090 		return (fc_priv_error(cp, "request doesn't match a "
17181772Sjl139090 		    "known mapping"));
17191772Sjl139090 
17201772Sjl139090 	(void) ndi_ra_free(ddi_root_node(), vaddr, size,
17211772Sjl139090 	    "opl-fcodemem", NDI_RA_PASS);
17221772Sjl139090 
17231772Sjl139090 	/*
17241772Sjl139090 	 * remove the resource from the list and release it.
17251772Sjl139090 	 */
17261772Sjl139090 	fc_rem_resource(rp, resp);
17271772Sjl139090 	kmem_free(resp, sizeof (struct fc_resource));
17281772Sjl139090 
17291772Sjl139090 	cp->nresults = fc_int2cell(0);
17301772Sjl139090 
17311772Sjl139090 	return (fc_success_op(ap, rp, cp));
17321772Sjl139090 }
17331772Sjl139090 
17341772Sjl139090 /*
17351772Sjl139090  * opl_vtop
17361772Sjl139090  *
17371772Sjl139090  * vtop (vaddr -- paddr.lo paddr.hi)
17381772Sjl139090  */
17391772Sjl139090 static int
opl_vtop(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)17401772Sjl139090 opl_vtop(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
17411772Sjl139090 {
17421772Sjl139090 	int			vaddr;
17431772Sjl139090 	uint64_t		paddr;
17441772Sjl139090 	struct fc_resource	*resp;
17451772Sjl139090 
17461772Sjl139090 	if (fc_cell2int(cp->nargs) != 1)
17471772Sjl139090 		return (fc_syntax_error(cp, "nargs must be 1"));
17481772Sjl139090 
17491772Sjl139090 	if (fc_cell2int(cp->nresults) >= 3)
17501772Sjl139090 		return (fc_syntax_error(cp, "nresults must be less than 2"));
17511772Sjl139090 
17521772Sjl139090 	vaddr = fc_cell2int(fc_arg(cp, 0));
17531772Sjl139090 
17541772Sjl139090 	/*
17551772Sjl139090 	 * Find if this request matches a mapping resource we set up.
17561772Sjl139090 	 */
17571772Sjl139090 	fc_lock_resource_list(rp);
17581772Sjl139090 	for (resp = rp->head; resp != NULL; resp = resp->next) {
17591772Sjl139090 		if (resp->type != RT_CONTIGIOUS)
17601772Sjl139090 			continue;
17613965Sbm42561 		if (((uint64_t)resp->fc_contig_virt <= vaddr) &&
17623965Sbm42561 		    (vaddr < (uint64_t)resp->fc_contig_virt +
17633965Sbm42561 		    resp->fc_contig_len))
17641772Sjl139090 			break;
17651772Sjl139090 	}
17661772Sjl139090 	fc_unlock_resource_list(rp);
17671772Sjl139090 
17681772Sjl139090 	if (resp == NULL)
17691772Sjl139090 		return (fc_priv_error(cp, "request doesn't match a "
17701772Sjl139090 		    "known mapping"));
17711772Sjl139090 
17721772Sjl139090 	paddr = va_to_pa((void *)(uintptr_t)vaddr);
17731772Sjl139090 
17741772Sjl139090 	FC_DEBUG2(1, CE_CONT, "opl_vtop: vaddr=0x%x paddr=0x%x\n",
17751772Sjl139090 	    vaddr, paddr);
17761772Sjl139090 
17771772Sjl139090 	cp->nresults = fc_int2cell(2);
17781772Sjl139090 
17791772Sjl139090 	fc_result(cp, 0) = paddr;
17801772Sjl139090 	fc_result(cp, 1) = 0;
17811772Sjl139090 
17821772Sjl139090 	return (fc_success_op(ap, rp, cp));
17831772Sjl139090 }
17841772Sjl139090 
17851772Sjl139090 static int
opl_config_child(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)17861772Sjl139090 opl_config_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
17871772Sjl139090 {
17881772Sjl139090 	fc_phandle_t h;
17891772Sjl139090 
17901772Sjl139090 	if (fc_cell2int(cp->nargs) != 0)
17911772Sjl139090 		return (fc_syntax_error(cp, "nargs must be 0"));
17921772Sjl139090 
17931772Sjl139090 	if (fc_cell2int(cp->nresults) < 1)
17941772Sjl139090 		return (fc_syntax_error(cp, "nresults must be >= 1"));
17951772Sjl139090 
17961772Sjl139090 	h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child);
17971772Sjl139090 
17981772Sjl139090 	cp->nresults = fc_int2cell(1);
17991772Sjl139090 	fc_result(cp, 0) = fc_phandle2cell(h);
18001772Sjl139090 
18011772Sjl139090 	return (fc_success_op(ap, rp, cp));
18021772Sjl139090 }
18031772Sjl139090 
18041772Sjl139090 static int
opl_get_fcode(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)18051772Sjl139090 opl_get_fcode(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
18061772Sjl139090 {
18071772Sjl139090 	caddr_t		dropin_name_virt, fcode_virt;
18081772Sjl139090 	char		*dropin_name, *fcode;
18091772Sjl139090 	int		fcode_len, status;
18101772Sjl139090 
18111772Sjl139090 	if (fc_cell2int(cp->nargs) != 3)
18121772Sjl139090 		return (fc_syntax_error(cp, "nargs must be 3"));
18131772Sjl139090 
18141772Sjl139090 	if (fc_cell2int(cp->nresults) < 1)
18151772Sjl139090 		return (fc_syntax_error(cp, "nresults must be >= 1"));
18161772Sjl139090 
18171772Sjl139090 	dropin_name_virt = fc_cell2ptr(fc_arg(cp, 0));
18181772Sjl139090 
18191772Sjl139090 	fcode_virt = fc_cell2ptr(fc_arg(cp, 1));
18201772Sjl139090 
18211772Sjl139090 	fcode_len = fc_cell2int(fc_arg(cp, 2));
18221772Sjl139090 
18231772Sjl139090 	dropin_name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP);
18241772Sjl139090 
18251772Sjl139090 	FC_DEBUG2(1, CE_CONT, "get_fcode: %x %d\n", fcode_virt, fcode_len);
18261772Sjl139090 
18271772Sjl139090 	if (copyinstr(fc_cell2ptr(dropin_name_virt), dropin_name,
18281772Sjl139090 	    FC_SVC_NAME_LEN - 1, NULL))  {
18291772Sjl139090 		FC_DEBUG1(1, CE_CONT, "opl_get_fcode: "
18301772Sjl139090 		    "fault copying in drop in name %p\n", dropin_name_virt);
18311772Sjl139090 		status = 0;
18321772Sjl139090 	} else {
18331772Sjl139090 		FC_DEBUG1(1, CE_CONT, "get_fcode: %s\n", dropin_name);
18341772Sjl139090 
18351772Sjl139090 		fcode = kmem_zalloc(fcode_len, KM_SLEEP);
18361772Sjl139090 
18371772Sjl139090 		if ((status = prom_get_fcode(dropin_name, fcode)) != 0) {
18381772Sjl139090 
18391772Sjl139090 			if (copyout((void *)fcode, (void *)fcode_virt,
18401772Sjl139090 			    fcode_len)) {
18411772Sjl139090 				cmn_err(CE_WARN, " opl_get_fcode: Unable "
18421772Sjl139090 				    "to copy out fcode image");
18431772Sjl139090 				status = 0;
18441772Sjl139090 			}
18451772Sjl139090 		}
18461772Sjl139090 
18471772Sjl139090 		kmem_free(fcode, fcode_len);
18481772Sjl139090 	}
18491772Sjl139090 
18501772Sjl139090 	kmem_free(dropin_name, FC_SVC_NAME_LEN);
18511772Sjl139090 
18521772Sjl139090 	cp->nresults = fc_int2cell(1);
18531772Sjl139090 	fc_result(cp, 0) = status;
18541772Sjl139090 
18551772Sjl139090 	return (fc_success_op(ap, rp, cp));
18561772Sjl139090 }
18571772Sjl139090 
18581772Sjl139090 static int
opl_get_fcode_size(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)18591772Sjl139090 opl_get_fcode_size(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
18601772Sjl139090 {
18611772Sjl139090 	caddr_t		virt;
18621772Sjl139090 	char		*dropin_name;
18631772Sjl139090 	int		len;
18641772Sjl139090 
18651772Sjl139090 	if (fc_cell2int(cp->nargs) != 1)
18661772Sjl139090 		return (fc_syntax_error(cp, "nargs must be 1"));
18671772Sjl139090 
18681772Sjl139090 	if (fc_cell2int(cp->nresults) < 1)
18691772Sjl139090 		return (fc_syntax_error(cp, "nresults must be >= 1"));
18701772Sjl139090 
18711772Sjl139090 	virt = fc_cell2ptr(fc_arg(cp, 0));
18721772Sjl139090 
18731772Sjl139090 	dropin_name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP);
18741772Sjl139090 
18751772Sjl139090 	FC_DEBUG0(1, CE_CONT, "opl_get_fcode_size:\n");
18761772Sjl139090 
18771772Sjl139090 	if (copyinstr(fc_cell2ptr(virt), dropin_name,
18781772Sjl139090 	    FC_SVC_NAME_LEN - 1, NULL))  {
18791772Sjl139090 		FC_DEBUG1(1, CE_CONT, "opl_get_fcode_size: "
18801772Sjl139090 		    "fault copying in drop in name %p\n", virt);
18811772Sjl139090 		len = 0;
18821772Sjl139090 	} else {
18831772Sjl139090 		FC_DEBUG1(1, CE_CONT, "opl_get_fcode_size: %s\n", dropin_name);
18841772Sjl139090 
18851772Sjl139090 		len = prom_get_fcode_size(dropin_name);
18861772Sjl139090 	}
18871772Sjl139090 
18881772Sjl139090 	kmem_free(dropin_name, FC_SVC_NAME_LEN);
18891772Sjl139090 
18901772Sjl139090 	FC_DEBUG1(1, CE_CONT, "opl_get_fcode_size: fcode_len = %d\n", len);
18911772Sjl139090 
18921772Sjl139090 	cp->nresults = fc_int2cell(1);
18931772Sjl139090 	fc_result(cp, 0) = len;
18941772Sjl139090 
18951772Sjl139090 	return (fc_success_op(ap, rp, cp));
18961772Sjl139090 }
18971772Sjl139090 
18981772Sjl139090 static int
opl_map_phys(dev_info_t * dip,struct regspec * phys_spec,caddr_t * addrp,ddi_device_acc_attr_t * accattrp,ddi_acc_handle_t * handlep)18991772Sjl139090 opl_map_phys(dev_info_t *dip, struct regspec *phys_spec,
19001772Sjl139090     caddr_t *addrp, ddi_device_acc_attr_t *accattrp,
19011772Sjl139090     ddi_acc_handle_t *handlep)
19021772Sjl139090 {
19031772Sjl139090 	ddi_map_req_t 	mapreq;
19041772Sjl139090 	ddi_acc_hdl_t	*acc_handlep;
19051772Sjl139090 	int		result;
19061772Sjl139090 	struct regspec	*rspecp;
19071772Sjl139090 
19081772Sjl139090 	*handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL);
19091772Sjl139090 	acc_handlep = impl_acc_hdl_get(*handlep);
19101772Sjl139090 	acc_handlep->ah_vers = VERS_ACCHDL;
19111772Sjl139090 	acc_handlep->ah_dip = dip;
19121772Sjl139090 	acc_handlep->ah_rnumber = 0;
19131772Sjl139090 	acc_handlep->ah_offset = 0;
19141772Sjl139090 	acc_handlep->ah_len = 0;
19151772Sjl139090 	acc_handlep->ah_acc = *accattrp;
19161772Sjl139090 	rspecp = kmem_zalloc(sizeof (struct regspec), KM_SLEEP);
19171772Sjl139090 	*rspecp = *phys_spec;
19181772Sjl139090 	/*
19191772Sjl139090 	 * cache a copy of the reg spec
19201772Sjl139090 	 */
19211772Sjl139090 	acc_handlep->ah_bus_private = rspecp;
19221772Sjl139090 
19231772Sjl139090 	mapreq.map_op = DDI_MO_MAP_LOCKED;
19241772Sjl139090 	mapreq.map_type = DDI_MT_REGSPEC;
19251772Sjl139090 	mapreq.map_obj.rp = (struct regspec *)phys_spec;
19261772Sjl139090 	mapreq.map_prot = PROT_READ | PROT_WRITE;
19271772Sjl139090 	mapreq.map_flags = DDI_MF_KERNEL_MAPPING;
19281772Sjl139090 	mapreq.map_handlep = acc_handlep;
19291772Sjl139090 	mapreq.map_vers = DDI_MAP_VERSION;
19301772Sjl139090 
19311772Sjl139090 	result = ddi_map(dip, &mapreq, 0, 0, addrp);
19321772Sjl139090 
19331772Sjl139090 	if (result != DDI_SUCCESS) {
19341772Sjl139090 		impl_acc_hdl_free(*handlep);
19353354Sjl139090 		kmem_free(rspecp, sizeof (struct regspec));
19361772Sjl139090 		*handlep = (ddi_acc_handle_t)NULL;
19371772Sjl139090 	} else {
19381772Sjl139090 		acc_handlep->ah_addr = *addrp;
19391772Sjl139090 	}
19401772Sjl139090 
19411772Sjl139090 	return (result);
19421772Sjl139090 }
19431772Sjl139090 
19441772Sjl139090 static void
opl_unmap_phys(ddi_acc_handle_t * handlep)19451772Sjl139090 opl_unmap_phys(ddi_acc_handle_t *handlep)
19461772Sjl139090 {
19471772Sjl139090 	ddi_map_req_t	mapreq;
19481772Sjl139090 	ddi_acc_hdl_t	*acc_handlep;
19491772Sjl139090 	struct regspec	*rspecp;
19501772Sjl139090 
19511772Sjl139090 	acc_handlep = impl_acc_hdl_get(*handlep);
19521772Sjl139090 	ASSERT(acc_handlep);
19531772Sjl139090 	rspecp = acc_handlep->ah_bus_private;
19541772Sjl139090 
19551772Sjl139090 	mapreq.map_op = DDI_MO_UNMAP;
19561772Sjl139090 	mapreq.map_type = DDI_MT_REGSPEC;
19571772Sjl139090 	mapreq.map_obj.rp = (struct regspec *)rspecp;
19581772Sjl139090 	mapreq.map_prot = PROT_READ | PROT_WRITE;
19591772Sjl139090 	mapreq.map_flags = DDI_MF_KERNEL_MAPPING;
19601772Sjl139090 	mapreq.map_handlep = acc_handlep;
19611772Sjl139090 	mapreq.map_vers = DDI_MAP_VERSION;
19621772Sjl139090 
19631772Sjl139090 	(void) ddi_map(acc_handlep->ah_dip, &mapreq, acc_handlep->ah_offset,
19641772Sjl139090 	    acc_handlep->ah_len, &acc_handlep->ah_addr);
19651772Sjl139090 
19661772Sjl139090 	impl_acc_hdl_free(*handlep);
19671772Sjl139090 	/*
19681772Sjl139090 	 * Free the cached copy
19691772Sjl139090 	 */
19701772Sjl139090 	kmem_free(rspecp, sizeof (struct regspec));
19711772Sjl139090 	*handlep = (ddi_acc_handle_t)NULL;
19721772Sjl139090 }
19731772Sjl139090 
19741772Sjl139090 static int
opl_get_hwd_va(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)19751772Sjl139090 opl_get_hwd_va(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
19761772Sjl139090 {
19771772Sjl139090 	uint32_t	portid;
19781772Sjl139090 	void		*hwd_virt;
19791772Sjl139090 	hwd_header_t	*hwd_h = NULL;
19801772Sjl139090 	hwd_sb_t	*hwd_sb = NULL;
19811772Sjl139090 	int		lsb, ch, leaf;
19821772Sjl139090 	int		status = 1;
19831772Sjl139090 
19841772Sjl139090 	/* Check the argument */
19851772Sjl139090 	if (fc_cell2int(cp->nargs) != 2)
19861772Sjl139090 		return (fc_syntax_error(cp, "nargs must be 2"));
19871772Sjl139090 
19881772Sjl139090 	if (fc_cell2int(cp->nresults) < 1)
19891772Sjl139090 		return (fc_syntax_error(cp, "nresults must be >= 1"));
19901772Sjl139090 
19911772Sjl139090 	/* Get the parameters */
19921772Sjl139090 	portid = fc_cell2uint32_t(fc_arg(cp, 0));
19931772Sjl139090 	hwd_virt = (void *)fc_cell2ptr(fc_arg(cp, 1));
19941772Sjl139090 
19951772Sjl139090 	/* Get the ID numbers */
19961772Sjl139090 	lsb  = OPL_IO_PORTID_TO_LSB(portid);
19971772Sjl139090 	ch   = OPL_PORTID_TO_CHANNEL(portid);
19981772Sjl139090 	leaf = OPL_PORTID_TO_LEAF(portid);
19991772Sjl139090 	ASSERT(OPL_IO_PORTID(lsb, ch, leaf) == portid);
20001772Sjl139090 
20011772Sjl139090 	/* Set the pointer of hwd. */
20021772Sjl139090 	if ((hwd_h = (hwd_header_t *)opl_boards[lsb].cfg_hwd) == NULL) {
20031772Sjl139090 		return (fc_priv_error(cp, "null hwd header"));
20041772Sjl139090 	}
20051772Sjl139090 	/* Set the pointer of hwd sb. */
20061772Sjl139090 	if ((hwd_sb = (hwd_sb_t *)((char *)hwd_h + hwd_h->hdr_sb_info_offset))
20071772Sjl139090 	    == NULL) {
20081772Sjl139090 		return (fc_priv_error(cp, "null hwd sb"));
20091772Sjl139090 	}
20101772Sjl139090 
20111772Sjl139090 	if (ch == OPL_CMU_CHANNEL) {
20121772Sjl139090 		/* Copyout CMU-CH HW Descriptor */
20131772Sjl139090 		if (copyout((void *)&hwd_sb->sb_cmu.cmu_ch,
20141772Sjl139090 		    (void *)hwd_virt, sizeof (hwd_cmu_chan_t))) {
20151772Sjl139090 			cmn_err(CE_WARN, "opl_get_hwd_va: "
20161772Sjl139090 			"Unable to copy out cmuch descriptor for %x",
20171772Sjl139090 			    portid);
20181772Sjl139090 			status = 0;
20191772Sjl139090 		}
20201772Sjl139090 	} else {
20211772Sjl139090 		/* Copyout PCI-CH HW Descriptor */
20221772Sjl139090 		if (copyout((void *)&hwd_sb->sb_pci_ch[ch].pci_leaf[leaf],
20231772Sjl139090 		    (void *)hwd_virt, sizeof (hwd_leaf_t))) {
20241772Sjl139090 			cmn_err(CE_WARN, "opl_get_hwd_va: "
20251772Sjl139090 			"Unable to copy out pcich descriptor for %x",
20261772Sjl139090 			    portid);
20271772Sjl139090 			status = 0;
20281772Sjl139090 		}
20291772Sjl139090 	}
20301772Sjl139090 
20311772Sjl139090 	cp->nresults = fc_int2cell(1);
20321772Sjl139090 	fc_result(cp, 0) = status;
20331772Sjl139090 
20341772Sjl139090 	return (fc_success_op(ap, rp, cp));
20351772Sjl139090 }
20361772Sjl139090 
20371772Sjl139090 /*
20381982Smv143129  * After Solaris boots, a user can enter OBP using L1A, etc. While in OBP,
20391982Smv143129  * interrupts may be received from PCI devices. These interrupts
20401982Smv143129  * cannot be handled meaningfully since the system is in OBP. These
20411982Smv143129  * interrupts need to be cleared on the CPU side so that the CPU may
20421982Smv143129  * continue with whatever it is doing. Devices that have raised the
20431982Smv143129  * interrupts are expected to reraise the interrupts after sometime
20441982Smv143129  * as they have not been handled. At that time, Solaris will have a
20451982Smv143129  * chance to properly service the interrupts.
20461982Smv143129  *
20471982Smv143129  * The location of the interrupt registers depends on what is present
20481982Smv143129  * at a port. OPL currently supports the Oberon and the CMU channel.
20491982Smv143129  * The following handler handles both kinds of ports and computes
20501982Smv143129  * interrupt register addresses from the specifications and Jupiter Bus
20511982Smv143129  * device bindings.
20521982Smv143129  *
20531982Smv143129  * Fcode drivers install their interrupt handler via a "master-interrupt"
20541982Smv143129  * service. For boot time devices, this takes place within OBP. In the case
20551982Smv143129  * of DR, OPL uses IKP. The Fcode drivers that run within the efcode framework
20561982Smv143129  * attempt to install their handler via the "master-interrupt" service.
20571982Smv143129  * However, we cannot meaningfully install the Fcode driver's handler.
20581982Smv143129  * Instead, we install our own handler in OBP which does the same thing.
20591982Smv143129  *
20601982Smv143129  * Note that the only handling done for interrupts here is to clear it
20611982Smv143129  * on the CPU side. If any device in the future requires more special
20621982Smv143129  * handling, we would have to put in some kind of framework for adding
20631982Smv143129  * device-specific handlers. This is *highly* unlikely, but possible.
20641982Smv143129  *
20651982Smv143129  * Finally, OBP provides a hook called "unix-interrupt-handler" to install
20661982Smv143129  * a Solaris-defined master-interrupt handler for a port. The default
20671982Smv143129  * definition for this method does nothing. Solaris may override this
20681982Smv143129  * with its own definition. This is the way the following handler gets
20691982Smv143129  * control from OBP when interrupts happen at a port after L1A, etc.
20701982Smv143129  */
20711982Smv143129 
20721982Smv143129 static char define_master_interrupt_handler[] =
20731982Smv143129 
20741982Smv143129 /*
20751982Smv143129  * This method translates an Oberon port id to the base (physical) address
20761982Smv143129  * of the interrupt clear registers for that port id.
20771982Smv143129  */
20781982Smv143129 
20791982Smv143129 ": pcich-mid>clear-int-pa   ( mid -- pa ) "
20801982Smv143129 "   dup 1 >> 7 and          ( mid ch# ) "
20811982Smv143129 "   over 4 >> h# 1f and     ( mid ch# lsb# ) "
20821982Smv143129 "   1 d# 46 <<              ( mid ch# lsb# pa ) "
20831982Smv143129 "   swap d# 40 << or        ( mid ch# pa ) "
20841982Smv143129 "   swap d# 37 << or        ( mid pa ) "
20851982Smv143129 "   swap 1 and if h# 70.0000 else h# 60.0000 then "
20861982Smv143129 "   or h# 1400 or           ( pa ) "
20871982Smv143129 "; "
20881982Smv143129 
20891982Smv143129 /*
20901982Smv143129  * This method translates a CMU channel port id to the base (physical) address
20911982Smv143129  * of the interrupt clear registers for that port id. There are two classes of
20921982Smv143129  * interrupts that need to be handled for a CMU channel:
20931982Smv143129  *	- obio interrupts
20941982Smv143129  *	- pci interrupts
20951982Smv143129  * So, there are two addresses that need to be computed.
20961982Smv143129  */
20971982Smv143129 
20981982Smv143129 ": cmuch-mid>clear-int-pa   ( mid -- obio-pa pci-pa ) "
20991982Smv143129 "   dup 1 >> 7 and          ( mid ch# ) "
21001982Smv143129 "   over 4 >> h# 1f and     ( mid ch# lsb# ) "
21011982Smv143129 "   1 d# 46 <<              ( mid ch# lsb# pa ) "
21021982Smv143129 "   swap d# 40 << or        ( mid ch# pa ) "
21031982Smv143129 "   swap d# 37 << or        ( mid pa ) "
21041982Smv143129 "   nip dup h# 1800 +       ( pa obio-pa ) "
21051982Smv143129 "   swap h# 1400 +          ( obio-pa pci-pa ) "
21061982Smv143129 "; "
21071982Smv143129 
21081982Smv143129 /*
21091982Smv143129  * This method checks if a given I/O port ID is valid or not.
21101982Smv143129  * For a given LSB,
21111982Smv143129  *	Oberon ports range from 0 - 3
21121982Smv143129  *	CMU ch ports range from 4 - 4
21131982Smv143129  *
21141982Smv143129  * Also, the Oberon supports leaves 0 and 1.
21151982Smv143129  * The CMU ch supports only one leaf, leaf 0.
21161982Smv143129  */
21171982Smv143129 
21181982Smv143129 ": valid-io-mid? ( mid -- flag ) "
21191982Smv143129 "   dup 1 >> 7 and                     ( mid ch# ) "
21201982Smv143129 "   dup 4 > if 2drop false exit then   ( mid ch# ) "
21211982Smv143129 "   4 = swap 1 and 1 = and not "
21221982Smv143129 "; "
21231982Smv143129 
21241982Smv143129 /*
21251982Smv143129  * This method checks if a given port id is a CMU ch.
21261982Smv143129  */
21271982Smv143129 
21281982Smv143129 ": cmuch? ( mid -- flag ) 1 >> 7 and 4 = ; "
21291982Smv143129 
21301982Smv143129 /*
21311982Smv143129  * Given the base address of the array of interrupt clear registers for
21321982Smv143129  * a port id, this method iterates over the given interrupt number bitmap
21331982Smv143129  * and resets the interrupt on the CPU side for every interrupt number
21341982Smv143129  * in the bitmap. Note that physical addresses are used to perform the
21351982Smv143129  * writes, not virtual addresses. This allows the handler to work without
21361982Smv143129  * any involvement from Solaris.
21371982Smv143129  */
21381982Smv143129 
21391982Smv143129 ": clear-ints ( pa bitmap count -- ) "
21401982Smv143129 "   0 do                            ( pa bitmap ) "
21411982Smv143129 "      dup 0= if 2drop unloop exit then "
21421982Smv143129 "      tuck                         ( bitmap pa bitmap ) "
21431982Smv143129 "      1 and if                     ( bitmap pa ) "
21441982Smv143129 "	 dup i 8 * + 0 swap         ( bitmap pa 0 pa' ) "
21451982Smv143129 "	 h# 15 spacex!              ( bitmap pa ) "
21461982Smv143129 "      then                         ( bitmap pa ) "
21471982Smv143129 "      swap 1 >>                    ( pa bitmap ) "
21481982Smv143129 "   loop "
21491982Smv143129 "; "
21501982Smv143129 
21511982Smv143129 /*
21521982Smv143129  * This method replaces the master-interrupt handler in OBP. Once
21531982Smv143129  * this method is plumbed into OBP, OBP transfers control to this
21541982Smv143129  * handler while returning to Solaris from OBP after L1A. This method's
21551982Smv143129  * task is to simply reset received interrupts on the CPU side.
21561982Smv143129  * When the devices reassert the interrupts later, Solaris will
21571982Smv143129  * be able to see them and handle them.
21581982Smv143129  *
21591982Smv143129  * For each port ID that has interrupts, this method is called
21601982Smv143129  * once by OBP. The input arguments are:
21611982Smv143129  *	mid	portid
21621982Smv143129  *	bitmap	bitmap of interrupts that have happened
21631982Smv143129  *
21641982Smv143129  * This method returns true, if it is able to handle the interrupts.
21651982Smv143129  * OBP does nothing further.
21661982Smv143129  *
21671982Smv143129  * This method returns false, if it encountered a problem. Currently,
21681982Smv143129  * the only problem could be an invalid port id. OBP needs to do
21691982Smv143129  * its own processing in that case. If this method returns false,
21701982Smv143129  * it preserves the mid and bitmap arguments for OBP.
21711982Smv143129  */
21721982Smv143129 
21731982Smv143129 ": unix-resend-mondos ( mid bitmap -- [ mid bitmap false ] | true ) "
21741982Smv143129 
21751982Smv143129 /*
21761982Smv143129  * Uncomment the following line if you want to display the input arguments.
21771982Smv143129  * This is meant for debugging.
21781982Smv143129  * "   .\" Bitmap=\" dup u. .\" MID=\" over u. cr "
21791982Smv143129  */
21801982Smv143129 
21811982Smv143129 /*
21821982Smv143129  * If the port id is not valid (according to the Oberon and CMU ch
21831982Smv143129  * specifications, then return false to OBP to continue further
21841982Smv143129  * processing.
21851982Smv143129  */
21861982Smv143129 
21871982Smv143129 "   over valid-io-mid? not if       ( mid bitmap ) "
21881982Smv143129 "      false exit "
21891982Smv143129 "   then "
21901982Smv143129 
21911982Smv143129 /*
21921982Smv143129  * If the port is a CMU ch, then the 64-bit bitmap represents
21931982Smv143129  * 2 32-bit bitmaps:
21941982Smv143129  *	- obio interrupt bitmap (20 bits)
21951982Smv143129  *	- pci interrupt bitmap (32 bits)
21961982Smv143129  *
21971982Smv143129  * - Split the bitmap into two
21981982Smv143129  * - Compute the base addresses of the interrupt clear registers
21991982Smv143129  *   for both pci interrupts and obio interrupts
22001982Smv143129  * - Clear obio interrupts
22011982Smv143129  * - Clear pci interrupts
22021982Smv143129  */
22031982Smv143129 
22041982Smv143129 "   over cmuch? if                  ( mid bitmap ) "
22051982Smv143129 "      xlsplit                      ( mid pci-bit obio-bit ) "
22061982Smv143129 "      rot cmuch-mid>clear-int-pa   ( pci-bit obio-bit obio-pa pci-pa ) "
22071982Smv143129 "      >r                           ( pci-bit obio-bit obio-pa ) ( r: pci-pa ) "
22081982Smv143129 "      swap d# 20 clear-ints        ( pci-bit ) ( r: pci-pa ) "
22091982Smv143129 "      r> swap d# 32 clear-ints     (  ) ( r: ) "
22101982Smv143129 
22111982Smv143129 /*
22121982Smv143129  * If the port is an Oberon, then the 64-bit bitmap is used fully.
22131982Smv143129  *
22141982Smv143129  * - Compute the base address of the interrupt clear registers
22151982Smv143129  * - Clear interrupts
22161982Smv143129  */
22171982Smv143129 
22181982Smv143129 "   else                            ( mid bitmap ) "
22191982Smv143129 "      swap pcich-mid>clear-int-pa  ( bitmap pa ) "
22201982Smv143129 "      swap d# 64 clear-ints        (  ) "
22211982Smv143129 "   then "
22221982Smv143129 
22231982Smv143129 /*
22241982Smv143129  * Always return true from here.
22251982Smv143129  */
22261982Smv143129 
22271982Smv143129 "   true                            ( true ) "
22281982Smv143129 "; "
22291982Smv143129 ;
22301982Smv143129 
22311982Smv143129 static char	install_master_interrupt_handler[] =
22321982Smv143129 	"' unix-resend-mondos to unix-interrupt-handler";
22331982Smv143129 static char	handler[] = "unix-interrupt-handler";
22341982Smv143129 static char	handler_defined[] = "p\" %s\" find nip swap l! ";
22351982Smv143129 
22361982Smv143129 /*ARGSUSED*/
22371982Smv143129 static int
master_interrupt_init(uint32_t portid,uint32_t xt)22381982Smv143129 master_interrupt_init(uint32_t portid, uint32_t xt)
22391982Smv143129 {
22401982Smv143129 	uint_t	defined;
22411982Smv143129 	char	buf[sizeof (handler) + sizeof (handler_defined)];
22421982Smv143129 
22431982Smv143129 	if (master_interrupt_inited)
22441982Smv143129 		return (1);
22451982Smv143129 
22461982Smv143129 	/*
22471982Smv143129 	 * Check if the defer word "unix-interrupt-handler" is defined.
22481982Smv143129 	 * This must be defined for OPL systems. So, this is only a
22491982Smv143129 	 * sanity check.
22501982Smv143129 	 */
22511982Smv143129 	(void) sprintf(buf, handler_defined, handler);
22521982Smv143129 	prom_interpret(buf, (uintptr_t)&defined, 0, 0, 0, 0);
22531982Smv143129 	if (!defined) {
22541982Smv143129 		cmn_err(CE_WARN, "master_interrupt_init: "
22551982Smv143129 		    "%s is not defined\n", handler);
22561982Smv143129 		return (0);
22571982Smv143129 	}
22581982Smv143129 
22591982Smv143129 	/*
22601982Smv143129 	 * Install the generic master-interrupt handler. Note that
22611982Smv143129 	 * this is only done one time on the first DR operation.
22621982Smv143129 	 * This is because, for OPL, one, single generic handler
22631982Smv143129 	 * handles all ports (Oberon and CMU channel) and all
22641982Smv143129 	 * interrupt sources within each port.
22651982Smv143129 	 *
22661982Smv143129 	 * The current support is only for the Oberon and CMU-channel.
22671982Smv143129 	 * If any others need to be supported, the handler has to be
22681982Smv143129 	 * modified accordingly.
22691982Smv143129 	 */
22701982Smv143129 
22711982Smv143129 	/*
22721982Smv143129 	 * Define the OPL master interrupt handler
22731982Smv143129 	 */
22741982Smv143129 	prom_interpret(define_master_interrupt_handler, 0, 0, 0, 0, 0);
22751982Smv143129 
22761982Smv143129 	/*
22771982Smv143129 	 * Take over the master interrupt handler from OBP.
22781982Smv143129 	 */
22791982Smv143129 	prom_interpret(install_master_interrupt_handler, 0, 0, 0, 0, 0);
22801982Smv143129 
22811982Smv143129 	master_interrupt_inited = 1;
22821982Smv143129 
22831982Smv143129 	/*
22841982Smv143129 	 * prom_interpret() does not return a status. So, we assume
22851982Smv143129 	 * that the calls succeeded. In reality, the calls may fail
22861982Smv143129 	 * if there is a syntax error, etc in the strings.
22871982Smv143129 	 */
22881982Smv143129 
22891982Smv143129 	return (1);
22901982Smv143129 }
22911982Smv143129 
22921982Smv143129 /*
22931982Smv143129  * Install the master-interrupt handler for a device.
22941982Smv143129  */
22951982Smv143129 static int
opl_master_interrupt(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)22961982Smv143129 opl_master_interrupt(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
22971982Smv143129 {
22981982Smv143129 	uint32_t	portid, xt;
22991982Smv143129 	int		board, channel, leaf;
23001982Smv143129 	int		status;
23011982Smv143129 
23021982Smv143129 	/* Check the argument */
23031982Smv143129 	if (fc_cell2int(cp->nargs) != 2)
23041982Smv143129 		return (fc_syntax_error(cp, "nargs must be 2"));
23051982Smv143129 
23061982Smv143129 	if (fc_cell2int(cp->nresults) < 1)
23071982Smv143129 		return (fc_syntax_error(cp, "nresults must be >= 1"));
23081982Smv143129 
23091982Smv143129 	/* Get the parameters */
23101982Smv143129 	portid = fc_cell2uint32_t(fc_arg(cp, 0));
23111982Smv143129 	xt = fc_cell2uint32_t(fc_arg(cp, 1));
23121982Smv143129 
23131982Smv143129 	board = OPL_IO_PORTID_TO_LSB(portid);
23141982Smv143129 	channel = OPL_PORTID_TO_CHANNEL(portid);
23151982Smv143129 	leaf = OPL_PORTID_TO_LEAF(portid);
23161982Smv143129 
23171982Smv143129 	if ((board >= HWD_SBS_PER_DOMAIN) || !OPL_VALID_CHANNEL(channel) ||
23181982Smv143129 	    (OPL_OBERON_CHANNEL(channel) && !OPL_VALID_LEAF(leaf)) ||
23191982Smv143129 	    ((channel == OPL_CMU_CHANNEL) && (leaf != 0))) {
23201982Smv143129 		FC_DEBUG1(1, CE_CONT, "opl_master_interrupt: invalid port %x\n",
23211982Smv143129 		    portid);
23221982Smv143129 		status = 0;
23231982Smv143129 	} else {
23241982Smv143129 		status = master_interrupt_init(portid, xt);
23251982Smv143129 	}
23261982Smv143129 
23271982Smv143129 	cp->nresults = fc_int2cell(1);
23281982Smv143129 	fc_result(cp, 0) = status;
23291982Smv143129 
23301982Smv143129 	return (fc_success_op(ap, rp, cp));
23311982Smv143129 }
23321982Smv143129 
23331982Smv143129 /*
23341772Sjl139090  * Set the properties for a leaf node (Oberon leaf or CMU channel leaf).
23351772Sjl139090  */
23361772Sjl139090 /*ARGSUSED*/
23371772Sjl139090 static int
opl_create_leaf(dev_info_t * node,void * arg,uint_t flags)23381772Sjl139090 opl_create_leaf(dev_info_t *node, void *arg, uint_t flags)
23391772Sjl139090 {
23401772Sjl139090 	int ret;
23411772Sjl139090 
23421772Sjl139090 	OPL_UPDATE_PROP(string, node, "name", OPL_PCI_LEAF_NODE);
23431772Sjl139090 
23441772Sjl139090 	OPL_UPDATE_PROP(string, node, "status", "okay");
23451772Sjl139090 
23461772Sjl139090 	return (DDI_WALK_TERMINATE);
23471772Sjl139090 }
23481772Sjl139090 
23491772Sjl139090 static char *
opl_get_probe_string(opl_probe_t * probe,int channel,int leaf)23501772Sjl139090 opl_get_probe_string(opl_probe_t *probe, int channel, int leaf)
23511772Sjl139090 {
23521772Sjl139090 	char 		*probe_string;
23531772Sjl139090 	int		portid;
23541772Sjl139090 
23551772Sjl139090 	probe_string = kmem_zalloc(PROBE_STR_SIZE, KM_SLEEP);
23561772Sjl139090 
23571772Sjl139090 	if (channel == OPL_CMU_CHANNEL)
23581772Sjl139090 		portid = probe->pr_sb->sb_cmu.cmu_ch.chan_portid;
23591772Sjl139090 	else
23601772Sjl139090 		portid = probe->
23611772Sjl139090 		    pr_sb->sb_pci_ch[channel].pci_leaf[leaf].leaf_port_id;
23621772Sjl139090 
23631772Sjl139090 	(void) sprintf(probe_string, "%x", portid);
23641772Sjl139090 
23651772Sjl139090 	return (probe_string);
23661772Sjl139090 }
23671772Sjl139090 
23681772Sjl139090 static int
opl_probe_leaf(opl_probe_t * probe)23691772Sjl139090 opl_probe_leaf(opl_probe_t *probe)
23701772Sjl139090 {
23711772Sjl139090 	int		channel, leaf, portid, error, circ;
23721772Sjl139090 	int		board;
23731772Sjl139090 	fco_handle_t	fco_handle, *cfg_handle;
23741772Sjl139090 	dev_info_t	*parent, *leaf_node;
23751772Sjl139090 	char		unit_address[UNIT_ADDR_SIZE];
23761772Sjl139090 	char		*probe_string;
23771772Sjl139090 	opl_board_cfg_t	*board_cfg;
23781772Sjl139090 
23791772Sjl139090 	board = probe->pr_board;
23801772Sjl139090 	channel = probe->pr_channel;
23811772Sjl139090 	leaf = probe->pr_leaf;
23821772Sjl139090 	parent = ddi_root_node();
23831772Sjl139090 	board_cfg = &opl_boards[board];
23841772Sjl139090 
23851772Sjl139090 	ASSERT(OPL_VALID_CHANNEL(channel));
23861772Sjl139090 	ASSERT(OPL_VALID_LEAF(leaf));
23871772Sjl139090 
23881772Sjl139090 	if (channel == OPL_CMU_CHANNEL) {
23891772Sjl139090 		portid = probe->pr_sb->sb_cmu.cmu_ch.chan_portid;
23901772Sjl139090 		cfg_handle = &board_cfg->cfg_cmuch_handle;
23911772Sjl139090 	} else {
23921772Sjl139090 		portid = probe->
23931772Sjl139090 		    pr_sb->sb_pci_ch[channel].pci_leaf[leaf].leaf_port_id;
23941772Sjl139090 		cfg_handle = &board_cfg->cfg_pcich_handle[channel][leaf];
23951772Sjl139090 	}
23961772Sjl139090 
23971772Sjl139090 	/*
23981772Sjl139090 	 * Prevent any changes to leaf_node until we have bound
23991772Sjl139090 	 * it to the correct driver.
24001772Sjl139090 	 */
24011772Sjl139090 	ndi_devi_enter(parent, &circ);
24021772Sjl139090 
24031772Sjl139090 	/*
24041772Sjl139090 	 * Ideally, fcode would be run from the "sid_branch_create"
24051772Sjl139090 	 * callback (that is the primary purpose of that callback).
24061772Sjl139090 	 * However, the fcode interpreter was written with the
24071772Sjl139090 	 * assumption that the "new_child" was linked into the
24081772Sjl139090 	 * device tree. The callback is invoked with the devinfo node
24091772Sjl139090 	 * in the DS_PROTO state. More investigation is needed before
24101772Sjl139090 	 * we can invoke the interpreter from the callback. For now,
24111772Sjl139090 	 * we create the "new_child" in the BOUND state, invoke the
24121772Sjl139090 	 * fcode interpreter and then rebind the dip to use any
24131772Sjl139090 	 * compatible properties created by fcode.
24141772Sjl139090 	 */
24151772Sjl139090 
24161772Sjl139090 	probe->pr_parent = parent;
24171772Sjl139090 	probe->pr_create = opl_create_leaf;
24181772Sjl139090 	probe->pr_hold = 1;
24191772Sjl139090 
24201772Sjl139090 	leaf_node = opl_create_node(probe);
24211772Sjl139090 	if (leaf_node == NULL) {
24221772Sjl139090 
24231772Sjl139090 		cmn_err(CE_WARN, "IKP: create leaf (%d-%d-%d) failed",
24245037Sjl139090 		    probe->pr_board, probe->pr_channel, probe->pr_leaf);
24251772Sjl139090 		ndi_devi_exit(parent, circ);
24261772Sjl139090 		return (-1);
24271772Sjl139090 	}
24281772Sjl139090 
24291772Sjl139090 	/*
24301772Sjl139090 	 * The platform DR interfaces created the dip in
24311772Sjl139090 	 * bound state. Bring devinfo node down to linked
24321772Sjl139090 	 * state and hold it there until compatible
24331772Sjl139090 	 * properties are created.
24341772Sjl139090 	 */
24351772Sjl139090 	e_ddi_branch_rele(leaf_node);
24361772Sjl139090 	(void) i_ndi_unconfig_node(leaf_node, DS_LINKED, 0);
24371772Sjl139090 	ASSERT(i_ddi_node_state(leaf_node) == DS_LINKED);
24381772Sjl139090 	e_ddi_branch_hold(leaf_node);
24391772Sjl139090 
24401772Sjl139090 	mutex_enter(&DEVI(leaf_node)->devi_lock);
24411772Sjl139090 	DEVI(leaf_node)->devi_flags |= DEVI_NO_BIND;
24421772Sjl139090 	mutex_exit(&DEVI(leaf_node)->devi_lock);
24431772Sjl139090 
24441772Sjl139090 	/*
24451772Sjl139090 	 * Drop the busy-hold on parent before calling
24461772Sjl139090 	 * fcode_interpreter to prevent potential deadlocks
24471772Sjl139090 	 */
24481772Sjl139090 	ndi_devi_exit(parent, circ);
24491772Sjl139090 
24501772Sjl139090 	(void) sprintf(unit_address, "%x", portid);
24511772Sjl139090 
24521772Sjl139090 	/*
24531772Sjl139090 	 * Get the probe string
24541772Sjl139090 	 */
24551772Sjl139090 	probe_string = opl_get_probe_string(probe, channel, leaf);
24561772Sjl139090 
24571772Sjl139090 	/*
24581772Sjl139090 	 * The fcode pointer specified here is NULL and the fcode
24591772Sjl139090 	 * size specified here is 0. This causes the user-level
24601772Sjl139090 	 * fcode interpreter to issue a request to the fcode
24611772Sjl139090 	 * driver to get the Oberon/cmu-ch fcode.
24621772Sjl139090 	 */
24631772Sjl139090 	fco_handle = opl_fc_ops_alloc_handle(parent, leaf_node,
24641772Sjl139090 	    NULL, 0, unit_address, probe_string);
24651772Sjl139090 
24661772Sjl139090 	error = fcode_interpreter(parent, &opl_fc_do_op, fco_handle);
24671772Sjl139090 
24681772Sjl139090 	if (error != 0) {
24691772Sjl139090 		cmn_err(CE_WARN, "IKP: Unable to probe PCI leaf (%d-%d-%d)",
24705037Sjl139090 		    probe->pr_board, probe->pr_channel, probe->pr_leaf);
24711772Sjl139090 
24721772Sjl139090 		opl_fc_ops_free_handle(fco_handle);
24731772Sjl139090 
24741772Sjl139090 		if (probe_string != NULL)
24751772Sjl139090 			kmem_free(probe_string, PROBE_STR_SIZE);
24761772Sjl139090 
24771772Sjl139090 		(void) opl_destroy_node(leaf_node);
24781772Sjl139090 	} else {
24791772Sjl139090 		*cfg_handle = fco_handle;
24801772Sjl139090 
24811772Sjl139090 		if (channel == OPL_CMU_CHANNEL)
24821772Sjl139090 			board_cfg->cfg_cmuch_probe_str = probe_string;
24831772Sjl139090 		else
24841772Sjl139090 			board_cfg->cfg_pcich_probe_str[channel][leaf]
24851772Sjl139090 			    = probe_string;
24861772Sjl139090 
24871772Sjl139090 		/*
24881772Sjl139090 		 * Compatible properties (if any) have been created,
24891772Sjl139090 		 * so bind driver.
24901772Sjl139090 		 */
24911772Sjl139090 		ndi_devi_enter(parent, &circ);
24921772Sjl139090 		ASSERT(i_ddi_node_state(leaf_node) <= DS_LINKED);
24931772Sjl139090 
24941772Sjl139090 		mutex_enter(&DEVI(leaf_node)->devi_lock);
24951772Sjl139090 		DEVI(leaf_node)->devi_flags &= ~DEVI_NO_BIND;
24961772Sjl139090 		mutex_exit(&DEVI(leaf_node)->devi_lock);
24971772Sjl139090 
24981772Sjl139090 		ndi_devi_exit(parent, circ);
24991772Sjl139090 
25005037Sjl139090 		if (ndi_devi_bind_driver(leaf_node, 0) != DDI_SUCCESS) {
25015037Sjl139090 			cmn_err(CE_WARN, "IKP: Unable to bind PCI leaf "
25025037Sjl139090 			    "(%d-%d-%d)", probe->pr_board, probe->pr_channel,
25035037Sjl139090 			    probe->pr_leaf);
25041772Sjl139090 		}
25051772Sjl139090 	}
25061772Sjl139090 
25071772Sjl139090 	if ((error != 0) && (channel == OPL_CMU_CHANNEL))
25081772Sjl139090 		return (-1);
25091772Sjl139090 
25101772Sjl139090 	return (0);
25111772Sjl139090 }
25121772Sjl139090 
25131772Sjl139090 static void
opl_init_leaves(int myboard)25141772Sjl139090 opl_init_leaves(int myboard)
25151772Sjl139090 {
25161772Sjl139090 	dev_info_t	*parent, *node;
25171772Sjl139090 	char		*name;
25181772Sjl139090 	int 		circ, ret;
25191772Sjl139090 	int		len, portid, board, channel, leaf;
25201772Sjl139090 	opl_board_cfg_t	*cfg;
25211772Sjl139090 
25221772Sjl139090 	parent = ddi_root_node();
25231772Sjl139090 
25241772Sjl139090 	/*
25251772Sjl139090 	 * Hold parent node busy to walk its child list
25261772Sjl139090 	 */
25271772Sjl139090 	ndi_devi_enter(parent, &circ);
25281772Sjl139090 
25295037Sjl139090 	for (node = ddi_get_child(parent); (node != NULL); node =
25305037Sjl139090 	    ddi_get_next_sibling(node)) {
25311772Sjl139090 
25321772Sjl139090 		ret = OPL_GET_PROP(string, node, "name", &name, &len);
25331772Sjl139090 		if (ret != DDI_PROP_SUCCESS) {
25341772Sjl139090 			/*
25351772Sjl139090 			 * The property does not exist for this node.
25361772Sjl139090 			 */
25371772Sjl139090 			continue;
25381772Sjl139090 		}
25391772Sjl139090 
25401772Sjl139090 		if (strncmp(name, OPL_PCI_LEAF_NODE, len) == 0) {
25411772Sjl139090 
25421772Sjl139090 			ret = OPL_GET_PROP(int, node, "portid", &portid, -1);
25431772Sjl139090 			if (ret == DDI_PROP_SUCCESS) {
25441772Sjl139090 
25451772Sjl139090 				ret = OPL_GET_PROP(int, node, "board#",
25461772Sjl139090 				    &board, -1);
25471772Sjl139090 				if ((ret != DDI_PROP_SUCCESS) ||
25483354Sjl139090 				    (board != myboard)) {
25493354Sjl139090 					kmem_free(name, len);
25501772Sjl139090 					continue;
25513354Sjl139090 				}
25521772Sjl139090 
25531772Sjl139090 				cfg = &opl_boards[board];
25541772Sjl139090 				channel = OPL_PORTID_TO_CHANNEL(portid);
25551772Sjl139090 				if (channel == OPL_CMU_CHANNEL) {
25561772Sjl139090 
25571772Sjl139090 					if (cfg->cfg_cmuch_handle != NULL)
25581772Sjl139090 						cfg->cfg_cmuch_leaf = node;
25591772Sjl139090 
25601772Sjl139090 				} else {
25611772Sjl139090 
25621772Sjl139090 					leaf = OPL_PORTID_TO_LEAF(portid);
25635037Sjl139090 					if (cfg->cfg_pcich_handle[
25645037Sjl139090 					    channel][leaf] != NULL)
25655037Sjl139090 						cfg->cfg_pcich_leaf[
25665037Sjl139090 						    channel][leaf] = node;
25671772Sjl139090 				}
25681772Sjl139090 			}
25691772Sjl139090 		}
25701772Sjl139090 
25711772Sjl139090 		kmem_free(name, len);
25721772Sjl139090 		if (ret != DDI_PROP_SUCCESS)
25731772Sjl139090 			break;
25741772Sjl139090 	}
25751772Sjl139090 
25761772Sjl139090 	ndi_devi_exit(parent, circ);
25771772Sjl139090 }
25781772Sjl139090 
25791772Sjl139090 /*
25801772Sjl139090  * Create "pci" node and hierarchy for the Oberon channels and the
25811772Sjl139090  * CMU channel.
25821772Sjl139090  */
25831772Sjl139090 /*ARGSUSED*/
25841772Sjl139090 static int
opl_probe_io(opl_probe_t * probe)25851772Sjl139090 opl_probe_io(opl_probe_t *probe)
25861772Sjl139090 {
25871772Sjl139090 
25881772Sjl139090 	int		i, j;
25891772Sjl139090 	hwd_pci_ch_t	*channels;
25901772Sjl139090 
25911772Sjl139090 	if (HWD_STATUS_OK(probe->pr_sb->sb_cmu.cmu_ch.chan_status)) {
25921772Sjl139090 
25931772Sjl139090 		probe->pr_channel = HWD_CMU_CHANNEL;
25941772Sjl139090 		probe->pr_channel_status =
25951772Sjl139090 		    probe->pr_sb->sb_cmu.cmu_ch.chan_status;
25961772Sjl139090 		probe->pr_leaf = 0;
25971772Sjl139090 		probe->pr_leaf_status = probe->pr_channel_status;
25981772Sjl139090 
25991772Sjl139090 		if (opl_probe_leaf(probe) != 0)
26001772Sjl139090 			return (-1);
26011772Sjl139090 	}
26021772Sjl139090 
26031772Sjl139090 	channels = &probe->pr_sb->sb_pci_ch[0];
26041772Sjl139090 
26051772Sjl139090 	for (i = 0; i < HWD_PCI_CHANNELS_PER_SB; i++) {
26061772Sjl139090 
26071772Sjl139090 		if (!HWD_STATUS_OK(channels[i].pci_status))
26081772Sjl139090 			continue;
26091772Sjl139090 
26101772Sjl139090 		probe->pr_channel = i;
26111772Sjl139090 		probe->pr_channel_status = channels[i].pci_status;
26121772Sjl139090 
26131772Sjl139090 		for (j = 0; j < HWD_LEAVES_PER_PCI_CHANNEL; j++) {
26141772Sjl139090 
26151772Sjl139090 			probe->pr_leaf = j;
26161772Sjl139090 			probe->pr_leaf_status =
26175037Sjl139090 			    channels[i].pci_leaf[j].leaf_status;
26181772Sjl139090 
26191772Sjl139090 			if (!HWD_STATUS_OK(probe->pr_leaf_status))
26201772Sjl139090 				continue;
26211772Sjl139090 
26221772Sjl139090 			(void) opl_probe_leaf(probe);
26231772Sjl139090 		}
26241772Sjl139090 	}
26251772Sjl139090 	opl_init_leaves(probe->pr_board);
26261772Sjl139090 	return (0);
26271772Sjl139090 }
26281772Sjl139090 
26291772Sjl139090 /*
26301772Sjl139090  * Perform the probe in the following order:
26311772Sjl139090  *
26321772Sjl139090  *	processors
26331772Sjl139090  *	memory
26341772Sjl139090  *	IO
26351772Sjl139090  *
26361772Sjl139090  * Each probe function returns 0 on sucess and a non-zero value on failure.
26371772Sjl139090  * What is a failure is determined by the implementor of the probe function.
26381772Sjl139090  * For example, while probing CPUs, any error encountered during probe
26391772Sjl139090  * is considered a failure and causes the whole probe operation to fail.
26401772Sjl139090  * However, for I/O, an error encountered while probing one device
26411772Sjl139090  * should not prevent other devices from being probed. It should not cause
26421772Sjl139090  * the whole probe operation to fail.
26431772Sjl139090  */
26441772Sjl139090 int
opl_probe_sb(int board,unsigned * cpu_impl)26455037Sjl139090 opl_probe_sb(int board, unsigned *cpu_impl)
26461772Sjl139090 {
26471772Sjl139090 	opl_probe_t	*probe;
26481772Sjl139090 	int		ret;
26491772Sjl139090 
26501772Sjl139090 	if ((board < 0) || (board >= HWD_SBS_PER_DOMAIN))
26511772Sjl139090 		return (-1);
26521772Sjl139090 
26531772Sjl139090 	ASSERT(opl_cfg_inited != 0);
26541772Sjl139090 
26551772Sjl139090 	/*
26561772Sjl139090 	 * If the previous probe failed and left a partially configured
26571772Sjl139090 	 * board, we need to unprobe the board and start with a clean slate.
26581772Sjl139090 	 */
26591772Sjl139090 	if ((opl_boards[board].cfg_hwd != NULL) &&
26601772Sjl139090 	    (opl_unprobe_sb(board) != 0))
26611772Sjl139090 		return (-1);
26621772Sjl139090 
26631772Sjl139090 	ret = 0;
26641772Sjl139090 
26651772Sjl139090 	probe = kmem_zalloc(sizeof (opl_probe_t), KM_SLEEP);
26661772Sjl139090 	probe->pr_board = board;
26671772Sjl139090 
26681772Sjl139090 	if ((opl_probe_init(probe) != 0) ||
26691772Sjl139090 
26701772Sjl139090 	    (opl_probe_cpu_chips(probe) != 0) ||
26711772Sjl139090 
26721772Sjl139090 	    (opl_probe_memory(probe) != 0) ||
26731772Sjl139090 
26741772Sjl139090 	    (opl_probe_io(probe) != 0)) {
26751772Sjl139090 
26761772Sjl139090 		/*
26771772Sjl139090 		 * Probe failed. Perform cleanup.
26781772Sjl139090 		 */
26791772Sjl139090 		(void) opl_unprobe_sb(board);
26801772Sjl139090 		ret = -1;
26811772Sjl139090 	}
26821772Sjl139090 
26835037Sjl139090 	*cpu_impl = probe->pr_cpu_impl;
26845037Sjl139090 
26851772Sjl139090 	kmem_free(probe, sizeof (opl_probe_t));
26861772Sjl139090 
26871772Sjl139090 	return (ret);
26881772Sjl139090 }
26891772Sjl139090 
26901772Sjl139090 /*
26911772Sjl139090  * This unprobing also includes CMU-CH.
26921772Sjl139090  */
26931772Sjl139090 /*ARGSUSED*/
26941772Sjl139090 static int
opl_unprobe_io(int board)26951772Sjl139090 opl_unprobe_io(int board)
26961772Sjl139090 {
26971772Sjl139090 	int		i, j, ret;
26981772Sjl139090 	opl_board_cfg_t	*board_cfg;
26991772Sjl139090 	dev_info_t	**node;
27001772Sjl139090 	fco_handle_t	*hand;
27011772Sjl139090 	char		**probe_str;
27021772Sjl139090 
27031772Sjl139090 	board_cfg = &opl_boards[board];
27041772Sjl139090 
27051772Sjl139090 	for (i = 0; i < HWD_PCI_CHANNELS_PER_SB; i++) {
27061772Sjl139090 
27071772Sjl139090 		for (j = 0; j < HWD_LEAVES_PER_PCI_CHANNEL; j++) {
27081772Sjl139090 
27091772Sjl139090 			node = &board_cfg->cfg_pcich_leaf[i][j];
27101772Sjl139090 			hand = &board_cfg->cfg_pcich_handle[i][j];
27111772Sjl139090 			probe_str = &board_cfg->cfg_pcich_probe_str[i][j];
27121772Sjl139090 
27131772Sjl139090 			if (*node == NULL)
27141772Sjl139090 				continue;
27151772Sjl139090 
27161772Sjl139090 			if (*hand != NULL) {
27171772Sjl139090 				opl_fc_ops_free_handle(*hand);
27181772Sjl139090 				*hand = NULL;
27191772Sjl139090 			}
27201772Sjl139090 
27211772Sjl139090 			if (*probe_str != NULL) {
27221772Sjl139090 				kmem_free(*probe_str, PROBE_STR_SIZE);
27231772Sjl139090 				*probe_str = NULL;
27241772Sjl139090 			}
27251772Sjl139090 
27261772Sjl139090 			ret = opl_destroy_node(*node);
27271772Sjl139090 			if (ret != 0) {
27281772Sjl139090 
27295037Sjl139090 				cmn_err(CE_WARN, "IKP: destroy pci (%d-%d-%d) "
27305037Sjl139090 				    "failed", board, i, j);
27311772Sjl139090 				return (-1);
27321772Sjl139090 			}
27331772Sjl139090 
27341772Sjl139090 			*node = NULL;
27351772Sjl139090 
27361772Sjl139090 		}
27371772Sjl139090 	}
27381772Sjl139090 
27391772Sjl139090 	node = &board_cfg->cfg_cmuch_leaf;
27401772Sjl139090 	hand = &board_cfg->cfg_cmuch_handle;
27411772Sjl139090 	probe_str = &board_cfg->cfg_cmuch_probe_str;
27421772Sjl139090 
27431772Sjl139090 	if (*node == NULL)
27441772Sjl139090 		return (0);
27451772Sjl139090 
27461772Sjl139090 	if (*hand != NULL) {
27471772Sjl139090 		opl_fc_ops_free_handle(*hand);
27481772Sjl139090 		*hand = NULL;
27491772Sjl139090 	}
27501772Sjl139090 
27511772Sjl139090 	if (*probe_str != NULL) {
27521772Sjl139090 		kmem_free(*probe_str, PROBE_STR_SIZE);
27531772Sjl139090 		*probe_str = NULL;
27541772Sjl139090 	}
27551772Sjl139090 
27561772Sjl139090 	if (opl_destroy_node(*node) != 0) {
27571772Sjl139090 
27585037Sjl139090 		cmn_err(CE_WARN, "IKP: destroy pci (%d-%d-%d) failed", board,
27595037Sjl139090 		    OPL_CMU_CHANNEL, 0);
27601772Sjl139090 		return (-1);
27611772Sjl139090 	}
27621772Sjl139090 
27631772Sjl139090 	*node = NULL;
27641772Sjl139090 
27651772Sjl139090 	return (0);
27661772Sjl139090 }
27671772Sjl139090 
27681772Sjl139090 /*
27691772Sjl139090  * Destroy the "pseudo-mc" node for a board.
27701772Sjl139090  */
27711772Sjl139090 static int
opl_unprobe_memory(int board)27721772Sjl139090 opl_unprobe_memory(int board)
27731772Sjl139090 {
27741772Sjl139090 	opl_board_cfg_t	*board_cfg;
27751772Sjl139090 
27761772Sjl139090 	board_cfg = &opl_boards[board];
27771772Sjl139090 
27781772Sjl139090 	if (board_cfg->cfg_pseudo_mc == NULL)
27791772Sjl139090 		return (0);
27801772Sjl139090 
27811772Sjl139090 	if (opl_destroy_node(board_cfg->cfg_pseudo_mc) != 0) {
27821772Sjl139090 
27831772Sjl139090 		cmn_err(CE_WARN, "IKP: destroy pseudo-mc (%d) failed", board);
27841772Sjl139090 		return (-1);
27851772Sjl139090 	}
27861772Sjl139090 
27871772Sjl139090 	board_cfg->cfg_pseudo_mc = NULL;
27881772Sjl139090 
27891772Sjl139090 	return (0);
27901772Sjl139090 }
27911772Sjl139090 
27921772Sjl139090 /*
27931772Sjl139090  * Destroy the "cmp" nodes for a board. This also destroys the "core"
27941772Sjl139090  * and "cpu" nodes below the "cmp" nodes.
27951772Sjl139090  */
27961772Sjl139090 static int
opl_unprobe_processors(int board)27971772Sjl139090 opl_unprobe_processors(int board)
27981772Sjl139090 {
27991772Sjl139090 	int		i;
28001772Sjl139090 	dev_info_t	**cfg_cpu_chips;
28011772Sjl139090 
28021772Sjl139090 	cfg_cpu_chips = opl_boards[board].cfg_cpu_chips;
28031772Sjl139090 
28041772Sjl139090 	for (i = 0; i < HWD_CPU_CHIPS_PER_CMU; i++) {
28051772Sjl139090 
28061772Sjl139090 		if (cfg_cpu_chips[i] == NULL)
28071772Sjl139090 			continue;
28081772Sjl139090 
28091772Sjl139090 		if (opl_destroy_node(cfg_cpu_chips[i]) != 0) {
28101772Sjl139090 
28115037Sjl139090 			cmn_err(CE_WARN, "IKP: destroy chip (%d-%d) failed",
28125037Sjl139090 			    board, i);
28131772Sjl139090 			return (-1);
28141772Sjl139090 		}
28151772Sjl139090 
28161772Sjl139090 		cfg_cpu_chips[i] = NULL;
28171772Sjl139090 	}
28181772Sjl139090 
28191772Sjl139090 	return (0);
28201772Sjl139090 }
28211772Sjl139090 
28221772Sjl139090 /*
28231772Sjl139090  * Perform the unprobe in the following order:
28241772Sjl139090  *
28251772Sjl139090  *	IO
28261772Sjl139090  *	memory
28271772Sjl139090  *	processors
28281772Sjl139090  */
28291772Sjl139090 int
opl_unprobe_sb(int board)28301772Sjl139090 opl_unprobe_sb(int board)
28311772Sjl139090 {
28321772Sjl139090 	if ((board < 0) || (board >= HWD_SBS_PER_DOMAIN))
28331772Sjl139090 		return (-1);
28341772Sjl139090 
28351772Sjl139090 	ASSERT(opl_cfg_inited != 0);
28361772Sjl139090 
28371772Sjl139090 	if ((opl_unprobe_io(board) != 0) ||
28381772Sjl139090 
28391772Sjl139090 	    (opl_unprobe_memory(board) != 0) ||
28401772Sjl139090 
28411772Sjl139090 	    (opl_unprobe_processors(board) != 0))
28421772Sjl139090 
28431772Sjl139090 		return (-1);
28441772Sjl139090 
28451772Sjl139090 	if (opl_boards[board].cfg_hwd != NULL) {
28461772Sjl139090 #ifdef UCTEST
28471772Sjl139090 		size_t			size = 0xA000;
28481772Sjl139090 #endif
28491772Sjl139090 		/* Release the memory for the HWD */
28501772Sjl139090 		void *hwdp = opl_boards[board].cfg_hwd;
28511772Sjl139090 		opl_boards[board].cfg_hwd = NULL;
28521772Sjl139090 #ifdef UCTEST
28531772Sjl139090 		hwdp = (void *)((char *)hwdp - 0x1000);
28541772Sjl139090 		hat_unload(kas.a_hat, hwdp, size, HAT_UNLOAD_UNLOCK);
28551772Sjl139090 		vmem_free(heap_arena, hwdp, size);
28561772Sjl139090 #else
28571772Sjl139090 		kmem_free(hwdp, HWD_DATA_SIZE);
28581772Sjl139090 #endif
28591772Sjl139090 	}
28601772Sjl139090 	return (0);
28611772Sjl139090 }
28621772Sjl139090 
28631772Sjl139090 /*
28641772Sjl139090  * For MAC patrol support, we need to update the PA-related properties
28651772Sjl139090  * when there is a copy-rename event.  This should be called after the
28661772Sjl139090  * physical copy and rename has been done by DR, and before the MAC
28671772Sjl139090  * patrol is restarted.
28681772Sjl139090  */
28691772Sjl139090 int
oplcfg_pa_swap(int from,int to)28701772Sjl139090 oplcfg_pa_swap(int from, int to)
28711772Sjl139090 {
28721772Sjl139090 	dev_info_t *from_node = opl_boards[from].cfg_pseudo_mc;
28731772Sjl139090 	dev_info_t *to_node = opl_boards[to].cfg_pseudo_mc;
28741772Sjl139090 	opl_range_t *rangef, *ranget;
28751772Sjl139090 	int elems;
28761772Sjl139090 	int ret;
28771772Sjl139090 
28781772Sjl139090 	if ((OPL_GET_PROP_ARRAY(int, from_node, "sb-mem-ranges", rangef,
28791772Sjl139090 	    elems) != DDI_SUCCESS) || (elems != 4)) {
28801772Sjl139090 		/* XXX -- bad news */
28811772Sjl139090 		return (-1);
28821772Sjl139090 	}
28831772Sjl139090 	if ((OPL_GET_PROP_ARRAY(int, to_node, "sb-mem-ranges", ranget,
28841772Sjl139090 	    elems) != DDI_SUCCESS) || (elems != 4)) {
28851772Sjl139090 		/* XXX -- bad news */
28861772Sjl139090 		return (-1);
28871772Sjl139090 	}
28881772Sjl139090 	OPL_UPDATE_PROP_ARRAY(int, from_node, "sb-mem-ranges", (int *)ranget,
28891772Sjl139090 	    4);
28901772Sjl139090 	OPL_UPDATE_PROP_ARRAY(int, to_node, "sb-mem-ranges", (int *)rangef,
28911772Sjl139090 	    4);
28921772Sjl139090 
28931772Sjl139090 	OPL_FREE_PROP(ranget);
28941772Sjl139090 	OPL_FREE_PROP(rangef);
28951772Sjl139090 
28961772Sjl139090 	return (0);
28971772Sjl139090 }
2898