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 /* 27 * Support for MSI, MSIX and INTx 28 */ 29 30 #include <sys/conf.h> 31 #include <sys/debug.h> 32 #include <sys/pci.h> 33 #include <sys/pci_cap.h> 34 #include <sys/pci_intr_lib.h> 35 #include <sys/sunddi.h> 36 #include <sys/bitmap.h> 37 38 /* 39 * MSI-X BIR Index Table: 40 * 41 * BAR indicator register (BIR) to Base Address register. 42 */ 43 static uchar_t pci_msix_bir_index[8] = {0x10, 0x14, 0x18, 0x1c, 44 0x20, 0x24, 0xff, 0xff}; 45 46 /* default class to pil value mapping */ 47 pci_class_val_t pci_default_pil [] = { 48 {0x000000, 0xff0000, 0x1}, /* Class code for pre-2.0 devices */ 49 {0x010000, 0xff0000, 0x5}, /* Mass Storage Controller */ 50 {0x020000, 0xff0000, 0x6}, /* Network Controller */ 51 {0x030000, 0xff0000, 0x9}, /* Display Controller */ 52 {0x040000, 0xff0000, 0x8}, /* Multimedia Controller */ 53 {0x050000, 0xff0000, 0x9}, /* Memory Controller */ 54 {0x060000, 0xff0000, 0x9}, /* Bridge Controller */ 55 {0x0c0000, 0xffff00, 0x9}, /* Serial Bus, FireWire (IEEE 1394) */ 56 {0x0c0100, 0xffff00, 0x4}, /* Serial Bus, ACCESS.bus */ 57 {0x0c0200, 0xffff00, 0x4}, /* Serial Bus, SSA */ 58 {0x0c0300, 0xffff00, 0x9}, /* Serial Bus Universal Serial Bus */ 59 /* 60 * XXX - This is a temporary workaround and it will be removed 61 * after x86 interrupt scalability support. 62 */ 63 #if defined(__i386) || defined(__amd64) 64 {0x0c0400, 0xffff00, 0x5}, /* Serial Bus, Fibre Channel */ 65 #else 66 {0x0c0400, 0xffff00, 0x6}, /* Serial Bus, Fibre Channel */ 67 #endif 68 {0x0c0600, 0xffff00, 0x6} /* Serial Bus, Infiniband */ 69 }; 70 71 /* 72 * Default class to intr_weight value mapping (% of CPU). A driver.conf 73 * entry on or above the pci node like 74 * 75 * pci-class-intr-weights= 0x020000, 0xff0000, 30; 76 * 77 * can be used to augment or override entries in the default table below. 78 * 79 * NB: The values below give NICs preference on redistribution, and provide 80 * NICs some isolation from other interrupt sources. We need better interfaces 81 * that allow the NIC driver to identify a specific NIC instance as high 82 * bandwidth, and thus deserving of separation from other low bandwidth 83 * NICs additional isolation from other interrupt sources. 84 * 85 * NB: We treat Infiniband like a NIC. 86 */ 87 pci_class_val_t pci_default_intr_weight [] = { 88 {0x020000, 0xff0000, 35}, /* Network Controller */ 89 {0x010000, 0xff0000, 10}, /* Mass Storage Controller */ 90 {0x0c0400, 0xffff00, 10}, /* Serial Bus, Fibre Channel */ 91 {0x0c0600, 0xffff00, 50} /* Serial Bus, Infiniband */ 92 }; 93 94 /* 95 * Library utility functions 96 */ 97 98 /* 99 * pci_get_msi_ctrl: 100 * 101 * Helper function that returns with 'cfg_hdl', MSI/X ctrl pointer, 102 * and caps_ptr for MSI/X if these are found. 103 */ 104 static int 105 pci_get_msi_ctrl(dev_info_t *dip, int type, ushort_t *msi_ctrl, 106 ushort_t *caps_ptr, ddi_acc_handle_t *h) 107 { 108 *msi_ctrl = *caps_ptr = 0; 109 110 if (pci_config_setup(dip, h) != DDI_SUCCESS) { 111 DDI_INTR_NEXDBG((CE_CONT, "pci_get_msi_ctrl: " 112 "%s%d can't get config handle", 113 ddi_driver_name(dip), ddi_get_instance(dip))); 114 115 return (DDI_FAILURE); 116 } 117 118 if ((PCI_CAP_LOCATE(*h, PCI_CAP_ID_MSI, caps_ptr) == DDI_SUCCESS) && 119 (type == DDI_INTR_TYPE_MSI)) { 120 if ((*msi_ctrl = PCI_CAP_GET16(*h, NULL, *caps_ptr, 121 PCI_MSI_CTRL)) == PCI_CAP_EINVAL16) 122 goto done; 123 124 DDI_INTR_NEXDBG((CE_CONT, "pci_get_msi_ctrl: MSI " 125 "caps_ptr=%x msi_ctrl=%x\n", *caps_ptr, *msi_ctrl)); 126 127 return (DDI_SUCCESS); 128 } 129 130 if ((PCI_CAP_LOCATE(*h, PCI_CAP_ID_MSI_X, caps_ptr) == DDI_SUCCESS) && 131 (type == DDI_INTR_TYPE_MSIX)) { 132 if ((*msi_ctrl = PCI_CAP_GET16(*h, NULL, *caps_ptr, 133 PCI_MSIX_CTRL)) == PCI_CAP_EINVAL16) 134 goto done; 135 136 DDI_INTR_NEXDBG((CE_CONT, "pci_get_msi_ctrl: MSI-X " 137 "caps_ptr=%x msi_ctrl=%x\n", *caps_ptr, *msi_ctrl)); 138 139 return (DDI_SUCCESS); 140 } 141 142 done: 143 pci_config_teardown(h); 144 return (DDI_FAILURE); 145 } 146 147 148 /* 149 * pci_msi_get_cap: 150 * 151 * Get the capabilities of the MSI/X interrupt 152 */ 153 int 154 pci_msi_get_cap(dev_info_t *rdip, int type, int *flagsp) 155 { 156 ushort_t caps_ptr, msi_ctrl; 157 ddi_acc_handle_t cfg_hdle; 158 159 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_cap: rdip = 0x%p\n", 160 (void *)rdip)); 161 162 *flagsp = 0; 163 164 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl, 165 &caps_ptr, &cfg_hdle) != DDI_SUCCESS) 166 return (DDI_FAILURE); 167 168 if (type == DDI_INTR_TYPE_MSI) { 169 if (msi_ctrl & PCI_MSI_64BIT_MASK) 170 *flagsp |= DDI_INTR_FLAG_MSI64; 171 if (msi_ctrl & PCI_MSI_PVM_MASK) 172 *flagsp |= (DDI_INTR_FLAG_MASKABLE | 173 DDI_INTR_FLAG_PENDING); 174 else 175 *flagsp |= DDI_INTR_FLAG_BLOCK; 176 } else if (type == DDI_INTR_TYPE_MSIX) { 177 /* MSI-X supports PVM, 64bit by default */ 178 *flagsp |= (DDI_INTR_FLAG_MASKABLE | DDI_INTR_FLAG_MSI64 | 179 DDI_INTR_FLAG_PENDING); 180 } 181 182 *flagsp |= DDI_INTR_FLAG_EDGE; 183 184 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_cap: flags = 0x%x\n", *flagsp)); 185 186 pci_config_teardown(&cfg_hdle); 187 return (DDI_SUCCESS); 188 } 189 190 191 /* 192 * pci_msi_configure: 193 * 194 * Configure address/data and number MSI/Xs fields in the MSI/X 195 * capability structure. 196 */ 197 /* ARGSUSED */ 198 int 199 pci_msi_configure(dev_info_t *rdip, int type, int count, int inum, 200 uint64_t addr, uint64_t data) 201 { 202 ushort_t caps_ptr, msi_ctrl; 203 ddi_acc_handle_t h; 204 205 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: rdip = 0x%p type 0x%x " 206 "count 0x%x inum 0x%x addr 0x%" PRIx64 " data 0x%" PRIx64 "\n", 207 (void *)rdip, type, count, inum, addr, data)); 208 209 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl, 210 &caps_ptr, &h) != DDI_SUCCESS) 211 return (DDI_FAILURE); 212 213 if (type == DDI_INTR_TYPE_MSI) { 214 /* Set the bits to inform how many MSIs are enabled */ 215 msi_ctrl |= ((highbit(count) -1) << PCI_MSI_MME_SHIFT); 216 PCI_CAP_PUT16(h, NULL, caps_ptr, PCI_MSI_CTRL, msi_ctrl); 217 218 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: msi_ctrl = %x\n", 219 PCI_CAP_GET16(h, NULL, caps_ptr, PCI_MSI_CTRL))); 220 221 /* Set the "data" and "addr" bits */ 222 PCI_CAP_PUT32(h, NULL, caps_ptr, PCI_MSI_ADDR_OFFSET, addr); 223 224 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: msi_addr = %x\n", 225 PCI_CAP_GET32(h, NULL, caps_ptr, PCI_MSI_ADDR_OFFSET))); 226 227 if (msi_ctrl & PCI_MSI_64BIT_MASK) { 228 PCI_CAP_PUT32(h, NULL, caps_ptr, PCI_MSI_ADDR_OFFSET 229 + 4, addr >> 32); 230 231 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: upper " 232 "32bit msi_addr = %x\n", PCI_CAP_GET32(h, NULL, 233 caps_ptr, PCI_MSI_ADDR_OFFSET + 4))); 234 235 PCI_CAP_PUT16(h, NULL, caps_ptr, PCI_MSI_64BIT_DATA, 236 data); 237 238 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: msi_data " 239 "= %x\n", PCI_CAP_GET16(h, NULL, caps_ptr, 240 PCI_MSI_64BIT_DATA))); 241 } else { 242 PCI_CAP_PUT16(h, NULL, caps_ptr, PCI_MSI_32BIT_DATA, 243 data); 244 245 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: msi_data " 246 "= %x\n", PCI_CAP_GET16(h, NULL, caps_ptr, 247 PCI_MSI_32BIT_DATA))); 248 } 249 } else if (type == DDI_INTR_TYPE_MSIX) { 250 uintptr_t off; 251 ddi_intr_msix_t *msix_p = i_ddi_get_msix(rdip); 252 253 /* Offset into the "inum"th entry in the MSI-X table */ 254 off = (uintptr_t)msix_p->msix_tbl_addr + 255 (inum * PCI_MSIX_VECTOR_SIZE); 256 257 /* Set the "data" and "addr" bits */ 258 ddi_put32(msix_p->msix_tbl_hdl, 259 (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), data); 260 261 ddi_put64(msix_p->msix_tbl_hdl, 262 (uint64_t *)(off + PCI_MSIX_LOWER_ADDR_OFFSET), addr); 263 264 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: " 265 "msix_addr 0x%" PRIx64 " msix_data 0x%x\n", 266 ddi_get64(msix_p->msix_tbl_hdl, 267 (uint64_t *)(off + PCI_MSIX_LOWER_ADDR_OFFSET)), 268 ddi_get32(msix_p->msix_tbl_hdl, 269 (uint32_t *)(off + PCI_MSIX_DATA_OFFSET)))); 270 } 271 272 pci_config_teardown(&h); 273 return (DDI_SUCCESS); 274 } 275 276 277 /* 278 * pci_msi_unconfigure: 279 * 280 * Unconfigure address/data and number MSI/Xs fields in the MSI/X 281 * capability structure. 282 */ 283 /* ARGSUSED */ 284 int 285 pci_msi_unconfigure(dev_info_t *rdip, int type, int inum) 286 { 287 ushort_t msi_ctrl, caps_ptr; 288 ddi_acc_handle_t h; 289 290 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_unconfigure: rdip = 0x%p type 0x%x " 291 "inum 0x%x\n", (void *)rdip, type, inum)); 292 293 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl, &caps_ptr, &h) != 294 DDI_SUCCESS) 295 return (DDI_FAILURE); 296 297 if (type == DDI_INTR_TYPE_MSI) { 298 msi_ctrl &= (~PCI_MSI_MME_MASK); 299 PCI_CAP_PUT16(h, NULL, caps_ptr, PCI_MSI_CTRL, msi_ctrl); 300 301 PCI_CAP_PUT32(h, NULL, caps_ptr, PCI_MSI_ADDR_OFFSET, 0); 302 303 if (msi_ctrl & PCI_MSI_64BIT_MASK) { 304 PCI_CAP_PUT16(h, NULL, caps_ptr, PCI_MSI_64BIT_DATA, 305 0); 306 PCI_CAP_PUT32(h, NULL, caps_ptr, PCI_MSI_ADDR_OFFSET 307 + 4, 0); 308 } else { 309 PCI_CAP_PUT16(h, NULL, caps_ptr, PCI_MSI_32BIT_DATA, 310 0); 311 } 312 313 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_unconfigure: msi_ctrl " 314 "= %x\n", PCI_CAP_GET16(h, NULL, caps_ptr, PCI_MSI_CTRL))); 315 316 } else if (type == DDI_INTR_TYPE_MSIX) { 317 uintptr_t off; 318 ddi_intr_msix_t *msix_p = i_ddi_get_msix(rdip); 319 320 /* Offset into the "inum"th entry in the MSI-X table */ 321 off = (uintptr_t)msix_p->msix_tbl_addr + 322 (inum * PCI_MSIX_VECTOR_SIZE); 323 324 /* Reset the "data" and "addr" bits */ 325 ddi_put32(msix_p->msix_tbl_hdl, 326 (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), 0); 327 328 ddi_put64(msix_p->msix_tbl_hdl, 329 (uint64_t *)(off + PCI_MSIX_LOWER_ADDR_OFFSET), 0); 330 } 331 332 pci_config_teardown(&h); 333 return (DDI_SUCCESS); 334 } 335 336 337 /* 338 * pci_is_msi_enabled: 339 * 340 * This function returns DDI_SUCCESS if MSI/X is already enabled, otherwise 341 * it returns DDI_FAILURE. 342 */ 343 int 344 pci_is_msi_enabled(dev_info_t *rdip, int type) 345 { 346 ushort_t caps_ptr, msi_ctrl; 347 ddi_acc_handle_t cfg_hdle; 348 int ret = DDI_FAILURE; 349 350 DDI_INTR_NEXDBG((CE_CONT, "pci_is_msi_enabled: rdip = 0x%p, " 351 "type = 0x%x\n", (void *)rdip, type)); 352 353 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl, 354 &caps_ptr, &cfg_hdle) != DDI_SUCCESS) 355 return (DDI_FAILURE); 356 357 if ((type == DDI_INTR_TYPE_MSI) && (msi_ctrl & PCI_MSI_ENABLE_BIT)) 358 ret = DDI_SUCCESS; 359 360 if ((type == DDI_INTR_TYPE_MSIX) && (msi_ctrl & PCI_MSIX_ENABLE_BIT)) 361 ret = DDI_SUCCESS; 362 363 pci_config_teardown(&cfg_hdle); 364 return (ret); 365 } 366 367 368 /* 369 * pci_msi_enable_mode: 370 * 371 * This function sets the MSI_ENABLE bit in the capability structure 372 * (for MSI) and MSIX_ENABLE bit in the MSI-X capability structure. 373 * 374 * NOTE: It is the nexus driver's responsibility to clear the MSI/X 375 * interrupt's mask bit in the MSI/X capability structure before the 376 * interrupt can be used. 377 */ 378 int 379 pci_msi_enable_mode(dev_info_t *rdip, int type) 380 { 381 ushort_t caps_ptr, msi_ctrl; 382 ddi_acc_handle_t cfg_hdle; 383 384 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_enable_mode: rdip = 0x%p\n", 385 (void *)rdip)); 386 387 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl, 388 &caps_ptr, &cfg_hdle) != DDI_SUCCESS) 389 return (DDI_FAILURE); 390 391 if (type == DDI_INTR_TYPE_MSI) { 392 if (msi_ctrl & PCI_MSI_ENABLE_BIT) 393 goto finished; 394 395 msi_ctrl |= PCI_MSI_ENABLE_BIT; 396 PCI_CAP_PUT16(cfg_hdle, NULL, caps_ptr, PCI_MSI_CTRL, msi_ctrl); 397 398 } else if (type == DDI_INTR_TYPE_MSIX) { 399 if (msi_ctrl & PCI_MSIX_ENABLE_BIT) 400 goto finished; 401 402 msi_ctrl |= PCI_MSIX_ENABLE_BIT; 403 PCI_CAP_PUT16(cfg_hdle, NULL, caps_ptr, PCI_MSIX_CTRL, 404 msi_ctrl); 405 } 406 407 finished: 408 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_enable_mode: msi_ctrl = %x\n", 409 msi_ctrl)); 410 411 pci_config_teardown(&cfg_hdle); 412 return (DDI_SUCCESS); 413 } 414 415 416 /* 417 * pci_msi_disable_mode: 418 * 419 * This function resets the MSI_ENABLE bit in the capability structure 420 * (for MSI) and MSIX_ENABLE bit in the MSI-X capability structure. 421 * 422 * NOTE: It is the nexus driver's responsibility to set the MSI/X 423 * interrupt's mask bit in the MSI/X capability structure before the 424 * interrupt can be disabled. 425 */ 426 int 427 pci_msi_disable_mode(dev_info_t *rdip, int type, uint_t flags) 428 { 429 ushort_t caps_ptr, msi_ctrl; 430 ddi_acc_handle_t cfg_hdle; 431 432 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_disable_mode: rdip = 0x%p " 433 "flags = 0x%x\n", (void *)rdip, flags)); 434 435 /* 436 * Do not turn off the master enable bit if other interrupts are 437 * still active. 438 */ 439 if ((flags != DDI_INTR_FLAG_BLOCK) && 440 (i_ddi_intr_get_current_nenables(rdip) > 1)) 441 return (DDI_SUCCESS); 442 443 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl, 444 &caps_ptr, &cfg_hdle) != DDI_SUCCESS) 445 return (DDI_FAILURE); 446 447 /* Reset the "enable" bit */ 448 if (type == DDI_INTR_TYPE_MSI) { 449 if (!(msi_ctrl & PCI_MSI_ENABLE_BIT)) 450 goto finished; 451 msi_ctrl &= ~PCI_MSI_ENABLE_BIT; 452 PCI_CAP_PUT16(cfg_hdle, NULL, caps_ptr, PCI_MSI_CTRL, msi_ctrl); 453 } else if (type == DDI_INTR_TYPE_MSIX) { 454 if (!(msi_ctrl & PCI_MSIX_ENABLE_BIT)) 455 goto finished; 456 457 msi_ctrl &= ~PCI_MSIX_ENABLE_BIT; 458 PCI_CAP_PUT16(cfg_hdle, NULL, caps_ptr, PCI_MSIX_CTRL, 459 msi_ctrl); 460 } 461 462 finished: 463 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_disable_mode: msi_ctrl = %x\n", 464 msi_ctrl)); 465 466 pci_config_teardown(&cfg_hdle); 467 return (DDI_SUCCESS); 468 } 469 470 471 /* 472 * pci_msi_set_mask: 473 * 474 * Set the mask bit in the MSI/X capability structure 475 */ 476 /* ARGSUSED */ 477 int 478 pci_msi_set_mask(dev_info_t *rdip, int type, int inum) 479 { 480 int offset; 481 int ret = DDI_FAILURE; 482 ushort_t caps_ptr, msi_ctrl; 483 ddi_acc_handle_t cfg_hdle; 484 uint32_t mask_bits; 485 486 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_set_mask: rdip = 0x%p, " 487 "type = 0x%x\n", (void *)rdip, type)); 488 489 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl, 490 &caps_ptr, &cfg_hdle) != DDI_SUCCESS) 491 return (DDI_FAILURE); 492 493 if (type == DDI_INTR_TYPE_MSI) { 494 if (!(msi_ctrl & PCI_MSI_PVM_MASK)) 495 goto done; 496 497 offset = (msi_ctrl & PCI_MSI_64BIT_MASK) ? 498 PCI_MSI_64BIT_MASKBITS : PCI_MSI_32BIT_MASK; 499 500 if ((mask_bits = PCI_CAP_GET32(cfg_hdle, NULL, caps_ptr, 501 offset)) == PCI_CAP_EINVAL32) 502 goto done; 503 504 mask_bits |= (1 << inum); 505 506 PCI_CAP_PUT32(cfg_hdle, NULL, caps_ptr, offset, mask_bits); 507 508 } else if (type == DDI_INTR_TYPE_MSIX) { 509 uintptr_t off; 510 ddi_intr_msix_t *msix_p; 511 512 /* Set function mask */ 513 if (msi_ctrl & PCI_MSIX_FUNCTION_MASK) { 514 ret = DDI_SUCCESS; 515 goto done; 516 } 517 518 msix_p = i_ddi_get_msix(rdip); 519 520 /* Offset into the "inum"th entry in the MSI-X table */ 521 off = (uintptr_t)msix_p->msix_tbl_addr + (inum * 522 PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET; 523 524 /* Set the Mask bit */ 525 ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, 0x1); 526 } 527 528 ret = DDI_SUCCESS; 529 done: 530 pci_config_teardown(&cfg_hdle); 531 return (ret); 532 } 533 534 535 /* 536 * pci_msi_clr_mask: 537 * 538 * Clear the mask bit in the MSI/X capability structure 539 */ 540 /* ARGSUSED */ 541 int 542 pci_msi_clr_mask(dev_info_t *rdip, int type, int inum) 543 { 544 ushort_t caps_ptr, msi_ctrl; 545 ddi_acc_handle_t cfg_hdle; 546 int offset; 547 int ret = DDI_FAILURE; 548 uint32_t mask_bits; 549 550 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_clr_mask: rdip = 0x%p, " 551 "type = 0x%x\n", (void *)rdip, type)); 552 553 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl, 554 &caps_ptr, &cfg_hdle) != DDI_SUCCESS) 555 return (DDI_FAILURE); 556 557 if (type == DDI_INTR_TYPE_MSI) { 558 if (!(msi_ctrl & PCI_MSI_PVM_MASK)) 559 goto done; 560 561 offset = (msi_ctrl & PCI_MSI_64BIT_MASK) ? 562 PCI_MSI_64BIT_MASKBITS : PCI_MSI_32BIT_MASK; 563 if ((mask_bits = PCI_CAP_GET32(cfg_hdle, NULL, caps_ptr, 564 offset)) == PCI_CAP_EINVAL32) 565 goto done; 566 567 mask_bits &= ~(1 << inum); 568 569 PCI_CAP_PUT32(cfg_hdle, NULL, caps_ptr, offset, mask_bits); 570 571 } else if (type == DDI_INTR_TYPE_MSIX) { 572 uintptr_t off; 573 ddi_intr_msix_t *msix_p; 574 575 if (msi_ctrl & PCI_MSIX_FUNCTION_MASK) { 576 ret = DDI_SUCCESS; 577 goto done; 578 } 579 580 msix_p = i_ddi_get_msix(rdip); 581 582 /* Offset into the "inum"th entry in the MSI-X table */ 583 off = (uintptr_t)msix_p->msix_tbl_addr + (inum * 584 PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET; 585 586 /* Clear the Mask bit */ 587 ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, 0x0); 588 } 589 590 ret = DDI_SUCCESS; 591 done: 592 pci_config_teardown(&cfg_hdle); 593 return (ret); 594 } 595 596 597 /* 598 * pci_msi_get_pending: 599 * 600 * Get the pending bit from the MSI/X capability structure 601 */ 602 /* ARGSUSED */ 603 int 604 pci_msi_get_pending(dev_info_t *rdip, int type, int inum, int *pendingp) 605 { 606 ushort_t caps_ptr, msi_ctrl; 607 ddi_acc_handle_t cfg_hdle; 608 int offset; 609 int ret = DDI_FAILURE; 610 611 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_pending: rdip = 0x%p\n", 612 (void *)rdip)); 613 614 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl, 615 &caps_ptr, &cfg_hdle) != DDI_SUCCESS) 616 return (DDI_FAILURE); 617 618 if (type == DDI_INTR_TYPE_MSI) { 619 uint32_t pending_bits; 620 621 if (!(msi_ctrl & PCI_MSI_PVM_MASK)) { 622 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_pending: " 623 "PVM is not supported\n")); 624 goto done; 625 } 626 627 offset = (msi_ctrl & PCI_MSI_64BIT_MASK) ? 628 PCI_MSI_64BIT_PENDING : PCI_MSI_32BIT_PENDING; 629 630 if ((pending_bits = PCI_CAP_GET32(cfg_hdle, NULL, caps_ptr, 631 offset)) == PCI_CAP_EINVAL32) 632 goto done; 633 634 *pendingp = pending_bits & ~(1 >> inum); 635 636 } else if (type == DDI_INTR_TYPE_MSIX) { 637 uintptr_t off; 638 uint64_t pending_bits; 639 ddi_intr_msix_t *msix_p = i_ddi_get_msix(rdip); 640 641 /* Offset into the PBA array which has entry for "inum" */ 642 off = (uintptr_t)msix_p->msix_pba_addr + (inum / 64); 643 644 /* Read the PBA array */ 645 pending_bits = ddi_get64(msix_p->msix_pba_hdl, (uint64_t *)off); 646 647 *pendingp = pending_bits & ~(1 >> inum); 648 } 649 650 ret = DDI_SUCCESS; 651 done: 652 pci_config_teardown(&cfg_hdle); 653 return (ret); 654 } 655 656 657 /* 658 * pci_msi_get_nintrs: 659 * 660 * For a given type (MSI/X) returns the number of interrupts supported 661 */ 662 int 663 pci_msi_get_nintrs(dev_info_t *rdip, int type, int *nintrs) 664 { 665 ushort_t caps_ptr, msi_ctrl; 666 ddi_acc_handle_t cfg_hdle; 667 668 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_nintrs: rdip = 0x%p\n", 669 (void *)rdip)); 670 671 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl, 672 &caps_ptr, &cfg_hdle) != DDI_SUCCESS) 673 return (DDI_FAILURE); 674 675 if (type == DDI_INTR_TYPE_MSI) { 676 *nintrs = 1 << ((msi_ctrl & PCI_MSI_MMC_MASK) >> 677 PCI_MSI_MMC_SHIFT); 678 } else if (type == DDI_INTR_TYPE_MSIX) { 679 if (msi_ctrl & PCI_MSIX_TBL_SIZE_MASK) 680 *nintrs = (msi_ctrl & PCI_MSIX_TBL_SIZE_MASK) + 1; 681 } 682 683 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_nintrs: " 684 "nintr = 0x%x\n", *nintrs)); 685 686 pci_config_teardown(&cfg_hdle); 687 return (DDI_SUCCESS); 688 } 689 690 691 /* 692 * pci_msi_set_nintrs: 693 * 694 * For a given type (MSI/X) sets the number of interrupts supported 695 * by the system. 696 * For MSI: Return an error if this func is called for navail > 32 697 * For MSI-X: Return an error if this func is called for navail > 2048 698 */ 699 int 700 pci_msi_set_nintrs(dev_info_t *rdip, int type, int navail) 701 { 702 ushort_t caps_ptr, msi_ctrl; 703 ddi_acc_handle_t cfg_hdle; 704 705 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_set_nintrs: rdip = 0x%p, " 706 "navail = 0x%x\n", (void *)rdip, navail)); 707 708 /* Check for valid input argument */ 709 if (((type == DDI_INTR_TYPE_MSI) && (navail > PCI_MSI_MAX_INTRS)) || 710 ((type == DDI_INTR_TYPE_MSIX) && (navail > PCI_MSIX_MAX_INTRS))) 711 return (DDI_EINVAL); 712 713 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl, 714 &caps_ptr, &cfg_hdle) != DDI_SUCCESS) 715 return (DDI_FAILURE); 716 717 if (type == DDI_INTR_TYPE_MSI) { 718 msi_ctrl |= ((highbit(navail) -1) << PCI_MSI_MME_SHIFT); 719 720 PCI_CAP_PUT16(cfg_hdle, NULL, caps_ptr, PCI_MSI_CTRL, msi_ctrl); 721 } else if (type == DDI_INTR_TYPE_MSIX) { 722 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_set_nintrs: unsupported\n")); 723 } 724 725 pci_config_teardown(&cfg_hdle); 726 return (DDI_SUCCESS); 727 } 728 729 730 /* 731 * pci_msi_get_supported_type: 732 * 733 * Returns DDI_INTR_TYPE_MSI and/or DDI_INTR_TYPE_MSIX as supported 734 * types if device supports them. A DDI_FAILURE is returned otherwise. 735 */ 736 int 737 pci_msi_get_supported_type(dev_info_t *rdip, int *typesp) 738 { 739 ushort_t caps_ptr, msi_ctrl; 740 ddi_acc_handle_t cfg_hdle; 741 742 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_supported_type: " 743 "rdip = 0x%p\n", (void *)rdip)); 744 745 *typesp = 0; 746 747 if (pci_get_msi_ctrl(rdip, DDI_INTR_TYPE_MSI, &msi_ctrl, 748 &caps_ptr, &cfg_hdle) == DDI_SUCCESS) { 749 *typesp |= DDI_INTR_TYPE_MSI; 750 pci_config_teardown(&cfg_hdle); 751 } 752 753 if (pci_get_msi_ctrl(rdip, DDI_INTR_TYPE_MSIX, &msi_ctrl, 754 &caps_ptr, &cfg_hdle) == DDI_SUCCESS) { 755 *typesp |= DDI_INTR_TYPE_MSIX; 756 pci_config_teardown(&cfg_hdle); 757 } 758 759 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_supported_type: " 760 "rdip = 0x%p types 0x%x\n", (void *)rdip, *typesp)); 761 762 return (*typesp == 0 ? DDI_FAILURE : DDI_SUCCESS); 763 } 764 765 766 /* 767 * pci_msix_init: 768 * This function initializes the various handles/addrs etc. 769 * needed for MSI-X support. It also allocates a private 770 * structure to keep track of these. 771 */ 772 ddi_intr_msix_t * 773 pci_msix_init(dev_info_t *rdip) 774 { 775 uint_t rnumber, breg, nregs; 776 size_t msix_tbl_size; 777 size_t pba_tbl_size; 778 ushort_t caps_ptr, msix_ctrl; 779 ddi_intr_msix_t *msix_p; 780 ddi_acc_handle_t cfg_hdle; 781 pci_regspec_t *rp; 782 int reg_size, addr_space, offset, *regs_list; 783 int i, ret; 784 785 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: rdip = %p\n", (void *)rdip)); 786 787 if (pci_get_msi_ctrl(rdip, DDI_INTR_TYPE_MSIX, &msix_ctrl, 788 &caps_ptr, &cfg_hdle) != DDI_SUCCESS) 789 return (NULL); 790 791 msix_p = kmem_zalloc(sizeof (ddi_intr_msix_t), KM_SLEEP); 792 793 /* 794 * Initialize the devacc structure 795 */ 796 msix_p->msix_dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 797 msix_p->msix_dev_attr.devacc_attr_endian_flags = 798 DDI_STRUCTURE_LE_ACC; 799 msix_p->msix_dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 800 801 /* Map the entire MSI-X vector table */ 802 msix_p->msix_tbl_offset = PCI_CAP_GET32(cfg_hdle, NULL, caps_ptr, 803 PCI_MSIX_TBL_OFFSET); 804 805 if ((breg = pci_msix_bir_index[msix_p->msix_tbl_offset & 806 PCI_MSIX_TBL_BIR_MASK]) == 0xff) 807 goto fail1; 808 809 msix_p->msix_tbl_offset = msix_p->msix_tbl_offset & 810 ~PCI_MSIX_TBL_BIR_MASK; 811 msix_tbl_size = ((msix_ctrl & PCI_MSIX_TBL_SIZE_MASK) + 1) * 812 PCI_MSIX_VECTOR_SIZE; 813 814 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: MSI-X table offset 0x%x " 815 "breg 0x%x size 0x%lx\n", msix_p->msix_tbl_offset, breg, 816 msix_tbl_size)); 817 818 if ((ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, 819 DDI_PROP_DONTPASS, "reg", (int **)®s_list, &nregs)) 820 != DDI_PROP_SUCCESS) { 821 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: " 822 "ddi_prop_lookup_int_array failed %d\n", ret)); 823 824 goto fail1; 825 } 826 827 reg_size = sizeof (pci_regspec_t) / sizeof (int); 828 829 for (i = 1, rnumber = 0; i < nregs/reg_size; i++) { 830 rp = (pci_regspec_t *)®s_list[i * reg_size]; 831 addr_space = rp->pci_phys_hi & PCI_ADDR_MASK; 832 offset = PCI_REG_REG_G(rp->pci_phys_hi); 833 834 if ((offset == breg) && ((addr_space == PCI_ADDR_MEM32) || 835 (addr_space == PCI_ADDR_MEM64))) { 836 rnumber = i; 837 break; 838 } 839 } 840 841 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: MSI-X rnum = %d\n", rnumber)); 842 843 if (rnumber == 0) { 844 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: " 845 "no mtaching reg number for offset 0x%x\n", breg)); 846 847 goto fail2; 848 } 849 850 if ((ret = ddi_regs_map_setup(rdip, rnumber, 851 (caddr_t *)&msix_p->msix_tbl_addr, msix_p->msix_tbl_offset, 852 msix_tbl_size, &msix_p->msix_dev_attr, 853 &msix_p->msix_tbl_hdl)) != DDI_SUCCESS) { 854 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: MSI-X Table " 855 "ddi_regs_map_setup failed %d\n", ret)); 856 857 goto fail2; 858 } 859 860 /* 861 * Map in the MSI-X Pending Bit Array 862 */ 863 msix_p->msix_pba_offset = PCI_CAP_GET32(cfg_hdle, NULL, caps_ptr, 864 PCI_MSIX_PBA_OFFSET); 865 866 if ((breg = pci_msix_bir_index[msix_p->msix_pba_offset & 867 PCI_MSIX_PBA_BIR_MASK]) == 0xff) 868 goto fail3; 869 870 msix_p->msix_pba_offset = msix_p->msix_pba_offset & 871 ~PCI_MSIX_PBA_BIR_MASK; 872 pba_tbl_size = ((msix_ctrl & PCI_MSIX_TBL_SIZE_MASK) + 1)/8; 873 874 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: PBA table offset 0x%x " 875 "breg 0x%x size 0x%lx\n", msix_p->msix_pba_offset, breg, 876 pba_tbl_size)); 877 878 for (i = 1, rnumber = 0; i < nregs/reg_size; i++) { 879 rp = (pci_regspec_t *)®s_list[i * reg_size]; 880 addr_space = rp->pci_phys_hi & PCI_ADDR_MASK; 881 offset = PCI_REG_REG_G(rp->pci_phys_hi); 882 883 if ((offset == breg) && ((addr_space == PCI_ADDR_MEM32) || 884 (addr_space == PCI_ADDR_MEM64))) { 885 rnumber = i; 886 break; 887 } 888 } 889 890 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: PBA rnum = %d\n", rnumber)); 891 892 if (rnumber == 0) { 893 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: " 894 "no matching reg number for offset 0x%x\n", breg)); 895 896 goto fail3; 897 } 898 899 if ((ret = ddi_regs_map_setup(rdip, rnumber, 900 (caddr_t *)&msix_p->msix_pba_addr, msix_p->msix_pba_offset, 901 pba_tbl_size, &msix_p->msix_dev_attr, 902 &msix_p->msix_pba_hdl)) != DDI_SUCCESS) { 903 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: PBA " 904 "ddi_regs_map_setup failed %d\n", ret)); 905 906 goto fail3; 907 } 908 909 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: msix_p = 0x%p DONE!!\n", 910 (void *)msix_p)); 911 912 ddi_prop_free(regs_list); 913 goto done; 914 915 fail3: 916 ddi_regs_map_free(&msix_p->msix_tbl_hdl); 917 fail2: 918 ddi_prop_free(regs_list); 919 fail1: 920 kmem_free(msix_p, sizeof (ddi_intr_msix_t)); 921 msix_p = NULL; 922 done: 923 pci_config_teardown(&cfg_hdle); 924 return (msix_p); 925 } 926 927 928 /* 929 * pci_msix_fini: 930 * This function cleans up previously allocated handles/addrs etc. 931 * It is only called if no more MSI-X interrupts are being used. 932 */ 933 void 934 pci_msix_fini(ddi_intr_msix_t *msix_p) 935 { 936 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_fini: msix_p = 0x%p\n", 937 (void *)msix_p)); 938 939 ddi_regs_map_free(&msix_p->msix_pba_hdl); 940 ddi_regs_map_free(&msix_p->msix_tbl_hdl); 941 kmem_free(msix_p, sizeof (ddi_intr_msix_t)); 942 } 943 944 945 /* 946 * pci_msix_dup: 947 * This function duplicates the address and data pair of one msi-x 948 * vector to another msi-x vector. 949 */ 950 int 951 pci_msix_dup(dev_info_t *rdip, int org_inum, int dup_inum) 952 { 953 ddi_intr_msix_t *msix_p = i_ddi_get_msix(rdip); 954 uint64_t addr; 955 uint64_t data; 956 uintptr_t off; 957 958 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_dup: dip = %p, inum = 0x%x, " 959 "to_vector = 0x%x\n", (void *)rdip, org_inum, dup_inum)); 960 961 /* Offset into the original inum's entry in the MSI-X table */ 962 off = (uintptr_t)msix_p->msix_tbl_addr + 963 (org_inum * PCI_MSIX_VECTOR_SIZE); 964 965 /* For the MSI-X number passed in, get the "data" and "addr" fields */ 966 addr = ddi_get64(msix_p->msix_tbl_hdl, 967 (uint64_t *)(off + PCI_MSIX_LOWER_ADDR_OFFSET)); 968 969 data = ddi_get32(msix_p->msix_tbl_hdl, 970 (uint32_t *)(off + PCI_MSIX_DATA_OFFSET)); 971 972 /* Program new vector with these existing values */ 973 return (pci_msi_configure(rdip, DDI_INTR_TYPE_MSIX, 1, dup_inum, addr, 974 data)); 975 } 976 977 978 /* 979 * Next set of routines are for INTx (legacy) PCI interrupt 980 * support only. 981 */ 982 983 /* 984 * pci_intx_get_cap: 985 * For non-MSI devices that comply to PCI v2.3 or greater; 986 * read the command register. Bit 10 implies interrupt disable. 987 * Set this bit and then read the status register bit 3. 988 * Bit 3 of status register is Interrupt state. 989 * If it is set; then the device supports 'Masking' 990 * 991 * Reset the device back to the original state. 992 */ 993 int 994 pci_intx_get_cap(dev_info_t *dip, int *flagsp) 995 { 996 uint16_t cmdreg, savereg; 997 ddi_acc_handle_t cfg_hdl; 998 #ifdef DEBUG 999 uint16_t statreg; 1000 #endif /* DEBUG */ 1001 1002 *flagsp = 0; 1003 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_cap: %s%d: called\n", 1004 ddi_driver_name(dip), ddi_get_instance(dip))); 1005 1006 if (pci_config_setup(dip, &cfg_hdl) != DDI_SUCCESS) { 1007 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_cap: can't get " 1008 "config handle\n")); 1009 return (DDI_FAILURE); 1010 } 1011 1012 savereg = pci_config_get16(cfg_hdl, PCI_CONF_COMM); 1013 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_cap: " 1014 "command register was 0x%x\n", savereg)); 1015 1016 /* Disable the interrupts */ 1017 cmdreg = savereg | PCI_COMM_INTX_DISABLE; 1018 pci_config_put16(cfg_hdl, PCI_CONF_COMM, cmdreg); 1019 1020 #ifdef DEBUG 1021 statreg = pci_config_get16(cfg_hdl, PCI_CONF_STAT); 1022 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_cap: " 1023 "status register is 0x%x\n", statreg)); 1024 #endif /* DEBUG */ 1025 1026 /* Read the bit back */ 1027 cmdreg = pci_config_get16(cfg_hdl, PCI_CONF_COMM); 1028 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_cap: " 1029 "command register is now 0x%x\n", cmdreg)); 1030 1031 *flagsp = DDI_INTR_FLAG_LEVEL; 1032 1033 if (cmdreg & PCI_COMM_INTX_DISABLE) { 1034 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_cap: " 1035 "masking supported\n")); 1036 *flagsp |= (DDI_INTR_FLAG_MASKABLE | 1037 DDI_INTR_FLAG_PENDING); 1038 } 1039 1040 /* Restore the device back to the original state and return */ 1041 pci_config_put16(cfg_hdl, PCI_CONF_COMM, savereg); 1042 1043 pci_config_teardown(&cfg_hdl); 1044 return (DDI_SUCCESS); 1045 } 1046 1047 1048 /* 1049 * pci_intx_clr_mask: 1050 * For non-MSI devices that comply to PCI v2.3 or greater; 1051 * clear the bit10 in the command register. 1052 */ 1053 int 1054 pci_intx_clr_mask(dev_info_t *dip) 1055 { 1056 uint16_t cmdreg; 1057 ddi_acc_handle_t cfg_hdl; 1058 1059 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_clr_mask: %s%d: called\n", 1060 ddi_driver_name(dip), ddi_get_instance(dip))); 1061 1062 if (pci_config_setup(dip, &cfg_hdl) != DDI_SUCCESS) { 1063 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_clr_mask: can't get " 1064 "config handle\n")); 1065 return (DDI_FAILURE); 1066 } 1067 1068 cmdreg = pci_config_get16(cfg_hdl, PCI_CONF_COMM); 1069 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_clr_mask: " 1070 "command register was 0x%x\n", cmdreg)); 1071 1072 /* Enable the interrupts */ 1073 cmdreg &= ~PCI_COMM_INTX_DISABLE; 1074 pci_config_put16(cfg_hdl, PCI_CONF_COMM, cmdreg); 1075 pci_config_teardown(&cfg_hdl); 1076 return (DDI_SUCCESS); 1077 } 1078 1079 1080 /* 1081 * pci_intx_set_mask: 1082 * For non-MSI devices that comply to PCI v2.3 or greater; 1083 * set the bit10 in the command register. 1084 */ 1085 int 1086 pci_intx_set_mask(dev_info_t *dip) 1087 { 1088 uint16_t cmdreg; 1089 ddi_acc_handle_t cfg_hdl; 1090 1091 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_set_mask: %s%d: called\n", 1092 ddi_driver_name(dip), ddi_get_instance(dip))); 1093 1094 if (pci_config_setup(dip, &cfg_hdl) != DDI_SUCCESS) { 1095 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_set_mask: can't get " 1096 "config handle\n")); 1097 return (DDI_FAILURE); 1098 } 1099 1100 cmdreg = pci_config_get16(cfg_hdl, PCI_CONF_COMM); 1101 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_set_mask: " 1102 "command register was 0x%x\n", cmdreg)); 1103 1104 /* Disable the interrupts */ 1105 cmdreg |= PCI_COMM_INTX_DISABLE; 1106 pci_config_put16(cfg_hdl, PCI_CONF_COMM, cmdreg); 1107 pci_config_teardown(&cfg_hdl); 1108 return (DDI_SUCCESS); 1109 } 1110 1111 /* 1112 * pci_intx_get_pending: 1113 * For non-MSI devices that comply to PCI v2.3 or greater; 1114 * read the status register. Bit 3 of status register is 1115 * Interrupt state. If it is set; then the interrupt is 1116 * 'Pending'. 1117 */ 1118 int 1119 pci_intx_get_pending(dev_info_t *dip, int *pendingp) 1120 { 1121 uint16_t statreg; 1122 ddi_acc_handle_t cfg_hdl; 1123 1124 *pendingp = 0; 1125 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_pending: %s%d: called\n", 1126 ddi_driver_name(dip), ddi_get_instance(dip))); 1127 1128 if (pci_config_setup(dip, &cfg_hdl) != DDI_SUCCESS) { 1129 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_pending: can't get " 1130 "config handle\n")); 1131 return (DDI_FAILURE); 1132 } 1133 1134 statreg = pci_config_get16(cfg_hdl, PCI_CONF_STAT); 1135 1136 if (statreg & PCI_STAT_INTR) { 1137 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_pending: " 1138 "interrupt is pending\n")); 1139 *pendingp = 1; 1140 } 1141 1142 pci_config_teardown(&cfg_hdl); 1143 return (DDI_SUCCESS); 1144 } 1145 1146 1147 /* 1148 * pci_intx_get_ispec: 1149 * Get intrspec for PCI devices (legacy support) 1150 * NOTE: This is moved here from x86 pci.c and is 1151 * needed here as pci-ide.c uses it as well 1152 */ 1153 /*ARGSUSED*/ 1154 ddi_intrspec_t 1155 pci_intx_get_ispec(dev_info_t *dip, dev_info_t *rdip, int inum) 1156 { 1157 int *intpriorities; 1158 uint_t num_intpriorities; 1159 struct intrspec *ispec; 1160 ddi_acc_handle_t cfg_hdl; 1161 struct ddi_parent_private_data *pdptr; 1162 1163 if ((pdptr = ddi_get_parent_data(rdip)) == NULL) 1164 return (NULL); 1165 1166 ispec = pdptr->par_intr; 1167 ASSERT(ispec); 1168 1169 /* check if the intrspec_pri has been initialized */ 1170 if (!ispec->intrspec_pri) { 1171 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, 1172 DDI_PROP_DONTPASS, "interrupt-priorities", 1173 &intpriorities, &num_intpriorities) == DDI_PROP_SUCCESS) { 1174 if (inum < num_intpriorities) 1175 ispec->intrspec_pri = intpriorities[inum]; 1176 ddi_prop_free(intpriorities); 1177 } 1178 1179 /* If still no priority, guess based on the class code */ 1180 if (ispec->intrspec_pri == 0) 1181 ispec->intrspec_pri = pci_class_to_pil(rdip); 1182 } 1183 1184 /* Get interrupt line value */ 1185 if (!ispec->intrspec_vec) { 1186 if (pci_config_setup(rdip, &cfg_hdl) != DDI_SUCCESS) { 1187 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_iline: " 1188 "can't get config handle\n")); 1189 return ((ddi_intrspec_t)ispec); 1190 } 1191 1192 ispec->intrspec_vec = pci_config_get8(cfg_hdl, PCI_CONF_ILINE); 1193 pci_config_teardown(&cfg_hdl); 1194 } 1195 1196 return ((ddi_intrspec_t)ispec); 1197 } 1198 1199 static uint32_t 1200 pci_match_class_val(uint32_t key, pci_class_val_t *rec_p, int nrec, 1201 uint32_t default_val) 1202 { 1203 int i; 1204 1205 for (i = 0; i < nrec; rec_p++, i++) { 1206 if ((rec_p->class_code & rec_p->class_mask) == 1207 (key & rec_p->class_mask)) 1208 return (rec_p->class_val); 1209 } 1210 1211 return (default_val); 1212 } 1213 1214 /* 1215 * Return the configuration value, based on class code and sub class code, 1216 * from the specified property based or default pci_class_val_t table. 1217 */ 1218 uint32_t 1219 pci_class_to_val(dev_info_t *rdip, char *property_name, pci_class_val_t *rec_p, 1220 int nrec, uint32_t default_val) 1221 { 1222 int property_len; 1223 uint32_t class_code; 1224 pci_class_val_t *conf; 1225 uint32_t val = default_val; 1226 1227 /* 1228 * Use the "class-code" property to get the base and sub class 1229 * codes for the requesting device. 1230 */ 1231 class_code = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, rdip, 1232 DDI_PROP_DONTPASS, "class-code", -1); 1233 1234 if (class_code == -1) 1235 return (val); 1236 1237 /* look up the val from the default table */ 1238 val = pci_match_class_val(class_code, rec_p, nrec, val); 1239 1240 1241 /* see if there is a more specific property specified value */ 1242 if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_NOTPROM, 1243 property_name, (caddr_t)&conf, &property_len)) 1244 return (val); 1245 1246 if ((property_len % sizeof (pci_class_val_t)) == 0) 1247 val = pci_match_class_val(class_code, conf, 1248 property_len / sizeof (pci_class_val_t), val); 1249 kmem_free(conf, property_len); 1250 return (val); 1251 } 1252 1253 /* 1254 * pci_class_to_pil: 1255 * 1256 * Return the pil for a given PCI device. 1257 */ 1258 uint32_t 1259 pci_class_to_pil(dev_info_t *rdip) 1260 { 1261 uint32_t pil; 1262 1263 /* Default pil is 1 */ 1264 pil = pci_class_to_val(rdip, 1265 "pci-class-priorities", pci_default_pil, 1266 sizeof (pci_default_pil) / sizeof (pci_class_val_t), 1); 1267 1268 /* Range check the result */ 1269 if (pil >= 0xf) 1270 pil = 1; 1271 1272 return (pil); 1273 } 1274 1275 /* 1276 * pci_class_to_intr_weight: 1277 * 1278 * Return the intr_weight for a given PCI device. 1279 */ 1280 int32_t 1281 pci_class_to_intr_weight(dev_info_t *rdip) 1282 { 1283 int32_t intr_weight; 1284 1285 /* default weight is 0% */ 1286 intr_weight = pci_class_to_val(rdip, 1287 "pci-class-intr-weights", pci_default_intr_weight, 1288 sizeof (pci_default_intr_weight) / sizeof (pci_class_val_t), 0); 1289 1290 /* range check the result */ 1291 if (intr_weight < 0) 1292 intr_weight = 0; 1293 if (intr_weight > 1000) 1294 intr_weight = 1000; 1295 1296 return (intr_weight); 1297 } 1298