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