aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/pseries/msi.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/pseries/msi.c')
-rw-r--r--arch/powerpc/platforms/pseries/msi.c26
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)
210static struct device_node *find_pe_dn(struct pci_dev *dev, int *total) 210static 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
390static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) 394static 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 */
426again:
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 }