|
@@ -387,12 +387,13 @@ static int check_msix_entries(struct pci_dev *pdev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
|
|
|
+static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type)
|
|
|
{
|
|
|
struct pci_dn *pdn;
|
|
|
int hwirq, virq, i, rc;
|
|
|
struct msi_desc *entry;
|
|
|
struct msi_msg msg;
|
|
|
+ int nvec = nvec_in;
|
|
|
|
|
|
pdn = get_pdn(pdev);
|
|
|
if (!pdn)
|
|
@@ -401,11 +402,24 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
|
|
|
if (type == PCI_CAP_ID_MSIX && check_msix_entries(pdev))
|
|
|
return -EINVAL;
|
|
|
|
|
|
+ /*
|
|
|
+ * Firmware currently refuse any non power of two allocation
|
|
|
+ * so we round up if the quota will allow it.
|
|
|
+ */
|
|
|
+ if (type == PCI_CAP_ID_MSIX) {
|
|
|
+ int m = roundup_pow_of_two(nvec);
|
|
|
+ int quota = msi_quota_for_device(pdev, m);
|
|
|
+
|
|
|
+ if (quota >= m)
|
|
|
+ nvec = m;
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* Try the new more explicit firmware interface, if that fails fall
|
|
|
* back to the old interface. The old interface is known to never
|
|
|
* return MSI-Xs.
|
|
|
*/
|
|
|
+again:
|
|
|
if (type == PCI_CAP_ID_MSI) {
|
|
|
rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec);
|
|
|
|
|
@@ -417,6 +431,10 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
|
|
|
rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec);
|
|
|
|
|
|
if (rc != nvec) {
|
|
|
+ if (nvec != nvec_in) {
|
|
|
+ nvec = nvec_in;
|
|
|
+ goto again;
|
|
|
+ }
|
|
|
pr_debug("rtas_msi: rtas_change_msi() failed\n");
|
|
|
return rc;
|
|
|
}
|