Merge commit 'ftrace/function-graph' into next
[deliverable/linux.git] / arch / powerpc / platforms / pseries / msi.c
index 6063ea2f67ad1512b4ab0b44bc9a559daa97f8df..073b518338a3f601189109a7b2e597318cd1fa85 100644 (file)
@@ -70,11 +70,17 @@ static int rtas_change_msi(struct pci_dn *pdn, u32 func, u32 num_irqs)
                seq_num = rtas_ret[1];
        } while (rtas_busy_delay(rc));
 
-       if (rc == 0) /* Success */
+       /*
+        * If the RTAS call succeeded, return the number of irqs allocated.
+        * If not, make sure we return a negative error code.
+        */
+       if (rc == 0)
                rc = rtas_ret[0];
+       else if (rc > 0)
+               rc = -rc;
 
-       pr_debug("rtas_msi: ibm,change_msi(func=%d,num=%d) = (%d)\n",
-                func, num_irqs, rc);
+       pr_debug("rtas_msi: ibm,change_msi(func=%d,num=%d), got %d rc = %d\n",
+                func, num_irqs, rtas_ret[0], rc);
 
        return rc;
 }
@@ -128,7 +134,7 @@ static void rtas_teardown_msi_irqs(struct pci_dev *pdev)
        rtas_disable_msi(pdev);
 }
 
-static int check_req_msi(struct pci_dev *pdev, int nvec)
+static int check_req(struct pci_dev *pdev, int nvec, char *prop_name)
 {
        struct device_node *dn;
        struct pci_dn *pdn;
@@ -140,24 +146,34 @@ static int check_req_msi(struct pci_dev *pdev, int nvec)
 
        dn = pdn->node;
 
-       req_msi = of_get_property(dn, "ibm,req#msi", NULL);
+       req_msi = of_get_property(dn, prop_name, NULL);
        if (!req_msi) {
-               pr_debug("rtas_msi: No ibm,req#msi on %s\n", dn->full_name);
+               pr_debug("rtas_msi: No %s on %s\n", prop_name, dn->full_name);
                return -ENOENT;
        }
 
        if (*req_msi < nvec) {
-               pr_debug("rtas_msi: ibm,req#msi requests < %d MSIs\n", nvec);
+               pr_debug("rtas_msi: %s requests < %d MSIs\n", prop_name, nvec);
                return -ENOSPC;
        }
 
        return 0;
 }
 
+static int check_req_msi(struct pci_dev *pdev, int nvec)
+{
+       return check_req(pdev, nvec, "ibm,req#msi");
+}
+
+static int check_req_msix(struct pci_dev *pdev, int nvec)
+{
+       return check_req(pdev, nvec, "ibm,req#msi-x");
+}
+
 static int rtas_msi_check_device(struct pci_dev *pdev, int nvec, int type)
 {
        if (type == PCI_CAP_ID_MSIX)
-               pr_debug("rtas_msi: MSI-X untested, trying anyway.\n");
+               return check_req_msix(pdev, nvec);
 
        return check_req_msi(pdev, nvec);
 }
@@ -167,6 +183,7 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
        struct pci_dn *pdn;
        int hwirq, virq, i, rc;
        struct msi_desc *entry;
+       struct msi_msg msg;
 
        pdn = get_pdn(pdev);
        if (!pdn)
@@ -180,7 +197,7 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
        if (type == PCI_CAP_ID_MSI) {
                rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec);
 
-               if (rc != nvec) {
+               if (rc < 0) {
                        pr_debug("rtas_msi: trying the old firmware call.\n");
                        rc = rtas_change_msi(pdn, RTAS_CHANGE_FN, nvec);
                }
@@ -189,41 +206,35 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
 
        if (rc != nvec) {
                pr_debug("rtas_msi: rtas_change_msi() failed\n");
-
-               /*
-                * In case of an error it's not clear whether the device is
-                * left with MSI enabled or not, so we explicitly disable.
-                */
-               goto out_free;
+               return rc;
        }
 
        i = 0;
        list_for_each_entry(entry, &pdev->msi_list, list) {
-               hwirq = rtas_query_irq_number(pdn, i);
+               hwirq = rtas_query_irq_number(pdn, i++);
                if (hwirq < 0) {
-                       rc = hwirq;
                        pr_debug("rtas_msi: error (%d) getting hwirq\n", rc);
-                       goto out_free;
+                       return hwirq;
                }
 
                virq = irq_create_mapping(NULL, hwirq);
 
                if (virq == NO_IRQ) {
                        pr_debug("rtas_msi: Failed mapping hwirq %d\n", hwirq);
-                       rc = -ENOSPC;
-                       goto out_free;
+                       return -ENOSPC;
                }
 
                dev_dbg(&pdev->dev, "rtas_msi: allocated virq %d\n", virq);
                set_irq_msi(virq, entry);
+
+               /* Read config space back so we can restore after reset */
+               read_msi_msg(virq, &msg);
+               entry->msg = msg;
+
                unmask_msi_irq(virq);
        }
 
        return 0;
-
- out_free:
-       rtas_teardown_msi_irqs(pdev);
-       return rc;
 }
 
 static void rtas_msi_pci_irq_fixup(struct pci_dev *pdev)
@@ -235,8 +246,8 @@ static void rtas_msi_pci_irq_fixup(struct pci_dev *pdev)
        }
 
        /* No MSI -> MSIs can't have been assigned by fw, leave LSI */
-       if (check_req_msi(pdev, 1)) {
-               dev_dbg(&pdev->dev, "rtas_msi: no req#msi, nothing to do.\n");
+       if (check_req_msi(pdev, 1) && check_req_msix(pdev, 1)) {
+               dev_dbg(&pdev->dev, "rtas_msi: no req#msi/x, nothing to do.\n");
                return;
        }
 
This page took 0.028135 seconds and 5 git commands to generate.