| From f1dd153121dcb872ae6cba8d52bec97519eb7d97 Mon Sep 17 00:00:00 2001 |
| From: Brian King <brking@linux.vnet.ibm.com> |
| Date: Wed, 22 May 2013 11:07:46 +0000 |
| Subject: powerpc/pseries: Make 32-bit MSI quirk work on systems lacking firmware support |
| |
| From: Brian King <brking@linux.vnet.ibm.com> |
| |
| commit f1dd153121dcb872ae6cba8d52bec97519eb7d97 upstream. |
| |
| Recent commit e61133dda480062d221f09e4fc18f66763f8ecd0 added support |
| for a new firmware feature to force an adapter to use 32 bit MSIs. |
| However, this firmware is not available for all systems. The hack below |
| allows devices needing 32 bit MSIs to work on these systems as well. |
| It is careful to only enable this on Gen2 slots, which should limit |
| this to configurations where this hack is needed and tested to work. |
| |
| [Small change to factor out the hack into a separate function -- BenH] |
| |
| Signed-off-by: Brian King <brking@linux.vnet.ibm.com> |
| Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> |
| Signed-off-by: Kleber Sacilotto de Souza <klebers@linux.vnet.ibm.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| |
| --- |
| arch/powerpc/platforms/pseries/msi.c | 42 ++++++++++++++++++++++++++++++++--- |
| 1 file changed, 39 insertions(+), 3 deletions(-) |
| |
| --- a/arch/powerpc/platforms/pseries/msi.c |
| +++ b/arch/powerpc/platforms/pseries/msi.c |
| @@ -394,6 +394,25 @@ static int check_msix_entries(struct pci |
| return 0; |
| } |
| |
| +static void rtas_hack_32bit_msi_gen2(struct pci_dev *pdev) |
| +{ |
| + u32 addr_hi, addr_lo; |
| + int pos; |
| + |
| + /* |
| + * We should only get in here for IODA1 configs. This is based on the |
| + * fact that we using RTAS for MSIs, we don't have the 32 bit MSI RTAS |
| + * support, and we are in a PCIe Gen2 slot. |
| + */ |
| + dev_info(&pdev->dev, |
| + "rtas_msi: No 32 bit MSI firmware support, forcing 32 bit MSI\n"); |
| + pos = pci_find_capability(pdev, PCI_CAP_ID_MSI); |
| + pci_read_config_dword(pdev, pos + PCI_MSI_ADDRESS_HI, &addr_hi); |
| + addr_lo = 0xffff0000 | ((addr_hi >> (48 - 32)) << 4); |
| + pci_write_config_dword(pdev, pos + PCI_MSI_ADDRESS_LO, addr_lo); |
| + pci_write_config_dword(pdev, pos + PCI_MSI_ADDRESS_HI, 0); |
| +} |
| + |
| static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) |
| { |
| struct pci_dn *pdn; |
| @@ -401,6 +420,7 @@ static int rtas_setup_msi_irqs(struct pc |
| struct msi_desc *entry; |
| struct msi_msg msg; |
| int nvec = nvec_in; |
| + int use_32bit_msi_hack = 0; |
| |
| pdn = get_pdn(pdev); |
| if (!pdn) |
| @@ -428,15 +448,31 @@ static int rtas_setup_msi_irqs(struct pc |
| */ |
| again: |
| if (type == PCI_CAP_ID_MSI) { |
| - if (pdn->force_32bit_msi) |
| + if (pdn->force_32bit_msi) { |
| rc = rtas_change_msi(pdn, RTAS_CHANGE_32MSI_FN, nvec); |
| - else |
| + if (rc < 0) { |
| + /* |
| + * We only want to run the 32 bit MSI hack below if |
| + * the max bus speed is Gen2 speed |
| + */ |
| + if (pdev->bus->max_bus_speed != PCIE_SPEED_5_0GT) |
| + return rc; |
| + |
| + use_32bit_msi_hack = 1; |
| + } |
| + } else |
| + rc = -1; |
| + |
| + if (rc < 0) |
| rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec); |
| |
| - if (rc < 0 && !pdn->force_32bit_msi) { |
| + if (rc < 0) { |
| pr_debug("rtas_msi: trying the old firmware call.\n"); |
| rc = rtas_change_msi(pdn, RTAS_CHANGE_FN, nvec); |
| } |
| + |
| + if (use_32bit_msi_hack && rc > 0) |
| + rtas_hack_32bit_msi_gen2(pdev); |
| } else |
| rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec); |
| |