From: Dominik Brodowski <linux@dominikbrodowski.de>
To: cpufreq@www.linux.org.uk
Subject: patch-05 [Re: [PATCHES] cpufreq_get(), cpufreq->get()]
Date: Mon, 12 Apr 2004 00:00:47 +0200 [thread overview]
Message-ID: <20040411220047.GD8160@dominikbrodowski.de> (raw)
In-Reply-To: <20040411215912.GA8160@dominikbrodowski.de>
(Hopefully) fix cpufreq resume support.
Upon resuming, first CPUfreq hardware support needs to be re-enabled in ceratin cases
(call to cpufreq_driver->resume()).
Then, two different paths may need to be taken:
a) frequency during suspend equals frequency during resume ==> everything is fine,
b) frequency differ ==> either we can't handle it, then panic (see flag
CPUFREQ_PANIC_RESUME_OUTOFSYNC). Or we can handle it, then notify all
transition notifiers of this frequency change (CPUFREQ_RESUMECHANGE so that they
know IRQs are disabled).
At last, a call to cpufreq_update_policy() is scheduled. This asserts that
that the policy can be updated soon, in case platform limit, thermal and/or other
issues make an adjustment necessary.
Documentation/cpu-freq/core.txt | 4 ++
drivers/cpufreq/cpufreq.c | 63 ++++++++++++++++++++++++----------------
include/linux/cpufreq.h | 5 +++
3 files changed, 47 insertions(+), 25 deletions(-)
diff -ruN linux-original/Documentation/cpu-freq/core.txt linux/Documentation/cpu-freq/core.txt
--- linux-original/Documentation/cpu-freq/core.txt 2004-04-11 14:47:24.000000000 +0200
+++ linux/Documentation/cpu-freq/core.txt 2004-04-11 17:13:16.571514384 +0200
@@ -92,3 +92,7 @@
cpu - number of the affected CPU
old - old frequency
new - new frequency
+
+If the cpufreq core detects the frequency has changed while the system
+was suspended, these notifiers are called with CPUFREQ_RESUMECHANGE as
+second argument.
diff -ruN linux-original/drivers/cpufreq/cpufreq.c linux/drivers/cpufreq/cpufreq.c
--- linux-original/drivers/cpufreq/cpufreq.c 2004-04-11 17:14:34.836616280 +0200
+++ linux/drivers/cpufreq/cpufreq.c 2004-04-11 17:13:16.572514232 +0200
@@ -33,8 +33,10 @@
static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS];
static spinlock_t cpufreq_driver_lock = SPIN_LOCK_UNLOCKED;
-/* internal prototype */
+/* internal prototypes */
static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
+static void handle_update(void *data);
+static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci);
/**
@@ -362,7 +364,6 @@
.release = cpufreq_sysfs_release,
};
-static void handle_update(void *data);
/**
* cpufreq_add_dev - add a CPU device
@@ -572,10 +573,11 @@
/**
- * cpufreq_resume - restore the CPU clock frequency after resume
+ * cpufreq_resume - restore proper CPU frequency handling after resume
*
- * Restore the CPU clock frequency so that our idea of the current
- * frequency reflects the actual hardware.
+ * 1.) resume CPUfreq hardware support (cpufreq_driver->resume())
+ * 2.) if ->target and !CPUFREQ_CONST_LOOPS: verify we're in sync
+ * 3.) schedule call cpufreq_update_policy() ASAP as interrupts are restored.
*/
static int cpufreq_resume(struct sys_device * sysdev)
{
@@ -595,25 +597,37 @@
if (!cpu_policy)
return -EINVAL;
- if (cpufreq_driver->resume)
- ret = cpufreq_driver->resume(cpu_policy);
- if (ret) {
- printk(KERN_ERR "cpufreq: resume failed in ->resume step on CPU %u\n", cpu_policy->cpu);
- goto out;
- }
+ if (!cpufreq_driver->flags & CPUFREQ_CONST_LOOPS) {
+ unsigned int cur_freq = 0;
- if (cpufreq_driver->setpolicy)
- ret = cpufreq_driver->setpolicy(cpu_policy);
- else
- /* CPUFREQ_RELATION_H or CPUFREQ_RELATION_L have the same effect here, as cpu_policy->cur is known
- * to be a valid and exact target frequency
- */
- ret = cpufreq_driver->target(cpu_policy, cpu_policy->cur, CPUFREQ_RELATION_H);
+ if (cpufreq_driver->get)
+ cur_freq = cpufreq_driver->get(cpu_policy->cpu);
- if (ret)
- printk(KERN_ERR "cpufreq: resume failed in ->setpolicy/target step on CPU %u\n", cpu_policy->cpu);
+ if (!cur_freq || !cpu_policy->cur) {
+ printk(KERN_ERR "cpufreq: resume failed to assert current frequency is what timing core thinks it is.\n");
+ goto out;
+ }
+
+ if (unlikely(cur_freq != cpu_policy->cur)) {
+ struct cpufreq_freqs freqs;
+
+ if (cpufreq_driver->flags & CPUFREQ_PANIC_RESUME_OUTOFSYNC)
+ panic("CPU Frequency is out of sync.");
+
+ printk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing"
+ "core thinks of %u, is %u kHz.\n", cpu_policy->cur, cur_freq);
+
+ freqs.cpu = cpu;
+ freqs.old = cpu_policy->cur;
+ freqs.new = cur_freq;
+
+ notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_RESUMECHANGE, &freqs);
+ adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
+ }
+ }
out:
+ schedule_work(&cpu_policy->update);
cpufreq_cpu_put(cpu_policy);
return ret;
}
@@ -1009,11 +1023,12 @@
l_p_j_ref_freq = ci->old;
}
if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) ||
- (val == CPUFREQ_POSTCHANGE && ci->old > ci->new))
+ (val == CPUFREQ_POSTCHANGE && ci->old > ci->new) ||
+ (val == CPUFREQ_RESUMECHANGE))
loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new);
}
#else
-#define adjust_jiffies(x...) do {} while (0)
+static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { return; }
#endif
@@ -1025,9 +1040,7 @@
*/
void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
{
- if (irqs_disabled())
- return; /* Only valid if we're in the resume process where
- * everyone knows what CPU frequency we are at */
+ BUG_ON(irqs_disabled());
down_read(&cpufreq_notifier_rwsem);
switch (state) {
diff -ruN linux-original/include/linux/cpufreq.h linux/include/linux/cpufreq.h
--- linux-original/include/linux/cpufreq.h 2004-04-11 17:14:34.837616128 +0200
+++ linux/include/linux/cpufreq.h 2004-04-11 17:13:49.038578640 +0200
@@ -100,6 +100,7 @@
#define CPUFREQ_PRECHANGE (0)
#define CPUFREQ_POSTCHANGE (1)
+#define CPUFREQ_RESUMECHANGE (8)
struct cpufreq_freqs {
unsigned int cpu; /* cpu nr */
@@ -210,6 +211,10 @@
#define CPUFREQ_PANIC_OUTOFSYNC 0x04 /* panic if cpufreq's opinion of
* current frequency differs from
* actual frequency */
+#define CPUFREQ_PANIC_RESUME_OUTOFSYNC 0x08 /* panic if cpufreq's opinion of
+ * current frequency differs from
+ * actual frequency on resume
+ * from sleep. */
int cpufreq_register_driver(struct cpufreq_driver *driver_data);
next prev parent reply other threads:[~2004-04-11 22:00 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-04-11 21:59 [PATCHES] cpufreq_get(), cpufreq->get() Dominik Brodowski
2004-04-11 22:00 ` patch-02 [Re: [PATCHES] cpufreq_get(), cpufreq->get()] Dominik Brodowski
2004-04-11 22:00 ` patch-04 " Dominik Brodowski
2004-04-11 22:00 ` Dominik Brodowski [this message]
2004-04-11 22:01 ` patch-06 " Dominik Brodowski
2004-04-12 12:04 ` give the TSC a fair chance [Was: " Dominik Brodowski
2004-04-14 18:24 ` john stultz
2004-04-14 18:54 ` Dominik Brodowski
2004-04-14 20:03 ` john stultz
2004-04-14 20:57 ` Dominik Brodowski
2004-04-14 21:24 ` john stultz
2004-04-19 15:32 ` Dominik Brodowski
2004-04-14 10:52 ` [PATCHES] cpufreq_get(), cpufreq->get() Dave Jones
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20040411220047.GD8160@dominikbrodowski.de \
--to=linux@dominikbrodowski.de \
--cc=cpufreq@www.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox