From 7ff0589c7bff4ca31b255ac2028f633f14047762 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Jun 2015 08:52:22 +0000 Subject: [PATCH 1/7] regmap: add force_write option on _regmap_update_bits() Sometimes we want to write data even though it doesn't change value. Then, force_write option on _regmap_update_bits() helps this purpose. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 7111d04f2621..69ec411ce722 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -34,7 +34,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, - bool *change); + bool *change, bool force_write); static int _regmap_bus_reg_read(void *context, unsigned int reg, unsigned int *val); @@ -1178,7 +1178,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg, ret = _regmap_update_bits(map, range->selector_reg, range->selector_mask, win_page << range->selector_shift, - &page_chg); + &page_chg, false); map->work_buf = orig_work_buf; @@ -2327,7 +2327,7 @@ EXPORT_SYMBOL_GPL(regmap_bulk_read); static int _regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, - bool *change) + bool *change, bool force_write) { int ret; unsigned int tmp, orig; @@ -2339,7 +2339,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, tmp = orig & ~mask; tmp |= val & mask; - if (tmp != orig) { + if (force_write || (tmp != orig)) { ret = _regmap_write(map, reg, tmp); if (change) *change = true; @@ -2367,7 +2367,7 @@ int regmap_update_bits(struct regmap *map, unsigned int reg, int ret; map->lock(map->lock_arg); - ret = _regmap_update_bits(map, reg, mask, val, NULL); + ret = _regmap_update_bits(map, reg, mask, val, NULL, false); map->unlock(map->lock_arg); return ret; @@ -2398,7 +2398,7 @@ int regmap_update_bits_async(struct regmap *map, unsigned int reg, map->async = true; - ret = _regmap_update_bits(map, reg, mask, val, NULL); + ret = _regmap_update_bits(map, reg, mask, val, NULL, false); map->async = false; @@ -2427,7 +2427,7 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, int ret; map->lock(map->lock_arg); - ret = _regmap_update_bits(map, reg, mask, val, change); + ret = _regmap_update_bits(map, reg, mask, val, change, false); map->unlock(map->lock_arg); return ret; } @@ -2460,7 +2460,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg, map->async = true; - ret = _regmap_update_bits(map, reg, mask, val, change); + ret = _regmap_update_bits(map, reg, mask, val, change, false); map->async = false; From fd4b7286ccc469bf5dde22db6b8fcc455c3c4a66 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Jun 2015 08:52:39 +0000 Subject: [PATCH 2/7] regmap: add regmap_write_bits() regmap_write_bits() is similar to regmap_update_bits(), but regmap_write_bits() write data to register even though it is same value. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 23 +++++++++++++++++++++++ include/linux/regmap.h | 9 +++++++++ 2 files changed, 32 insertions(+) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 69ec411ce722..d93bb9a8ab98 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2374,6 +2374,29 @@ int regmap_update_bits(struct regmap *map, unsigned int reg, } EXPORT_SYMBOL_GPL(regmap_update_bits); +/** + * regmap_write_bits: Perform a read/modify/write cycle on the register map + * + * @map: Register map to update + * @reg: Register to update + * @mask: Bitmask to change + * @val: New value for bitmask + * + * Returns zero for success, a negative number on error. + */ +int regmap_write_bits(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val) +{ + int ret; + + map->lock(map->lock_arg); + ret = _regmap_update_bits(map, reg, mask, val, NULL, true); + map->unlock(map->lock_arg); + + return ret; +} +EXPORT_SYMBOL_GPL(regmap_write_bits); + /** * regmap_update_bits_async: Perform a read/modify/write cycle on the register * map asynchronously diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 59c55ea0f0b5..e4b9ad4f05ef 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -424,6 +424,8 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, size_t val_count); int regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val); +int regmap_write_bits(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val); int regmap_update_bits_async(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val); int regmap_update_bits_check(struct regmap *map, unsigned int reg, @@ -645,6 +647,13 @@ static inline int regmap_update_bits(struct regmap *map, unsigned int reg, return -EINVAL; } +static inline int regmap_write_bits(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val) +{ + WARN_ONCE(1, "regmap API is disabled"); + return -EINVAL; +} + static inline int regmap_update_bits_async(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val) From e874e6c7edc43436f73cf84157d9221f8b807c36 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Jun 2015 08:52:55 +0000 Subject: [PATCH 3/7] regmap: add regmap_fields_force_write() regmap_fields_force_write() is similar to regmap_fields_write(), but regmap_fields_force_write() write data to register even though it is same value. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 12 ++++++++++++ include/linux/regmap.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index d93bb9a8ab98..dd63bcbbf8a5 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1624,6 +1624,18 @@ int regmap_fields_write(struct regmap_field *field, unsigned int id, } EXPORT_SYMBOL_GPL(regmap_fields_write); +int regmap_fields_force_write(struct regmap_field *field, unsigned int id, + unsigned int val) +{ + if (id >= field->id_size) + return -EINVAL; + + return regmap_write_bits(field->regmap, + field->reg + (field->id_offset * id), + field->mask, val << field->shift); +} +EXPORT_SYMBOL_GPL(regmap_fields_force_write); + /** * regmap_fields_update_bits(): Perform a read/modify/write cycle * on the register field diff --git a/include/linux/regmap.h b/include/linux/regmap.h index e4b9ad4f05ef..519c96231a91 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -505,6 +505,8 @@ int regmap_field_update_bits(struct regmap_field *field, int regmap_fields_write(struct regmap_field *field, unsigned int id, unsigned int val); +int regmap_fields_force_write(struct regmap_field *field, unsigned int id, + unsigned int val); int regmap_fields_read(struct regmap_field *field, unsigned int id, unsigned int *val); int regmap_fields_update_bits(struct regmap_field *field, unsigned int id, From 0642ef6f2992eba46c41abb5ceb7d4fa14ba888e Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 23 Jun 2015 14:32:54 +0100 Subject: [PATCH 4/7] debugfs: Export bool read/write functions The file read/write functions for bools have no special dependencies on debugfs internals and are sufficiently non-trivial to be worth exporting so clients can re-use the implementation. Signed-off-by: Richard Fitzgerald Acked-by: Greg Kroah-Hartman Signed-off-by: Mark Brown --- fs/debugfs/file.c | 14 ++++++++------ include/linux/debugfs.h | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 284f9aa0028b..6c55ade071c3 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -435,8 +435,8 @@ struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode, } EXPORT_SYMBOL_GPL(debugfs_create_atomic_t); -static ssize_t read_file_bool(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) { char buf[3]; u32 *val = file->private_data; @@ -449,9 +449,10 @@ static ssize_t read_file_bool(struct file *file, char __user *user_buf, buf[2] = 0x00; return simple_read_from_buffer(user_buf, count, ppos, buf, 2); } +EXPORT_SYMBOL_GPL(debugfs_read_file_bool); -static ssize_t write_file_bool(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) +ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) { char buf[32]; size_t buf_size; @@ -468,10 +469,11 @@ static ssize_t write_file_bool(struct file *file, const char __user *user_buf, return count; } +EXPORT_SYMBOL_GPL(debugfs_write_file_bool); static const struct file_operations fops_bool = { - .read = read_file_bool, - .write = write_file_bool, + .read = debugfs_read_file_bool, + .write = debugfs_write_file_bool, .open = simple_open, .llseek = default_llseek, }; diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index 420311bcee38..9beb636b97eb 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -116,6 +116,12 @@ struct dentry *debugfs_create_devm_seqfile(struct device *dev, const char *name, bool debugfs_initialized(void); +ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos); + +ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos); + #else #include @@ -282,6 +288,20 @@ static inline struct dentry *debugfs_create_devm_seqfile(struct device *dev, return ERR_PTR(-ENODEV); } +static inline ssize_t debugfs_read_file_bool(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + return -ENODEV; +} + +static inline ssize_t debugfs_write_file_bool(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + return -ENODEV; +} + #endif #endif From d3dc5430d68fb91a62d971648170b34d46ab85bc Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 23 Jun 2015 14:32:55 +0100 Subject: [PATCH 5/7] regmap: debugfs: Allow writes to cache state settings Allow the user to write the cache_only and cache_bypass settings. This can be useful for debugging. Since this can lead to the hardware getting out-of-sync with the cache, at least for the period that the cache state is forced, the kernel is tainted and the action is recorded in the kernel log. When disabling cache_only through debugfs a cache sync will be performed. Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-debugfs.c | 90 ++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 4 deletions(-) diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 5799a0b9e6cc..6a61e4fa73a2 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -469,6 +469,87 @@ static const struct file_operations regmap_access_fops = { .llseek = default_llseek, }; +static ssize_t regmap_cache_only_write_file(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct regmap *map = container_of(file->private_data, + struct regmap, cache_only); + ssize_t result; + bool was_enabled, require_sync = false; + int err; + + map->lock(map->lock_arg); + + was_enabled = map->cache_only; + + result = debugfs_write_file_bool(file, user_buf, count, ppos); + if (result < 0) { + map->unlock(map->lock_arg); + return result; + } + + if (map->cache_only && !was_enabled) { + dev_warn(map->dev, "debugfs cache_only=Y forced\n"); + add_taint(TAINT_USER, LOCKDEP_STILL_OK); + } else if (!map->cache_only && was_enabled) { + dev_warn(map->dev, "debugfs cache_only=N forced: syncing cache\n"); + require_sync = true; + } + + map->unlock(map->lock_arg); + + if (require_sync) { + err = regcache_sync(map); + if (err) + dev_err(map->dev, "Failed to sync cache %d\n", err); + } + + return result; +} + +static const struct file_operations regmap_cache_only_fops = { + .open = simple_open, + .read = debugfs_read_file_bool, + .write = regmap_cache_only_write_file, +}; + +static ssize_t regmap_cache_bypass_write_file(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct regmap *map = container_of(file->private_data, + struct regmap, cache_bypass); + ssize_t result; + bool was_enabled; + + map->lock(map->lock_arg); + + was_enabled = map->cache_bypass; + + result = debugfs_write_file_bool(file, user_buf, count, ppos); + if (result < 0) + goto out; + + if (map->cache_bypass && !was_enabled) { + dev_warn(map->dev, "debugfs cache_bypass=Y forced\n"); + add_taint(TAINT_USER, LOCKDEP_STILL_OK); + } else if (!map->cache_bypass && was_enabled) { + dev_warn(map->dev, "debugfs cache_bypass=N forced\n"); + } + +out: + map->unlock(map->lock_arg); + + return result; +} + +static const struct file_operations regmap_cache_bypass_fops = { + .open = simple_open, + .read = debugfs_read_file_bool, + .write = regmap_cache_bypass_write_file, +}; + void regmap_debugfs_init(struct regmap *map, const char *name) { struct rb_node *next; @@ -530,12 +611,13 @@ void regmap_debugfs_init(struct regmap *map, const char *name) } if (map->cache_type) { - debugfs_create_bool("cache_only", 0400, map->debugfs, - &map->cache_only); + debugfs_create_file("cache_only", 0600, map->debugfs, + &map->cache_only, ®map_cache_only_fops); debugfs_create_bool("cache_dirty", 0400, map->debugfs, &map->cache_dirty); - debugfs_create_bool("cache_bypass", 0400, map->debugfs, - &map->cache_bypass); + debugfs_create_file("cache_bypass", 0600, map->debugfs, + &map->cache_bypass, + ®map_cache_bypass_fops); } next = rb_first(&map->range_tree); From 1635e88885a8e16dec21206c981421f1f3c3b1df Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 6 Aug 2015 10:35:23 +0800 Subject: [PATCH 6/7] regmap: debugfs: Fix misuse of IS_ENABLED IS_ENABLED should only be used for CONFIG_* symbols. I have done a small test: #define REGMAP_ALLOW_WRITE_DEBUGFS IS_ENABLED(REGMAP_ALLOW_WRITE_DEBUGFS) returns 0. #define REGMAP_ALLOW_WRITE_DEBUGFS 0 IS_ENABLED(REGMAP_ALLOW_WRITE_DEBUGFS) returns 0. #define REGMAP_ALLOW_WRITE_DEBUGFS 1 IS_ENABLED(REGMAP_ALLOW_WRITE_DEBUGFS) returns 1. #define REGMAP_ALLOW_WRITE_DEBUGFS 2 IS_ENABLED(REGMAP_ALLOW_WRITE_DEBUGFS) returns 0. So fix the misuse of IS_ENABLED(REGMAP_ALLOW_WRITE_DEBUGFS) and switch to use #if defined(REGMAP_ALLOW_WRITE_DEBUGFS) instead. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-debugfs.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 6a61e4fa73a2..f42f2bac6466 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -599,10 +599,11 @@ void regmap_debugfs_init(struct regmap *map, const char *name) if (map->max_register || regmap_readable(map, 0)) { umode_t registers_mode; - if (IS_ENABLED(REGMAP_ALLOW_WRITE_DEBUGFS)) - registers_mode = 0600; - else - registers_mode = 0400; +#if defined(REGMAP_ALLOW_WRITE_DEBUGFS) + registers_mode = 0600; +#else + registers_mode = 0400; +#endif debugfs_create_file("registers", registers_mode, map->debugfs, map, ®map_map_fops); From ad3a942bd22fd40a0f4ddaf2759946ce945662af Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 1 Jun 2015 18:47:55 -0700 Subject: [PATCH 7/7] regulator: core: Print at debug level on debugfs creation failure Failure to create a debugfs node is not an error, but we print a warning upon failure to create the node. Downgrade this to a debug printk so that we're quiet here. This allows multiple drivers to request a CPU's regulator so that CPUfreq and AVSish drivers can coexist. The downside of this approach is that whoever gets to debugfs first the others who come later to not have any debugfs attributes associated with them. Signed-off-by: Stephen Boyd Signed-off-by: Mark Brown --- drivers/regulator/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index c9f72019bd68..c203f3ebe951 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1240,7 +1240,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, regulator->debugfs = debugfs_create_dir(regulator->supply_name, rdev->debugfs); if (!regulator->debugfs) { - rdev_warn(rdev, "Failed to create debugfs directory\n"); + rdev_dbg(rdev, "Failed to create debugfs directory\n"); } else { debugfs_create_u32("uA_load", 0444, regulator->debugfs, ®ulator->uA_load);