'/ibm,plat-res-int-priorities' contains a list of priorities that the
hypervisor has reserved for its own use. Scan these ranges to choose
the lowest unused priority for the xive spapr backend.

Signed-off-by: Cédric Le Goater <c...@kaod.org>
---
 arch/powerpc/sysdev/xive/spapr.c | 62 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/sysdev/xive/spapr.c b/arch/powerpc/sysdev/xive/spapr.c
index 7fc40047c23d..220331986bd8 100644
--- a/arch/powerpc/sysdev/xive/spapr.c
+++ b/arch/powerpc/sysdev/xive/spapr.c
@@ -532,13 +532,70 @@ static const struct xive_ops xive_spapr_ops = {
        .name                   = "spapr",
 };
 
+/*
+ * get max priority from "/ibm,plat-res-int-priorities"
+ */
+static bool xive_get_max_prio(u8 *max_prio)
+{
+       struct device_node *rootdn;
+       const __be32 *reg;
+       u32 len;
+       int prio, found;
+
+       rootdn = of_find_node_by_path("/");
+       if (!rootdn) {
+               pr_err("not root node found !\n");
+               return false;
+       }
+
+       reg = of_get_property(rootdn, "ibm,plat-res-int-priorities", &len);
+       if (!reg) {
+               pr_err("Failed to read 'ibm,plat-res-int-priorities' 
property\n");
+               return false;
+       }
+
+       if (len % (2 * sizeof(u32)) != 0) {
+               pr_err("invalid 'ibm,plat-res-int-priorities' property\n");
+               return false;
+       }
+
+       /* HW supports priorities in the range [0-7] and 0xFF is a
+        * wildcard priority used to mask. We scan the ranges reserved
+        * by the hypervisor to find the lowest priority we can use.
+        */
+       found = 0xFF;
+       for (prio = 0; prio < 8; prio++) {
+               int reserved = 0;
+               int i;
+
+               for (i = 0; i < len / (2 * sizeof(u32)); i++) {
+                       int base  = be32_to_cpu(reg[2 * i]);
+                       int range = be32_to_cpu(reg[2 * i + 1]);
+
+                       if (prio >= base && prio < base + range)
+                               reserved++;
+               }
+
+               if (!reserved)
+                       found = prio;
+       }
+
+       if (found == 0xFF) {
+               pr_err("no valid priority found in 
'ibm,plat-res-int-priorities'\n");
+               return false;
+       }
+
+       *max_prio = found;
+       return true;
+}
+
 bool xive_spapr_init(void)
 {
        struct device_node *np;
        struct resource r;
        void __iomem *tima;
        struct property *prop;
-       u8 max_prio = 7;
+       u8 max_prio;
        u32 val;
        u32 len;
        const __be32 *reg;
@@ -566,6 +623,9 @@ bool xive_spapr_init(void)
                return false;
        }
 
+       if (!xive_get_max_prio(&max_prio))
+               return false;
+
        /* Feed the IRQ number allocator with the ranges given in the DT */
        reg = of_get_property(np, "ibm,xive-lisn-ranges", &len);
        if (!reg) {
-- 
2.7.5

Reply via email to