1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * PX nexus interrupt handling: 30 * PX device interrupt handler wrapper 31 * PIL lookup routine 32 * PX device interrupt related initchild code 33 */ 34 35 #include <sys/types.h> 36 #include <sys/kmem.h> 37 #include <sys/async.h> 38 #include <sys/spl.h> 39 #include <sys/sunddi.h> 40 #include <sys/fm/protocol.h> 41 #include <sys/fm/util.h> 42 #include <sys/machsystm.h> /* e_ddi_nodeid_to_dip() */ 43 #include <sys/ddi_impldefs.h> 44 #include <sys/sdt.h> 45 #include <sys/atomic.h> 46 #include "px_obj.h" 47 #include <sys/ontrap.h> 48 #include <sys/membar.h> 49 #include <sys/clock.h> 50 51 /* 52 * interrupt jabber: 53 * 54 * When an interrupt line is jabbering, every time the state machine for the 55 * associated ino is idled, a new mondo will be sent and the ino will go into 56 * the pending state again. The mondo will cause a new call to 57 * px_intr_wrapper() which normally idles the ino's state machine which would 58 * precipitate another trip round the loop. 59 * 60 * The loop can be broken by preventing the ino's state machine from being 61 * idled when an interrupt line is jabbering. See the comment at the 62 * beginning of px_intr_wrapper() explaining how the 'interrupt jabber 63 * protection' code does this. 64 */ 65 66 /*LINTLIBRARY*/ 67 68 /* 69 * If the unclaimed interrupt count has reached the limit set by 70 * pci_unclaimed_intr_max within the time limit, then all interrupts 71 * on this ino is blocked by not idling the interrupt state machine. 72 */ 73 static int 74 px_spurintr(px_ino_pil_t *ipil_p) 75 { 76 px_ino_t *ino_p = ipil_p->ipil_ino_p; 77 px_ih_t *ih_p = ipil_p->ipil_ih_start; 78 px_t *px_p = ino_p->ino_ib_p->ib_px_p; 79 char *err_fmt_str; 80 boolean_t blocked = B_FALSE; 81 int i; 82 83 if (ino_p->ino_unclaimed_intrs > px_unclaimed_intr_max) 84 return (DDI_INTR_CLAIMED); 85 86 if (!ino_p->ino_unclaimed_intrs) 87 ino_p->ino_spurintr_begin = ddi_get_lbolt(); 88 89 ino_p->ino_unclaimed_intrs++; 90 91 if (ino_p->ino_unclaimed_intrs <= px_unclaimed_intr_max) 92 goto clear; 93 94 if (drv_hztousec(ddi_get_lbolt() - ino_p->ino_spurintr_begin) 95 > px_spurintr_duration) { 96 ino_p->ino_unclaimed_intrs = 0; 97 goto clear; 98 } 99 err_fmt_str = "%s%d: ino 0x%x blocked"; 100 blocked = B_TRUE; 101 goto warn; 102 clear: 103 err_fmt_str = "!%s%d: spurious interrupt from ino 0x%x"; 104 warn: 105 cmn_err(CE_WARN, err_fmt_str, NAMEINST(px_p->px_dip), ino_p->ino_ino); 106 for (i = 0; i < ipil_p->ipil_ih_size; i++, ih_p = ih_p->ih_next) 107 cmn_err(CE_CONT, "!%s-%d#%x ", NAMEINST(ih_p->ih_dip), 108 ih_p->ih_inum); 109 cmn_err(CE_CONT, "!\n"); 110 111 /* Clear the pending state */ 112 if (blocked == B_FALSE) { 113 if (px_lib_intr_setstate(px_p->px_dip, ino_p->ino_sysino, 114 INTR_IDLE_STATE) != DDI_SUCCESS) 115 return (DDI_INTR_UNCLAIMED); 116 } 117 118 return (DDI_INTR_CLAIMED); 119 } 120 121 extern uint64_t intr_get_time(void); 122 123 /* 124 * px_intx_intr (INTx or legacy interrupt handler) 125 * 126 * This routine is used as wrapper around interrupt handlers installed by child 127 * device drivers. This routine invokes the driver interrupt handlers and 128 * examines the return codes. 129 * 130 * There is a count of unclaimed interrupts kept on a per-ino basis. If at 131 * least one handler claims the interrupt then the counter is halved and the 132 * interrupt state machine is idled. If no handler claims the interrupt then 133 * the counter is incremented by one and the state machine is idled. 134 * If the count ever reaches the limit value set by pci_unclaimed_intr_max 135 * then the interrupt state machine is not idled thus preventing any further 136 * interrupts on that ino. The state machine will only be idled again if a 137 * handler is subsequently added or removed. 138 * 139 * return value: DDI_INTR_CLAIMED if any handlers claimed the interrupt, 140 * DDI_INTR_UNCLAIMED otherwise. 141 */ 142 uint_t 143 px_intx_intr(caddr_t arg) 144 { 145 px_ino_pil_t *ipil_p = (px_ino_pil_t *)arg; 146 px_ino_t *ino_p = ipil_p->ipil_ino_p; 147 px_t *px_p = ino_p->ino_ib_p->ib_px_p; 148 px_ih_t *ih_p = ipil_p->ipil_ih_start; 149 ushort_t pil = ipil_p->ipil_pil; 150 uint_t result = 0, r = DDI_INTR_UNCLAIMED; 151 int i; 152 153 DBG(DBG_INTX_INTR, px_p->px_dip, "px_intx_intr:" 154 "ino=%x sysino=%llx pil=%x ih_size=%x ih_lst=%x\n", 155 ino_p->ino_ino, ino_p->ino_sysino, ipil_p->ipil_pil, 156 ipil_p->ipil_ih_size, ipil_p->ipil_ih_head); 157 158 for (i = 0; i < ipil_p->ipil_ih_size; i++, ih_p = ih_p->ih_next) { 159 dev_info_t *dip = ih_p->ih_dip; 160 uint_t (*handler)() = ih_p->ih_handler; 161 caddr_t arg1 = ih_p->ih_handler_arg1; 162 caddr_t arg2 = ih_p->ih_handler_arg2; 163 164 if (ih_p->ih_intr_state == PX_INTR_STATE_DISABLE) { 165 DBG(DBG_INTX_INTR, px_p->px_dip, 166 "px_intx_intr: %s%d interrupt %d is disabled\n", 167 ddi_driver_name(dip), ddi_get_instance(dip), 168 ino_p->ino_ino); 169 170 continue; 171 } 172 173 DBG(DBG_INTX_INTR, px_p->px_dip, "px_intx_intr:" 174 "ino=%x handler=%p arg1 =%p arg2 = %p\n", 175 ino_p->ino_ino, handler, arg1, arg2); 176 177 DTRACE_PROBE4(interrupt__start, dev_info_t, dip, 178 void *, handler, caddr_t, arg1, caddr_t, arg2); 179 180 r = (*handler)(arg1, arg2); 181 182 /* 183 * Account for time used by this interrupt. Protect against 184 * conflicting writes to ih_ticks from ib_intr_dist_all() by 185 * using atomic ops. 186 */ 187 188 if (pil <= LOCK_LEVEL) 189 atomic_add_64(&ih_p->ih_ticks, intr_get_time()); 190 191 DTRACE_PROBE4(interrupt__complete, dev_info_t, dip, 192 void *, handler, caddr_t, arg1, int, r); 193 194 result += r; 195 196 if (px_check_all_handlers) 197 continue; 198 if (result) 199 break; 200 } 201 202 if (result) 203 ino_p->ino_claimed |= (1 << pil); 204 205 /* Interrupt can only be cleared after all pil levels are handled */ 206 if (pil != ino_p->ino_lopil) 207 return (DDI_INTR_CLAIMED); 208 209 if (!ino_p->ino_claimed) { 210 if (px_unclaimed_intr_block) 211 return (px_spurintr(ipil_p)); 212 } 213 214 ino_p->ino_unclaimed_intrs = 0; 215 ino_p->ino_claimed = 0; 216 217 /* Clear the pending state */ 218 if (px_lib_intr_setstate(px_p->px_dip, 219 ino_p->ino_sysino, INTR_IDLE_STATE) != DDI_SUCCESS) 220 return (DDI_INTR_UNCLAIMED); 221 222 return (DDI_INTR_CLAIMED); 223 } 224 225 /* 226 * px_msiq_intr (MSI/X or PCIe MSG interrupt handler) 227 * 228 * This routine is used as wrapper around interrupt handlers installed by child 229 * device drivers. This routine invokes the driver interrupt handlers and 230 * examines the return codes. 231 * 232 * There is a count of unclaimed interrupts kept on a per-ino basis. If at 233 * least one handler claims the interrupt then the counter is halved and the 234 * interrupt state machine is idled. If no handler claims the interrupt then 235 * the counter is incremented by one and the state machine is idled. 236 * If the count ever reaches the limit value set by pci_unclaimed_intr_max 237 * then the interrupt state machine is not idled thus preventing any further 238 * interrupts on that ino. The state machine will only be idled again if a 239 * handler is subsequently added or removed. 240 * 241 * return value: DDI_INTR_CLAIMED if any handlers claimed the interrupt, 242 * DDI_INTR_UNCLAIMED otherwise. 243 */ 244 uint_t 245 px_msiq_intr(caddr_t arg) 246 { 247 px_ino_pil_t *ipil_p = (px_ino_pil_t *)arg; 248 px_ino_t *ino_p = ipil_p->ipil_ino_p; 249 px_t *px_p = ino_p->ino_ib_p->ib_px_p; 250 px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 251 px_msiq_t *msiq_p = ino_p->ino_msiq_p; 252 dev_info_t *dip = px_p->px_dip; 253 ushort_t pil = ipil_p->ipil_pil; 254 msiq_rec_t msiq_rec, *msiq_rec_p = &msiq_rec; 255 msiqhead_t *curr_head_p; 256 msiqtail_t curr_tail_index; 257 msgcode_t msg_code; 258 px_ih_t *ih_p; 259 uint_t ret = DDI_INTR_UNCLAIMED; 260 int i, j; 261 262 DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: msiq_id =%x ino=%x pil=%x " 263 "ih_size=%x ih_lst=%x\n", msiq_p->msiq_id, ino_p->ino_ino, 264 ipil_p->ipil_pil, ipil_p->ipil_ih_size, ipil_p->ipil_ih_head); 265 266 /* 267 * The px_msiq_intr() handles multiple interrupt priorities and it 268 * will set msiq->msiq_rec2process to the number of MSIQ records to 269 * process while handling the highest priority interrupt. Subsequent 270 * lower priority interrupts will just process any unprocessed MSIQ 271 * records or will just return immediately. 272 */ 273 if (msiq_p->msiq_recs2process == 0) { 274 /* Read current MSIQ tail index */ 275 px_lib_msiq_gettail(dip, msiq_p->msiq_id, &curr_tail_index); 276 msiq_p->msiq_new_head_index = msiq_p->msiq_curr_head_index; 277 278 if (curr_tail_index < msiq_p->msiq_curr_head_index) 279 curr_tail_index += msiq_state_p->msiq_rec_cnt; 280 281 msiq_p->msiq_recs2process = curr_tail_index - 282 msiq_p->msiq_curr_head_index; 283 } 284 285 DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: curr_head %x new_head %x " 286 "rec2process %x\n", msiq_p->msiq_curr_head_index, 287 msiq_p->msiq_new_head_index, msiq_p->msiq_recs2process); 288 289 /* If all MSIQ records are already processed, just return immediately */ 290 if ((msiq_p->msiq_new_head_index - msiq_p->msiq_curr_head_index) 291 == msiq_p->msiq_recs2process) 292 goto intr_done; 293 294 curr_head_p = (msiqhead_t *)((caddr_t)msiq_p->msiq_base_p + 295 (msiq_p->msiq_curr_head_index * sizeof (msiq_rec_t))); 296 297 /* 298 * Calculate the number of recs to process by taking the difference 299 * between the head and tail pointers. For all records we always 300 * verify that we have a valid record type before we do any processing. 301 * If triggered, we should always have at least one valid record. 302 */ 303 for (i = 0; i < msiq_p->msiq_recs2process; i++) { 304 /* Read next MSIQ record */ 305 px_lib_get_msiq_rec(dip, curr_head_p, msiq_rec_p); 306 307 DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: MSIQ RECORD, " 308 "msiq_rec_type 0x%llx msiq_rec_rid 0x%llx\n", 309 msiq_rec_p->msiq_rec_type, msiq_rec_p->msiq_rec_rid); 310 311 if (!msiq_rec_p->msiq_rec_type) 312 goto next_rec; 313 314 /* Check MSIQ record type */ 315 switch (msiq_rec_p->msiq_rec_type) { 316 case MSG_REC: 317 msg_code = msiq_rec_p->msiq_rec_data.msg.msg_code; 318 DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: PCIE MSG " 319 "record, msg type 0x%x\n", msg_code); 320 break; 321 case MSI32_REC: 322 case MSI64_REC: 323 msg_code = msiq_rec_p->msiq_rec_data.msi.msi_data; 324 DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: MSI record, " 325 "msi 0x%x\n", msg_code); 326 327 /* Clear MSI state */ 328 px_lib_msi_setstate(dip, (msinum_t)msg_code, 329 PCI_MSI_STATE_IDLE); 330 break; 331 default: 332 msg_code = 0; 333 cmn_err(CE_WARN, "%s%d: px_msiq_intr: 0x%x MSIQ " 334 "record type is not supported", 335 ddi_driver_name(dip), ddi_get_instance(dip), 336 msiq_rec_p->msiq_rec_type); 337 338 goto next_rec; 339 } 340 341 /* 342 * Scan through px_ih_t linked list, searching for the 343 * right px_ih_t, matching MSIQ record data. 344 */ 345 for (j = 0, ih_p = ipil_p->ipil_ih_start; 346 ih_p && (j < ipil_p->ipil_ih_size) && 347 ((ih_p->ih_msg_code != msg_code) || 348 (ih_p->ih_rec_type != msiq_rec_p->msiq_rec_type)); 349 ih_p = ih_p->ih_next, j++); 350 351 if ((ih_p->ih_msg_code == msg_code) && 352 (ih_p->ih_rec_type == msiq_rec_p->msiq_rec_type)) { 353 dev_info_t *dip = ih_p->ih_dip; 354 uint_t (*handler)() = ih_p->ih_handler; 355 caddr_t arg1 = ih_p->ih_handler_arg1; 356 caddr_t arg2 = ih_p->ih_handler_arg2; 357 358 DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: ino=%x data=%x " 359 "handler=%p arg1 =%p arg2=%p\n", ino_p->ino_ino, 360 msg_code, handler, arg1, arg2); 361 362 DTRACE_PROBE4(interrupt__start, dev_info_t, dip, 363 void *, handler, caddr_t, arg1, caddr_t, arg2); 364 365 /* 366 * Special case for PCIE Error Messages. 367 * The current frame work doesn't fit PCIE Err Msgs 368 * This should be fixed when PCIE MESSAGES as a whole 369 * is architected correctly. 370 */ 371 if ((msg_code == PCIE_MSG_CODE_ERR_COR) || 372 (msg_code == PCIE_MSG_CODE_ERR_NONFATAL) || 373 (msg_code == PCIE_MSG_CODE_ERR_FATAL)) { 374 ret = px_err_fabric_intr(px_p, msg_code, 375 msiq_rec_p->msiq_rec_rid); 376 } else 377 ret = (*handler)(arg1, arg2); 378 379 /* 380 * Account for time used by this interrupt. Protect 381 * against conflicting writes to ih_ticks from 382 * ib_intr_dist_all() by using atomic ops. 383 */ 384 385 if (pil <= LOCK_LEVEL) 386 atomic_add_64(&ih_p->ih_ticks, intr_get_time()); 387 388 DTRACE_PROBE4(interrupt__complete, dev_info_t, dip, 389 void *, handler, caddr_t, arg1, int, ret); 390 391 msiq_p->msiq_new_head_index++; 392 px_lib_clr_msiq_rec(dip, curr_head_p); 393 } else { 394 DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr:" 395 "No matching MSIQ record found\n"); 396 } 397 next_rec: 398 /* Get the pointer next EQ record */ 399 curr_head_p = (msiqhead_t *) 400 ((caddr_t)curr_head_p + sizeof (msiq_rec_t)); 401 402 /* Check for overflow condition */ 403 if (curr_head_p >= (msiqhead_t *)((caddr_t)msiq_p->msiq_base_p 404 + (msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t)))) 405 curr_head_p = (msiqhead_t *)msiq_p->msiq_base_p; 406 } 407 408 DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: No of MSIQ recs processed %x\n", 409 (msiq_p->msiq_new_head_index - msiq_p->msiq_curr_head_index)); 410 411 DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: curr_head %x new_head %x " 412 "rec2process %x\n", msiq_p->msiq_curr_head_index, 413 msiq_p->msiq_new_head_index, msiq_p->msiq_recs2process); 414 415 /* ino_claimed used just for debugging purpose */ 416 if (ret) 417 ino_p->ino_claimed |= (1 << pil); 418 419 intr_done: 420 /* Interrupt can only be cleared after all pil levels are handled */ 421 if (pil != ino_p->ino_lopil) 422 return (DDI_INTR_CLAIMED); 423 424 if (msiq_p->msiq_new_head_index <= msiq_p->msiq_curr_head_index) { 425 if (px_unclaimed_intr_block) 426 return (px_spurintr(ipil_p)); 427 } 428 429 /* Update MSIQ head index with no of MSIQ records processed */ 430 if (msiq_p->msiq_new_head_index >= msiq_state_p->msiq_rec_cnt) 431 msiq_p->msiq_new_head_index -= msiq_state_p->msiq_rec_cnt; 432 433 msiq_p->msiq_curr_head_index = msiq_p->msiq_new_head_index; 434 px_lib_msiq_sethead(dip, msiq_p->msiq_id, msiq_p->msiq_new_head_index); 435 436 msiq_p->msiq_new_head_index = 0; 437 msiq_p->msiq_recs2process = 0; 438 ino_p->ino_claimed = 0; 439 440 /* Clear the pending state */ 441 if (px_lib_intr_setstate(dip, ino_p->ino_sysino, 442 INTR_IDLE_STATE) != DDI_SUCCESS) 443 return (DDI_INTR_UNCLAIMED); 444 445 return (DDI_INTR_CLAIMED); 446 } 447 448 dev_info_t * 449 px_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip) 450 { 451 dev_info_t *cdip = rdip; 452 453 for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip)) 454 ; 455 456 return (cdip); 457 } 458 459 /* Default class to pil value mapping */ 460 px_class_val_t px_default_pil [] = { 461 {0x000000, 0xff0000, 0x1}, /* Class code for pre-2.0 devices */ 462 {0x010000, 0xff0000, 0x4}, /* Mass Storage Controller */ 463 {0x020000, 0xff0000, 0x6}, /* Network Controller */ 464 {0x030000, 0xff0000, 0x9}, /* Display Controller */ 465 {0x040000, 0xff0000, 0x9}, /* Multimedia Controller */ 466 {0x050000, 0xff0000, 0x9}, /* Memory Controller */ 467 {0x060000, 0xff0000, 0x9}, /* Bridge Controller */ 468 {0x0c0000, 0xffff00, 0x9}, /* Serial Bus, FireWire (IEEE 1394) */ 469 {0x0c0100, 0xffff00, 0x4}, /* Serial Bus, ACCESS.bus */ 470 {0x0c0200, 0xffff00, 0x4}, /* Serial Bus, SSA */ 471 {0x0c0300, 0xffff00, 0x9}, /* Serial Bus Universal Serial Bus */ 472 {0x0c0400, 0xffff00, 0x6}, /* Serial Bus, Fibre Channel */ 473 {0x0c0600, 0xffff00, 0x6} /* Serial Bus, Infiniband */ 474 }; 475 476 /* 477 * Default class to intr_weight value mapping (% of CPU). A driver.conf 478 * entry on or above the pci node like 479 * 480 * pci-class-intr-weights= 0x020000, 0xff0000, 30; 481 * 482 * can be used to augment or override entries in the default table below. 483 * 484 * NB: The values below give NICs preference on redistribution, and provide 485 * NICs some isolation from other interrupt sources. We need better interfaces 486 * that allow the NIC driver to identify a specific NIC instance as high 487 * bandwidth, and thus deserving of separation from other low bandwidth 488 * NICs additional isolation from other interrupt sources. 489 * 490 * NB: We treat Infiniband like a NIC. 491 */ 492 px_class_val_t px_default_intr_weight [] = { 493 {0x020000, 0xff0000, 35}, /* Network Controller */ 494 {0x010000, 0xff0000, 10}, /* Mass Storage Controller */ 495 {0x0c0400, 0xffff00, 10}, /* Serial Bus, Fibre Channel */ 496 {0x0c0600, 0xffff00, 50} /* Serial Bus, Infiniband */ 497 }; 498 499 static uint32_t 500 px_match_class_val(uint32_t key, px_class_val_t *rec_p, int nrec, 501 uint32_t default_val) 502 { 503 int i; 504 505 for (i = 0; i < nrec; rec_p++, i++) { 506 if ((rec_p->class_code & rec_p->class_mask) == 507 (key & rec_p->class_mask)) 508 return (rec_p->class_val); 509 } 510 511 return (default_val); 512 } 513 514 /* 515 * px_class_to_val 516 * 517 * Return the configuration value, based on class code and sub class code, 518 * from the specified property based or default px_class_val_t table. 519 */ 520 uint32_t 521 px_class_to_val(dev_info_t *rdip, char *property_name, px_class_val_t *rec_p, 522 int nrec, uint32_t default_val) 523 { 524 int property_len; 525 uint32_t class_code; 526 px_class_val_t *conf; 527 uint32_t val = default_val; 528 529 /* 530 * Use the "class-code" property to get the base and sub class 531 * codes for the requesting device. 532 */ 533 class_code = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, rdip, 534 DDI_PROP_DONTPASS, "class-code", -1); 535 536 if (class_code == -1) 537 return (val); 538 539 /* look up the val from the default table */ 540 val = px_match_class_val(class_code, rec_p, nrec, val); 541 542 /* see if there is a more specific property specified value */ 543 if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_NOTPROM, 544 property_name, (caddr_t)&conf, &property_len)) 545 return (val); 546 547 if ((property_len % sizeof (px_class_val_t)) == 0) 548 val = px_match_class_val(class_code, conf, 549 property_len / sizeof (px_class_val_t), val); 550 kmem_free(conf, property_len); 551 return (val); 552 } 553 554 /* px_class_to_pil: return the pil for a given device. */ 555 uint32_t 556 px_class_to_pil(dev_info_t *rdip) 557 { 558 uint32_t pil; 559 560 /* Default pil is 1 */ 561 pil = px_class_to_val(rdip, 562 "pci-class-priorities", px_default_pil, 563 sizeof (px_default_pil) / sizeof (px_class_val_t), 1); 564 565 /* Range check the result */ 566 if (pil >= 0xf) 567 pil = 1; 568 569 return (pil); 570 } 571 572 /* px_class_to_intr_weight: return the intr_weight for a given device. */ 573 static int32_t 574 px_class_to_intr_weight(dev_info_t *rdip) 575 { 576 int32_t intr_weight; 577 578 /* default weight is 0% */ 579 intr_weight = px_class_to_val(rdip, 580 "pci-class-intr-weights", px_default_intr_weight, 581 sizeof (px_default_intr_weight) / sizeof (px_class_val_t), 0); 582 583 /* range check the result */ 584 if (intr_weight < 0) 585 intr_weight = 0; 586 if (intr_weight > 1000) 587 intr_weight = 1000; 588 589 return (intr_weight); 590 } 591 592 /* ARGSUSED */ 593 int 594 px_intx_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 595 ddi_intr_handle_impl_t *hdlp, void *result) 596 { 597 px_t *px_p = DIP_TO_STATE(dip); 598 int ret = DDI_SUCCESS; 599 600 DBG(DBG_INTROPS, dip, "px_intx_ops: dip=%x rdip=%x intr_op=%x " 601 "handle=%p\n", dip, rdip, intr_op, hdlp); 602 603 switch (intr_op) { 604 case DDI_INTROP_GETCAP: 605 ret = pci_intx_get_cap(rdip, (int *)result); 606 break; 607 case DDI_INTROP_SETCAP: 608 DBG(DBG_INTROPS, dip, "px_intx_ops: SetCap is not supported\n"); 609 ret = DDI_ENOTSUP; 610 break; 611 case DDI_INTROP_ALLOC: 612 *(int *)result = hdlp->ih_scratch1; 613 break; 614 case DDI_INTROP_FREE: 615 break; 616 case DDI_INTROP_GETPRI: 617 *(int *)result = hdlp->ih_pri ? 618 hdlp->ih_pri : px_class_to_pil(rdip); 619 break; 620 case DDI_INTROP_SETPRI: 621 break; 622 case DDI_INTROP_ADDISR: 623 ret = px_add_intx_intr(dip, rdip, hdlp); 624 break; 625 case DDI_INTROP_REMISR: 626 ret = px_rem_intx_intr(dip, rdip, hdlp); 627 break; 628 case DDI_INTROP_ENABLE: 629 ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum, 630 hdlp->ih_vector, hdlp->ih_pri, PX_INTR_STATE_ENABLE, 0, 0); 631 break; 632 case DDI_INTROP_DISABLE: 633 ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum, 634 hdlp->ih_vector, hdlp->ih_pri, PX_INTR_STATE_DISABLE, 0, 0); 635 break; 636 case DDI_INTROP_SETMASK: 637 ret = pci_intx_set_mask(rdip); 638 break; 639 case DDI_INTROP_CLRMASK: 640 ret = pci_intx_clr_mask(rdip); 641 break; 642 case DDI_INTROP_GETPENDING: 643 ret = pci_intx_get_pending(rdip, (int *)result); 644 break; 645 case DDI_INTROP_NINTRS: 646 case DDI_INTROP_NAVAIL: 647 *(int *)result = i_ddi_get_intx_nintrs(rdip); 648 break; 649 default: 650 ret = DDI_ENOTSUP; 651 break; 652 } 653 654 return (ret); 655 } 656 657 /* ARGSUSED */ 658 int 659 px_msix_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 660 ddi_intr_handle_impl_t *hdlp, void *result) 661 { 662 px_t *px_p = DIP_TO_STATE(dip); 663 px_msi_state_t *msi_state_p = &px_p->px_ib_p->ib_msi_state; 664 msiq_rec_type_t msiq_rec_type; 665 msi_type_t msi_type; 666 uint64_t msi_addr; 667 msinum_t msi_num; 668 msiqid_t msiq_id; 669 uint_t nintrs; 670 int i, ret = DDI_SUCCESS; 671 672 DBG(DBG_INTROPS, dip, "px_msix_ops: dip=%x rdip=%x intr_op=%x " 673 "handle=%p\n", dip, rdip, intr_op, hdlp); 674 675 /* Check for MSI64 support */ 676 if ((hdlp->ih_cap & DDI_INTR_FLAG_MSI64) && msi_state_p->msi_addr64) { 677 msiq_rec_type = MSI64_REC; 678 msi_type = MSI64_TYPE; 679 msi_addr = msi_state_p->msi_addr64; 680 } else { 681 msiq_rec_type = MSI32_REC; 682 msi_type = MSI32_TYPE; 683 msi_addr = msi_state_p->msi_addr32; 684 } 685 686 switch (intr_op) { 687 case DDI_INTROP_GETCAP: 688 ret = pci_msi_get_cap(rdip, hdlp->ih_type, (int *)result); 689 break; 690 case DDI_INTROP_SETCAP: 691 DBG(DBG_INTROPS, dip, "px_msix_ops: SetCap is not supported\n"); 692 ret = DDI_ENOTSUP; 693 break; 694 case DDI_INTROP_ALLOC: 695 /* 696 * We need to restrict this allocation in future 697 * based on Resource Management policies. 698 */ 699 if ((ret = px_msi_alloc(px_p, rdip, hdlp->ih_inum, 700 hdlp->ih_scratch1, (uintptr_t)hdlp->ih_scratch2, &msi_num, 701 (int *)result)) != DDI_SUCCESS) { 702 DBG(DBG_INTROPS, dip, "px_msix_ops: allocation " 703 "failed, rdip 0x%p type 0x%d inum 0x%x " 704 "count 0x%x\n", rdip, hdlp->ih_type, hdlp->ih_inum, 705 hdlp->ih_scratch1); 706 707 return (ret); 708 } 709 710 if ((hdlp->ih_type == DDI_INTR_TYPE_MSIX) && 711 (i_ddi_get_msix(rdip) == NULL)) { 712 ddi_intr_msix_t *msix_p; 713 714 if (msix_p = pci_msix_init(rdip)) { 715 i_ddi_set_msix(rdip, msix_p); 716 break; 717 } 718 719 DBG(DBG_INTROPS, dip, "px_msix_ops: MSI-X allocation " 720 "failed, rdip 0x%p inum 0x%x\n", rdip, 721 hdlp->ih_inum); 722 723 (void) px_msi_free(px_p, rdip, hdlp->ih_inum, 724 hdlp->ih_scratch1); 725 726 return (DDI_FAILURE); 727 } 728 729 break; 730 case DDI_INTROP_FREE: 731 (void) pci_msi_disable_mode(rdip, hdlp->ih_type, NULL); 732 (void) pci_msi_unconfigure(rdip, hdlp->ih_type, hdlp->ih_inum); 733 734 if (hdlp->ih_type == DDI_INTR_TYPE_MSI) 735 goto msi_free; 736 737 if (hdlp->ih_flags & DDI_INTR_MSIX_DUP) 738 break; 739 740 if (((i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1) == 0) && 741 (i_ddi_get_msix(rdip))) { 742 pci_msix_fini(i_ddi_get_msix(rdip)); 743 i_ddi_set_msix(rdip, NULL); 744 } 745 msi_free: 746 (void) px_msi_free(px_p, rdip, hdlp->ih_inum, 747 hdlp->ih_scratch1); 748 break; 749 case DDI_INTROP_GETPRI: 750 *(int *)result = hdlp->ih_pri ? 751 hdlp->ih_pri : px_class_to_pil(rdip); 752 break; 753 case DDI_INTROP_SETPRI: 754 break; 755 case DDI_INTROP_ADDISR: 756 if ((ret = px_msi_get_msinum(px_p, hdlp->ih_dip, 757 hdlp->ih_inum, &msi_num)) != DDI_SUCCESS) 758 return (ret); 759 760 if ((ret = px_add_msiq_intr(dip, rdip, hdlp, 761 msiq_rec_type, msi_num, &msiq_id)) != DDI_SUCCESS) { 762 DBG(DBG_INTROPS, dip, "px_msix_ops: Add MSI handler " 763 "failed, rdip 0x%p msi 0x%x\n", rdip, msi_num); 764 return (ret); 765 } 766 767 DBG(DBG_INTROPS, dip, "px_msix_ops: msiq used 0x%x\n", msiq_id); 768 769 if ((ret = px_lib_msi_setmsiq(dip, msi_num, 770 msiq_id, msi_type)) != DDI_SUCCESS) { 771 (void) px_rem_msiq_intr(dip, rdip, 772 hdlp, msiq_rec_type, msi_num, msiq_id); 773 return (ret); 774 } 775 776 if ((ret = px_lib_msi_setstate(dip, msi_num, 777 PCI_MSI_STATE_IDLE)) != DDI_SUCCESS) { 778 (void) px_rem_msiq_intr(dip, rdip, 779 hdlp, msiq_rec_type, msi_num, msiq_id); 780 return (ret); 781 } 782 783 hdlp->ih_vector = msi_num; 784 break; 785 case DDI_INTROP_DUPVEC: 786 DBG(DBG_INTROPS, dip, "px_msix_ops: dupisr - inum: %x, " 787 "new_vector: %x\n", hdlp->ih_inum, hdlp->ih_scratch1); 788 789 ret = pci_msix_dup(hdlp->ih_dip, hdlp->ih_inum, 790 hdlp->ih_scratch1); 791 break; 792 case DDI_INTROP_REMISR: 793 msi_num = hdlp->ih_vector; 794 795 if ((ret = px_lib_msi_getmsiq(dip, msi_num, 796 &msiq_id)) != DDI_SUCCESS) 797 return (ret); 798 799 if ((ret = px_lib_msi_setstate(dip, msi_num, 800 PCI_MSI_STATE_IDLE)) != DDI_SUCCESS) 801 return (ret); 802 803 ret = px_rem_msiq_intr(dip, rdip, 804 hdlp, msiq_rec_type, msi_num, msiq_id); 805 806 hdlp->ih_vector = 0; 807 break; 808 case DDI_INTROP_ENABLE: 809 msi_num = hdlp->ih_vector; 810 811 if ((ret = px_lib_msi_setvalid(dip, msi_num, 812 PCI_MSI_VALID)) != DDI_SUCCESS) 813 return (ret); 814 815 if ((pci_is_msi_enabled(rdip, hdlp->ih_type) != DDI_SUCCESS) || 816 (hdlp->ih_type == DDI_INTR_TYPE_MSIX)) { 817 nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip); 818 819 if ((ret = pci_msi_configure(rdip, hdlp->ih_type, 820 nintrs, hdlp->ih_inum, msi_addr, 821 hdlp->ih_type == DDI_INTR_TYPE_MSIX ? 822 msi_num : msi_num & ~(nintrs - 1))) != DDI_SUCCESS) 823 return (ret); 824 825 if ((ret = pci_msi_enable_mode(rdip, hdlp->ih_type)) 826 != DDI_SUCCESS) 827 return (ret); 828 } 829 830 if ((ret = pci_msi_clr_mask(rdip, hdlp->ih_type, 831 hdlp->ih_inum)) != DDI_SUCCESS) 832 return (ret); 833 834 if (hdlp->ih_flags & DDI_INTR_MSIX_DUP) 835 break; 836 837 if ((ret = px_lib_msi_getmsiq(dip, msi_num, 838 &msiq_id)) != DDI_SUCCESS) 839 return (ret); 840 841 ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum, 842 px_msiqid_to_devino(px_p, msiq_id), hdlp->ih_pri, 843 PX_INTR_STATE_ENABLE, msiq_rec_type, msi_num); 844 845 break; 846 case DDI_INTROP_DISABLE: 847 msi_num = hdlp->ih_vector; 848 849 if ((ret = pci_msi_set_mask(rdip, hdlp->ih_type, 850 hdlp->ih_inum)) != DDI_SUCCESS) 851 return (ret); 852 853 if ((ret = px_lib_msi_setvalid(dip, msi_num, 854 PCI_MSI_INVALID)) != DDI_SUCCESS) 855 return (ret); 856 857 if (hdlp->ih_flags & DDI_INTR_MSIX_DUP) 858 break; 859 860 if ((ret = px_lib_msi_getmsiq(dip, msi_num, 861 &msiq_id)) != DDI_SUCCESS) 862 return (ret); 863 864 ret = px_ib_update_intr_state(px_p, rdip, 865 hdlp->ih_inum, px_msiqid_to_devino(px_p, msiq_id), 866 hdlp->ih_pri, PX_INTR_STATE_DISABLE, msiq_rec_type, 867 msi_num); 868 869 break; 870 case DDI_INTROP_BLOCKENABLE: 871 nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip); 872 msi_num = hdlp->ih_vector; 873 874 if ((ret = pci_msi_configure(rdip, hdlp->ih_type, 875 nintrs, hdlp->ih_inum, msi_addr, 876 msi_num & ~(nintrs - 1))) != DDI_SUCCESS) 877 return (ret); 878 879 for (i = 0; i < nintrs; i++, msi_num++) { 880 if ((ret = px_lib_msi_setvalid(dip, msi_num, 881 PCI_MSI_VALID)) != DDI_SUCCESS) 882 return (ret); 883 884 if ((ret = px_lib_msi_getmsiq(dip, msi_num, 885 &msiq_id)) != DDI_SUCCESS) 886 return (ret); 887 888 if ((ret = px_ib_update_intr_state(px_p, rdip, 889 hdlp->ih_inum + i, px_msiqid_to_devino(px_p, 890 msiq_id), hdlp->ih_pri, PX_INTR_STATE_ENABLE, 891 msiq_rec_type, msi_num)) != DDI_SUCCESS) 892 return (ret); 893 } 894 895 ret = pci_msi_enable_mode(rdip, hdlp->ih_type); 896 break; 897 case DDI_INTROP_BLOCKDISABLE: 898 nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip); 899 msi_num = hdlp->ih_vector; 900 901 if ((ret = pci_msi_disable_mode(rdip, hdlp->ih_type, 902 hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) != DDI_SUCCESS) 903 return (ret); 904 905 for (i = 0; i < nintrs; i++, msi_num++) { 906 if ((ret = px_lib_msi_setvalid(dip, msi_num, 907 PCI_MSI_INVALID)) != DDI_SUCCESS) 908 return (ret); 909 910 if ((ret = px_lib_msi_getmsiq(dip, msi_num, 911 &msiq_id)) != DDI_SUCCESS) 912 return (ret); 913 914 if ((ret = px_ib_update_intr_state(px_p, rdip, 915 hdlp->ih_inum + i, px_msiqid_to_devino(px_p, 916 msiq_id), hdlp->ih_pri, PX_INTR_STATE_DISABLE, 917 msiq_rec_type, msi_num)) != DDI_SUCCESS) 918 return (ret); 919 } 920 921 break; 922 case DDI_INTROP_SETMASK: 923 ret = pci_msi_set_mask(rdip, hdlp->ih_type, hdlp->ih_inum); 924 break; 925 case DDI_INTROP_CLRMASK: 926 ret = pci_msi_clr_mask(rdip, hdlp->ih_type, hdlp->ih_inum); 927 break; 928 case DDI_INTROP_GETPENDING: 929 ret = pci_msi_get_pending(rdip, hdlp->ih_type, 930 hdlp->ih_inum, (int *)result); 931 break; 932 case DDI_INTROP_NINTRS: 933 ret = pci_msi_get_nintrs(rdip, hdlp->ih_type, (int *)result); 934 break; 935 case DDI_INTROP_NAVAIL: 936 /* XXX - a new interface may be needed */ 937 ret = pci_msi_get_nintrs(rdip, hdlp->ih_type, (int *)result); 938 break; 939 default: 940 ret = DDI_ENOTSUP; 941 break; 942 } 943 944 return (ret); 945 } 946 947 static struct { 948 kstat_named_t pxintr_ks_name; 949 kstat_named_t pxintr_ks_type; 950 kstat_named_t pxintr_ks_cpu; 951 kstat_named_t pxintr_ks_pil; 952 kstat_named_t pxintr_ks_time; 953 kstat_named_t pxintr_ks_ino; 954 kstat_named_t pxintr_ks_cookie; 955 kstat_named_t pxintr_ks_devpath; 956 kstat_named_t pxintr_ks_buspath; 957 } pxintr_ks_template = { 958 { "name", KSTAT_DATA_CHAR }, 959 { "type", KSTAT_DATA_CHAR }, 960 { "cpu", KSTAT_DATA_UINT64 }, 961 { "pil", KSTAT_DATA_UINT64 }, 962 { "time", KSTAT_DATA_UINT64 }, 963 { "ino", KSTAT_DATA_UINT64 }, 964 { "cookie", KSTAT_DATA_UINT64 }, 965 { "devpath", KSTAT_DATA_STRING }, 966 { "buspath", KSTAT_DATA_STRING }, 967 }; 968 969 static uint32_t pxintr_ks_instance; 970 static char ih_devpath[MAXPATHLEN]; 971 static char ih_buspath[MAXPATHLEN]; 972 kmutex_t pxintr_ks_template_lock; 973 974 int 975 px_ks_update(kstat_t *ksp, int rw) 976 { 977 px_ih_t *ih_p = ksp->ks_private; 978 int maxlen = sizeof (pxintr_ks_template.pxintr_ks_name.value.c); 979 px_ino_pil_t *ipil_p = ih_p->ih_ipil_p; 980 px_ino_t *ino_p = ipil_p->ipil_ino_p; 981 px_t *px_p = ino_p->ino_ib_p->ib_px_p; 982 devino_t ino; 983 sysino_t sysino; 984 985 ino = ino_p->ino_ino; 986 (void) px_lib_intr_devino_to_sysino(px_p->px_dip, ino, &sysino); 987 988 (void) snprintf(pxintr_ks_template.pxintr_ks_name.value.c, maxlen, 989 "%s%d", ddi_driver_name(ih_p->ih_dip), 990 ddi_get_instance(ih_p->ih_dip)); 991 992 (void) ddi_pathname(ih_p->ih_dip, ih_devpath); 993 (void) ddi_pathname(px_p->px_dip, ih_buspath); 994 kstat_named_setstr(&pxintr_ks_template.pxintr_ks_devpath, ih_devpath); 995 kstat_named_setstr(&pxintr_ks_template.pxintr_ks_buspath, ih_buspath); 996 997 if (ih_p->ih_intr_state == PX_INTR_STATE_ENABLE) { 998 999 (void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c, 1000 (ih_p->ih_rec_type == 0) ? "fixed" : "msi"); 1001 pxintr_ks_template.pxintr_ks_cpu.value.ui64 = ino_p->ino_cpuid; 1002 pxintr_ks_template.pxintr_ks_pil.value.ui64 = ipil_p->ipil_pil; 1003 pxintr_ks_template.pxintr_ks_time.value.ui64 = ih_p->ih_nsec + 1004 (uint64_t)tick2ns((hrtime_t)ih_p->ih_ticks, 1005 ino_p->ino_cpuid); 1006 pxintr_ks_template.pxintr_ks_ino.value.ui64 = ino; 1007 pxintr_ks_template.pxintr_ks_cookie.value.ui64 = sysino; 1008 } else { 1009 (void) strcpy(pxintr_ks_template.pxintr_ks_type.value.c, 1010 "disabled"); 1011 pxintr_ks_template.pxintr_ks_cpu.value.ui64 = 0; 1012 pxintr_ks_template.pxintr_ks_pil.value.ui64 = 0; 1013 pxintr_ks_template.pxintr_ks_time.value.ui64 = 0; 1014 pxintr_ks_template.pxintr_ks_ino.value.ui64 = 0; 1015 pxintr_ks_template.pxintr_ks_cookie.value.ui64 = 0; 1016 } 1017 return (0); 1018 } 1019 1020 void 1021 px_create_intr_kstats(px_ih_t *ih_p) 1022 { 1023 msiq_rec_type_t rec_type = ih_p->ih_rec_type; 1024 1025 ASSERT(ih_p->ih_ksp == NULL); 1026 1027 /* 1028 * Create pci_intrs::: kstats for all ih types except messages, 1029 * which represent unusual conditions and don't need to be tracked. 1030 */ 1031 if (rec_type == 0 || rec_type == MSI32_REC || rec_type == MSI64_REC) { 1032 ih_p->ih_ksp = kstat_create("pci_intrs", 1033 atomic_inc_32_nv(&pxintr_ks_instance), "config", 1034 "interrupts", KSTAT_TYPE_NAMED, 1035 sizeof (pxintr_ks_template) / sizeof (kstat_named_t), 1036 KSTAT_FLAG_VIRTUAL); 1037 } 1038 if (ih_p->ih_ksp != NULL) { 1039 ih_p->ih_ksp->ks_data_size += MAXPATHLEN * 2; 1040 ih_p->ih_ksp->ks_lock = &pxintr_ks_template_lock; 1041 ih_p->ih_ksp->ks_data = &pxintr_ks_template; 1042 ih_p->ih_ksp->ks_private = ih_p; 1043 ih_p->ih_ksp->ks_update = px_ks_update; 1044 } 1045 } 1046 1047 /* 1048 * px_add_intx_intr: 1049 * 1050 * This function is called to register INTx and legacy hardware 1051 * interrupt pins interrupts. 1052 */ 1053 int 1054 px_add_intx_intr(dev_info_t *dip, dev_info_t *rdip, 1055 ddi_intr_handle_impl_t *hdlp) 1056 { 1057 px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 1058 px_ib_t *ib_p = px_p->px_ib_p; 1059 devino_t ino; 1060 px_ih_t *ih_p; 1061 px_ino_t *ino_p; 1062 px_ino_pil_t *ipil_p, *ipil_list; 1063 int32_t weight; 1064 int ret = DDI_SUCCESS; 1065 1066 ino = hdlp->ih_vector; 1067 1068 DBG(DBG_A_INTX, dip, "px_add_intx_intr: rdip=%s%d ino=%x " 1069 "handler=%x arg1=%x arg2=%x\n", ddi_driver_name(rdip), 1070 ddi_get_instance(rdip), ino, hdlp->ih_cb_func, 1071 hdlp->ih_cb_arg1, hdlp->ih_cb_arg2); 1072 1073 ih_p = px_ib_alloc_ih(rdip, hdlp->ih_inum, 1074 hdlp->ih_cb_func, hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, 0, 0); 1075 1076 mutex_enter(&ib_p->ib_ino_lst_mutex); 1077 1078 ino_p = px_ib_locate_ino(ib_p, ino); 1079 ipil_list = ino_p ? ino_p->ino_ipil_p : NULL; 1080 1081 /* Sharing ino */ 1082 if (ino_p && (ipil_p = px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri))) { 1083 if (px_ib_intr_locate_ih(ipil_p, rdip, hdlp->ih_inum, 0, 0)) { 1084 DBG(DBG_A_INTX, dip, "px_add_intx_intr: " 1085 "dup intr #%d\n", hdlp->ih_inum); 1086 1087 ret = DDI_FAILURE; 1088 goto fail1; 1089 } 1090 1091 /* Save mondo value in hdlp */ 1092 hdlp->ih_vector = ino_p->ino_sysino; 1093 1094 if ((ret = px_ib_ino_add_intr(px_p, ipil_p, 1095 ih_p)) != DDI_SUCCESS) 1096 goto fail1; 1097 1098 goto ino_done; 1099 } 1100 1101 if (hdlp->ih_pri == 0) 1102 hdlp->ih_pri = px_class_to_pil(rdip); 1103 1104 ipil_p = px_ib_new_ino_pil(ib_p, ino, hdlp->ih_pri, ih_p); 1105 ino_p = ipil_p->ipil_ino_p; 1106 1107 /* Save mondo value in hdlp */ 1108 hdlp->ih_vector = ino_p->ino_sysino; 1109 1110 DBG(DBG_A_INTX, dip, "px_add_intx_intr: pil=0x%x mondo=0x%x\n", 1111 hdlp->ih_pri, hdlp->ih_vector); 1112 1113 DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, 1114 (ddi_intr_handler_t *)px_intx_intr, (caddr_t)ipil_p, NULL); 1115 1116 ret = i_ddi_add_ivintr(hdlp); 1117 1118 /* 1119 * Restore original interrupt handler 1120 * and arguments in interrupt handle. 1121 */ 1122 DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_handler, 1123 ih_p->ih_handler_arg1, ih_p->ih_handler_arg2); 1124 1125 if (ret != DDI_SUCCESS) 1126 goto fail2; 1127 1128 /* Save the pil for this ino */ 1129 ipil_p->ipil_pil = hdlp->ih_pri; 1130 1131 /* Select cpu, saving it for sharing and removal */ 1132 if (ipil_list == NULL) { 1133 ino_p->ino_cpuid = intr_dist_cpuid(); 1134 1135 /* Enable interrupt */ 1136 px_ib_intr_enable(px_p, ino_p->ino_cpuid, ino); 1137 } 1138 1139 ino_done: 1140 /* Add weight to the cpu that we are already targeting */ 1141 weight = px_class_to_intr_weight(rdip); 1142 intr_dist_cpuid_add_device_weight(ino_p->ino_cpuid, rdip, weight); 1143 1144 ih_p->ih_ipil_p = ipil_p; 1145 px_create_intr_kstats(ih_p); 1146 if (ih_p->ih_ksp) 1147 kstat_install(ih_p->ih_ksp); 1148 mutex_exit(&ib_p->ib_ino_lst_mutex); 1149 1150 DBG(DBG_A_INTX, dip, "px_add_intx_intr: done! Interrupt 0x%x pil=%x\n", 1151 ino_p->ino_sysino, hdlp->ih_pri); 1152 1153 return (ret); 1154 fail2: 1155 px_ib_delete_ino_pil(ib_p, ipil_p); 1156 fail1: 1157 if (ih_p->ih_config_handle) 1158 pci_config_teardown(&ih_p->ih_config_handle); 1159 1160 mutex_exit(&ib_p->ib_ino_lst_mutex); 1161 kmem_free(ih_p, sizeof (px_ih_t)); 1162 1163 DBG(DBG_A_INTX, dip, "px_add_intx_intr: Failed! Interrupt 0x%x " 1164 "pil=%x\n", ino_p->ino_sysino, hdlp->ih_pri); 1165 1166 return (ret); 1167 } 1168 1169 /* 1170 * px_rem_intx_intr: 1171 * 1172 * This function is called to unregister INTx and legacy hardware 1173 * interrupt pins interrupts. 1174 */ 1175 int 1176 px_rem_intx_intr(dev_info_t *dip, dev_info_t *rdip, 1177 ddi_intr_handle_impl_t *hdlp) 1178 { 1179 px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 1180 px_ib_t *ib_p = px_p->px_ib_p; 1181 devino_t ino; 1182 cpuid_t curr_cpu; 1183 px_ino_t *ino_p; 1184 px_ino_pil_t *ipil_p; 1185 px_ih_t *ih_p; 1186 int ret = DDI_SUCCESS; 1187 1188 ino = hdlp->ih_vector; 1189 1190 DBG(DBG_R_INTX, dip, "px_rem_intx_intr: rdip=%s%d ino=%x\n", 1191 ddi_driver_name(rdip), ddi_get_instance(rdip), ino); 1192 1193 mutex_enter(&ib_p->ib_ino_lst_mutex); 1194 1195 ino_p = px_ib_locate_ino(ib_p, ino); 1196 ipil_p = px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri); 1197 ih_p = px_ib_intr_locate_ih(ipil_p, rdip, hdlp->ih_inum, 0, 0); 1198 1199 /* Get the current cpu */ 1200 if ((ret = px_lib_intr_gettarget(px_p->px_dip, ino_p->ino_sysino, 1201 &curr_cpu)) != DDI_SUCCESS) 1202 goto fail; 1203 1204 if ((ret = px_ib_ino_rem_intr(px_p, ipil_p, ih_p)) != DDI_SUCCESS) 1205 goto fail; 1206 1207 intr_dist_cpuid_rem_device_weight(ino_p->ino_cpuid, rdip); 1208 1209 if (ipil_p->ipil_ih_size == 0) { 1210 hdlp->ih_vector = ino_p->ino_sysino; 1211 i_ddi_rem_ivintr(hdlp); 1212 1213 px_ib_delete_ino_pil(ib_p, ipil_p); 1214 } 1215 1216 if (ino_p->ino_ipil_size == 0) { 1217 kmem_free(ino_p, sizeof (px_ino_t)); 1218 } else { 1219 /* Re-enable interrupt only if mapping register still shared */ 1220 PX_INTR_ENABLE(px_p->px_dip, ino_p->ino_sysino, curr_cpu); 1221 } 1222 1223 fail: 1224 mutex_exit(&ib_p->ib_ino_lst_mutex); 1225 return (ret); 1226 } 1227 1228 /* 1229 * px_add_msiq_intr: 1230 * 1231 * This function is called to register MSI/Xs and PCIe message interrupts. 1232 */ 1233 int 1234 px_add_msiq_intr(dev_info_t *dip, dev_info_t *rdip, 1235 ddi_intr_handle_impl_t *hdlp, msiq_rec_type_t rec_type, 1236 msgcode_t msg_code, msiqid_t *msiq_id_p) 1237 { 1238 px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 1239 px_ib_t *ib_p = px_p->px_ib_p; 1240 px_msiq_state_t *msiq_state_p = &ib_p->ib_msiq_state; 1241 devino_t ino; 1242 px_ih_t *ih_p; 1243 px_ino_t *ino_p; 1244 px_ino_pil_t *ipil_p, *ipil_list; 1245 int32_t weight; 1246 int ret = DDI_SUCCESS; 1247 1248 DBG(DBG_MSIQ, dip, "px_add_msiq_intr: rdip=%s%d handler=%x " 1249 "arg1=%x arg2=%x\n", ddi_driver_name(rdip), ddi_get_instance(rdip), 1250 hdlp->ih_cb_func, hdlp->ih_cb_arg1, hdlp->ih_cb_arg2); 1251 1252 if ((ret = px_msiq_alloc(px_p, rec_type, msiq_id_p)) != DDI_SUCCESS) { 1253 DBG(DBG_MSIQ, dip, "px_add_msiq_intr: " 1254 "msiq allocation failed\n"); 1255 return (ret); 1256 } 1257 1258 ino = px_msiqid_to_devino(px_p, *msiq_id_p); 1259 1260 ih_p = px_ib_alloc_ih(rdip, hdlp->ih_inum, hdlp->ih_cb_func, 1261 hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, rec_type, msg_code); 1262 1263 mutex_enter(&ib_p->ib_ino_lst_mutex); 1264 1265 ino_p = px_ib_locate_ino(ib_p, ino); 1266 ipil_list = ino_p ? ino_p->ino_ipil_p : NULL; 1267 1268 /* Sharing ino */ 1269 if (ino_p && (ipil_p = px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri))) { 1270 if (px_ib_intr_locate_ih(ipil_p, rdip, 1271 hdlp->ih_inum, rec_type, msg_code)) { 1272 DBG(DBG_MSIQ, dip, "px_add_msiq_intr: " 1273 "dup intr #%d\n", hdlp->ih_inum); 1274 1275 ret = DDI_FAILURE; 1276 goto fail1; 1277 } 1278 1279 /* Save mondo value in hdlp */ 1280 hdlp->ih_vector = ino_p->ino_sysino; 1281 1282 if ((ret = px_ib_ino_add_intr(px_p, ipil_p, 1283 ih_p)) != DDI_SUCCESS) 1284 goto fail1; 1285 1286 goto ino_done; 1287 } 1288 1289 if (hdlp->ih_pri == 0) 1290 hdlp->ih_pri = px_class_to_pil(rdip); 1291 1292 ipil_p = px_ib_new_ino_pil(ib_p, ino, hdlp->ih_pri, ih_p); 1293 ino_p = ipil_p->ipil_ino_p; 1294 1295 ino_p->ino_msiq_p = msiq_state_p->msiq_p + 1296 (*msiq_id_p - msiq_state_p->msiq_1st_msiq_id); 1297 1298 /* Save mondo value in hdlp */ 1299 hdlp->ih_vector = ino_p->ino_sysino; 1300 1301 DBG(DBG_MSIQ, dip, "px_add_msiq_intr: pil=0x%x mondo=0x%x\n", 1302 hdlp->ih_pri, hdlp->ih_vector); 1303 1304 DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, 1305 (ddi_intr_handler_t *)px_msiq_intr, (caddr_t)ipil_p, NULL); 1306 1307 ret = i_ddi_add_ivintr(hdlp); 1308 1309 /* 1310 * Restore original interrupt handler 1311 * and arguments in interrupt handle. 1312 */ 1313 DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_handler, 1314 ih_p->ih_handler_arg1, ih_p->ih_handler_arg2); 1315 1316 if (ret != DDI_SUCCESS) 1317 goto fail2; 1318 1319 /* Save the pil for this ino */ 1320 ipil_p->ipil_pil = hdlp->ih_pri; 1321 1322 /* Select cpu, saving it for sharing and removal */ 1323 if (ipil_list == NULL) { 1324 ino_p->ino_cpuid = intr_dist_cpuid(); 1325 1326 /* Enable MSIQ */ 1327 px_lib_msiq_setstate(dip, *msiq_id_p, PCI_MSIQ_STATE_IDLE); 1328 px_lib_msiq_setvalid(dip, *msiq_id_p, PCI_MSIQ_VALID); 1329 1330 /* Enable interrupt */ 1331 px_ib_intr_enable(px_p, ino_p->ino_cpuid, ino); 1332 } 1333 1334 ino_done: 1335 /* Add weight to the cpu that we are already targeting */ 1336 weight = px_class_to_intr_weight(rdip); 1337 intr_dist_cpuid_add_device_weight(ino_p->ino_cpuid, rdip, weight); 1338 1339 ih_p->ih_ipil_p = ipil_p; 1340 px_create_intr_kstats(ih_p); 1341 if (ih_p->ih_ksp) 1342 kstat_install(ih_p->ih_ksp); 1343 mutex_exit(&ib_p->ib_ino_lst_mutex); 1344 1345 DBG(DBG_MSIQ, dip, "px_add_msiq_intr: done! Interrupt 0x%x pil=%x\n", 1346 ino_p->ino_sysino, hdlp->ih_pri); 1347 1348 return (ret); 1349 fail2: 1350 px_ib_delete_ino_pil(ib_p, ipil_p); 1351 fail1: 1352 if (ih_p->ih_config_handle) 1353 pci_config_teardown(&ih_p->ih_config_handle); 1354 1355 mutex_exit(&ib_p->ib_ino_lst_mutex); 1356 kmem_free(ih_p, sizeof (px_ih_t)); 1357 1358 DBG(DBG_MSIQ, dip, "px_add_msiq_intr: Failed! Interrupt 0x%x pil=%x\n", 1359 ino_p->ino_sysino, hdlp->ih_pri); 1360 1361 return (ret); 1362 } 1363 1364 /* 1365 * px_rem_msiq_intr: 1366 * 1367 * This function is called to unregister MSI/Xs and PCIe message interrupts. 1368 */ 1369 int 1370 px_rem_msiq_intr(dev_info_t *dip, dev_info_t *rdip, 1371 ddi_intr_handle_impl_t *hdlp, msiq_rec_type_t rec_type, 1372 msgcode_t msg_code, msiqid_t msiq_id) 1373 { 1374 px_t *px_p = INST_TO_STATE(ddi_get_instance(dip)); 1375 px_ib_t *ib_p = px_p->px_ib_p; 1376 devino_t ino = px_msiqid_to_devino(px_p, msiq_id); 1377 cpuid_t curr_cpu; 1378 px_ino_t *ino_p; 1379 px_ino_pil_t *ipil_p; 1380 px_ih_t *ih_p; 1381 int ret = DDI_SUCCESS; 1382 1383 DBG(DBG_MSIQ, dip, "px_rem_msiq_intr: rdip=%s%d msiq_id=%x ino=%x\n", 1384 ddi_driver_name(rdip), ddi_get_instance(rdip), msiq_id, ino); 1385 1386 mutex_enter(&ib_p->ib_ino_lst_mutex); 1387 1388 ino_p = px_ib_locate_ino(ib_p, ino); 1389 ipil_p = px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri); 1390 ih_p = px_ib_intr_locate_ih(ipil_p, rdip, hdlp->ih_inum, rec_type, 1391 msg_code); 1392 1393 /* Get the current cpu */ 1394 if ((ret = px_lib_intr_gettarget(px_p->px_dip, ino_p->ino_sysino, 1395 &curr_cpu)) != DDI_SUCCESS) 1396 goto fail; 1397 1398 if ((ret = px_ib_ino_rem_intr(px_p, ipil_p, ih_p)) != DDI_SUCCESS) 1399 goto fail; 1400 1401 intr_dist_cpuid_rem_device_weight(ino_p->ino_cpuid, rdip); 1402 1403 if (ipil_p->ipil_ih_size == 0) { 1404 hdlp->ih_vector = ino_p->ino_sysino; 1405 i_ddi_rem_ivintr(hdlp); 1406 1407 px_ib_delete_ino_pil(ib_p, ipil_p); 1408 1409 if (ino_p->ino_ipil_size == 0) 1410 px_lib_msiq_setvalid(dip, 1411 px_devino_to_msiqid(px_p, ino), PCI_MSIQ_INVALID); 1412 1413 (void) px_msiq_free(px_p, msiq_id); 1414 } 1415 1416 if (ino_p->ino_ipil_size == 0) { 1417 kmem_free(ino_p, sizeof (px_ino_t)); 1418 } else { 1419 /* Re-enable interrupt only if mapping register still shared */ 1420 PX_INTR_ENABLE(px_p->px_dip, ino_p->ino_sysino, curr_cpu); 1421 } 1422 1423 fail: 1424 mutex_exit(&ib_p->ib_ino_lst_mutex); 1425 return (ret); 1426 } 1427