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;
}
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;
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);
}
struct pci_dn *pdn;
int hwirq, virq, i, rc;
struct msi_desc *entry;
+ struct msi_msg msg;
pdn = get_pdn(pdev);
if (!pdn)
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);
}
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)
}
/* 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;
}