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