xref: /onnv-gate/usr/src/uts/sun4u/serengeti/io/sgsbbc.c (revision 7656:2621e50fdf4a)
11708Sstevel /*
21708Sstevel  * CDDL HEADER START
31708Sstevel  *
41708Sstevel  * The contents of this file are subject to the terms of the
51708Sstevel  * Common Development and Distribution License (the "License").
61708Sstevel  * You may not use this file except in compliance with the License.
71708Sstevel  *
81708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel  * or http://www.opensolaris.org/os/licensing.
101708Sstevel  * See the License for the specific language governing permissions
111708Sstevel  * and limitations under the License.
121708Sstevel  *
131708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel  *
191708Sstevel  * CDDL HEADER END
201708Sstevel  */
211708Sstevel 
221708Sstevel /*
23*7656SSherry.Moore@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241708Sstevel  * Use is subject to license terms.
251708Sstevel  */
261708Sstevel 
271708Sstevel 
281708Sstevel /*
291708Sstevel  * PCI SBBC Device Driver that provides interfaces into
301708Sstevel  * EPLD and IO-SRAM
311708Sstevel  *
321708Sstevel  */
331708Sstevel #include <sys/types.h>
341708Sstevel #include <sys/param.h>
351708Sstevel #include <sys/errno.h>
361708Sstevel #include <sys/file.h>
371708Sstevel #include <sys/cmn_err.h>
381708Sstevel #include <sys/stropts.h>
391708Sstevel #include <sys/kmem.h>
401708Sstevel #include <sys/sunndi.h>
411708Sstevel #include <sys/conf.h>		/* req. by dev_ops flags MTSAFE etc. */
421708Sstevel #include <sys/modctl.h>		/* for modldrv */
431708Sstevel #include <sys/promif.h>
441708Sstevel #include <sys/stat.h>
451708Sstevel #include <sys/ddi.h>
461708Sstevel 
471708Sstevel #include <sys/serengeti.h>
481708Sstevel #include <sys/sgsbbc_priv.h>
491708Sstevel #include <sys/sgsbbc_iosram_priv.h>
501708Sstevel #include <sys/sgsbbc_mailbox_priv.h>
511708Sstevel 
521708Sstevel #ifdef DEBUG
531708Sstevel /* debug flag */
541708Sstevel uint_t sgsbbc_debug = 0;
551708Sstevel #endif /* DEBUG */
561708Sstevel 
571708Sstevel /* driver entry point fn definitions */
581708Sstevel static int	sbbc_attach(dev_info_t *, ddi_attach_cmd_t);
591708Sstevel static int	sbbc_detach(dev_info_t *, ddi_detach_cmd_t);
601708Sstevel 
611708Sstevel /*
621708Sstevel  * SBBC soft state hook
631708Sstevel  */
641708Sstevel static void    *sbbcp;
651708Sstevel 
661708Sstevel /*
671708Sstevel  * Chosen IOSRAM
681708Sstevel  */
691708Sstevel struct chosen_iosram *master_iosram = NULL;
701708Sstevel 
711708Sstevel /*
721708Sstevel  * define new iosram's sbbc and liked list of sbbc.
731708Sstevel  */
741708Sstevel struct sbbc_softstate *sgsbbc_instances = NULL;
751708Sstevel 
761708Sstevel /*
771708Sstevel  * At attach time, check if the device is the 'chosen' node
781708Sstevel  * if it is, set up the IOSRAM Solaris<->SC Comm tunnel
791708Sstevel  * Its like 'Highlander' - there can be only one !
801708Sstevel  */
811708Sstevel static int	master_chosen = FALSE;
821708Sstevel kmutex_t	chosen_lock;
831708Sstevel 
841708Sstevel /*
851708Sstevel  * Local variable to save intr_in_enabled when the driver is suspended
861708Sstevel  */
871708Sstevel static uint32_t	intr_in_enabled;
881708Sstevel 
891708Sstevel /*
901708Sstevel  * Local declarations
911708Sstevel  */
921708Sstevel static void	softsp_init(sbbc_softstate_t *, dev_info_t *);
931708Sstevel static void	sbbc_chosen_init(sbbc_softstate_t *);
941708Sstevel static void	sbbc_add_instance(sbbc_softstate_t *);
951708Sstevel static void	sbbc_remove_instance(sbbc_softstate_t *);
961708Sstevel static int	sbbc_find_dip(dev_info_t *, void *);
971708Sstevel static void	sbbc_unmap_regs(sbbc_softstate_t *);
981708Sstevel 
991708Sstevel /*
1001708Sstevel  * ops stuff.
1011708Sstevel  */
1021708Sstevel static struct cb_ops sbbc_cb_ops = {
1031708Sstevel 	nodev,					/* cb_open */
1041708Sstevel 	nodev,					/* cb_close */
1051708Sstevel 	nodev,					/* cb_strategy */
1061708Sstevel 	nodev,					/* cb_print */
1071708Sstevel 	nodev,					/* cb_dump */
1081708Sstevel 	nodev,					/* cb_read */
1091708Sstevel 	nodev,					/* cb_write */
1101708Sstevel 	nodev,					/* cb_ioctl */
1111708Sstevel 	nodev,					/* cb_devmap */
1121708Sstevel 	nodev,					/* cb_mmap */
1131708Sstevel 	nodev,					/* cb_segmap */
1141708Sstevel 	nochpoll,				/* cb_chpoll */
1151708Sstevel 	ddi_prop_op,				/* cb_prop_op */
1161708Sstevel 	NULL,					/* cb_stream */
1171708Sstevel 	D_NEW | D_MP				/* cb_flag */
1181708Sstevel };
1191708Sstevel 
1201708Sstevel /*
1211708Sstevel  * Declare ops vectors for auto configuration.
1221708Sstevel  */
1231708Sstevel struct dev_ops  sbbc_ops = {
1241708Sstevel 	DEVO_REV,		/* devo_rev */
1251708Sstevel 	0,			/* devo_refcnt */
1261708Sstevel 	ddi_getinfo_1to1,	/* devo_getinfo */
1271708Sstevel 	nulldev,		/* devo_identify */
1281708Sstevel 	nulldev,		/* devo_probe */
1291708Sstevel 	sbbc_attach,		/* devo_attach */
1301708Sstevel 	sbbc_detach,		/* devo_detach */
1311708Sstevel 	nodev,			/* devo_reset */
1321708Sstevel 	&sbbc_cb_ops,		/* devo_cb_ops */
1331708Sstevel 	(struct bus_ops *)NULL,	/* devo_bus_ops */
134*7656SSherry.Moore@Sun.COM 	nulldev,		/* devo_power */
135*7656SSherry.Moore@Sun.COM 	ddi_quiesce_not_supported,	/* devo_quiesce */
1361708Sstevel };
1371708Sstevel 
1381708Sstevel /*
1391708Sstevel  * Loadable module support.
1401708Sstevel  */
1411708Sstevel extern struct mod_ops mod_driverops;
1421708Sstevel 
1431708Sstevel static struct modldrv modldrv = {
1441708Sstevel 	&mod_driverops,		/* type of module - driver */
145*7656SSherry.Moore@Sun.COM 	"PCI SBBC",
1461708Sstevel 	&sbbc_ops,
1471708Sstevel };
1481708Sstevel 
1491708Sstevel static struct modlinkage modlinkage = {
1501708Sstevel 	MODREV_1,
1511708Sstevel 	(void *)&modldrv,
1521708Sstevel 	NULL
1531708Sstevel };
1541708Sstevel 
1551708Sstevel int
_init(void)1561708Sstevel _init(void)
1571708Sstevel {
1581708Sstevel 	int    error;
1591708Sstevel 
1601708Sstevel 	if ((error = ddi_soft_state_init(&sbbcp,
161*7656SSherry.Moore@Sun.COM 	    sizeof (sbbc_softstate_t), 1)) != 0)
1621708Sstevel 		return (error);
1631708Sstevel 
1641708Sstevel 	if ((error = mod_install(&modlinkage)) != 0) {
1651708Sstevel 		ddi_soft_state_fini(&sbbcp);
1661708Sstevel 		return (error);
1671708Sstevel 	}
1681708Sstevel 
1691708Sstevel 	/*
1701708Sstevel 	 * Initialise the global 'chosen' IOSRAM mutex
1711708Sstevel 	 */
1721708Sstevel 	mutex_init(&chosen_lock, NULL, MUTEX_DEFAULT, NULL);
1731708Sstevel 
1741708Sstevel 	/*
1751708Sstevel 	 * Initialise the iosram driver
1761708Sstevel 	 */
1771708Sstevel 	iosram_init();
1781708Sstevel 
1791708Sstevel 	/*
1801708Sstevel 	 * Initialize the mailbox
1811708Sstevel 	 */
1821708Sstevel 	sbbc_mbox_init();
1831708Sstevel 
1841708Sstevel 	return (error);
1851708Sstevel 
1861708Sstevel }
1871708Sstevel 
1881708Sstevel int
_fini(void)1891708Sstevel _fini(void)
1901708Sstevel {
1911708Sstevel 	int    error;
1921708Sstevel 
1931708Sstevel 	if ((error = mod_remove(&modlinkage)) == 0)
1941708Sstevel 		ddi_soft_state_fini(&sbbcp);
1951708Sstevel 
1961708Sstevel 	master_chosen = FALSE;
1971708Sstevel 
1981708Sstevel 	mutex_destroy(&chosen_lock);
1991708Sstevel 
2001708Sstevel 	/*
2011708Sstevel 	 * remove the mailbox
2021708Sstevel 	 */
2031708Sstevel 	sbbc_mbox_fini();
2041708Sstevel 
2051708Sstevel 	/*
2061708Sstevel 	 * remove the iosram driver
2071708Sstevel 	 */
2081708Sstevel 	iosram_fini();
2091708Sstevel 
2101708Sstevel 	return (error);
2111708Sstevel }
2121708Sstevel 
2131708Sstevel int
_info(struct modinfo * modinfop)2141708Sstevel _info(struct modinfo *modinfop)
2151708Sstevel {
2161708Sstevel 	return (mod_info(&modlinkage, modinfop));
2171708Sstevel }
2181708Sstevel 
2191708Sstevel static int
sbbc_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)2201708Sstevel sbbc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
2211708Sstevel {
2221708Sstevel 	int			instance;
2231708Sstevel 	sbbc_softstate_t	*softsp;
2241708Sstevel 	uint32_t		*pci_intr_enable_reg;
2251708Sstevel 	int			len;
2261708Sstevel #ifdef	DEBUG
2271708Sstevel 	char			name[8];
2281708Sstevel #endif	/* DEBUG */
2291708Sstevel 
2301708Sstevel 	instance = ddi_get_instance(devi);
2311708Sstevel 
2321708Sstevel 	switch (cmd) {
2331708Sstevel 	case DDI_ATTACH:
2341708Sstevel 
2351708Sstevel 		if (ddi_soft_state_zalloc(sbbcp, instance) != 0)
2361708Sstevel 			return (DDI_FAILURE);
2371708Sstevel 
2381708Sstevel 		softsp = ddi_get_soft_state(sbbcp, instance);
2391708Sstevel 		softsp->sbbc_instance = instance;
2401708Sstevel 
2411708Sstevel 		/*
2421708Sstevel 		 * Set the dip in the soft state
2431708Sstevel 		 * And get interrupt cookies and initialize the
2441708Sstevel 		 * per instance mutex.
2451708Sstevel 		 */
2461708Sstevel 		softsp_init(softsp, devi);
2471708Sstevel 
2481708Sstevel 
2491708Sstevel 		/*
2501708Sstevel 		 * Verify that an 'interrupts' property exists for
2511708Sstevel 		 * this device. If not, this instance will be ignored.
2521708Sstevel 		 */
2531708Sstevel 		if (ddi_getproplen(DDI_DEV_T_ANY, softsp->dip,
254*7656SSherry.Moore@Sun.COM 		    DDI_PROP_DONTPASS, "interrupts",
255*7656SSherry.Moore@Sun.COM 		    &len) != DDI_PROP_SUCCESS) {
2561708Sstevel 			SBBC_ERR1(CE_WARN, "No 'interrupts' property for the "
257*7656SSherry.Moore@Sun.COM 			    "SBBC instance %d\n", instance);
2581708Sstevel 			return (DDI_FAILURE);
2591708Sstevel 		}
2601708Sstevel 		/*
2611708Sstevel 		 * Add this instance to the sbbc chosen iosram list
2621708Sstevel 		 * so that it can be used for tunnel switch.
2631708Sstevel 		 */
2641708Sstevel 		mutex_enter(&chosen_lock);
2651708Sstevel 		softsp->sbbc_state = SBBC_STATE_INIT;
2661708Sstevel 		sbbc_add_instance(softsp);
2671708Sstevel 
2681708Sstevel 		/*
2691708Sstevel 		 * If this is the chosen IOSRAM and there is no master IOSRAM
2701708Sstevel 		 * yet, then let's set this instance as the master.
2711708Sstevel 		 * if there is a master alreay due to the previous tunnel switch
2721708Sstevel 		 * then keep as is even though this is the chosen.
2731708Sstevel 		 */
2741708Sstevel 		if (sgsbbc_iosram_is_chosen(softsp)) {
2751708Sstevel 			ASSERT(master_iosram);
2761708Sstevel 			softsp->iosram = master_iosram;
2771708Sstevel 			master_iosram->sgsbbc = softsp;
2781708Sstevel 
2791708Sstevel 			/* Do 'chosen' init only */
2801708Sstevel 			sbbc_chosen_init(softsp);
2811708Sstevel 		}
2821708Sstevel 
2831708Sstevel 		mutex_exit(&chosen_lock);
2841708Sstevel #ifdef	DEBUG
2851708Sstevel 		(void) sprintf(name, "sbbc%d", instance);
2861708Sstevel 
2871708Sstevel 		if (ddi_create_minor_node(devi, name, S_IFCHR, instance,
288*7656SSherry.Moore@Sun.COM 		    NULL, NULL) == DDI_FAILURE) {
2891708Sstevel 			mutex_destroy(&softsp->sbbc_lock);
2901708Sstevel 			ddi_remove_minor_node(devi, NULL);
2911708Sstevel 			ddi_soft_state_free(sbbcp, instance);
2921708Sstevel 			return (DDI_FAILURE);
2931708Sstevel 		}
2941708Sstevel #endif	/* DEBUG */
2951708Sstevel 
2961708Sstevel 		ddi_report_dev(devi);
2971708Sstevel 
2981708Sstevel 		return (DDI_SUCCESS);
2991708Sstevel 
3001708Sstevel 	case DDI_RESUME:
3011708Sstevel 
3021708Sstevel 		if (!(softsp = ddi_get_soft_state(sbbcp, instance)))
3031708Sstevel 			return (DDI_FAILURE);
3041708Sstevel 
3051708Sstevel 		mutex_enter(&softsp->sbbc_lock);
3061708Sstevel 		if ((softsp->suspended == TRUE) && (softsp->chosen == TRUE)) {
3071708Sstevel 			/*
3081708Sstevel 			 * Enable Interrupts now, turn on both INT#A lines
3091708Sstevel 			 */
3101708Sstevel 			pci_intr_enable_reg =  (uint32_t *)
311*7656SSherry.Moore@Sun.COM 			    ((char *)softsp->sbbc_regs +
312*7656SSherry.Moore@Sun.COM 			    SBBC_PCI_INT_ENABLE);
3131708Sstevel 
3141708Sstevel 			ddi_put32(softsp->sbbc_reg_handle1,
315*7656SSherry.Moore@Sun.COM 			    pci_intr_enable_reg,
316*7656SSherry.Moore@Sun.COM 			    (uint32_t)SBBC_PCI_ENABLE_INT_A);
3171708Sstevel 
3181708Sstevel 			/*
3191708Sstevel 			 * Reset intr_in_enabled to the original value
3201708Sstevel 			 * so the SC can send us interrupt.
3211708Sstevel 			 */
3221708Sstevel 			if (iosram_write(SBBC_SC_INTR_ENABLED_KEY,
323*7656SSherry.Moore@Sun.COM 			    0, (caddr_t)&intr_in_enabled,
324*7656SSherry.Moore@Sun.COM 			    sizeof (intr_in_enabled))) {
3251708Sstevel 
3261708Sstevel 				mutex_exit(&softsp->sbbc_lock);
3271708Sstevel 				return (DDI_FAILURE);
3281708Sstevel 			}
3291708Sstevel 		}
3301708Sstevel 		softsp->suspended = FALSE;
3311708Sstevel 
3321708Sstevel 		mutex_exit(&softsp->sbbc_lock);
3331708Sstevel 
3341708Sstevel 		return (DDI_SUCCESS);
3351708Sstevel 
3361708Sstevel 	default:
3371708Sstevel 		return (DDI_FAILURE);
3381708Sstevel 	}
3391708Sstevel }
3401708Sstevel 
3411708Sstevel static int
sbbc_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)3421708Sstevel sbbc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
3431708Sstevel {
3441708Sstevel 	sbbc_softstate_t	*softsp;
3451708Sstevel 	int			instance;
3461708Sstevel 	uint32_t		*pci_intr_enable_reg;
3471708Sstevel 	int			rc = DDI_SUCCESS;
3481708Sstevel 
3491708Sstevel 	instance = ddi_get_instance(devi);
3501708Sstevel 
3511708Sstevel 	if (!(softsp = ddi_get_soft_state(sbbcp, instance)))
3521708Sstevel 		return (DDI_FAILURE);
3531708Sstevel 
3541708Sstevel 	switch (cmd) {
3551708Sstevel 	case DDI_DETACH:
3561708Sstevel 		mutex_enter(&chosen_lock);
3571708Sstevel 		softsp->sbbc_state |= SBBC_STATE_DETACH;
3581708Sstevel 		mutex_exit(&chosen_lock);
3591708Sstevel 
3601708Sstevel 		/* only tunnel switch the instance with iosram chosen */
3611708Sstevel 		if (softsp->chosen == TRUE) {
3621708Sstevel 			if (sgsbbc_iosram_switchfrom(softsp) == DDI_FAILURE) {
3631708Sstevel 				SBBC_ERR(CE_WARN, "Cannot unconfigure: "
3641708Sstevel 				    "tunnel switch failed\n");
3651708Sstevel 				return (DDI_FAILURE);
3661708Sstevel 			}
3671708Sstevel 		}
3681708Sstevel 
3691708Sstevel 		/* Adjust linked list */
3701708Sstevel 		mutex_enter(&chosen_lock);
3711708Sstevel 		sbbc_remove_instance(softsp);
3721708Sstevel 		mutex_exit(&chosen_lock);
3731708Sstevel 
3741708Sstevel 		sbbc_unmap_regs(softsp);
3751708Sstevel 		mutex_destroy(&softsp->sbbc_lock);
3761708Sstevel 		ddi_soft_state_free(sbbcp, instance);
3771708Sstevel 
3781708Sstevel 		return (DDI_SUCCESS);
3791708Sstevel 
3801708Sstevel 	case DDI_SUSPEND:
3811708Sstevel 
3821708Sstevel 		mutex_enter(&softsp->sbbc_lock);
3831708Sstevel 
3841708Sstevel 		if ((softsp->suspended == FALSE) && (softsp->chosen == TRUE)) {
3851708Sstevel 			uint32_t	tmp_intr_enabled = 0;
3861708Sstevel 
3871708Sstevel 			/*
3881708Sstevel 			 * Disable Interrupts now, turn OFF both INT#A lines
3891708Sstevel 			 */
3901708Sstevel 			pci_intr_enable_reg =  (uint32_t *)
391*7656SSherry.Moore@Sun.COM 			    ((char *)softsp->sbbc_regs +
392*7656SSherry.Moore@Sun.COM 			    SBBC_PCI_INT_ENABLE);
3931708Sstevel 
3941708Sstevel 			ddi_put32(softsp->sbbc_reg_handle1,
395*7656SSherry.Moore@Sun.COM 			    pci_intr_enable_reg, 0);
3961708Sstevel 
3971708Sstevel 			/*
3981708Sstevel 			 * Set intr_in_enabled to 0 so the SC won't send
3991708Sstevel 			 * us interrupt.
4001708Sstevel 			 */
4011708Sstevel 			rc = iosram_read(SBBC_SC_INTR_ENABLED_KEY,
402*7656SSherry.Moore@Sun.COM 			    0, (caddr_t)&intr_in_enabled,
403*7656SSherry.Moore@Sun.COM 			    sizeof (intr_in_enabled));
4041708Sstevel 
4051708Sstevel 			if (rc) {
4061708Sstevel 				mutex_exit(&softsp->sbbc_lock);
4071708Sstevel 				return (DDI_FAILURE);
4081708Sstevel 			}
4091708Sstevel 
4101708Sstevel 			rc = iosram_write(SBBC_SC_INTR_ENABLED_KEY,
411*7656SSherry.Moore@Sun.COM 			    0, (caddr_t)&tmp_intr_enabled,
412*7656SSherry.Moore@Sun.COM 			    sizeof (tmp_intr_enabled));
4131708Sstevel 
4141708Sstevel 			if (rc) {
4151708Sstevel 				mutex_exit(&softsp->sbbc_lock);
4161708Sstevel 				return (DDI_FAILURE);
4171708Sstevel 			}
4181708Sstevel 		}
4191708Sstevel 		softsp->suspended = TRUE;
4201708Sstevel 
4211708Sstevel 		mutex_exit(&softsp->sbbc_lock);
4221708Sstevel 
4231708Sstevel 		return (DDI_SUCCESS);
4241708Sstevel 
4251708Sstevel 	default:
4261708Sstevel 		return (DDI_FAILURE);
4271708Sstevel 	}
4281708Sstevel 
4291708Sstevel }
4301708Sstevel 
4311708Sstevel static void
softsp_init(sbbc_softstate_t * softsp,dev_info_t * devi)4321708Sstevel softsp_init(sbbc_softstate_t *softsp, dev_info_t *devi)
4331708Sstevel {
4341708Sstevel 	softsp->dip = devi;
4351708Sstevel 
4361708Sstevel 	/*
4371708Sstevel 	 * XXXX
4381708Sstevel 	 * ddi_get_iblock_cookie() here because we need
4391708Sstevel 	 * to initialise the mutex regardless of whether
4401708Sstevel 	 * or not this SBBC will eventually
4411708Sstevel 	 * register an interrupt handler
4421708Sstevel 	 */
4431708Sstevel 
4441708Sstevel 	(void) ddi_get_iblock_cookie(devi, 0, &softsp->iblock);
4451708Sstevel 
4461708Sstevel 	mutex_init(&softsp->sbbc_lock, NULL, MUTEX_DRIVER,
447*7656SSherry.Moore@Sun.COM 	    (void *)softsp->iblock);
4481708Sstevel 
4491708Sstevel 	softsp->suspended = FALSE;
4501708Sstevel 	softsp->chosen = FALSE;
4511708Sstevel }
4521708Sstevel 
4531708Sstevel static int
sbbc_find_dip(dev_info_t * dip,void * arg)4541708Sstevel sbbc_find_dip(dev_info_t *dip, void *arg)
4551708Sstevel {
4561708Sstevel 	char		*node_name;
4571708Sstevel 	sbbc_find_dip_t	*dip_struct = (sbbc_find_dip_t *)arg;
4581708Sstevel 	char		status[OBP_MAXPROPNAME];
4591708Sstevel 
4601708Sstevel 	/*
4611708Sstevel 	 * Need to find a node named "bootbus-controller" that is neither
4621708Sstevel 	 * disabled nor failed.  If a node is not ok, there will be an
4631708Sstevel 	 * OBP status property.  Therefore, we will look for a node
4641708Sstevel 	 * without the status property.
4651708Sstevel 	 */
4661708Sstevel 	node_name = ddi_node_name(dip);
4671708Sstevel 	if (strcmp(node_name, "bootbus-controller") == 0 && DDI_CF2(dip) &&
468*7656SSherry.Moore@Sun.COM 	    (prom_getprop(ddi_get_nodeid(dip),
469*7656SSherry.Moore@Sun.COM 	    "status", (caddr_t)status) == -1) &&
470*7656SSherry.Moore@Sun.COM 	    (prom_getprop(ddi_get_nodeid(ddi_get_parent(dip)),
471*7656SSherry.Moore@Sun.COM 	    "status", (caddr_t)status) == -1)) {
4721708Sstevel 
4731708Sstevel 		if (dip != dip_struct->cur_dip) {
4741708Sstevel 			dip_struct->new_dip = (void *)dip;
4751708Sstevel 			return (DDI_WALK_TERMINATE);
4761708Sstevel 		}
4771708Sstevel 	}
4781708Sstevel 
4791708Sstevel 	return (DDI_WALK_CONTINUE);
4801708Sstevel }
4811708Sstevel 
4821708Sstevel /*
4831708Sstevel  * SBBC Interrupt Handler
4841708Sstevel  *
4851708Sstevel  * Check the SBBC Port Interrupt Status
4861708Sstevel  * register to verify that its our interrupt.
4871708Sstevel  * If yes, clear the register.
4881708Sstevel  *
4891708Sstevel  * Then read the 'interrupt reason' field from SRAM,
4901708Sstevel  * this triggers the appropriate soft_intr handler
4911708Sstevel  */
4921708Sstevel uint_t
sbbc_intr_handler(caddr_t arg)4931708Sstevel sbbc_intr_handler(caddr_t arg)
4941708Sstevel {
4951708Sstevel 	sbbc_softstate_t	*softsp = (sbbc_softstate_t *)arg;
4961708Sstevel 	uint32_t		*port_int_reg;
4971708Sstevel 	volatile uint32_t	port_int_status;
4981708Sstevel 	volatile uint32_t	intr_reason;
4991708Sstevel 	uint32_t		intr_enabled;
5001708Sstevel 	sbbc_intrs_t		*intr;
5011708Sstevel 	int			i, intr_mask;
5021708Sstevel 	struct tunnel_key	tunnel_key;
5031708Sstevel 	ddi_acc_handle_t	intr_in_handle;
5041708Sstevel 	uint32_t		*intr_in_reason;
5051708Sstevel 
5061708Sstevel 	if (softsp == (sbbc_softstate_t *)NULL) {
5071708Sstevel 
5081708Sstevel 		return (DDI_INTR_UNCLAIMED);
5091708Sstevel 	}
5101708Sstevel 
5111708Sstevel 	mutex_enter(&softsp->sbbc_lock);
5121708Sstevel 
5131708Sstevel 	if (softsp->port_int_regs == NULL) {
5141708Sstevel 		mutex_exit(&softsp->sbbc_lock);
5151708Sstevel 		return (DDI_INTR_UNCLAIMED);
5161708Sstevel 	}
5171708Sstevel 
5181708Sstevel 	/*
5191708Sstevel 	 * Normally if port_int_status is 0, we assume it is not
5201708Sstevel 	 * our interrupt.  However, we don't want to miss the
5211708Sstevel 	 * ones that come in during tunnel switch.  Therefore,
5221708Sstevel 	 * we always check the interrupt reason bits in IOSRAM
5231708Sstevel 	 * to be sure.
5241708Sstevel 	 */
5251708Sstevel 	port_int_reg = softsp->port_int_regs;
5261708Sstevel 
5271708Sstevel 	port_int_status = ddi_get32(softsp->sbbc_reg_handle1, port_int_reg);
5281708Sstevel 
5291708Sstevel 	/*
5301708Sstevel 	 * Generate a softint for each interrupt
5311708Sstevel 	 * bit set in the intr_in_reason field in SRAM
5321708Sstevel 	 * that has a corresponding bit set in the
5331708Sstevel 	 * intr_in_enabled field in SRAM
5341708Sstevel 	 */
5351708Sstevel 
5361708Sstevel 	if (iosram_read(SBBC_SC_INTR_ENABLED_KEY, 0,
537*7656SSherry.Moore@Sun.COM 	    (caddr_t)&intr_enabled, sizeof (intr_enabled))) {
5381708Sstevel 
5391708Sstevel 		goto intr_handler_exit;
5401708Sstevel 	}
5411708Sstevel 
5421708Sstevel 	tunnel_key = master_iosram->tunnel->tunnel_keys[SBBC_SC_INTR_KEY];
5431708Sstevel 	intr_in_reason = (uint32_t *)tunnel_key.base;
5441708Sstevel 	intr_in_handle = tunnel_key.reg_handle;
5451708Sstevel 
5461708Sstevel 	intr_reason = ddi_get32(intr_in_handle, intr_in_reason);
5471708Sstevel 
5481708Sstevel 	SGSBBC_DBG_INTR(CE_CONT, "intr_reason = %x\n", intr_reason);
5491708Sstevel 
5501708Sstevel 	intr_reason &= intr_enabled;
5511708Sstevel 
5521708Sstevel 	for (i = 0; i < SBBC_MAX_INTRS; i++) {
5531708Sstevel 		intr_mask = (1 << i);
5541708Sstevel 		if (intr_reason & intr_mask) {
5551708Sstevel 			intr = &softsp->intr_hdlrs[i];
5561708Sstevel 			if ((intr != NULL) &&
557*7656SSherry.Moore@Sun.COM 			    (intr->sbbc_intr_id != 0)) {
5581708Sstevel 				/*
5591708Sstevel 				 * XXXX
5601708Sstevel 				 * The model we agree with a handler
5611708Sstevel 				 * is that they run until they have
5621708Sstevel 				 * exhausted all work. To avoid
5631708Sstevel 				 * triggering them again, they pass
5641708Sstevel 				 * a state flag and lock when registering.
5651708Sstevel 				 * We check the flag, if they are idle,
5661708Sstevel 				 * we trigger.
5671708Sstevel 				 * The interrupt handler should so
5681708Sstevel 				 *   intr_func()
5691708Sstevel 				 *	mutex_enter(sbbc_intr_lock);
5701708Sstevel 				 *	sbbc_intr_state = RUNNING;
5711708Sstevel 				 *	mutex_exit(sbbc_intr_lock);
5721708Sstevel 				 *	  ..........
5731708Sstevel 				 *	  ..........
5741708Sstevel 				 *	  ..........
5751708Sstevel 				 *	mutex_enter(sbbc_intr_lock);
5761708Sstevel 				 *	sbbc_intr_state = IDLE;
5771708Sstevel 				 *	mutex_exit(sbbc_intr_lock);
5781708Sstevel 				 *
5791708Sstevel 				 * XXXX
5801708Sstevel 				 */
5811708Sstevel 				mutex_enter(intr->sbbc_intr_lock);
5821708Sstevel 				if (*(intr->sbbc_intr_state) ==
583*7656SSherry.Moore@Sun.COM 				    SBBC_INTR_IDLE) {
5841708Sstevel 					mutex_exit(intr->sbbc_intr_lock);
5851708Sstevel 					ddi_trigger_softintr(
586*7656SSherry.Moore@Sun.COM 					    intr->sbbc_intr_id);
5871708Sstevel 				} else {
5881708Sstevel 					/*
5891708Sstevel 					 * The handler is running
5901708Sstevel 					 */
5911708Sstevel 					mutex_exit(intr->sbbc_intr_lock);
5921708Sstevel 				}
5931708Sstevel 				intr_reason &= ~intr_mask;
5941708Sstevel 				/*
5951708Sstevel 				 * Clear the corresponding reason bit in SRAM
5961708Sstevel 				 *
5971708Sstevel 				 * Since there is no interlocking between
5981708Sstevel 				 * Solaris and the SC when writing to SRAM,
5991708Sstevel 				 * it is possible for the SC to set another
6001708Sstevel 				 * bit in the interrupt reason field while
6011708Sstevel 				 * we are handling the current interrupt.
6021708Sstevel 				 * To minimize the window in which an
6031708Sstevel 				 * additional bit can be set, reading
6041708Sstevel 				 * and writing the interrupt reason
6051708Sstevel 				 * in SRAM must be as close as possible.
6061708Sstevel 				 */
6071708Sstevel 				ddi_put32(intr_in_handle, intr_in_reason,
608*7656SSherry.Moore@Sun.COM 				    ddi_get32(intr_in_handle,
609*7656SSherry.Moore@Sun.COM 				    intr_in_reason) & ~intr_mask);
6101708Sstevel 			}
6111708Sstevel 		}
6121708Sstevel 		if (intr_reason == 0)	/* No more interrupts to be processed */
6131708Sstevel 			break;
6141708Sstevel 	}
6151708Sstevel 
6161708Sstevel 	/*
6171708Sstevel 	 * Clear the Interrupt Status Register (RW1C)
6181708Sstevel 	 */
6191708Sstevel 	ddi_put32(softsp->sbbc_reg_handle1, port_int_reg, port_int_status);
6201708Sstevel 
6211708Sstevel 	port_int_status = ddi_get32(softsp->sbbc_reg_handle1, port_int_reg);
6221708Sstevel 
6231708Sstevel intr_handler_exit:
6241708Sstevel 
6251708Sstevel 	mutex_exit(&softsp->sbbc_lock);
6261708Sstevel 
6271708Sstevel 	return (DDI_INTR_CLAIMED);
6281708Sstevel 
6291708Sstevel }
6301708Sstevel 
6311708Sstevel /*
6321708Sstevel  * If we don't already have a master SBBC selected,
6331708Sstevel  * get the <sbbc> property from the /chosen node. If
6341708Sstevel  * the pathname matches, this is the master SBBC and
6351708Sstevel  * we set up the console/TOD SRAM mapping here.
6361708Sstevel  */
6371708Sstevel static void
sbbc_chosen_init(sbbc_softstate_t * softsp)6381708Sstevel sbbc_chosen_init(sbbc_softstate_t *softsp)
6391708Sstevel {
6401708Sstevel 	char		master_sbbc[MAXNAMELEN];
6411708Sstevel 	char		pn[MAXNAMELEN];
6421708Sstevel 	int		nodeid, len;
6431708Sstevel 	pnode_t		dnode;
6441708Sstevel 
6451708Sstevel 	if (master_chosen != FALSE) {
6461708Sstevel 		/*
6471708Sstevel 		 * We've got one already
6481708Sstevel 		 */
6491708Sstevel 		return;
6501708Sstevel 	}
6511708Sstevel 
6521708Sstevel 	/*
6531708Sstevel 	 * Get /chosen node info. prom interface will handle errors.
6541708Sstevel 	 */
6551708Sstevel 	dnode = prom_chosennode();
6561708Sstevel 
6571708Sstevel 	/*
6581708Sstevel 	 * Look for the "iosram" property on the chosen node with a prom
6591708Sstevel 	 * interface as ddi_find_devinfo() couldn't be used (calls
6601708Sstevel 	 * ddi_walk_devs() that creates one extra lock on the device tree).
6611708Sstevel 	 */
6621708Sstevel 	if (prom_getprop(dnode, IOSRAM_CHOSEN_PROP, (caddr_t)&nodeid) <= 0) {
6631708Sstevel 		/*
6641708Sstevel 		 * No I/O Board SBBC set up as console, what to do ?
6651708Sstevel 		 */
6661708Sstevel 		SBBC_ERR(CE_PANIC, "No SBBC found for Console/TOD \n");
6671708Sstevel 	}
6681708Sstevel 
6691708Sstevel 	if (prom_getprop(dnode, IOSRAM_TOC_PROP,
6701708Sstevel 	    (caddr_t)&softsp->sram_toc) <= 0) {
6711708Sstevel 		/*
6721708Sstevel 		 * SRAM TOC Offset defaults to 0
6731708Sstevel 		 */
6741708Sstevel 		SBBC_ERR(CE_WARN, "No SBBC TOC Offset found\n");
6751708Sstevel 		softsp->sram_toc = 0;
6761708Sstevel 	}
6771708Sstevel 
6781708Sstevel 	/*
6791708Sstevel 	 * get the full OBP pathname of this node
6801708Sstevel 	 */
6811708Sstevel 	if (prom_phandle_to_path((phandle_t)nodeid, master_sbbc,
682*7656SSherry.Moore@Sun.COM 	    sizeof (master_sbbc)) < 0) {
6831708Sstevel 
6841708Sstevel 		SBBC_ERR1(CE_PANIC, "prom_phandle_to_path(%d) failed\n",
6851708Sstevel 		    nodeid);
6861708Sstevel 	}
6871708Sstevel 	SGSBBC_DBG_ALL("chosen pathname : %s\n", master_sbbc);
6881708Sstevel 	SGSBBC_DBG_ALL("device pathname : %s\n", ddi_pathname(softsp->dip, pn));
6891708Sstevel 	if (strcmp(master_sbbc, ddi_pathname(softsp->dip, pn)) == 0) {
6901708Sstevel 
6911708Sstevel 		/*
6921708Sstevel 		 * map in the SBBC regs
6931708Sstevel 		 */
6941708Sstevel 
6951708Sstevel 		if (sbbc_map_regs(softsp) != DDI_SUCCESS) {
6961708Sstevel 			SBBC_ERR(CE_PANIC, "Can't map the SBBC regs \n");
6971708Sstevel 		}
6981708Sstevel 		/*
6991708Sstevel 		 * Only the 'chosen' node is used for iosram_read()/_write()
7001708Sstevel 		 * Must initialise the tunnel before the console/tod
7011708Sstevel 		 *
7021708Sstevel 		 */
7031708Sstevel 		if (iosram_tunnel_init(softsp) == DDI_FAILURE) {
7041708Sstevel 			SBBC_ERR(CE_PANIC, "Can't create the SRAM <-> SC "
705*7656SSherry.Moore@Sun.COM 			    "comm. tunnel \n");
7061708Sstevel 		}
7071708Sstevel 
7081708Sstevel 		master_chosen = TRUE;
7091708Sstevel 
7101708Sstevel 		/*
7111708Sstevel 		 * Verify that an 'interrupts' property
7121708Sstevel 		 * exists for this device
7131708Sstevel 		 */
7141708Sstevel 
7151708Sstevel 		if (ddi_getproplen(DDI_DEV_T_ANY, softsp->dip,
716*7656SSherry.Moore@Sun.COM 		    DDI_PROP_DONTPASS, "interrupts",
717*7656SSherry.Moore@Sun.COM 		    &len) != DDI_PROP_SUCCESS) {
7181708Sstevel 
7191708Sstevel 			SBBC_ERR(CE_PANIC, "No 'interrupts' property for the "
720*7656SSherry.Moore@Sun.COM 			    "'chosen' SBBC \n");
7211708Sstevel 		}
7221708Sstevel 
7231708Sstevel 		/*
7241708Sstevel 		 * add the interrupt handler
7251708Sstevel 		 * NB
7261708Sstevel 		 * should this be a high-level interrupt ?
7271708Sstevel 		 * NB
7281708Sstevel 		 */
7291708Sstevel 		if (sbbc_add_intr(softsp) == DDI_FAILURE) {
7301708Sstevel 			SBBC_ERR(CE_PANIC, "Can't add interrupt handler for "
731*7656SSherry.Moore@Sun.COM 			    "'chosen' SBBC \n");
7321708Sstevel 		}
7331708Sstevel 
7341708Sstevel 		sbbc_enable_intr(softsp);
7351708Sstevel 
7361708Sstevel 		/*
7371708Sstevel 		 * Create the mailbox
7381708Sstevel 		 */
7391708Sstevel 		if (sbbc_mbox_create(softsp) != 0) {
7401708Sstevel 			cmn_err(CE_WARN, "No IOSRAM MailBox created!\n");
7411708Sstevel 		}
7421708Sstevel 
7431708Sstevel 	}
7441708Sstevel }
7451708Sstevel /*
7461708Sstevel  * sbbc_add_instance
7471708Sstevel  * Must be called to hold chosen_lock.
7481708Sstevel  */
7491708Sstevel static void
sbbc_add_instance(sbbc_softstate_t * softsp)7501708Sstevel sbbc_add_instance(sbbc_softstate_t *softsp)
7511708Sstevel {
7521708Sstevel #ifdef DEBUG
7531708Sstevel 	struct  sbbc_softstate *sp;
7541708Sstevel #endif
7551708Sstevel 
7561708Sstevel 	ASSERT(mutex_owned(&chosen_lock));
7571708Sstevel 
7581708Sstevel #if defined(DEBUG)
7591708Sstevel 	/* Verify that this instance is not in the list yet */
7601708Sstevel 	for (sp = sgsbbc_instances; sp != NULL; sp = sp->next) {
7611708Sstevel 		ASSERT(sp != softsp);
7621708Sstevel 	}
7631708Sstevel #endif
7641708Sstevel 
7651708Sstevel 	/*
7661708Sstevel 	 * Add this instance to the front of the list.
7671708Sstevel 	 */
7681708Sstevel 	if (sgsbbc_instances != NULL) {
7691708Sstevel 		sgsbbc_instances->prev = softsp;
7701708Sstevel 	}
7711708Sstevel 
7721708Sstevel 	softsp->next = sgsbbc_instances;
7731708Sstevel 	softsp->prev = NULL;
7741708Sstevel 	sgsbbc_instances = softsp;
7751708Sstevel }
7761708Sstevel 
7771708Sstevel static void
sbbc_remove_instance(sbbc_softstate_t * softsp)7781708Sstevel sbbc_remove_instance(sbbc_softstate_t *softsp)
7791708Sstevel {
7801708Sstevel 	struct sbbc_softstate *sp;
7811708Sstevel 
7821708Sstevel 	for (sp = sgsbbc_instances; sp != NULL; sp = sp->next) {
7831708Sstevel 		if (sp == softsp) {
7841708Sstevel 			if (sp->next != NULL) {
7851708Sstevel 				sp->next->prev = sp->prev;
7861708Sstevel 			}
7871708Sstevel 			if (sp->prev != NULL) {
7881708Sstevel 				sp->prev->next = sp->next;
7891708Sstevel 			}
7901708Sstevel 			if (sgsbbc_instances == softsp) {
7911708Sstevel 				sgsbbc_instances = sp->next;
7921708Sstevel 			}
7931708Sstevel 			break;
7941708Sstevel 		}
7951708Sstevel 	}
7961708Sstevel }
7971708Sstevel 
7981708Sstevel /*
7991708Sstevel  * Generate an SBBC interrupt to the SC
8001708Sstevel  * Called from iosram_send_intr()
8011708Sstevel  *
8021708Sstevel  * send_intr == 0, check if EPLD register clear
8031708Sstevel  *	           for sync'ing SC/OS
8041708Sstevel  * send_intr == 1, send the interrupt
8051708Sstevel  */
8061708Sstevel int
sbbc_send_intr(sbbc_softstate_t * softsp,int send_intr)8071708Sstevel sbbc_send_intr(sbbc_softstate_t *softsp, int send_intr)
8081708Sstevel {
8091708Sstevel 
8101708Sstevel 	uchar_t			*epld_int;
8111708Sstevel 	volatile uchar_t 	epld_status;
8121708Sstevel 
8131708Sstevel 	ASSERT(MUTEX_HELD(&master_iosram->iosram_lock));
8141708Sstevel 
8151708Sstevel 	if ((softsp == (sbbc_softstate_t *)NULL) ||
816*7656SSherry.Moore@Sun.COM 	    (softsp->epld_regs == (struct sbbc_epld_regs *)NULL))
8171708Sstevel 		return (ENXIO);
8181708Sstevel 
8191708Sstevel 	/*
8201708Sstevel 	 * Check the L1 EPLD Interrupt register. If the
8211708Sstevel 	 * interrupt bit is set, theres an interrupt outstanding
8221708Sstevel 	 * (we assume) so return (EBUSY).
8231708Sstevel 	 */
8241708Sstevel 
8251708Sstevel 	epld_int = &softsp->epld_regs->epld_reg[EPLD_INTERRUPT];
8261708Sstevel 
8271708Sstevel 	epld_status = ddi_get8(softsp->sbbc_reg_handle2, epld_int);
8281708Sstevel 
8291708Sstevel 	if (epld_status & INTERRUPT_ON)
8301708Sstevel 		return (EBUSY);
8311708Sstevel 
8321708Sstevel 	if (send_intr == TRUE)
8331708Sstevel 		ddi_put8(softsp->sbbc_reg_handle2, epld_int,
834*7656SSherry.Moore@Sun.COM 		    (epld_status | INTERRUPT_ON));
8351708Sstevel 
8361708Sstevel 	return (0);
8371708Sstevel }
8381708Sstevel 
8391708Sstevel /*
8401708Sstevel  * Map SBBC Internal registers
8411708Sstevel  *
8421708Sstevel  * The call to function should be protected by
8431708Sstevel  * chosen_lock or master_iosram->iosram_lock
8441708Sstevel  * to make sure a tunnel switch will not occur
8451708Sstevel  * in a middle of mapping.
8461708Sstevel  */
8471708Sstevel int
sbbc_map_regs(sbbc_softstate_t * softsp)8481708Sstevel sbbc_map_regs(sbbc_softstate_t *softsp)
8491708Sstevel {
8501708Sstevel 	struct ddi_device_acc_attr attr;
8511708Sstevel 
8521708Sstevel 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
8531708Sstevel 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
8541708Sstevel 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
8551708Sstevel 
8561708Sstevel 	/*
8571708Sstevel 	 * Map in register set 1, Common Device Regs
8581708Sstevel 	 * SBCC offset 0x0
8591708Sstevel 	 */
8601708Sstevel 	if (ddi_regs_map_setup(softsp->dip, RNUM_SBBC_REGS,
861*7656SSherry.Moore@Sun.COM 	    (caddr_t *)&softsp->sbbc_regs,
862*7656SSherry.Moore@Sun.COM 	    SBBC_REGS_OFFSET, SBBC_REGS_SIZE,
863*7656SSherry.Moore@Sun.COM 	    &attr, &softsp->sbbc_reg_handle1) != DDI_SUCCESS) {
8641708Sstevel 
8651708Sstevel 		cmn_err(CE_WARN, "sbbc%d: unable to map interrupt "
866*7656SSherry.Moore@Sun.COM 		    "registers", ddi_get_instance(softsp->dip));
8671708Sstevel 		return (DDI_FAILURE);
8681708Sstevel 	}
8691708Sstevel 	/*
8701708Sstevel 	 * Map in using register set 1, EPLD
8711708Sstevel 	 * SBCC offset 0xe000
8721708Sstevel 	 */
8731708Sstevel 	if (ddi_regs_map_setup(softsp->dip, RNUM_SBBC_REGS,
874*7656SSherry.Moore@Sun.COM 	    (caddr_t *)&softsp->epld_regs,
875*7656SSherry.Moore@Sun.COM 	    SBBC_EPLD_OFFSET, SBBC_EPLD_SIZE,
876*7656SSherry.Moore@Sun.COM 	    &attr, &softsp->sbbc_reg_handle2) != DDI_SUCCESS) {
8771708Sstevel 
8781708Sstevel 		cmn_err(CE_WARN, "sbbc%d: unable to map EPLD "
879*7656SSherry.Moore@Sun.COM 		    "registers", ddi_get_instance(softsp->dip));
8801708Sstevel 		return (DDI_FAILURE);
8811708Sstevel 	}
8821708Sstevel 
8831708Sstevel 	/*
8841708Sstevel 	 * Set up pointers for registers
8851708Sstevel 	 */
8861708Sstevel 	softsp->port_int_regs =  (uint32_t *)((char *)softsp->sbbc_regs +
887*7656SSherry.Moore@Sun.COM 	    SBBC_PCI_INT_STATUS);
8881708Sstevel 
8891708Sstevel map_regs_exit:
8901708Sstevel 	return (DDI_SUCCESS);
8911708Sstevel }
8921708Sstevel 
8931708Sstevel 
8941708Sstevel /*
8951708Sstevel  * Unmap SBBC Internal registers
8961708Sstevel  */
8971708Sstevel static void
sbbc_unmap_regs(sbbc_softstate_t * softsp)8981708Sstevel sbbc_unmap_regs(sbbc_softstate_t *softsp)
8991708Sstevel {
9001708Sstevel 	if (softsp == NULL)
9011708Sstevel 		return;
9021708Sstevel 
9031708Sstevel 	mutex_enter(&master_iosram->iosram_lock);
9041708Sstevel 
9051708Sstevel 	if (softsp->sbbc_regs) {
9061708Sstevel 		ddi_regs_map_free(&softsp->sbbc_reg_handle1);
9071708Sstevel 		softsp->sbbc_regs = NULL;
9081708Sstevel 		softsp->port_int_regs = NULL;
9091708Sstevel 	}
9101708Sstevel 
9111708Sstevel 	if (softsp->epld_regs) {
9121708Sstevel 		ddi_regs_map_free(&softsp->sbbc_reg_handle2);
9131708Sstevel 		softsp->epld_regs = NULL;
9141708Sstevel 	}
9151708Sstevel 
9161708Sstevel 	mutex_exit(&master_iosram->iosram_lock);
9171708Sstevel 
9181708Sstevel 	return;
9191708Sstevel 
9201708Sstevel }
9211708Sstevel /*
9221708Sstevel  * This is here to allow the IOSRAM driver get the softstate
9231708Sstevel  * for a chosen node when doing a tunnel switch. Just enables
9241708Sstevel  * us to avoid exporting the sbbcp softstate hook
9251708Sstevel  */
9261708Sstevel sbbc_softstate_t *
sbbc_get_soft_state(int instance)9271708Sstevel sbbc_get_soft_state(int instance)
9281708Sstevel {
9291708Sstevel 	return (ddi_get_soft_state(sbbcp, instance));
9301708Sstevel }
9311708Sstevel 
9321708Sstevel /*
9331708Sstevel  * Add interrupt handlers
9341708Sstevel  */
9351708Sstevel int
sbbc_add_intr(sbbc_softstate_t * softsp)9361708Sstevel sbbc_add_intr(sbbc_softstate_t *softsp)
9371708Sstevel {
9381708Sstevel 	int		rc = DDI_SUCCESS;
9391708Sstevel 
9401708Sstevel 	/*
9411708Sstevel 	 * map in the SBBC interrupts
9421708Sstevel 	 * Note that the iblock_cookie was initialised
9431708Sstevel 	 * in the 'attach' routine
9441708Sstevel 	 */
9451708Sstevel 
9461708Sstevel 	if (ddi_add_intr(softsp->dip, 0, &softsp->iblock,
947*7656SSherry.Moore@Sun.COM 	    &softsp->idevice, sbbc_intr_handler,
948*7656SSherry.Moore@Sun.COM 	    (caddr_t)softsp) != DDI_SUCCESS) {
9491708Sstevel 
9501708Sstevel 		cmn_err(CE_WARN, "Can't register SBBC "
951*7656SSherry.Moore@Sun.COM 		    " interrupt handler\n");
9521708Sstevel 		rc = DDI_FAILURE;
9531708Sstevel 	}
9541708Sstevel 
9551708Sstevel 	return (rc);
9561708Sstevel }
9571708Sstevel 
9581708Sstevel void
sbbc_enable_intr(sbbc_softstate_t * softsp)9591708Sstevel sbbc_enable_intr(sbbc_softstate_t *softsp)
9601708Sstevel {
9611708Sstevel 	uint32_t	*pci_intr_enable_reg;
9621708Sstevel 
9631708Sstevel 	/*
9641708Sstevel 	 * Enable Interrupts now, turn on both INT#A lines
9651708Sstevel 	 */
9661708Sstevel 	pci_intr_enable_reg =  (uint32_t *)((char *)softsp->sbbc_regs +
967*7656SSherry.Moore@Sun.COM 	    SBBC_PCI_INT_ENABLE);
9681708Sstevel 	ddi_put32(softsp->sbbc_reg_handle1, pci_intr_enable_reg,
969*7656SSherry.Moore@Sun.COM 	    (uint32_t)SBBC_PCI_ENABLE_INT_A);
9701708Sstevel }
9711708Sstevel 
9721708Sstevel void
sbbc_disable_intr(sbbc_softstate_t * softsp)9731708Sstevel sbbc_disable_intr(sbbc_softstate_t *softsp)
9741708Sstevel {
9751708Sstevel 	uint32_t	*pci_intr_enable_reg;
9761708Sstevel 
9771708Sstevel 	/*
9781708Sstevel 	 * Disable Interrupts now, turn off both INT#A lines
9791708Sstevel 	 */
9801708Sstevel 	pci_intr_enable_reg =  (uint32_t *)((char *)softsp->sbbc_regs +
981*7656SSherry.Moore@Sun.COM 	    SBBC_PCI_INT_ENABLE);
9821708Sstevel 	ddi_put32(softsp->sbbc_reg_handle1, pci_intr_enable_reg, 0);
9831708Sstevel }
984