1*03831d35Sstevel /* 2*03831d35Sstevel * CDDL HEADER START 3*03831d35Sstevel * 4*03831d35Sstevel * The contents of this file are subject to the terms of the 5*03831d35Sstevel * Common Development and Distribution License (the "License"). 6*03831d35Sstevel * You may not use this file except in compliance with the License. 7*03831d35Sstevel * 8*03831d35Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*03831d35Sstevel * or http://www.opensolaris.org/os/licensing. 10*03831d35Sstevel * See the License for the specific language governing permissions 11*03831d35Sstevel * and limitations under the License. 12*03831d35Sstevel * 13*03831d35Sstevel * When distributing Covered Code, include this CDDL HEADER in each 14*03831d35Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*03831d35Sstevel * If applicable, add the following below this CDDL HEADER, with the 16*03831d35Sstevel * fields enclosed by brackets "[]" replaced with your own identifying 17*03831d35Sstevel * information: Portions Copyright [yyyy] [name of copyright owner] 18*03831d35Sstevel * 19*03831d35Sstevel * CDDL HEADER END 20*03831d35Sstevel */ 21*03831d35Sstevel 22*03831d35Sstevel /* 23*03831d35Sstevel * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*03831d35Sstevel * Use is subject to license terms. 25*03831d35Sstevel */ 26*03831d35Sstevel 27*03831d35Sstevel #pragma ident "%Z%%M% %I% %E% SMI" 28*03831d35Sstevel 29*03831d35Sstevel /* 30*03831d35Sstevel * PCI SBBC Device Driver that provides interfaces into 31*03831d35Sstevel * EPLD and IO-SRAM 32*03831d35Sstevel * 33*03831d35Sstevel */ 34*03831d35Sstevel #include <sys/types.h> 35*03831d35Sstevel #include <sys/param.h> 36*03831d35Sstevel #include <sys/errno.h> 37*03831d35Sstevel #include <sys/file.h> 38*03831d35Sstevel #include <sys/cmn_err.h> 39*03831d35Sstevel #include <sys/stropts.h> 40*03831d35Sstevel #include <sys/kmem.h> 41*03831d35Sstevel #include <sys/sunndi.h> 42*03831d35Sstevel #include <sys/conf.h> /* req. by dev_ops flags MTSAFE etc. */ 43*03831d35Sstevel #include <sys/modctl.h> /* for modldrv */ 44*03831d35Sstevel #include <sys/promif.h> 45*03831d35Sstevel #include <sys/stat.h> 46*03831d35Sstevel #include <sys/ddi.h> 47*03831d35Sstevel 48*03831d35Sstevel #include <sys/serengeti.h> 49*03831d35Sstevel #include <sys/sgsbbc_priv.h> 50*03831d35Sstevel #include <sys/sgsbbc_iosram_priv.h> 51*03831d35Sstevel #include <sys/sgsbbc_mailbox_priv.h> 52*03831d35Sstevel 53*03831d35Sstevel #ifdef DEBUG 54*03831d35Sstevel /* debug flag */ 55*03831d35Sstevel uint_t sgsbbc_debug = 0; 56*03831d35Sstevel #endif /* DEBUG */ 57*03831d35Sstevel 58*03831d35Sstevel /* driver entry point fn definitions */ 59*03831d35Sstevel static int sbbc_attach(dev_info_t *, ddi_attach_cmd_t); 60*03831d35Sstevel static int sbbc_detach(dev_info_t *, ddi_detach_cmd_t); 61*03831d35Sstevel 62*03831d35Sstevel /* 63*03831d35Sstevel * SBBC soft state hook 64*03831d35Sstevel */ 65*03831d35Sstevel static void *sbbcp; 66*03831d35Sstevel 67*03831d35Sstevel /* 68*03831d35Sstevel * Chosen IOSRAM 69*03831d35Sstevel */ 70*03831d35Sstevel struct chosen_iosram *master_iosram = NULL; 71*03831d35Sstevel 72*03831d35Sstevel /* 73*03831d35Sstevel * define new iosram's sbbc and liked list of sbbc. 74*03831d35Sstevel */ 75*03831d35Sstevel struct sbbc_softstate *sgsbbc_instances = NULL; 76*03831d35Sstevel 77*03831d35Sstevel /* 78*03831d35Sstevel * At attach time, check if the device is the 'chosen' node 79*03831d35Sstevel * if it is, set up the IOSRAM Solaris<->SC Comm tunnel 80*03831d35Sstevel * Its like 'Highlander' - there can be only one ! 81*03831d35Sstevel */ 82*03831d35Sstevel static int master_chosen = FALSE; 83*03831d35Sstevel kmutex_t chosen_lock; 84*03831d35Sstevel 85*03831d35Sstevel /* 86*03831d35Sstevel * Local variable to save intr_in_enabled when the driver is suspended 87*03831d35Sstevel */ 88*03831d35Sstevel static uint32_t intr_in_enabled; 89*03831d35Sstevel 90*03831d35Sstevel /* 91*03831d35Sstevel * Local declarations 92*03831d35Sstevel */ 93*03831d35Sstevel static void softsp_init(sbbc_softstate_t *, dev_info_t *); 94*03831d35Sstevel static void sbbc_chosen_init(sbbc_softstate_t *); 95*03831d35Sstevel static void sbbc_add_instance(sbbc_softstate_t *); 96*03831d35Sstevel static void sbbc_remove_instance(sbbc_softstate_t *); 97*03831d35Sstevel static int sbbc_find_dip(dev_info_t *, void *); 98*03831d35Sstevel static void sbbc_unmap_regs(sbbc_softstate_t *); 99*03831d35Sstevel 100*03831d35Sstevel /* 101*03831d35Sstevel * ops stuff. 102*03831d35Sstevel */ 103*03831d35Sstevel static struct cb_ops sbbc_cb_ops = { 104*03831d35Sstevel nodev, /* cb_open */ 105*03831d35Sstevel nodev, /* cb_close */ 106*03831d35Sstevel nodev, /* cb_strategy */ 107*03831d35Sstevel nodev, /* cb_print */ 108*03831d35Sstevel nodev, /* cb_dump */ 109*03831d35Sstevel nodev, /* cb_read */ 110*03831d35Sstevel nodev, /* cb_write */ 111*03831d35Sstevel nodev, /* cb_ioctl */ 112*03831d35Sstevel nodev, /* cb_devmap */ 113*03831d35Sstevel nodev, /* cb_mmap */ 114*03831d35Sstevel nodev, /* cb_segmap */ 115*03831d35Sstevel nochpoll, /* cb_chpoll */ 116*03831d35Sstevel ddi_prop_op, /* cb_prop_op */ 117*03831d35Sstevel NULL, /* cb_stream */ 118*03831d35Sstevel D_NEW | D_MP /* cb_flag */ 119*03831d35Sstevel }; 120*03831d35Sstevel 121*03831d35Sstevel /* 122*03831d35Sstevel * Declare ops vectors for auto configuration. 123*03831d35Sstevel */ 124*03831d35Sstevel struct dev_ops sbbc_ops = { 125*03831d35Sstevel DEVO_REV, /* devo_rev */ 126*03831d35Sstevel 0, /* devo_refcnt */ 127*03831d35Sstevel ddi_getinfo_1to1, /* devo_getinfo */ 128*03831d35Sstevel nulldev, /* devo_identify */ 129*03831d35Sstevel nulldev, /* devo_probe */ 130*03831d35Sstevel sbbc_attach, /* devo_attach */ 131*03831d35Sstevel sbbc_detach, /* devo_detach */ 132*03831d35Sstevel nodev, /* devo_reset */ 133*03831d35Sstevel &sbbc_cb_ops, /* devo_cb_ops */ 134*03831d35Sstevel (struct bus_ops *)NULL, /* devo_bus_ops */ 135*03831d35Sstevel nulldev /* devo_power */ 136*03831d35Sstevel }; 137*03831d35Sstevel 138*03831d35Sstevel /* 139*03831d35Sstevel * Loadable module support. 140*03831d35Sstevel */ 141*03831d35Sstevel extern struct mod_ops mod_driverops; 142*03831d35Sstevel 143*03831d35Sstevel static struct modldrv modldrv = { 144*03831d35Sstevel &mod_driverops, /* type of module - driver */ 145*03831d35Sstevel "PCI SBBC %I%", 146*03831d35Sstevel &sbbc_ops, 147*03831d35Sstevel }; 148*03831d35Sstevel 149*03831d35Sstevel static struct modlinkage modlinkage = { 150*03831d35Sstevel MODREV_1, 151*03831d35Sstevel (void *)&modldrv, 152*03831d35Sstevel NULL 153*03831d35Sstevel }; 154*03831d35Sstevel 155*03831d35Sstevel int 156*03831d35Sstevel _init(void) 157*03831d35Sstevel { 158*03831d35Sstevel int error; 159*03831d35Sstevel 160*03831d35Sstevel if ((error = ddi_soft_state_init(&sbbcp, 161*03831d35Sstevel sizeof (sbbc_softstate_t), 1)) != 0) 162*03831d35Sstevel return (error); 163*03831d35Sstevel 164*03831d35Sstevel if ((error = mod_install(&modlinkage)) != 0) { 165*03831d35Sstevel ddi_soft_state_fini(&sbbcp); 166*03831d35Sstevel return (error); 167*03831d35Sstevel } 168*03831d35Sstevel 169*03831d35Sstevel /* 170*03831d35Sstevel * Initialise the global 'chosen' IOSRAM mutex 171*03831d35Sstevel */ 172*03831d35Sstevel mutex_init(&chosen_lock, NULL, MUTEX_DEFAULT, NULL); 173*03831d35Sstevel 174*03831d35Sstevel /* 175*03831d35Sstevel * Initialise the iosram driver 176*03831d35Sstevel */ 177*03831d35Sstevel iosram_init(); 178*03831d35Sstevel 179*03831d35Sstevel /* 180*03831d35Sstevel * Initialize the mailbox 181*03831d35Sstevel */ 182*03831d35Sstevel sbbc_mbox_init(); 183*03831d35Sstevel 184*03831d35Sstevel return (error); 185*03831d35Sstevel 186*03831d35Sstevel } 187*03831d35Sstevel 188*03831d35Sstevel int 189*03831d35Sstevel _fini(void) 190*03831d35Sstevel { 191*03831d35Sstevel int error; 192*03831d35Sstevel 193*03831d35Sstevel if ((error = mod_remove(&modlinkage)) == 0) 194*03831d35Sstevel ddi_soft_state_fini(&sbbcp); 195*03831d35Sstevel 196*03831d35Sstevel master_chosen = FALSE; 197*03831d35Sstevel 198*03831d35Sstevel mutex_destroy(&chosen_lock); 199*03831d35Sstevel 200*03831d35Sstevel /* 201*03831d35Sstevel * remove the mailbox 202*03831d35Sstevel */ 203*03831d35Sstevel sbbc_mbox_fini(); 204*03831d35Sstevel 205*03831d35Sstevel /* 206*03831d35Sstevel * remove the iosram driver 207*03831d35Sstevel */ 208*03831d35Sstevel iosram_fini(); 209*03831d35Sstevel 210*03831d35Sstevel return (error); 211*03831d35Sstevel } 212*03831d35Sstevel 213*03831d35Sstevel int 214*03831d35Sstevel _info(struct modinfo *modinfop) 215*03831d35Sstevel { 216*03831d35Sstevel return (mod_info(&modlinkage, modinfop)); 217*03831d35Sstevel } 218*03831d35Sstevel 219*03831d35Sstevel static int 220*03831d35Sstevel sbbc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 221*03831d35Sstevel { 222*03831d35Sstevel int instance; 223*03831d35Sstevel sbbc_softstate_t *softsp; 224*03831d35Sstevel uint32_t *pci_intr_enable_reg; 225*03831d35Sstevel int len; 226*03831d35Sstevel #ifdef DEBUG 227*03831d35Sstevel char name[8]; 228*03831d35Sstevel #endif /* DEBUG */ 229*03831d35Sstevel 230*03831d35Sstevel instance = ddi_get_instance(devi); 231*03831d35Sstevel 232*03831d35Sstevel switch (cmd) { 233*03831d35Sstevel case DDI_ATTACH: 234*03831d35Sstevel 235*03831d35Sstevel if (ddi_soft_state_zalloc(sbbcp, instance) != 0) 236*03831d35Sstevel return (DDI_FAILURE); 237*03831d35Sstevel 238*03831d35Sstevel softsp = ddi_get_soft_state(sbbcp, instance); 239*03831d35Sstevel softsp->sbbc_instance = instance; 240*03831d35Sstevel 241*03831d35Sstevel /* 242*03831d35Sstevel * Set the dip in the soft state 243*03831d35Sstevel * And get interrupt cookies and initialize the 244*03831d35Sstevel * per instance mutex. 245*03831d35Sstevel */ 246*03831d35Sstevel softsp_init(softsp, devi); 247*03831d35Sstevel 248*03831d35Sstevel 249*03831d35Sstevel /* 250*03831d35Sstevel * Verify that an 'interrupts' property exists for 251*03831d35Sstevel * this device. If not, this instance will be ignored. 252*03831d35Sstevel */ 253*03831d35Sstevel if (ddi_getproplen(DDI_DEV_T_ANY, softsp->dip, 254*03831d35Sstevel DDI_PROP_DONTPASS, "interrupts", 255*03831d35Sstevel &len) != DDI_PROP_SUCCESS) { 256*03831d35Sstevel SBBC_ERR1(CE_WARN, "No 'interrupts' property for the " 257*03831d35Sstevel "SBBC instance %d\n", instance); 258*03831d35Sstevel return (DDI_FAILURE); 259*03831d35Sstevel } 260*03831d35Sstevel /* 261*03831d35Sstevel * Add this instance to the sbbc chosen iosram list 262*03831d35Sstevel * so that it can be used for tunnel switch. 263*03831d35Sstevel */ 264*03831d35Sstevel mutex_enter(&chosen_lock); 265*03831d35Sstevel softsp->sbbc_state = SBBC_STATE_INIT; 266*03831d35Sstevel sbbc_add_instance(softsp); 267*03831d35Sstevel 268*03831d35Sstevel /* 269*03831d35Sstevel * If this is the chosen IOSRAM and there is no master IOSRAM 270*03831d35Sstevel * yet, then let's set this instance as the master. 271*03831d35Sstevel * if there is a master alreay due to the previous tunnel switch 272*03831d35Sstevel * then keep as is even though this is the chosen. 273*03831d35Sstevel */ 274*03831d35Sstevel if (sgsbbc_iosram_is_chosen(softsp)) { 275*03831d35Sstevel ASSERT(master_iosram); 276*03831d35Sstevel softsp->iosram = master_iosram; 277*03831d35Sstevel master_iosram->sgsbbc = softsp; 278*03831d35Sstevel 279*03831d35Sstevel /* Do 'chosen' init only */ 280*03831d35Sstevel sbbc_chosen_init(softsp); 281*03831d35Sstevel } 282*03831d35Sstevel 283*03831d35Sstevel mutex_exit(&chosen_lock); 284*03831d35Sstevel #ifdef DEBUG 285*03831d35Sstevel (void) sprintf(name, "sbbc%d", instance); 286*03831d35Sstevel 287*03831d35Sstevel if (ddi_create_minor_node(devi, name, S_IFCHR, instance, 288*03831d35Sstevel NULL, NULL) == DDI_FAILURE) { 289*03831d35Sstevel mutex_destroy(&softsp->sbbc_lock); 290*03831d35Sstevel ddi_remove_minor_node(devi, NULL); 291*03831d35Sstevel ddi_soft_state_free(sbbcp, instance); 292*03831d35Sstevel return (DDI_FAILURE); 293*03831d35Sstevel } 294*03831d35Sstevel #endif /* DEBUG */ 295*03831d35Sstevel 296*03831d35Sstevel ddi_report_dev(devi); 297*03831d35Sstevel 298*03831d35Sstevel return (DDI_SUCCESS); 299*03831d35Sstevel 300*03831d35Sstevel case DDI_RESUME: 301*03831d35Sstevel 302*03831d35Sstevel if (!(softsp = ddi_get_soft_state(sbbcp, instance))) 303*03831d35Sstevel return (DDI_FAILURE); 304*03831d35Sstevel 305*03831d35Sstevel mutex_enter(&softsp->sbbc_lock); 306*03831d35Sstevel if ((softsp->suspended == TRUE) && (softsp->chosen == TRUE)) { 307*03831d35Sstevel /* 308*03831d35Sstevel * Enable Interrupts now, turn on both INT#A lines 309*03831d35Sstevel */ 310*03831d35Sstevel pci_intr_enable_reg = (uint32_t *) 311*03831d35Sstevel ((char *)softsp->sbbc_regs + 312*03831d35Sstevel SBBC_PCI_INT_ENABLE); 313*03831d35Sstevel 314*03831d35Sstevel ddi_put32(softsp->sbbc_reg_handle1, 315*03831d35Sstevel pci_intr_enable_reg, 316*03831d35Sstevel (uint32_t)SBBC_PCI_ENABLE_INT_A); 317*03831d35Sstevel 318*03831d35Sstevel /* 319*03831d35Sstevel * Reset intr_in_enabled to the original value 320*03831d35Sstevel * so the SC can send us interrupt. 321*03831d35Sstevel */ 322*03831d35Sstevel if (iosram_write(SBBC_SC_INTR_ENABLED_KEY, 323*03831d35Sstevel 0, (caddr_t)&intr_in_enabled, 324*03831d35Sstevel sizeof (intr_in_enabled))) { 325*03831d35Sstevel 326*03831d35Sstevel mutex_exit(&softsp->sbbc_lock); 327*03831d35Sstevel return (DDI_FAILURE); 328*03831d35Sstevel } 329*03831d35Sstevel } 330*03831d35Sstevel softsp->suspended = FALSE; 331*03831d35Sstevel 332*03831d35Sstevel mutex_exit(&softsp->sbbc_lock); 333*03831d35Sstevel 334*03831d35Sstevel return (DDI_SUCCESS); 335*03831d35Sstevel 336*03831d35Sstevel default: 337*03831d35Sstevel return (DDI_FAILURE); 338*03831d35Sstevel } 339*03831d35Sstevel } 340*03831d35Sstevel 341*03831d35Sstevel static int 342*03831d35Sstevel sbbc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 343*03831d35Sstevel { 344*03831d35Sstevel sbbc_softstate_t *softsp; 345*03831d35Sstevel int instance; 346*03831d35Sstevel uint32_t *pci_intr_enable_reg; 347*03831d35Sstevel int rc = DDI_SUCCESS; 348*03831d35Sstevel 349*03831d35Sstevel instance = ddi_get_instance(devi); 350*03831d35Sstevel 351*03831d35Sstevel if (!(softsp = ddi_get_soft_state(sbbcp, instance))) 352*03831d35Sstevel return (DDI_FAILURE); 353*03831d35Sstevel 354*03831d35Sstevel switch (cmd) { 355*03831d35Sstevel case DDI_DETACH: 356*03831d35Sstevel mutex_enter(&chosen_lock); 357*03831d35Sstevel softsp->sbbc_state |= SBBC_STATE_DETACH; 358*03831d35Sstevel mutex_exit(&chosen_lock); 359*03831d35Sstevel 360*03831d35Sstevel /* only tunnel switch the instance with iosram chosen */ 361*03831d35Sstevel if (softsp->chosen == TRUE) { 362*03831d35Sstevel if (sgsbbc_iosram_switchfrom(softsp) == DDI_FAILURE) { 363*03831d35Sstevel SBBC_ERR(CE_WARN, "Cannot unconfigure: " 364*03831d35Sstevel "tunnel switch failed\n"); 365*03831d35Sstevel return (DDI_FAILURE); 366*03831d35Sstevel } 367*03831d35Sstevel } 368*03831d35Sstevel 369*03831d35Sstevel /* Adjust linked list */ 370*03831d35Sstevel mutex_enter(&chosen_lock); 371*03831d35Sstevel sbbc_remove_instance(softsp); 372*03831d35Sstevel mutex_exit(&chosen_lock); 373*03831d35Sstevel 374*03831d35Sstevel sbbc_unmap_regs(softsp); 375*03831d35Sstevel mutex_destroy(&softsp->sbbc_lock); 376*03831d35Sstevel ddi_soft_state_free(sbbcp, instance); 377*03831d35Sstevel 378*03831d35Sstevel return (DDI_SUCCESS); 379*03831d35Sstevel 380*03831d35Sstevel case DDI_SUSPEND: 381*03831d35Sstevel 382*03831d35Sstevel mutex_enter(&softsp->sbbc_lock); 383*03831d35Sstevel 384*03831d35Sstevel if ((softsp->suspended == FALSE) && (softsp->chosen == TRUE)) { 385*03831d35Sstevel uint32_t tmp_intr_enabled = 0; 386*03831d35Sstevel 387*03831d35Sstevel /* 388*03831d35Sstevel * Disable Interrupts now, turn OFF both INT#A lines 389*03831d35Sstevel */ 390*03831d35Sstevel pci_intr_enable_reg = (uint32_t *) 391*03831d35Sstevel ((char *)softsp->sbbc_regs + 392*03831d35Sstevel SBBC_PCI_INT_ENABLE); 393*03831d35Sstevel 394*03831d35Sstevel ddi_put32(softsp->sbbc_reg_handle1, 395*03831d35Sstevel pci_intr_enable_reg, 0); 396*03831d35Sstevel 397*03831d35Sstevel /* 398*03831d35Sstevel * Set intr_in_enabled to 0 so the SC won't send 399*03831d35Sstevel * us interrupt. 400*03831d35Sstevel */ 401*03831d35Sstevel rc = iosram_read(SBBC_SC_INTR_ENABLED_KEY, 402*03831d35Sstevel 0, (caddr_t)&intr_in_enabled, 403*03831d35Sstevel sizeof (intr_in_enabled)); 404*03831d35Sstevel 405*03831d35Sstevel if (rc) { 406*03831d35Sstevel mutex_exit(&softsp->sbbc_lock); 407*03831d35Sstevel return (DDI_FAILURE); 408*03831d35Sstevel } 409*03831d35Sstevel 410*03831d35Sstevel rc = iosram_write(SBBC_SC_INTR_ENABLED_KEY, 411*03831d35Sstevel 0, (caddr_t)&tmp_intr_enabled, 412*03831d35Sstevel sizeof (tmp_intr_enabled)); 413*03831d35Sstevel 414*03831d35Sstevel if (rc) { 415*03831d35Sstevel mutex_exit(&softsp->sbbc_lock); 416*03831d35Sstevel return (DDI_FAILURE); 417*03831d35Sstevel } 418*03831d35Sstevel } 419*03831d35Sstevel softsp->suspended = TRUE; 420*03831d35Sstevel 421*03831d35Sstevel mutex_exit(&softsp->sbbc_lock); 422*03831d35Sstevel 423*03831d35Sstevel return (DDI_SUCCESS); 424*03831d35Sstevel 425*03831d35Sstevel default: 426*03831d35Sstevel return (DDI_FAILURE); 427*03831d35Sstevel } 428*03831d35Sstevel 429*03831d35Sstevel } 430*03831d35Sstevel 431*03831d35Sstevel static void 432*03831d35Sstevel softsp_init(sbbc_softstate_t *softsp, dev_info_t *devi) 433*03831d35Sstevel { 434*03831d35Sstevel softsp->dip = devi; 435*03831d35Sstevel 436*03831d35Sstevel /* 437*03831d35Sstevel * XXXX 438*03831d35Sstevel * ddi_get_iblock_cookie() here because we need 439*03831d35Sstevel * to initialise the mutex regardless of whether 440*03831d35Sstevel * or not this SBBC will eventually 441*03831d35Sstevel * register an interrupt handler 442*03831d35Sstevel */ 443*03831d35Sstevel 444*03831d35Sstevel (void) ddi_get_iblock_cookie(devi, 0, &softsp->iblock); 445*03831d35Sstevel 446*03831d35Sstevel mutex_init(&softsp->sbbc_lock, NULL, MUTEX_DRIVER, 447*03831d35Sstevel (void *)softsp->iblock); 448*03831d35Sstevel 449*03831d35Sstevel softsp->suspended = FALSE; 450*03831d35Sstevel softsp->chosen = FALSE; 451*03831d35Sstevel } 452*03831d35Sstevel 453*03831d35Sstevel static int 454*03831d35Sstevel sbbc_find_dip(dev_info_t *dip, void *arg) 455*03831d35Sstevel { 456*03831d35Sstevel char *node_name; 457*03831d35Sstevel sbbc_find_dip_t *dip_struct = (sbbc_find_dip_t *)arg; 458*03831d35Sstevel char status[OBP_MAXPROPNAME]; 459*03831d35Sstevel 460*03831d35Sstevel /* 461*03831d35Sstevel * Need to find a node named "bootbus-controller" that is neither 462*03831d35Sstevel * disabled nor failed. If a node is not ok, there will be an 463*03831d35Sstevel * OBP status property. Therefore, we will look for a node 464*03831d35Sstevel * without the status property. 465*03831d35Sstevel */ 466*03831d35Sstevel node_name = ddi_node_name(dip); 467*03831d35Sstevel if (strcmp(node_name, "bootbus-controller") == 0 && DDI_CF2(dip) && 468*03831d35Sstevel (prom_getprop(ddi_get_nodeid(dip), 469*03831d35Sstevel "status", (caddr_t)status) == -1) && 470*03831d35Sstevel (prom_getprop(ddi_get_nodeid(ddi_get_parent(dip)), 471*03831d35Sstevel "status", (caddr_t)status) == -1)) { 472*03831d35Sstevel 473*03831d35Sstevel if (dip != dip_struct->cur_dip) { 474*03831d35Sstevel dip_struct->new_dip = (void *)dip; 475*03831d35Sstevel return (DDI_WALK_TERMINATE); 476*03831d35Sstevel } 477*03831d35Sstevel } 478*03831d35Sstevel 479*03831d35Sstevel return (DDI_WALK_CONTINUE); 480*03831d35Sstevel } 481*03831d35Sstevel 482*03831d35Sstevel /* 483*03831d35Sstevel * SBBC Interrupt Handler 484*03831d35Sstevel * 485*03831d35Sstevel * Check the SBBC Port Interrupt Status 486*03831d35Sstevel * register to verify that its our interrupt. 487*03831d35Sstevel * If yes, clear the register. 488*03831d35Sstevel * 489*03831d35Sstevel * Then read the 'interrupt reason' field from SRAM, 490*03831d35Sstevel * this triggers the appropriate soft_intr handler 491*03831d35Sstevel */ 492*03831d35Sstevel uint_t 493*03831d35Sstevel sbbc_intr_handler(caddr_t arg) 494*03831d35Sstevel { 495*03831d35Sstevel sbbc_softstate_t *softsp = (sbbc_softstate_t *)arg; 496*03831d35Sstevel uint32_t *port_int_reg; 497*03831d35Sstevel volatile uint32_t port_int_status; 498*03831d35Sstevel volatile uint32_t intr_reason; 499*03831d35Sstevel uint32_t intr_enabled; 500*03831d35Sstevel sbbc_intrs_t *intr; 501*03831d35Sstevel int i, intr_mask; 502*03831d35Sstevel struct tunnel_key tunnel_key; 503*03831d35Sstevel ddi_acc_handle_t intr_in_handle; 504*03831d35Sstevel uint32_t *intr_in_reason; 505*03831d35Sstevel 506*03831d35Sstevel if (softsp == (sbbc_softstate_t *)NULL) { 507*03831d35Sstevel 508*03831d35Sstevel return (DDI_INTR_UNCLAIMED); 509*03831d35Sstevel } 510*03831d35Sstevel 511*03831d35Sstevel mutex_enter(&softsp->sbbc_lock); 512*03831d35Sstevel 513*03831d35Sstevel if (softsp->port_int_regs == NULL) { 514*03831d35Sstevel mutex_exit(&softsp->sbbc_lock); 515*03831d35Sstevel return (DDI_INTR_UNCLAIMED); 516*03831d35Sstevel } 517*03831d35Sstevel 518*03831d35Sstevel /* 519*03831d35Sstevel * Normally if port_int_status is 0, we assume it is not 520*03831d35Sstevel * our interrupt. However, we don't want to miss the 521*03831d35Sstevel * ones that come in during tunnel switch. Therefore, 522*03831d35Sstevel * we always check the interrupt reason bits in IOSRAM 523*03831d35Sstevel * to be sure. 524*03831d35Sstevel */ 525*03831d35Sstevel port_int_reg = softsp->port_int_regs; 526*03831d35Sstevel 527*03831d35Sstevel port_int_status = ddi_get32(softsp->sbbc_reg_handle1, port_int_reg); 528*03831d35Sstevel 529*03831d35Sstevel /* 530*03831d35Sstevel * Generate a softint for each interrupt 531*03831d35Sstevel * bit set in the intr_in_reason field in SRAM 532*03831d35Sstevel * that has a corresponding bit set in the 533*03831d35Sstevel * intr_in_enabled field in SRAM 534*03831d35Sstevel */ 535*03831d35Sstevel 536*03831d35Sstevel if (iosram_read(SBBC_SC_INTR_ENABLED_KEY, 0, 537*03831d35Sstevel (caddr_t)&intr_enabled, sizeof (intr_enabled))) { 538*03831d35Sstevel 539*03831d35Sstevel goto intr_handler_exit; 540*03831d35Sstevel } 541*03831d35Sstevel 542*03831d35Sstevel tunnel_key = master_iosram->tunnel->tunnel_keys[SBBC_SC_INTR_KEY]; 543*03831d35Sstevel intr_in_reason = (uint32_t *)tunnel_key.base; 544*03831d35Sstevel intr_in_handle = tunnel_key.reg_handle; 545*03831d35Sstevel 546*03831d35Sstevel intr_reason = ddi_get32(intr_in_handle, intr_in_reason); 547*03831d35Sstevel 548*03831d35Sstevel SGSBBC_DBG_INTR(CE_CONT, "intr_reason = %x\n", intr_reason); 549*03831d35Sstevel 550*03831d35Sstevel intr_reason &= intr_enabled; 551*03831d35Sstevel 552*03831d35Sstevel for (i = 0; i < SBBC_MAX_INTRS; i++) { 553*03831d35Sstevel intr_mask = (1 << i); 554*03831d35Sstevel if (intr_reason & intr_mask) { 555*03831d35Sstevel intr = &softsp->intr_hdlrs[i]; 556*03831d35Sstevel if ((intr != NULL) && 557*03831d35Sstevel (intr->sbbc_intr_id != 0)) { 558*03831d35Sstevel /* 559*03831d35Sstevel * XXXX 560*03831d35Sstevel * The model we agree with a handler 561*03831d35Sstevel * is that they run until they have 562*03831d35Sstevel * exhausted all work. To avoid 563*03831d35Sstevel * triggering them again, they pass 564*03831d35Sstevel * a state flag and lock when registering. 565*03831d35Sstevel * We check the flag, if they are idle, 566*03831d35Sstevel * we trigger. 567*03831d35Sstevel * The interrupt handler should so 568*03831d35Sstevel * intr_func() 569*03831d35Sstevel * mutex_enter(sbbc_intr_lock); 570*03831d35Sstevel * sbbc_intr_state = RUNNING; 571*03831d35Sstevel * mutex_exit(sbbc_intr_lock); 572*03831d35Sstevel * .......... 573*03831d35Sstevel * .......... 574*03831d35Sstevel * .......... 575*03831d35Sstevel * mutex_enter(sbbc_intr_lock); 576*03831d35Sstevel * sbbc_intr_state = IDLE; 577*03831d35Sstevel * mutex_exit(sbbc_intr_lock); 578*03831d35Sstevel * 579*03831d35Sstevel * XXXX 580*03831d35Sstevel */ 581*03831d35Sstevel mutex_enter(intr->sbbc_intr_lock); 582*03831d35Sstevel if (*(intr->sbbc_intr_state) == 583*03831d35Sstevel SBBC_INTR_IDLE) { 584*03831d35Sstevel mutex_exit(intr->sbbc_intr_lock); 585*03831d35Sstevel ddi_trigger_softintr( 586*03831d35Sstevel intr->sbbc_intr_id); 587*03831d35Sstevel } else { 588*03831d35Sstevel /* 589*03831d35Sstevel * The handler is running 590*03831d35Sstevel */ 591*03831d35Sstevel mutex_exit(intr->sbbc_intr_lock); 592*03831d35Sstevel } 593*03831d35Sstevel intr_reason &= ~intr_mask; 594*03831d35Sstevel /* 595*03831d35Sstevel * Clear the corresponding reason bit in SRAM 596*03831d35Sstevel * 597*03831d35Sstevel * Since there is no interlocking between 598*03831d35Sstevel * Solaris and the SC when writing to SRAM, 599*03831d35Sstevel * it is possible for the SC to set another 600*03831d35Sstevel * bit in the interrupt reason field while 601*03831d35Sstevel * we are handling the current interrupt. 602*03831d35Sstevel * To minimize the window in which an 603*03831d35Sstevel * additional bit can be set, reading 604*03831d35Sstevel * and writing the interrupt reason 605*03831d35Sstevel * in SRAM must be as close as possible. 606*03831d35Sstevel */ 607*03831d35Sstevel ddi_put32(intr_in_handle, intr_in_reason, 608*03831d35Sstevel ddi_get32(intr_in_handle, 609*03831d35Sstevel intr_in_reason) & ~intr_mask); 610*03831d35Sstevel } 611*03831d35Sstevel } 612*03831d35Sstevel if (intr_reason == 0) /* No more interrupts to be processed */ 613*03831d35Sstevel break; 614*03831d35Sstevel } 615*03831d35Sstevel 616*03831d35Sstevel /* 617*03831d35Sstevel * Clear the Interrupt Status Register (RW1C) 618*03831d35Sstevel */ 619*03831d35Sstevel ddi_put32(softsp->sbbc_reg_handle1, port_int_reg, port_int_status); 620*03831d35Sstevel 621*03831d35Sstevel port_int_status = ddi_get32(softsp->sbbc_reg_handle1, port_int_reg); 622*03831d35Sstevel 623*03831d35Sstevel intr_handler_exit: 624*03831d35Sstevel 625*03831d35Sstevel mutex_exit(&softsp->sbbc_lock); 626*03831d35Sstevel 627*03831d35Sstevel return (DDI_INTR_CLAIMED); 628*03831d35Sstevel 629*03831d35Sstevel } 630*03831d35Sstevel 631*03831d35Sstevel /* 632*03831d35Sstevel * If we don't already have a master SBBC selected, 633*03831d35Sstevel * get the <sbbc> property from the /chosen node. If 634*03831d35Sstevel * the pathname matches, this is the master SBBC and 635*03831d35Sstevel * we set up the console/TOD SRAM mapping here. 636*03831d35Sstevel */ 637*03831d35Sstevel static void 638*03831d35Sstevel sbbc_chosen_init(sbbc_softstate_t *softsp) 639*03831d35Sstevel { 640*03831d35Sstevel char master_sbbc[MAXNAMELEN]; 641*03831d35Sstevel char pn[MAXNAMELEN]; 642*03831d35Sstevel int nodeid, len; 643*03831d35Sstevel pnode_t dnode; 644*03831d35Sstevel 645*03831d35Sstevel if (master_chosen != FALSE) { 646*03831d35Sstevel /* 647*03831d35Sstevel * We've got one already 648*03831d35Sstevel */ 649*03831d35Sstevel return; 650*03831d35Sstevel } 651*03831d35Sstevel 652*03831d35Sstevel /* 653*03831d35Sstevel * Get /chosen node info. prom interface will handle errors. 654*03831d35Sstevel */ 655*03831d35Sstevel dnode = prom_chosennode(); 656*03831d35Sstevel 657*03831d35Sstevel /* 658*03831d35Sstevel * Look for the "iosram" property on the chosen node with a prom 659*03831d35Sstevel * interface as ddi_find_devinfo() couldn't be used (calls 660*03831d35Sstevel * ddi_walk_devs() that creates one extra lock on the device tree). 661*03831d35Sstevel */ 662*03831d35Sstevel if (prom_getprop(dnode, IOSRAM_CHOSEN_PROP, (caddr_t)&nodeid) <= 0) { 663*03831d35Sstevel /* 664*03831d35Sstevel * No I/O Board SBBC set up as console, what to do ? 665*03831d35Sstevel */ 666*03831d35Sstevel SBBC_ERR(CE_PANIC, "No SBBC found for Console/TOD \n"); 667*03831d35Sstevel } 668*03831d35Sstevel 669*03831d35Sstevel if (prom_getprop(dnode, IOSRAM_TOC_PROP, 670*03831d35Sstevel (caddr_t)&softsp->sram_toc) <= 0) { 671*03831d35Sstevel /* 672*03831d35Sstevel * SRAM TOC Offset defaults to 0 673*03831d35Sstevel */ 674*03831d35Sstevel SBBC_ERR(CE_WARN, "No SBBC TOC Offset found\n"); 675*03831d35Sstevel softsp->sram_toc = 0; 676*03831d35Sstevel } 677*03831d35Sstevel 678*03831d35Sstevel /* 679*03831d35Sstevel * get the full OBP pathname of this node 680*03831d35Sstevel */ 681*03831d35Sstevel if (prom_phandle_to_path((phandle_t)nodeid, master_sbbc, 682*03831d35Sstevel sizeof (master_sbbc)) < 0) { 683*03831d35Sstevel 684*03831d35Sstevel SBBC_ERR1(CE_PANIC, "prom_phandle_to_path(%d) failed\n", 685*03831d35Sstevel nodeid); 686*03831d35Sstevel } 687*03831d35Sstevel SGSBBC_DBG_ALL("chosen pathname : %s\n", master_sbbc); 688*03831d35Sstevel SGSBBC_DBG_ALL("device pathname : %s\n", ddi_pathname(softsp->dip, pn)); 689*03831d35Sstevel if (strcmp(master_sbbc, ddi_pathname(softsp->dip, pn)) == 0) { 690*03831d35Sstevel 691*03831d35Sstevel /* 692*03831d35Sstevel * map in the SBBC regs 693*03831d35Sstevel */ 694*03831d35Sstevel 695*03831d35Sstevel if (sbbc_map_regs(softsp) != DDI_SUCCESS) { 696*03831d35Sstevel SBBC_ERR(CE_PANIC, "Can't map the SBBC regs \n"); 697*03831d35Sstevel } 698*03831d35Sstevel /* 699*03831d35Sstevel * Only the 'chosen' node is used for iosram_read()/_write() 700*03831d35Sstevel * Must initialise the tunnel before the console/tod 701*03831d35Sstevel * 702*03831d35Sstevel */ 703*03831d35Sstevel if (iosram_tunnel_init(softsp) == DDI_FAILURE) { 704*03831d35Sstevel SBBC_ERR(CE_PANIC, "Can't create the SRAM <-> SC " 705*03831d35Sstevel "comm. tunnel \n"); 706*03831d35Sstevel } 707*03831d35Sstevel 708*03831d35Sstevel master_chosen = TRUE; 709*03831d35Sstevel 710*03831d35Sstevel /* 711*03831d35Sstevel * Verify that an 'interrupts' property 712*03831d35Sstevel * exists for this device 713*03831d35Sstevel */ 714*03831d35Sstevel 715*03831d35Sstevel if (ddi_getproplen(DDI_DEV_T_ANY, softsp->dip, 716*03831d35Sstevel DDI_PROP_DONTPASS, "interrupts", 717*03831d35Sstevel &len) != DDI_PROP_SUCCESS) { 718*03831d35Sstevel 719*03831d35Sstevel SBBC_ERR(CE_PANIC, "No 'interrupts' property for the " 720*03831d35Sstevel "'chosen' SBBC \n"); 721*03831d35Sstevel } 722*03831d35Sstevel 723*03831d35Sstevel /* 724*03831d35Sstevel * add the interrupt handler 725*03831d35Sstevel * NB 726*03831d35Sstevel * should this be a high-level interrupt ? 727*03831d35Sstevel * NB 728*03831d35Sstevel */ 729*03831d35Sstevel if (sbbc_add_intr(softsp) == DDI_FAILURE) { 730*03831d35Sstevel SBBC_ERR(CE_PANIC, "Can't add interrupt handler for " 731*03831d35Sstevel "'chosen' SBBC \n"); 732*03831d35Sstevel } 733*03831d35Sstevel 734*03831d35Sstevel sbbc_enable_intr(softsp); 735*03831d35Sstevel 736*03831d35Sstevel /* 737*03831d35Sstevel * Create the mailbox 738*03831d35Sstevel */ 739*03831d35Sstevel if (sbbc_mbox_create(softsp) != 0) { 740*03831d35Sstevel cmn_err(CE_WARN, "No IOSRAM MailBox created!\n"); 741*03831d35Sstevel } 742*03831d35Sstevel 743*03831d35Sstevel } 744*03831d35Sstevel } 745*03831d35Sstevel /* 746*03831d35Sstevel * sbbc_add_instance 747*03831d35Sstevel * Must be called to hold chosen_lock. 748*03831d35Sstevel */ 749*03831d35Sstevel static void 750*03831d35Sstevel sbbc_add_instance(sbbc_softstate_t *softsp) 751*03831d35Sstevel { 752*03831d35Sstevel #ifdef DEBUG 753*03831d35Sstevel struct sbbc_softstate *sp; 754*03831d35Sstevel #endif 755*03831d35Sstevel 756*03831d35Sstevel ASSERT(mutex_owned(&chosen_lock)); 757*03831d35Sstevel 758*03831d35Sstevel #if defined(DEBUG) 759*03831d35Sstevel /* Verify that this instance is not in the list yet */ 760*03831d35Sstevel for (sp = sgsbbc_instances; sp != NULL; sp = sp->next) { 761*03831d35Sstevel ASSERT(sp != softsp); 762*03831d35Sstevel } 763*03831d35Sstevel #endif 764*03831d35Sstevel 765*03831d35Sstevel /* 766*03831d35Sstevel * Add this instance to the front of the list. 767*03831d35Sstevel */ 768*03831d35Sstevel if (sgsbbc_instances != NULL) { 769*03831d35Sstevel sgsbbc_instances->prev = softsp; 770*03831d35Sstevel } 771*03831d35Sstevel 772*03831d35Sstevel softsp->next = sgsbbc_instances; 773*03831d35Sstevel softsp->prev = NULL; 774*03831d35Sstevel sgsbbc_instances = softsp; 775*03831d35Sstevel } 776*03831d35Sstevel 777*03831d35Sstevel static void 778*03831d35Sstevel sbbc_remove_instance(sbbc_softstate_t *softsp) 779*03831d35Sstevel { 780*03831d35Sstevel struct sbbc_softstate *sp; 781*03831d35Sstevel 782*03831d35Sstevel for (sp = sgsbbc_instances; sp != NULL; sp = sp->next) { 783*03831d35Sstevel if (sp == softsp) { 784*03831d35Sstevel if (sp->next != NULL) { 785*03831d35Sstevel sp->next->prev = sp->prev; 786*03831d35Sstevel } 787*03831d35Sstevel if (sp->prev != NULL) { 788*03831d35Sstevel sp->prev->next = sp->next; 789*03831d35Sstevel } 790*03831d35Sstevel if (sgsbbc_instances == softsp) { 791*03831d35Sstevel sgsbbc_instances = sp->next; 792*03831d35Sstevel } 793*03831d35Sstevel break; 794*03831d35Sstevel } 795*03831d35Sstevel } 796*03831d35Sstevel } 797*03831d35Sstevel 798*03831d35Sstevel /* 799*03831d35Sstevel * Generate an SBBC interrupt to the SC 800*03831d35Sstevel * Called from iosram_send_intr() 801*03831d35Sstevel * 802*03831d35Sstevel * send_intr == 0, check if EPLD register clear 803*03831d35Sstevel * for sync'ing SC/OS 804*03831d35Sstevel * send_intr == 1, send the interrupt 805*03831d35Sstevel */ 806*03831d35Sstevel int 807*03831d35Sstevel sbbc_send_intr(sbbc_softstate_t *softsp, int send_intr) 808*03831d35Sstevel { 809*03831d35Sstevel 810*03831d35Sstevel uchar_t *epld_int; 811*03831d35Sstevel volatile uchar_t epld_status; 812*03831d35Sstevel 813*03831d35Sstevel ASSERT(MUTEX_HELD(&master_iosram->iosram_lock)); 814*03831d35Sstevel 815*03831d35Sstevel if ((softsp == (sbbc_softstate_t *)NULL) || 816*03831d35Sstevel (softsp->epld_regs == (struct sbbc_epld_regs *)NULL)) 817*03831d35Sstevel return (ENXIO); 818*03831d35Sstevel 819*03831d35Sstevel /* 820*03831d35Sstevel * Check the L1 EPLD Interrupt register. If the 821*03831d35Sstevel * interrupt bit is set, theres an interrupt outstanding 822*03831d35Sstevel * (we assume) so return (EBUSY). 823*03831d35Sstevel */ 824*03831d35Sstevel 825*03831d35Sstevel epld_int = &softsp->epld_regs->epld_reg[EPLD_INTERRUPT]; 826*03831d35Sstevel 827*03831d35Sstevel epld_status = ddi_get8(softsp->sbbc_reg_handle2, epld_int); 828*03831d35Sstevel 829*03831d35Sstevel if (epld_status & INTERRUPT_ON) 830*03831d35Sstevel return (EBUSY); 831*03831d35Sstevel 832*03831d35Sstevel if (send_intr == TRUE) 833*03831d35Sstevel ddi_put8(softsp->sbbc_reg_handle2, epld_int, 834*03831d35Sstevel (epld_status | INTERRUPT_ON)); 835*03831d35Sstevel 836*03831d35Sstevel return (0); 837*03831d35Sstevel } 838*03831d35Sstevel 839*03831d35Sstevel /* 840*03831d35Sstevel * Map SBBC Internal registers 841*03831d35Sstevel * 842*03831d35Sstevel * The call to function should be protected by 843*03831d35Sstevel * chosen_lock or master_iosram->iosram_lock 844*03831d35Sstevel * to make sure a tunnel switch will not occur 845*03831d35Sstevel * in a middle of mapping. 846*03831d35Sstevel */ 847*03831d35Sstevel int 848*03831d35Sstevel sbbc_map_regs(sbbc_softstate_t *softsp) 849*03831d35Sstevel { 850*03831d35Sstevel struct ddi_device_acc_attr attr; 851*03831d35Sstevel 852*03831d35Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 853*03831d35Sstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 854*03831d35Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 855*03831d35Sstevel 856*03831d35Sstevel /* 857*03831d35Sstevel * Map in register set 1, Common Device Regs 858*03831d35Sstevel * SBCC offset 0x0 859*03831d35Sstevel */ 860*03831d35Sstevel if (ddi_regs_map_setup(softsp->dip, RNUM_SBBC_REGS, 861*03831d35Sstevel (caddr_t *)&softsp->sbbc_regs, 862*03831d35Sstevel SBBC_REGS_OFFSET, SBBC_REGS_SIZE, 863*03831d35Sstevel &attr, &softsp->sbbc_reg_handle1) != DDI_SUCCESS) { 864*03831d35Sstevel 865*03831d35Sstevel cmn_err(CE_WARN, "sbbc%d: unable to map interrupt " 866*03831d35Sstevel "registers", ddi_get_instance(softsp->dip)); 867*03831d35Sstevel return (DDI_FAILURE); 868*03831d35Sstevel } 869*03831d35Sstevel /* 870*03831d35Sstevel * Map in using register set 1, EPLD 871*03831d35Sstevel * SBCC offset 0xe000 872*03831d35Sstevel */ 873*03831d35Sstevel if (ddi_regs_map_setup(softsp->dip, RNUM_SBBC_REGS, 874*03831d35Sstevel (caddr_t *)&softsp->epld_regs, 875*03831d35Sstevel SBBC_EPLD_OFFSET, SBBC_EPLD_SIZE, 876*03831d35Sstevel &attr, &softsp->sbbc_reg_handle2) != DDI_SUCCESS) { 877*03831d35Sstevel 878*03831d35Sstevel cmn_err(CE_WARN, "sbbc%d: unable to map EPLD " 879*03831d35Sstevel "registers", ddi_get_instance(softsp->dip)); 880*03831d35Sstevel return (DDI_FAILURE); 881*03831d35Sstevel } 882*03831d35Sstevel 883*03831d35Sstevel /* 884*03831d35Sstevel * Set up pointers for registers 885*03831d35Sstevel */ 886*03831d35Sstevel softsp->port_int_regs = (uint32_t *)((char *)softsp->sbbc_regs + 887*03831d35Sstevel SBBC_PCI_INT_STATUS); 888*03831d35Sstevel 889*03831d35Sstevel map_regs_exit: 890*03831d35Sstevel return (DDI_SUCCESS); 891*03831d35Sstevel } 892*03831d35Sstevel 893*03831d35Sstevel 894*03831d35Sstevel /* 895*03831d35Sstevel * Unmap SBBC Internal registers 896*03831d35Sstevel */ 897*03831d35Sstevel static void 898*03831d35Sstevel sbbc_unmap_regs(sbbc_softstate_t *softsp) 899*03831d35Sstevel { 900*03831d35Sstevel if (softsp == NULL) 901*03831d35Sstevel return; 902*03831d35Sstevel 903*03831d35Sstevel mutex_enter(&master_iosram->iosram_lock); 904*03831d35Sstevel 905*03831d35Sstevel if (softsp->sbbc_regs) { 906*03831d35Sstevel ddi_regs_map_free(&softsp->sbbc_reg_handle1); 907*03831d35Sstevel softsp->sbbc_regs = NULL; 908*03831d35Sstevel softsp->port_int_regs = NULL; 909*03831d35Sstevel } 910*03831d35Sstevel 911*03831d35Sstevel if (softsp->epld_regs) { 912*03831d35Sstevel ddi_regs_map_free(&softsp->sbbc_reg_handle2); 913*03831d35Sstevel softsp->epld_regs = NULL; 914*03831d35Sstevel } 915*03831d35Sstevel 916*03831d35Sstevel mutex_exit(&master_iosram->iosram_lock); 917*03831d35Sstevel 918*03831d35Sstevel return; 919*03831d35Sstevel 920*03831d35Sstevel } 921*03831d35Sstevel /* 922*03831d35Sstevel * This is here to allow the IOSRAM driver get the softstate 923*03831d35Sstevel * for a chosen node when doing a tunnel switch. Just enables 924*03831d35Sstevel * us to avoid exporting the sbbcp softstate hook 925*03831d35Sstevel */ 926*03831d35Sstevel sbbc_softstate_t * 927*03831d35Sstevel sbbc_get_soft_state(int instance) 928*03831d35Sstevel { 929*03831d35Sstevel return (ddi_get_soft_state(sbbcp, instance)); 930*03831d35Sstevel } 931*03831d35Sstevel 932*03831d35Sstevel /* 933*03831d35Sstevel * Add interrupt handlers 934*03831d35Sstevel */ 935*03831d35Sstevel int 936*03831d35Sstevel sbbc_add_intr(sbbc_softstate_t *softsp) 937*03831d35Sstevel { 938*03831d35Sstevel int rc = DDI_SUCCESS; 939*03831d35Sstevel 940*03831d35Sstevel /* 941*03831d35Sstevel * map in the SBBC interrupts 942*03831d35Sstevel * Note that the iblock_cookie was initialised 943*03831d35Sstevel * in the 'attach' routine 944*03831d35Sstevel */ 945*03831d35Sstevel 946*03831d35Sstevel if (ddi_add_intr(softsp->dip, 0, &softsp->iblock, 947*03831d35Sstevel &softsp->idevice, sbbc_intr_handler, 948*03831d35Sstevel (caddr_t)softsp) != DDI_SUCCESS) { 949*03831d35Sstevel 950*03831d35Sstevel cmn_err(CE_WARN, "Can't register SBBC " 951*03831d35Sstevel " interrupt handler\n"); 952*03831d35Sstevel rc = DDI_FAILURE; 953*03831d35Sstevel } 954*03831d35Sstevel 955*03831d35Sstevel return (rc); 956*03831d35Sstevel } 957*03831d35Sstevel 958*03831d35Sstevel void 959*03831d35Sstevel sbbc_enable_intr(sbbc_softstate_t *softsp) 960*03831d35Sstevel { 961*03831d35Sstevel uint32_t *pci_intr_enable_reg; 962*03831d35Sstevel 963*03831d35Sstevel /* 964*03831d35Sstevel * Enable Interrupts now, turn on both INT#A lines 965*03831d35Sstevel */ 966*03831d35Sstevel pci_intr_enable_reg = (uint32_t *)((char *)softsp->sbbc_regs + 967*03831d35Sstevel SBBC_PCI_INT_ENABLE); 968*03831d35Sstevel ddi_put32(softsp->sbbc_reg_handle1, pci_intr_enable_reg, 969*03831d35Sstevel (uint32_t)SBBC_PCI_ENABLE_INT_A); 970*03831d35Sstevel } 971*03831d35Sstevel 972*03831d35Sstevel void 973*03831d35Sstevel sbbc_disable_intr(sbbc_softstate_t *softsp) 974*03831d35Sstevel { 975*03831d35Sstevel uint32_t *pci_intr_enable_reg; 976*03831d35Sstevel 977*03831d35Sstevel /* 978*03831d35Sstevel * Disable Interrupts now, turn off both INT#A lines 979*03831d35Sstevel */ 980*03831d35Sstevel pci_intr_enable_reg = (uint32_t *)((char *)softsp->sbbc_regs + 981*03831d35Sstevel SBBC_PCI_INT_ENABLE); 982*03831d35Sstevel ddi_put32(softsp->sbbc_reg_handle1, pci_intr_enable_reg, 0); 983*03831d35Sstevel } 984