Loading Documentation/devicetree/bindings/arm/marvell/armada-37xx.txt +15 −0 Original line number Diff line number Diff line Loading @@ -33,3 +33,18 @@ nb_pm: syscon@14000 { compatible = "marvell,armada-3700-nb-pm", "syscon"; reg = <0x14000 0x60>; } AVS --- For AVS an other component is needed: Required properties: - compatible : should contain "marvell,armada-3700-avs", "syscon"; - reg : the register start and length for the AVS Example: avs: avs@11500 { compatible = "marvell,armada-3700-avs", "syscon"; reg = <0x11500 0x40>; } Documentation/trace/events-power.rst +1 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ cpufreq. cpu_idle "state=%lu cpu_id=%lu" cpu_frequency "state=%lu cpu_id=%lu" cpu_frequency_limits "min=%lu max=%lu cpu_id=%lu" A suspend event is used to indicate the system going in and out of the suspend mode: Loading drivers/cpufreq/armada-37xx-cpufreq.c +160 −3 Original line number Diff line number Diff line Loading @@ -51,6 +51,16 @@ #define ARMADA_37XX_DVFS_LOAD_2 2 #define ARMADA_37XX_DVFS_LOAD_3 3 /* AVS register set */ #define ARMADA_37XX_AVS_CTL0 0x0 #define ARMADA_37XX_AVS_ENABLE BIT(30) #define ARMADA_37XX_AVS_HIGH_VDD_LIMIT 16 #define ARMADA_37XX_AVS_LOW_VDD_LIMIT 22 #define ARMADA_37XX_AVS_VDD_MASK 0x3F #define ARMADA_37XX_AVS_CTL2 0x8 #define ARMADA_37XX_AVS_LOW_VDD_EN BIT(6) #define ARMADA_37XX_AVS_VSET(x) (0x1C + 4 * (x)) /* * On Armada 37xx the Power management manages 4 level of CPU load, * each level can be associated with a CPU clock source, a CPU Loading @@ -58,6 +68,17 @@ */ #define LOAD_LEVEL_NR 4 #define MIN_VOLT_MV 1000 /* AVS value for the corresponding voltage (in mV) */ static int avs_map[] = { 747, 758, 770, 782, 793, 805, 817, 828, 840, 852, 863, 875, 887, 898, 910, 922, 933, 945, 957, 968, 980, 992, 1003, 1015, 1027, 1038, 1050, 1062, 1073, 1085, 1097, 1108, 1120, 1132, 1143, 1155, 1167, 1178, 1190, 1202, 1213, 1225, 1237, 1248, 1260, 1272, 1283, 1295, 1307, 1318, 1330, 1342 }; struct armada37xx_cpufreq_state { struct regmap *regmap; u32 nb_l0l1; Loading @@ -71,6 +92,7 @@ static struct armada37xx_cpufreq_state *armada37xx_cpufreq_state; struct armada_37xx_dvfs { u32 cpu_freq_max; u8 divider[LOAD_LEVEL_NR]; u32 avs[LOAD_LEVEL_NR]; }; static struct armada_37xx_dvfs armada_37xx_dvfs[] = { Loading Loading @@ -148,6 +170,128 @@ static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base, clk_set_parent(clk, parent); } /* * Find out the armada 37x supported AVS value whose voltage value is * the round-up closest to the target voltage value. */ static u32 armada_37xx_avs_val_match(int target_vm) { u32 avs; /* Find out the round-up closest supported voltage value */ for (avs = 0; avs < ARRAY_SIZE(avs_map); avs++) if (avs_map[avs] >= target_vm) break; /* * If all supported voltages are smaller than target one, * choose the largest supported voltage */ if (avs == ARRAY_SIZE(avs_map)) avs = ARRAY_SIZE(avs_map) - 1; return avs; } /* * For Armada 37xx soc, L0(VSET0) VDD AVS value is set to SVC revision * value or a default value when SVC is not supported. * - L0 can be read out from the register of AVS_CTRL_0 and L0 voltage * can be got from the mapping table of avs_map. * - L1 voltage should be about 100mv smaller than L0 voltage * - L2 & L3 voltage should be about 150mv smaller than L0 voltage. * This function calculates L1 & L2 & L3 AVS values dynamically based * on L0 voltage and fill all AVS values to the AVS value table. */ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base, struct armada_37xx_dvfs *dvfs) { unsigned int target_vm; int load_level = 0; u32 l0_vdd_min; if (base == NULL) return; /* Get L0 VDD min value */ regmap_read(base, ARMADA_37XX_AVS_CTL0, &l0_vdd_min); l0_vdd_min = (l0_vdd_min >> ARMADA_37XX_AVS_LOW_VDD_LIMIT) & ARMADA_37XX_AVS_VDD_MASK; if (l0_vdd_min >= ARRAY_SIZE(avs_map)) { pr_err("L0 VDD MIN %d is not correct.\n", l0_vdd_min); return; } dvfs->avs[0] = l0_vdd_min; if (avs_map[l0_vdd_min] <= MIN_VOLT_MV) { /* * If L0 voltage is smaller than 1000mv, then all VDD sets * use L0 voltage; */ u32 avs_min = armada_37xx_avs_val_match(MIN_VOLT_MV); for (load_level = 1; load_level < LOAD_LEVEL_NR; load_level++) dvfs->avs[load_level] = avs_min; return; } /* * L1 voltage is equal to L0 voltage - 100mv and it must be * larger than 1000mv */ target_vm = avs_map[l0_vdd_min] - 100; target_vm = target_vm > MIN_VOLT_MV ? target_vm : MIN_VOLT_MV; dvfs->avs[1] = armada_37xx_avs_val_match(target_vm); /* * L2 & L3 voltage is equal to L0 voltage - 150mv and it must * be larger than 1000mv */ target_vm = avs_map[l0_vdd_min] - 150; target_vm = target_vm > MIN_VOLT_MV ? target_vm : MIN_VOLT_MV; dvfs->avs[2] = dvfs->avs[3] = armada_37xx_avs_val_match(target_vm); } static void __init armada37xx_cpufreq_avs_setup(struct regmap *base, struct armada_37xx_dvfs *dvfs) { unsigned int avs_val = 0, freq; int load_level = 0; if (base == NULL) return; /* Disable AVS before the configuration */ regmap_update_bits(base, ARMADA_37XX_AVS_CTL0, ARMADA_37XX_AVS_ENABLE, 0); /* Enable low voltage mode */ regmap_update_bits(base, ARMADA_37XX_AVS_CTL2, ARMADA_37XX_AVS_LOW_VDD_EN, ARMADA_37XX_AVS_LOW_VDD_EN); for (load_level = 1; load_level < LOAD_LEVEL_NR; load_level++) { freq = dvfs->cpu_freq_max / dvfs->divider[load_level]; avs_val = dvfs->avs[load_level]; regmap_update_bits(base, ARMADA_37XX_AVS_VSET(load_level-1), ARMADA_37XX_AVS_VDD_MASK << ARMADA_37XX_AVS_HIGH_VDD_LIMIT | ARMADA_37XX_AVS_VDD_MASK << ARMADA_37XX_AVS_LOW_VDD_LIMIT, avs_val << ARMADA_37XX_AVS_HIGH_VDD_LIMIT | avs_val << ARMADA_37XX_AVS_LOW_VDD_LIMIT); } /* Enable AVS after the configuration */ regmap_update_bits(base, ARMADA_37XX_AVS_CTL0, ARMADA_37XX_AVS_ENABLE, ARMADA_37XX_AVS_ENABLE); } static void armada37xx_cpufreq_disable_dvfs(struct regmap *base) { unsigned int reg = ARMADA_37XX_NB_DYN_MOD, Loading Loading @@ -216,7 +360,7 @@ static int __init armada37xx_cpufreq_driver_init(void) struct platform_device *pdev; unsigned long freq; unsigned int cur_frequency; struct regmap *nb_pm_base; struct regmap *nb_pm_base, *avs_base; struct device *cpu_dev; int load_lvl, ret; struct clk *clk; Loading @@ -227,6 +371,14 @@ static int __init armada37xx_cpufreq_driver_init(void) if (IS_ERR(nb_pm_base)) return -ENODEV; avs_base = syscon_regmap_lookup_by_compatible("marvell,armada-3700-avs"); /* if AVS is not present don't use it but still try to setup dvfs */ if (IS_ERR(avs_base)) { pr_info("Syscon failed for Adapting Voltage Scaling: skip it\n"); avs_base = NULL; } /* Before doing any configuration on the DVFS first, disable it */ armada37xx_cpufreq_disable_dvfs(nb_pm_base); Loading Loading @@ -270,16 +422,21 @@ static int __init armada37xx_cpufreq_driver_init(void) armada37xx_cpufreq_state->regmap = nb_pm_base; armada37xx_cpufreq_avs_configure(avs_base, dvfs); armada37xx_cpufreq_avs_setup(avs_base, dvfs); armada37xx_cpufreq_dvfs_setup(nb_pm_base, clk, dvfs->divider); clk_put(clk); for (load_lvl = ARMADA_37XX_DVFS_LOAD_0; load_lvl < LOAD_LEVEL_NR; load_lvl++) { unsigned long u_volt = avs_map[dvfs->avs[load_lvl]] * 1000; freq = cur_frequency / dvfs->divider[load_lvl]; ret = dev_pm_opp_add(cpu_dev, freq, 0); ret = dev_pm_opp_add(cpu_dev, freq, u_volt); if (ret) goto remove_opp; } /* Now that everything is setup, enable the DVFS at hardware level */ Loading drivers/cpufreq/cppc_cpufreq.c +52 −0 Original line number Diff line number Diff line Loading @@ -296,10 +296,62 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) return ret; } static inline u64 get_delta(u64 t1, u64 t0) { if (t1 > t0 || t0 > ~(u32)0) return t1 - t0; return (u32)t1 - (u32)t0; } static int cppc_get_rate_from_fbctrs(struct cppc_cpudata *cpu, struct cppc_perf_fb_ctrs fb_ctrs_t0, struct cppc_perf_fb_ctrs fb_ctrs_t1) { u64 delta_reference, delta_delivered; u64 reference_perf, delivered_perf; reference_perf = fb_ctrs_t0.reference_perf; delta_reference = get_delta(fb_ctrs_t1.reference, fb_ctrs_t0.reference); delta_delivered = get_delta(fb_ctrs_t1.delivered, fb_ctrs_t0.delivered); /* Check to avoid divide-by zero */ if (delta_reference || delta_delivered) delivered_perf = (reference_perf * delta_delivered) / delta_reference; else delivered_perf = cpu->perf_ctrls.desired_perf; return cppc_cpufreq_perf_to_khz(cpu, delivered_perf); } static unsigned int cppc_cpufreq_get_rate(unsigned int cpunum) { struct cppc_perf_fb_ctrs fb_ctrs_t0 = {0}, fb_ctrs_t1 = {0}; struct cppc_cpudata *cpu = all_cpu_data[cpunum]; int ret; ret = cppc_get_perf_ctrs(cpunum, &fb_ctrs_t0); if (ret) return ret; udelay(2); /* 2usec delay between sampling */ ret = cppc_get_perf_ctrs(cpunum, &fb_ctrs_t1); if (ret) return ret; return cppc_get_rate_from_fbctrs(cpu, fb_ctrs_t0, fb_ctrs_t1); } static struct cpufreq_driver cppc_cpufreq_driver = { .flags = CPUFREQ_CONST_LOOPS, .verify = cppc_verify_policy, .target = cppc_cpufreq_set_target, .get = cppc_cpufreq_get_rate, .init = cppc_cpufreq_cpu_init, .stop_cpu = cppc_cpufreq_stop_cpu, .name = "cppc_cpufreq", Loading drivers/cpufreq/cpufreq.c +7 −1 Original line number Diff line number Diff line Loading @@ -923,7 +923,12 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr, struct freq_attr *fattr = to_attr(attr); ssize_t ret = -EINVAL; cpus_read_lock(); /* * cpus_read_trylock() is used here to work around a circular lock * dependency problem with respect to the cpufreq_register_driver(). */ if (!cpus_read_trylock()) return -EBUSY; if (cpu_online(policy->cpu)) { down_write(&policy->rwsem); Loading Loading @@ -2236,6 +2241,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, policy->min = new_policy->min; policy->max = new_policy->max; trace_cpu_frequency_limits(policy); policy->cached_target_freq = UINT_MAX; Loading Loading
Documentation/devicetree/bindings/arm/marvell/armada-37xx.txt +15 −0 Original line number Diff line number Diff line Loading @@ -33,3 +33,18 @@ nb_pm: syscon@14000 { compatible = "marvell,armada-3700-nb-pm", "syscon"; reg = <0x14000 0x60>; } AVS --- For AVS an other component is needed: Required properties: - compatible : should contain "marvell,armada-3700-avs", "syscon"; - reg : the register start and length for the AVS Example: avs: avs@11500 { compatible = "marvell,armada-3700-avs", "syscon"; reg = <0x11500 0x40>; }
Documentation/trace/events-power.rst +1 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ cpufreq. cpu_idle "state=%lu cpu_id=%lu" cpu_frequency "state=%lu cpu_id=%lu" cpu_frequency_limits "min=%lu max=%lu cpu_id=%lu" A suspend event is used to indicate the system going in and out of the suspend mode: Loading
drivers/cpufreq/armada-37xx-cpufreq.c +160 −3 Original line number Diff line number Diff line Loading @@ -51,6 +51,16 @@ #define ARMADA_37XX_DVFS_LOAD_2 2 #define ARMADA_37XX_DVFS_LOAD_3 3 /* AVS register set */ #define ARMADA_37XX_AVS_CTL0 0x0 #define ARMADA_37XX_AVS_ENABLE BIT(30) #define ARMADA_37XX_AVS_HIGH_VDD_LIMIT 16 #define ARMADA_37XX_AVS_LOW_VDD_LIMIT 22 #define ARMADA_37XX_AVS_VDD_MASK 0x3F #define ARMADA_37XX_AVS_CTL2 0x8 #define ARMADA_37XX_AVS_LOW_VDD_EN BIT(6) #define ARMADA_37XX_AVS_VSET(x) (0x1C + 4 * (x)) /* * On Armada 37xx the Power management manages 4 level of CPU load, * each level can be associated with a CPU clock source, a CPU Loading @@ -58,6 +68,17 @@ */ #define LOAD_LEVEL_NR 4 #define MIN_VOLT_MV 1000 /* AVS value for the corresponding voltage (in mV) */ static int avs_map[] = { 747, 758, 770, 782, 793, 805, 817, 828, 840, 852, 863, 875, 887, 898, 910, 922, 933, 945, 957, 968, 980, 992, 1003, 1015, 1027, 1038, 1050, 1062, 1073, 1085, 1097, 1108, 1120, 1132, 1143, 1155, 1167, 1178, 1190, 1202, 1213, 1225, 1237, 1248, 1260, 1272, 1283, 1295, 1307, 1318, 1330, 1342 }; struct armada37xx_cpufreq_state { struct regmap *regmap; u32 nb_l0l1; Loading @@ -71,6 +92,7 @@ static struct armada37xx_cpufreq_state *armada37xx_cpufreq_state; struct armada_37xx_dvfs { u32 cpu_freq_max; u8 divider[LOAD_LEVEL_NR]; u32 avs[LOAD_LEVEL_NR]; }; static struct armada_37xx_dvfs armada_37xx_dvfs[] = { Loading Loading @@ -148,6 +170,128 @@ static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base, clk_set_parent(clk, parent); } /* * Find out the armada 37x supported AVS value whose voltage value is * the round-up closest to the target voltage value. */ static u32 armada_37xx_avs_val_match(int target_vm) { u32 avs; /* Find out the round-up closest supported voltage value */ for (avs = 0; avs < ARRAY_SIZE(avs_map); avs++) if (avs_map[avs] >= target_vm) break; /* * If all supported voltages are smaller than target one, * choose the largest supported voltage */ if (avs == ARRAY_SIZE(avs_map)) avs = ARRAY_SIZE(avs_map) - 1; return avs; } /* * For Armada 37xx soc, L0(VSET0) VDD AVS value is set to SVC revision * value or a default value when SVC is not supported. * - L0 can be read out from the register of AVS_CTRL_0 and L0 voltage * can be got from the mapping table of avs_map. * - L1 voltage should be about 100mv smaller than L0 voltage * - L2 & L3 voltage should be about 150mv smaller than L0 voltage. * This function calculates L1 & L2 & L3 AVS values dynamically based * on L0 voltage and fill all AVS values to the AVS value table. */ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base, struct armada_37xx_dvfs *dvfs) { unsigned int target_vm; int load_level = 0; u32 l0_vdd_min; if (base == NULL) return; /* Get L0 VDD min value */ regmap_read(base, ARMADA_37XX_AVS_CTL0, &l0_vdd_min); l0_vdd_min = (l0_vdd_min >> ARMADA_37XX_AVS_LOW_VDD_LIMIT) & ARMADA_37XX_AVS_VDD_MASK; if (l0_vdd_min >= ARRAY_SIZE(avs_map)) { pr_err("L0 VDD MIN %d is not correct.\n", l0_vdd_min); return; } dvfs->avs[0] = l0_vdd_min; if (avs_map[l0_vdd_min] <= MIN_VOLT_MV) { /* * If L0 voltage is smaller than 1000mv, then all VDD sets * use L0 voltage; */ u32 avs_min = armada_37xx_avs_val_match(MIN_VOLT_MV); for (load_level = 1; load_level < LOAD_LEVEL_NR; load_level++) dvfs->avs[load_level] = avs_min; return; } /* * L1 voltage is equal to L0 voltage - 100mv and it must be * larger than 1000mv */ target_vm = avs_map[l0_vdd_min] - 100; target_vm = target_vm > MIN_VOLT_MV ? target_vm : MIN_VOLT_MV; dvfs->avs[1] = armada_37xx_avs_val_match(target_vm); /* * L2 & L3 voltage is equal to L0 voltage - 150mv and it must * be larger than 1000mv */ target_vm = avs_map[l0_vdd_min] - 150; target_vm = target_vm > MIN_VOLT_MV ? target_vm : MIN_VOLT_MV; dvfs->avs[2] = dvfs->avs[3] = armada_37xx_avs_val_match(target_vm); } static void __init armada37xx_cpufreq_avs_setup(struct regmap *base, struct armada_37xx_dvfs *dvfs) { unsigned int avs_val = 0, freq; int load_level = 0; if (base == NULL) return; /* Disable AVS before the configuration */ regmap_update_bits(base, ARMADA_37XX_AVS_CTL0, ARMADA_37XX_AVS_ENABLE, 0); /* Enable low voltage mode */ regmap_update_bits(base, ARMADA_37XX_AVS_CTL2, ARMADA_37XX_AVS_LOW_VDD_EN, ARMADA_37XX_AVS_LOW_VDD_EN); for (load_level = 1; load_level < LOAD_LEVEL_NR; load_level++) { freq = dvfs->cpu_freq_max / dvfs->divider[load_level]; avs_val = dvfs->avs[load_level]; regmap_update_bits(base, ARMADA_37XX_AVS_VSET(load_level-1), ARMADA_37XX_AVS_VDD_MASK << ARMADA_37XX_AVS_HIGH_VDD_LIMIT | ARMADA_37XX_AVS_VDD_MASK << ARMADA_37XX_AVS_LOW_VDD_LIMIT, avs_val << ARMADA_37XX_AVS_HIGH_VDD_LIMIT | avs_val << ARMADA_37XX_AVS_LOW_VDD_LIMIT); } /* Enable AVS after the configuration */ regmap_update_bits(base, ARMADA_37XX_AVS_CTL0, ARMADA_37XX_AVS_ENABLE, ARMADA_37XX_AVS_ENABLE); } static void armada37xx_cpufreq_disable_dvfs(struct regmap *base) { unsigned int reg = ARMADA_37XX_NB_DYN_MOD, Loading Loading @@ -216,7 +360,7 @@ static int __init armada37xx_cpufreq_driver_init(void) struct platform_device *pdev; unsigned long freq; unsigned int cur_frequency; struct regmap *nb_pm_base; struct regmap *nb_pm_base, *avs_base; struct device *cpu_dev; int load_lvl, ret; struct clk *clk; Loading @@ -227,6 +371,14 @@ static int __init armada37xx_cpufreq_driver_init(void) if (IS_ERR(nb_pm_base)) return -ENODEV; avs_base = syscon_regmap_lookup_by_compatible("marvell,armada-3700-avs"); /* if AVS is not present don't use it but still try to setup dvfs */ if (IS_ERR(avs_base)) { pr_info("Syscon failed for Adapting Voltage Scaling: skip it\n"); avs_base = NULL; } /* Before doing any configuration on the DVFS first, disable it */ armada37xx_cpufreq_disable_dvfs(nb_pm_base); Loading Loading @@ -270,16 +422,21 @@ static int __init armada37xx_cpufreq_driver_init(void) armada37xx_cpufreq_state->regmap = nb_pm_base; armada37xx_cpufreq_avs_configure(avs_base, dvfs); armada37xx_cpufreq_avs_setup(avs_base, dvfs); armada37xx_cpufreq_dvfs_setup(nb_pm_base, clk, dvfs->divider); clk_put(clk); for (load_lvl = ARMADA_37XX_DVFS_LOAD_0; load_lvl < LOAD_LEVEL_NR; load_lvl++) { unsigned long u_volt = avs_map[dvfs->avs[load_lvl]] * 1000; freq = cur_frequency / dvfs->divider[load_lvl]; ret = dev_pm_opp_add(cpu_dev, freq, 0); ret = dev_pm_opp_add(cpu_dev, freq, u_volt); if (ret) goto remove_opp; } /* Now that everything is setup, enable the DVFS at hardware level */ Loading
drivers/cpufreq/cppc_cpufreq.c +52 −0 Original line number Diff line number Diff line Loading @@ -296,10 +296,62 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) return ret; } static inline u64 get_delta(u64 t1, u64 t0) { if (t1 > t0 || t0 > ~(u32)0) return t1 - t0; return (u32)t1 - (u32)t0; } static int cppc_get_rate_from_fbctrs(struct cppc_cpudata *cpu, struct cppc_perf_fb_ctrs fb_ctrs_t0, struct cppc_perf_fb_ctrs fb_ctrs_t1) { u64 delta_reference, delta_delivered; u64 reference_perf, delivered_perf; reference_perf = fb_ctrs_t0.reference_perf; delta_reference = get_delta(fb_ctrs_t1.reference, fb_ctrs_t0.reference); delta_delivered = get_delta(fb_ctrs_t1.delivered, fb_ctrs_t0.delivered); /* Check to avoid divide-by zero */ if (delta_reference || delta_delivered) delivered_perf = (reference_perf * delta_delivered) / delta_reference; else delivered_perf = cpu->perf_ctrls.desired_perf; return cppc_cpufreq_perf_to_khz(cpu, delivered_perf); } static unsigned int cppc_cpufreq_get_rate(unsigned int cpunum) { struct cppc_perf_fb_ctrs fb_ctrs_t0 = {0}, fb_ctrs_t1 = {0}; struct cppc_cpudata *cpu = all_cpu_data[cpunum]; int ret; ret = cppc_get_perf_ctrs(cpunum, &fb_ctrs_t0); if (ret) return ret; udelay(2); /* 2usec delay between sampling */ ret = cppc_get_perf_ctrs(cpunum, &fb_ctrs_t1); if (ret) return ret; return cppc_get_rate_from_fbctrs(cpu, fb_ctrs_t0, fb_ctrs_t1); } static struct cpufreq_driver cppc_cpufreq_driver = { .flags = CPUFREQ_CONST_LOOPS, .verify = cppc_verify_policy, .target = cppc_cpufreq_set_target, .get = cppc_cpufreq_get_rate, .init = cppc_cpufreq_cpu_init, .stop_cpu = cppc_cpufreq_stop_cpu, .name = "cppc_cpufreq", Loading
drivers/cpufreq/cpufreq.c +7 −1 Original line number Diff line number Diff line Loading @@ -923,7 +923,12 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr, struct freq_attr *fattr = to_attr(attr); ssize_t ret = -EINVAL; cpus_read_lock(); /* * cpus_read_trylock() is used here to work around a circular lock * dependency problem with respect to the cpufreq_register_driver(). */ if (!cpus_read_trylock()) return -EBUSY; if (cpu_online(policy->cpu)) { down_write(&policy->rwsem); Loading Loading @@ -2236,6 +2241,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, policy->min = new_policy->min; policy->max = new_policy->max; trace_cpu_frequency_limits(policy); policy->cached_target_freq = UINT_MAX; Loading