diff options
| -rw-r--r-- | arch/powerpc/platforms/pseries/msi.c | 40 |
1 files changed, 37 insertions, 3 deletions
diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index d34f4ffdb796..6d2f0abce6fa 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c | |||
| @@ -374,6 +374,23 @@ static int check_msix_entries(struct pci_dev *pdev) | |||
| 374 | return 0; | 374 | return 0; |
| 375 | } | 375 | } |
| 376 | 376 | ||
| 377 | static void rtas_hack_32bit_msi_gen2(struct pci_dev *pdev) | ||
| 378 | { | ||
| 379 | u32 addr_hi, addr_lo; | ||
| 380 | |||
| 381 | /* | ||
| 382 | * We should only get in here for IODA1 configs. This is based on the | ||
| 383 | * fact that we using RTAS for MSIs, we don't have the 32 bit MSI RTAS | ||
| 384 | * support, and we are in a PCIe Gen2 slot. | ||
| 385 | */ | ||
| 386 | dev_info(&pdev->dev, | ||
| 387 | "rtas_msi: No 32 bit MSI firmware support, forcing 32 bit MSI\n"); | ||
| 388 | pci_read_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_HI, &addr_hi); | ||
| 389 | addr_lo = 0xffff0000 | ((addr_hi >> (48 - 32)) << 4); | ||
| 390 | pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_LO, addr_lo); | ||
| 391 | pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_HI, 0); | ||
| 392 | } | ||
| 393 | |||
| 377 | static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) | 394 | static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) |
| 378 | { | 395 | { |
| 379 | struct pci_dn *pdn; | 396 | struct pci_dn *pdn; |
| @@ -381,6 +398,7 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) | |||
| 381 | struct msi_desc *entry; | 398 | struct msi_desc *entry; |
| 382 | struct msi_msg msg; | 399 | struct msi_msg msg; |
| 383 | int nvec = nvec_in; | 400 | int nvec = nvec_in; |
| 401 | int use_32bit_msi_hack = 0; | ||
| 384 | 402 | ||
| 385 | pdn = pci_get_pdn(pdev); | 403 | pdn = pci_get_pdn(pdev); |
| 386 | if (!pdn) | 404 | if (!pdn) |
| @@ -408,15 +426,31 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) | |||
| 408 | */ | 426 | */ |
| 409 | again: | 427 | again: |
| 410 | if (type == PCI_CAP_ID_MSI) { | 428 | if (type == PCI_CAP_ID_MSI) { |
| 411 | if (pdn->force_32bit_msi) | 429 | if (pdn->force_32bit_msi) { |
| 412 | rc = rtas_change_msi(pdn, RTAS_CHANGE_32MSI_FN, nvec); | 430 | rc = rtas_change_msi(pdn, RTAS_CHANGE_32MSI_FN, nvec); |
| 413 | else | 431 | if (rc < 0) { |
| 432 | /* | ||
| 433 | * We only want to run the 32 bit MSI hack below if | ||
| 434 | * the max bus speed is Gen2 speed | ||
| 435 | */ | ||
| 436 | if (pdev->bus->max_bus_speed != PCIE_SPEED_5_0GT) | ||
| 437 | return rc; | ||
| 438 | |||
| 439 | use_32bit_msi_hack = 1; | ||
| 440 | } | ||
| 441 | } else | ||
| 442 | rc = -1; | ||
| 443 | |||
| 444 | if (rc < 0) | ||
| 414 | rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec); | 445 | rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec); |
| 415 | 446 | ||
| 416 | if (rc < 0 && !pdn->force_32bit_msi) { | 447 | if (rc < 0) { |
| 417 | pr_debug("rtas_msi: trying the old firmware call.\n"); | 448 | pr_debug("rtas_msi: trying the old firmware call.\n"); |
| 418 | rc = rtas_change_msi(pdn, RTAS_CHANGE_FN, nvec); | 449 | rc = rtas_change_msi(pdn, RTAS_CHANGE_FN, nvec); |
| 419 | } | 450 | } |
| 451 | |||
| 452 | if (use_32bit_msi_hack && rc > 0) | ||
| 453 | rtas_hack_32bit_msi_gen2(pdev); | ||
| 420 | } else | 454 | } else |
| 421 | rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec); | 455 | rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec); |
| 422 | 456 | ||
