浏览代码

powerpc/pseries: Round up MSI-X requests

The pseries firmware currently refuses any non power of two MSI-X
request. Unfortunately most network drivers end up asking for that
because they want a power of two for RX queues and one or two extra
for everything else.

This patch rounds up the firmware request to the next power of two
if the quota allows it. If this fails we fall back to using the
original request size.

Signed-off-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Anton Blanchard 13 年之前
父节点
当前提交
752f5216f1
共有 1 个文件被更改,包括 19 次插入1 次删除
  1. 19 1
      arch/powerpc/platforms/pseries/msi.c

+ 19 - 1
arch/powerpc/platforms/pseries/msi.c

@@ -387,12 +387,13 @@ static int check_msix_entries(struct pci_dev *pdev)
 	return 0;
 	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;
 	struct pci_dn *pdn;
 	int hwirq, virq, i, rc;
 	int hwirq, virq, i, rc;
 	struct msi_desc *entry;
 	struct msi_desc *entry;
 	struct msi_msg msg;
 	struct msi_msg msg;
+	int nvec = nvec_in;
 
 
 	pdn = get_pdn(pdev);
 	pdn = get_pdn(pdev);
 	if (!pdn)
 	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))
 	if (type == PCI_CAP_ID_MSIX && check_msix_entries(pdev))
 		return -EINVAL;
 		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
 	 * Try the new more explicit firmware interface, if that fails fall
 	 * back to the old interface. The old interface is known to never
 	 * back to the old interface. The old interface is known to never
 	 * return MSI-Xs.
 	 * return MSI-Xs.
 	 */
 	 */
+again:
 	if (type == PCI_CAP_ID_MSI) {
 	if (type == PCI_CAP_ID_MSI) {
 		rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec);
 		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);
 		rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec);
 
 
 	if (rc != nvec) {
 	if (rc != nvec) {
+		if (nvec != nvec_in) {
+			nvec = nvec_in;
+			goto again;
+		}
 		pr_debug("rtas_msi: rtas_change_msi() failed\n");
 		pr_debug("rtas_msi: rtas_change_msi() failed\n");
 		return rc;
 		return rc;
 	}
 	}