1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/ddi_implfuncs.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/obpdefs.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/spl.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/iommu.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/sysiosbus.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/sysioerr.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/iocache.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/async.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/intreg.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/ddi_subrdefs.h> 52*7c478bd9Sstevel@tonic-gate #ifdef _STARFIRE 53*7c478bd9Sstevel@tonic-gate #include <sys/starfire.h> 54*7c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */ 55*7c478bd9Sstevel@tonic-gate #include <sys/sdt.h> 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate /* Useful debugging Stuff */ 58*7c478bd9Sstevel@tonic-gate #include <sys/nexusdebug.h> 59*7c478bd9Sstevel@tonic-gate /* Bitfield debugging definitions for this file */ 60*7c478bd9Sstevel@tonic-gate #define SBUS_ATTACH_DEBUG 0x1 61*7c478bd9Sstevel@tonic-gate #define SBUS_SBUSMEM_DEBUG 0x2 62*7c478bd9Sstevel@tonic-gate #define SBUS_INTERRUPT_DEBUG 0x4 63*7c478bd9Sstevel@tonic-gate #define SBUS_REGISTERS_DEBUG 0x8 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate /* 66*7c478bd9Sstevel@tonic-gate * Interrupt registers table. 67*7c478bd9Sstevel@tonic-gate * This table is necessary due to inconsistencies in the sysio register 68*7c478bd9Sstevel@tonic-gate * layout. If this gets fixed in the chip, we can get rid of this stupid 69*7c478bd9Sstevel@tonic-gate * table. 70*7c478bd9Sstevel@tonic-gate */ 71*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_1 = {SBUS_SLOT0_CONFIG, SBUS_SLOT0_MAPREG, 72*7c478bd9Sstevel@tonic-gate SBUS_SLOT0_L1_CLEAR, NULL}; 73*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_2 = {SBUS_SLOT0_CONFIG, SBUS_SLOT0_MAPREG, 74*7c478bd9Sstevel@tonic-gate SBUS_SLOT0_L2_CLEAR, NULL}; 75*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_3 = {SBUS_SLOT0_CONFIG, SBUS_SLOT0_MAPREG, 76*7c478bd9Sstevel@tonic-gate SBUS_SLOT0_L3_CLEAR, NULL}; 77*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_4 = {SBUS_SLOT0_CONFIG, SBUS_SLOT0_MAPREG, 78*7c478bd9Sstevel@tonic-gate SBUS_SLOT0_L4_CLEAR, NULL}; 79*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_5 = {SBUS_SLOT0_CONFIG, SBUS_SLOT0_MAPREG, 80*7c478bd9Sstevel@tonic-gate SBUS_SLOT0_L5_CLEAR, NULL}; 81*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_6 = {SBUS_SLOT0_CONFIG, SBUS_SLOT0_MAPREG, 82*7c478bd9Sstevel@tonic-gate SBUS_SLOT0_L6_CLEAR, NULL}; 83*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_7 = {SBUS_SLOT0_CONFIG, SBUS_SLOT0_MAPREG, 84*7c478bd9Sstevel@tonic-gate SBUS_SLOT0_L7_CLEAR, NULL}; 85*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_9 = {SBUS_SLOT1_CONFIG, SBUS_SLOT1_MAPREG, 86*7c478bd9Sstevel@tonic-gate SBUS_SLOT1_L1_CLEAR, NULL}; 87*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_10 = {SBUS_SLOT1_CONFIG, SBUS_SLOT1_MAPREG, 88*7c478bd9Sstevel@tonic-gate SBUS_SLOT1_L2_CLEAR, NULL}; 89*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_11 = {SBUS_SLOT1_CONFIG, SBUS_SLOT1_MAPREG, 90*7c478bd9Sstevel@tonic-gate SBUS_SLOT1_L3_CLEAR, NULL}; 91*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_12 = {SBUS_SLOT1_CONFIG, SBUS_SLOT1_MAPREG, 92*7c478bd9Sstevel@tonic-gate SBUS_SLOT1_L4_CLEAR, NULL}; 93*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_13 = {SBUS_SLOT1_CONFIG, SBUS_SLOT1_MAPREG, 94*7c478bd9Sstevel@tonic-gate SBUS_SLOT1_L5_CLEAR, NULL}; 95*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_14 = {SBUS_SLOT1_CONFIG, SBUS_SLOT1_MAPREG, 96*7c478bd9Sstevel@tonic-gate SBUS_SLOT1_L6_CLEAR, NULL}; 97*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_15 = {SBUS_SLOT1_CONFIG, SBUS_SLOT1_MAPREG, 98*7c478bd9Sstevel@tonic-gate SBUS_SLOT1_L7_CLEAR, NULL}; 99*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_17 = {SBUS_SLOT2_CONFIG, SBUS_SLOT2_MAPREG, 100*7c478bd9Sstevel@tonic-gate SBUS_SLOT2_L1_CLEAR, NULL}; 101*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_18 = {SBUS_SLOT2_CONFIG, SBUS_SLOT2_MAPREG, 102*7c478bd9Sstevel@tonic-gate SBUS_SLOT2_L2_CLEAR, NULL}; 103*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_19 = {SBUS_SLOT2_CONFIG, SBUS_SLOT2_MAPREG, 104*7c478bd9Sstevel@tonic-gate SBUS_SLOT2_L3_CLEAR, NULL}; 105*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_20 = {SBUS_SLOT2_CONFIG, SBUS_SLOT2_MAPREG, 106*7c478bd9Sstevel@tonic-gate SBUS_SLOT2_L4_CLEAR, NULL}; 107*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_21 = {SBUS_SLOT2_CONFIG, SBUS_SLOT2_MAPREG, 108*7c478bd9Sstevel@tonic-gate SBUS_SLOT2_L5_CLEAR, NULL}; 109*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_22 = {SBUS_SLOT2_CONFIG, SBUS_SLOT2_MAPREG, 110*7c478bd9Sstevel@tonic-gate SBUS_SLOT2_L6_CLEAR, NULL}; 111*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_23 = {SBUS_SLOT2_CONFIG, SBUS_SLOT2_MAPREG, 112*7c478bd9Sstevel@tonic-gate SBUS_SLOT2_L7_CLEAR, NULL}; 113*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_25 = {SBUS_SLOT3_CONFIG, SBUS_SLOT3_MAPREG, 114*7c478bd9Sstevel@tonic-gate SBUS_SLOT3_L1_CLEAR, NULL}; 115*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_26 = {SBUS_SLOT3_CONFIG, SBUS_SLOT3_MAPREG, 116*7c478bd9Sstevel@tonic-gate SBUS_SLOT3_L2_CLEAR, NULL}; 117*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_27 = {SBUS_SLOT3_CONFIG, SBUS_SLOT3_MAPREG, 118*7c478bd9Sstevel@tonic-gate SBUS_SLOT3_L3_CLEAR, NULL}; 119*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_28 = {SBUS_SLOT3_CONFIG, SBUS_SLOT3_MAPREG, 120*7c478bd9Sstevel@tonic-gate SBUS_SLOT3_L4_CLEAR, NULL}; 121*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_29 = {SBUS_SLOT3_CONFIG, SBUS_SLOT3_MAPREG, 122*7c478bd9Sstevel@tonic-gate SBUS_SLOT3_L5_CLEAR, NULL}; 123*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_30 = {SBUS_SLOT3_CONFIG, SBUS_SLOT3_MAPREG, 124*7c478bd9Sstevel@tonic-gate SBUS_SLOT3_L6_CLEAR, NULL}; 125*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_31 = {SBUS_SLOT3_CONFIG, SBUS_SLOT3_MAPREG, 126*7c478bd9Sstevel@tonic-gate SBUS_SLOT3_L7_CLEAR, NULL}; 127*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_32 = {SBUS_SLOT5_CONFIG, ESP_MAPREG, 128*7c478bd9Sstevel@tonic-gate ESP_CLEAR, ESP_INTR_STATE_SHIFT}; 129*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_33 = {SBUS_SLOT5_CONFIG, ETHER_MAPREG, 130*7c478bd9Sstevel@tonic-gate ETHER_CLEAR, ETHER_INTR_STATE_SHIFT}; 131*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_34 = {SBUS_SLOT5_CONFIG, PP_MAPREG, 132*7c478bd9Sstevel@tonic-gate PP_CLEAR, PP_INTR_STATE_SHIFT}; 133*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_36 = {SBUS_SLOT4_CONFIG, AUDIO_MAPREG, 134*7c478bd9Sstevel@tonic-gate AUDIO_CLEAR, AUDIO_INTR_STATE_SHIFT}; 135*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_40 = {SBUS_SLOT6_CONFIG, KBDMOUSE_MAPREG, 136*7c478bd9Sstevel@tonic-gate KBDMOUSE_CLEAR, 137*7c478bd9Sstevel@tonic-gate KBDMOUSE_INTR_STATE_SHIFT}; 138*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_41 = {SBUS_SLOT6_CONFIG, FLOPPY_MAPREG, 139*7c478bd9Sstevel@tonic-gate FLOPPY_CLEAR, FLOPPY_INTR_STATE_SHIFT}; 140*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_42 = {SBUS_SLOT6_CONFIG, THERMAL_MAPREG, 141*7c478bd9Sstevel@tonic-gate THERMAL_CLEAR, 142*7c478bd9Sstevel@tonic-gate THERMAL_INTR_STATE_SHIFT}; 143*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_48 = {SBUS_SLOT6_CONFIG, TIMER0_MAPREG, 144*7c478bd9Sstevel@tonic-gate TIMER0_CLEAR, TIMER0_INTR_STATE_SHIFT}; 145*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_49 = {SBUS_SLOT6_CONFIG, TIMER1_MAPREG, 146*7c478bd9Sstevel@tonic-gate TIMER1_CLEAR, TIMER1_INTR_STATE_SHIFT}; 147*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_52 = {SBUS_SLOT6_CONFIG, UE_ECC_MAPREG, 148*7c478bd9Sstevel@tonic-gate UE_ECC_CLEAR, UE_INTR_STATE_SHIFT}; 149*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_53 = {SBUS_SLOT6_CONFIG, CE_ECC_MAPREG, 150*7c478bd9Sstevel@tonic-gate CE_ECC_CLEAR, CE_INTR_STATE_SHIFT}; 151*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_54 = {SBUS_SLOT6_CONFIG, SBUS_ERR_MAPREG, 152*7c478bd9Sstevel@tonic-gate SBUS_ERR_CLEAR, SERR_INTR_STATE_SHIFT}; 153*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_55 = {SBUS_SLOT6_CONFIG, PM_WAKEUP_MAPREG, 154*7c478bd9Sstevel@tonic-gate PM_WAKEUP_CLEAR, PM_INTR_STATE_SHIFT}; 155*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_ffb = {NULL, FFB_MAPPING_REG, NULL, NULL}; 156*7c478bd9Sstevel@tonic-gate static struct sbus_slot_entry ino_exp = {NULL, EXP_MAPPING_REG, NULL, NULL}; 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate /* Construct the interrupt number array */ 159*7c478bd9Sstevel@tonic-gate struct sbus_slot_entry *ino_table[] = { 160*7c478bd9Sstevel@tonic-gate NULL, &ino_1, &ino_2, &ino_3, &ino_4, &ino_5, &ino_6, &ino_7, 161*7c478bd9Sstevel@tonic-gate NULL, &ino_9, &ino_10, &ino_11, &ino_12, &ino_13, &ino_14, &ino_15, 162*7c478bd9Sstevel@tonic-gate NULL, &ino_17, &ino_18, &ino_19, &ino_20, &ino_21, &ino_22, &ino_23, 163*7c478bd9Sstevel@tonic-gate NULL, &ino_25, &ino_26, &ino_27, &ino_28, &ino_29, &ino_30, &ino_31, 164*7c478bd9Sstevel@tonic-gate &ino_32, &ino_33, &ino_34, NULL, &ino_36, NULL, NULL, NULL, 165*7c478bd9Sstevel@tonic-gate &ino_40, &ino_41, &ino_42, NULL, NULL, NULL, NULL, NULL, &ino_48, 166*7c478bd9Sstevel@tonic-gate &ino_49, NULL, NULL, &ino_52, &ino_53, &ino_54, &ino_55, &ino_ffb, 167*7c478bd9Sstevel@tonic-gate &ino_exp 168*7c478bd9Sstevel@tonic-gate }; 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate /* 171*7c478bd9Sstevel@tonic-gate * This table represents the Fusion interrupt priorities. They range 172*7c478bd9Sstevel@tonic-gate * from 1 - 15, so we'll pattern the priorities after the 4M. We map Fusion 173*7c478bd9Sstevel@tonic-gate * interrupt number to system priority. The mondo number is used as an 174*7c478bd9Sstevel@tonic-gate * index into this table. 175*7c478bd9Sstevel@tonic-gate */ 176*7c478bd9Sstevel@tonic-gate int interrupt_priorities[] = { 177*7c478bd9Sstevel@tonic-gate -1, 2, 3, 5, 7, 9, 11, 13, /* Slot 0 sbus level 1 - 7 */ 178*7c478bd9Sstevel@tonic-gate -1, 2, 3, 5, 7, 9, 11, 13, /* Slot 1 sbus level 1 - 7 */ 179*7c478bd9Sstevel@tonic-gate -1, 2, 3, 5, 7, 9, 11, 13, /* Slot 2 sbus level 1 - 7 */ 180*7c478bd9Sstevel@tonic-gate -1, 2, 3, 5, 7, 9, 11, 13, /* Slot 3 sbus level 1 - 7 */ 181*7c478bd9Sstevel@tonic-gate 4, /* Onboard SCSI */ 182*7c478bd9Sstevel@tonic-gate 6, /* Onboard Ethernet */ 183*7c478bd9Sstevel@tonic-gate 3, /* Onboard Parallel port */ 184*7c478bd9Sstevel@tonic-gate -1, /* Not in use */ 185*7c478bd9Sstevel@tonic-gate 9, /* Onboard Audio */ 186*7c478bd9Sstevel@tonic-gate -1, -1, -1, /* Not in use */ 187*7c478bd9Sstevel@tonic-gate 12, /* Onboard keyboard/serial ports */ 188*7c478bd9Sstevel@tonic-gate 11, /* Onboard Floppy */ 189*7c478bd9Sstevel@tonic-gate 9, /* Thermal interrupt */ 190*7c478bd9Sstevel@tonic-gate -1, -1, -1, /* Not is use */ 191*7c478bd9Sstevel@tonic-gate 10, /* Timer 0 (tick timer) */ 192*7c478bd9Sstevel@tonic-gate 14, /* Timer 1 (not used) */ 193*7c478bd9Sstevel@tonic-gate 15, /* Sysio UE ECC error */ 194*7c478bd9Sstevel@tonic-gate 10, /* Sysio CE ECC error */ 195*7c478bd9Sstevel@tonic-gate 10, /* Sysio Sbus error */ 196*7c478bd9Sstevel@tonic-gate 10, /* PM Wakeup */ 197*7c478bd9Sstevel@tonic-gate }; 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate /* Interrupt counter flag. To enable/disable spurious interrupt counter. */ 200*7c478bd9Sstevel@tonic-gate static int intr_cntr_on; 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate /* 203*7c478bd9Sstevel@tonic-gate * Function prototypes. 204*7c478bd9Sstevel@tonic-gate */ 205*7c478bd9Sstevel@tonic-gate static int 206*7c478bd9Sstevel@tonic-gate sbus_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *); 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate static int 209*7c478bd9Sstevel@tonic-gate sbus_add_intr_impl(dev_info_t *dip, dev_info_t *rdip, 210*7c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp); 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate static void 213*7c478bd9Sstevel@tonic-gate sbus_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip, 214*7c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp); 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate static int 217*7c478bd9Sstevel@tonic-gate sbus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 218*7c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result); 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate static int 221*7c478bd9Sstevel@tonic-gate sbus_xlate_intrs(dev_info_t *dip, dev_info_t *rdip, ddi_ispec_t *ispecp, 222*7c478bd9Sstevel@tonic-gate int32_t ign); 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate static int 225*7c478bd9Sstevel@tonic-gate sbus_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate static int 228*7c478bd9Sstevel@tonic-gate sbus_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate static int 231*7c478bd9Sstevel@tonic-gate sbus_do_detach(dev_info_t *devi); 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate static void 234*7c478bd9Sstevel@tonic-gate sbus_add_picN_kstats(dev_info_t *dip); 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate static void 237*7c478bd9Sstevel@tonic-gate sbus_add_kstats(struct sbus_soft_state *); 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate static int 240*7c478bd9Sstevel@tonic-gate sbus_counters_kstat_update(kstat_t *, int); 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate extern int 243*7c478bd9Sstevel@tonic-gate sysio_err_uninit(struct sbus_soft_state *softsp); 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate extern int 246*7c478bd9Sstevel@tonic-gate iommu_uninit(struct sbus_soft_state *softsp); 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate extern int 249*7c478bd9Sstevel@tonic-gate stream_buf_uninit(struct sbus_soft_state *softsp); 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate static int 252*7c478bd9Sstevel@tonic-gate find_sbus_slot(dev_info_t *dip, dev_info_t *rdip); 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate static void make_sbus_ppd(dev_info_t *child); 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate static int 257*7c478bd9Sstevel@tonic-gate sbusmem_initchild(dev_info_t *dip, dev_info_t *child); 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate static int 260*7c478bd9Sstevel@tonic-gate sbus_initchild(dev_info_t *dip, dev_info_t *child); 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate static int 263*7c478bd9Sstevel@tonic-gate sbus_uninitchild(dev_info_t *dip); 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate static int 266*7c478bd9Sstevel@tonic-gate sbus_ctlops_poke(struct sbus_soft_state *softsp, peekpoke_ctlops_t *in_args); 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate static int 269*7c478bd9Sstevel@tonic-gate sbus_ctlops_peek(struct sbus_soft_state *softsp, peekpoke_ctlops_t *in_args, 270*7c478bd9Sstevel@tonic-gate void *result); 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate static int 273*7c478bd9Sstevel@tonic-gate sbus_init(struct sbus_soft_state *softsp, caddr_t address); 274*7c478bd9Sstevel@tonic-gate 275*7c478bd9Sstevel@tonic-gate static int 276*7c478bd9Sstevel@tonic-gate sbus_resume_init(struct sbus_soft_state *softsp, int resume); 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate static void 279*7c478bd9Sstevel@tonic-gate sbus_cpr_handle_intr_map_reg(uint64_t *cpr_softsp, volatile uint64_t *baddr, 280*7c478bd9Sstevel@tonic-gate int flag); 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate static void sbus_intrdist(void *); 283*7c478bd9Sstevel@tonic-gate static uint_t sbus_intr_reset(void *); 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate static int 286*7c478bd9Sstevel@tonic-gate sbus_update_intr_state(dev_info_t *dip, dev_info_t *rdip, 287*7c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, uint_t new_intr_state); 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate #ifdef _STARFIRE 290*7c478bd9Sstevel@tonic-gate void 291*7c478bd9Sstevel@tonic-gate pc_ittrans_init(int, caddr_t *); 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate void 294*7c478bd9Sstevel@tonic-gate pc_ittrans_uninit(caddr_t); 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate int 297*7c478bd9Sstevel@tonic-gate pc_translate_tgtid(caddr_t, int, volatile uint64_t *); 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate void 300*7c478bd9Sstevel@tonic-gate pc_ittrans_cleanup(caddr_t, volatile uint64_t *); 301*7c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */ 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate /* 304*7c478bd9Sstevel@tonic-gate * Configuration data structures 305*7c478bd9Sstevel@tonic-gate */ 306*7c478bd9Sstevel@tonic-gate static struct bus_ops sbus_bus_ops = { 307*7c478bd9Sstevel@tonic-gate BUSO_REV, 308*7c478bd9Sstevel@tonic-gate i_ddi_bus_map, 309*7c478bd9Sstevel@tonic-gate 0, 310*7c478bd9Sstevel@tonic-gate 0, 311*7c478bd9Sstevel@tonic-gate 0, 312*7c478bd9Sstevel@tonic-gate i_ddi_map_fault, 313*7c478bd9Sstevel@tonic-gate iommu_dma_map, 314*7c478bd9Sstevel@tonic-gate iommu_dma_allochdl, 315*7c478bd9Sstevel@tonic-gate iommu_dma_freehdl, 316*7c478bd9Sstevel@tonic-gate iommu_dma_bindhdl, 317*7c478bd9Sstevel@tonic-gate iommu_dma_unbindhdl, 318*7c478bd9Sstevel@tonic-gate iommu_dma_flush, 319*7c478bd9Sstevel@tonic-gate iommu_dma_win, 320*7c478bd9Sstevel@tonic-gate iommu_dma_mctl, 321*7c478bd9Sstevel@tonic-gate sbus_ctlops, 322*7c478bd9Sstevel@tonic-gate ddi_bus_prop_op, 323*7c478bd9Sstevel@tonic-gate 0, /* (*bus_get_eventcookie)(); */ 324*7c478bd9Sstevel@tonic-gate 0, /* (*bus_add_eventcall)(); */ 325*7c478bd9Sstevel@tonic-gate 0, /* (*bus_remove_eventcall)(); */ 326*7c478bd9Sstevel@tonic-gate 0, /* (*bus_post_event)(); */ 327*7c478bd9Sstevel@tonic-gate 0, /* (*bus_intr_control)(); */ 328*7c478bd9Sstevel@tonic-gate 0, /* (*bus_config)(); */ 329*7c478bd9Sstevel@tonic-gate 0, /* (*bus_unconfig)(); */ 330*7c478bd9Sstevel@tonic-gate 0, /* (*bus_fm_init)(); */ 331*7c478bd9Sstevel@tonic-gate 0, /* (*bus_fm_fini)(); */ 332*7c478bd9Sstevel@tonic-gate 0, /* (*bus_fm_access_enter)(); */ 333*7c478bd9Sstevel@tonic-gate 0, /* (*bus_fm_access_exit)(); */ 334*7c478bd9Sstevel@tonic-gate 0, /* (*bus_power)(); */ 335*7c478bd9Sstevel@tonic-gate sbus_intr_ops /* (*bus_intr_op)(); */ 336*7c478bd9Sstevel@tonic-gate }; 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate static struct cb_ops sbus_cb_ops = { 339*7c478bd9Sstevel@tonic-gate nodev, /* open */ 340*7c478bd9Sstevel@tonic-gate nodev, /* close */ 341*7c478bd9Sstevel@tonic-gate nodev, /* strategy */ 342*7c478bd9Sstevel@tonic-gate nodev, /* print */ 343*7c478bd9Sstevel@tonic-gate nodev, /* dump */ 344*7c478bd9Sstevel@tonic-gate nodev, /* read */ 345*7c478bd9Sstevel@tonic-gate nodev, /* write */ 346*7c478bd9Sstevel@tonic-gate nodev, /* ioctl */ 347*7c478bd9Sstevel@tonic-gate nodev, /* devmap */ 348*7c478bd9Sstevel@tonic-gate nodev, /* mmap */ 349*7c478bd9Sstevel@tonic-gate nodev, /* segmap */ 350*7c478bd9Sstevel@tonic-gate nochpoll, /* poll */ 351*7c478bd9Sstevel@tonic-gate ddi_prop_op, /* prop_op */ 352*7c478bd9Sstevel@tonic-gate NULL, 353*7c478bd9Sstevel@tonic-gate D_NEW | D_MP | D_HOTPLUG, 354*7c478bd9Sstevel@tonic-gate CB_REV, /* rev */ 355*7c478bd9Sstevel@tonic-gate nodev, /* int (*cb_aread)() */ 356*7c478bd9Sstevel@tonic-gate nodev /* int (*cb_awrite)() */ 357*7c478bd9Sstevel@tonic-gate }; 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate static struct dev_ops sbus_ops = { 360*7c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 361*7c478bd9Sstevel@tonic-gate 0, /* refcnt */ 362*7c478bd9Sstevel@tonic-gate ddi_no_info, /* info */ 363*7c478bd9Sstevel@tonic-gate nulldev, /* identify */ 364*7c478bd9Sstevel@tonic-gate nulldev, /* probe */ 365*7c478bd9Sstevel@tonic-gate sbus_attach, /* attach */ 366*7c478bd9Sstevel@tonic-gate sbus_detach, /* detach */ 367*7c478bd9Sstevel@tonic-gate nodev, /* reset */ 368*7c478bd9Sstevel@tonic-gate &sbus_cb_ops, /* driver operations */ 369*7c478bd9Sstevel@tonic-gate &sbus_bus_ops, /* bus operations */ 370*7c478bd9Sstevel@tonic-gate nulldev /* power */ 371*7c478bd9Sstevel@tonic-gate }; 372*7c478bd9Sstevel@tonic-gate 373*7c478bd9Sstevel@tonic-gate /* global data */ 374*7c478bd9Sstevel@tonic-gate void *sbusp; /* sbus soft state hook */ 375*7c478bd9Sstevel@tonic-gate void *sbus_cprp; /* subs suspend/resume soft state hook */ 376*7c478bd9Sstevel@tonic-gate static kstat_t *sbus_picN_ksp[SBUS_NUM_PICS]; /* performance picN kstats */ 377*7c478bd9Sstevel@tonic-gate static int sbus_attachcnt = 0; /* number of instances attached */ 378*7c478bd9Sstevel@tonic-gate static kmutex_t sbus_attachcnt_mutex; /* sbus_attachcnt lock - attach/detach */ 379*7c478bd9Sstevel@tonic-gate 380*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 381*7c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops; 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 384*7c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 385*7c478bd9Sstevel@tonic-gate "SBus (sysio) nexus driver %I%", /* Name of module. */ 386*7c478bd9Sstevel@tonic-gate &sbus_ops, /* driver ops */ 387*7c478bd9Sstevel@tonic-gate }; 388*7c478bd9Sstevel@tonic-gate 389*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 390*7c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 391*7c478bd9Sstevel@tonic-gate }; 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate /* 394*7c478bd9Sstevel@tonic-gate * These are the module initialization routines. 395*7c478bd9Sstevel@tonic-gate */ 396*7c478bd9Sstevel@tonic-gate int 397*7c478bd9Sstevel@tonic-gate _init(void) 398*7c478bd9Sstevel@tonic-gate { 399*7c478bd9Sstevel@tonic-gate int error; 400*7c478bd9Sstevel@tonic-gate 401*7c478bd9Sstevel@tonic-gate if ((error = ddi_soft_state_init(&sbusp, 402*7c478bd9Sstevel@tonic-gate sizeof (struct sbus_soft_state), 1)) != 0) 403*7c478bd9Sstevel@tonic-gate return (error); 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate /* 406*7c478bd9Sstevel@tonic-gate * Initialize cpr soft state structure 407*7c478bd9Sstevel@tonic-gate */ 408*7c478bd9Sstevel@tonic-gate if ((error = ddi_soft_state_init(&sbus_cprp, 409*7c478bd9Sstevel@tonic-gate sizeof (uint64_t) * MAX_INO_TABLE_SIZE, 0)) != 0) 410*7c478bd9Sstevel@tonic-gate return (error); 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate /* Initialize global mutex */ 413*7c478bd9Sstevel@tonic-gate mutex_init(&sbus_attachcnt_mutex, NULL, MUTEX_DRIVER, NULL); 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 416*7c478bd9Sstevel@tonic-gate } 417*7c478bd9Sstevel@tonic-gate 418*7c478bd9Sstevel@tonic-gate int 419*7c478bd9Sstevel@tonic-gate _fini(void) 420*7c478bd9Sstevel@tonic-gate { 421*7c478bd9Sstevel@tonic-gate int error; 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate if ((error = mod_remove(&modlinkage)) != 0) 424*7c478bd9Sstevel@tonic-gate return (error); 425*7c478bd9Sstevel@tonic-gate 426*7c478bd9Sstevel@tonic-gate mutex_destroy(&sbus_attachcnt_mutex); 427*7c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&sbusp); 428*7c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&sbus_cprp); 429*7c478bd9Sstevel@tonic-gate return (0); 430*7c478bd9Sstevel@tonic-gate } 431*7c478bd9Sstevel@tonic-gate 432*7c478bd9Sstevel@tonic-gate int 433*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 434*7c478bd9Sstevel@tonic-gate { 435*7c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 436*7c478bd9Sstevel@tonic-gate } 437*7c478bd9Sstevel@tonic-gate 438*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 439*7c478bd9Sstevel@tonic-gate static int 440*7c478bd9Sstevel@tonic-gate sbus_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 441*7c478bd9Sstevel@tonic-gate { 442*7c478bd9Sstevel@tonic-gate struct sbus_soft_state *softsp; 443*7c478bd9Sstevel@tonic-gate int instance, error; 444*7c478bd9Sstevel@tonic-gate uint64_t *cpr_softsp; 445*7c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr; 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 449*7c478bd9Sstevel@tonic-gate debug_info = 1; 450*7c478bd9Sstevel@tonic-gate debug_print_level = 0; 451*7c478bd9Sstevel@tonic-gate #endif 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate instance = ddi_get_instance(devi); 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate switch (cmd) { 456*7c478bd9Sstevel@tonic-gate case DDI_ATTACH: 457*7c478bd9Sstevel@tonic-gate break; 458*7c478bd9Sstevel@tonic-gate 459*7c478bd9Sstevel@tonic-gate case DDI_RESUME: 460*7c478bd9Sstevel@tonic-gate softsp = ddi_get_soft_state(sbusp, instance); 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate if ((error = iommu_resume_init(softsp)) != DDI_SUCCESS) 463*7c478bd9Sstevel@tonic-gate return (error); 464*7c478bd9Sstevel@tonic-gate 465*7c478bd9Sstevel@tonic-gate if ((error = sbus_resume_init(softsp, 1)) != DDI_SUCCESS) 466*7c478bd9Sstevel@tonic-gate return (error); 467*7c478bd9Sstevel@tonic-gate 468*7c478bd9Sstevel@tonic-gate if ((error = stream_buf_resume_init(softsp)) != DDI_SUCCESS) 469*7c478bd9Sstevel@tonic-gate return (error); 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate /* 472*7c478bd9Sstevel@tonic-gate * Restore Interrupt Mapping registers 473*7c478bd9Sstevel@tonic-gate */ 474*7c478bd9Sstevel@tonic-gate cpr_softsp = ddi_get_soft_state(sbus_cprp, instance); 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate if (cpr_softsp != NULL) { 477*7c478bd9Sstevel@tonic-gate sbus_cpr_handle_intr_map_reg(cpr_softsp, 478*7c478bd9Sstevel@tonic-gate softsp->intr_mapping_reg, 0); 479*7c478bd9Sstevel@tonic-gate ddi_soft_state_free(sbus_cprp, instance); 480*7c478bd9Sstevel@tonic-gate } 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 483*7c478bd9Sstevel@tonic-gate 484*7c478bd9Sstevel@tonic-gate default: 485*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 486*7c478bd9Sstevel@tonic-gate } 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(sbusp, instance) != DDI_SUCCESS) 489*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 490*7c478bd9Sstevel@tonic-gate 491*7c478bd9Sstevel@tonic-gate softsp = ddi_get_soft_state(sbusp, instance); 492*7c478bd9Sstevel@tonic-gate 493*7c478bd9Sstevel@tonic-gate /* Set the dip in the soft state */ 494*7c478bd9Sstevel@tonic-gate softsp->dip = devi; 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate if ((softsp->upa_id = (int)ddi_getprop(DDI_DEV_T_ANY, softsp->dip, 497*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "upa-portid", -1)) == -1) { 498*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Unable to retrieve sbus upa-portid" 499*7c478bd9Sstevel@tonic-gate "property."); 500*7c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 501*7c478bd9Sstevel@tonic-gate goto bad; 502*7c478bd9Sstevel@tonic-gate } 503*7c478bd9Sstevel@tonic-gate 504*7c478bd9Sstevel@tonic-gate /* 505*7c478bd9Sstevel@tonic-gate * The firmware maps in all 3 pages of the sysio chips device 506*7c478bd9Sstevel@tonic-gate * device registers and exports the mapping in the int-sized 507*7c478bd9Sstevel@tonic-gate * property "address". Read in this address and pass it to 508*7c478bd9Sstevel@tonic-gate * the subsidiary *_init functions, so we don't create extra 509*7c478bd9Sstevel@tonic-gate * mappings to the same physical pages and we don't have to 510*7c478bd9Sstevel@tonic-gate * retrieve the more than once. 511*7c478bd9Sstevel@tonic-gate */ 512*7c478bd9Sstevel@tonic-gate /* 513*7c478bd9Sstevel@tonic-gate * Implement new policy to start ignoring the "address" property 514*7c478bd9Sstevel@tonic-gate * due to new requirements from DR. The problem is that the contents 515*7c478bd9Sstevel@tonic-gate * of the "address" property contain vm mappings from OBP which needs 516*7c478bd9Sstevel@tonic-gate * to be recaptured into kernel vm. Instead of relying on a blanket 517*7c478bd9Sstevel@tonic-gate * recapture during boot time, we map psycho registers each time during 518*7c478bd9Sstevel@tonic-gate * attach and unmap the during detach. In some future point of time 519*7c478bd9Sstevel@tonic-gate * OBP will drop creating "address" property but this driver will 520*7c478bd9Sstevel@tonic-gate * will already not rely on this property any more. 521*7c478bd9Sstevel@tonic-gate */ 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 524*7c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 525*7c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 526*7c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(softsp->dip, 0, &softsp->address, 0, 0, 527*7c478bd9Sstevel@tonic-gate &attr, &softsp->ac) != DDI_SUCCESS) { 528*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: unable to map reg set 0\n", 529*7c478bd9Sstevel@tonic-gate ddi_get_name(softsp->dip), 530*7c478bd9Sstevel@tonic-gate ddi_get_instance(softsp->dip)); 531*7c478bd9Sstevel@tonic-gate return (0); 532*7c478bd9Sstevel@tonic-gate } 533*7c478bd9Sstevel@tonic-gate if (softsp->address == (caddr_t)-1) { 534*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?sbus%d: No sysio <address> property\n", 535*7c478bd9Sstevel@tonic-gate ddi_get_instance(softsp->dip)); 536*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 537*7c478bd9Sstevel@tonic-gate } 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate DPRINTF(SBUS_ATTACH_DEBUG, ("sbus: devi=0x%x, softsp=0x%x\n", 540*7c478bd9Sstevel@tonic-gate devi, softsp)); 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate #ifdef notdef 543*7c478bd9Sstevel@tonic-gate /* 544*7c478bd9Sstevel@tonic-gate * This bit of code, plus the firmware, will tell us if 545*7c478bd9Sstevel@tonic-gate * the #size-cells infrastructure code works, to some degree. 546*7c478bd9Sstevel@tonic-gate * You should be able to use the firmware to determine if 547*7c478bd9Sstevel@tonic-gate * the address returned by ddi_map_regs maps the correct phys. pages. 548*7c478bd9Sstevel@tonic-gate */ 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate { 551*7c478bd9Sstevel@tonic-gate caddr_t addr; 552*7c478bd9Sstevel@tonic-gate int rv; 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?sbus: address property = 0x%x\n", address); 555*7c478bd9Sstevel@tonic-gate 556*7c478bd9Sstevel@tonic-gate if ((rv = ddi_map_regs(softsp->dip, 0, &addr, 557*7c478bd9Sstevel@tonic-gate (off_t)0, (off_t)0)) != DDI_SUCCESS) { 558*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?sbus: ddi_map_regs failed: %d\n", 559*7c478bd9Sstevel@tonic-gate rv); 560*7c478bd9Sstevel@tonic-gate } else { 561*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?sbus: ddi_map_regs returned " 562*7c478bd9Sstevel@tonic-gate " virtual address 0x%x\n", addr); 563*7c478bd9Sstevel@tonic-gate } 564*7c478bd9Sstevel@tonic-gate } 565*7c478bd9Sstevel@tonic-gate #endif /* notdef */ 566*7c478bd9Sstevel@tonic-gate 567*7c478bd9Sstevel@tonic-gate if ((error = iommu_init(softsp, softsp->address)) != DDI_SUCCESS) 568*7c478bd9Sstevel@tonic-gate goto bad; 569*7c478bd9Sstevel@tonic-gate 570*7c478bd9Sstevel@tonic-gate if ((error = sbus_init(softsp, softsp->address)) != DDI_SUCCESS) 571*7c478bd9Sstevel@tonic-gate goto bad; 572*7c478bd9Sstevel@tonic-gate 573*7c478bd9Sstevel@tonic-gate if ((error = sysio_err_init(softsp, softsp->address)) != DDI_SUCCESS) 574*7c478bd9Sstevel@tonic-gate goto bad; 575*7c478bd9Sstevel@tonic-gate 576*7c478bd9Sstevel@tonic-gate if ((error = stream_buf_init(softsp, softsp->address)) != DDI_SUCCESS) 577*7c478bd9Sstevel@tonic-gate goto bad; 578*7c478bd9Sstevel@tonic-gate 579*7c478bd9Sstevel@tonic-gate /* Init the pokefault mutex for sbus devices */ 580*7c478bd9Sstevel@tonic-gate mutex_init(&softsp->pokefault_mutex, NULL, MUTEX_SPIN, 581*7c478bd9Sstevel@tonic-gate (void *)ipltospl(SBUS_ERR_PIL - 1)); 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate sbus_add_kstats(softsp); 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate bus_func_register(BF_TYPE_RESINTR, sbus_intr_reset, devi); 586*7c478bd9Sstevel@tonic-gate 587*7c478bd9Sstevel@tonic-gate intr_dist_add(sbus_intrdist, devi); 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate ddi_report_dev(devi); 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 592*7c478bd9Sstevel@tonic-gate 593*7c478bd9Sstevel@tonic-gate bad: 594*7c478bd9Sstevel@tonic-gate ddi_soft_state_free(sbusp, instance); 595*7c478bd9Sstevel@tonic-gate return (error); 596*7c478bd9Sstevel@tonic-gate } 597*7c478bd9Sstevel@tonic-gate 598*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 599*7c478bd9Sstevel@tonic-gate static int 600*7c478bd9Sstevel@tonic-gate sbus_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 601*7c478bd9Sstevel@tonic-gate { 602*7c478bd9Sstevel@tonic-gate int instance; 603*7c478bd9Sstevel@tonic-gate struct sbus_soft_state *softsp; 604*7c478bd9Sstevel@tonic-gate uint64_t *cpr_softsp; 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate switch (cmd) { 607*7c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 608*7c478bd9Sstevel@tonic-gate /* 609*7c478bd9Sstevel@tonic-gate * Allocate the cpr soft data structure to save the current 610*7c478bd9Sstevel@tonic-gate * state of the interrupt mapping registers. 611*7c478bd9Sstevel@tonic-gate * This structure will be deallocated after the system 612*7c478bd9Sstevel@tonic-gate * is resumed. 613*7c478bd9Sstevel@tonic-gate */ 614*7c478bd9Sstevel@tonic-gate instance = ddi_get_instance(devi); 615*7c478bd9Sstevel@tonic-gate 616*7c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(sbus_cprp, instance) 617*7c478bd9Sstevel@tonic-gate != DDI_SUCCESS) 618*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate cpr_softsp = ddi_get_soft_state(sbus_cprp, instance); 621*7c478bd9Sstevel@tonic-gate 622*7c478bd9Sstevel@tonic-gate softsp = ddi_get_soft_state(sbusp, instance); 623*7c478bd9Sstevel@tonic-gate 624*7c478bd9Sstevel@tonic-gate sbus_cpr_handle_intr_map_reg(cpr_softsp, 625*7c478bd9Sstevel@tonic-gate softsp->intr_mapping_reg, 1); 626*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate case DDI_DETACH: 629*7c478bd9Sstevel@tonic-gate return (sbus_do_detach(devi)); 630*7c478bd9Sstevel@tonic-gate default: 631*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 632*7c478bd9Sstevel@tonic-gate } 633*7c478bd9Sstevel@tonic-gate } 634*7c478bd9Sstevel@tonic-gate 635*7c478bd9Sstevel@tonic-gate static int 636*7c478bd9Sstevel@tonic-gate sbus_do_detach(dev_info_t *devi) 637*7c478bd9Sstevel@tonic-gate { 638*7c478bd9Sstevel@tonic-gate int instance, pic; 639*7c478bd9Sstevel@tonic-gate struct sbus_soft_state *softsp; 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate instance = ddi_get_instance(devi); 642*7c478bd9Sstevel@tonic-gate softsp = ddi_get_soft_state(sbusp, instance); 643*7c478bd9Sstevel@tonic-gate ASSERT(softsp != NULL); 644*7c478bd9Sstevel@tonic-gate 645*7c478bd9Sstevel@tonic-gate bus_func_unregister(BF_TYPE_RESINTR, sbus_intr_reset, devi); 646*7c478bd9Sstevel@tonic-gate 647*7c478bd9Sstevel@tonic-gate intr_dist_rem(sbus_intrdist, devi); 648*7c478bd9Sstevel@tonic-gate 649*7c478bd9Sstevel@tonic-gate /* disable the streamming cache */ 650*7c478bd9Sstevel@tonic-gate if (stream_buf_uninit(softsp) == DDI_FAILURE) { 651*7c478bd9Sstevel@tonic-gate goto err; 652*7c478bd9Sstevel@tonic-gate } 653*7c478bd9Sstevel@tonic-gate 654*7c478bd9Sstevel@tonic-gate /* remove the interrupt handlers from the system */ 655*7c478bd9Sstevel@tonic-gate if (sysio_err_uninit(softsp) == DDI_FAILURE) { 656*7c478bd9Sstevel@tonic-gate goto err; 657*7c478bd9Sstevel@tonic-gate } 658*7c478bd9Sstevel@tonic-gate 659*7c478bd9Sstevel@tonic-gate /* disable the IOMMU */ 660*7c478bd9Sstevel@tonic-gate if (iommu_uninit(softsp)) { 661*7c478bd9Sstevel@tonic-gate goto err; 662*7c478bd9Sstevel@tonic-gate } 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate /* unmap register space if we have a handle */ 665*7c478bd9Sstevel@tonic-gate if (softsp->ac) { 666*7c478bd9Sstevel@tonic-gate ddi_regs_map_free(&softsp->ac); 667*7c478bd9Sstevel@tonic-gate softsp->address = NULL; 668*7c478bd9Sstevel@tonic-gate } 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate /* 671*7c478bd9Sstevel@tonic-gate * remove counter kstats for this device 672*7c478bd9Sstevel@tonic-gate */ 673*7c478bd9Sstevel@tonic-gate if (softsp->sbus_counters_ksp != (kstat_t *)NULL) 674*7c478bd9Sstevel@tonic-gate kstat_delete(softsp->sbus_counters_ksp); 675*7c478bd9Sstevel@tonic-gate 676*7c478bd9Sstevel@tonic-gate /* 677*7c478bd9Sstevel@tonic-gate * if we are the last instance to detach we need to 678*7c478bd9Sstevel@tonic-gate * remove the picN kstats. We use sbus_attachcnt as a 679*7c478bd9Sstevel@tonic-gate * count of how many instances are still attached. This 680*7c478bd9Sstevel@tonic-gate * is protected by a mutex. 681*7c478bd9Sstevel@tonic-gate */ 682*7c478bd9Sstevel@tonic-gate mutex_enter(&sbus_attachcnt_mutex); 683*7c478bd9Sstevel@tonic-gate sbus_attachcnt --; 684*7c478bd9Sstevel@tonic-gate if (sbus_attachcnt == 0) { 685*7c478bd9Sstevel@tonic-gate for (pic = 0; pic < SBUS_NUM_PICS; pic++) { 686*7c478bd9Sstevel@tonic-gate if (sbus_picN_ksp[pic] != (kstat_t *)NULL) { 687*7c478bd9Sstevel@tonic-gate kstat_delete(sbus_picN_ksp[pic]); 688*7c478bd9Sstevel@tonic-gate sbus_picN_ksp[pic] = NULL; 689*7c478bd9Sstevel@tonic-gate } 690*7c478bd9Sstevel@tonic-gate } 691*7c478bd9Sstevel@tonic-gate } 692*7c478bd9Sstevel@tonic-gate mutex_exit(&sbus_attachcnt_mutex); 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate #ifdef _STARFIRE 695*7c478bd9Sstevel@tonic-gate /* free starfire specific soft intr mapping structure */ 696*7c478bd9Sstevel@tonic-gate pc_ittrans_uninit(softsp->ittrans_cookie); 697*7c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */ 698*7c478bd9Sstevel@tonic-gate 699*7c478bd9Sstevel@tonic-gate /* free the soft state structure */ 700*7c478bd9Sstevel@tonic-gate ddi_soft_state_free(sbusp, instance); 701*7c478bd9Sstevel@tonic-gate 702*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 703*7c478bd9Sstevel@tonic-gate err: 704*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 705*7c478bd9Sstevel@tonic-gate } 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate static int 708*7c478bd9Sstevel@tonic-gate sbus_init(struct sbus_soft_state *softsp, caddr_t address) 709*7c478bd9Sstevel@tonic-gate { 710*7c478bd9Sstevel@tonic-gate int i; 711*7c478bd9Sstevel@tonic-gate extern void set_intr_mapping_reg(int, uint64_t *, int); 712*7c478bd9Sstevel@tonic-gate int numproxy; 713*7c478bd9Sstevel@tonic-gate 714*7c478bd9Sstevel@tonic-gate /* 715*7c478bd9Sstevel@tonic-gate * Simply add each registers offset to the base address 716*7c478bd9Sstevel@tonic-gate * to calculate the already mapped virtual address of 717*7c478bd9Sstevel@tonic-gate * the device register... 718*7c478bd9Sstevel@tonic-gate * 719*7c478bd9Sstevel@tonic-gate * define a macro for the pointer arithmetic; all registers 720*7c478bd9Sstevel@tonic-gate * are 64 bits wide and are defined as uint64_t's. 721*7c478bd9Sstevel@tonic-gate */ 722*7c478bd9Sstevel@tonic-gate 723*7c478bd9Sstevel@tonic-gate #define REG_ADDR(b, o) (uint64_t *)((caddr_t)(b) + (o)) 724*7c478bd9Sstevel@tonic-gate 725*7c478bd9Sstevel@tonic-gate softsp->sysio_ctrl_reg = REG_ADDR(address, OFF_SYSIO_CTRL_REG); 726*7c478bd9Sstevel@tonic-gate softsp->sbus_ctrl_reg = REG_ADDR(address, OFF_SBUS_CTRL_REG); 727*7c478bd9Sstevel@tonic-gate softsp->sbus_slot_config_reg = REG_ADDR(address, OFF_SBUS_SLOT_CONFIG); 728*7c478bd9Sstevel@tonic-gate softsp->intr_mapping_reg = REG_ADDR(address, OFF_INTR_MAPPING_REG); 729*7c478bd9Sstevel@tonic-gate softsp->clr_intr_reg = REG_ADDR(address, OFF_CLR_INTR_REG); 730*7c478bd9Sstevel@tonic-gate softsp->intr_retry_reg = REG_ADDR(address, OFF_INTR_RETRY_REG); 731*7c478bd9Sstevel@tonic-gate softsp->sbus_intr_state = REG_ADDR(address, OFF_SBUS_INTR_STATE_REG); 732*7c478bd9Sstevel@tonic-gate softsp->sbus_pcr = REG_ADDR(address, OFF_SBUS_PCR); 733*7c478bd9Sstevel@tonic-gate softsp->sbus_pic = REG_ADDR(address, OFF_SBUS_PIC); 734*7c478bd9Sstevel@tonic-gate 735*7c478bd9Sstevel@tonic-gate #undef REG_ADDR 736*7c478bd9Sstevel@tonic-gate 737*7c478bd9Sstevel@tonic-gate DPRINTF(SBUS_REGISTERS_DEBUG, ("SYSIO Control reg: 0x%x\n" 738*7c478bd9Sstevel@tonic-gate "SBUS Control reg: 0x%x", softsp->sysio_ctrl_reg, 739*7c478bd9Sstevel@tonic-gate softsp->sbus_ctrl_reg)); 740*7c478bd9Sstevel@tonic-gate 741*7c478bd9Sstevel@tonic-gate #ifdef _STARFIRE 742*7c478bd9Sstevel@tonic-gate /* Setup interrupt target translation for starfire */ 743*7c478bd9Sstevel@tonic-gate pc_ittrans_init(softsp->upa_id, &softsp->ittrans_cookie); 744*7c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */ 745*7c478bd9Sstevel@tonic-gate 746*7c478bd9Sstevel@tonic-gate softsp->intr_mapping_ign = 747*7c478bd9Sstevel@tonic-gate UPAID_TO_IGN(softsp->upa_id) << IMR_IGN_SHIFT; 748*7c478bd9Sstevel@tonic-gate 749*7c478bd9Sstevel@tonic-gate /* Diag reg 2 is the next 64 bit word after diag reg 1 */ 750*7c478bd9Sstevel@tonic-gate softsp->obio_intr_state = softsp->sbus_intr_state + 1; 751*7c478bd9Sstevel@tonic-gate 752*7c478bd9Sstevel@tonic-gate (void) sbus_resume_init(softsp, 0); 753*7c478bd9Sstevel@tonic-gate 754*7c478bd9Sstevel@tonic-gate /* 755*7c478bd9Sstevel@tonic-gate * Set the initial burstsizes for each slot to all 1's. This will 756*7c478bd9Sstevel@tonic-gate * get changed at initchild time. 757*7c478bd9Sstevel@tonic-gate */ 758*7c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_SBUS_SLOTS; i++) 759*7c478bd9Sstevel@tonic-gate softsp->sbus_slave_burstsizes[i] = 0xffffffffu; 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate /* 762*7c478bd9Sstevel@tonic-gate * Since SYSIO is used as an interrupt mastering device for slave 763*7c478bd9Sstevel@tonic-gate * only UPA devices, we call a dedicated kernel function to register 764*7c478bd9Sstevel@tonic-gate * The address of the interrupt mapping register for the slave device. 765*7c478bd9Sstevel@tonic-gate * 766*7c478bd9Sstevel@tonic-gate * If RISC/sysio is wired to support 2 upa slave interrupt 767*7c478bd9Sstevel@tonic-gate * devices then register 2nd mapping register with system. 768*7c478bd9Sstevel@tonic-gate * The slave/proxy portid algorithm (decribed in Fusion Desktop Spec) 769*7c478bd9Sstevel@tonic-gate * allows for upto 3 slaves per proxy but Psycho/SYSIO only support 2. 770*7c478bd9Sstevel@tonic-gate * 771*7c478bd9Sstevel@tonic-gate * #upa-interrupt-proxies property defines how many UPA interrupt 772*7c478bd9Sstevel@tonic-gate * slaves a bridge is wired to support. Older systems that lack 773*7c478bd9Sstevel@tonic-gate * this property will default to 1. 774*7c478bd9Sstevel@tonic-gate */ 775*7c478bd9Sstevel@tonic-gate numproxy = ddi_prop_get_int(DDI_DEV_T_ANY, softsp->dip, 776*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "#upa-interrupt-proxies", 1); 777*7c478bd9Sstevel@tonic-gate 778*7c478bd9Sstevel@tonic-gate if (numproxy > 0) 779*7c478bd9Sstevel@tonic-gate set_intr_mapping_reg(softsp->upa_id, 780*7c478bd9Sstevel@tonic-gate (uint64_t *)(softsp->intr_mapping_reg + 781*7c478bd9Sstevel@tonic-gate FFB_MAPPING_REG), 1); 782*7c478bd9Sstevel@tonic-gate 783*7c478bd9Sstevel@tonic-gate if (numproxy > 1) 784*7c478bd9Sstevel@tonic-gate set_intr_mapping_reg(softsp->upa_id, 785*7c478bd9Sstevel@tonic-gate (uint64_t *)(softsp->intr_mapping_reg + 786*7c478bd9Sstevel@tonic-gate EXP_MAPPING_REG), 2); 787*7c478bd9Sstevel@tonic-gate 788*7c478bd9Sstevel@tonic-gate /* support for a 3 interrupt proxy would go here */ 789*7c478bd9Sstevel@tonic-gate 790*7c478bd9Sstevel@tonic-gate /* Turn on spurious interrupt counter if we're not a DEBUG kernel. */ 791*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 792*7c478bd9Sstevel@tonic-gate intr_cntr_on = 1; 793*7c478bd9Sstevel@tonic-gate #else 794*7c478bd9Sstevel@tonic-gate intr_cntr_on = 0; 795*7c478bd9Sstevel@tonic-gate #endif 796*7c478bd9Sstevel@tonic-gate 797*7c478bd9Sstevel@tonic-gate 798*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 799*7c478bd9Sstevel@tonic-gate } 800*7c478bd9Sstevel@tonic-gate 801*7c478bd9Sstevel@tonic-gate /* 802*7c478bd9Sstevel@tonic-gate * This procedure is part of sbus initialization. It is called by 803*7c478bd9Sstevel@tonic-gate * sbus_init() and is invoked when the system is being resumed. 804*7c478bd9Sstevel@tonic-gate */ 805*7c478bd9Sstevel@tonic-gate static int 806*7c478bd9Sstevel@tonic-gate sbus_resume_init(struct sbus_soft_state *softsp, int resume) 807*7c478bd9Sstevel@tonic-gate { 808*7c478bd9Sstevel@tonic-gate int i; 809*7c478bd9Sstevel@tonic-gate uint_t sbus_burst_sizes; 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate /* 812*7c478bd9Sstevel@tonic-gate * This shouldn't be needed when we have a real OBP PROM. 813*7c478bd9Sstevel@tonic-gate * (RAZ) Get rid of this later!!! 814*7c478bd9Sstevel@tonic-gate */ 815*7c478bd9Sstevel@tonic-gate 816*7c478bd9Sstevel@tonic-gate #ifdef _STARFIRE 817*7c478bd9Sstevel@tonic-gate /* 818*7c478bd9Sstevel@tonic-gate * For Starfire, we need to program a 819*7c478bd9Sstevel@tonic-gate * constant odd value. 820*7c478bd9Sstevel@tonic-gate * Zero out the MID field before ORing 821*7c478bd9Sstevel@tonic-gate * We leave the LSB of the MID field intact since 822*7c478bd9Sstevel@tonic-gate * we cannot have a zero(even) MID value 823*7c478bd9Sstevel@tonic-gate */ 824*7c478bd9Sstevel@tonic-gate uint64_t tmpconst = 0x1DULL; 825*7c478bd9Sstevel@tonic-gate *softsp->sysio_ctrl_reg &= 0xFF0FFFFFFFFFFFFFULL; 826*7c478bd9Sstevel@tonic-gate *softsp->sysio_ctrl_reg |= tmpconst << 51; 827*7c478bd9Sstevel@tonic-gate 828*7c478bd9Sstevel@tonic-gate /* 829*7c478bd9Sstevel@tonic-gate * Program in the interrupt group number 830*7c478bd9Sstevel@tonic-gate * Here we have to convert the starfire 831*7c478bd9Sstevel@tonic-gate * 7 bit upaid into a 5bit value. 832*7c478bd9Sstevel@tonic-gate */ 833*7c478bd9Sstevel@tonic-gate *softsp->sysio_ctrl_reg |= 834*7c478bd9Sstevel@tonic-gate (uint64_t)STARFIRE_UPAID2HWIGN(softsp->upa_id) 835*7c478bd9Sstevel@tonic-gate << SYSIO_IGN; 836*7c478bd9Sstevel@tonic-gate #else 837*7c478bd9Sstevel@tonic-gate /* for the rest of sun4u's */ 838*7c478bd9Sstevel@tonic-gate *softsp->sysio_ctrl_reg |= 839*7c478bd9Sstevel@tonic-gate (uint64_t)softsp->upa_id << 51; 840*7c478bd9Sstevel@tonic-gate 841*7c478bd9Sstevel@tonic-gate /* Program in the interrupt group number */ 842*7c478bd9Sstevel@tonic-gate *softsp->sysio_ctrl_reg |= 843*7c478bd9Sstevel@tonic-gate (uint64_t)softsp->upa_id << SYSIO_IGN; 844*7c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */ 845*7c478bd9Sstevel@tonic-gate 846*7c478bd9Sstevel@tonic-gate /* 847*7c478bd9Sstevel@tonic-gate * Set appropriate fields of sbus control register. 848*7c478bd9Sstevel@tonic-gate * Set DVMA arbitration enable for all devices. 849*7c478bd9Sstevel@tonic-gate */ 850*7c478bd9Sstevel@tonic-gate *softsp->sbus_ctrl_reg |= SBUS_ARBIT_ALL; 851*7c478bd9Sstevel@tonic-gate 852*7c478bd9Sstevel@tonic-gate /* Calculate our burstsizes now so we don't have to do it later */ 853*7c478bd9Sstevel@tonic-gate sbus_burst_sizes = (SYSIO64_BURST_RANGE << SYSIO64_BURST_SHIFT) 854*7c478bd9Sstevel@tonic-gate | SYSIO_BURST_RANGE; 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate sbus_burst_sizes = ddi_getprop(DDI_DEV_T_ANY, softsp->dip, 857*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "up-burst-sizes", sbus_burst_sizes); 858*7c478bd9Sstevel@tonic-gate 859*7c478bd9Sstevel@tonic-gate softsp->sbus_burst_sizes = sbus_burst_sizes & SYSIO_BURST_MASK; 860*7c478bd9Sstevel@tonic-gate softsp->sbus64_burst_sizes = sbus_burst_sizes & SYSIO64_BURST_MASK; 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate if (!resume) { 863*7c478bd9Sstevel@tonic-gate /* Set burstsizes to smallest value */ 864*7c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_SBUS_SLOTS; i++) { 865*7c478bd9Sstevel@tonic-gate volatile uint64_t *config; 866*7c478bd9Sstevel@tonic-gate uint64_t tmpreg; 867*7c478bd9Sstevel@tonic-gate 868*7c478bd9Sstevel@tonic-gate config = softsp->sbus_slot_config_reg + i; 869*7c478bd9Sstevel@tonic-gate 870*7c478bd9Sstevel@tonic-gate /* Write out the burst size */ 871*7c478bd9Sstevel@tonic-gate tmpreg = (uint64_t)0; 872*7c478bd9Sstevel@tonic-gate *config = tmpreg; 873*7c478bd9Sstevel@tonic-gate 874*7c478bd9Sstevel@tonic-gate /* Flush any write buffers */ 875*7c478bd9Sstevel@tonic-gate tmpreg = *softsp->sbus_ctrl_reg; 876*7c478bd9Sstevel@tonic-gate 877*7c478bd9Sstevel@tonic-gate DPRINTF(SBUS_REGISTERS_DEBUG, ("Sbus slot 0x%x slot " 878*7c478bd9Sstevel@tonic-gate "configuration reg: 0x%x", (i > 3) ? i + 9 : i, 879*7c478bd9Sstevel@tonic-gate config)); 880*7c478bd9Sstevel@tonic-gate } 881*7c478bd9Sstevel@tonic-gate } else { 882*7c478bd9Sstevel@tonic-gate /* Program the slot configuration registers */ 883*7c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_SBUS_SLOTS; i++) { 884*7c478bd9Sstevel@tonic-gate volatile uint64_t *config; 885*7c478bd9Sstevel@tonic-gate #ifndef lint 886*7c478bd9Sstevel@tonic-gate uint64_t tmpreg; 887*7c478bd9Sstevel@tonic-gate #endif /* !lint */ 888*7c478bd9Sstevel@tonic-gate uint_t slave_burstsizes; 889*7c478bd9Sstevel@tonic-gate 890*7c478bd9Sstevel@tonic-gate slave_burstsizes = 0; 891*7c478bd9Sstevel@tonic-gate if (softsp->sbus_slave_burstsizes[i] != 0xffffffffu) { 892*7c478bd9Sstevel@tonic-gate config = softsp->sbus_slot_config_reg + i; 893*7c478bd9Sstevel@tonic-gate 894*7c478bd9Sstevel@tonic-gate if (softsp->sbus_slave_burstsizes[i] & 895*7c478bd9Sstevel@tonic-gate SYSIO64_BURST_MASK) { 896*7c478bd9Sstevel@tonic-gate /* get the 64 bit burstsizes */ 897*7c478bd9Sstevel@tonic-gate slave_burstsizes = 898*7c478bd9Sstevel@tonic-gate softsp->sbus_slave_burstsizes[i] >> 899*7c478bd9Sstevel@tonic-gate SYSIO64_BURST_SHIFT; 900*7c478bd9Sstevel@tonic-gate 901*7c478bd9Sstevel@tonic-gate /* Turn on 64 bit PIO's on the sbus */ 902*7c478bd9Sstevel@tonic-gate *config |= SBUS_ETM; 903*7c478bd9Sstevel@tonic-gate } else { 904*7c478bd9Sstevel@tonic-gate slave_burstsizes = 905*7c478bd9Sstevel@tonic-gate softsp->sbus_slave_burstsizes[i] & 906*7c478bd9Sstevel@tonic-gate SYSIO_BURST_MASK; 907*7c478bd9Sstevel@tonic-gate } 908*7c478bd9Sstevel@tonic-gate 909*7c478bd9Sstevel@tonic-gate /* Get burstsizes into sysio register format */ 910*7c478bd9Sstevel@tonic-gate slave_burstsizes >>= SYSIO_SLAVEBURST_REGSHIFT; 911*7c478bd9Sstevel@tonic-gate 912*7c478bd9Sstevel@tonic-gate /* Program the burstsizes */ 913*7c478bd9Sstevel@tonic-gate *config |= (uint64_t)slave_burstsizes; 914*7c478bd9Sstevel@tonic-gate 915*7c478bd9Sstevel@tonic-gate /* Flush any write buffers */ 916*7c478bd9Sstevel@tonic-gate #ifndef lint 917*7c478bd9Sstevel@tonic-gate tmpreg = *softsp->sbus_ctrl_reg; 918*7c478bd9Sstevel@tonic-gate #endif /* !lint */ 919*7c478bd9Sstevel@tonic-gate } 920*7c478bd9Sstevel@tonic-gate } 921*7c478bd9Sstevel@tonic-gate } 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 924*7c478bd9Sstevel@tonic-gate } 925*7c478bd9Sstevel@tonic-gate 926*7c478bd9Sstevel@tonic-gate #define get_prop(di, pname, flag, pval, plen) \ 927*7c478bd9Sstevel@tonic-gate (ddi_prop_op(DDI_DEV_T_NONE, di, PROP_LEN_AND_VAL_ALLOC, \ 928*7c478bd9Sstevel@tonic-gate flag | DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, \ 929*7c478bd9Sstevel@tonic-gate pname, (caddr_t)pval, plen)) 930*7c478bd9Sstevel@tonic-gate 931*7c478bd9Sstevel@tonic-gate struct prop_ispec { 932*7c478bd9Sstevel@tonic-gate uint_t pri, vec; 933*7c478bd9Sstevel@tonic-gate }; 934*7c478bd9Sstevel@tonic-gate 935*7c478bd9Sstevel@tonic-gate /* 936*7c478bd9Sstevel@tonic-gate * Create a sysio_parent_private_data structure from the ddi properties of 937*7c478bd9Sstevel@tonic-gate * the dev_info node. 938*7c478bd9Sstevel@tonic-gate * 939*7c478bd9Sstevel@tonic-gate * The "reg" and either an "intr" or "interrupts" properties are required 940*7c478bd9Sstevel@tonic-gate * if the driver wishes to create mappings or field interrupts on behalf 941*7c478bd9Sstevel@tonic-gate * of the device. 942*7c478bd9Sstevel@tonic-gate * 943*7c478bd9Sstevel@tonic-gate * The "reg" property is assumed to be a list of at least one triple 944*7c478bd9Sstevel@tonic-gate * 945*7c478bd9Sstevel@tonic-gate * <bustype, address, size>*1 946*7c478bd9Sstevel@tonic-gate * 947*7c478bd9Sstevel@tonic-gate * On pre-fusion machines, the "intr" property was the IPL for the system. 948*7c478bd9Sstevel@tonic-gate * Most new sbus devices post an "interrupts" property that corresponds to 949*7c478bd9Sstevel@tonic-gate * a particular bus level. All devices on fusion using an "intr" property 950*7c478bd9Sstevel@tonic-gate * will have it's contents translated into a bus level. Hence, "intr" and 951*7c478bd9Sstevel@tonic-gate * "interrupts on the fusion platform can be treated the same. 952*7c478bd9Sstevel@tonic-gate * 953*7c478bd9Sstevel@tonic-gate * The "interrupts" property is assumed to be a list of at least one 954*7c478bd9Sstevel@tonic-gate * n-tuples that describes the interrupt capabilities of the bus the device 955*7c478bd9Sstevel@tonic-gate * is connected to. For SBus, this looks like 956*7c478bd9Sstevel@tonic-gate * 957*7c478bd9Sstevel@tonic-gate * <SBus-level>*1 958*7c478bd9Sstevel@tonic-gate * 959*7c478bd9Sstevel@tonic-gate * (This property obsoletes the 'intr' property). 960*7c478bd9Sstevel@tonic-gate * 961*7c478bd9Sstevel@tonic-gate * The OBP_RANGES property is optional. 962*7c478bd9Sstevel@tonic-gate */ 963*7c478bd9Sstevel@tonic-gate static void 964*7c478bd9Sstevel@tonic-gate make_sbus_ppd(dev_info_t *child) 965*7c478bd9Sstevel@tonic-gate { 966*7c478bd9Sstevel@tonic-gate struct sysio_parent_private_data *pdptr; 967*7c478bd9Sstevel@tonic-gate int n; 968*7c478bd9Sstevel@tonic-gate int *reg_prop, *rgstr_prop, *rng_prop; 969*7c478bd9Sstevel@tonic-gate int reg_len, rgstr_len, rng_len; 970*7c478bd9Sstevel@tonic-gate 971*7c478bd9Sstevel@tonic-gate /* 972*7c478bd9Sstevel@tonic-gate * Make the function idempotent, because name_child could 973*7c478bd9Sstevel@tonic-gate * be called multiple times on a node. 974*7c478bd9Sstevel@tonic-gate */ 975*7c478bd9Sstevel@tonic-gate if (ddi_get_parent_data(child) != NULL) 976*7c478bd9Sstevel@tonic-gate return; 977*7c478bd9Sstevel@tonic-gate 978*7c478bd9Sstevel@tonic-gate pdptr = kmem_zalloc(sizeof (*pdptr), KM_SLEEP); 979*7c478bd9Sstevel@tonic-gate ddi_set_parent_data(child, pdptr); 980*7c478bd9Sstevel@tonic-gate 981*7c478bd9Sstevel@tonic-gate /* 982*7c478bd9Sstevel@tonic-gate * Handle the 'reg'/'registers' properties. 983*7c478bd9Sstevel@tonic-gate * "registers" overrides "reg", but requires that "reg" be exported, 984*7c478bd9Sstevel@tonic-gate * so we can handle wildcard specifiers. "registers" implies an 985*7c478bd9Sstevel@tonic-gate * sbus style device. "registers" implies that we insert the 986*7c478bd9Sstevel@tonic-gate * correct value in the regspec_bustype field of each spec for a real 987*7c478bd9Sstevel@tonic-gate * (non-pseudo) device node. "registers" is a s/w only property, so 988*7c478bd9Sstevel@tonic-gate * we inhibit the prom search for this property. 989*7c478bd9Sstevel@tonic-gate */ 990*7c478bd9Sstevel@tonic-gate if (get_prop(child, OBP_REG, 0, ®_prop, ®_len) != DDI_SUCCESS) 991*7c478bd9Sstevel@tonic-gate reg_len = 0; 992*7c478bd9Sstevel@tonic-gate 993*7c478bd9Sstevel@tonic-gate /* 994*7c478bd9Sstevel@tonic-gate * Save the underlying slot number and slot offset. 995*7c478bd9Sstevel@tonic-gate * Among other things, we use these to name the child node. 996*7c478bd9Sstevel@tonic-gate */ 997*7c478bd9Sstevel@tonic-gate pdptr->slot = (uint_t)-1; 998*7c478bd9Sstevel@tonic-gate if (reg_len != 0) { 999*7c478bd9Sstevel@tonic-gate pdptr->slot = ((struct regspec *)reg_prop)->regspec_bustype; 1000*7c478bd9Sstevel@tonic-gate pdptr->offset = ((struct regspec *)reg_prop)->regspec_addr; 1001*7c478bd9Sstevel@tonic-gate } 1002*7c478bd9Sstevel@tonic-gate 1003*7c478bd9Sstevel@tonic-gate rgstr_len = 0; 1004*7c478bd9Sstevel@tonic-gate (void) get_prop(child, "registers", DDI_PROP_NOTPROM, 1005*7c478bd9Sstevel@tonic-gate &rgstr_prop, &rgstr_len); 1006*7c478bd9Sstevel@tonic-gate 1007*7c478bd9Sstevel@tonic-gate if (rgstr_len != 0) { 1008*7c478bd9Sstevel@tonic-gate if (ndi_dev_is_persistent_node(child) && (reg_len != 0)) { 1009*7c478bd9Sstevel@tonic-gate /* 1010*7c478bd9Sstevel@tonic-gate * Convert wildcard "registers" for a real node... 1011*7c478bd9Sstevel@tonic-gate * (Else, this is the wildcard prototype node) 1012*7c478bd9Sstevel@tonic-gate */ 1013*7c478bd9Sstevel@tonic-gate struct regspec *rp = (struct regspec *)reg_prop; 1014*7c478bd9Sstevel@tonic-gate uint_t slot = rp->regspec_bustype; 1015*7c478bd9Sstevel@tonic-gate int i; 1016*7c478bd9Sstevel@tonic-gate 1017*7c478bd9Sstevel@tonic-gate rp = (struct regspec *)rgstr_prop; 1018*7c478bd9Sstevel@tonic-gate n = rgstr_len / sizeof (struct regspec); 1019*7c478bd9Sstevel@tonic-gate for (i = 0; i < n; ++i, ++rp) 1020*7c478bd9Sstevel@tonic-gate rp->regspec_bustype = slot; 1021*7c478bd9Sstevel@tonic-gate } 1022*7c478bd9Sstevel@tonic-gate 1023*7c478bd9Sstevel@tonic-gate if (reg_len != 0) 1024*7c478bd9Sstevel@tonic-gate kmem_free(reg_prop, reg_len); 1025*7c478bd9Sstevel@tonic-gate 1026*7c478bd9Sstevel@tonic-gate reg_prop = rgstr_prop; 1027*7c478bd9Sstevel@tonic-gate reg_len = rgstr_len; 1028*7c478bd9Sstevel@tonic-gate } 1029*7c478bd9Sstevel@tonic-gate if (reg_len != 0) { 1030*7c478bd9Sstevel@tonic-gate pdptr->par_nreg = reg_len / (int)sizeof (struct regspec); 1031*7c478bd9Sstevel@tonic-gate pdptr->par_reg = (struct regspec *)reg_prop; 1032*7c478bd9Sstevel@tonic-gate } 1033*7c478bd9Sstevel@tonic-gate 1034*7c478bd9Sstevel@tonic-gate /* 1035*7c478bd9Sstevel@tonic-gate * See if I have ranges. 1036*7c478bd9Sstevel@tonic-gate */ 1037*7c478bd9Sstevel@tonic-gate if (get_prop(child, OBP_RANGES, 0, &rng_prop, &rng_len) == 1038*7c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 1039*7c478bd9Sstevel@tonic-gate pdptr->par_nrng = rng_len / (int)(sizeof (struct rangespec)); 1040*7c478bd9Sstevel@tonic-gate pdptr->par_rng = (struct rangespec *)rng_prop; 1041*7c478bd9Sstevel@tonic-gate } 1042*7c478bd9Sstevel@tonic-gate } 1043*7c478bd9Sstevel@tonic-gate 1044*7c478bd9Sstevel@tonic-gate /* 1045*7c478bd9Sstevel@tonic-gate * Special handling for "sbusmem" pseudo device nodes. 1046*7c478bd9Sstevel@tonic-gate * The special handling automatically creates the "reg" 1047*7c478bd9Sstevel@tonic-gate * property in the sbusmem nodes, based on the parent's 1048*7c478bd9Sstevel@tonic-gate * property so that each slot will automtically have a 1049*7c478bd9Sstevel@tonic-gate * correctly sized "reg" property, once created, 1050*7c478bd9Sstevel@tonic-gate * sbus_initchild does the rest of the work to init 1051*7c478bd9Sstevel@tonic-gate * the child node. 1052*7c478bd9Sstevel@tonic-gate */ 1053*7c478bd9Sstevel@tonic-gate static int 1054*7c478bd9Sstevel@tonic-gate sbusmem_initchild(dev_info_t *dip, dev_info_t *child) 1055*7c478bd9Sstevel@tonic-gate { 1056*7c478bd9Sstevel@tonic-gate int i, n; 1057*7c478bd9Sstevel@tonic-gate int slot, size; 1058*7c478bd9Sstevel@tonic-gate char ident[10]; 1059*7c478bd9Sstevel@tonic-gate 1060*7c478bd9Sstevel@tonic-gate slot = ddi_getprop(DDI_DEV_T_NONE, child, 1061*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "slot", -1); 1062*7c478bd9Sstevel@tonic-gate if (slot == -1) { 1063*7c478bd9Sstevel@tonic-gate DPRINTF(SBUS_SBUSMEM_DEBUG, ("can't get slot property\n")); 1064*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1065*7c478bd9Sstevel@tonic-gate } 1066*7c478bd9Sstevel@tonic-gate 1067*7c478bd9Sstevel@tonic-gate /* 1068*7c478bd9Sstevel@tonic-gate * Find the parent range corresponding to this "slot", 1069*7c478bd9Sstevel@tonic-gate * so we can set the size of the child's "reg" property. 1070*7c478bd9Sstevel@tonic-gate */ 1071*7c478bd9Sstevel@tonic-gate for (i = 0, n = sparc_pd_getnrng(dip); i < n; i++) { 1072*7c478bd9Sstevel@tonic-gate struct rangespec *rp = sparc_pd_getrng(dip, i); 1073*7c478bd9Sstevel@tonic-gate 1074*7c478bd9Sstevel@tonic-gate if (rp->rng_cbustype == (uint_t)slot) { 1075*7c478bd9Sstevel@tonic-gate struct regspec r; 1076*7c478bd9Sstevel@tonic-gate 1077*7c478bd9Sstevel@tonic-gate /* create reg property */ 1078*7c478bd9Sstevel@tonic-gate 1079*7c478bd9Sstevel@tonic-gate r.regspec_bustype = (uint_t)slot; 1080*7c478bd9Sstevel@tonic-gate r.regspec_addr = 0; 1081*7c478bd9Sstevel@tonic-gate r.regspec_size = rp->rng_size; 1082*7c478bd9Sstevel@tonic-gate (void) ddi_prop_update_int_array(DDI_DEV_T_NONE, 1083*7c478bd9Sstevel@tonic-gate child, "reg", (int *)&r, 1084*7c478bd9Sstevel@tonic-gate sizeof (struct regspec) / sizeof (int)); 1085*7c478bd9Sstevel@tonic-gate 1086*7c478bd9Sstevel@tonic-gate /* create size property for slot */ 1087*7c478bd9Sstevel@tonic-gate 1088*7c478bd9Sstevel@tonic-gate size = rp->rng_size; 1089*7c478bd9Sstevel@tonic-gate (void) ddi_prop_update_int(DDI_DEV_T_NONE, 1090*7c478bd9Sstevel@tonic-gate child, "size", size); 1091*7c478bd9Sstevel@tonic-gate 1092*7c478bd9Sstevel@tonic-gate (void) sprintf(ident, "slot%x", slot); 1093*7c478bd9Sstevel@tonic-gate (void) ddi_prop_update_string(DDI_DEV_T_NONE, 1094*7c478bd9Sstevel@tonic-gate child, "ident", ident); 1095*7c478bd9Sstevel@tonic-gate 1096*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1097*7c478bd9Sstevel@tonic-gate } 1098*7c478bd9Sstevel@tonic-gate } 1099*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1100*7c478bd9Sstevel@tonic-gate } 1101*7c478bd9Sstevel@tonic-gate 1102*7c478bd9Sstevel@tonic-gate /* 1103*7c478bd9Sstevel@tonic-gate * Nexus routine to name a child. 1104*7c478bd9Sstevel@tonic-gate * It takes a dev_info node and a buffer, returns the name 1105*7c478bd9Sstevel@tonic-gate * in the buffer. 1106*7c478bd9Sstevel@tonic-gate */ 1107*7c478bd9Sstevel@tonic-gate static int 1108*7c478bd9Sstevel@tonic-gate sysio_name_child(dev_info_t *child, char *name, int namelen) 1109*7c478bd9Sstevel@tonic-gate { 1110*7c478bd9Sstevel@tonic-gate /* 1111*7c478bd9Sstevel@tonic-gate * Fill in parent-private data 1112*7c478bd9Sstevel@tonic-gate */ 1113*7c478bd9Sstevel@tonic-gate make_sbus_ppd(child); 1114*7c478bd9Sstevel@tonic-gate 1115*7c478bd9Sstevel@tonic-gate /* 1116*7c478bd9Sstevel@tonic-gate * Name the device node using the underlying (prom) values 1117*7c478bd9Sstevel@tonic-gate * of the first entry in the "reg" property. For SBus devices, 1118*7c478bd9Sstevel@tonic-gate * the textual form of the name is <name>@<slot#>,<offset>. 1119*7c478bd9Sstevel@tonic-gate * This must match the prom's pathname or mountroot, etc, won't 1120*7c478bd9Sstevel@tonic-gate */ 1121*7c478bd9Sstevel@tonic-gate name[0] = '\0'; 1122*7c478bd9Sstevel@tonic-gate if (sysio_pd_getslot(child) != (uint_t)-1) { 1123*7c478bd9Sstevel@tonic-gate (void) snprintf(name, namelen, "%x,%x", 1124*7c478bd9Sstevel@tonic-gate sysio_pd_getslot(child), sysio_pd_getoffset(child)); 1125*7c478bd9Sstevel@tonic-gate } 1126*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1127*7c478bd9Sstevel@tonic-gate } 1128*7c478bd9Sstevel@tonic-gate 1129*7c478bd9Sstevel@tonic-gate /* 1130*7c478bd9Sstevel@tonic-gate * Called from the bus_ctl op of sysio sbus nexus driver 1131*7c478bd9Sstevel@tonic-gate * to implement the DDI_CTLOPS_INITCHILD operation. That is, it names 1132*7c478bd9Sstevel@tonic-gate * the children of sysio sbusses based on the reg spec. 1133*7c478bd9Sstevel@tonic-gate * 1134*7c478bd9Sstevel@tonic-gate * Handles the following properties: 1135*7c478bd9Sstevel@tonic-gate * 1136*7c478bd9Sstevel@tonic-gate * Property value 1137*7c478bd9Sstevel@tonic-gate * Name type 1138*7c478bd9Sstevel@tonic-gate * 1139*7c478bd9Sstevel@tonic-gate * reg register spec 1140*7c478bd9Sstevel@tonic-gate * registers wildcard s/w sbus register spec (.conf file property) 1141*7c478bd9Sstevel@tonic-gate * intr old-form interrupt spec 1142*7c478bd9Sstevel@tonic-gate * interrupts new (bus-oriented) interrupt spec 1143*7c478bd9Sstevel@tonic-gate * ranges range spec 1144*7c478bd9Sstevel@tonic-gate */ 1145*7c478bd9Sstevel@tonic-gate static int 1146*7c478bd9Sstevel@tonic-gate sbus_initchild(dev_info_t *dip, dev_info_t *child) 1147*7c478bd9Sstevel@tonic-gate { 1148*7c478bd9Sstevel@tonic-gate char name[MAXNAMELEN]; 1149*7c478bd9Sstevel@tonic-gate ulong_t slave_burstsizes; 1150*7c478bd9Sstevel@tonic-gate int slot; 1151*7c478bd9Sstevel@tonic-gate volatile uint64_t *slot_reg; 1152*7c478bd9Sstevel@tonic-gate #ifndef lint 1153*7c478bd9Sstevel@tonic-gate uint64_t tmp; 1154*7c478bd9Sstevel@tonic-gate #endif /* !lint */ 1155*7c478bd9Sstevel@tonic-gate struct sbus_soft_state *softsp = (struct sbus_soft_state *) 1156*7c478bd9Sstevel@tonic-gate ddi_get_soft_state(sbusp, ddi_get_instance(dip)); 1157*7c478bd9Sstevel@tonic-gate 1158*7c478bd9Sstevel@tonic-gate if (strcmp(ddi_get_name(child), "sbusmem") == 0) { 1159*7c478bd9Sstevel@tonic-gate if (sbusmem_initchild(dip, child) != DDI_SUCCESS) 1160*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1161*7c478bd9Sstevel@tonic-gate } 1162*7c478bd9Sstevel@tonic-gate 1163*7c478bd9Sstevel@tonic-gate /* 1164*7c478bd9Sstevel@tonic-gate * If this is a s/w node defined with the "registers" property, 1165*7c478bd9Sstevel@tonic-gate * this means that this is a wildcard specifier, whose properties 1166*7c478bd9Sstevel@tonic-gate * get applied to all previously defined h/w nodes with the same 1167*7c478bd9Sstevel@tonic-gate * name and same parent. 1168*7c478bd9Sstevel@tonic-gate */ 1169*7c478bd9Sstevel@tonic-gate if (ndi_dev_is_persistent_node(child) == 0) { 1170*7c478bd9Sstevel@tonic-gate int len = 0; 1171*7c478bd9Sstevel@tonic-gate if ((ddi_getproplen(DDI_DEV_T_ANY, child, DDI_PROP_NOTPROM, 1172*7c478bd9Sstevel@tonic-gate "registers", &len) == DDI_SUCCESS) && (len != 0)) { 1173*7c478bd9Sstevel@tonic-gate ndi_merge_wildcard_node(child); 1174*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1175*7c478bd9Sstevel@tonic-gate } 1176*7c478bd9Sstevel@tonic-gate } 1177*7c478bd9Sstevel@tonic-gate 1178*7c478bd9Sstevel@tonic-gate /* name the child */ 1179*7c478bd9Sstevel@tonic-gate (void) sysio_name_child(child, name, MAXNAMELEN); 1180*7c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, name); 1181*7c478bd9Sstevel@tonic-gate 1182*7c478bd9Sstevel@tonic-gate /* 1183*7c478bd9Sstevel@tonic-gate * If a pseudo node, attempt to merge it into a hw node. 1184*7c478bd9Sstevel@tonic-gate * If merge is successful, we uinitialize the node and 1185*7c478bd9Sstevel@tonic-gate * return failure, to allow caller to remove the node. 1186*7c478bd9Sstevel@tonic-gate * The merge fails, this is a real pseudo node. Allow 1187*7c478bd9Sstevel@tonic-gate * initchild to continue. 1188*7c478bd9Sstevel@tonic-gate */ 1189*7c478bd9Sstevel@tonic-gate if ((ndi_dev_is_persistent_node(child) == 0) && 1190*7c478bd9Sstevel@tonic-gate (ndi_merge_node(child, sysio_name_child) == DDI_SUCCESS)) { 1191*7c478bd9Sstevel@tonic-gate (void) sbus_uninitchild(child); 1192*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1193*7c478bd9Sstevel@tonic-gate } 1194*7c478bd9Sstevel@tonic-gate 1195*7c478bd9Sstevel@tonic-gate /* Figure out the child devices slot number */ 1196*7c478bd9Sstevel@tonic-gate slot = sysio_pd_getslot(child); 1197*7c478bd9Sstevel@tonic-gate 1198*7c478bd9Sstevel@tonic-gate /* If we don't have a reg property, bypass slot specific programming */ 1199*7c478bd9Sstevel@tonic-gate if (slot < 0 || slot >= MAX_SBUS_SLOT_ADDR) { 1200*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1201*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "?Invalid sbus slot address 0x%x for %s " 1202*7c478bd9Sstevel@tonic-gate "device\n", slot, ddi_get_name(child)); 1203*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 1204*7c478bd9Sstevel@tonic-gate goto done; 1205*7c478bd9Sstevel@tonic-gate } 1206*7c478bd9Sstevel@tonic-gate 1207*7c478bd9Sstevel@tonic-gate /* Modify the onboard slot numbers if applicable. */ 1208*7c478bd9Sstevel@tonic-gate slot = (slot > 3) ? slot - 9 : slot; 1209*7c478bd9Sstevel@tonic-gate 1210*7c478bd9Sstevel@tonic-gate /* Get the slot configuration register for the child device. */ 1211*7c478bd9Sstevel@tonic-gate slot_reg = softsp->sbus_slot_config_reg + slot; 1212*7c478bd9Sstevel@tonic-gate 1213*7c478bd9Sstevel@tonic-gate /* 1214*7c478bd9Sstevel@tonic-gate * Program the devices slot configuration register for the 1215*7c478bd9Sstevel@tonic-gate * appropriate slave burstsizes. 1216*7c478bd9Sstevel@tonic-gate * The upper 16 bits of the slave-burst-sizes are for 64 bit sbus 1217*7c478bd9Sstevel@tonic-gate * and the lower 16 bits are the burst sizes for 32 bit sbus. If 1218*7c478bd9Sstevel@tonic-gate * we see that a device supports both 64 bit and 32 bit slave accesses, 1219*7c478bd9Sstevel@tonic-gate * we default to 64 bit and turn it on in the slot config reg. 1220*7c478bd9Sstevel@tonic-gate * 1221*7c478bd9Sstevel@tonic-gate * For older devices, make sure we check the "burst-sizes" property 1222*7c478bd9Sstevel@tonic-gate * too. 1223*7c478bd9Sstevel@tonic-gate */ 1224*7c478bd9Sstevel@tonic-gate if ((slave_burstsizes = (ulong_t)ddi_getprop(DDI_DEV_T_ANY, child, 1225*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "slave-burst-sizes", 0)) != 0 || 1226*7c478bd9Sstevel@tonic-gate (slave_burstsizes = (ulong_t)ddi_getprop(DDI_DEV_T_ANY, child, 1227*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "burst-sizes", 0)) != 0) { 1228*7c478bd9Sstevel@tonic-gate uint_t burstsizes = 0; 1229*7c478bd9Sstevel@tonic-gate 1230*7c478bd9Sstevel@tonic-gate /* 1231*7c478bd9Sstevel@tonic-gate * If we only have 32 bit burst sizes from a previous device, 1232*7c478bd9Sstevel@tonic-gate * mask out any burstsizes for 64 bit mode. 1233*7c478bd9Sstevel@tonic-gate */ 1234*7c478bd9Sstevel@tonic-gate if (((softsp->sbus_slave_burstsizes[slot] & 1235*7c478bd9Sstevel@tonic-gate 0xffff0000u) == 0) && 1236*7c478bd9Sstevel@tonic-gate ((softsp->sbus_slave_burstsizes[slot] & 0xffff) != 0)) { 1237*7c478bd9Sstevel@tonic-gate slave_burstsizes &= 0xffff; 1238*7c478bd9Sstevel@tonic-gate } 1239*7c478bd9Sstevel@tonic-gate 1240*7c478bd9Sstevel@tonic-gate /* 1241*7c478bd9Sstevel@tonic-gate * If "slave-burst-sizes was defined but we have 0 at this 1242*7c478bd9Sstevel@tonic-gate * point, we must have had 64 bit burstsizes, however a prior 1243*7c478bd9Sstevel@tonic-gate * device can only burst in 32 bit mode. Therefore, we leave 1244*7c478bd9Sstevel@tonic-gate * the burstsizes in the 32 bit mode and disregard the 64 bit. 1245*7c478bd9Sstevel@tonic-gate */ 1246*7c478bd9Sstevel@tonic-gate if (slave_burstsizes == 0) 1247*7c478bd9Sstevel@tonic-gate goto done; 1248*7c478bd9Sstevel@tonic-gate 1249*7c478bd9Sstevel@tonic-gate /* 1250*7c478bd9Sstevel@tonic-gate * We and in the new burst sizes with that of prior devices. 1251*7c478bd9Sstevel@tonic-gate * This ensures that we always take the least common 1252*7c478bd9Sstevel@tonic-gate * denominator of the burst sizes. 1253*7c478bd9Sstevel@tonic-gate */ 1254*7c478bd9Sstevel@tonic-gate softsp->sbus_slave_burstsizes[slot] &= 1255*7c478bd9Sstevel@tonic-gate (slave_burstsizes & 1256*7c478bd9Sstevel@tonic-gate ((SYSIO64_SLAVEBURST_RANGE << 1257*7c478bd9Sstevel@tonic-gate SYSIO64_BURST_SHIFT) | 1258*7c478bd9Sstevel@tonic-gate SYSIO_SLAVEBURST_RANGE)); 1259*7c478bd9Sstevel@tonic-gate 1260*7c478bd9Sstevel@tonic-gate /* Get the 64 bit burstsizes. */ 1261*7c478bd9Sstevel@tonic-gate if (softsp->sbus_slave_burstsizes[slot] & 1262*7c478bd9Sstevel@tonic-gate SYSIO64_BURST_MASK) { 1263*7c478bd9Sstevel@tonic-gate /* get the 64 bit burstsizes */ 1264*7c478bd9Sstevel@tonic-gate burstsizes = softsp->sbus_slave_burstsizes[slot] >> 1265*7c478bd9Sstevel@tonic-gate SYSIO64_BURST_SHIFT; 1266*7c478bd9Sstevel@tonic-gate 1267*7c478bd9Sstevel@tonic-gate /* Turn on 64 bit PIO's on the sbus */ 1268*7c478bd9Sstevel@tonic-gate *slot_reg |= SBUS_ETM; 1269*7c478bd9Sstevel@tonic-gate } else { 1270*7c478bd9Sstevel@tonic-gate /* Turn off 64 bit PIO's on the sbus */ 1271*7c478bd9Sstevel@tonic-gate *slot_reg &= ~SBUS_ETM; 1272*7c478bd9Sstevel@tonic-gate 1273*7c478bd9Sstevel@tonic-gate /* Get the 32 bit burstsizes if we don't have 64 bit. */ 1274*7c478bd9Sstevel@tonic-gate if (softsp->sbus_slave_burstsizes[slot] & 1275*7c478bd9Sstevel@tonic-gate SYSIO_BURST_MASK) { 1276*7c478bd9Sstevel@tonic-gate burstsizes = 1277*7c478bd9Sstevel@tonic-gate softsp->sbus_slave_burstsizes[slot] & 1278*7c478bd9Sstevel@tonic-gate SYSIO_BURST_MASK; 1279*7c478bd9Sstevel@tonic-gate } 1280*7c478bd9Sstevel@tonic-gate } 1281*7c478bd9Sstevel@tonic-gate 1282*7c478bd9Sstevel@tonic-gate /* Get the burstsizes into sysio register format */ 1283*7c478bd9Sstevel@tonic-gate burstsizes >>= SYSIO_SLAVEBURST_REGSHIFT; 1284*7c478bd9Sstevel@tonic-gate 1285*7c478bd9Sstevel@tonic-gate /* Reset reg in case we're scaling back */ 1286*7c478bd9Sstevel@tonic-gate *slot_reg &= (uint64_t)~SYSIO_SLAVEBURST_MASK; 1287*7c478bd9Sstevel@tonic-gate 1288*7c478bd9Sstevel@tonic-gate /* Program the burstsizes */ 1289*7c478bd9Sstevel@tonic-gate *slot_reg |= (uint64_t)burstsizes; 1290*7c478bd9Sstevel@tonic-gate 1291*7c478bd9Sstevel@tonic-gate /* Flush system load/store buffers */ 1292*7c478bd9Sstevel@tonic-gate #ifndef lint 1293*7c478bd9Sstevel@tonic-gate tmp = *slot_reg; 1294*7c478bd9Sstevel@tonic-gate #endif /* !lint */ 1295*7c478bd9Sstevel@tonic-gate } 1296*7c478bd9Sstevel@tonic-gate 1297*7c478bd9Sstevel@tonic-gate done: 1298*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1299*7c478bd9Sstevel@tonic-gate } 1300*7c478bd9Sstevel@tonic-gate 1301*7c478bd9Sstevel@tonic-gate static int 1302*7c478bd9Sstevel@tonic-gate sbus_uninitchild(dev_info_t *dip) 1303*7c478bd9Sstevel@tonic-gate { 1304*7c478bd9Sstevel@tonic-gate struct sysio_parent_private_data *pdptr; 1305*7c478bd9Sstevel@tonic-gate size_t n; 1306*7c478bd9Sstevel@tonic-gate 1307*7c478bd9Sstevel@tonic-gate if ((pdptr = ddi_get_parent_data(dip)) != NULL) { 1308*7c478bd9Sstevel@tonic-gate if ((n = (size_t)pdptr->par_nrng) != 0) 1309*7c478bd9Sstevel@tonic-gate kmem_free(pdptr->par_rng, n * 1310*7c478bd9Sstevel@tonic-gate sizeof (struct rangespec)); 1311*7c478bd9Sstevel@tonic-gate 1312*7c478bd9Sstevel@tonic-gate if ((n = pdptr->par_nreg) != 0) 1313*7c478bd9Sstevel@tonic-gate kmem_free(pdptr->par_reg, n * sizeof (struct regspec)); 1314*7c478bd9Sstevel@tonic-gate 1315*7c478bd9Sstevel@tonic-gate kmem_free(pdptr, sizeof (*pdptr)); 1316*7c478bd9Sstevel@tonic-gate ddi_set_parent_data(dip, NULL); 1317*7c478bd9Sstevel@tonic-gate } 1318*7c478bd9Sstevel@tonic-gate ddi_set_name_addr(dip, NULL); 1319*7c478bd9Sstevel@tonic-gate /* 1320*7c478bd9Sstevel@tonic-gate * Strip the node to properly convert it back to prototype form 1321*7c478bd9Sstevel@tonic-gate */ 1322*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 1323*7c478bd9Sstevel@tonic-gate impl_rem_dev_props(dip); 1324*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1325*7c478bd9Sstevel@tonic-gate } 1326*7c478bd9Sstevel@tonic-gate 1327*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1328*7c478bd9Sstevel@tonic-gate int sbus_peekfault_cnt = 0; 1329*7c478bd9Sstevel@tonic-gate int sbus_pokefault_cnt = 0; 1330*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 1331*7c478bd9Sstevel@tonic-gate 1332*7c478bd9Sstevel@tonic-gate static int 1333*7c478bd9Sstevel@tonic-gate sbus_ctlops_poke(struct sbus_soft_state *softsp, peekpoke_ctlops_t *in_args) 1334*7c478bd9Sstevel@tonic-gate { 1335*7c478bd9Sstevel@tonic-gate int err = DDI_SUCCESS; 1336*7c478bd9Sstevel@tonic-gate on_trap_data_t otd; 1337*7c478bd9Sstevel@tonic-gate volatile uint64_t tmpreg; 1338*7c478bd9Sstevel@tonic-gate 1339*7c478bd9Sstevel@tonic-gate /* Cautious access not supported. */ 1340*7c478bd9Sstevel@tonic-gate if (in_args->handle != NULL) 1341*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1342*7c478bd9Sstevel@tonic-gate 1343*7c478bd9Sstevel@tonic-gate mutex_enter(&softsp->pokefault_mutex); 1344*7c478bd9Sstevel@tonic-gate softsp->ontrap_data = &otd; 1345*7c478bd9Sstevel@tonic-gate 1346*7c478bd9Sstevel@tonic-gate /* Set up protected environment. */ 1347*7c478bd9Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 1348*7c478bd9Sstevel@tonic-gate uintptr_t tramp = otd.ot_trampoline; 1349*7c478bd9Sstevel@tonic-gate 1350*7c478bd9Sstevel@tonic-gate otd.ot_trampoline = (uintptr_t)&poke_fault; 1351*7c478bd9Sstevel@tonic-gate err = do_poke(in_args->size, (void *)in_args->dev_addr, 1352*7c478bd9Sstevel@tonic-gate (void *)in_args->host_addr); 1353*7c478bd9Sstevel@tonic-gate otd.ot_trampoline = tramp; 1354*7c478bd9Sstevel@tonic-gate } else 1355*7c478bd9Sstevel@tonic-gate err = DDI_FAILURE; 1356*7c478bd9Sstevel@tonic-gate 1357*7c478bd9Sstevel@tonic-gate /* Flush any sbus store buffers. */ 1358*7c478bd9Sstevel@tonic-gate tmpreg = *softsp->sbus_ctrl_reg; 1359*7c478bd9Sstevel@tonic-gate 1360*7c478bd9Sstevel@tonic-gate /* 1361*7c478bd9Sstevel@tonic-gate * Read the sbus error reg and see if a fault occured. If 1362*7c478bd9Sstevel@tonic-gate * one has, give the SYSIO time to packetize the interrupt 1363*7c478bd9Sstevel@tonic-gate * for the fault and send it out. The sbus error handler will 1364*7c478bd9Sstevel@tonic-gate * 0 these fields when it's called to service the fault. 1365*7c478bd9Sstevel@tonic-gate */ 1366*7c478bd9Sstevel@tonic-gate tmpreg = *softsp->sbus_err_reg; 1367*7c478bd9Sstevel@tonic-gate while (tmpreg & SB_AFSR_P_TO || tmpreg & SB_AFSR_P_BERR) 1368*7c478bd9Sstevel@tonic-gate tmpreg = *softsp->sbus_err_reg; 1369*7c478bd9Sstevel@tonic-gate 1370*7c478bd9Sstevel@tonic-gate /* Take down protected environment. */ 1371*7c478bd9Sstevel@tonic-gate no_trap(); 1372*7c478bd9Sstevel@tonic-gate 1373*7c478bd9Sstevel@tonic-gate softsp->ontrap_data = NULL; 1374*7c478bd9Sstevel@tonic-gate mutex_exit(&softsp->pokefault_mutex); 1375*7c478bd9Sstevel@tonic-gate 1376*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1377*7c478bd9Sstevel@tonic-gate if (err == DDI_FAILURE) 1378*7c478bd9Sstevel@tonic-gate sbus_pokefault_cnt++; 1379*7c478bd9Sstevel@tonic-gate #endif 1380*7c478bd9Sstevel@tonic-gate return (err); 1381*7c478bd9Sstevel@tonic-gate } 1382*7c478bd9Sstevel@tonic-gate 1383*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1384*7c478bd9Sstevel@tonic-gate static int 1385*7c478bd9Sstevel@tonic-gate sbus_ctlops_peek(struct sbus_soft_state *softsp, peekpoke_ctlops_t *in_args, 1386*7c478bd9Sstevel@tonic-gate void *result) 1387*7c478bd9Sstevel@tonic-gate { 1388*7c478bd9Sstevel@tonic-gate int err = DDI_SUCCESS; 1389*7c478bd9Sstevel@tonic-gate on_trap_data_t otd; 1390*7c478bd9Sstevel@tonic-gate 1391*7c478bd9Sstevel@tonic-gate /* No safe access except for peek is supported. */ 1392*7c478bd9Sstevel@tonic-gate if (in_args->handle != NULL) 1393*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1394*7c478bd9Sstevel@tonic-gate 1395*7c478bd9Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 1396*7c478bd9Sstevel@tonic-gate uintptr_t tramp = otd.ot_trampoline; 1397*7c478bd9Sstevel@tonic-gate 1398*7c478bd9Sstevel@tonic-gate otd.ot_trampoline = (uintptr_t)&peek_fault; 1399*7c478bd9Sstevel@tonic-gate err = do_peek(in_args->size, (void *)in_args->dev_addr, 1400*7c478bd9Sstevel@tonic-gate (void *)in_args->host_addr); 1401*7c478bd9Sstevel@tonic-gate otd.ot_trampoline = tramp; 1402*7c478bd9Sstevel@tonic-gate result = (void *)in_args->host_addr; 1403*7c478bd9Sstevel@tonic-gate } else 1404*7c478bd9Sstevel@tonic-gate err = DDI_FAILURE; 1405*7c478bd9Sstevel@tonic-gate 1406*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1407*7c478bd9Sstevel@tonic-gate if (err == DDI_FAILURE) 1408*7c478bd9Sstevel@tonic-gate sbus_peekfault_cnt++; 1409*7c478bd9Sstevel@tonic-gate #endif 1410*7c478bd9Sstevel@tonic-gate no_trap(); 1411*7c478bd9Sstevel@tonic-gate return (err); 1412*7c478bd9Sstevel@tonic-gate } 1413*7c478bd9Sstevel@tonic-gate 1414*7c478bd9Sstevel@tonic-gate static int 1415*7c478bd9Sstevel@tonic-gate sbus_ctlops(dev_info_t *dip, dev_info_t *rdip, 1416*7c478bd9Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result) 1417*7c478bd9Sstevel@tonic-gate { 1418*7c478bd9Sstevel@tonic-gate struct sbus_soft_state *softsp = (struct sbus_soft_state *) 1419*7c478bd9Sstevel@tonic-gate ddi_get_soft_state(sbusp, ddi_get_instance(dip)); 1420*7c478bd9Sstevel@tonic-gate 1421*7c478bd9Sstevel@tonic-gate switch (op) { 1422*7c478bd9Sstevel@tonic-gate 1423*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 1424*7c478bd9Sstevel@tonic-gate return (sbus_initchild(dip, (dev_info_t *)arg)); 1425*7c478bd9Sstevel@tonic-gate 1426*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 1427*7c478bd9Sstevel@tonic-gate return (sbus_uninitchild(arg)); 1428*7c478bd9Sstevel@tonic-gate 1429*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_IOMIN: { 1430*7c478bd9Sstevel@tonic-gate int val = *((int *)result); 1431*7c478bd9Sstevel@tonic-gate 1432*7c478bd9Sstevel@tonic-gate /* 1433*7c478bd9Sstevel@tonic-gate * The 'arg' value of nonzero indicates 'streaming' mode. 1434*7c478bd9Sstevel@tonic-gate * If in streaming mode, pick the largest of our burstsizes 1435*7c478bd9Sstevel@tonic-gate * available and say that that is our minimum value (modulo 1436*7c478bd9Sstevel@tonic-gate * what mincycle is). 1437*7c478bd9Sstevel@tonic-gate */ 1438*7c478bd9Sstevel@tonic-gate if ((int)arg) 1439*7c478bd9Sstevel@tonic-gate val = maxbit(val, 1440*7c478bd9Sstevel@tonic-gate (1 << (ddi_fls(softsp->sbus_burst_sizes) - 1))); 1441*7c478bd9Sstevel@tonic-gate else 1442*7c478bd9Sstevel@tonic-gate val = maxbit(val, 1443*7c478bd9Sstevel@tonic-gate (1 << (ddi_ffs(softsp->sbus_burst_sizes) - 1))); 1444*7c478bd9Sstevel@tonic-gate 1445*7c478bd9Sstevel@tonic-gate *((int *)result) = val; 1446*7c478bd9Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, op, arg, result)); 1447*7c478bd9Sstevel@tonic-gate } 1448*7c478bd9Sstevel@tonic-gate 1449*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: { 1450*7c478bd9Sstevel@tonic-gate dev_info_t *pdev; 1451*7c478bd9Sstevel@tonic-gate int i, n, len, f_len; 1452*7c478bd9Sstevel@tonic-gate char *msgbuf; 1453*7c478bd9Sstevel@tonic-gate 1454*7c478bd9Sstevel@tonic-gate /* 1455*7c478bd9Sstevel@tonic-gate * So we can do one atomic cmn_err call, we allocate a 4k 1456*7c478bd9Sstevel@tonic-gate * buffer, and format the reportdev message into that buffer, 1457*7c478bd9Sstevel@tonic-gate * send it to cmn_err, and then free the allocated buffer. 1458*7c478bd9Sstevel@tonic-gate * If message is longer than 1k, the message is truncated and 1459*7c478bd9Sstevel@tonic-gate * an error message is emitted (debug kernel only). 1460*7c478bd9Sstevel@tonic-gate */ 1461*7c478bd9Sstevel@tonic-gate #define REPORTDEV_BUFSIZE 1024 1462*7c478bd9Sstevel@tonic-gate 1463*7c478bd9Sstevel@tonic-gate int sbusid = ddi_get_instance(dip); 1464*7c478bd9Sstevel@tonic-gate 1465*7c478bd9Sstevel@tonic-gate if (ddi_get_parent_data(rdip) == NULL) 1466*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1467*7c478bd9Sstevel@tonic-gate 1468*7c478bd9Sstevel@tonic-gate msgbuf = kmem_zalloc(REPORTDEV_BUFSIZE, KM_SLEEP); 1469*7c478bd9Sstevel@tonic-gate 1470*7c478bd9Sstevel@tonic-gate pdev = ddi_get_parent(rdip); 1471*7c478bd9Sstevel@tonic-gate f_len = snprintf(msgbuf, REPORTDEV_BUFSIZE, 1472*7c478bd9Sstevel@tonic-gate "%s%d at %s%d: SBus%d ", 1473*7c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), 1474*7c478bd9Sstevel@tonic-gate ddi_driver_name(pdev), ddi_get_instance(pdev), sbusid); 1475*7c478bd9Sstevel@tonic-gate len = strlen(msgbuf); 1476*7c478bd9Sstevel@tonic-gate 1477*7c478bd9Sstevel@tonic-gate for (i = 0, n = sysio_pd_getnreg(rdip); i < n; i++) { 1478*7c478bd9Sstevel@tonic-gate struct regspec *rp; 1479*7c478bd9Sstevel@tonic-gate 1480*7c478bd9Sstevel@tonic-gate rp = sysio_pd_getreg(rdip, i); 1481*7c478bd9Sstevel@tonic-gate if (i != 0) { 1482*7c478bd9Sstevel@tonic-gate f_len += snprintf(msgbuf + len, 1483*7c478bd9Sstevel@tonic-gate REPORTDEV_BUFSIZE - len, " and "); 1484*7c478bd9Sstevel@tonic-gate len = strlen(msgbuf); 1485*7c478bd9Sstevel@tonic-gate } 1486*7c478bd9Sstevel@tonic-gate 1487*7c478bd9Sstevel@tonic-gate f_len += snprintf(msgbuf + len, REPORTDEV_BUFSIZE - len, 1488*7c478bd9Sstevel@tonic-gate "slot 0x%x offset 0x%x", 1489*7c478bd9Sstevel@tonic-gate rp->regspec_bustype, rp->regspec_addr); 1490*7c478bd9Sstevel@tonic-gate len = strlen(msgbuf); 1491*7c478bd9Sstevel@tonic-gate } 1492*7c478bd9Sstevel@tonic-gate 1493*7c478bd9Sstevel@tonic-gate for (i = 0, n = i_ddi_get_nintrs(rdip); i < n; i++) { 1494*7c478bd9Sstevel@tonic-gate ddi_ispec_t *ispecp; 1495*7c478bd9Sstevel@tonic-gate uint32_t sbuslevel, pri; 1496*7c478bd9Sstevel@tonic-gate 1497*7c478bd9Sstevel@tonic-gate if (i != 0) { 1498*7c478bd9Sstevel@tonic-gate f_len += snprintf(msgbuf + len, 1499*7c478bd9Sstevel@tonic-gate REPORTDEV_BUFSIZE - len, ","); 1500*7c478bd9Sstevel@tonic-gate len = strlen(msgbuf); 1501*7c478bd9Sstevel@tonic-gate } 1502*7c478bd9Sstevel@tonic-gate 1503*7c478bd9Sstevel@tonic-gate i_ddi_alloc_ispec(rdip, i, 1504*7c478bd9Sstevel@tonic-gate (ddi_intrspec_t *)&ispecp); 1505*7c478bd9Sstevel@tonic-gate 1506*7c478bd9Sstevel@tonic-gate sbuslevel = *ispecp->is_intr; 1507*7c478bd9Sstevel@tonic-gate 1508*7c478bd9Sstevel@tonic-gate (void) sbus_xlate_intrs(dip, rdip, ispecp, 1509*7c478bd9Sstevel@tonic-gate softsp->intr_mapping_ign); 1510*7c478bd9Sstevel@tonic-gate 1511*7c478bd9Sstevel@tonic-gate pri = ispecp->is_pil; 1512*7c478bd9Sstevel@tonic-gate 1513*7c478bd9Sstevel@tonic-gate if (sbuslevel > MAX_SBUS_LEVEL) 1514*7c478bd9Sstevel@tonic-gate f_len += snprintf(msgbuf + len, 1515*7c478bd9Sstevel@tonic-gate REPORTDEV_BUFSIZE - len, 1516*7c478bd9Sstevel@tonic-gate " Onboard device "); 1517*7c478bd9Sstevel@tonic-gate else 1518*7c478bd9Sstevel@tonic-gate f_len += snprintf(msgbuf + len, 1519*7c478bd9Sstevel@tonic-gate REPORTDEV_BUFSIZE - len, " SBus level %d ", 1520*7c478bd9Sstevel@tonic-gate sbuslevel); 1521*7c478bd9Sstevel@tonic-gate len = strlen(msgbuf); 1522*7c478bd9Sstevel@tonic-gate 1523*7c478bd9Sstevel@tonic-gate f_len += snprintf(msgbuf + len, REPORTDEV_BUFSIZE - len, 1524*7c478bd9Sstevel@tonic-gate "sparc9 ipl %d", pri); 1525*7c478bd9Sstevel@tonic-gate len = strlen(msgbuf); 1526*7c478bd9Sstevel@tonic-gate 1527*7c478bd9Sstevel@tonic-gate i_ddi_free_ispec((ddi_intrspec_t)ispecp); 1528*7c478bd9Sstevel@tonic-gate } 1529*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1530*7c478bd9Sstevel@tonic-gate if (f_len + 1 >= REPORTDEV_BUFSIZE) { 1531*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "next message is truncated: " 1532*7c478bd9Sstevel@tonic-gate "printed length 1024, real length %d", f_len); 1533*7c478bd9Sstevel@tonic-gate } 1534*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 1535*7c478bd9Sstevel@tonic-gate 1536*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?%s\n", msgbuf); 1537*7c478bd9Sstevel@tonic-gate kmem_free(msgbuf, REPORTDEV_BUFSIZE); 1538*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1539*7c478bd9Sstevel@tonic-gate 1540*7c478bd9Sstevel@tonic-gate #undef REPORTDEV_BUFSIZE 1541*7c478bd9Sstevel@tonic-gate } 1542*7c478bd9Sstevel@tonic-gate 1543*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_SLAVEONLY: 1544*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1545*7c478bd9Sstevel@tonic-gate 1546*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_AFFINITY: { 1547*7c478bd9Sstevel@tonic-gate dev_info_t *dipb = (dev_info_t *)arg; 1548*7c478bd9Sstevel@tonic-gate int r_slot, b_slot; 1549*7c478bd9Sstevel@tonic-gate 1550*7c478bd9Sstevel@tonic-gate if ((b_slot = find_sbus_slot(dip, dipb)) < 0) 1551*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1552*7c478bd9Sstevel@tonic-gate 1553*7c478bd9Sstevel@tonic-gate if ((r_slot = find_sbus_slot(dip, rdip)) < 0) 1554*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1555*7c478bd9Sstevel@tonic-gate 1556*7c478bd9Sstevel@tonic-gate return ((b_slot == r_slot)? DDI_SUCCESS : DDI_FAILURE); 1557*7c478bd9Sstevel@tonic-gate 1558*7c478bd9Sstevel@tonic-gate } 1559*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_DMAPMAPC: 1560*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?DDI_DMAPMAPC called!!\n"); 1561*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1562*7c478bd9Sstevel@tonic-gate 1563*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_POKE: 1564*7c478bd9Sstevel@tonic-gate return (sbus_ctlops_poke(softsp, (peekpoke_ctlops_t *)arg)); 1565*7c478bd9Sstevel@tonic-gate 1566*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_PEEK: 1567*7c478bd9Sstevel@tonic-gate return (sbus_ctlops_peek(softsp, (peekpoke_ctlops_t *)arg, 1568*7c478bd9Sstevel@tonic-gate result)); 1569*7c478bd9Sstevel@tonic-gate 1570*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_DVMAPAGESIZE: 1571*7c478bd9Sstevel@tonic-gate *(ulong_t *)result = IOMMU_PAGESIZE; 1572*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1573*7c478bd9Sstevel@tonic-gate 1574*7c478bd9Sstevel@tonic-gate default: 1575*7c478bd9Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, op, arg, result)); 1576*7c478bd9Sstevel@tonic-gate } 1577*7c478bd9Sstevel@tonic-gate } 1578*7c478bd9Sstevel@tonic-gate 1579*7c478bd9Sstevel@tonic-gate static int 1580*7c478bd9Sstevel@tonic-gate find_sbus_slot(dev_info_t *dip, dev_info_t *rdip) 1581*7c478bd9Sstevel@tonic-gate { 1582*7c478bd9Sstevel@tonic-gate dev_info_t *child; 1583*7c478bd9Sstevel@tonic-gate int slot = -1; 1584*7c478bd9Sstevel@tonic-gate 1585*7c478bd9Sstevel@tonic-gate /* 1586*7c478bd9Sstevel@tonic-gate * look for the node that's a direct child of this Sbus node. 1587*7c478bd9Sstevel@tonic-gate */ 1588*7c478bd9Sstevel@tonic-gate while (rdip && (child = ddi_get_parent(rdip)) != dip) { 1589*7c478bd9Sstevel@tonic-gate rdip = child; 1590*7c478bd9Sstevel@tonic-gate } 1591*7c478bd9Sstevel@tonic-gate 1592*7c478bd9Sstevel@tonic-gate /* 1593*7c478bd9Sstevel@tonic-gate * If there is one, get the slot number of *my* child 1594*7c478bd9Sstevel@tonic-gate */ 1595*7c478bd9Sstevel@tonic-gate if (child == dip) 1596*7c478bd9Sstevel@tonic-gate slot = sysio_pd_getslot(rdip); 1597*7c478bd9Sstevel@tonic-gate 1598*7c478bd9Sstevel@tonic-gate return (slot); 1599*7c478bd9Sstevel@tonic-gate } 1600*7c478bd9Sstevel@tonic-gate 1601*7c478bd9Sstevel@tonic-gate /* 1602*7c478bd9Sstevel@tonic-gate * This is the sbus interrupt routine wrapper function. This function 1603*7c478bd9Sstevel@tonic-gate * installs itself as a child devices interrupt handler. It's function is 1604*7c478bd9Sstevel@tonic-gate * to dispatch a child devices interrupt handler, and then 1605*7c478bd9Sstevel@tonic-gate * reset the interrupt clear register for the child device. 1606*7c478bd9Sstevel@tonic-gate * 1607*7c478bd9Sstevel@tonic-gate * Warning: This routine may need to be implemented as an assembly level 1608*7c478bd9Sstevel@tonic-gate * routine to improve performance. 1609*7c478bd9Sstevel@tonic-gate */ 1610*7c478bd9Sstevel@tonic-gate 1611*7c478bd9Sstevel@tonic-gate #define MAX_INTR_CNT 10 1612*7c478bd9Sstevel@tonic-gate 1613*7c478bd9Sstevel@tonic-gate static uint_t 1614*7c478bd9Sstevel@tonic-gate sbus_intr_wrapper(caddr_t arg) 1615*7c478bd9Sstevel@tonic-gate { 1616*7c478bd9Sstevel@tonic-gate uint_t intr_return = DDI_INTR_UNCLAIMED; 1617*7c478bd9Sstevel@tonic-gate volatile uint64_t tmpreg; 1618*7c478bd9Sstevel@tonic-gate struct sbus_wrapper_arg *intr_info; 1619*7c478bd9Sstevel@tonic-gate struct sbus_intr_handler *intr_handler; 1620*7c478bd9Sstevel@tonic-gate uchar_t *spurious_cntr; 1621*7c478bd9Sstevel@tonic-gate 1622*7c478bd9Sstevel@tonic-gate intr_info = (struct sbus_wrapper_arg *)arg; 1623*7c478bd9Sstevel@tonic-gate spurious_cntr = &intr_info->softsp->spurious_cntrs[intr_info->pil]; 1624*7c478bd9Sstevel@tonic-gate intr_handler = intr_info->handler_list; 1625*7c478bd9Sstevel@tonic-gate 1626*7c478bd9Sstevel@tonic-gate while (intr_handler) { 1627*7c478bd9Sstevel@tonic-gate caddr_t arg1 = intr_handler->arg1; 1628*7c478bd9Sstevel@tonic-gate caddr_t arg2 = intr_handler->arg2; 1629*7c478bd9Sstevel@tonic-gate uint_t (*funcp)() = intr_handler->funcp; 1630*7c478bd9Sstevel@tonic-gate dev_info_t *dip = intr_handler->dip; 1631*7c478bd9Sstevel@tonic-gate int r; 1632*7c478bd9Sstevel@tonic-gate 1633*7c478bd9Sstevel@tonic-gate if (intr_handler->intr_state == SBUS_INTR_STATE_DISABLE) { 1634*7c478bd9Sstevel@tonic-gate intr_handler = intr_handler->next; 1635*7c478bd9Sstevel@tonic-gate continue; 1636*7c478bd9Sstevel@tonic-gate } 1637*7c478bd9Sstevel@tonic-gate 1638*7c478bd9Sstevel@tonic-gate DTRACE_PROBE4(interrupt__start, dev_info_t, dip, 1639*7c478bd9Sstevel@tonic-gate void *, funcp, caddr_t, arg1, caddr_t, arg2); 1640*7c478bd9Sstevel@tonic-gate 1641*7c478bd9Sstevel@tonic-gate r = (*funcp)(arg1, arg2); 1642*7c478bd9Sstevel@tonic-gate 1643*7c478bd9Sstevel@tonic-gate DTRACE_PROBE4(interrupt__complete, dev_info_t, dip, 1644*7c478bd9Sstevel@tonic-gate void *, funcp, caddr_t, arg1, int, r); 1645*7c478bd9Sstevel@tonic-gate 1646*7c478bd9Sstevel@tonic-gate intr_return |= r; 1647*7c478bd9Sstevel@tonic-gate intr_handler = intr_handler->next; 1648*7c478bd9Sstevel@tonic-gate } 1649*7c478bd9Sstevel@tonic-gate 1650*7c478bd9Sstevel@tonic-gate /* Set the interrupt state machine to idle */ 1651*7c478bd9Sstevel@tonic-gate tmpreg = *intr_info->softsp->sbus_ctrl_reg; 1652*7c478bd9Sstevel@tonic-gate tmpreg = SBUS_INTR_IDLE; 1653*7c478bd9Sstevel@tonic-gate *intr_info->clear_reg = tmpreg; 1654*7c478bd9Sstevel@tonic-gate tmpreg = *intr_info->softsp->sbus_ctrl_reg; 1655*7c478bd9Sstevel@tonic-gate 1656*7c478bd9Sstevel@tonic-gate if (intr_return == DDI_INTR_UNCLAIMED) { 1657*7c478bd9Sstevel@tonic-gate (*spurious_cntr)++; 1658*7c478bd9Sstevel@tonic-gate 1659*7c478bd9Sstevel@tonic-gate if (*spurious_cntr < MAX_INTR_CNT) { 1660*7c478bd9Sstevel@tonic-gate if (intr_cntr_on) 1661*7c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 1662*7c478bd9Sstevel@tonic-gate } 1663*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1664*7c478bd9Sstevel@tonic-gate else if (intr_info->pil >= LOCK_LEVEL) { 1665*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "%d unclaimed interrupts at " 1666*7c478bd9Sstevel@tonic-gate "interrupt level %d", MAX_INTR_CNT, 1667*7c478bd9Sstevel@tonic-gate intr_info->pil); 1668*7c478bd9Sstevel@tonic-gate } 1669*7c478bd9Sstevel@tonic-gate #endif 1670*7c478bd9Sstevel@tonic-gate 1671*7c478bd9Sstevel@tonic-gate /* 1672*7c478bd9Sstevel@tonic-gate * Reset spurious counter once we acknowledge 1673*7c478bd9Sstevel@tonic-gate * it to the system level. 1674*7c478bd9Sstevel@tonic-gate */ 1675*7c478bd9Sstevel@tonic-gate *spurious_cntr = (uchar_t)0; 1676*7c478bd9Sstevel@tonic-gate } else { 1677*7c478bd9Sstevel@tonic-gate *spurious_cntr = (uchar_t)0; 1678*7c478bd9Sstevel@tonic-gate } 1679*7c478bd9Sstevel@tonic-gate 1680*7c478bd9Sstevel@tonic-gate return (intr_return); 1681*7c478bd9Sstevel@tonic-gate } 1682*7c478bd9Sstevel@tonic-gate 1683*7c478bd9Sstevel@tonic-gate /* 1684*7c478bd9Sstevel@tonic-gate * add_intrspec - Add an interrupt specification. 1685*7c478bd9Sstevel@tonic-gate */ 1686*7c478bd9Sstevel@tonic-gate static int 1687*7c478bd9Sstevel@tonic-gate sbus_add_intr_impl(dev_info_t *dip, dev_info_t *rdip, 1688*7c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 1689*7c478bd9Sstevel@tonic-gate { 1690*7c478bd9Sstevel@tonic-gate struct sbus_soft_state *softsp = (struct sbus_soft_state *) 1691*7c478bd9Sstevel@tonic-gate ddi_get_soft_state(sbusp, ddi_get_instance(dip)); 1692*7c478bd9Sstevel@tonic-gate ddi_ispec_t *ip = (ddi_ispec_t *)hdlp->ih_private; 1693*7c478bd9Sstevel@tonic-gate volatile uint64_t *mondo_vec_reg; 1694*7c478bd9Sstevel@tonic-gate volatile uint64_t tmp_mondo_vec; 1695*7c478bd9Sstevel@tonic-gate volatile uint64_t *intr_state_reg; 1696*7c478bd9Sstevel@tonic-gate volatile uint64_t tmpreg; /* HW flush reg */ 1697*7c478bd9Sstevel@tonic-gate uint_t start_bit; 1698*7c478bd9Sstevel@tonic-gate int ino; 1699*7c478bd9Sstevel@tonic-gate uint_t cpu_id; 1700*7c478bd9Sstevel@tonic-gate struct sbus_wrapper_arg *sbus_arg; 1701*7c478bd9Sstevel@tonic-gate struct sbus_intr_handler *intr_handler; 1702*7c478bd9Sstevel@tonic-gate uint32_t slot; 1703*7c478bd9Sstevel@tonic-gate /* Interrupt state machine reset flag */ 1704*7c478bd9Sstevel@tonic-gate int reset_ism_register = 1; 1705*7c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 1706*7c478bd9Sstevel@tonic-gate 1707*7c478bd9Sstevel@tonic-gate /* Check if we have a valid sbus slot address */ 1708*7c478bd9Sstevel@tonic-gate if (((slot = (uint_t)find_sbus_slot(dip, rdip)) >= 1709*7c478bd9Sstevel@tonic-gate MAX_SBUS_SLOT_ADDR) || (slot < (uint_t)0)) { 1710*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Invalid sbus slot 0x%x during add intr\n", 1711*7c478bd9Sstevel@tonic-gate slot); 1712*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1713*7c478bd9Sstevel@tonic-gate } 1714*7c478bd9Sstevel@tonic-gate 1715*7c478bd9Sstevel@tonic-gate DPRINTF(SBUS_INTERRUPT_DEBUG, ("Add intr: sbus interrupt %d " 1716*7c478bd9Sstevel@tonic-gate "for device %s%d\n", hdlp->ih_vector, ddi_get_name(rdip), 1717*7c478bd9Sstevel@tonic-gate ddi_get_instance(rdip))); 1718*7c478bd9Sstevel@tonic-gate 1719*7c478bd9Sstevel@tonic-gate /* Xlate the interrupt */ 1720*7c478bd9Sstevel@tonic-gate if (sbus_xlate_intrs(dip, rdip, ip, 1721*7c478bd9Sstevel@tonic-gate softsp->intr_mapping_ign) == DDI_FAILURE) { 1722*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Can't xlate SBUS devices %s interrupt.\n", 1723*7c478bd9Sstevel@tonic-gate ddi_get_name(rdip)); 1724*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1725*7c478bd9Sstevel@tonic-gate } 1726*7c478bd9Sstevel@tonic-gate 1727*7c478bd9Sstevel@tonic-gate /* get the ino number */ 1728*7c478bd9Sstevel@tonic-gate ino = (*ip->is_intr) & SBUS_MAX_INO; 1729*7c478bd9Sstevel@tonic-gate mondo_vec_reg = (softsp->intr_mapping_reg + 1730*7c478bd9Sstevel@tonic-gate ino_table[ino]->mapping_reg); 1731*7c478bd9Sstevel@tonic-gate 1732*7c478bd9Sstevel@tonic-gate /* 1733*7c478bd9Sstevel@tonic-gate * This is an intermediate step in identifying 1734*7c478bd9Sstevel@tonic-gate * the exact bits which represent the device in the interrupt 1735*7c478bd9Sstevel@tonic-gate * state diagnostic register. 1736*7c478bd9Sstevel@tonic-gate */ 1737*7c478bd9Sstevel@tonic-gate if (ino > MAX_MONDO_EXTERNAL) { 1738*7c478bd9Sstevel@tonic-gate start_bit = ino_table[ino]->diagreg_shift; 1739*7c478bd9Sstevel@tonic-gate intr_state_reg = softsp->obio_intr_state; 1740*7c478bd9Sstevel@tonic-gate } else { 1741*7c478bd9Sstevel@tonic-gate start_bit = 16 * (ino >> 3) + 2 * (ino & 0x7); 1742*7c478bd9Sstevel@tonic-gate intr_state_reg = softsp->sbus_intr_state; 1743*7c478bd9Sstevel@tonic-gate } 1744*7c478bd9Sstevel@tonic-gate 1745*7c478bd9Sstevel@tonic-gate 1746*7c478bd9Sstevel@tonic-gate /* Allocate a nexus interrupt data structure */ 1747*7c478bd9Sstevel@tonic-gate intr_handler = kmem_zalloc(sizeof (struct sbus_intr_handler), KM_SLEEP); 1748*7c478bd9Sstevel@tonic-gate intr_handler->dip = rdip; 1749*7c478bd9Sstevel@tonic-gate intr_handler->funcp = hdlp->ih_cb_func; 1750*7c478bd9Sstevel@tonic-gate intr_handler->arg1 = hdlp->ih_cb_arg1; 1751*7c478bd9Sstevel@tonic-gate intr_handler->arg2 = hdlp->ih_cb_arg2; 1752*7c478bd9Sstevel@tonic-gate intr_handler->inum = hdlp->ih_inum; 1753*7c478bd9Sstevel@tonic-gate 1754*7c478bd9Sstevel@tonic-gate DPRINTF(SBUS_INTERRUPT_DEBUG, ("Add intr: xlated interrupt 0x%x " 1755*7c478bd9Sstevel@tonic-gate "intr_handler 0x%x\n", *ip->is_intr, intr_handler)); 1756*7c478bd9Sstevel@tonic-gate 1757*7c478bd9Sstevel@tonic-gate /* 1758*7c478bd9Sstevel@tonic-gate * Grab this lock here. So it will protect the poll list. 1759*7c478bd9Sstevel@tonic-gate */ 1760*7c478bd9Sstevel@tonic-gate mutex_enter(&softsp->intr_poll_list_lock); 1761*7c478bd9Sstevel@tonic-gate 1762*7c478bd9Sstevel@tonic-gate sbus_arg = softsp->intr_list[ino]; 1763*7c478bd9Sstevel@tonic-gate /* Check if we have a poll list to deal with */ 1764*7c478bd9Sstevel@tonic-gate if (sbus_arg) { 1765*7c478bd9Sstevel@tonic-gate tmp_mondo_vec = *mondo_vec_reg; 1766*7c478bd9Sstevel@tonic-gate tmp_mondo_vec &= ~INTERRUPT_VALID; 1767*7c478bd9Sstevel@tonic-gate *mondo_vec_reg = tmp_mondo_vec; 1768*7c478bd9Sstevel@tonic-gate 1769*7c478bd9Sstevel@tonic-gate tmpreg = *softsp->sbus_ctrl_reg; 1770*7c478bd9Sstevel@tonic-gate #ifdef lint 1771*7c478bd9Sstevel@tonic-gate tmpreg = tmpreg; 1772*7c478bd9Sstevel@tonic-gate #endif 1773*7c478bd9Sstevel@tonic-gate 1774*7c478bd9Sstevel@tonic-gate DPRINTF(SBUS_INTERRUPT_DEBUG, ("Add intr:sbus_arg exists " 1775*7c478bd9Sstevel@tonic-gate "0x%x\n", sbus_arg)); 1776*7c478bd9Sstevel@tonic-gate /* 1777*7c478bd9Sstevel@tonic-gate * Two bits per ino in the diagnostic register 1778*7c478bd9Sstevel@tonic-gate * indicate the status of its interrupt. 1779*7c478bd9Sstevel@tonic-gate * 0 - idle, 1 - transmit, 3 - pending. 1780*7c478bd9Sstevel@tonic-gate */ 1781*7c478bd9Sstevel@tonic-gate while (((*intr_state_reg >> 1782*7c478bd9Sstevel@tonic-gate start_bit) & 0x3) == INT_PENDING && !panicstr) 1783*7c478bd9Sstevel@tonic-gate /* empty */; 1784*7c478bd9Sstevel@tonic-gate 1785*7c478bd9Sstevel@tonic-gate intr_handler->next = sbus_arg->handler_list; 1786*7c478bd9Sstevel@tonic-gate sbus_arg->handler_list = intr_handler; 1787*7c478bd9Sstevel@tonic-gate 1788*7c478bd9Sstevel@tonic-gate reset_ism_register = 0; 1789*7c478bd9Sstevel@tonic-gate } else { 1790*7c478bd9Sstevel@tonic-gate sbus_arg = kmem_zalloc(sizeof (struct sbus_wrapper_arg), 1791*7c478bd9Sstevel@tonic-gate KM_SLEEP); 1792*7c478bd9Sstevel@tonic-gate 1793*7c478bd9Sstevel@tonic-gate softsp->intr_list[ino] = sbus_arg; 1794*7c478bd9Sstevel@tonic-gate sbus_arg->clear_reg = (softsp->clr_intr_reg + 1795*7c478bd9Sstevel@tonic-gate ino_table[ino]->clear_reg); 1796*7c478bd9Sstevel@tonic-gate DPRINTF(SBUS_INTERRUPT_DEBUG, ("Add intr:Ino 0x%x Interrupt " 1797*7c478bd9Sstevel@tonic-gate "clear reg: 0x%x\n", ino, sbus_arg->clear_reg)); 1798*7c478bd9Sstevel@tonic-gate sbus_arg->softsp = softsp; 1799*7c478bd9Sstevel@tonic-gate sbus_arg->handler_list = intr_handler; 1800*7c478bd9Sstevel@tonic-gate 1801*7c478bd9Sstevel@tonic-gate hdlp->ih_vector = *ip->is_intr; 1802*7c478bd9Sstevel@tonic-gate 1803*7c478bd9Sstevel@tonic-gate /* 1804*7c478bd9Sstevel@tonic-gate * No handler added yet in the interrupt vector 1805*7c478bd9Sstevel@tonic-gate * table for this ino. 1806*7c478bd9Sstevel@tonic-gate * Install the nexus interrupt wrapper in the 1807*7c478bd9Sstevel@tonic-gate * system. The wrapper will call the device 1808*7c478bd9Sstevel@tonic-gate * interrupt handler. 1809*7c478bd9Sstevel@tonic-gate */ 1810*7c478bd9Sstevel@tonic-gate DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, 1811*7c478bd9Sstevel@tonic-gate (ddi_intr_handler_t *)sbus_intr_wrapper, 1812*7c478bd9Sstevel@tonic-gate (caddr_t)sbus_arg, NULL); 1813*7c478bd9Sstevel@tonic-gate 1814*7c478bd9Sstevel@tonic-gate ret = i_ddi_add_ivintr(hdlp); 1815*7c478bd9Sstevel@tonic-gate 1816*7c478bd9Sstevel@tonic-gate /* 1817*7c478bd9Sstevel@tonic-gate * Restore original interrupt handler 1818*7c478bd9Sstevel@tonic-gate * and arguments in interrupt handle. 1819*7c478bd9Sstevel@tonic-gate */ 1820*7c478bd9Sstevel@tonic-gate DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, intr_handler->funcp, 1821*7c478bd9Sstevel@tonic-gate intr_handler->arg1, intr_handler->arg2); 1822*7c478bd9Sstevel@tonic-gate 1823*7c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) 1824*7c478bd9Sstevel@tonic-gate goto done; 1825*7c478bd9Sstevel@tonic-gate 1826*7c478bd9Sstevel@tonic-gate if ((slot >= EXT_SBUS_SLOTS) || 1827*7c478bd9Sstevel@tonic-gate (softsp->intr_hndlr_cnt[slot] == 0)) { 1828*7c478bd9Sstevel@tonic-gate 1829*7c478bd9Sstevel@tonic-gate cpu_id = intr_dist_cpuid(); 1830*7c478bd9Sstevel@tonic-gate #ifdef _STARFIRE 1831*7c478bd9Sstevel@tonic-gate tmp_mondo_vec = pc_translate_tgtid( 1832*7c478bd9Sstevel@tonic-gate softsp->ittrans_cookie, cpu_id, 1833*7c478bd9Sstevel@tonic-gate mondo_vec_reg) << IMR_TID_SHIFT; 1834*7c478bd9Sstevel@tonic-gate #else 1835*7c478bd9Sstevel@tonic-gate tmp_mondo_vec = 1836*7c478bd9Sstevel@tonic-gate cpu_id << IMR_TID_SHIFT; 1837*7c478bd9Sstevel@tonic-gate DPRINTF(SBUS_INTERRUPT_DEBUG, ("Add intr: initial " 1838*7c478bd9Sstevel@tonic-gate "mapping reg 0x%llx\n", tmp_mondo_vec)); 1839*7c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */ 1840*7c478bd9Sstevel@tonic-gate } else { 1841*7c478bd9Sstevel@tonic-gate /* 1842*7c478bd9Sstevel@tonic-gate * There is already a different 1843*7c478bd9Sstevel@tonic-gate * ino programmed at this IMR. 1844*7c478bd9Sstevel@tonic-gate * Just read the IMR out to get the 1845*7c478bd9Sstevel@tonic-gate * correct MID target. 1846*7c478bd9Sstevel@tonic-gate */ 1847*7c478bd9Sstevel@tonic-gate tmp_mondo_vec = *mondo_vec_reg; 1848*7c478bd9Sstevel@tonic-gate tmp_mondo_vec &= ~INTERRUPT_VALID; 1849*7c478bd9Sstevel@tonic-gate *mondo_vec_reg = tmp_mondo_vec; 1850*7c478bd9Sstevel@tonic-gate DPRINTF(SBUS_INTERRUPT_DEBUG, ("Add intr: existing " 1851*7c478bd9Sstevel@tonic-gate "mapping reg 0x%llx\n", tmp_mondo_vec)); 1852*7c478bd9Sstevel@tonic-gate } 1853*7c478bd9Sstevel@tonic-gate 1854*7c478bd9Sstevel@tonic-gate sbus_arg->pil = hdlp->ih_pri; 1855*7c478bd9Sstevel@tonic-gate 1856*7c478bd9Sstevel@tonic-gate DPRINTF(SBUS_INTERRUPT_DEBUG, ("Add intr:Alloc sbus_arg " 1857*7c478bd9Sstevel@tonic-gate "0x%x\n", sbus_arg)); 1858*7c478bd9Sstevel@tonic-gate } 1859*7c478bd9Sstevel@tonic-gate 1860*7c478bd9Sstevel@tonic-gate softsp->intr_hndlr_cnt[slot]++; 1861*7c478bd9Sstevel@tonic-gate 1862*7c478bd9Sstevel@tonic-gate mutex_exit(&softsp->intr_poll_list_lock); 1863*7c478bd9Sstevel@tonic-gate 1864*7c478bd9Sstevel@tonic-gate /* 1865*7c478bd9Sstevel@tonic-gate * Program the ino vector accordingly. This MUST be the 1866*7c478bd9Sstevel@tonic-gate * last thing we do. Once we program the ino, the device 1867*7c478bd9Sstevel@tonic-gate * may begin to interrupt. Add this hardware interrupt to 1868*7c478bd9Sstevel@tonic-gate * the interrupt lists, and get the CPU to target it at. 1869*7c478bd9Sstevel@tonic-gate */ 1870*7c478bd9Sstevel@tonic-gate 1871*7c478bd9Sstevel@tonic-gate tmp_mondo_vec |= INTERRUPT_VALID; 1872*7c478bd9Sstevel@tonic-gate 1873*7c478bd9Sstevel@tonic-gate DPRINTF(SBUS_INTERRUPT_DEBUG, ("Add intr: Ino 0x%x mapping reg: 0x%x " 1874*7c478bd9Sstevel@tonic-gate "Intr cntr %d\n", ino, mondo_vec_reg, 1875*7c478bd9Sstevel@tonic-gate softsp->intr_hndlr_cnt[slot])); 1876*7c478bd9Sstevel@tonic-gate 1877*7c478bd9Sstevel@tonic-gate /* Force the interrupt state machine to idle. */ 1878*7c478bd9Sstevel@tonic-gate if (reset_ism_register) { 1879*7c478bd9Sstevel@tonic-gate tmpreg = SBUS_INTR_IDLE; 1880*7c478bd9Sstevel@tonic-gate *sbus_arg->clear_reg = tmpreg; 1881*7c478bd9Sstevel@tonic-gate } 1882*7c478bd9Sstevel@tonic-gate 1883*7c478bd9Sstevel@tonic-gate /* Store it in the hardware reg. */ 1884*7c478bd9Sstevel@tonic-gate *mondo_vec_reg = tmp_mondo_vec; 1885*7c478bd9Sstevel@tonic-gate 1886*7c478bd9Sstevel@tonic-gate /* Flush store buffers */ 1887*7c478bd9Sstevel@tonic-gate tmpreg = *softsp->sbus_ctrl_reg; 1888*7c478bd9Sstevel@tonic-gate 1889*7c478bd9Sstevel@tonic-gate done: 1890*7c478bd9Sstevel@tonic-gate return (ret); 1891*7c478bd9Sstevel@tonic-gate } 1892*7c478bd9Sstevel@tonic-gate 1893*7c478bd9Sstevel@tonic-gate static void 1894*7c478bd9Sstevel@tonic-gate sbus_free_handler(dev_info_t *dip, uint32_t inum, 1895*7c478bd9Sstevel@tonic-gate struct sbus_wrapper_arg *sbus_arg) 1896*7c478bd9Sstevel@tonic-gate { 1897*7c478bd9Sstevel@tonic-gate struct sbus_intr_handler *listp, *prevp; 1898*7c478bd9Sstevel@tonic-gate 1899*7c478bd9Sstevel@tonic-gate if (sbus_arg) { 1900*7c478bd9Sstevel@tonic-gate prevp = NULL; 1901*7c478bd9Sstevel@tonic-gate listp = sbus_arg->handler_list; 1902*7c478bd9Sstevel@tonic-gate 1903*7c478bd9Sstevel@tonic-gate while (listp) { 1904*7c478bd9Sstevel@tonic-gate if (listp->dip == dip && listp->inum == inum) { 1905*7c478bd9Sstevel@tonic-gate if (prevp) 1906*7c478bd9Sstevel@tonic-gate prevp->next = listp->next; 1907*7c478bd9Sstevel@tonic-gate else { 1908*7c478bd9Sstevel@tonic-gate prevp = listp->next; 1909*7c478bd9Sstevel@tonic-gate sbus_arg->handler_list = prevp; 1910*7c478bd9Sstevel@tonic-gate } 1911*7c478bd9Sstevel@tonic-gate 1912*7c478bd9Sstevel@tonic-gate kmem_free(listp, 1913*7c478bd9Sstevel@tonic-gate sizeof (struct sbus_intr_handler)); 1914*7c478bd9Sstevel@tonic-gate break; 1915*7c478bd9Sstevel@tonic-gate } 1916*7c478bd9Sstevel@tonic-gate prevp = listp; 1917*7c478bd9Sstevel@tonic-gate listp = listp->next; 1918*7c478bd9Sstevel@tonic-gate } 1919*7c478bd9Sstevel@tonic-gate } 1920*7c478bd9Sstevel@tonic-gate } 1921*7c478bd9Sstevel@tonic-gate 1922*7c478bd9Sstevel@tonic-gate /* 1923*7c478bd9Sstevel@tonic-gate * remove_intrspec - Remove an interrupt specification. 1924*7c478bd9Sstevel@tonic-gate */ 1925*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1926*7c478bd9Sstevel@tonic-gate static void 1927*7c478bd9Sstevel@tonic-gate sbus_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip, 1928*7c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 1929*7c478bd9Sstevel@tonic-gate { 1930*7c478bd9Sstevel@tonic-gate volatile uint64_t *mondo_vec_reg; 1931*7c478bd9Sstevel@tonic-gate volatile uint64_t *intr_state_reg; 1932*7c478bd9Sstevel@tonic-gate #ifndef lint 1933*7c478bd9Sstevel@tonic-gate volatile uint64_t tmpreg; 1934*7c478bd9Sstevel@tonic-gate #endif /* !lint */ 1935*7c478bd9Sstevel@tonic-gate struct sbus_soft_state *softsp = (struct sbus_soft_state *) 1936*7c478bd9Sstevel@tonic-gate ddi_get_soft_state(sbusp, ddi_get_instance(dip)); 1937*7c478bd9Sstevel@tonic-gate ddi_ispec_t *ip = (ddi_ispec_t *)hdlp->ih_private; 1938*7c478bd9Sstevel@tonic-gate int start_bit, ino, slot; 1939*7c478bd9Sstevel@tonic-gate struct sbus_wrapper_arg *sbus_arg; 1940*7c478bd9Sstevel@tonic-gate 1941*7c478bd9Sstevel@tonic-gate /* Grab the mutex protecting the poll list */ 1942*7c478bd9Sstevel@tonic-gate mutex_enter(&softsp->intr_poll_list_lock); 1943*7c478bd9Sstevel@tonic-gate 1944*7c478bd9Sstevel@tonic-gate /* Xlate the interrupt */ 1945*7c478bd9Sstevel@tonic-gate if (sbus_xlate_intrs(dip, rdip, ip, 1946*7c478bd9Sstevel@tonic-gate softsp->intr_mapping_ign) == DDI_FAILURE) { 1947*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Can't xlate SBUS devices %s interrupt.\n", 1948*7c478bd9Sstevel@tonic-gate ddi_get_name(rdip)); 1949*7c478bd9Sstevel@tonic-gate goto done; 1950*7c478bd9Sstevel@tonic-gate } 1951*7c478bd9Sstevel@tonic-gate 1952*7c478bd9Sstevel@tonic-gate ino = ((int32_t)*ip->is_intr) & SBUS_MAX_INO; 1953*7c478bd9Sstevel@tonic-gate 1954*7c478bd9Sstevel@tonic-gate mondo_vec_reg = (softsp->intr_mapping_reg + 1955*7c478bd9Sstevel@tonic-gate ino_table[ino]->mapping_reg); 1956*7c478bd9Sstevel@tonic-gate 1957*7c478bd9Sstevel@tonic-gate /* Turn off the valid bit in the mapping register. */ 1958*7c478bd9Sstevel@tonic-gate *mondo_vec_reg &= ~INTERRUPT_VALID; 1959*7c478bd9Sstevel@tonic-gate #ifndef lint 1960*7c478bd9Sstevel@tonic-gate tmpreg = *softsp->sbus_ctrl_reg; 1961*7c478bd9Sstevel@tonic-gate #endif /* !lint */ 1962*7c478bd9Sstevel@tonic-gate 1963*7c478bd9Sstevel@tonic-gate /* Get our bit position for checking intr pending */ 1964*7c478bd9Sstevel@tonic-gate if (ino > MAX_MONDO_EXTERNAL) { 1965*7c478bd9Sstevel@tonic-gate start_bit = ino_table[ino]->diagreg_shift; 1966*7c478bd9Sstevel@tonic-gate intr_state_reg = softsp->obio_intr_state; 1967*7c478bd9Sstevel@tonic-gate } else { 1968*7c478bd9Sstevel@tonic-gate start_bit = 16 * (ino >> 3) + 2 * (ino & 0x7); 1969*7c478bd9Sstevel@tonic-gate intr_state_reg = softsp->sbus_intr_state; 1970*7c478bd9Sstevel@tonic-gate } 1971*7c478bd9Sstevel@tonic-gate 1972*7c478bd9Sstevel@tonic-gate while (((*intr_state_reg >> start_bit) & 0x3) == INT_PENDING && 1973*7c478bd9Sstevel@tonic-gate !panicstr) 1974*7c478bd9Sstevel@tonic-gate /* empty */; 1975*7c478bd9Sstevel@tonic-gate 1976*7c478bd9Sstevel@tonic-gate slot = find_sbus_slot(dip, rdip); 1977*7c478bd9Sstevel@tonic-gate 1978*7c478bd9Sstevel@tonic-gate /* Return if the slot is invalid */ 1979*7c478bd9Sstevel@tonic-gate if (slot >= MAX_SBUS_SLOT_ADDR || slot < 0) { 1980*7c478bd9Sstevel@tonic-gate goto done; 1981*7c478bd9Sstevel@tonic-gate } 1982*7c478bd9Sstevel@tonic-gate 1983*7c478bd9Sstevel@tonic-gate sbus_arg = softsp->intr_list[ino]; 1984*7c478bd9Sstevel@tonic-gate 1985*7c478bd9Sstevel@tonic-gate /* Decrement the intr handler count on this slot */ 1986*7c478bd9Sstevel@tonic-gate softsp->intr_hndlr_cnt[slot]--; 1987*7c478bd9Sstevel@tonic-gate 1988*7c478bd9Sstevel@tonic-gate DPRINTF(SBUS_INTERRUPT_DEBUG, ("Rem intr: Softsp 0x%x, Mondo 0x%x, " 1989*7c478bd9Sstevel@tonic-gate "ino 0x%x, sbus_arg 0x%x intr cntr %d\n", softsp, 1990*7c478bd9Sstevel@tonic-gate *ip->is_intr, ino, sbus_arg, softsp->intr_hndlr_cnt[slot])); 1991*7c478bd9Sstevel@tonic-gate 1992*7c478bd9Sstevel@tonic-gate ASSERT(sbus_arg != NULL); 1993*7c478bd9Sstevel@tonic-gate ASSERT(sbus_arg->handler_list != NULL); 1994*7c478bd9Sstevel@tonic-gate sbus_free_handler(rdip, hdlp->ih_inum, sbus_arg); 1995*7c478bd9Sstevel@tonic-gate 1996*7c478bd9Sstevel@tonic-gate /* If we still have a list, we're done. */ 1997*7c478bd9Sstevel@tonic-gate if (sbus_arg->handler_list == NULL) { 1998*7c478bd9Sstevel@tonic-gate hdlp->ih_vector = *ip->is_intr; 1999*7c478bd9Sstevel@tonic-gate i_ddi_rem_ivintr(hdlp); 2000*7c478bd9Sstevel@tonic-gate } 2001*7c478bd9Sstevel@tonic-gate 2002*7c478bd9Sstevel@tonic-gate /* 2003*7c478bd9Sstevel@tonic-gate * If other devices are still installed for this slot, we need to 2004*7c478bd9Sstevel@tonic-gate * turn the valid bit back on. 2005*7c478bd9Sstevel@tonic-gate */ 2006*7c478bd9Sstevel@tonic-gate if (softsp->intr_hndlr_cnt[slot] > 0) { 2007*7c478bd9Sstevel@tonic-gate *mondo_vec_reg |= INTERRUPT_VALID; 2008*7c478bd9Sstevel@tonic-gate #ifndef lint 2009*7c478bd9Sstevel@tonic-gate tmpreg = *softsp->sbus_ctrl_reg; 2010*7c478bd9Sstevel@tonic-gate #endif /* !lint */ 2011*7c478bd9Sstevel@tonic-gate } 2012*7c478bd9Sstevel@tonic-gate 2013*7c478bd9Sstevel@tonic-gate if ((softsp->intr_hndlr_cnt[slot] == 0) || (slot >= EXT_SBUS_SLOTS)) { 2014*7c478bd9Sstevel@tonic-gate ASSERT(sbus_arg->handler_list == NULL); 2015*7c478bd9Sstevel@tonic-gate #ifdef _STARFIRE 2016*7c478bd9Sstevel@tonic-gate /* Do cleanup for interrupt target translation */ 2017*7c478bd9Sstevel@tonic-gate pc_ittrans_cleanup(softsp->ittrans_cookie, mondo_vec_reg); 2018*7c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */ 2019*7c478bd9Sstevel@tonic-gate } 2020*7c478bd9Sstevel@tonic-gate 2021*7c478bd9Sstevel@tonic-gate 2022*7c478bd9Sstevel@tonic-gate /* Free up the memory used for the sbus interrupt handler */ 2023*7c478bd9Sstevel@tonic-gate if (sbus_arg->handler_list == NULL) { 2024*7c478bd9Sstevel@tonic-gate DPRINTF(SBUS_INTERRUPT_DEBUG, ("Rem intr: Freeing sbus arg " 2025*7c478bd9Sstevel@tonic-gate "0x%x\n", sbus_arg)); 2026*7c478bd9Sstevel@tonic-gate kmem_free(sbus_arg, sizeof (struct sbus_wrapper_arg)); 2027*7c478bd9Sstevel@tonic-gate softsp->intr_list[ino] = NULL; 2028*7c478bd9Sstevel@tonic-gate } 2029*7c478bd9Sstevel@tonic-gate 2030*7c478bd9Sstevel@tonic-gate done: 2031*7c478bd9Sstevel@tonic-gate mutex_exit(&softsp->intr_poll_list_lock); 2032*7c478bd9Sstevel@tonic-gate } 2033*7c478bd9Sstevel@tonic-gate 2034*7c478bd9Sstevel@tonic-gate /* 2035*7c478bd9Sstevel@tonic-gate * We're prepared to claim that the interrupt string is in 2036*7c478bd9Sstevel@tonic-gate * the form of a list of <SBusintr> specifications, or we're dealing 2037*7c478bd9Sstevel@tonic-gate * with on-board devices and we have an interrupt_number property which 2038*7c478bd9Sstevel@tonic-gate * gives us our mondo number. 2039*7c478bd9Sstevel@tonic-gate * Translate the sbus levels or mondos into sysiointrspecs. 2040*7c478bd9Sstevel@tonic-gate */ 2041*7c478bd9Sstevel@tonic-gate static int 2042*7c478bd9Sstevel@tonic-gate sbus_xlate_intrs(dev_info_t *dip, dev_info_t *rdip, ddi_ispec_t *ispecp, 2043*7c478bd9Sstevel@tonic-gate int32_t ign) 2044*7c478bd9Sstevel@tonic-gate { 2045*7c478bd9Sstevel@tonic-gate uint32_t ino, slot, level = *ispecp->is_intr; 2046*7c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 2047*7c478bd9Sstevel@tonic-gate 2048*7c478bd9Sstevel@tonic-gate /* 2049*7c478bd9Sstevel@tonic-gate * Create the sysio ino number. onboard devices will have 2050*7c478bd9Sstevel@tonic-gate * an "interrupts" property, that is equal to the ino number. 2051*7c478bd9Sstevel@tonic-gate * If the devices are from the 2052*7c478bd9Sstevel@tonic-gate * expansion slots, we construct the ino number by putting 2053*7c478bd9Sstevel@tonic-gate * the slot number in the upper three bits, and the sbus 2054*7c478bd9Sstevel@tonic-gate * interrupt level in the lower three bits. 2055*7c478bd9Sstevel@tonic-gate */ 2056*7c478bd9Sstevel@tonic-gate if (level > MAX_SBUS_LEVEL) { 2057*7c478bd9Sstevel@tonic-gate ino = level; 2058*7c478bd9Sstevel@tonic-gate } else { 2059*7c478bd9Sstevel@tonic-gate /* Construct ino from slot and interrupts */ 2060*7c478bd9Sstevel@tonic-gate if ((slot = find_sbus_slot(dip, rdip)) == -1) { 2061*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Can't determine sbus slot " 2062*7c478bd9Sstevel@tonic-gate "of %s device\n", ddi_get_name(rdip)); 2063*7c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 2064*7c478bd9Sstevel@tonic-gate goto done; 2065*7c478bd9Sstevel@tonic-gate } 2066*7c478bd9Sstevel@tonic-gate 2067*7c478bd9Sstevel@tonic-gate if (slot >= MAX_SBUS_SLOT_ADDR) { 2068*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Invalid sbus slot 0x%x" 2069*7c478bd9Sstevel@tonic-gate "in %s device\n", slot, ddi_get_name(rdip)); 2070*7c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 2071*7c478bd9Sstevel@tonic-gate goto done; 2072*7c478bd9Sstevel@tonic-gate } 2073*7c478bd9Sstevel@tonic-gate 2074*7c478bd9Sstevel@tonic-gate ino = slot << 3; 2075*7c478bd9Sstevel@tonic-gate ino |= level; 2076*7c478bd9Sstevel@tonic-gate } 2077*7c478bd9Sstevel@tonic-gate 2078*7c478bd9Sstevel@tonic-gate /* Sanity check the inos range */ 2079*7c478bd9Sstevel@tonic-gate if (ino >= MAX_INO_TABLE_SIZE) { 2080*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Ino vector 0x%x out of range", ino); 2081*7c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 2082*7c478bd9Sstevel@tonic-gate goto done; 2083*7c478bd9Sstevel@tonic-gate } 2084*7c478bd9Sstevel@tonic-gate /* Sanity check the inos value */ 2085*7c478bd9Sstevel@tonic-gate if (!ino_table[ino]) { 2086*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Ino vector 0x%x is invalid", ino); 2087*7c478bd9Sstevel@tonic-gate ret = DDI_FAILURE; 2088*7c478bd9Sstevel@tonic-gate goto done; 2089*7c478bd9Sstevel@tonic-gate } 2090*7c478bd9Sstevel@tonic-gate 2091*7c478bd9Sstevel@tonic-gate if (ispecp->is_pil == 0) { 2092*7c478bd9Sstevel@tonic-gate #define SOC_PRIORITY 5 2093*7c478bd9Sstevel@tonic-gate /* The sunfire i/o board has a soc in the printer slot */ 2094*7c478bd9Sstevel@tonic-gate if ((ino_table[ino]->clear_reg == PP_CLEAR) && 2095*7c478bd9Sstevel@tonic-gate ((strcmp(ddi_get_name(rdip), "soc") == 0) || 2096*7c478bd9Sstevel@tonic-gate (strcmp(ddi_get_name(rdip), "SUNW,soc") == 0))) { 2097*7c478bd9Sstevel@tonic-gate ispecp->is_pil = SOC_PRIORITY; 2098*7c478bd9Sstevel@tonic-gate } else { 2099*7c478bd9Sstevel@tonic-gate /* Figure out the pil associated with this interrupt */ 2100*7c478bd9Sstevel@tonic-gate ispecp->is_pil = interrupt_priorities[ino]; 2101*7c478bd9Sstevel@tonic-gate } 2102*7c478bd9Sstevel@tonic-gate } 2103*7c478bd9Sstevel@tonic-gate 2104*7c478bd9Sstevel@tonic-gate /* Or in the upa_id into the interrupt group number field */ 2105*7c478bd9Sstevel@tonic-gate *ispecp->is_intr = (uint32_t)(ino | ign); 2106*7c478bd9Sstevel@tonic-gate 2107*7c478bd9Sstevel@tonic-gate DPRINTF(SBUS_INTERRUPT_DEBUG, ("Xlate intr: Interrupt info for " 2108*7c478bd9Sstevel@tonic-gate "device %s Mondo: 0x%x, ino: 0x%x, Pil: 0x%x, sbus level: 0x%x\n", 2109*7c478bd9Sstevel@tonic-gate ddi_get_name(rdip), *ispecp->is_intr, ino, ispecp->is_pil, level)); 2110*7c478bd9Sstevel@tonic-gate 2111*7c478bd9Sstevel@tonic-gate done: 2112*7c478bd9Sstevel@tonic-gate return (ret); 2113*7c478bd9Sstevel@tonic-gate 2114*7c478bd9Sstevel@tonic-gate } 2115*7c478bd9Sstevel@tonic-gate 2116*7c478bd9Sstevel@tonic-gate /* new intr_ops structure */ 2117*7c478bd9Sstevel@tonic-gate int 2118*7c478bd9Sstevel@tonic-gate sbus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 2119*7c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 2120*7c478bd9Sstevel@tonic-gate { 2121*7c478bd9Sstevel@tonic-gate struct sbus_soft_state *softsp = (struct sbus_soft_state *) 2122*7c478bd9Sstevel@tonic-gate ddi_get_soft_state(sbusp, ddi_get_instance(dip)); 2123*7c478bd9Sstevel@tonic-gate ddi_ispec_t *ip = (ddi_ispec_t *)hdlp->ih_private; 2124*7c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 2125*7c478bd9Sstevel@tonic-gate 2126*7c478bd9Sstevel@tonic-gate 2127*7c478bd9Sstevel@tonic-gate switch (intr_op) { 2128*7c478bd9Sstevel@tonic-gate case DDI_INTROP_GETCAP: 2129*7c478bd9Sstevel@tonic-gate *(int *)result = 0; 2130*7c478bd9Sstevel@tonic-gate break; 2131*7c478bd9Sstevel@tonic-gate case DDI_INTROP_ALLOC: 2132*7c478bd9Sstevel@tonic-gate *(int *)result = hdlp->ih_scratch1; 2133*7c478bd9Sstevel@tonic-gate break; 2134*7c478bd9Sstevel@tonic-gate case DDI_INTROP_FREE: 2135*7c478bd9Sstevel@tonic-gate break; 2136*7c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPRI: 2137*7c478bd9Sstevel@tonic-gate if (ip->is_pil == 0) { 2138*7c478bd9Sstevel@tonic-gate /* Xlate the interrupt */ 2139*7c478bd9Sstevel@tonic-gate (void) sbus_xlate_intrs(dip, rdip, 2140*7c478bd9Sstevel@tonic-gate ip, softsp->intr_mapping_ign); 2141*7c478bd9Sstevel@tonic-gate } 2142*7c478bd9Sstevel@tonic-gate 2143*7c478bd9Sstevel@tonic-gate *(int *)result = ip->is_pil; 2144*7c478bd9Sstevel@tonic-gate break; 2145*7c478bd9Sstevel@tonic-gate case DDI_INTROP_SETPRI: 2146*7c478bd9Sstevel@tonic-gate ip->is_pil = (*(int *)result); 2147*7c478bd9Sstevel@tonic-gate break; 2148*7c478bd9Sstevel@tonic-gate case DDI_INTROP_ADDISR: 2149*7c478bd9Sstevel@tonic-gate hdlp->ih_vector = *ip->is_intr; 2150*7c478bd9Sstevel@tonic-gate ret = sbus_add_intr_impl(dip, rdip, hdlp); 2151*7c478bd9Sstevel@tonic-gate break; 2152*7c478bd9Sstevel@tonic-gate case DDI_INTROP_REMISR: 2153*7c478bd9Sstevel@tonic-gate hdlp->ih_vector = *ip->is_intr; 2154*7c478bd9Sstevel@tonic-gate sbus_remove_intr_impl(dip, rdip, hdlp); 2155*7c478bd9Sstevel@tonic-gate break; 2156*7c478bd9Sstevel@tonic-gate case DDI_INTROP_ENABLE: 2157*7c478bd9Sstevel@tonic-gate ret = sbus_update_intr_state(dip, rdip, hdlp, 2158*7c478bd9Sstevel@tonic-gate SBUS_INTR_STATE_ENABLE); 2159*7c478bd9Sstevel@tonic-gate break; 2160*7c478bd9Sstevel@tonic-gate case DDI_INTROP_DISABLE: 2161*7c478bd9Sstevel@tonic-gate ret = sbus_update_intr_state(dip, rdip, hdlp, 2162*7c478bd9Sstevel@tonic-gate SBUS_INTR_STATE_DISABLE); 2163*7c478bd9Sstevel@tonic-gate break; 2164*7c478bd9Sstevel@tonic-gate case DDI_INTROP_NINTRS: 2165*7c478bd9Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 2166*7c478bd9Sstevel@tonic-gate *(int *)result = i_ddi_get_nintrs(rdip); 2167*7c478bd9Sstevel@tonic-gate break; 2168*7c478bd9Sstevel@tonic-gate case DDI_INTROP_SETCAP: 2169*7c478bd9Sstevel@tonic-gate case DDI_INTROP_SETMASK: 2170*7c478bd9Sstevel@tonic-gate case DDI_INTROP_CLRMASK: 2171*7c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPENDING: 2172*7c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 2173*7c478bd9Sstevel@tonic-gate break; 2174*7c478bd9Sstevel@tonic-gate case DDI_INTROP_SUPPORTED_TYPES: 2175*7c478bd9Sstevel@tonic-gate /* Sbus nexus driver supports only fixed interrupts */ 2176*7c478bd9Sstevel@tonic-gate *(int *)result = i_ddi_get_nintrs(rdip) ? 2177*7c478bd9Sstevel@tonic-gate DDI_INTR_TYPE_FIXED : 0; 2178*7c478bd9Sstevel@tonic-gate break; 2179*7c478bd9Sstevel@tonic-gate default: 2180*7c478bd9Sstevel@tonic-gate ret = i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result); 2181*7c478bd9Sstevel@tonic-gate break; 2182*7c478bd9Sstevel@tonic-gate } 2183*7c478bd9Sstevel@tonic-gate 2184*7c478bd9Sstevel@tonic-gate return (ret); 2185*7c478bd9Sstevel@tonic-gate } 2186*7c478bd9Sstevel@tonic-gate 2187*7c478bd9Sstevel@tonic-gate 2188*7c478bd9Sstevel@tonic-gate /* 2189*7c478bd9Sstevel@tonic-gate * Called by suspend/resume to save/restore the interrupt status (valid bit) 2190*7c478bd9Sstevel@tonic-gate * of the interrupt mapping registers. 2191*7c478bd9Sstevel@tonic-gate */ 2192*7c478bd9Sstevel@tonic-gate static void 2193*7c478bd9Sstevel@tonic-gate sbus_cpr_handle_intr_map_reg(uint64_t *cpr_softsp, volatile uint64_t *baddr, 2194*7c478bd9Sstevel@tonic-gate int save) 2195*7c478bd9Sstevel@tonic-gate { 2196*7c478bd9Sstevel@tonic-gate int i; 2197*7c478bd9Sstevel@tonic-gate volatile uint64_t *mondo_vec_reg; 2198*7c478bd9Sstevel@tonic-gate 2199*7c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_INO_TABLE_SIZE; i++) { 2200*7c478bd9Sstevel@tonic-gate if (ino_table[i] != NULL) { 2201*7c478bd9Sstevel@tonic-gate mondo_vec_reg = baddr + ino_table[i]->mapping_reg; 2202*7c478bd9Sstevel@tonic-gate if (save) { 2203*7c478bd9Sstevel@tonic-gate if (*mondo_vec_reg & INTERRUPT_VALID) { 2204*7c478bd9Sstevel@tonic-gate cpr_softsp[i] = *mondo_vec_reg; 2205*7c478bd9Sstevel@tonic-gate } 2206*7c478bd9Sstevel@tonic-gate } else { 2207*7c478bd9Sstevel@tonic-gate if (cpr_softsp[i]) { 2208*7c478bd9Sstevel@tonic-gate *mondo_vec_reg = cpr_softsp[i]; 2209*7c478bd9Sstevel@tonic-gate } 2210*7c478bd9Sstevel@tonic-gate } 2211*7c478bd9Sstevel@tonic-gate } 2212*7c478bd9Sstevel@tonic-gate } 2213*7c478bd9Sstevel@tonic-gate } 2214*7c478bd9Sstevel@tonic-gate 2215*7c478bd9Sstevel@tonic-gate #define SZ_INO_TABLE (sizeof (ino_table) / sizeof (ino_table[0])) 2216*7c478bd9Sstevel@tonic-gate 2217*7c478bd9Sstevel@tonic-gate /* 2218*7c478bd9Sstevel@tonic-gate * sbus_intrdist 2219*7c478bd9Sstevel@tonic-gate * 2220*7c478bd9Sstevel@tonic-gate * This function retargets active interrupts by reprogramming the mondo 2221*7c478bd9Sstevel@tonic-gate * vec register. If the CPU ID of the target has not changed, then 2222*7c478bd9Sstevel@tonic-gate * the mondo is not reprogrammed. The routine must hold the mondo 2223*7c478bd9Sstevel@tonic-gate * lock for this instance of the sbus. 2224*7c478bd9Sstevel@tonic-gate */ 2225*7c478bd9Sstevel@tonic-gate static void 2226*7c478bd9Sstevel@tonic-gate sbus_intrdist(void *arg) 2227*7c478bd9Sstevel@tonic-gate { 2228*7c478bd9Sstevel@tonic-gate struct sbus_soft_state *softsp; 2229*7c478bd9Sstevel@tonic-gate dev_info_t *dip = (dev_info_t *)arg; 2230*7c478bd9Sstevel@tonic-gate volatile uint64_t *mondo_vec_reg; 2231*7c478bd9Sstevel@tonic-gate uint64_t *last_mondo_vec_reg; 2232*7c478bd9Sstevel@tonic-gate uint64_t mondo_vec; 2233*7c478bd9Sstevel@tonic-gate volatile uint64_t *intr_state_reg; 2234*7c478bd9Sstevel@tonic-gate uint_t start_bit; 2235*7c478bd9Sstevel@tonic-gate volatile uint64_t tmpreg; /* HW flush reg */ 2236*7c478bd9Sstevel@tonic-gate uint_t mondo; 2237*7c478bd9Sstevel@tonic-gate uint_t cpu_id; 2238*7c478bd9Sstevel@tonic-gate 2239*7c478bd9Sstevel@tonic-gate /* extract the soft state pointer */ 2240*7c478bd9Sstevel@tonic-gate softsp = ddi_get_soft_state(sbusp, ddi_get_instance(dip)); 2241*7c478bd9Sstevel@tonic-gate 2242*7c478bd9Sstevel@tonic-gate last_mondo_vec_reg = NULL; 2243*7c478bd9Sstevel@tonic-gate for (mondo = 0; mondo < SZ_INO_TABLE; mondo++) { 2244*7c478bd9Sstevel@tonic-gate if (ino_table[mondo] == NULL) 2245*7c478bd9Sstevel@tonic-gate continue; 2246*7c478bd9Sstevel@tonic-gate 2247*7c478bd9Sstevel@tonic-gate mondo_vec_reg = (softsp->intr_mapping_reg + 2248*7c478bd9Sstevel@tonic-gate ino_table[mondo]->mapping_reg); 2249*7c478bd9Sstevel@tonic-gate 2250*7c478bd9Sstevel@tonic-gate /* Don't reprogram the same register twice */ 2251*7c478bd9Sstevel@tonic-gate if (mondo_vec_reg == last_mondo_vec_reg) 2252*7c478bd9Sstevel@tonic-gate continue; 2253*7c478bd9Sstevel@tonic-gate 2254*7c478bd9Sstevel@tonic-gate if ((*mondo_vec_reg & INTERRUPT_VALID) == 0) 2255*7c478bd9Sstevel@tonic-gate continue; 2256*7c478bd9Sstevel@tonic-gate 2257*7c478bd9Sstevel@tonic-gate last_mondo_vec_reg = (uint64_t *)mondo_vec_reg; 2258*7c478bd9Sstevel@tonic-gate 2259*7c478bd9Sstevel@tonic-gate cpu_id = intr_dist_cpuid(); 2260*7c478bd9Sstevel@tonic-gate #ifdef _STARFIRE 2261*7c478bd9Sstevel@tonic-gate /* 2262*7c478bd9Sstevel@tonic-gate * For Starfire it is a pain to check the current target for 2263*7c478bd9Sstevel@tonic-gate * the mondo since we have to read the PC asics ITTR slot 2264*7c478bd9Sstevel@tonic-gate * assigned to this mondo. It will be much easier to assume 2265*7c478bd9Sstevel@tonic-gate * the current target is always different and do the target 2266*7c478bd9Sstevel@tonic-gate * reprogram all the time. 2267*7c478bd9Sstevel@tonic-gate */ 2268*7c478bd9Sstevel@tonic-gate #else 2269*7c478bd9Sstevel@tonic-gate if (((*mondo_vec_reg & IMR_TID) >> IMR_TID_SHIFT) == cpu_id) { 2270*7c478bd9Sstevel@tonic-gate /* It is the same, don't reprogram */ 2271*7c478bd9Sstevel@tonic-gate return; 2272*7c478bd9Sstevel@tonic-gate } 2273*7c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */ 2274*7c478bd9Sstevel@tonic-gate 2275*7c478bd9Sstevel@tonic-gate /* So it's OK to reprogram the CPU target */ 2276*7c478bd9Sstevel@tonic-gate 2277*7c478bd9Sstevel@tonic-gate /* turn off valid bit and wait for the state machine to idle */ 2278*7c478bd9Sstevel@tonic-gate *mondo_vec_reg &= ~INTERRUPT_VALID; 2279*7c478bd9Sstevel@tonic-gate 2280*7c478bd9Sstevel@tonic-gate tmpreg = *softsp->sbus_ctrl_reg; 2281*7c478bd9Sstevel@tonic-gate 2282*7c478bd9Sstevel@tonic-gate #ifdef lint 2283*7c478bd9Sstevel@tonic-gate tmpreg = tmpreg; 2284*7c478bd9Sstevel@tonic-gate #endif /* lint */ 2285*7c478bd9Sstevel@tonic-gate 2286*7c478bd9Sstevel@tonic-gate if (mondo > MAX_MONDO_EXTERNAL) { 2287*7c478bd9Sstevel@tonic-gate start_bit = ino_table[mondo]->diagreg_shift; 2288*7c478bd9Sstevel@tonic-gate intr_state_reg = softsp->obio_intr_state; 2289*7c478bd9Sstevel@tonic-gate 2290*7c478bd9Sstevel@tonic-gate /* 2291*7c478bd9Sstevel@tonic-gate * Loop waiting for state machine to idle. Do not keep 2292*7c478bd9Sstevel@tonic-gate * looping on a panic so that the system does not hang. 2293*7c478bd9Sstevel@tonic-gate */ 2294*7c478bd9Sstevel@tonic-gate while ((((*intr_state_reg >> start_bit) & 0x3) == 2295*7c478bd9Sstevel@tonic-gate INT_PENDING) && !panicstr) 2296*7c478bd9Sstevel@tonic-gate /* empty */; 2297*7c478bd9Sstevel@tonic-gate } else { 2298*7c478bd9Sstevel@tonic-gate int int_pending = 0; /* interrupts pending */ 2299*7c478bd9Sstevel@tonic-gate 2300*7c478bd9Sstevel@tonic-gate /* 2301*7c478bd9Sstevel@tonic-gate * Shift over to first bit for this Sbus slot, 16 2302*7c478bd9Sstevel@tonic-gate * bits per slot, bits 0-1 of each slot are reserved. 2303*7c478bd9Sstevel@tonic-gate */ 2304*7c478bd9Sstevel@tonic-gate start_bit = 16 * (mondo >> 3) + 2; 2305*7c478bd9Sstevel@tonic-gate intr_state_reg = softsp->sbus_intr_state; 2306*7c478bd9Sstevel@tonic-gate 2307*7c478bd9Sstevel@tonic-gate /* 2308*7c478bd9Sstevel@tonic-gate * Make sure interrupts for levels 1-7 of this slot 2309*7c478bd9Sstevel@tonic-gate * are not pending. 2310*7c478bd9Sstevel@tonic-gate */ 2311*7c478bd9Sstevel@tonic-gate do { 2312*7c478bd9Sstevel@tonic-gate int level; /* Sbus interrupt level */ 2313*7c478bd9Sstevel@tonic-gate int shift; /* # of bits to shift */ 2314*7c478bd9Sstevel@tonic-gate uint64_t state_reg = *intr_state_reg; 2315*7c478bd9Sstevel@tonic-gate 2316*7c478bd9Sstevel@tonic-gate int_pending = 0; 2317*7c478bd9Sstevel@tonic-gate 2318*7c478bd9Sstevel@tonic-gate for (shift = start_bit, level = 1; level < 8; 2319*7c478bd9Sstevel@tonic-gate level++, shift += 2) { 2320*7c478bd9Sstevel@tonic-gate if (((state_reg >> shift) & 2321*7c478bd9Sstevel@tonic-gate 0x3) == INT_PENDING) { 2322*7c478bd9Sstevel@tonic-gate int_pending = 1; 2323*7c478bd9Sstevel@tonic-gate break; 2324*7c478bd9Sstevel@tonic-gate } 2325*7c478bd9Sstevel@tonic-gate } 2326*7c478bd9Sstevel@tonic-gate } while (int_pending && !panicstr); 2327*7c478bd9Sstevel@tonic-gate } 2328*7c478bd9Sstevel@tonic-gate 2329*7c478bd9Sstevel@tonic-gate /* re-target the mondo and turn it on */ 2330*7c478bd9Sstevel@tonic-gate #ifdef _STARFIRE 2331*7c478bd9Sstevel@tonic-gate mondo_vec = (pc_translate_tgtid(softsp->ittrans_cookie, 2332*7c478bd9Sstevel@tonic-gate cpu_id, mondo_vec_reg) << 2333*7c478bd9Sstevel@tonic-gate INTERRUPT_CPU_FIELD) | 2334*7c478bd9Sstevel@tonic-gate INTERRUPT_VALID; 2335*7c478bd9Sstevel@tonic-gate #else 2336*7c478bd9Sstevel@tonic-gate mondo_vec = (cpu_id << INTERRUPT_CPU_FIELD) | INTERRUPT_VALID; 2337*7c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */ 2338*7c478bd9Sstevel@tonic-gate 2339*7c478bd9Sstevel@tonic-gate /* write it back to the hardware. */ 2340*7c478bd9Sstevel@tonic-gate *mondo_vec_reg = mondo_vec; 2341*7c478bd9Sstevel@tonic-gate 2342*7c478bd9Sstevel@tonic-gate /* flush the hardware buffers. */ 2343*7c478bd9Sstevel@tonic-gate tmpreg = *mondo_vec_reg; 2344*7c478bd9Sstevel@tonic-gate 2345*7c478bd9Sstevel@tonic-gate #ifdef lint 2346*7c478bd9Sstevel@tonic-gate tmpreg = tmpreg; 2347*7c478bd9Sstevel@tonic-gate #endif /* lint */ 2348*7c478bd9Sstevel@tonic-gate } 2349*7c478bd9Sstevel@tonic-gate } 2350*7c478bd9Sstevel@tonic-gate 2351*7c478bd9Sstevel@tonic-gate /* 2352*7c478bd9Sstevel@tonic-gate * Reset interrupts to IDLE. This function is called during 2353*7c478bd9Sstevel@tonic-gate * panic handling after redistributing interrupts; it's needed to 2354*7c478bd9Sstevel@tonic-gate * support dumping to network devices after 'sync' from OBP. 2355*7c478bd9Sstevel@tonic-gate * 2356*7c478bd9Sstevel@tonic-gate * N.B. This routine runs in a context where all other threads 2357*7c478bd9Sstevel@tonic-gate * are permanently suspended. 2358*7c478bd9Sstevel@tonic-gate */ 2359*7c478bd9Sstevel@tonic-gate static uint_t 2360*7c478bd9Sstevel@tonic-gate sbus_intr_reset(void *arg) 2361*7c478bd9Sstevel@tonic-gate { 2362*7c478bd9Sstevel@tonic-gate dev_info_t *dip = (dev_info_t *)arg; 2363*7c478bd9Sstevel@tonic-gate struct sbus_soft_state *softsp; 2364*7c478bd9Sstevel@tonic-gate uint_t mondo; 2365*7c478bd9Sstevel@tonic-gate volatile uint64_t *mondo_clear_reg; 2366*7c478bd9Sstevel@tonic-gate 2367*7c478bd9Sstevel@tonic-gate softsp = ddi_get_soft_state(sbusp, ddi_get_instance(dip)); 2368*7c478bd9Sstevel@tonic-gate 2369*7c478bd9Sstevel@tonic-gate for (mondo = 0; mondo < SZ_INO_TABLE; mondo++) { 2370*7c478bd9Sstevel@tonic-gate if (ino_table[mondo] == NULL || 2371*7c478bd9Sstevel@tonic-gate ino_table[mondo]->clear_reg == NULL) { 2372*7c478bd9Sstevel@tonic-gate 2373*7c478bd9Sstevel@tonic-gate continue; 2374*7c478bd9Sstevel@tonic-gate } 2375*7c478bd9Sstevel@tonic-gate 2376*7c478bd9Sstevel@tonic-gate mondo_clear_reg = (softsp->clr_intr_reg + 2377*7c478bd9Sstevel@tonic-gate ino_table[mondo]->clear_reg); 2378*7c478bd9Sstevel@tonic-gate *mondo_clear_reg = SBUS_INTR_IDLE; 2379*7c478bd9Sstevel@tonic-gate } 2380*7c478bd9Sstevel@tonic-gate 2381*7c478bd9Sstevel@tonic-gate return (BF_NONE); 2382*7c478bd9Sstevel@tonic-gate } 2383*7c478bd9Sstevel@tonic-gate 2384*7c478bd9Sstevel@tonic-gate /* 2385*7c478bd9Sstevel@tonic-gate * called from sbus_add_kstats() to create a kstat for each %pic 2386*7c478bd9Sstevel@tonic-gate * that the SBUS supports. These (read-only) kstats export the 2387*7c478bd9Sstevel@tonic-gate * event names that each %pic supports. 2388*7c478bd9Sstevel@tonic-gate * 2389*7c478bd9Sstevel@tonic-gate * if we fail to create any of these kstats we must remove any 2390*7c478bd9Sstevel@tonic-gate * that we have already created and return; 2391*7c478bd9Sstevel@tonic-gate * 2392*7c478bd9Sstevel@tonic-gate * NOTE: because all sbus devices use the same events we only 2393*7c478bd9Sstevel@tonic-gate * need to create the picN kstats once. All instances can 2394*7c478bd9Sstevel@tonic-gate * use the same picN kstats. 2395*7c478bd9Sstevel@tonic-gate * 2396*7c478bd9Sstevel@tonic-gate * The flexibility exists to allow each device specify it's 2397*7c478bd9Sstevel@tonic-gate * own events by creating picN kstats with the instance number 2398*7c478bd9Sstevel@tonic-gate * set to ddi_get_instance(softsp->dip). 2399*7c478bd9Sstevel@tonic-gate * 2400*7c478bd9Sstevel@tonic-gate * When searching for a picN kstat for a device you should 2401*7c478bd9Sstevel@tonic-gate * first search for a picN kstat using the instance number 2402*7c478bd9Sstevel@tonic-gate * of the device you are interested in. If that fails you 2403*7c478bd9Sstevel@tonic-gate * should use the first picN kstat found for that device. 2404*7c478bd9Sstevel@tonic-gate */ 2405*7c478bd9Sstevel@tonic-gate static void 2406*7c478bd9Sstevel@tonic-gate sbus_add_picN_kstats(dev_info_t *dip) 2407*7c478bd9Sstevel@tonic-gate { 2408*7c478bd9Sstevel@tonic-gate /* 2409*7c478bd9Sstevel@tonic-gate * SBUS Performance Events. 2410*7c478bd9Sstevel@tonic-gate * 2411*7c478bd9Sstevel@tonic-gate * We declare an array of event-names and event-masks. 2412*7c478bd9Sstevel@tonic-gate * The num of events in this array is AC_NUM_EVENTS. 2413*7c478bd9Sstevel@tonic-gate */ 2414*7c478bd9Sstevel@tonic-gate sbus_event_mask_t sbus_events_arr[SBUS_NUM_EVENTS] = { 2415*7c478bd9Sstevel@tonic-gate {"dvma_stream_rd", 0x0}, {"dvma_stream_wr", 0x1}, 2416*7c478bd9Sstevel@tonic-gate {"dvma_const_rd", 0x2}, {"dvma_const_wr", 0x3}, 2417*7c478bd9Sstevel@tonic-gate {"dvma_tlb_misses", 0x4}, {"dvma_stream_buf_mis", 0x5}, 2418*7c478bd9Sstevel@tonic-gate {"dvma_cycles", 0x6}, {"dvma_bytes_xfr", 0x7}, 2419*7c478bd9Sstevel@tonic-gate {"interrupts", 0x8}, {"upa_inter_nack", 0x9}, 2420*7c478bd9Sstevel@tonic-gate {"pio_reads", 0xA}, {"pio_writes", 0xB}, 2421*7c478bd9Sstevel@tonic-gate {"sbus_reruns", 0xC}, {"pio_cycles", 0xD} 2422*7c478bd9Sstevel@tonic-gate }; 2423*7c478bd9Sstevel@tonic-gate 2424*7c478bd9Sstevel@tonic-gate /* 2425*7c478bd9Sstevel@tonic-gate * We declare an array of clear masks for each pic. 2426*7c478bd9Sstevel@tonic-gate * These masks are used to clear the %pcr bits for 2427*7c478bd9Sstevel@tonic-gate * each pic. 2428*7c478bd9Sstevel@tonic-gate */ 2429*7c478bd9Sstevel@tonic-gate sbus_event_mask_t sbus_clear_pic[SBUS_NUM_PICS] = { 2430*7c478bd9Sstevel@tonic-gate /* pic0 */ 2431*7c478bd9Sstevel@tonic-gate {"clear_pic", (uint64_t)~(0xf)}, 2432*7c478bd9Sstevel@tonic-gate /* pic1 */ 2433*7c478bd9Sstevel@tonic-gate {"clear_pic", (uint64_t)~(0xf << 8)} 2434*7c478bd9Sstevel@tonic-gate }; 2435*7c478bd9Sstevel@tonic-gate 2436*7c478bd9Sstevel@tonic-gate struct kstat_named *sbus_pic_named_data; 2437*7c478bd9Sstevel@tonic-gate int event, pic; 2438*7c478bd9Sstevel@tonic-gate char pic_name[30]; 2439*7c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 2440*7c478bd9Sstevel@tonic-gate int pic_shift = 0; 2441*7c478bd9Sstevel@tonic-gate 2442*7c478bd9Sstevel@tonic-gate for (pic = 0; pic < SBUS_NUM_PICS; pic++) { 2443*7c478bd9Sstevel@tonic-gate /* 2444*7c478bd9Sstevel@tonic-gate * create the picN kstat. The size of this kstat is 2445*7c478bd9Sstevel@tonic-gate * SBUS_NUM_EVENTS + 1 for the clear_event_mask 2446*7c478bd9Sstevel@tonic-gate */ 2447*7c478bd9Sstevel@tonic-gate (void) sprintf(pic_name, "pic%d", pic); /* pic0, pic1 ... */ 2448*7c478bd9Sstevel@tonic-gate if ((sbus_picN_ksp[pic] = kstat_create("sbus", 2449*7c478bd9Sstevel@tonic-gate instance, pic_name, "bus", KSTAT_TYPE_NAMED, 2450*7c478bd9Sstevel@tonic-gate SBUS_NUM_EVENTS + 1, NULL)) == NULL) { 2451*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "sbus %s: kstat_create failed", 2452*7c478bd9Sstevel@tonic-gate pic_name); 2453*7c478bd9Sstevel@tonic-gate 2454*7c478bd9Sstevel@tonic-gate /* remove pic0 kstat if pic1 create fails */ 2455*7c478bd9Sstevel@tonic-gate if (pic == 1) { 2456*7c478bd9Sstevel@tonic-gate kstat_delete(sbus_picN_ksp[0]); 2457*7c478bd9Sstevel@tonic-gate sbus_picN_ksp[0] = NULL; 2458*7c478bd9Sstevel@tonic-gate } 2459*7c478bd9Sstevel@tonic-gate return; 2460*7c478bd9Sstevel@tonic-gate } 2461*7c478bd9Sstevel@tonic-gate 2462*7c478bd9Sstevel@tonic-gate sbus_pic_named_data = 2463*7c478bd9Sstevel@tonic-gate (struct kstat_named *)(sbus_picN_ksp[pic]->ks_data); 2464*7c478bd9Sstevel@tonic-gate 2465*7c478bd9Sstevel@tonic-gate /* 2466*7c478bd9Sstevel@tonic-gate * when we are writing pcr_masks to the kstat we need to 2467*7c478bd9Sstevel@tonic-gate * shift bits left by 8 for pic1 events. 2468*7c478bd9Sstevel@tonic-gate */ 2469*7c478bd9Sstevel@tonic-gate if (pic == 1) 2470*7c478bd9Sstevel@tonic-gate pic_shift = 8; 2471*7c478bd9Sstevel@tonic-gate 2472*7c478bd9Sstevel@tonic-gate /* 2473*7c478bd9Sstevel@tonic-gate * for each picN event we need to write a kstat record 2474*7c478bd9Sstevel@tonic-gate * (name = EVENT, value.ui64 = PCR_MASK) 2475*7c478bd9Sstevel@tonic-gate */ 2476*7c478bd9Sstevel@tonic-gate for (event = 0; event < SBUS_NUM_EVENTS; event ++) { 2477*7c478bd9Sstevel@tonic-gate 2478*7c478bd9Sstevel@tonic-gate /* pcr_mask */ 2479*7c478bd9Sstevel@tonic-gate sbus_pic_named_data[event].value.ui64 = 2480*7c478bd9Sstevel@tonic-gate sbus_events_arr[event].pcr_mask << pic_shift; 2481*7c478bd9Sstevel@tonic-gate 2482*7c478bd9Sstevel@tonic-gate /* event-name */ 2483*7c478bd9Sstevel@tonic-gate kstat_named_init(&sbus_pic_named_data[event], 2484*7c478bd9Sstevel@tonic-gate sbus_events_arr[event].event_name, 2485*7c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT64); 2486*7c478bd9Sstevel@tonic-gate } 2487*7c478bd9Sstevel@tonic-gate 2488*7c478bd9Sstevel@tonic-gate /* 2489*7c478bd9Sstevel@tonic-gate * we add the clear_pic event and mask as the last 2490*7c478bd9Sstevel@tonic-gate * record in the kstat 2491*7c478bd9Sstevel@tonic-gate */ 2492*7c478bd9Sstevel@tonic-gate /* pcr mask */ 2493*7c478bd9Sstevel@tonic-gate sbus_pic_named_data[SBUS_NUM_EVENTS].value.ui64 = 2494*7c478bd9Sstevel@tonic-gate sbus_clear_pic[pic].pcr_mask; 2495*7c478bd9Sstevel@tonic-gate 2496*7c478bd9Sstevel@tonic-gate /* event-name */ 2497*7c478bd9Sstevel@tonic-gate kstat_named_init(&sbus_pic_named_data[SBUS_NUM_EVENTS], 2498*7c478bd9Sstevel@tonic-gate sbus_clear_pic[pic].event_name, 2499*7c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT64); 2500*7c478bd9Sstevel@tonic-gate 2501*7c478bd9Sstevel@tonic-gate kstat_install(sbus_picN_ksp[pic]); 2502*7c478bd9Sstevel@tonic-gate } 2503*7c478bd9Sstevel@tonic-gate } 2504*7c478bd9Sstevel@tonic-gate 2505*7c478bd9Sstevel@tonic-gate static void 2506*7c478bd9Sstevel@tonic-gate sbus_add_kstats(struct sbus_soft_state *softsp) 2507*7c478bd9Sstevel@tonic-gate { 2508*7c478bd9Sstevel@tonic-gate struct kstat *sbus_counters_ksp; 2509*7c478bd9Sstevel@tonic-gate struct kstat_named *sbus_counters_named_data; 2510*7c478bd9Sstevel@tonic-gate 2511*7c478bd9Sstevel@tonic-gate /* 2512*7c478bd9Sstevel@tonic-gate * Create the picN kstats if we are the first instance 2513*7c478bd9Sstevel@tonic-gate * to attach. We use sbus_attachcnt as a count of how 2514*7c478bd9Sstevel@tonic-gate * many instances have attached. This is protected by 2515*7c478bd9Sstevel@tonic-gate * a mutex. 2516*7c478bd9Sstevel@tonic-gate */ 2517*7c478bd9Sstevel@tonic-gate mutex_enter(&sbus_attachcnt_mutex); 2518*7c478bd9Sstevel@tonic-gate if (sbus_attachcnt == 0) 2519*7c478bd9Sstevel@tonic-gate sbus_add_picN_kstats(softsp->dip); 2520*7c478bd9Sstevel@tonic-gate 2521*7c478bd9Sstevel@tonic-gate sbus_attachcnt ++; 2522*7c478bd9Sstevel@tonic-gate mutex_exit(&sbus_attachcnt_mutex); 2523*7c478bd9Sstevel@tonic-gate 2524*7c478bd9Sstevel@tonic-gate /* 2525*7c478bd9Sstevel@tonic-gate * A "counter" kstat is created for each sbus 2526*7c478bd9Sstevel@tonic-gate * instance that provides access to the %pcr and %pic 2527*7c478bd9Sstevel@tonic-gate * registers for that instance. 2528*7c478bd9Sstevel@tonic-gate * 2529*7c478bd9Sstevel@tonic-gate * The size of this kstat is SBUS_NUM_PICS + 1 for %pcr 2530*7c478bd9Sstevel@tonic-gate */ 2531*7c478bd9Sstevel@tonic-gate if ((sbus_counters_ksp = kstat_create("sbus", 2532*7c478bd9Sstevel@tonic-gate ddi_get_instance(softsp->dip), "counters", 2533*7c478bd9Sstevel@tonic-gate "bus", KSTAT_TYPE_NAMED, SBUS_NUM_PICS + 1, 2534*7c478bd9Sstevel@tonic-gate KSTAT_FLAG_WRITABLE)) == NULL) { 2535*7c478bd9Sstevel@tonic-gate 2536*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "sbus%d counters: kstat_create" 2537*7c478bd9Sstevel@tonic-gate " failed", ddi_get_instance(softsp->dip)); 2538*7c478bd9Sstevel@tonic-gate return; 2539*7c478bd9Sstevel@tonic-gate } 2540*7c478bd9Sstevel@tonic-gate 2541*7c478bd9Sstevel@tonic-gate sbus_counters_named_data = 2542*7c478bd9Sstevel@tonic-gate (struct kstat_named *)(sbus_counters_ksp->ks_data); 2543*7c478bd9Sstevel@tonic-gate 2544*7c478bd9Sstevel@tonic-gate /* initialize the named kstats */ 2545*7c478bd9Sstevel@tonic-gate kstat_named_init(&sbus_counters_named_data[0], 2546*7c478bd9Sstevel@tonic-gate "pcr", KSTAT_DATA_UINT64); 2547*7c478bd9Sstevel@tonic-gate 2548*7c478bd9Sstevel@tonic-gate kstat_named_init(&sbus_counters_named_data[1], 2549*7c478bd9Sstevel@tonic-gate "pic0", KSTAT_DATA_UINT64); 2550*7c478bd9Sstevel@tonic-gate 2551*7c478bd9Sstevel@tonic-gate kstat_named_init(&sbus_counters_named_data[2], 2552*7c478bd9Sstevel@tonic-gate "pic1", KSTAT_DATA_UINT64); 2553*7c478bd9Sstevel@tonic-gate 2554*7c478bd9Sstevel@tonic-gate sbus_counters_ksp->ks_update = sbus_counters_kstat_update; 2555*7c478bd9Sstevel@tonic-gate sbus_counters_ksp->ks_private = (void *)softsp; 2556*7c478bd9Sstevel@tonic-gate 2557*7c478bd9Sstevel@tonic-gate kstat_install(sbus_counters_ksp); 2558*7c478bd9Sstevel@tonic-gate 2559*7c478bd9Sstevel@tonic-gate /* update the sofstate */ 2560*7c478bd9Sstevel@tonic-gate softsp->sbus_counters_ksp = sbus_counters_ksp; 2561*7c478bd9Sstevel@tonic-gate } 2562*7c478bd9Sstevel@tonic-gate 2563*7c478bd9Sstevel@tonic-gate static int 2564*7c478bd9Sstevel@tonic-gate sbus_counters_kstat_update(kstat_t *ksp, int rw) 2565*7c478bd9Sstevel@tonic-gate { 2566*7c478bd9Sstevel@tonic-gate struct kstat_named *sbus_counters_data; 2567*7c478bd9Sstevel@tonic-gate struct sbus_soft_state *softsp; 2568*7c478bd9Sstevel@tonic-gate uint64_t pic_register; 2569*7c478bd9Sstevel@tonic-gate 2570*7c478bd9Sstevel@tonic-gate sbus_counters_data = (struct kstat_named *)ksp->ks_data; 2571*7c478bd9Sstevel@tonic-gate softsp = (struct sbus_soft_state *)ksp->ks_private; 2572*7c478bd9Sstevel@tonic-gate 2573*7c478bd9Sstevel@tonic-gate if (rw == KSTAT_WRITE) { 2574*7c478bd9Sstevel@tonic-gate 2575*7c478bd9Sstevel@tonic-gate /* 2576*7c478bd9Sstevel@tonic-gate * Write the pcr value to the softsp->sbus_pcr. 2577*7c478bd9Sstevel@tonic-gate * The pic register is read-only so we don't 2578*7c478bd9Sstevel@tonic-gate * attempt to write to it. 2579*7c478bd9Sstevel@tonic-gate */ 2580*7c478bd9Sstevel@tonic-gate 2581*7c478bd9Sstevel@tonic-gate *softsp->sbus_pcr = 2582*7c478bd9Sstevel@tonic-gate (uint32_t)sbus_counters_data[0].value.ui64; 2583*7c478bd9Sstevel@tonic-gate 2584*7c478bd9Sstevel@tonic-gate } else { 2585*7c478bd9Sstevel@tonic-gate /* 2586*7c478bd9Sstevel@tonic-gate * Read %pcr and %pic register values and write them 2587*7c478bd9Sstevel@tonic-gate * into counters kstat. 2588*7c478bd9Sstevel@tonic-gate * 2589*7c478bd9Sstevel@tonic-gate * Due to a hardware bug we need to right shift the %pcr 2590*7c478bd9Sstevel@tonic-gate * by 4 bits. This is only done when reading the %pcr. 2591*7c478bd9Sstevel@tonic-gate * 2592*7c478bd9Sstevel@tonic-gate */ 2593*7c478bd9Sstevel@tonic-gate /* pcr */ 2594*7c478bd9Sstevel@tonic-gate sbus_counters_data[0].value.ui64 = *softsp->sbus_pcr >> 4; 2595*7c478bd9Sstevel@tonic-gate 2596*7c478bd9Sstevel@tonic-gate pic_register = *softsp->sbus_pic; 2597*7c478bd9Sstevel@tonic-gate /* 2598*7c478bd9Sstevel@tonic-gate * sbus pic register: 2599*7c478bd9Sstevel@tonic-gate * (63:32) = pic0 2600*7c478bd9Sstevel@tonic-gate * (31:00) = pic1 2601*7c478bd9Sstevel@tonic-gate */ 2602*7c478bd9Sstevel@tonic-gate 2603*7c478bd9Sstevel@tonic-gate /* pic0 */ 2604*7c478bd9Sstevel@tonic-gate sbus_counters_data[1].value.ui64 = pic_register >> 32; 2605*7c478bd9Sstevel@tonic-gate /* pic1 */ 2606*7c478bd9Sstevel@tonic-gate sbus_counters_data[2].value.ui64 = 2607*7c478bd9Sstevel@tonic-gate pic_register & SBUS_PIC0_MASK; 2608*7c478bd9Sstevel@tonic-gate 2609*7c478bd9Sstevel@tonic-gate } 2610*7c478bd9Sstevel@tonic-gate return (0); 2611*7c478bd9Sstevel@tonic-gate } 2612*7c478bd9Sstevel@tonic-gate 2613*7c478bd9Sstevel@tonic-gate static int 2614*7c478bd9Sstevel@tonic-gate sbus_update_intr_state(dev_info_t *dip, dev_info_t *rdip, 2615*7c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, uint_t new_intr_state) 2616*7c478bd9Sstevel@tonic-gate { 2617*7c478bd9Sstevel@tonic-gate struct sbus_soft_state *softsp = (struct sbus_soft_state *) 2618*7c478bd9Sstevel@tonic-gate ddi_get_soft_state(sbusp, ddi_get_instance(dip)); 2619*7c478bd9Sstevel@tonic-gate int ino; 2620*7c478bd9Sstevel@tonic-gate struct sbus_wrapper_arg *sbus_arg; 2621*7c478bd9Sstevel@tonic-gate struct sbus_intr_handler *intr_handler; 2622*7c478bd9Sstevel@tonic-gate ddi_ispec_t *ip = (ddi_ispec_t *)hdlp->ih_private; 2623*7c478bd9Sstevel@tonic-gate 2624*7c478bd9Sstevel@tonic-gate /* Xlate the interrupt */ 2625*7c478bd9Sstevel@tonic-gate if (sbus_xlate_intrs(dip, rdip, ip, 2626*7c478bd9Sstevel@tonic-gate softsp->intr_mapping_ign) == DDI_FAILURE) { 2627*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "sbus_update_intr_state() can't xlate SBUS " 2628*7c478bd9Sstevel@tonic-gate "devices %s interrupt.", ddi_get_name(rdip)); 2629*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2630*7c478bd9Sstevel@tonic-gate } 2631*7c478bd9Sstevel@tonic-gate 2632*7c478bd9Sstevel@tonic-gate ino = ((int32_t)*ip->is_intr) & SBUS_MAX_INO; 2633*7c478bd9Sstevel@tonic-gate sbus_arg = softsp->intr_list[ino]; 2634*7c478bd9Sstevel@tonic-gate 2635*7c478bd9Sstevel@tonic-gate ASSERT(sbus_arg != NULL); 2636*7c478bd9Sstevel@tonic-gate ASSERT(sbus_arg->handler_list != NULL); 2637*7c478bd9Sstevel@tonic-gate intr_handler = sbus_arg->handler_list; 2638*7c478bd9Sstevel@tonic-gate 2639*7c478bd9Sstevel@tonic-gate while (intr_handler) { 2640*7c478bd9Sstevel@tonic-gate if ((intr_handler->inum == hdlp->ih_inum) && 2641*7c478bd9Sstevel@tonic-gate (intr_handler->dip == rdip)) { 2642*7c478bd9Sstevel@tonic-gate intr_handler->intr_state = new_intr_state; 2643*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2644*7c478bd9Sstevel@tonic-gate } 2645*7c478bd9Sstevel@tonic-gate 2646*7c478bd9Sstevel@tonic-gate intr_handler = intr_handler->next; 2647*7c478bd9Sstevel@tonic-gate } 2648*7c478bd9Sstevel@tonic-gate 2649*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2650*7c478bd9Sstevel@tonic-gate } 2651