Skip to content

Commit

Permalink
powerpc/pseries: Force 32 bit MSIs for devices that require it
Browse files Browse the repository at this point in the history
The following patch implements a new PAPR change which allows
the OS to force the use of 32 bit MSIs, regardless of what
the PCI capabilities indicate. This is required for some
devices that advertise support for 64 bit MSIs but don't
actually support them.

Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
  • Loading branch information
Brian King authored and Benjamin Herrenschmidt committed May 5, 2013
1 parent c2fd22d commit e61133d
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 3 deletions.
2 changes: 2 additions & 0 deletions arch/powerpc/include/asm/pci-bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ struct pci_dn {

int pci_ext_config_space; /* for pci devices */

int force_32bit_msi:1;

struct pci_dev *pcidev; /* back-pointer to the pci device */
#ifdef CONFIG_EEH
struct eeh_dev *edev; /* eeh device */
Expand Down
21 changes: 18 additions & 3 deletions arch/powerpc/platforms/pseries/msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ static int query_token, change_token;
#define RTAS_RESET_FN 2
#define RTAS_CHANGE_MSI_FN 3
#define RTAS_CHANGE_MSIX_FN 4
#define RTAS_CHANGE_32MSI_FN 5

static struct pci_dn *get_pdn(struct pci_dev *pdev)
{
Expand Down Expand Up @@ -58,7 +59,8 @@ static int rtas_change_msi(struct pci_dn *pdn, u32 func, u32 num_irqs)

seq_num = 1;
do {
if (func == RTAS_CHANGE_MSI_FN || func == RTAS_CHANGE_MSIX_FN)
if (func == RTAS_CHANGE_MSI_FN || func == RTAS_CHANGE_MSIX_FN ||
func == RTAS_CHANGE_32MSI_FN)
rc = rtas_call(change_token, 6, 4, rtas_ret, addr,
BUID_HI(buid), BUID_LO(buid),
func, num_irqs, seq_num);
Expand Down Expand Up @@ -426,9 +428,12 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type)
*/
again:
if (type == PCI_CAP_ID_MSI) {
rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec);
if (pdn->force_32bit_msi)
rc = rtas_change_msi(pdn, RTAS_CHANGE_32MSI_FN, nvec);
else
rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec);

if (rc < 0) {
if (rc < 0 && !pdn->force_32bit_msi) {
pr_debug("rtas_msi: trying the old firmware call.\n");
rc = rtas_change_msi(pdn, RTAS_CHANGE_FN, nvec);
}
Expand Down Expand Up @@ -512,3 +517,13 @@ static int rtas_msi_init(void)
return 0;
}
arch_initcall(rtas_msi_init);

static void quirk_radeon(struct pci_dev *dev)
{
struct pci_dn *pdn = get_pdn(dev);

if (pdn)
pdn->force_32bit_msi = 1;
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x68f2, quirk_radeon);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0xaa68, quirk_radeon);

0 comments on commit e61133d

Please sign in to comment.