[PATCH 2/2] clocksource: Add suspend clocksource sysfs attribute
From: Thierry Reding
Date: Fri Jun 14 2019 - 06:50:04 EST
From: Thierry Reding <treding@xxxxxxxxxx>
Allow the currently selected suspend clocksource to be inspected via
sysfs. The suspend clocksource can also be set using this attribute,
which can be useful for debugging.
Signed-off-by: Thierry Reding <treding@xxxxxxxxxx>
---
kernel/time/clocksource.c | 53 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 52 insertions(+), 1 deletion(-)
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 467b36d2f9f8..d963bcecbc96 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -489,7 +489,8 @@ static void __clocksource_suspend_select(struct clocksource *cs)
}
/* Pick the best rating. */
- if (!suspend_clocksource || cs->rating > suspend_clocksource->rating)
+ if (!suspend_clocksource || cs->rating > suspend_clocksource->rating ||
+ (suspend_clocksource->flags & CLOCK_SOURCE_SUSPEND_NONSTOP) == 0)
suspend_clocksource = cs;
}
@@ -1172,10 +1173,60 @@ static ssize_t available_clocksource_show(struct device *dev,
}
static DEVICE_ATTR_RO(available_clocksource);
+static ssize_t suspend_clocksource_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct clocksource *clksrc = suspend_clocksource;
+ ssize_t count = 0;
+
+ if (clksrc)
+ count += snprintf(buf, PAGE_SIZE, "%s\n", clksrc->name);
+
+ return count;
+}
+
+static ssize_t suspend_clocksource_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct clocksource *cs;
+ char name[CS_NAME_LEN];
+ ssize_t ret;
+
+ ret = sysfs_get_uname(buf, name, count);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&clocksource_mutex);
+
+ if (strlen(name) > 0) {
+ cs = clocksource_lookup(name);
+ if (cs) {
+ if (!(cs->flags & CLOCK_SOURCE_SUSPEND_NONSTOP))
+ pr_warn("using non-persistent clocksource %s for suspend\n",
+ cs->name);
+
+ suspend_clocksource = cs;
+ } else {
+ ret = -ENODEV;
+ }
+ } else {
+ clocksource_suspend_select(false);
+ }
+
+ mutex_unlock(&clocksource_mutex);
+
+ return ret ? ret : count;
+}
+
+static DEVICE_ATTR_RW(suspend_clocksource);
+
static struct attribute *clocksource_attrs[] = {
&dev_attr_current_clocksource.attr,
&dev_attr_unbind_clocksource.attr,
&dev_attr_available_clocksource.attr,
+ &dev_attr_suspend_clocksource.attr,
NULL
};
ATTRIBUTE_GROUPS(clocksource);
--
2.21.0