* the table if any of the mentioned functions have been invoked in the interim.
  *
  * Locking: The internal device_opp and opp structures are RCU protected.
- * To simplify the logic, we pretend we are updater and hold relevant mutex here
- * Callers should ensure that this function is *NOT* called under RCU protection
- * or in contexts where mutex locking cannot be used.
+ * Since we just use the regular accessor functions to access the internal data
+ * structures, we use RCU read lock inside this function. As a result, users of
+ * this function DONOT need to use explicit locks for invoking.
  */
 int dev_pm_opp_init_cpufreq_table(struct device *dev,
                            struct cpufreq_frequency_table **table)
 {
-       struct device_opp *dev_opp;
        struct dev_pm_opp *opp;
-       struct cpufreq_frequency_table *freq_table;
-       int i = 0;
+       struct cpufreq_frequency_table *freq_table = NULL;
+       int i, max_opps, ret = 0;
+       unsigned long rate;
 
-       /* Pretend as if I am an updater */
-       mutex_lock(&dev_opp_list_lock);
+       rcu_read_lock();
 
-       dev_opp = find_device_opp(dev);
-       if (IS_ERR(dev_opp)) {
-               int r = PTR_ERR(dev_opp);
-               mutex_unlock(&dev_opp_list_lock);
-               dev_err(dev, "%s: Device OPP not found (%d)\n", __func__, r);
-               return r;
+       max_opps = dev_pm_opp_get_opp_count(dev);
+       if (max_opps <= 0) {
+               ret = max_opps ? max_opps : -ENODATA;
+               goto out;
        }
 
-       freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) *
-                            (dev_pm_opp_get_opp_count(dev) + 1), GFP_KERNEL);
+       freq_table = kzalloc(sizeof(*freq_table) * (max_opps + 1), GFP_KERNEL);
        if (!freq_table) {
-               mutex_unlock(&dev_opp_list_lock);
-               dev_warn(dev, "%s: Unable to allocate frequency table\n",
-                       __func__);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out;
        }
 
-       list_for_each_entry(opp, &dev_opp->opp_list, node) {
-               if (opp->available) {
-                       freq_table[i].driver_data = i;
-                       freq_table[i].frequency = opp->rate / 1000;
-                       i++;
+       for (i = 0, rate = 0; i < max_opps; i++, rate++) {
+               /* find next rate */
+               opp = dev_pm_opp_find_freq_ceil(dev, &rate);
+               if (IS_ERR(opp)) {
+                       ret = PTR_ERR(opp);
+                       goto out;
                }
+               freq_table[i].driver_data = i;
+               freq_table[i].frequency = rate / 1000;
        }
-       mutex_unlock(&dev_opp_list_lock);
 
        freq_table[i].driver_data = i;
        freq_table[i].frequency = CPUFREQ_TABLE_END;
 
        *table = &freq_table[0];
 
-       return 0;
+out:
+       rcu_read_unlock();
+       if (ret)
+               kfree(freq_table);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_init_cpufreq_table);