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