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 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 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 21403831d35Sstevel _info(struct modinfo *modinfop) 21503831d35Sstevel { 21603831d35Sstevel return (mod_info(&modlinkage, modinfop)); 21703831d35Sstevel } 21803831d35Sstevel 21903831d35Sstevel static int 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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