Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[sfrench/cifs-2.6.git] / drivers / of / base.c
index 614f0c674995566b839f0066bd32d6c4d76167ba..ae03b1218b06e5f5da9111fecf09cd30ca3d8691 100644 (file)
@@ -135,115 +135,38 @@ int __weak of_node_to_nid(struct device_node *np)
 }
 #endif
 
-/*
- * Assumptions behind phandle_cache implementation:
- *   - phandle property values are in a contiguous range of 1..n
- *
- * If the assumptions do not hold, then
- *   - the phandle lookup overhead reduction provided by the cache
- *     will likely be less
- */
+#define OF_PHANDLE_CACHE_BITS  7
+#define OF_PHANDLE_CACHE_SZ    BIT(OF_PHANDLE_CACHE_BITS)
 
-static struct device_node **phandle_cache;
-static u32 phandle_cache_mask;
+static struct device_node *phandle_cache[OF_PHANDLE_CACHE_SZ];
 
-/*
- * Caller must hold devtree_lock.
- */
-static void __of_free_phandle_cache(void)
+static u32 of_phandle_cache_hash(phandle handle)
 {
-       u32 cache_entries = phandle_cache_mask + 1;
-       u32 k;
-
-       if (!phandle_cache)
-               return;
-
-       for (k = 0; k < cache_entries; k++)
-               of_node_put(phandle_cache[k]);
-
-       kfree(phandle_cache);
-       phandle_cache = NULL;
+       return hash_32(handle, OF_PHANDLE_CACHE_BITS);
 }
 
-int of_free_phandle_cache(void)
-{
-       unsigned long flags;
-
-       raw_spin_lock_irqsave(&devtree_lock, flags);
-
-       __of_free_phandle_cache();
-
-       raw_spin_unlock_irqrestore(&devtree_lock, flags);
-
-       return 0;
-}
-#if !defined(CONFIG_MODULES)
-late_initcall_sync(of_free_phandle_cache);
-#endif
-
 /*
  * Caller must hold devtree_lock.
  */
-void __of_free_phandle_cache_entry(phandle handle)
+void __of_phandle_cache_inv_entry(phandle handle)
 {
-       phandle masked_handle;
+       u32 handle_hash;
        struct device_node *np;
 
        if (!handle)
                return;
 
-       masked_handle = handle & phandle_cache_mask;
-
-       if (phandle_cache) {
-               np = phandle_cache[masked_handle];
-               if (np && handle == np->phandle) {
-                       of_node_put(np);
-                       phandle_cache[masked_handle] = NULL;
-               }
-       }
-}
-
-void of_populate_phandle_cache(void)
-{
-       unsigned long flags;
-       u32 cache_entries;
-       struct device_node *np;
-       u32 phandles = 0;
-
-       raw_spin_lock_irqsave(&devtree_lock, flags);
-
-       __of_free_phandle_cache();
-
-       for_each_of_allnodes(np)
-               if (np->phandle && np->phandle != OF_PHANDLE_ILLEGAL)
-                       phandles++;
-
-       if (!phandles)
-               goto out;
+       handle_hash = of_phandle_cache_hash(handle);
 
-       cache_entries = roundup_pow_of_two(phandles);
-       phandle_cache_mask = cache_entries - 1;
-
-       phandle_cache = kcalloc(cache_entries, sizeof(*phandle_cache),
-                               GFP_ATOMIC);
-       if (!phandle_cache)
-               goto out;
-
-       for_each_of_allnodes(np)
-               if (np->phandle && np->phandle != OF_PHANDLE_ILLEGAL) {
-                       of_node_get(np);
-                       phandle_cache[np->phandle & phandle_cache_mask] = np;
-               }
-
-out:
-       raw_spin_unlock_irqrestore(&devtree_lock, flags);
+       np = phandle_cache[handle_hash];
+       if (np && handle == np->phandle)
+               phandle_cache[handle_hash] = NULL;
 }
 
 void __init of_core_init(void)
 {
        struct device_node *np;
 
-       of_populate_phandle_cache();
 
        /* Create the kset, and register existing nodes */
        mutex_lock(&of_mutex);
@@ -253,8 +176,11 @@ void __init of_core_init(void)
                pr_err("failed to register existing nodes\n");
                return;
        }
-       for_each_of_allnodes(np)
+       for_each_of_allnodes(np) {
                __of_attach_node_sysfs(np);
+               if (np->phandle && !phandle_cache[of_phandle_cache_hash(np->phandle)])
+                       phandle_cache[of_phandle_cache_hash(np->phandle)] = np;
+       }
        mutex_unlock(&of_mutex);
 
        /* Symlink in /proc as required by userspace ABI */
@@ -1271,36 +1197,24 @@ struct device_node *of_find_node_by_phandle(phandle handle)
 {
        struct device_node *np = NULL;
        unsigned long flags;
-       phandle masked_handle;
+       u32 handle_hash;
 
        if (!handle)
                return NULL;
 
+       handle_hash = of_phandle_cache_hash(handle);
+
        raw_spin_lock_irqsave(&devtree_lock, flags);
 
-       masked_handle = handle & phandle_cache_mask;
-
-       if (phandle_cache) {
-               if (phandle_cache[masked_handle] &&
-                   handle == phandle_cache[masked_handle]->phandle)
-                       np = phandle_cache[masked_handle];
-               if (np && of_node_check_flag(np, OF_DETACHED)) {
-                       WARN_ON(1); /* did not uncache np on node removal */
-                       of_node_put(np);
-                       phandle_cache[masked_handle] = NULL;
-                       np = NULL;
-               }
-       }
+       if (phandle_cache[handle_hash] &&
+           handle == phandle_cache[handle_hash]->phandle)
+               np = phandle_cache[handle_hash];
 
        if (!np) {
                for_each_of_allnodes(np)
                        if (np->phandle == handle &&
                            !of_node_check_flag(np, OF_DETACHED)) {
-                               if (phandle_cache) {
-                                       /* will put when removed from cache */
-                                       of_node_get(np);
-                                       phandle_cache[masked_handle] = np;
-                               }
+                               phandle_cache[handle_hash] = np;
                                break;
                        }
        }