of/irq: improve error report on irq discovery process failure
authorGuilherme G. Piccoli <gpiccoli@linux.vnet.ibm.com>
Mon, 5 Dec 2016 13:59:16 +0000 (11:59 -0200)
committerRob Herring <robh@kernel.org>
Mon, 9 Jan 2017 15:52:17 +0000 (09:52 -0600)
On PowerPC machines some PCI slots might not have level triggered
interrupts capability (also know as level signaled interrupts),
leading of_irq_parse_pci() to complain by presenting error messages
on the kernel log - in this case, the properties "interrupt-map" and
"interrupt-map-mask" are not present on device's node in the device
tree.

This patch introduces a different message for this specific case,
and also reduces its level from error to warning. Besides, we warn
(once) that possibly some PCI slots on the system have no level
triggered interrupts available.
We changed some error return codes too on function of_irq_parse_raw()
in order other failure's cases can be presented in a more precise way.

Before this patch, when an adapter was plugged in a slot without level
interrupts capabilitiy on PowerPC, we saw a generic error message
like this:

    [54.239] pci 002d:70:00.0: of_irq_parse_pci() failed with rc=-22

Now, with this applied, we see the following specific message:

    [16.154] pci 0014:60:00.1: of_irq_parse_pci: no interrupt-map found,
    INTx interrupts not available

Finally, we standardize the error path in of_irq_parse_raw() by always
taking the fail path instead of returning directly from the loop.

Signed-off-by: Guilherme G. Piccoli <gpiccoli@linux.vnet.ibm.com>
Signed-off-by: Rob Herring <robh@kernel.org>
drivers/of/irq.c
drivers/of/of_pci_irq.c

index 3fda9a32defbbdabbed554fb9f9dfd5f42056e0f..7c56b72d1dc6d1090b990402d07b4404856e1693 100644 (file)
@@ -104,7 +104,7 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
        const __be32 *match_array = initial_match_array;
        const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 };
        u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
-       int imaplen, match, i;
+       int imaplen, match, i, rc = -EINVAL;
 
 #ifdef DEBUG
        of_print_phandle_args("of_irq_parse_raw: ", out_irq);
@@ -134,7 +134,7 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
        pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize);
 
        if (out_irq->args_count != intsize)
-               return -EINVAL;
+               goto fail;
 
        /* Look for this #address-cells. We have to implement the old linux
         * trick of looking for the parent here as some device-trees rely on it
@@ -153,8 +153,10 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
        pr_debug(" -> addrsize=%d\n", addrsize);
 
        /* Range check so that the temporary buffer doesn't overflow */
-       if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS))
+       if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS)) {
+               rc = -EFAULT;
                goto fail;
+       }
 
        /* Precalculate the match array - this simplifies match loop */
        for (i = 0; i < addrsize; i++)
@@ -240,10 +242,11 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
                            newintsize, newaddrsize);
 
                        /* Check for malformed properties */
-                       if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS))
-                               goto fail;
-                       if (imaplen < (newaddrsize + newintsize))
+                       if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS)
+                           || (imaplen < (newaddrsize + newintsize))) {
+                               rc = -EFAULT;
                                goto fail;
+                       }
 
                        imap += newaddrsize + newintsize;
                        imaplen -= newaddrsize + newintsize;
@@ -271,11 +274,13 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
                ipar = newpar;
                newpar = NULL;
        }
+       rc = -ENOENT; /* No interrupt-map found */
+
  fail:
        of_node_put(ipar);
        of_node_put(newpar);
 
-       return -EINVAL;
+       return rc;
 }
 EXPORT_SYMBOL_GPL(of_irq_parse_raw);
 
index 2306313c0029a095c1fefa6b7b5eb0ff28f1cf9c..c175d9cd0bb53efc39b2adad42820bbab7fc90d5 100644 (file)
@@ -93,7 +93,15 @@ int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq
                goto err;
        return 0;
 err:
-       dev_err(&pdev->dev, "of_irq_parse_pci() failed with rc=%d\n", rc);
+       if (rc == -ENOENT) {
+               dev_warn(&pdev->dev,
+                       "%s: no interrupt-map found, INTx interrupts not available\n",
+                       __func__);
+               pr_warn_once("%s: possibly some PCI slots don't have level triggered interrupts capability\n",
+                       __func__);
+       } else {
+               dev_err(&pdev->dev, "%s: failed with rc=%d\n", __func__, rc);
+       }
        return rc;
 }
 EXPORT_SYMBOL_GPL(of_irq_parse_pci);