103831d35Sstevel /*
203831d35Sstevel  * CDDL HEADER START
303831d35Sstevel  *
403831d35Sstevel  * The contents of this file are subject to the terms of the
503831d35Sstevel  * Common Development and Distribution License (the "License").
603831d35Sstevel  * You may not use this file except in compliance with the License.
703831d35Sstevel  *
803831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel  * See the License for the specific language governing permissions
1103831d35Sstevel  * and limitations under the License.
1203831d35Sstevel  *
1303831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel  *
1903831d35Sstevel  * CDDL HEADER END
2003831d35Sstevel  */
2103831d35Sstevel 
2203831d35Sstevel /*
23*19397407SSherry Moore  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2403831d35Sstevel  * Use is subject to license terms.
2503831d35Sstevel  */
2603831d35Sstevel 
2703831d35Sstevel 
2803831d35Sstevel /*
2903831d35Sstevel  * PCI SBBC Device Driver that provides interfaces into
3003831d35Sstevel  * EPLD and IO-SRAM
3103831d35Sstevel  *
3203831d35Sstevel  */
3303831d35Sstevel #include <sys/types.h>
3403831d35Sstevel #include <sys/param.h>
3503831d35Sstevel #include <sys/errno.h>
3603831d35Sstevel #include <sys/file.h>
3703831d35Sstevel #include <sys/cmn_err.h>
3803831d35Sstevel #include <sys/stropts.h>
3903831d35Sstevel #include <sys/kmem.h>
4003831d35Sstevel #include <sys/sunndi.h>
4103831d35Sstevel #include <sys/conf.h>		/* req. by dev_ops flags MTSAFE etc. */
4203831d35Sstevel #include <sys/modctl.h>		/* for modldrv */
4303831d35Sstevel #include <sys/promif.h>
4403831d35Sstevel #include <sys/stat.h>
4503831d35Sstevel #include <sys/ddi.h>
4603831d35Sstevel 
4703831d35Sstevel #include <sys/serengeti.h>
4803831d35Sstevel #include <sys/sgsbbc_priv.h>
4903831d35Sstevel #include <sys/sgsbbc_iosram_priv.h>
5003831d35Sstevel #include <sys/sgsbbc_mailbox_priv.h>
5103831d35Sstevel 
5203831d35Sstevel #ifdef DEBUG
5303831d35Sstevel /* debug flag */
5403831d35Sstevel uint_t sgsbbc_debug = 0;
5503831d35Sstevel #endif /* DEBUG */
5603831d35Sstevel 
5703831d35Sstevel /* driver entry point fn definitions */
5803831d35Sstevel static int	sbbc_attach(dev_info_t *, ddi_attach_cmd_t);
5903831d35Sstevel static int	sbbc_detach(dev_info_t *, ddi_detach_cmd_t);
6003831d35Sstevel 
6103831d35Sstevel /*
6203831d35Sstevel  * SBBC soft state hook
6303831d35Sstevel  */
6403831d35Sstevel static void    *sbbcp;
6503831d35Sstevel 
6603831d35Sstevel /*
6703831d35Sstevel  * Chosen IOSRAM
6803831d35Sstevel  */
6903831d35Sstevel struct chosen_iosram *master_iosram = NULL;
7003831d35Sstevel 
7103831d35Sstevel /*
7203831d35Sstevel  * define new iosram's sbbc and liked list of sbbc.
7303831d35Sstevel  */
7403831d35Sstevel struct sbbc_softstate *sgsbbc_instances = NULL;
7503831d35Sstevel 
7603831d35Sstevel /*
7703831d35Sstevel  * At attach time, check if the device is the 'chosen' node
7803831d35Sstevel  * if it is, set up the IOSRAM Solaris<->SC Comm tunnel
7903831d35Sstevel  * Its like 'Highlander' - there can be only one !
8003831d35Sstevel  */
8103831d35Sstevel static int	master_chosen = FALSE;
8203831d35Sstevel kmutex_t	chosen_lock;
8303831d35Sstevel 
8403831d35Sstevel /*
8503831d35Sstevel  * Local variable to save intr_in_enabled when the driver is suspended
8603831d35Sstevel  */
8703831d35Sstevel static uint32_t	intr_in_enabled;
8803831d35Sstevel 
8903831d35Sstevel /*
9003831d35Sstevel  * Local declarations
9103831d35Sstevel  */
9203831d35Sstevel static void	softsp_init(sbbc_softstate_t *, dev_info_t *);
9303831d35Sstevel static void	sbbc_chosen_init(sbbc_softstate_t *);
9403831d35Sstevel static void	sbbc_add_instance(sbbc_softstate_t *);
9503831d35Sstevel static void	sbbc_remove_instance(sbbc_softstate_t *);
9603831d35Sstevel static int	sbbc_find_dip(dev_info_t *, void *);
9703831d35Sstevel static void	sbbc_unmap_regs(sbbc_softstate_t *);
9803831d35Sstevel 
9903831d35Sstevel /*
10003831d35Sstevel  * ops stuff.
10103831d35Sstevel  */
10203831d35Sstevel static struct cb_ops sbbc_cb_ops = {
10303831d35Sstevel 	nodev,					/* cb_open */
10403831d35Sstevel 	nodev,					/* cb_close */
10503831d35Sstevel 	nodev,					/* cb_strategy */
10603831d35Sstevel 	nodev,					/* cb_print */
10703831d35Sstevel 	nodev,					/* cb_dump */
10803831d35Sstevel 	nodev,					/* cb_read */
10903831d35Sstevel 	nodev,					/* cb_write */
11003831d35Sstevel 	nodev,					/* cb_ioctl */
11103831d35Sstevel 	nodev,					/* cb_devmap */
11203831d35Sstevel 	nodev,					/* cb_mmap */
11303831d35Sstevel 	nodev,					/* cb_segmap */
11403831d35Sstevel 	nochpoll,				/* cb_chpoll */
11503831d35Sstevel 	ddi_prop_op,				/* cb_prop_op */
11603831d35Sstevel 	NULL,					/* cb_stream */
11703831d35Sstevel 	D_NEW | D_MP				/* cb_flag */
11803831d35Sstevel };
11903831d35Sstevel 
12003831d35Sstevel /*
12103831d35Sstevel  * Declare ops vectors for auto configuration.
12203831d35Sstevel  */
12303831d35Sstevel struct dev_ops  sbbc_ops = {
12403831d35Sstevel 	DEVO_REV,		/* devo_rev */
12503831d35Sstevel 	0,			/* devo_refcnt */
12603831d35Sstevel 	ddi_getinfo_1to1,	/* devo_getinfo */
12703831d35Sstevel 	nulldev,		/* devo_identify */
12803831d35Sstevel 	nulldev,		/* devo_probe */
12903831d35Sstevel 	sbbc_attach,		/* devo_attach */
13003831d35Sstevel 	sbbc_detach,		/* devo_detach */
13103831d35Sstevel 	nodev,			/* devo_reset */
13203831d35Sstevel 	&sbbc_cb_ops,		/* devo_cb_ops */
13303831d35Sstevel 	(struct bus_ops *)NULL,	/* devo_bus_ops */
134*19397407SSherry Moore 	nulldev,		/* devo_power */
135*19397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
13603831d35Sstevel };
13703831d35Sstevel 
13803831d35Sstevel /*
13903831d35Sstevel  * Loadable module support.
14003831d35Sstevel  */
14103831d35Sstevel extern struct mod_ops mod_driverops;
14203831d35Sstevel 
14303831d35Sstevel static struct modldrv modldrv = {
14403831d35Sstevel 	&mod_driverops,		/* type of module - driver */
145*19397407SSherry Moore 	"PCI SBBC",
14603831d35Sstevel 	&sbbc_ops,
14703831d35Sstevel };
14803831d35Sstevel 
14903831d35Sstevel static struct modlinkage modlinkage = {
15003831d35Sstevel 	MODREV_1,
15103831d35Sstevel 	(void *)&modldrv,
15203831d35Sstevel 	NULL
15303831d35Sstevel };
15403831d35Sstevel 
15503831d35Sstevel int
_init(void)15603831d35Sstevel _init(void)
15703831d35Sstevel {
15803831d35Sstevel 	int    error;
15903831d35Sstevel 
16003831d35Sstevel 	if ((error = ddi_soft_state_init(&sbbcp,
161*19397407SSherry Moore 	    sizeof (sbbc_softstate_t), 1)) != 0)
16203831d35Sstevel 		return (error);
16303831d35Sstevel 
16403831d35Sstevel 	if ((error = mod_install(&modlinkage)) != 0) {
16503831d35Sstevel 		ddi_soft_state_fini(&sbbcp);
16603831d35Sstevel 		return (error);
16703831d35Sstevel 	}
16803831d35Sstevel 
16903831d35Sstevel 	/*
17003831d35Sstevel 	 * Initialise the global 'chosen' IOSRAM mutex
17103831d35Sstevel 	 */
17203831d35Sstevel 	mutex_init(&chosen_lock, NULL, MUTEX_DEFAULT, NULL);
17303831d35Sstevel 
17403831d35Sstevel 	/*
17503831d35Sstevel 	 * Initialise the iosram driver
17603831d35Sstevel 	 */
17703831d35Sstevel 	iosram_init();
17803831d35Sstevel 
17903831d35Sstevel 	/*
18003831d35Sstevel 	 * Initialize the mailbox
18103831d35Sstevel 	 */
18203831d35Sstevel 	sbbc_mbox_init();
18303831d35Sstevel 
18403831d35Sstevel 	return (error);
18503831d35Sstevel 
18603831d35Sstevel }
18703831d35Sstevel 
18803831d35Sstevel int
_fini(void)18903831d35Sstevel _fini(void)
19003831d35Sstevel {
19103831d35Sstevel 	int    error;
19203831d35Sstevel 
19303831d35Sstevel 	if ((error = mod_remove(&modlinkage)) == 0)
19403831d35Sstevel 		ddi_soft_state_fini(&sbbcp);
19503831d35Sstevel 
19603831d35Sstevel 	master_chosen = FALSE;
19703831d35Sstevel 
19803831d35Sstevel 	mutex_destroy(&chosen_lock);
19903831d35Sstevel 
20003831d35Sstevel 	/*
20103831d35Sstevel 	 * remove the mailbox
20203831d35Sstevel 	 */
20303831d35Sstevel 	sbbc_mbox_fini();
20403831d35Sstevel 
20503831d35Sstevel 	/*
20603831d35Sstevel 	 * remove the iosram driver
20703831d35Sstevel 	 */
20803831d35Sstevel 	iosram_fini();
20903831d35Sstevel 
21003831d35Sstevel 	return (error);
21103831d35Sstevel }
21203831d35Sstevel 
21303831d35Sstevel int
_info(struct modinfo * modinfop)21403831d35Sstevel _info(struct modinfo *modinfop)
21503831d35Sstevel {
21603831d35Sstevel 	return (mod_info(&modlinkage, modinfop));
21703831d35Sstevel }
21803831d35Sstevel 
21903831d35Sstevel static int
sbbc_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)22003831d35Sstevel sbbc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
22103831d35Sstevel {
22203831d35Sstevel 	int			instance;
22303831d35Sstevel 	sbbc_softstate_t	*softsp;
22403831d35Sstevel 	uint32_t		*pci_intr_enable_reg;
22503831d35Sstevel 	int			len;
22603831d35Sstevel #ifdef	DEBUG
22703831d35Sstevel 	char			name[8];
22803831d35Sstevel #endif	/* DEBUG */
22903831d35Sstevel 
23003831d35Sstevel 	instance = ddi_get_instance(devi);
23103831d35Sstevel 
23203831d35Sstevel 	switch (cmd) {
23303831d35Sstevel 	case DDI_ATTACH:
23403831d35Sstevel 
23503831d35Sstevel 		if (ddi_soft_state_zalloc(sbbcp, instance) != 0)
23603831d35Sstevel 			return (DDI_FAILURE);
23703831d35Sstevel 
23803831d35Sstevel 		softsp = ddi_get_soft_state(sbbcp, instance);
23903831d35Sstevel 		softsp->sbbc_instance = instance;
24003831d35Sstevel 
24103831d35Sstevel 		/*
24203831d35Sstevel 		 * Set the dip in the soft state
24303831d35Sstevel 		 * And get interrupt cookies and initialize the
24403831d35Sstevel 		 * per instance mutex.
24503831d35Sstevel 		 */
24603831d35Sstevel 		softsp_init(softsp, devi);
24703831d35Sstevel 
24803831d35Sstevel 
24903831d35Sstevel 		/*
25003831d35Sstevel 		 * Verify that an 'interrupts' property exists for
25103831d35Sstevel 		 * this device. If not, this instance will be ignored.
25203831d35Sstevel 		 */
25303831d35Sstevel 		if (ddi_getproplen(DDI_DEV_T_ANY, softsp->dip,
254*19397407SSherry Moore 		    DDI_PROP_DONTPASS, "interrupts",
255*19397407SSherry Moore 		    &len) != DDI_PROP_SUCCESS) {
25603831d35Sstevel 			SBBC_ERR1(CE_WARN, "No 'interrupts' property for the "
257*19397407SSherry Moore 			    "SBBC instance %d\n", instance);
25803831d35Sstevel 			return (DDI_FAILURE);
25903831d35Sstevel 		}
26003831d35Sstevel 		/*
26103831d35Sstevel 		 * Add this instance to the sbbc chosen iosram list
26203831d35Sstevel 		 * so that it can be used for tunnel switch.
26303831d35Sstevel 		 */
26403831d35Sstevel 		mutex_enter(&chosen_lock);
26503831d35Sstevel 		softsp->sbbc_state = SBBC_STATE_INIT;
26603831d35Sstevel 		sbbc_add_instance(softsp);
26703831d35Sstevel 
26803831d35Sstevel 		/*
26903831d35Sstevel 		 * If this is the chosen IOSRAM and there is no master IOSRAM
27003831d35Sstevel 		 * yet, then let's set this instance as the master.
27103831d35Sstevel 		 * if there is a master alreay due to the previous tunnel switch
27203831d35Sstevel 		 * then keep as is even though this is the chosen.
27303831d35Sstevel 		 */
27403831d35Sstevel 		if (sgsbbc_iosram_is_chosen(softsp)) {
27503831d35Sstevel 			ASSERT(master_iosram);
27603831d35Sstevel 			softsp->iosram = master_iosram;
27703831d35Sstevel 			master_iosram->sgsbbc = softsp;
27803831d35Sstevel 
27903831d35Sstevel 			/* Do 'chosen' init only */
28003831d35Sstevel 			sbbc_chosen_init(softsp);
28103831d35Sstevel 		}
28203831d35Sstevel 
28303831d35Sstevel 		mutex_exit(&chosen_lock);
28403831d35Sstevel #ifdef	DEBUG
28503831d35Sstevel 		(void) sprintf(name, "sbbc%d", instance);
28603831d35Sstevel 
28703831d35Sstevel 		if (ddi_create_minor_node(devi, name, S_IFCHR, instance,
288*19397407SSherry Moore 		    NULL, NULL) == DDI_FAILURE) {
28903831d35Sstevel 			mutex_destroy(&softsp->sbbc_lock);
29003831d35Sstevel 			ddi_remove_minor_node(devi, NULL);
29103831d35Sstevel 			ddi_soft_state_free(sbbcp, instance);
29203831d35Sstevel 			return (DDI_FAILURE);
29303831d35Sstevel 		}
29403831d35Sstevel #endif	/* DEBUG */
29503831d35Sstevel 
29603831d35Sstevel 		ddi_report_dev(devi);
29703831d35Sstevel 
29803831d35Sstevel 		return (DDI_SUCCESS);
29903831d35Sstevel 
30003831d35Sstevel 	case DDI_RESUME:
30103831d35Sstevel 
30203831d35Sstevel 		if (!(softsp = ddi_get_soft_state(sbbcp, instance)))
30303831d35Sstevel 			return (DDI_FAILURE);
30403831d35Sstevel 
30503831d35Sstevel 		mutex_enter(&softsp->sbbc_lock);
30603831d35Sstevel 		if ((softsp->suspended == TRUE) && (softsp->chosen == TRUE)) {
30703831d35Sstevel 			/*
30803831d35Sstevel 			 * Enable Interrupts now, turn on both INT#A lines
30903831d35Sstevel 			 */
31003831d35Sstevel 			pci_intr_enable_reg =  (uint32_t *)
311*19397407SSherry Moore 			    ((char *)softsp->sbbc_regs +
312*19397407SSherry Moore 			    SBBC_PCI_INT_ENABLE);
31303831d35Sstevel 
31403831d35Sstevel 			ddi_put32(softsp->sbbc_reg_handle1,
315*19397407SSherry Moore 			    pci_intr_enable_reg,
316*19397407SSherry Moore 			    (uint32_t)SBBC_PCI_ENABLE_INT_A);
31703831d35Sstevel 
31803831d35Sstevel 			/*
31903831d35Sstevel 			 * Reset intr_in_enabled to the original value
32003831d35Sstevel 			 * so the SC can send us interrupt.
32103831d35Sstevel 			 */
32203831d35Sstevel 			if (iosram_write(SBBC_SC_INTR_ENABLED_KEY,
323*19397407SSherry Moore 			    0, (caddr_t)&intr_in_enabled,
324*19397407SSherry Moore 			    sizeof (intr_in_enabled))) {
32503831d35Sstevel 
32603831d35Sstevel 				mutex_exit(&softsp->sbbc_lock);
32703831d35Sstevel 				return (DDI_FAILURE);
32803831d35Sstevel 			}
32903831d35Sstevel 		}
33003831d35Sstevel 		softsp->suspended = FALSE;
33103831d35Sstevel 
33203831d35Sstevel 		mutex_exit(&softsp->sbbc_lock);
33303831d35Sstevel 
33403831d35Sstevel 		return (DDI_SUCCESS);
33503831d35Sstevel 
33603831d35Sstevel 	default:
33703831d35Sstevel 		return (DDI_FAILURE);
33803831d35Sstevel 	}
33903831d35Sstevel }
34003831d35Sstevel 
34103831d35Sstevel static int
sbbc_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)34203831d35Sstevel sbbc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
34303831d35Sstevel {
34403831d35Sstevel 	sbbc_softstate_t	*softsp;
34503831d35Sstevel 	int			instance;
34603831d35Sstevel 	uint32_t		*pci_intr_enable_reg;
34703831d35Sstevel 	int			rc = DDI_SUCCESS;
34803831d35Sstevel 
34903831d35Sstevel 	instance = ddi_get_instance(devi);
35003831d35Sstevel 
35103831d35Sstevel 	if (!(softsp = ddi_get_soft_state(sbbcp, instance)))
35203831d35Sstevel 		return (DDI_FAILURE);
35303831d35Sstevel 
35403831d35Sstevel 	switch (cmd) {
35503831d35Sstevel 	case DDI_DETACH:
35603831d35Sstevel 		mutex_enter(&chosen_lock);
35703831d35Sstevel 		softsp->sbbc_state |= SBBC_STATE_DETACH;
35803831d35Sstevel 		mutex_exit(&chosen_lock);
35903831d35Sstevel 
36003831d35Sstevel 		/* only tunnel switch the instance with iosram chosen */
36103831d35Sstevel 		if (softsp->chosen == TRUE) {
36203831d35Sstevel 			if (sgsbbc_iosram_switchfrom(softsp) == DDI_FAILURE) {
36303831d35Sstevel 				SBBC_ERR(CE_WARN, "Cannot unconfigure: "
36403831d35Sstevel 				    "tunnel switch failed\n");
36503831d35Sstevel 				return (DDI_FAILURE);
36603831d35Sstevel 			}
36703831d35Sstevel 		}
36803831d35Sstevel 
36903831d35Sstevel 		/* Adjust linked list */
37003831d35Sstevel 		mutex_enter(&chosen_lock);
37103831d35Sstevel 		sbbc_remove_instance(softsp);
37203831d35Sstevel 		mutex_exit(&chosen_lock);
37303831d35Sstevel 
37403831d35Sstevel 		sbbc_unmap_regs(softsp);
37503831d35Sstevel 		mutex_destroy(&softsp->sbbc_lock);
37603831d35Sstevel 		ddi_soft_state_free(sbbcp, instance);
37703831d35Sstevel 
37803831d35Sstevel 		return (DDI_SUCCESS);
37903831d35Sstevel 
38003831d35Sstevel 	case DDI_SUSPEND:
38103831d35Sstevel 
38203831d35Sstevel 		mutex_enter(&softsp->sbbc_lock);
38303831d35Sstevel 
38403831d35Sstevel 		if ((softsp->suspended == FALSE) && (softsp->chosen == TRUE)) {
38503831d35Sstevel 			uint32_t	tmp_intr_enabled = 0;
38603831d35Sstevel 
38703831d35Sstevel 			/*
38803831d35Sstevel 			 * Disable Interrupts now, turn OFF both INT#A lines
38903831d35Sstevel 			 */
39003831d35Sstevel 			pci_intr_enable_reg =  (uint32_t *)
391*19397407SSherry Moore 			    ((char *)softsp->sbbc_regs +
392*19397407SSherry Moore 			    SBBC_PCI_INT_ENABLE);
39303831d35Sstevel 
39403831d35Sstevel 			ddi_put32(softsp->sbbc_reg_handle1,
395*19397407SSherry Moore 			    pci_intr_enable_reg, 0);
39603831d35Sstevel 
39703831d35Sstevel 			/*
39803831d35Sstevel 			 * Set intr_in_enabled to 0 so the SC won't send
39903831d35Sstevel 			 * us interrupt.
40003831d35Sstevel 			 */
40103831d35Sstevel 			rc = iosram_read(SBBC_SC_INTR_ENABLED_KEY,
402*19397407SSherry Moore 			    0, (caddr_t)&intr_in_enabled,
403*19397407SSherry Moore 			    sizeof (intr_in_enabled));
40403831d35Sstevel 
40503831d35Sstevel 			if (rc) {
40603831d35Sstevel 				mutex_exit(&softsp->sbbc_lock);
40703831d35Sstevel 				return (DDI_FAILURE);
40803831d35Sstevel 			}
40903831d35Sstevel 
41003831d35Sstevel 			rc = iosram_write(SBBC_SC_INTR_ENABLED_KEY,
411*19397407SSherry Moore 			    0, (caddr_t)&tmp_intr_enabled,
412*19397407SSherry Moore 			    sizeof (tmp_intr_enabled));
41303831d35Sstevel 
41403831d35Sstevel 			if (rc) {
41503831d35Sstevel 				mutex_exit(&softsp->sbbc_lock);
41603831d35Sstevel 				return (DDI_FAILURE);
41703831d35Sstevel 			}
41803831d35Sstevel 		}
41903831d35Sstevel 		softsp->suspended = TRUE;
42003831d35Sstevel 
42103831d35Sstevel 		mutex_exit(&softsp->sbbc_lock);
42203831d35Sstevel 
42303831d35Sstevel 		return (DDI_SUCCESS);
42403831d35Sstevel 
42503831d35Sstevel 	default:
42603831d35Sstevel 		return (DDI_FAILURE);
42703831d35Sstevel 	}
42803831d35Sstevel 
42903831d35Sstevel }
43003831d35Sstevel 
43103831d35Sstevel static void
softsp_init(sbbc_softstate_t * softsp,dev_info_t * devi)43203831d35Sstevel softsp_init(sbbc_softstate_t *softsp, dev_info_t *devi)
43303831d35Sstevel {
43403831d35Sstevel 	softsp->dip = devi;
43503831d35Sstevel 
43603831d35Sstevel 	/*
43703831d35Sstevel 	 * XXXX
43803831d35Sstevel 	 * ddi_get_iblock_cookie() here because we need
43903831d35Sstevel 	 * to initialise the mutex regardless of whether
44003831d35Sstevel 	 * or not this SBBC will eventually
44103831d35Sstevel 	 * register an interrupt handler
44203831d35Sstevel 	 */
44303831d35Sstevel 
44403831d35Sstevel 	(void) ddi_get_iblock_cookie(devi, 0, &softsp->iblock);
44503831d35Sstevel 
44603831d35Sstevel 	mutex_init(&softsp->sbbc_lock, NULL, MUTEX_DRIVER,
447*19397407SSherry Moore 	    (void *)softsp->iblock);
44803831d35Sstevel 
44903831d35Sstevel 	softsp->suspended = FALSE;
45003831d35Sstevel 	softsp->chosen = FALSE;
45103831d35Sstevel }
45203831d35Sstevel 
45303831d35Sstevel static int
sbbc_find_dip(dev_info_t * dip,void * arg)45403831d35Sstevel sbbc_find_dip(dev_info_t *dip, void *arg)
45503831d35Sstevel {
45603831d35Sstevel 	char		*node_name;
45703831d35Sstevel 	sbbc_find_dip_t	*dip_struct = (sbbc_find_dip_t *)arg;
45803831d35Sstevel 	char		status[OBP_MAXPROPNAME];
45903831d35Sstevel 
46003831d35Sstevel 	/*
46103831d35Sstevel 	 * Need to find a node named "bootbus-controller" that is neither
46203831d35Sstevel 	 * disabled nor failed.  If a node is not ok, there will be an
46303831d35Sstevel 	 * OBP status property.  Therefore, we will look for a node
46403831d35Sstevel 	 * without the status property.
46503831d35Sstevel 	 */
46603831d35Sstevel 	node_name = ddi_node_name(dip);
46703831d35Sstevel 	if (strcmp(node_name, "bootbus-controller") == 0 && DDI_CF2(dip) &&
468*19397407SSherry Moore 	    (prom_getprop(ddi_get_nodeid(dip),
469*19397407SSherry Moore 	    "status", (caddr_t)status) == -1) &&
470*19397407SSherry Moore 	    (prom_getprop(ddi_get_nodeid(ddi_get_parent(dip)),
471*19397407SSherry Moore 	    "status", (caddr_t)status) == -1)) {
47203831d35Sstevel 
47303831d35Sstevel 		if (dip != dip_struct->cur_dip) {
47403831d35Sstevel 			dip_struct->new_dip = (void *)dip;
47503831d35Sstevel 			return (DDI_WALK_TERMINATE);
47603831d35Sstevel 		}
47703831d35Sstevel 	}
47803831d35Sstevel 
47903831d35Sstevel 	return (DDI_WALK_CONTINUE);
48003831d35Sstevel }
48103831d35Sstevel 
48203831d35Sstevel /*
48303831d35Sstevel  * SBBC Interrupt Handler
48403831d35Sstevel  *
48503831d35Sstevel  * Check the SBBC Port Interrupt Status
48603831d35Sstevel  * register to verify that its our interrupt.
48703831d35Sstevel  * If yes, clear the register.
48803831d35Sstevel  *
48903831d35Sstevel  * Then read the 'interrupt reason' field from SRAM,
49003831d35Sstevel  * this triggers the appropriate soft_intr handler
49103831d35Sstevel  */
49203831d35Sstevel uint_t
sbbc_intr_handler(caddr_t arg)49303831d35Sstevel sbbc_intr_handler(caddr_t arg)
49403831d35Sstevel {
49503831d35Sstevel 	sbbc_softstate_t	*softsp = (sbbc_softstate_t *)arg;
49603831d35Sstevel 	uint32_t		*port_int_reg;
49703831d35Sstevel 	volatile uint32_t	port_int_status;
49803831d35Sstevel 	volatile uint32_t	intr_reason;
49903831d35Sstevel 	uint32_t		intr_enabled;
50003831d35Sstevel 	sbbc_intrs_t		*intr;
50103831d35Sstevel 	int			i, intr_mask;
50203831d35Sstevel 	struct tunnel_key	tunnel_key;
50303831d35Sstevel 	ddi_acc_handle_t	intr_in_handle;
50403831d35Sstevel 	uint32_t		*intr_in_reason;
50503831d35Sstevel 
50603831d35Sstevel 	if (softsp == (sbbc_softstate_t *)NULL) {
50703831d35Sstevel 
50803831d35Sstevel 		return (DDI_INTR_UNCLAIMED);
50903831d35Sstevel 	}
51003831d35Sstevel 
51103831d35Sstevel 	mutex_enter(&softsp->sbbc_lock);
51203831d35Sstevel 
51303831d35Sstevel 	if (softsp->port_int_regs == NULL) {
51403831d35Sstevel 		mutex_exit(&softsp->sbbc_lock);
51503831d35Sstevel 		return (DDI_INTR_UNCLAIMED);
51603831d35Sstevel 	}
51703831d35Sstevel 
51803831d35Sstevel 	/*
51903831d35Sstevel 	 * Normally if port_int_status is 0, we assume it is not
52003831d35Sstevel 	 * our interrupt.  However, we don't want to miss the
52103831d35Sstevel 	 * ones that come in during tunnel switch.  Therefore,
52203831d35Sstevel 	 * we always check the interrupt reason bits in IOSRAM
52303831d35Sstevel 	 * to be sure.
52403831d35Sstevel 	 */
52503831d35Sstevel 	port_int_reg = softsp->port_int_regs;
52603831d35Sstevel 
52703831d35Sstevel 	port_int_status = ddi_get32(softsp->sbbc_reg_handle1, port_int_reg);
52803831d35Sstevel 
52903831d35Sstevel 	/*
53003831d35Sstevel 	 * Generate a softint for each interrupt
53103831d35Sstevel 	 * bit set in the intr_in_reason field in SRAM
53203831d35Sstevel 	 * that has a corresponding bit set in the
53303831d35Sstevel 	 * intr_in_enabled field in SRAM
53403831d35Sstevel 	 */
53503831d35Sstevel 
53603831d35Sstevel 	if (iosram_read(SBBC_SC_INTR_ENABLED_KEY, 0,
537*19397407SSherry Moore 	    (caddr_t)&intr_enabled, sizeof (intr_enabled))) {
53803831d35Sstevel 
53903831d35Sstevel 		goto intr_handler_exit;
54003831d35Sstevel 	}
54103831d35Sstevel 
54203831d35Sstevel 	tunnel_key = master_iosram->tunnel->tunnel_keys[SBBC_SC_INTR_KEY];
54303831d35Sstevel 	intr_in_reason = (uint32_t *)tunnel_key.base;
54403831d35Sstevel 	intr_in_handle = tunnel_key.reg_handle;
54503831d35Sstevel 
54603831d35Sstevel 	intr_reason = ddi_get32(intr_in_handle, intr_in_reason);
54703831d35Sstevel 
54803831d35Sstevel 	SGSBBC_DBG_INTR(CE_CONT, "intr_reason = %x\n", intr_reason);
54903831d35Sstevel 
55003831d35Sstevel 	intr_reason &= intr_enabled;
55103831d35Sstevel 
55203831d35Sstevel 	for (i = 0; i < SBBC_MAX_INTRS; i++) {
55303831d35Sstevel 		intr_mask = (1 << i);
55403831d35Sstevel 		if (intr_reason & intr_mask) {
55503831d35Sstevel 			intr = &softsp->intr_hdlrs[i];
55603831d35Sstevel 			if ((intr != NULL) &&
557*19397407SSherry Moore 			    (intr->sbbc_intr_id != 0)) {
55803831d35Sstevel 				/*
55903831d35Sstevel 				 * XXXX
56003831d35Sstevel 				 * The model we agree with a handler
56103831d35Sstevel 				 * is that they run until they have
56203831d35Sstevel 				 * exhausted all work. To avoid
56303831d35Sstevel 				 * triggering them again, they pass
56403831d35Sstevel 				 * a state flag and lock when registering.
56503831d35Sstevel 				 * We check the flag, if they are idle,
56603831d35Sstevel 				 * we trigger.
56703831d35Sstevel 				 * The interrupt handler should so
56803831d35Sstevel 				 *   intr_func()
56903831d35Sstevel 				 *	mutex_enter(sbbc_intr_lock);
57003831d35Sstevel 				 *	sbbc_intr_state = RUNNING;
57103831d35Sstevel 				 *	mutex_exit(sbbc_intr_lock);
57203831d35Sstevel 				 *	  ..........
57303831d35Sstevel 				 *	  ..........
57403831d35Sstevel 				 *	  ..........
57503831d35Sstevel 				 *	mutex_enter(sbbc_intr_lock);
57603831d35Sstevel 				 *	sbbc_intr_state = IDLE;
57703831d35Sstevel 				 *	mutex_exit(sbbc_intr_lock);
57803831d35Sstevel 				 *
57903831d35Sstevel 				 * XXXX
58003831d35Sstevel 				 */
58103831d35Sstevel 				mutex_enter(intr->sbbc_intr_lock);
58203831d35Sstevel 				if (*(intr->sbbc_intr_state) ==
583*19397407SSherry Moore 				    SBBC_INTR_IDLE) {
58403831d35Sstevel 					mutex_exit(intr->sbbc_intr_lock);
58503831d35Sstevel 					ddi_trigger_softintr(
586*19397407SSherry Moore 					    intr->sbbc_intr_id);
58703831d35Sstevel 				} else {
58803831d35Sstevel 					/*
58903831d35Sstevel 					 * The handler is running
59003831d35Sstevel 					 */
59103831d35Sstevel 					mutex_exit(intr->sbbc_intr_lock);
59203831d35Sstevel 				}
59303831d35Sstevel 				intr_reason &= ~intr_mask;
59403831d35Sstevel 				/*
59503831d35Sstevel 				 * Clear the corresponding reason bit in SRAM
59603831d35Sstevel 				 *
59703831d35Sstevel 				 * Since there is no interlocking between
59803831d35Sstevel 				 * Solaris and the SC when writing to SRAM,
59903831d35Sstevel 				 * it is possible for the SC to set another
60003831d35Sstevel 				 * bit in the interrupt reason field while
60103831d35Sstevel 				 * we are handling the current interrupt.
60203831d35Sstevel 				 * To minimize the window in which an
60303831d35Sstevel 				 * additional bit can be set, reading
60403831d35Sstevel 				 * and writing the interrupt reason
60503831d35Sstevel 				 * in SRAM must be as close as possible.
60603831d35Sstevel 				 */
60703831d35Sstevel 				ddi_put32(intr_in_handle, intr_in_reason,
608*19397407SSherry Moore 				    ddi_get32(intr_in_handle,
609*19397407SSherry Moore 				    intr_in_reason) & ~intr_mask);
61003831d35Sstevel 			}
61103831d35Sstevel 		}
61203831d35Sstevel 		if (intr_reason == 0)	/* No more interrupts to be processed */
61303831d35Sstevel 			break;
61403831d35Sstevel 	}
61503831d35Sstevel 
61603831d35Sstevel 	/*
61703831d35Sstevel 	 * Clear the Interrupt Status Register (RW1C)
61803831d35Sstevel 	 */
61903831d35Sstevel 	ddi_put32(softsp->sbbc_reg_handle1, port_int_reg, port_int_status);
62003831d35Sstevel 
62103831d35Sstevel 	port_int_status = ddi_get32(softsp->sbbc_reg_handle1, port_int_reg);
62203831d35Sstevel 
62303831d35Sstevel intr_handler_exit:
62403831d35Sstevel 
62503831d35Sstevel 	mutex_exit(&softsp->sbbc_lock);
62603831d35Sstevel 
62703831d35Sstevel 	return (DDI_INTR_CLAIMED);
62803831d35Sstevel 
62903831d35Sstevel }
63003831d35Sstevel 
63103831d35Sstevel /*
63203831d35Sstevel  * If we don't already have a master SBBC selected,
63303831d35Sstevel  * get the <sbbc> property from the /chosen node. If
63403831d35Sstevel  * the pathname matches, this is the master SBBC and
63503831d35Sstevel  * we set up the console/TOD SRAM mapping here.
63603831d35Sstevel  */
63703831d35Sstevel static void
sbbc_chosen_init(sbbc_softstate_t * softsp)63803831d35Sstevel sbbc_chosen_init(sbbc_softstate_t *softsp)
63903831d35Sstevel {
64003831d35Sstevel 	char		master_sbbc[MAXNAMELEN];
64103831d35Sstevel 	char		pn[MAXNAMELEN];
64203831d35Sstevel 	int		nodeid, len;
64303831d35Sstevel 	pnode_t		dnode;
64403831d35Sstevel 
64503831d35Sstevel 	if (master_chosen != FALSE) {
64603831d35Sstevel 		/*
64703831d35Sstevel 		 * We've got one already
64803831d35Sstevel 		 */
64903831d35Sstevel 		return;
65003831d35Sstevel 	}
65103831d35Sstevel 
65203831d35Sstevel 	/*
65303831d35Sstevel 	 * Get /chosen node info. prom interface will handle errors.
65403831d35Sstevel 	 */
65503831d35Sstevel 	dnode = prom_chosennode();
65603831d35Sstevel 
65703831d35Sstevel 	/*
65803831d35Sstevel 	 * Look for the "iosram" property on the chosen node with a prom
65903831d35Sstevel 	 * interface as ddi_find_devinfo() couldn't be used (calls
66003831d35Sstevel 	 * ddi_walk_devs() that creates one extra lock on the device tree).
66103831d35Sstevel 	 */
66203831d35Sstevel 	if (prom_getprop(dnode, IOSRAM_CHOSEN_PROP, (caddr_t)&nodeid) <= 0) {
66303831d35Sstevel 		/*
66403831d35Sstevel 		 * No I/O Board SBBC set up as console, what to do ?
66503831d35Sstevel 		 */
66603831d35Sstevel 		SBBC_ERR(CE_PANIC, "No SBBC found for Console/TOD \n");
66703831d35Sstevel 	}
66803831d35Sstevel 
66903831d35Sstevel 	if (prom_getprop(dnode, IOSRAM_TOC_PROP,
67003831d35Sstevel 	    (caddr_t)&softsp->sram_toc) <= 0) {
67103831d35Sstevel 		/*
67203831d35Sstevel 		 * SRAM TOC Offset defaults to 0
67303831d35Sstevel 		 */
67403831d35Sstevel 		SBBC_ERR(CE_WARN, "No SBBC TOC Offset found\n");
67503831d35Sstevel 		softsp->sram_toc = 0;
67603831d35Sstevel 	}
67703831d35Sstevel 
67803831d35Sstevel 	/*
67903831d35Sstevel 	 * get the full OBP pathname of this node
68003831d35Sstevel 	 */
68103831d35Sstevel 	if (prom_phandle_to_path((phandle_t)nodeid, master_sbbc,
682*19397407SSherry Moore 	    sizeof (master_sbbc)) < 0) {
68303831d35Sstevel 
68403831d35Sstevel 		SBBC_ERR1(CE_PANIC, "prom_phandle_to_path(%d) failed\n",
68503831d35Sstevel 		    nodeid);
68603831d35Sstevel 	}
68703831d35Sstevel 	SGSBBC_DBG_ALL("chosen pathname : %s\n", master_sbbc);
68803831d35Sstevel 	SGSBBC_DBG_ALL("device pathname : %s\n", ddi_pathname(softsp->dip, pn));
68903831d35Sstevel 	if (strcmp(master_sbbc, ddi_pathname(softsp->dip, pn)) == 0) {
69003831d35Sstevel 
69103831d35Sstevel 		/*
69203831d35Sstevel 		 * map in the SBBC regs
69303831d35Sstevel 		 */
69403831d35Sstevel 
69503831d35Sstevel 		if (sbbc_map_regs(softsp) != DDI_SUCCESS) {
69603831d35Sstevel 			SBBC_ERR(CE_PANIC, "Can't map the SBBC regs \n");
69703831d35Sstevel 		}
69803831d35Sstevel 		/*
69903831d35Sstevel 		 * Only the 'chosen' node is used for iosram_read()/_write()
70003831d35Sstevel 		 * Must initialise the tunnel before the console/tod
70103831d35Sstevel 		 *
70203831d35Sstevel 		 */
70303831d35Sstevel 		if (iosram_tunnel_init(softsp) == DDI_FAILURE) {
70403831d35Sstevel 			SBBC_ERR(CE_PANIC, "Can't create the SRAM <-> SC "
705*19397407SSherry Moore 			    "comm. tunnel \n");
70603831d35Sstevel 		}
70703831d35Sstevel 
70803831d35Sstevel 		master_chosen = TRUE;
70903831d35Sstevel 
71003831d35Sstevel 		/*
71103831d35Sstevel 		 * Verify that an 'interrupts' property
71203831d35Sstevel 		 * exists for this device
71303831d35Sstevel 		 */
71403831d35Sstevel 
71503831d35Sstevel 		if (ddi_getproplen(DDI_DEV_T_ANY, softsp->dip,
716*19397407SSherry Moore 		    DDI_PROP_DONTPASS, "interrupts",
717*19397407SSherry Moore 		    &len) != DDI_PROP_SUCCESS) {
71803831d35Sstevel 
71903831d35Sstevel 			SBBC_ERR(CE_PANIC, "No 'interrupts' property for the "
720*19397407SSherry Moore 			    "'chosen' SBBC \n");
72103831d35Sstevel 		}
72203831d35Sstevel 
72303831d35Sstevel 		/*
72403831d35Sstevel 		 * add the interrupt handler
72503831d35Sstevel 		 * NB
72603831d35Sstevel 		 * should this be a high-level interrupt ?
72703831d35Sstevel 		 * NB
72803831d35Sstevel 		 */
72903831d35Sstevel 		if (sbbc_add_intr(softsp) == DDI_FAILURE) {
73003831d35Sstevel 			SBBC_ERR(CE_PANIC, "Can't add interrupt handler for "
731*19397407SSherry Moore 			    "'chosen' SBBC \n");
73203831d35Sstevel 		}
73303831d35Sstevel 
73403831d35Sstevel 		sbbc_enable_intr(softsp);
73503831d35Sstevel 
73603831d35Sstevel 		/*
73703831d35Sstevel 		 * Create the mailbox
73803831d35Sstevel 		 */
73903831d35Sstevel 		if (sbbc_mbox_create(softsp) != 0) {
74003831d35Sstevel 			cmn_err(CE_WARN, "No IOSRAM MailBox created!\n");
74103831d35Sstevel 		}
74203831d35Sstevel 
74303831d35Sstevel 	}
74403831d35Sstevel }
74503831d35Sstevel /*
74603831d35Sstevel  * sbbc_add_instance
74703831d35Sstevel  * Must be called to hold chosen_lock.
74803831d35Sstevel  */
74903831d35Sstevel static void
sbbc_add_instance(sbbc_softstate_t * softsp)75003831d35Sstevel sbbc_add_instance(sbbc_softstate_t *softsp)
75103831d35Sstevel {
75203831d35Sstevel #ifdef DEBUG
75303831d35Sstevel 	struct  sbbc_softstate *sp;
75403831d35Sstevel #endif
75503831d35Sstevel 
75603831d35Sstevel 	ASSERT(mutex_owned(&chosen_lock));
75703831d35Sstevel 
75803831d35Sstevel #if defined(DEBUG)
75903831d35Sstevel 	/* Verify that this instance is not in the list yet */
76003831d35Sstevel 	for (sp = sgsbbc_instances; sp != NULL; sp = sp->next) {
76103831d35Sstevel 		ASSERT(sp != softsp);
76203831d35Sstevel 	}
76303831d35Sstevel #endif
76403831d35Sstevel 
76503831d35Sstevel 	/*
76603831d35Sstevel 	 * Add this instance to the front of the list.
76703831d35Sstevel 	 */
76803831d35Sstevel 	if (sgsbbc_instances != NULL) {
76903831d35Sstevel 		sgsbbc_instances->prev = softsp;
77003831d35Sstevel 	}
77103831d35Sstevel 
77203831d35Sstevel 	softsp->next = sgsbbc_instances;
77303831d35Sstevel 	softsp->prev = NULL;
77403831d35Sstevel 	sgsbbc_instances = softsp;
77503831d35Sstevel }
77603831d35Sstevel 
77703831d35Sstevel static void
sbbc_remove_instance(sbbc_softstate_t * softsp)77803831d35Sstevel sbbc_remove_instance(sbbc_softstate_t *softsp)
77903831d35Sstevel {
78003831d35Sstevel 	struct sbbc_softstate *sp;
78103831d35Sstevel 
78203831d35Sstevel 	for (sp = sgsbbc_instances; sp != NULL; sp = sp->next) {
78303831d35Sstevel 		if (sp == softsp) {
78403831d35Sstevel 			if (sp->next != NULL) {
78503831d35Sstevel 				sp->next->prev = sp->prev;
78603831d35Sstevel 			}
78703831d35Sstevel 			if (sp->prev != NULL) {
78803831d35Sstevel 				sp->prev->next = sp->next;
78903831d35Sstevel 			}
79003831d35Sstevel 			if (sgsbbc_instances == softsp) {
79103831d35Sstevel 				sgsbbc_instances = sp->next;
79203831d35Sstevel 			}
79303831d35Sstevel 			break;
79403831d35Sstevel 		}
79503831d35Sstevel 	}
79603831d35Sstevel }
79703831d35Sstevel 
79803831d35Sstevel /*
79903831d35Sstevel  * Generate an SBBC interrupt to the SC
80003831d35Sstevel  * Called from iosram_send_intr()
80103831d35Sstevel  *
80203831d35Sstevel  * send_intr == 0, check if EPLD register clear
80303831d35Sstevel  *	           for sync'ing SC/OS
80403831d35Sstevel  * send_intr == 1, send the interrupt
80503831d35Sstevel  */
80603831d35Sstevel int
sbbc_send_intr(sbbc_softstate_t * softsp,int send_intr)80703831d35Sstevel sbbc_send_intr(sbbc_softstate_t *softsp, int send_intr)
80803831d35Sstevel {
80903831d35Sstevel 
81003831d35Sstevel 	uchar_t			*epld_int;
81103831d35Sstevel 	volatile uchar_t 	epld_status;
81203831d35Sstevel 
81303831d35Sstevel 	ASSERT(MUTEX_HELD(&master_iosram->iosram_lock));
81403831d35Sstevel 
81503831d35Sstevel 	if ((softsp == (sbbc_softstate_t *)NULL) ||
816*19397407SSherry Moore 	    (softsp->epld_regs == (struct sbbc_epld_regs *)NULL))
81703831d35Sstevel 		return (ENXIO);
81803831d35Sstevel 
81903831d35Sstevel 	/*
82003831d35Sstevel 	 * Check the L1 EPLD Interrupt register. If the
82103831d35Sstevel 	 * interrupt bit is set, theres an interrupt outstanding
82203831d35Sstevel 	 * (we assume) so return (EBUSY).
82303831d35Sstevel 	 */
82403831d35Sstevel 
82503831d35Sstevel 	epld_int = &softsp->epld_regs->epld_reg[EPLD_INTERRUPT];
82603831d35Sstevel 
82703831d35Sstevel 	epld_status = ddi_get8(softsp->sbbc_reg_handle2, epld_int);
82803831d35Sstevel 
82903831d35Sstevel 	if (epld_status & INTERRUPT_ON)
83003831d35Sstevel 		return (EBUSY);
83103831d35Sstevel 
83203831d35Sstevel 	if (send_intr == TRUE)
83303831d35Sstevel 		ddi_put8(softsp->sbbc_reg_handle2, epld_int,
834*19397407SSherry Moore 		    (epld_status | INTERRUPT_ON));
83503831d35Sstevel 
83603831d35Sstevel 	return (0);
83703831d35Sstevel }
83803831d35Sstevel 
83903831d35Sstevel /*
84003831d35Sstevel  * Map SBBC Internal registers
84103831d35Sstevel  *
84203831d35Sstevel  * The call to function should be protected by
84303831d35Sstevel  * chosen_lock or master_iosram->iosram_lock
84403831d35Sstevel  * to make sure a tunnel switch will not occur
84503831d35Sstevel  * in a middle of mapping.
84603831d35Sstevel  */
84703831d35Sstevel int
sbbc_map_regs(sbbc_softstate_t * softsp)84803831d35Sstevel sbbc_map_regs(sbbc_softstate_t *softsp)
84903831d35Sstevel {
85003831d35Sstevel 	struct ddi_device_acc_attr attr;
85103831d35Sstevel 
85203831d35Sstevel 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
85303831d35Sstevel 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
85403831d35Sstevel 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
85503831d35Sstevel 
85603831d35Sstevel 	/*
85703831d35Sstevel 	 * Map in register set 1, Common Device Regs
85803831d35Sstevel 	 * SBCC offset 0x0
85903831d35Sstevel 	 */
86003831d35Sstevel 	if (ddi_regs_map_setup(softsp->dip, RNUM_SBBC_REGS,
861*19397407SSherry Moore 	    (caddr_t *)&softsp->sbbc_regs,
862*19397407SSherry Moore 	    SBBC_REGS_OFFSET, SBBC_REGS_SIZE,
863*19397407SSherry Moore 	    &attr, &softsp->sbbc_reg_handle1) != DDI_SUCCESS) {
86403831d35Sstevel 
86503831d35Sstevel 		cmn_err(CE_WARN, "sbbc%d: unable to map interrupt "
866*19397407SSherry Moore 		    "registers", ddi_get_instance(softsp->dip));
86703831d35Sstevel 		return (DDI_FAILURE);
86803831d35Sstevel 	}
86903831d35Sstevel 	/*
87003831d35Sstevel 	 * Map in using register set 1, EPLD
87103831d35Sstevel 	 * SBCC offset 0xe000
87203831d35Sstevel 	 */
87303831d35Sstevel 	if (ddi_regs_map_setup(softsp->dip, RNUM_SBBC_REGS,
874*19397407SSherry Moore 	    (caddr_t *)&softsp->epld_regs,
875*19397407SSherry Moore 	    SBBC_EPLD_OFFSET, SBBC_EPLD_SIZE,
876*19397407SSherry Moore 	    &attr, &softsp->sbbc_reg_handle2) != DDI_SUCCESS) {
87703831d35Sstevel 
87803831d35Sstevel 		cmn_err(CE_WARN, "sbbc%d: unable to map EPLD "
879*19397407SSherry Moore 		    "registers", ddi_get_instance(softsp->dip));
88003831d35Sstevel 		return (DDI_FAILURE);
88103831d35Sstevel 	}
88203831d35Sstevel 
88303831d35Sstevel 	/*
88403831d35Sstevel 	 * Set up pointers for registers
88503831d35Sstevel 	 */
88603831d35Sstevel 	softsp->port_int_regs =  (uint32_t *)((char *)softsp->sbbc_regs +
887*19397407SSherry Moore 	    SBBC_PCI_INT_STATUS);
88803831d35Sstevel 
88903831d35Sstevel map_regs_exit:
89003831d35Sstevel 	return (DDI_SUCCESS);
89103831d35Sstevel }
89203831d35Sstevel 
89303831d35Sstevel 
89403831d35Sstevel /*
89503831d35Sstevel  * Unmap SBBC Internal registers
89603831d35Sstevel  */
89703831d35Sstevel static void
sbbc_unmap_regs(sbbc_softstate_t * softsp)89803831d35Sstevel sbbc_unmap_regs(sbbc_softstate_t *softsp)
89903831d35Sstevel {
90003831d35Sstevel 	if (softsp == NULL)
90103831d35Sstevel 		return;
90203831d35Sstevel 
90303831d35Sstevel 	mutex_enter(&master_iosram->iosram_lock);
90403831d35Sstevel 
90503831d35Sstevel 	if (softsp->sbbc_regs) {
90603831d35Sstevel 		ddi_regs_map_free(&softsp->sbbc_reg_handle1);
90703831d35Sstevel 		softsp->sbbc_regs = NULL;
90803831d35Sstevel 		softsp->port_int_regs = NULL;
90903831d35Sstevel 	}
91003831d35Sstevel 
91103831d35Sstevel 	if (softsp->epld_regs) {
91203831d35Sstevel 		ddi_regs_map_free(&softsp->sbbc_reg_handle2);
91303831d35Sstevel 		softsp->epld_regs = NULL;
91403831d35Sstevel 	}
91503831d35Sstevel 
91603831d35Sstevel 	mutex_exit(&master_iosram->iosram_lock);
91703831d35Sstevel 
91803831d35Sstevel 	return;
91903831d35Sstevel 
92003831d35Sstevel }
92103831d35Sstevel /*
92203831d35Sstevel  * This is here to allow the IOSRAM driver get the softstate
92303831d35Sstevel  * for a chosen node when doing a tunnel switch. Just enables
92403831d35Sstevel  * us to avoid exporting the sbbcp softstate hook
92503831d35Sstevel  */
92603831d35Sstevel sbbc_softstate_t *
sbbc_get_soft_state(int instance)92703831d35Sstevel sbbc_get_soft_state(int instance)
92803831d35Sstevel {
92903831d35Sstevel 	return (ddi_get_soft_state(sbbcp, instance));
93003831d35Sstevel }
93103831d35Sstevel 
93203831d35Sstevel /*
93303831d35Sstevel  * Add interrupt handlers
93403831d35Sstevel  */
93503831d35Sstevel int
sbbc_add_intr(sbbc_softstate_t * softsp)93603831d35Sstevel sbbc_add_intr(sbbc_softstate_t *softsp)
93703831d35Sstevel {
93803831d35Sstevel 	int		rc = DDI_SUCCESS;
93903831d35Sstevel 
94003831d35Sstevel 	/*
94103831d35Sstevel 	 * map in the SBBC interrupts
94203831d35Sstevel 	 * Note that the iblock_cookie was initialised
94303831d35Sstevel 	 * in the 'attach' routine
94403831d35Sstevel 	 */
94503831d35Sstevel 
94603831d35Sstevel 	if (ddi_add_intr(softsp->dip, 0, &softsp->iblock,
947*19397407SSherry Moore 	    &softsp->idevice, sbbc_intr_handler,
948*19397407SSherry Moore 	    (caddr_t)softsp) != DDI_SUCCESS) {
94903831d35Sstevel 
95003831d35Sstevel 		cmn_err(CE_WARN, "Can't register SBBC "
951*19397407SSherry Moore 		    " interrupt handler\n");
95203831d35Sstevel 		rc = DDI_FAILURE;
95303831d35Sstevel 	}
95403831d35Sstevel 
95503831d35Sstevel 	return (rc);
95603831d35Sstevel }
95703831d35Sstevel 
95803831d35Sstevel void
sbbc_enable_intr(sbbc_softstate_t * softsp)95903831d35Sstevel sbbc_enable_intr(sbbc_softstate_t *softsp)
96003831d35Sstevel {
96103831d35Sstevel 	uint32_t	*pci_intr_enable_reg;
96203831d35Sstevel 
96303831d35Sstevel 	/*
96403831d35Sstevel 	 * Enable Interrupts now, turn on both INT#A lines
96503831d35Sstevel 	 */
96603831d35Sstevel 	pci_intr_enable_reg =  (uint32_t *)((char *)softsp->sbbc_regs +
967*19397407SSherry Moore 	    SBBC_PCI_INT_ENABLE);
96803831d35Sstevel 	ddi_put32(softsp->sbbc_reg_handle1, pci_intr_enable_reg,
969*19397407SSherry Moore 	    (uint32_t)SBBC_PCI_ENABLE_INT_A);
97003831d35Sstevel }
97103831d35Sstevel 
97203831d35Sstevel void
sbbc_disable_intr(sbbc_softstate_t * softsp)97303831d35Sstevel sbbc_disable_intr(sbbc_softstate_t *softsp)
97403831d35Sstevel {
97503831d35Sstevel 	uint32_t	*pci_intr_enable_reg;
97603831d35Sstevel 
97703831d35Sstevel 	/*
97803831d35Sstevel 	 * Disable Interrupts now, turn off both INT#A lines
97903831d35Sstevel 	 */
98003831d35Sstevel 	pci_intr_enable_reg =  (uint32_t *)((char *)softsp->sbbc_regs +
981*19397407SSherry Moore 	    SBBC_PCI_INT_ENABLE);
98203831d35Sstevel 	ddi_put32(softsp->sbbc_reg_handle1, pci_intr_enable_reg, 0);
98303831d35Sstevel }
984