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,
16103831d35Sstevel 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,
25403831d35Sstevel DDI_PROP_DONTPASS, "interrupts",
25503831d35Sstevel &len) != DDI_PROP_SUCCESS) {
25603831d35Sstevel SBBC_ERR1(CE_WARN, "No 'interrupts' property for the "
25703831d35Sstevel "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,
28803831d35Sstevel 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 *)
31103831d35Sstevel ((char *)softsp->sbbc_regs +
31203831d35Sstevel SBBC_PCI_INT_ENABLE);
31303831d35Sstevel
31403831d35Sstevel ddi_put32(softsp->sbbc_reg_handle1,
31503831d35Sstevel pci_intr_enable_reg,
31603831d35Sstevel (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,
32303831d35Sstevel 0, (caddr_t)&intr_in_enabled,
32403831d35Sstevel 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 *)
39103831d35Sstevel ((char *)softsp->sbbc_regs +
39203831d35Sstevel SBBC_PCI_INT_ENABLE);
39303831d35Sstevel
39403831d35Sstevel ddi_put32(softsp->sbbc_reg_handle1,
39503831d35Sstevel 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,
40203831d35Sstevel 0, (caddr_t)&intr_in_enabled,
40303831d35Sstevel 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,
41103831d35Sstevel 0, (caddr_t)&tmp_intr_enabled,
41203831d35Sstevel 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,
44703831d35Sstevel (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) &&
46803831d35Sstevel (prom_getprop(ddi_get_nodeid(dip),
46903831d35Sstevel "status", (caddr_t)status) == -1) &&
47003831d35Sstevel (prom_getprop(ddi_get_nodeid(ddi_get_parent(dip)),
47103831d35Sstevel "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,
53703831d35Sstevel (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) &&
55703831d35Sstevel (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) ==
58303831d35Sstevel SBBC_INTR_IDLE) {
58403831d35Sstevel mutex_exit(intr->sbbc_intr_lock);
58503831d35Sstevel ddi_trigger_softintr(
58603831d35Sstevel 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,
60803831d35Sstevel ddi_get32(intr_in_handle,
60903831d35Sstevel 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,
68203831d35Sstevel 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 "
70503831d35Sstevel "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,
71603831d35Sstevel DDI_PROP_DONTPASS, "interrupts",
71703831d35Sstevel &len) != DDI_PROP_SUCCESS) {
71803831d35Sstevel
71903831d35Sstevel SBBC_ERR(CE_PANIC, "No 'interrupts' property for the "
72003831d35Sstevel "'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 "
73103831d35Sstevel "'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) ||
81603831d35Sstevel (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,
83403831d35Sstevel (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,
86103831d35Sstevel (caddr_t *)&softsp->sbbc_regs,
86203831d35Sstevel SBBC_REGS_OFFSET, SBBC_REGS_SIZE,
86303831d35Sstevel &attr, &softsp->sbbc_reg_handle1) != DDI_SUCCESS) {
86403831d35Sstevel
86503831d35Sstevel cmn_err(CE_WARN, "sbbc%d: unable to map interrupt "
86603831d35Sstevel "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,
87403831d35Sstevel (caddr_t *)&softsp->epld_regs,
87503831d35Sstevel SBBC_EPLD_OFFSET, SBBC_EPLD_SIZE,
87603831d35Sstevel &attr, &softsp->sbbc_reg_handle2) != DDI_SUCCESS) {
87703831d35Sstevel
87803831d35Sstevel cmn_err(CE_WARN, "sbbc%d: unable to map EPLD "
87903831d35Sstevel "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 +
88703831d35Sstevel 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,
94703831d35Sstevel &softsp->idevice, sbbc_intr_handler,
94803831d35Sstevel (caddr_t)softsp) != DDI_SUCCESS) {
94903831d35Sstevel
95003831d35Sstevel cmn_err(CE_WARN, "Can't register SBBC "
95103831d35Sstevel " 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 +
96703831d35Sstevel SBBC_PCI_INT_ENABLE);
96803831d35Sstevel ddi_put32(softsp->sbbc_reg_handle1, pci_intr_enable_reg,
96903831d35Sstevel (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 +
98103831d35Sstevel SBBC_PCI_INT_ENABLE);
98203831d35Sstevel ddi_put32(softsp->sbbc_reg_handle1, pci_intr_enable_reg, 0);
98303831d35Sstevel }
984