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) 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\n", 433 (void *)rdip)); 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