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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* 26 * Copyright 2019 Peter Tribble. 27 */ 28 29 /* 30 * PCI nexus interrupt handling: 31 * PCI device interrupt handler wrapper 32 * pil lookup routine 33 * PCI device interrupt related initchild code 34 */ 35 36 #include <sys/types.h> 37 #include <sys/kmem.h> 38 #include <sys/async.h> 39 #include <sys/spl.h> 40 #include <sys/sunddi.h> 41 #include <sys/machsystm.h> /* e_ddi_nodeid_to_dip() */ 42 #include <sys/ddi_impldefs.h> 43 #include <sys/pci/pci_obj.h> 44 #include <sys/sdt.h> 45 #include <sys/clock.h> 46 47 /* 48 * interrupt jabber: 49 * 50 * When an interrupt line is jabbering, every time the state machine for the 51 * associated ino is idled, a new mondo will be sent and the ino will go into 52 * the pending state again. The mondo will cause a new call to 53 * pci_intr_wrapper() which normally idles the ino's state machine which would 54 * precipitate another trip round the loop. 55 * The loop can be broken by preventing the ino's state machine from being 56 * idled when an interrupt line is jabbering. See the comment at the 57 * beginning of pci_intr_wrapper() explaining how the 'interrupt jabber 58 * protection' code does this. 59 */ 60 61 /*LINTLIBRARY*/ 62 63 #ifdef NOT_DEFINED 64 /* 65 * This array is used to determine the sparc PIL at the which the 66 * handler for a given INO will execute. This table is for onboard 67 * devices only. A different scheme will be used for plug-in cards. 68 */ 69 70 uint_t ino_to_pil[] = { 71 72 /* pil */ /* ino */ 73 74 0, 0, 0, 0, /* 0x00 - 0x03: bus A slot 0 int#A, B, C, D */ 75 0, 0, 0, 0, /* 0x04 - 0x07: bus A slot 1 int#A, B, C, D */ 76 0, 0, 0, 0, /* 0x08 - 0x0B: unused */ 77 0, 0, 0, 0, /* 0x0C - 0x0F: unused */ 78 79 0, 0, 0, 0, /* 0x10 - 0x13: bus B slot 0 int#A, B, C, D */ 80 0, 0, 0, 0, /* 0x14 - 0x17: bus B slot 1 int#A, B, C, D */ 81 0, 0, 0, 0, /* 0x18 - 0x1B: bus B slot 2 int#A, B, C, D */ 82 4, 0, 0, 0, /* 0x1C - 0x1F: bus B slot 3 int#A, B, C, D */ 83 84 4, /* 0x20: SCSI */ 85 6, /* 0x21: ethernet */ 86 3, /* 0x22: parallel port */ 87 9, /* 0x23: audio record */ 88 9, /* 0x24: audio playback */ 89 14, /* 0x25: power fail */ 90 4, /* 0x26: 2nd SCSI */ 91 8, /* 0x27: floppy */ 92 14, /* 0x28: thermal warning */ 93 12, /* 0x29: keyboard */ 94 12, /* 0x2A: mouse */ 95 12, /* 0x2B: serial */ 96 0, /* 0x2C: timer/counter 0 */ 97 0, /* 0x2D: timer/counter 1 */ 98 14, /* 0x2E: uncorrectable ECC errors */ 99 14, /* 0x2F: correctable ECC errors */ 100 14, /* 0x30: PCI bus A error */ 101 14, /* 0x31: PCI bus B error */ 102 14, /* 0x32: power management wakeup */ 103 14, /* 0x33 */ 104 14, /* 0x34 */ 105 14, /* 0x35 */ 106 14, /* 0x36 */ 107 14, /* 0x37 */ 108 14, /* 0x38 */ 109 14, /* 0x39 */ 110 14, /* 0x3a */ 111 14, /* 0x3b */ 112 14, /* 0x3c */ 113 14, /* 0x3d */ 114 14, /* 0x3e */ 115 14, /* 0x3f */ 116 14 /* 0x40 */ 117 }; 118 #endif /* NOT_DEFINED */ 119 120 121 #define PCI_SIMBA_VENID 0x108e /* vendor id for simba */ 122 #define PCI_SIMBA_DEVID 0x5000 /* device id for simba */ 123 124 /* 125 * map_pcidev_cfg_reg - create mapping to pci device configuration registers 126 * if we have a simba AND a pci to pci bridge along the 127 * device path. 128 * Called with corresponding mutexes held!! 129 * 130 * XXX XXX XXX The purpose of this routine is to overcome a hardware 131 * defect in Sabre CPU and Simba bridge configuration 132 * which does not drain DMA write data stalled in 133 * PCI to PCI bridges (such as the DEC bridge) beyond 134 * Simba. This routine will setup the data structures 135 * to allow the pci_intr_wrapper to perform a manual 136 * drain data operation before passing the control to 137 * interrupt handlers of device drivers. 138 * return value: 139 * DDI_SUCCESS 140 * DDI_FAILURE if unable to create mapping 141 */ 142 static int 143 map_pcidev_cfg_reg(dev_info_t *dip, dev_info_t *rdip, ddi_acc_handle_t *hdl_p) 144 { 145 dev_info_t *cdip; 146 dev_info_t *pci_dip = NULL; 147 pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 148 int simba_found = 0, pci_bridge_found = 0; 149 150 for (cdip = rdip; cdip && cdip != dip; cdip = ddi_get_parent(cdip)) { 151 ddi_acc_handle_t config_handle; 152 uint32_t vendor_id = ddi_getprop(DDI_DEV_T_ANY, cdip, 153 DDI_PROP_DONTPASS, "vendor-id", 0xffff); 154 155 DEBUG4(DBG_A_INTX, pci_p->pci_dip, 156 "map dev cfg reg for %s%d: @%s%d\n", 157 ddi_driver_name(rdip), ddi_get_instance(rdip), 158 ddi_driver_name(cdip), ddi_get_instance(cdip)); 159 160 if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 161 "no-dma-interrupt-sync")) 162 continue; 163 164 /* continue to search up-stream if not a PCI device */ 165 if (vendor_id == 0xffff) 166 continue; 167 168 /* record the deepest pci device */ 169 if (!pci_dip) 170 pci_dip = cdip; 171 172 /* look for simba */ 173 if (vendor_id == PCI_SIMBA_VENID) { 174 uint32_t device_id = ddi_getprop(DDI_DEV_T_ANY, 175 cdip, DDI_PROP_DONTPASS, "device-id", -1); 176 if (device_id == PCI_SIMBA_DEVID) { 177 simba_found = 1; 178 DEBUG0(DBG_A_INTX, pci_p->pci_dip, 179 "\tFound simba\n"); 180 continue; /* do not check bridge if simba */ 181 } 182 } 183 184 /* look for pci to pci bridge */ 185 if (pci_config_setup(cdip, &config_handle) != DDI_SUCCESS) { 186 cmn_err(CE_WARN, 187 "%s%d: can't get brdg cfg space for %s%d\n", 188 ddi_driver_name(dip), ddi_get_instance(dip), 189 ddi_driver_name(cdip), ddi_get_instance(cdip)); 190 return (DDI_FAILURE); 191 } 192 if (pci_config_get8(config_handle, PCI_CONF_BASCLASS) 193 == PCI_CLASS_BRIDGE) { 194 DEBUG0(DBG_A_INTX, pci_p->pci_dip, 195 "\tFound PCI to xBus bridge\n"); 196 pci_bridge_found = 1; 197 } 198 pci_config_teardown(&config_handle); 199 } 200 201 if (!pci_bridge_found) 202 return (DDI_SUCCESS); 203 if (!simba_found && (CHIP_TYPE(pci_p) < PCI_CHIP_SCHIZO)) 204 return (DDI_SUCCESS); 205 if (pci_config_setup(pci_dip, hdl_p) != DDI_SUCCESS) { 206 cmn_err(CE_WARN, "%s%d: can not get config space for %s%d\n", 207 ddi_driver_name(dip), ddi_get_instance(dip), 208 ddi_driver_name(cdip), ddi_get_instance(cdip)); 209 return (DDI_FAILURE); 210 } 211 return (DDI_SUCCESS); 212 } 213 214 /* 215 * If the unclaimed interrupt count has reached the limit set by 216 * pci_unclaimed_intr_max within the time limit, then all interrupts 217 * on this ino is blocked by not idling the interrupt state machine. 218 */ 219 static int 220 pci_spurintr(ib_ino_pil_t *ipil_p) { 221 ib_ino_info_t *ino_p = ipil_p->ipil_ino_p; 222 ih_t *ih_p = ipil_p->ipil_ih_start; 223 pci_t *pci_p = ino_p->ino_ib_p->ib_pci_p; 224 char *err_fmt_str; 225 boolean_t blocked = B_FALSE; 226 int i; 227 228 if (ino_p->ino_unclaimed_intrs > pci_unclaimed_intr_max) 229 return (DDI_INTR_CLAIMED); 230 231 if (!ino_p->ino_unclaimed_intrs) 232 ino_p->ino_spurintr_begin = ddi_get_lbolt(); 233 234 ino_p->ino_unclaimed_intrs++; 235 236 if (ino_p->ino_unclaimed_intrs <= pci_unclaimed_intr_max) 237 goto clear; 238 239 if (drv_hztousec(ddi_get_lbolt() - ino_p->ino_spurintr_begin) 240 > pci_spurintr_duration) { 241 ino_p->ino_unclaimed_intrs = 0; 242 goto clear; 243 } 244 err_fmt_str = "%s%d: ino 0x%x blocked"; 245 blocked = B_TRUE; 246 goto warn; 247 clear: 248 if (!pci_spurintr_msgs) { /* tomatillo errata #71 spurious mondo */ 249 /* clear the pending state */ 250 IB_INO_INTR_CLEAR(ino_p->ino_clr_reg); 251 return (DDI_INTR_CLAIMED); 252 } 253 254 err_fmt_str = "!%s%d: spurious interrupt from ino 0x%x"; 255 warn: 256 cmn_err(CE_WARN, err_fmt_str, NAMEINST(pci_p->pci_dip), ino_p->ino_ino); 257 for (i = 0; i < ipil_p->ipil_ih_size; i++, ih_p = ih_p->ih_next) 258 cmn_err(CE_CONT, "!%s-%d#%x ", NAMEINST(ih_p->ih_dip), 259 ih_p->ih_inum); 260 cmn_err(CE_CONT, "!\n"); 261 if (blocked == B_FALSE) /* clear the pending state */ 262 IB_INO_INTR_CLEAR(ino_p->ino_clr_reg); 263 264 return (DDI_INTR_CLAIMED); 265 } 266 267 /* 268 * pci_intr_wrapper 269 * 270 * This routine is used as wrapper around interrupt handlers installed by child 271 * device drivers. This routine invokes the driver interrupt handlers and 272 * examines the return codes. 273 * There is a count of unclaimed interrupts kept on a per-ino basis. If at 274 * least one handler claims the interrupt then the counter is halved and the 275 * interrupt state machine is idled. If no handler claims the interrupt then 276 * the counter is incremented by one and the state machine is idled. 277 * If the count ever reaches the limit value set by pci_unclaimed_intr_max 278 * then the interrupt state machine is not idled thus preventing any further 279 * interrupts on that ino. The state machine will only be idled again if a 280 * handler is subsequently added or removed. 281 * 282 * return value: DDI_INTR_CLAIMED if any handlers claimed the interrupt, 283 * DDI_INTR_UNCLAIMED otherwise. 284 */ 285 286 extern uint64_t intr_get_time(void); 287 288 uint_t 289 pci_intr_wrapper(caddr_t arg) 290 { 291 ib_ino_pil_t *ipil_p = (ib_ino_pil_t *)arg; 292 ib_ino_info_t *ino_p = ipil_p->ipil_ino_p; 293 uint_t result = 0, r = DDI_INTR_UNCLAIMED; 294 pci_t *pci_p = ino_p->ino_ib_p->ib_pci_p; 295 pbm_t *pbm_p = pci_p->pci_pbm_p; 296 ih_t *ih_p = ipil_p->ipil_ih_start; 297 int i; 298 299 for (i = 0; i < ipil_p->ipil_ih_size; i++, ih_p = ih_p->ih_next) { 300 dev_info_t *dip = ih_p->ih_dip; 301 uint_t (*handler)() = ih_p->ih_handler; 302 caddr_t arg1 = ih_p->ih_handler_arg1; 303 caddr_t arg2 = ih_p->ih_handler_arg2; 304 ddi_acc_handle_t cfg_hdl = ih_p->ih_config_handle; 305 306 if (pci_intr_dma_sync && cfg_hdl && pbm_p->pbm_sync_reg_pa) { 307 (void) pci_config_get16(cfg_hdl, PCI_CONF_VENID); 308 pci_pbm_dma_sync(pbm_p, ino_p->ino_ino); 309 } 310 311 if (ih_p->ih_intr_state == PCI_INTR_STATE_DISABLE) { 312 DEBUG3(DBG_INTR, pci_p->pci_dip, 313 "pci_intr_wrapper: %s%d interrupt %d is disabled\n", 314 ddi_driver_name(dip), ddi_get_instance(dip), 315 ino_p->ino_ino); 316 317 continue; 318 } 319 320 DTRACE_PROBE4(interrupt__start, dev_info_t, dip, 321 void *, handler, caddr_t, arg1, caddr_t, arg2); 322 323 r = (*handler)(arg1, arg2); 324 325 /* 326 * Account for time used by this interrupt. Protect against 327 * conflicting writes to ih_ticks from ib_intr_dist_all() by 328 * using atomic ops. 329 */ 330 331 if (ipil_p->ipil_pil <= LOCK_LEVEL) 332 atomic_add_64(&ih_p->ih_ticks, intr_get_time()); 333 334 DTRACE_PROBE4(interrupt__complete, dev_info_t, dip, 335 void *, handler, caddr_t, arg1, int, r); 336 337 result += r; 338 339 if (pci_check_all_handlers) 340 continue; 341 if (result) 342 break; 343 } 344 345 if (result) 346 ino_p->ino_claimed |= (1 << ipil_p->ipil_pil); 347 348 /* Interrupt can only be cleared after all pil levels are handled */ 349 if (ipil_p->ipil_pil != ino_p->ino_lopil) 350 return (DDI_INTR_CLAIMED); 351 352 if (!ino_p->ino_claimed) 353 return (pci_spurintr(ipil_p)); 354 355 ino_p->ino_unclaimed_intrs = 0; 356 ino_p->ino_claimed = 0; 357 358 /* Clear the pending state */ 359 IB_INO_INTR_CLEAR(ino_p->ino_clr_reg); 360 361 return (DDI_INTR_CLAIMED); 362 } 363 364 dev_info_t * 365 get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip) 366 { 367 dev_info_t *cdip = rdip; 368 369 for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip)) 370 ; 371 372 return (cdip); 373 } 374 375 static struct { 376 kstat_named_t pciintr_ks_name; 377 kstat_named_t pciintr_ks_type; 378 kstat_named_t pciintr_ks_cpu; 379 kstat_named_t pciintr_ks_pil; 380 kstat_named_t pciintr_ks_time; 381 kstat_named_t pciintr_ks_ino; 382 kstat_named_t pciintr_ks_cookie; 383 kstat_named_t pciintr_ks_devpath; 384 kstat_named_t pciintr_ks_buspath; 385 } pciintr_ks_template = { 386 { "name", KSTAT_DATA_CHAR }, 387 { "type", KSTAT_DATA_CHAR }, 388 { "cpu", KSTAT_DATA_UINT64 }, 389 { "pil", KSTAT_DATA_UINT64 }, 390 { "time", KSTAT_DATA_UINT64 }, 391 { "ino", KSTAT_DATA_UINT64 }, 392 { "cookie", KSTAT_DATA_UINT64 }, 393 { "devpath", KSTAT_DATA_STRING }, 394 { "buspath", KSTAT_DATA_STRING }, 395 }; 396 static uint32_t pciintr_ks_instance; 397 static char ih_devpath[MAXPATHLEN]; 398 static char ih_buspath[MAXPATHLEN]; 399 400 kmutex_t pciintr_ks_template_lock; 401 402 int 403 pci_ks_update(kstat_t *ksp, int rw) 404 { 405 ih_t *ih_p = ksp->ks_private; 406 int maxlen = sizeof (pciintr_ks_template.pciintr_ks_name.value.c); 407 ib_ino_pil_t *ipil_p = ih_p->ih_ipil_p; 408 ib_ino_info_t *ino_p = ipil_p->ipil_ino_p; 409 ib_t *ib_p = ino_p->ino_ib_p; 410 pci_t *pci_p = ib_p->ib_pci_p; 411 ib_ino_t ino; 412 413 ino = ino_p->ino_ino; 414 415 (void) snprintf(pciintr_ks_template.pciintr_ks_name.value.c, maxlen, 416 "%s%d", ddi_driver_name(ih_p->ih_dip), 417 ddi_get_instance(ih_p->ih_dip)); 418 419 (void) ddi_pathname(ih_p->ih_dip, ih_devpath); 420 (void) ddi_pathname(pci_p->pci_dip, ih_buspath); 421 kstat_named_setstr(&pciintr_ks_template.pciintr_ks_devpath, ih_devpath); 422 kstat_named_setstr(&pciintr_ks_template.pciintr_ks_buspath, ih_buspath); 423 424 if (ih_p->ih_intr_state == PCI_INTR_STATE_ENABLE) { 425 (void) strcpy(pciintr_ks_template.pciintr_ks_type.value.c, 426 "fixed"); 427 pciintr_ks_template.pciintr_ks_cpu.value.ui64 = 428 ino_p->ino_cpuid; 429 pciintr_ks_template.pciintr_ks_pil.value.ui64 = 430 ipil_p->ipil_pil; 431 pciintr_ks_template.pciintr_ks_time.value.ui64 = ih_p->ih_nsec + 432 (uint64_t)tick2ns((hrtime_t)ih_p->ih_ticks, 433 ino_p->ino_cpuid); 434 pciintr_ks_template.pciintr_ks_ino.value.ui64 = ino; 435 pciintr_ks_template.pciintr_ks_cookie.value.ui64 = 436 IB_INO_TO_MONDO(ib_p, ino); 437 } else { 438 (void) strcpy(pciintr_ks_template.pciintr_ks_type.value.c, 439 "disabled"); 440 pciintr_ks_template.pciintr_ks_cpu.value.ui64 = 0; 441 pciintr_ks_template.pciintr_ks_pil.value.ui64 = 0; 442 pciintr_ks_template.pciintr_ks_time.value.ui64 = 0; 443 pciintr_ks_template.pciintr_ks_ino.value.ui64 = 0; 444 pciintr_ks_template.pciintr_ks_cookie.value.ui64 = 0; 445 } 446 447 return (0); 448 } 449 450 int 451 pci_add_intr(dev_info_t *dip, dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp) 452 { 453 pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 454 ib_t *ib_p = pci_p->pci_ib_p; 455 cb_t *cb_p = pci_p->pci_cb_p; 456 ih_t *ih_p; 457 ib_ino_t ino; 458 ib_ino_info_t *ino_p; /* pulse interrupts have no ino */ 459 ib_ino_pil_t *ipil_p, *ipil_list; 460 ib_mondo_t mondo; 461 uint32_t cpu_id; 462 int ret; 463 int32_t weight; 464 465 ino = IB_MONDO_TO_INO(hdlp->ih_vector); 466 467 DEBUG3(DBG_A_INTX, dip, "pci_add_intr: rdip=%s%d ino=%x\n", 468 ddi_driver_name(rdip), ddi_get_instance(rdip), ino); 469 470 if (ino > ib_p->ib_max_ino) { 471 DEBUG1(DBG_A_INTX, dip, "ino %x is invalid\n", ino); 472 return (DDI_INTR_NOTFOUND); 473 } 474 475 if (hdlp->ih_vector & PCI_PULSE_INO) { 476 volatile uint64_t *map_reg_addr; 477 map_reg_addr = ib_intr_map_reg_addr(ib_p, ino); 478 479 mondo = pci_xlate_intr(dip, rdip, ib_p, ino); 480 if (mondo == 0) 481 goto fail1; 482 483 hdlp->ih_vector = CB_MONDO_TO_XMONDO(cb_p, mondo); 484 485 if (i_ddi_add_ivintr(hdlp) != DDI_SUCCESS) 486 goto fail1; 487 488 /* 489 * Select cpu and program. 490 * 491 * Since there is no good way to always derive cpuid in 492 * pci_remove_intr for PCI_PULSE_INO (esp. for STARFIRE), we 493 * don't add (or remove) device weight for pulsed interrupt 494 * sources. 495 */ 496 mutex_enter(&ib_p->ib_intr_lock); 497 cpu_id = intr_dist_cpuid(); 498 *map_reg_addr = ib_get_map_reg(mondo, cpu_id); 499 mutex_exit(&ib_p->ib_intr_lock); 500 *map_reg_addr; /* flush previous write */ 501 goto done; 502 } 503 504 if ((mondo = pci_xlate_intr(dip, rdip, pci_p->pci_ib_p, ino)) == 0) 505 goto fail1; 506 507 ino = IB_MONDO_TO_INO(mondo); 508 509 mutex_enter(&ib_p->ib_ino_lst_mutex); 510 ih_p = ib_alloc_ih(rdip, hdlp->ih_inum, 511 hdlp->ih_cb_func, hdlp->ih_cb_arg1, hdlp->ih_cb_arg2); 512 if (map_pcidev_cfg_reg(dip, rdip, &ih_p->ih_config_handle)) 513 goto fail2; 514 515 ino_p = ib_locate_ino(ib_p, ino); 516 ipil_list = ino_p ? ino_p->ino_ipil_p:NULL; 517 518 /* Sharing ino */ 519 if (ino_p && (ipil_p = ib_ino_locate_ipil(ino_p, hdlp->ih_pri))) { 520 if (ib_intr_locate_ih(ipil_p, rdip, hdlp->ih_inum)) { 521 DEBUG1(DBG_A_INTX, dip, "dup intr #%d\n", 522 hdlp->ih_inum); 523 goto fail3; 524 } 525 526 /* add weight to the cpu that we are already targeting */ 527 cpu_id = ino_p->ino_cpuid; 528 weight = pci_class_to_intr_weight(rdip); 529 intr_dist_cpuid_add_device_weight(cpu_id, rdip, weight); 530 531 ib_ino_add_intr(pci_p, ipil_p, ih_p); 532 goto ino_done; 533 } 534 535 if (hdlp->ih_pri == 0) 536 hdlp->ih_pri = pci_class_to_pil(rdip); 537 538 ipil_p = ib_new_ino_pil(ib_p, ino, hdlp->ih_pri, ih_p); 539 ino_p = ipil_p->ipil_ino_p; 540 541 hdlp->ih_vector = CB_MONDO_TO_XMONDO(cb_p, mondo); 542 543 /* Store this global mondo */ 544 ino_p->ino_mondo = hdlp->ih_vector; 545 546 DEBUG2(DBG_A_INTX, dip, "pci_add_intr: pil=0x%x mondo=0x%x\n", 547 hdlp->ih_pri, hdlp->ih_vector); 548 549 DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, 550 (ddi_intr_handler_t *)pci_intr_wrapper, (caddr_t)ipil_p, NULL); 551 552 ret = i_ddi_add_ivintr(hdlp); 553 554 /* 555 * Restore original interrupt handler 556 * and arguments in interrupt handle. 557 */ 558 DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_handler, 559 ih_p->ih_handler_arg1, ih_p->ih_handler_arg2); 560 561 if (ret != DDI_SUCCESS) 562 goto fail4; 563 564 /* Save the pil for this ino */ 565 ipil_p->ipil_pil = hdlp->ih_pri; 566 567 /* clear and enable interrupt */ 568 IB_INO_INTR_CLEAR(ino_p->ino_clr_reg); 569 570 /* 571 * Select cpu and compute weight, saving both for sharing and removal. 572 */ 573 if (ipil_list == NULL) 574 ino_p->ino_cpuid = pci_intr_dist_cpuid(ib_p, ino_p); 575 576 cpu_id = ino_p->ino_cpuid; 577 ino_p->ino_established = 1; 578 weight = pci_class_to_intr_weight(rdip); 579 intr_dist_cpuid_add_device_weight(cpu_id, rdip, weight); 580 581 if (!ipil_list) { 582 *ino_p->ino_map_reg = ib_get_map_reg(mondo, cpu_id); 583 *ino_p->ino_map_reg; 584 } 585 ino_done: 586 hdlp->ih_target = ino_p->ino_cpuid; 587 ih_p->ih_ipil_p = ipil_p; 588 ih_p->ih_ksp = kstat_create("pci_intrs", 589 atomic_inc_32_nv(&pciintr_ks_instance), "config", "interrupts", 590 KSTAT_TYPE_NAMED, 591 sizeof (pciintr_ks_template) / sizeof (kstat_named_t), 592 KSTAT_FLAG_VIRTUAL); 593 if (ih_p->ih_ksp != NULL) { 594 ih_p->ih_ksp->ks_data_size += MAXPATHLEN * 2; 595 ih_p->ih_ksp->ks_lock = &pciintr_ks_template_lock; 596 ih_p->ih_ksp->ks_data = &pciintr_ks_template; 597 ih_p->ih_ksp->ks_private = ih_p; 598 ih_p->ih_ksp->ks_update = pci_ks_update; 599 kstat_install(ih_p->ih_ksp); 600 } 601 ib_ino_map_reg_share(ib_p, ino, ino_p); 602 mutex_exit(&ib_p->ib_ino_lst_mutex); 603 done: 604 DEBUG2(DBG_A_INTX, dip, "done! Interrupt 0x%x pil=%x\n", 605 hdlp->ih_vector, hdlp->ih_pri); 606 return (DDI_SUCCESS); 607 fail4: 608 ib_delete_ino_pil(ib_p, ipil_p); 609 fail3: 610 if (ih_p->ih_config_handle) 611 pci_config_teardown(&ih_p->ih_config_handle); 612 fail2: 613 mutex_exit(&ib_p->ib_ino_lst_mutex); 614 kmem_free(ih_p, sizeof (ih_t)); 615 fail1: 616 DEBUG2(DBG_A_INTX, dip, "Failed! Interrupt 0x%x pil=%x\n", 617 hdlp->ih_vector, hdlp->ih_pri); 618 return (DDI_FAILURE); 619 } 620 621 int 622 pci_remove_intr(dev_info_t *dip, dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp) 623 { 624 pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 625 ib_t *ib_p = pci_p->pci_ib_p; 626 cb_t *cb_p = pci_p->pci_cb_p; 627 ib_ino_t ino; 628 ib_mondo_t mondo; 629 ib_ino_info_t *ino_p; /* non-pulse only */ 630 ib_ino_pil_t *ipil_p; /* non-pulse only */ 631 ih_t *ih_p; /* non-pulse only */ 632 633 ino = IB_MONDO_TO_INO(hdlp->ih_vector); 634 635 DEBUG3(DBG_R_INTX, dip, "pci_rem_intr: rdip=%s%d ino=%x\n", 636 ddi_driver_name(rdip), ddi_get_instance(rdip), ino); 637 638 if (hdlp->ih_vector & PCI_PULSE_INO) { /* pulse interrupt */ 639 volatile uint64_t *map_reg_addr; 640 641 /* 642 * No weight was added by pci_add_intr for PCI_PULSE_INO 643 * because it is difficult to determine cpuid here. 644 */ 645 map_reg_addr = ib_intr_map_reg_addr(ib_p, ino); 646 IB_INO_INTR_RESET(map_reg_addr); /* disable intr */ 647 *map_reg_addr; 648 649 mondo = pci_xlate_intr(dip, rdip, ib_p, ino); 650 if (mondo == 0) { 651 DEBUG1(DBG_R_INTX, dip, 652 "can't get mondo for ino %x\n", ino); 653 return (DDI_FAILURE); 654 } 655 656 if (hdlp->ih_pri == 0) 657 hdlp->ih_pri = pci_class_to_pil(rdip); 658 659 hdlp->ih_vector = CB_MONDO_TO_XMONDO(cb_p, mondo); 660 661 DEBUG2(DBG_R_INTX, dip, "pci_rem_intr: pil=0x%x mondo=0x%x\n", 662 hdlp->ih_pri, hdlp->ih_vector); 663 664 i_ddi_rem_ivintr(hdlp); 665 666 DEBUG2(DBG_R_INTX, dip, "pulse success mondo=%x reg=%p\n", 667 mondo, map_reg_addr); 668 return (DDI_SUCCESS); 669 } 670 671 /* Translate the interrupt property */ 672 mondo = pci_xlate_intr(dip, rdip, pci_p->pci_ib_p, ino); 673 if (mondo == 0) { 674 DEBUG1(DBG_R_INTX, dip, "can't get mondo for ino %x\n", ino); 675 return (DDI_FAILURE); 676 } 677 ino = IB_MONDO_TO_INO(mondo); 678 679 mutex_enter(&ib_p->ib_ino_lst_mutex); 680 ino_p = ib_locate_ino(ib_p, ino); 681 if (!ino_p) { 682 int r = cb_remove_xintr(pci_p, dip, rdip, ino, mondo); 683 if (r != DDI_SUCCESS) 684 cmn_err(CE_WARN, "%s%d-xintr: ino %x is invalid", 685 ddi_driver_name(dip), ddi_get_instance(dip), ino); 686 mutex_exit(&ib_p->ib_ino_lst_mutex); 687 return (r); 688 } 689 690 ipil_p = ib_ino_locate_ipil(ino_p, hdlp->ih_pri); 691 ih_p = ib_intr_locate_ih(ipil_p, rdip, hdlp->ih_inum); 692 ib_ino_rem_intr(pci_p, ipil_p, ih_p); 693 intr_dist_cpuid_rem_device_weight(ino_p->ino_cpuid, rdip); 694 if (ipil_p->ipil_ih_size == 0) { 695 IB_INO_INTR_PEND(ib_clear_intr_reg_addr(ib_p, ino)); 696 hdlp->ih_vector = CB_MONDO_TO_XMONDO(cb_p, mondo); 697 698 i_ddi_rem_ivintr(hdlp); 699 ib_delete_ino_pil(ib_p, ipil_p); 700 } 701 702 /* re-enable interrupt only if mapping register still shared */ 703 if (ib_ino_map_reg_unshare(ib_p, ino, ino_p) || ino_p->ino_ipil_size) { 704 IB_INO_INTR_ON(ino_p->ino_map_reg); 705 *ino_p->ino_map_reg; 706 } 707 mutex_exit(&ib_p->ib_ino_lst_mutex); 708 709 if (ino_p->ino_ipil_size == 0) 710 kmem_free(ino_p, sizeof (ib_ino_info_t)); 711 712 DEBUG1(DBG_R_INTX, dip, "success! mondo=%x\n", mondo); 713 return (DDI_SUCCESS); 714 } 715 716 /* 717 * free the pci_inos array allocated during pci_intr_setup. the actual 718 * interrupts are torn down by their respective block destroy routines: 719 * cb_destroy, pbm_destroy, and ib_destroy. 720 */ 721 void 722 pci_intr_teardown(pci_t *pci_p) 723 { 724 kmem_free(pci_p->pci_inos, pci_p->pci_inos_len); 725 pci_p->pci_inos = NULL; 726 pci_p->pci_inos_len = 0; 727 } 728