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