Following patch "cpufreq: make sure frequency transitions are serialized" guarantees that we don't have any races while changing cpu frequency or sending notifications. It handled a special case with CPUFREQ_ASYNC_NOTIFICATION flag for drivers that don't complete their freq change from ->target() and exynos5440 driver is well adopted to it as well.. There is one more driver powernow-k8 that has similar implementation, schedules a work for doing transitions. All is good if that work function does notifications on every call to it and so the transition_ongoing count stays stable. But there are chances that the work function may return without actually doing the notifications, in which case transition_ongoing count will not be set to zero and so no transitions would be possible after that. This patch fixes powernow-k8 driver to get transition_ongoing count stable. It does following to ensure proper working of this driver: - return -EINPROGRESS from ->target() so that core doesn't mark transfer over at the end of ->target(). - mark cpufreq_driver->flags with CPUFREQ_ASYNC_NOTIFICATION, so that core knows that driver would terminate its transition. - call cpufreq_transition_complete() whenever we are returning before sending notifications Hopefully things will work well after this patch, only compiled tested at my end. Signed-off-by: Viresh Kumar <viresh.kumar@xxxxxxxxxx> --- drivers/cpufreq/powernow-k8.c | 47 +++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index 2344a9e..8215bbc 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -952,7 +952,7 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, if ((data->currvid == vid) && (data->currfid == fid)) { pr_debug("target matches current values (fid 0x%x, vid 0x%x)\n", fid, vid); - return 0; + return -EALREADY; } pr_debug("cpu %d, changing to fid 0x%x, vid 0x%x\n", @@ -993,22 +993,27 @@ static long powernowk8_target_fn(void *arg) unsigned int newstate; int ret; - if (!data) - return -EINVAL; + if (!data) { + ret = -EINVAL; + goto transition_complete; + } checkfid = data->currfid; checkvid = data->currvid; if (pending_bit_stuck()) { printk(KERN_ERR PFX "failing targ, change pending bit set\n"); - return -EIO; + ret = -EIO; + goto transition_complete; } pr_debug("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n", pol->cpu, targfreq, pol->min, pol->max, relation); - if (query_current_values_with_pending_wait(data)) - return -EIO; + if (query_current_values_with_pending_wait(data)) { + ret = -EIO; + goto transition_complete; + } pr_debug("targ: curr fid 0x%x, vid 0x%x\n", data->currfid, data->currvid); @@ -1022,25 +1027,36 @@ static long powernowk8_target_fn(void *arg) } if (cpufreq_frequency_table_target(pol, data->powernow_table, - targfreq, relation, &newstate)) - return -EIO; + targfreq, relation, &newstate)) { + ret = -EIO; + goto transition_complete; + } mutex_lock(&fidvid_mutex); powernow_k8_acpi_pst_values(data, newstate); ret = transition_frequency_fidvid(data, newstate); + mutex_unlock(&fidvid_mutex); if (ret) { - printk(KERN_ERR PFX "transition frequency failed\n"); - mutex_unlock(&fidvid_mutex); - return 1; + /* Not a error case, just need to mark transition complete */ + if (ret == -EALREADY) { + ret = 0; + } else { + printk(KERN_ERR PFX "transition frequency failed\n"); + ret = 1; + } + goto transition_complete; } - mutex_unlock(&fidvid_mutex); pol->cur = find_khz_freq_from_fid(data->currfid); return 0; + +transition_complete: + cpufreq_transition_complete(pol); + return ret; } /* Driver entry point to switch to the target frequency */ @@ -1049,8 +1065,12 @@ static int powernowk8_target(struct cpufreq_policy *pol, { struct powernowk8_target_arg pta = { .pol = pol, .targfreq = targfreq, .relation = relation }; + int ret; - return work_on_cpu(pol->cpu, powernowk8_target_fn, &pta); + ret = work_on_cpu(pol->cpu, powernowk8_target_fn, &pta); + if (!ret) + ret = -EINPROGRESS; /* Mark transition as In-progress */ + return ret; } /* Driver entry point to verify the policy and range of frequencies */ @@ -1233,6 +1253,7 @@ static struct freq_attr *powernow_k8_attr[] = { }; static struct cpufreq_driver cpufreq_amd64_driver = { + .flags = CPUFREQ_ASYNC_NOTIFICATION, .verify = powernowk8_verify, .target = powernowk8_target, .bios_limit = acpi_processor_get_bios_limit, -- 1.7.12.rc2.18.g61b472e -- To unsubscribe from this list: send the line "unsubscribe cpufreq" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html