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