From 29bb45f25ff3051354ed330c0d0f10418a2b8c7c Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Thu, 29 Oct 2015 19:58:47 +0000 Subject: regmap-mmio: Use native endianness for read/write The regmap API has an endianness setting for formatting reads and writes. This can be set by the usual DT "little-endian" and "big-endian" properties. To work properly the associated regmap_bus needs to read/write in native endian. The "syscon" DT device binding creates an mmio-based regmap_bus which performs all reads/writes as little-endian. These values are then converted again by regmap, which means that all of the MIPS BCM boards (which are big-endian) have been declared as "little-endian" to get regmap to convert them back to big-endian. Modify regmap-mmio to use the native-endian functions __raw_read*() and __raw_write*() instead of the little-endian functions read*() and write*(). Modify the big-endian MIPS BCM boards to use what will now be the correct endianness instead of pretending that the devices are little-endian. Signed-off-by: Simon Arlott Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-mmio.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index 426a57e41ac7..8a77876d439a 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -106,17 +106,17 @@ static int regmap_mmio_gather_write(void *context, while (val_size) { switch (ctx->val_bytes) { case 1: - writeb(*(u8 *)val, ctx->regs + offset); + __raw_writeb(*(u8 *)val, ctx->regs + offset); break; case 2: - writew(*(u16 *)val, ctx->regs + offset); + __raw_writew(*(u16 *)val, ctx->regs + offset); break; case 4: - writel(*(u32 *)val, ctx->regs + offset); + __raw_writel(*(u32 *)val, ctx->regs + offset); break; #ifdef CONFIG_64BIT case 8: - writeq(*(u64 *)val, ctx->regs + offset); + __raw_writeq(*(u64 *)val, ctx->regs + offset); break; #endif default: @@ -166,17 +166,17 @@ static int regmap_mmio_read(void *context, while (val_size) { switch (ctx->val_bytes) { case 1: - *(u8 *)val = readb(ctx->regs + offset); + *(u8 *)val = __raw_readb(ctx->regs + offset); break; case 2: - *(u16 *)val = readw(ctx->regs + offset); + *(u16 *)val = __raw_readw(ctx->regs + offset); break; case 4: - *(u32 *)val = readl(ctx->regs + offset); + *(u32 *)val = __raw_readl(ctx->regs + offset); break; #ifdef CONFIG_64BIT case 8: - *(u64 *)val = readq(ctx->regs + offset); + *(u64 *)val = __raw_readq(ctx->regs + offset); break; #endif default: -- cgit v1.2.3 From 6399aea629b02a23364efcb6eea1319b8e9d1abf Mon Sep 17 00:00:00 2001 From: Nikesh Oswal Date: Wed, 21 Oct 2015 14:16:14 +0100 Subject: regmap: rbtree: When adding a reg do a bsearch for target node A binary search is much more efficient rather than iterating over the rbtree in ascending order which the current code is doing. During initialisation the reg defaults are written to the cache in a large chunk and these are always sorted in the ascending order so for this situation ideally we should have iterated the rbtree in descending order. But at runtime the drivers may write into the cache in any random order so this patch selects to use a bsearch to give an optimal runtime performance and also at initialisation time when reg defaults are written the performance of binary search would be much better than iterating in ascending order which the current code was doing. Signed-off-by: Nikesh Oswal Signed-off-by: Mark Brown --- drivers/base/regmap/regcache-rbtree.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index 56486d92c4e7..353f60236ce0 100644 --- a/drivers/base/regmap/regcache-rbtree.c +++ b/drivers/base/regmap/regcache-rbtree.c @@ -413,8 +413,8 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg, max = reg + max_dist; /* look for an adjacent register to the one we are about to add */ - for (node = rb_first(&rbtree_ctx->root); node; - node = rb_next(node)) { + node = rbtree_ctx->root.rb_node; + while (node) { rbnode_tmp = rb_entry(node, struct regcache_rbtree_node, node); @@ -425,6 +425,11 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg, new_base_reg = min(reg, base_reg); new_top_reg = max(reg, top_reg); } else { + if (max < base_reg) + node = node->rb_left; + else + node = node->rb_right; + continue; } -- cgit v1.2.3 From 9d98fa712920a393591f446fa76cb277309dd37b Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Thu, 3 Dec 2015 13:27:20 +0800 Subject: regmap: mmio: remove the useless code Signed-off-by: Xiubo Li Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-mmio.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index 8a77876d439a..dc991c3bec25 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -247,7 +247,6 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, min_stride = 8; break; #endif - break; default: return ERR_PTR(-EINVAL); } -- cgit v1.2.3 From 75fb0aaea18dbcde60a740c5d62af705366d6357 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Thu, 3 Dec 2015 13:27:21 +0800 Subject: regmap: mmio: Add regmap_mmio_get_min_stride Splite the minimal stride parsing into one signal function. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-mmio.c | 49 ++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 19 deletions(-) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index dc991c3bec25..8812bfb9e3b8 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -61,6 +61,33 @@ static int regmap_mmio_regbits_check(size_t reg_bits) } } +static int regmap_mmio_get_min_stride(size_t val_bits) +{ + int min_stride; + + switch (val_bits) { + case 8: + /* The core treats 0 as 1 */ + min_stride = 0; + return 0; + case 16: + min_stride = 2; + break; + case 32: + min_stride = 4; + break; +#ifdef CONFIG_64BIT + case 64: + min_stride = 8; + break; +#endif + default: + return -EINVAL; + } + + return min_stride; +} + static inline void regmap_mmio_count_check(size_t count, u32 offset) { BUG_ON(count <= offset); @@ -231,25 +258,9 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, if (config->pad_bits) return ERR_PTR(-EINVAL); - switch (config->val_bits) { - case 8: - /* The core treats 0 as 1 */ - min_stride = 0; - break; - case 16: - min_stride = 2; - break; - case 32: - min_stride = 4; - break; -#ifdef CONFIG_64BIT - case 64: - min_stride = 8; - break; -#endif - default: - return ERR_PTR(-EINVAL); - } + min_stride = regmap_mmio_get_min_stride(config->val_bits); + if (min_stride < 0) + return ERR_PTR(min_stride); if (config->reg_stride < min_stride) return ERR_PTR(-EINVAL); -- cgit v1.2.3 From 8da61f24cc4a4a66ecae69aa9b9aa8fd989a8969 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 20 Oct 2015 15:40:59 +0100 Subject: regmap: debugfs: Use seq_file for the access map Unlike the registers file we don't have any substantial performance concerns rendering the entire file (it involves no device accesses) so just use seq_printf() to simplify the code. Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-debugfs.c | 69 ++++++++++-------------------------- 1 file changed, 18 insertions(+), 51 deletions(-) (limited to 'drivers/base/regmap') diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 3f0a7e262d69..1ee3d40861c7 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -397,72 +397,39 @@ static const struct file_operations regmap_reg_ranges_fops = { .llseek = default_llseek, }; -static ssize_t regmap_access_read_file(struct file *file, - char __user *user_buf, size_t count, - loff_t *ppos) +static int regmap_access_show(struct seq_file *s, void *ignored) { - int reg_len, tot_len; - size_t buf_pos = 0; - loff_t p = 0; - ssize_t ret; - int i; - struct regmap *map = file->private_data; - char *buf; - - if (*ppos < 0 || !count) - return -EINVAL; + struct regmap *map = s->private; + int i, reg_len; - buf = kmalloc(count, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - /* Calculate the length of a fixed format */ reg_len = regmap_calc_reg_len(map->max_register); - tot_len = reg_len + 10; /* ': R W V P\n' */ for (i = 0; i <= map->max_register; i += map->reg_stride) { /* Ignore registers which are neither readable nor writable */ if (!regmap_readable(map, i) && !regmap_writeable(map, i)) continue; - /* If we're in the region the user is trying to read */ - if (p >= *ppos) { - /* ...but not beyond it */ - if (buf_pos + tot_len + 1 >= count) - break; - - /* Format the register */ - snprintf(buf + buf_pos, count - buf_pos, - "%.*x: %c %c %c %c\n", - reg_len, i, - regmap_readable(map, i) ? 'y' : 'n', - regmap_writeable(map, i) ? 'y' : 'n', - regmap_volatile(map, i) ? 'y' : 'n', - regmap_precious(map, i) ? 'y' : 'n'); - - buf_pos += tot_len; - } - p += tot_len; - } - - ret = buf_pos; - - if (copy_to_user(user_buf, buf, buf_pos)) { - ret = -EFAULT; - goto out; + /* Format the register */ + seq_printf(s, "%.*x: %c %c %c %c\n", reg_len, i, + regmap_readable(map, i) ? 'y' : 'n', + regmap_writeable(map, i) ? 'y' : 'n', + regmap_volatile(map, i) ? 'y' : 'n', + regmap_precious(map, i) ? 'y' : 'n'); } - *ppos += buf_pos; + return 0; +} -out: - kfree(buf); - return ret; +static int access_open(struct inode *inode, struct file *file) +{ + return single_open(file, regmap_access_show, inode->i_private); } static const struct file_operations regmap_access_fops = { - .open = simple_open, - .read = regmap_access_read_file, - .llseek = default_llseek, + .open = access_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, }; static ssize_t regmap_cache_only_write_file(struct file *file, -- cgit v1.2.3