aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/pci-bridge.h2
-rw-r--r--arch/powerpc/platforms/pseries/msi.c21
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
28static struct pci_dn *get_pdn(struct pci_dev *pdev) 29static 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 */
427again: 429again:
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}
514arch_initcall(rtas_msi_init); 519arch_initcall(rtas_msi_init);
520
521static 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}
528DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x68f2, quirk_radeon);
529DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0xaa68, quirk_radeon);