]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/of/base.c
Merge tag 'nfs-for-4.20-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
[linux.git] / drivers / of / base.c
index 74eaedd5b860f1c1fd42faa187d5cda802d0ae8e..13ebb16be64e7bfe16669b0a9701f9e424914af3 100644 (file)
@@ -67,6 +67,7 @@ bool of_node_name_eq(const struct device_node *np, const char *name)
 
        return (strlen(name) == len) && (strncmp(node_name, name, len) == 0);
 }
+EXPORT_SYMBOL(of_node_name_eq);
 
 bool of_node_name_prefix(const struct device_node *np, const char *prefix)
 {
@@ -75,6 +76,7 @@ bool of_node_name_prefix(const struct device_node *np, const char *prefix)
 
        return strncmp(kbasename(np->full_name), prefix, strlen(prefix)) == 0;
 }
+EXPORT_SYMBOL(of_node_name_prefix);
 
 int of_n_addr_cells(struct device_node *np)
 {
@@ -330,6 +332,8 @@ static bool __of_find_n_match_cpu_property(struct device_node *cpun,
 
        ac = of_n_addr_cells(cpun);
        cell = of_get_property(cpun, prop_name, &prop_len);
+       if (!cell && !ac && arch_match_cpu_phys_id(cpu, 0))
+               return true;
        if (!cell || !ac)
                return false;
        prop_len /= sizeof(*cell) * ac;
@@ -390,7 +394,7 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
 {
        struct device_node *cpun;
 
-       for_each_node_by_type(cpun, "cpu") {
+       for_each_of_cpu_node(cpun) {
                if (arch_find_n_match_cpu_physical_id(cpun, cpu, thread))
                        return cpun;
        }
@@ -744,6 +748,45 @@ struct device_node *of_get_next_available_child(const struct device_node *node,
 }
 EXPORT_SYMBOL(of_get_next_available_child);
 
+/**
+ *     of_get_next_cpu_node - Iterate on cpu nodes
+ *     @prev:  previous child of the /cpus node, or NULL to get first
+ *
+ *     Returns a cpu node pointer with refcount incremented, use of_node_put()
+ *     on it when done. Returns NULL when prev is the last child. Decrements
+ *     the refcount of prev.
+ */
+struct device_node *of_get_next_cpu_node(struct device_node *prev)
+{
+       struct device_node *next = NULL;
+       unsigned long flags;
+       struct device_node *node;
+
+       if (!prev)
+               node = of_find_node_by_path("/cpus");
+
+       raw_spin_lock_irqsave(&devtree_lock, flags);
+       if (prev)
+               next = prev->sibling;
+       else if (node) {
+               next = node->child;
+               of_node_put(node);
+       }
+       for (; next; next = next->sibling) {
+               if (!(of_node_name_eq(next, "cpu") ||
+                     (next->type && !of_node_cmp(next->type, "cpu"))))
+                       continue;
+               if (!__of_device_is_available(next))
+                       continue;
+               if (of_node_get(next))
+                       break;
+       }
+       of_node_put(prev);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
+       return next;
+}
+EXPORT_SYMBOL(of_get_next_cpu_node);
+
 /**
  * of_get_compatible_child - Find compatible child node
  * @parent:    parent node
@@ -2013,7 +2056,7 @@ struct device_node *of_find_next_cache_node(const struct device_node *np)
        /* OF on pmac has nodes instead of properties named "l2-cache"
         * beneath CPU nodes.
         */
-       if (!strcmp(np->type, "cpu"))
+       if (IS_ENABLED(CONFIG_PPC_PMAC) && !strcmp(np->type, "cpu"))
                for_each_child_of_node(np, child)
                        if (!strcmp(child->type, "cache"))
                                return child;
@@ -2045,3 +2088,105 @@ int of_find_last_cache_level(unsigned int cpu)
 
        return cache_level;
 }
+
+/**
+ * of_map_rid - Translate a requester ID through a downstream mapping.
+ * @np: root complex device node.
+ * @rid: device requester ID to map.
+ * @map_name: property name of the map to use.
+ * @map_mask_name: optional property name of the mask to use.
+ * @target: optional pointer to a target device node.
+ * @id_out: optional pointer to receive the translated ID.
+ *
+ * Given a device requester ID, look up the appropriate implementation-defined
+ * platform ID and/or the target device which receives transactions on that
+ * ID, as per the "iommu-map" and "msi-map" bindings. Either of @target or
+ * @id_out may be NULL if only the other is required. If @target points to
+ * a non-NULL device node pointer, only entries targeting that node will be
+ * matched; if it points to a NULL value, it will receive the device node of
+ * the first matching target phandle, with a reference held.
+ *
+ * Return: 0 on success or a standard error code on failure.
+ */
+int of_map_rid(struct device_node *np, u32 rid,
+              const char *map_name, const char *map_mask_name,
+              struct device_node **target, u32 *id_out)
+{
+       u32 map_mask, masked_rid;
+       int map_len;
+       const __be32 *map = NULL;
+
+       if (!np || !map_name || (!target && !id_out))
+               return -EINVAL;
+
+       map = of_get_property(np, map_name, &map_len);
+       if (!map) {
+               if (target)
+                       return -ENODEV;
+               /* Otherwise, no map implies no translation */
+               *id_out = rid;
+               return 0;
+       }
+
+       if (!map_len || map_len % (4 * sizeof(*map))) {
+               pr_err("%pOF: Error: Bad %s length: %d\n", np,
+                       map_name, map_len);
+               return -EINVAL;
+       }
+
+       /* The default is to select all bits. */
+       map_mask = 0xffffffff;
+
+       /*
+        * Can be overridden by "{iommu,msi}-map-mask" property.
+        * If of_property_read_u32() fails, the default is used.
+        */
+       if (map_mask_name)
+               of_property_read_u32(np, map_mask_name, &map_mask);
+
+       masked_rid = map_mask & rid;
+       for ( ; map_len > 0; map_len -= 4 * sizeof(*map), map += 4) {
+               struct device_node *phandle_node;
+               u32 rid_base = be32_to_cpup(map + 0);
+               u32 phandle = be32_to_cpup(map + 1);
+               u32 out_base = be32_to_cpup(map + 2);
+               u32 rid_len = be32_to_cpup(map + 3);
+
+               if (rid_base & ~map_mask) {
+                       pr_err("%pOF: Invalid %s translation - %s-mask (0x%x) ignores rid-base (0x%x)\n",
+                               np, map_name, map_name,
+                               map_mask, rid_base);
+                       return -EFAULT;
+               }
+
+               if (masked_rid < rid_base || masked_rid >= rid_base + rid_len)
+                       continue;
+
+               phandle_node = of_find_node_by_phandle(phandle);
+               if (!phandle_node)
+                       return -ENODEV;
+
+               if (target) {
+                       if (*target)
+                               of_node_put(phandle_node);
+                       else
+                               *target = phandle_node;
+
+                       if (*target != phandle_node)
+                               continue;
+               }
+
+               if (id_out)
+                       *id_out = masked_rid - rid_base + out_base;
+
+               pr_debug("%pOF: %s, using mask %08x, rid-base: %08x, out-base: %08x, length: %08x, rid: %08x -> %08x\n",
+                       np, map_name, map_mask, rid_base, out_base,
+                       rid_len, rid, masked_rid - rid_base + out_base);
+               return 0;
+       }
+
+       pr_err("%pOF: Invalid %s translation - no match for rid 0x%x on %pOF\n",
+               np, map_name, rid, target && *target ? *target : NULL);
+       return -EFAULT;
+}
+EXPORT_SYMBOL_GPL(of_map_rid);