diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/include/asm/pci-bridge.h | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/msi.c | 21 |
2 files changed, 20 insertions, 3 deletions
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h index ffbc5fd549ac..0694f73db22d 100644 --- a/arch/powerpc/include/asm/pci-bridge.h +++ b/arch/powerpc/include/asm/pci-bridge.h | |||
@@ -163,6 +163,8 @@ struct pci_dn { | |||
163 | 163 | ||
164 | int pci_ext_config_space; /* for pci devices */ | 164 | int pci_ext_config_space; /* for pci devices */ |
165 | 165 | ||
166 | int force_32bit_msi:1; | ||
167 | |||
166 | struct pci_dev *pcidev; /* back-pointer to the pci device */ | 168 | struct pci_dev *pcidev; /* back-pointer to the pci device */ |
167 | #ifdef CONFIG_EEH | 169 | #ifdef CONFIG_EEH |
168 | struct eeh_dev *edev; /* eeh device */ | 170 | struct eeh_dev *edev; /* eeh device */ |
diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index e5b084723131..420524e6f8c9 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c | |||
@@ -24,6 +24,7 @@ static int query_token, change_token; | |||
24 | #define RTAS_RESET_FN 2 | 24 | #define RTAS_RESET_FN 2 |
25 | #define RTAS_CHANGE_MSI_FN 3 | 25 | #define RTAS_CHANGE_MSI_FN 3 |
26 | #define RTAS_CHANGE_MSIX_FN 4 | 26 | #define RTAS_CHANGE_MSIX_FN 4 |
27 | #define RTAS_CHANGE_32MSI_FN 5 | ||
27 | 28 | ||
28 | static struct pci_dn *get_pdn(struct pci_dev *pdev) | 29 | static struct pci_dn *get_pdn(struct pci_dev *pdev) |
29 | { | 30 | { |
@@ -58,7 +59,8 @@ static int rtas_change_msi(struct pci_dn *pdn, u32 func, u32 num_irqs) | |||
58 | 59 | ||
59 | seq_num = 1; | 60 | seq_num = 1; |
60 | do { | 61 | do { |
61 | if (func == RTAS_CHANGE_MSI_FN || func == RTAS_CHANGE_MSIX_FN) | 62 | if (func == RTAS_CHANGE_MSI_FN || func == RTAS_CHANGE_MSIX_FN || |
63 | func == RTAS_CHANGE_32MSI_FN) | ||
62 | rc = rtas_call(change_token, 6, 4, rtas_ret, addr, | 64 | rc = rtas_call(change_token, 6, 4, rtas_ret, addr, |
63 | BUID_HI(buid), BUID_LO(buid), | 65 | BUID_HI(buid), BUID_LO(buid), |
64 | func, num_irqs, seq_num); | 66 | func, num_irqs, seq_num); |
@@ -426,9 +428,12 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) | |||
426 | */ | 428 | */ |
427 | again: | 429 | again: |
428 | if (type == PCI_CAP_ID_MSI) { | 430 | if (type == PCI_CAP_ID_MSI) { |
429 | rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec); | 431 | if (pdn->force_32bit_msi) |
432 | rc = rtas_change_msi(pdn, RTAS_CHANGE_32MSI_FN, nvec); | ||
433 | else | ||
434 | rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec); | ||
430 | 435 | ||
431 | if (rc < 0) { | 436 | if (rc < 0 && !pdn->force_32bit_msi) { |
432 | pr_debug("rtas_msi: trying the old firmware call.\n"); | 437 | pr_debug("rtas_msi: trying the old firmware call.\n"); |
433 | rc = rtas_change_msi(pdn, RTAS_CHANGE_FN, nvec); | 438 | rc = rtas_change_msi(pdn, RTAS_CHANGE_FN, nvec); |
434 | } | 439 | } |
@@ -512,3 +517,13 @@ static int rtas_msi_init(void) | |||
512 | return 0; | 517 | return 0; |
513 | } | 518 | } |
514 | arch_initcall(rtas_msi_init); | 519 | arch_initcall(rtas_msi_init); |
520 | |||
521 | static void quirk_radeon(struct pci_dev *dev) | ||
522 | { | ||
523 | struct pci_dn *pdn = get_pdn(dev); | ||
524 | |||
525 | if (pdn) | ||
526 | pdn->force_32bit_msi = 1; | ||
527 | } | ||
528 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x68f2, quirk_radeon); | ||
529 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0xaa68, quirk_radeon); | ||