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