[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <4BFC687A.9040304@athenacr.com>
Date: Tue, 25 May 2010 20:16:58 -0400
From: Brian Bloniarz <bmb@...enacr.com>
To: "H. Peter Anvin" <hpa@...or.com>
CC: Dan Magenheimer <dan.magenheimer@...cle.com>,
john stultz <johnstul@...ibm.com>, Ingo Molnar <mingo@...e.hu>,
Thomas Gleixner <tglx@...utronix.de>,
Peter Zijlstra <peterz@...radead.org>,
Andi Kleen <andi@...stfloor.org>,
Arjan van de Ven <arjan@...radead.org>,
Venkatesh Pallipadi <venki@...gle.com>, chris.mason@...cle.com,
linux-kernel@...r.kernel.org
Subject: Re: [PATCH] x86: Export tsc related information in sysfs
On 05/24/2010 09:33 PM, Brian Bloniarz wrote:
> So what's wrong with just adding a
> /sys/devices/system/clocksource/clocksource0/tsc_khz?
As an RFC:
Add clocksource.sys_register & sys_unregister so the
current clocksource can add supplemental information to
/sys/devices/system/clocksource/clocksource0/
Export tsc_khz when current_clocksource==tsc so that
daemons like NTP can account for the variability of
calibration results.
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 9faf91a..9c99965 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -76,6 +76,11 @@ unsigned long long
sched_clock(void) __attribute__((alias("native_sched_clock")));
#endif
+int sysfs_tsc_register(struct sys_device *clocksource_dev,
+ struct clocksource *cs);
+void sysfs_tsc_unregister(struct sys_device *clocksource_dev,
+ struct clocksource *cs);
+
int check_tsc_unstable(void)
{
return tsc_unstable;
@@ -757,6 +762,8 @@ static struct clocksource clocksource_tsc = {
#ifdef CONFIG_X86_64
.vread = vread_tsc,
#endif
+ .sys_register = sysfs_tsc_register,
+ .sys_unregister = sysfs_tsc_unregister,
};
void mark_tsc_unstable(char *reason)
@@ -967,3 +974,22 @@ void __init tsc_init(void)
init_tsc_clocksource();
}
+static ssize_t show_tsc_khz(
+ struct sys_device *dev, struct sysdev_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", tsc_khz);
+}
+
+static SYSDEV_ATTR(tsc_khz, 0444, show_tsc_khz, NULL);
+
+int sysfs_tsc_register(struct sys_device *clocksource_dev,
+ struct clocksource *cs)
+{
+ return sysdev_create_file(clocksource_dev, &attr_tsc_khz);
+}
+
+void sysfs_tsc_unregister(struct sys_device *clocksource_dev,
+ struct clocksource *cs)
+{
+ sysdev_remove_file(clocksource_dev, &attr_tsc_khz);
+}
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 5ea3c60..d9f6f13 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -15,6 +15,7 @@
#include <linux/cache.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/sysdev.h>
#include <asm/div64.h>
#include <asm/io.h>
@@ -156,6 +157,8 @@ extern u64 timecounter_cyc2time(struct timecounter *tc,
* @vread: vsyscall based read
* @suspend: suspend function for the clocksource, if necessary
* @resume: resume function for the clocksource, if necessary
+ * @sys_register: optional, register additional sysfs attributes
+ * @sys_unregister: optional, unregister sysfs attributes
*/
struct clocksource {
/*
@@ -194,6 +197,10 @@ struct clocksource {
struct list_head wd_list;
cycle_t wd_last;
#endif
+ int (*sys_register)(struct sys_device *clocksource_dev,
+ struct clocksource *cs);
+ void (*sys_unregister)(struct sys_device *clocksource_dev,
+ struct clocksource *cs);
};
/*
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index f08e99c..d8b69a5 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -41,6 +41,8 @@ void timecounter_init(struct timecounter *tc,
}
EXPORT_SYMBOL_GPL(timecounter_init);
+void sysfs_alter_clocksource(struct clocksource *old, struct clocksource *new);
+
/**
* timecounter_read_delta - get nanoseconds since last call of this function
* @tc: Pointer to time counter
@@ -572,6 +574,7 @@ static void clocksource_select(void)
}
if (curr_clocksource != best) {
printk(KERN_INFO "Switching to clocksource %s\n", best->name);
+ sysfs_alter_clocksource(curr_clocksource, best);
curr_clocksource = best;
timekeeping_notify(curr_clocksource);
}
@@ -834,6 +837,8 @@ static struct sys_device device_clocksource = {
.cls = &clocksource_sysclass,
};
+static int sysfs_active = 0;
+
static int __init init_clocksource_sysfs(void)
{
int error = sysdev_class_register(&clocksource_sysclass);
@@ -848,10 +853,34 @@ static int __init init_clocksource_sysfs(void)
error = sysdev_create_file(
&device_clocksource,
&attr_available_clocksource);
+
+ if (!error)
+ {
+ mutex_lock(&clocksource_mutex);
+ if(curr_clocksource->sys_register)
+ error = curr_clocksource->sys_register(
+ &device_clocksource, curr_clocksource);
+ mutex_unlock(&clocksource_mutex);
+ }
+
+ if (!error)
+ sysfs_active = 1;
return error;
}
device_initcall(init_clocksource_sysfs);
+
+void sysfs_alter_clocksource(struct clocksource *old,
+ struct clocksource *new)
+{
+ if(!sysfs_active)
+ return;
+ if(old->sys_unregister)
+ old->sys_unregister(&device_clocksource, old);
+ if(new->sys_register)
+ new->sys_register(&device_clocksource, new);
+}
+
#endif /* CONFIG_SYSFS */
/**
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists