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