diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries/msi.c')
| -rw-r--r-- | arch/powerpc/platforms/pseries/msi.c | 26 |
1 files changed, 24 insertions, 2 deletions
diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 109fdb75578d..d19f4977c834 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c | |||
| @@ -210,6 +210,7 @@ static struct device_node *find_pe_total_msi(struct pci_dev *dev, int *total) | |||
| 210 | static struct device_node *find_pe_dn(struct pci_dev *dev, int *total) | 210 | static struct device_node *find_pe_dn(struct pci_dev *dev, int *total) |
| 211 | { | 211 | { |
| 212 | struct device_node *dn; | 212 | struct device_node *dn; |
| 213 | struct eeh_dev *edev; | ||
| 213 | 214 | ||
| 214 | /* Found our PE and assume 8 at that point. */ | 215 | /* Found our PE and assume 8 at that point. */ |
| 215 | 216 | ||
| @@ -217,7 +218,10 @@ static struct device_node *find_pe_dn(struct pci_dev *dev, int *total) | |||
| 217 | if (!dn) | 218 | if (!dn) |
| 218 | return NULL; | 219 | return NULL; |
| 219 | 220 | ||
| 220 | dn = eeh_find_device_pe(dn); | 221 | /* Get the top level device in the PE */ |
| 222 | edev = of_node_to_eeh_dev(dn); | ||
| 223 | edev = list_first_entry(&edev->pe->edevs, struct eeh_dev, list); | ||
| 224 | dn = eeh_dev_to_of_node(edev); | ||
| 221 | if (!dn) | 225 | if (!dn) |
| 222 | return NULL; | 226 | return NULL; |
| 223 | 227 | ||
| @@ -387,12 +391,13 @@ static int check_msix_entries(struct pci_dev *pdev) | |||
| 387 | return 0; | 391 | return 0; |
| 388 | } | 392 | } |
| 389 | 393 | ||
| 390 | static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | 394 | static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) |
| 391 | { | 395 | { |
| 392 | struct pci_dn *pdn; | 396 | struct pci_dn *pdn; |
| 393 | int hwirq, virq, i, rc; | 397 | int hwirq, virq, i, rc; |
| 394 | struct msi_desc *entry; | 398 | struct msi_desc *entry; |
| 395 | struct msi_msg msg; | 399 | struct msi_msg msg; |
| 400 | int nvec = nvec_in; | ||
| 396 | 401 | ||
| 397 | pdn = get_pdn(pdev); | 402 | pdn = get_pdn(pdev); |
| 398 | if (!pdn) | 403 | if (!pdn) |
| @@ -402,10 +407,23 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
| 402 | return -EINVAL; | 407 | return -EINVAL; |
| 403 | 408 | ||
| 404 | /* | 409 | /* |
| 410 | * Firmware currently refuse any non power of two allocation | ||
| 411 | * so we round up if the quota will allow it. | ||
| 412 | */ | ||
| 413 | if (type == PCI_CAP_ID_MSIX) { | ||
| 414 | int m = roundup_pow_of_two(nvec); | ||
| 415 | int quota = msi_quota_for_device(pdev, m); | ||
| 416 | |||
| 417 | if (quota >= m) | ||
| 418 | nvec = m; | ||
| 419 | } | ||
| 420 | |||
| 421 | /* | ||
| 405 | * Try the new more explicit firmware interface, if that fails fall | 422 | * Try the new more explicit firmware interface, if that fails fall |
| 406 | * back to the old interface. The old interface is known to never | 423 | * back to the old interface. The old interface is known to never |
| 407 | * return MSI-Xs. | 424 | * return MSI-Xs. |
| 408 | */ | 425 | */ |
| 426 | again: | ||
| 409 | if (type == PCI_CAP_ID_MSI) { | 427 | if (type == PCI_CAP_ID_MSI) { |
| 410 | rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec); | 428 | rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec); |
| 411 | 429 | ||
| @@ -417,6 +435,10 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
| 417 | rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec); | 435 | rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec); |
| 418 | 436 | ||
| 419 | if (rc != nvec) { | 437 | if (rc != nvec) { |
| 438 | if (nvec != nvec_in) { | ||
| 439 | nvec = nvec_in; | ||
| 440 | goto again; | ||
| 441 | } | ||
| 420 | pr_debug("rtas_msi: rtas_change_msi() failed\n"); | 442 | pr_debug("rtas_msi: rtas_change_msi() failed\n"); |
| 421 | return rc; | 443 | return rc; |
| 422 | } | 444 | } |
