* [PATCH 1/2 v3] regmap: Support accelerated noinc operations
@ 2022-08-16 13:08 Linus Walleij
2022-08-16 13:08 ` [PATCH 2/2 v3] regmap: mmio: Support accelerared " Linus Walleij
2022-08-17 13:34 ` [PATCH 1/2 v3] regmap: Support accelerated " Mark Brown
0 siblings, 2 replies; 8+ messages in thread
From: Linus Walleij @ 2022-08-16 13:08 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-kernel, Linus Walleij
Several architectures have accelerated operations for MMIO
operations writing to a single register, such as writesb, writesw,
writesl, writesq, readsb, readsw, readsl and readsq but regmap
currently cannot use them because we have no hooks for providing
an accelerated noinc back-end for MMIO.
Solve this by providing reg_[read/write]_noinc callbacks for
the bus abstraction, so that the regmap-mmio bus can use this.
Currently I do not see a need to support this for custom regmaps
so it is only added to the bus.
Callbacks are passed a void * with the array of values and a
count which is the number of items of the byte chunk size for
the specific register width.
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ChangeLog v2->v3:
- Rebase on kernel v6.0-rc1
ChangeLog v1->v2:
- Factor out and reuse the code to format and read or write a
buffer of data to a noinc register at the cost of dropping
const from the buffer pointer in the write call. This is a
deadly sin in Rust and therefore impossible, but hey, this is
C, and dropping a const is a lesser evil than not being
able to reuse code.
---
drivers/base/regmap/regmap.c | 123 ++++++++++++++++++++++++++++++++++-
include/linux/regmap.h | 8 +++
2 files changed, 128 insertions(+), 3 deletions(-)
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index fee221c5008c..dbe2042f92f3 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2132,6 +2132,99 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
}
EXPORT_SYMBOL_GPL(regmap_raw_write);
+static int regmap_noinc_readwrite(struct regmap *map, unsigned int reg,
+ void *val, unsigned int val_len, bool write)
+{
+ size_t val_bytes = map->format.val_bytes;
+ size_t val_count = val_len / val_bytes;
+ unsigned int lastval;
+ u8 *u8p;
+ u16 *u16p;
+ u32 *u32p;
+#ifdef CONFIG_64BIT
+ u64 *u64p;
+#endif
+ int ret;
+ int i;
+
+ switch (val_bytes) {
+ case 1:
+ u8p = val;
+ if (write)
+ lastval = (unsigned int)u8p[val_count - 1];
+ break;
+ case 2:
+ u16p = val;
+ if (write)
+ lastval = (unsigned int)u16p[val_count - 1];
+ break;
+ case 4:
+ u32p = val;
+ if (write)
+ lastval = (unsigned int)u32p[val_count - 1];
+ break;
+#ifdef CONFIG_64BIT
+ case 8:
+ u64p = val;
+ if (write)
+ lastval = (unsigned int)u64p[val_count - 1];
+ break;
+#endif
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * Update the cache with the last value we write, the rest is just
+ * gone down in the hardware FIFO. We can't cache FIFOs. This makes
+ * sure a single read from the cache will work.
+ */
+ if (write) {
+ if (!map->cache_bypass && !map->defer_caching) {
+ ret = regcache_write(map, reg, lastval);
+ if (ret != 0)
+ return ret;
+ if (map->cache_only) {
+ map->cache_dirty = true;
+ return 0;
+ }
+ }
+ ret = map->bus->reg_noinc_write(map->bus_context, reg, val, val_count);
+ } else {
+ ret = map->bus->reg_noinc_read(map->bus_context, reg, val, val_count);
+ }
+
+ if (!ret && regmap_should_log(map)) {
+ dev_info(map->dev, "%x %s [", reg, write ? "<=" : "=>");
+ for (i = 0; i < val_len; i++) {
+ switch (val_bytes) {
+ case 1:
+ pr_cont("%x", u8p[i]);
+ break;
+ case 2:
+ pr_cont("%x", u16p[i]);
+ break;
+ case 4:
+ pr_cont("%x", u32p[i]);
+ break;
+#ifdef CONFIG_64BIT
+ case 8:
+ pr_cont("%llx", u64p[i]);
+ break;
+#endif
+ default:
+ break;
+ }
+ if (i == (val_len - 1))
+ pr_cont("]\n");
+ else
+ pr_cont(",");
+ }
+ }
+
+ return 0;
+}
+
/**
* regmap_noinc_write(): Write data from a register without incrementing the
* register number
@@ -2159,9 +2252,8 @@ int regmap_noinc_write(struct regmap *map, unsigned int reg,
size_t write_len;
int ret;
- if (!map->write)
- return -ENOTSUPP;
-
+ if (!map->write && !(map->bus && map->bus->reg_noinc_write))
+ return -EINVAL;
if (val_len % map->format.val_bytes)
return -EINVAL;
if (!IS_ALIGNED(reg, map->reg_stride))
@@ -2176,6 +2268,15 @@ int regmap_noinc_write(struct regmap *map, unsigned int reg,
goto out_unlock;
}
+ /*
+ * Use the accelerated operation if we can. The val drops the const
+ * typing in order to facilitate code reuse in regmap_noinc_readwrite().
+ */
+ if (map->bus->reg_noinc_write) {
+ ret = regmap_noinc_readwrite(map, reg, (void *)val, val_len, true);
+ goto out_unlock;
+ }
+
while (val_len) {
if (map->max_raw_write && map->max_raw_write < val_len)
write_len = map->max_raw_write;
@@ -2946,6 +3047,22 @@ int regmap_noinc_read(struct regmap *map, unsigned int reg,
goto out_unlock;
}
+ /* Use the accelerated operation if we can */
+ if (map->bus->reg_noinc_read) {
+ /*
+ * We have not defined the FIFO semantics for cache, as the
+ * cache is just one value deep. Should we return the last
+ * written value? Just avoid this by always reading the FIFO
+ * even when using cache. Cache only will not work.
+ */
+ if (map->cache_only) {
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+ ret = regmap_noinc_readwrite(map, reg, val, val_len, false);
+ goto out_unlock;
+ }
+
while (val_len) {
if (map->max_raw_read && map->max_raw_read < val_len)
read_len = map->max_raw_read;
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 7cf2157134ac..7d4d257b2bf9 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -489,8 +489,12 @@ typedef int (*regmap_hw_read)(void *context,
void *val_buf, size_t val_size);
typedef int (*regmap_hw_reg_read)(void *context, unsigned int reg,
unsigned int *val);
+typedef int (*regmap_hw_reg_noinc_read)(void *context, unsigned int reg,
+ void *val, size_t val_count);
typedef int (*regmap_hw_reg_write)(void *context, unsigned int reg,
unsigned int val);
+typedef int (*regmap_hw_reg_noinc_write)(void *context, unsigned int reg,
+ const void *val, size_t val_count);
typedef int (*regmap_hw_reg_update_bits)(void *context, unsigned int reg,
unsigned int mask, unsigned int val);
typedef struct regmap_async *(*regmap_hw_async_alloc)(void);
@@ -511,6 +515,8 @@ typedef void (*regmap_hw_free_context)(void *context);
* must serialise with respect to non-async I/O.
* @reg_write: Write a single register value to the given register address. This
* write operation has to complete when returning from the function.
+ * @reg_write_noinc: Write multiple register value to the same register. This
+ * write operation has to complete when returning from the function.
* @reg_update_bits: Update bits operation to be used against volatile
* registers, intended for devices supporting some mechanism
* for setting clearing bits without having to
@@ -538,9 +544,11 @@ struct regmap_bus {
regmap_hw_gather_write gather_write;
regmap_hw_async_write async_write;
regmap_hw_reg_write reg_write;
+ regmap_hw_reg_noinc_write reg_noinc_write;
regmap_hw_reg_update_bits reg_update_bits;
regmap_hw_read read;
regmap_hw_reg_read reg_read;
+ regmap_hw_reg_noinc_read reg_noinc_read;
regmap_hw_free_context free_context;
regmap_hw_async_alloc async_alloc;
u8 read_flag_mask;
--
2.37.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/2 v3] regmap: mmio: Support accelerared noinc operations
2022-08-16 13:08 [PATCH 1/2 v3] regmap: Support accelerated noinc operations Linus Walleij
@ 2022-08-16 13:08 ` Linus Walleij
2022-08-16 13:13 ` Mark Brown
2022-08-16 19:44 ` kernel test robot
2022-08-17 13:34 ` [PATCH 1/2 v3] regmap: Support accelerated " Mark Brown
1 sibling, 2 replies; 8+ messages in thread
From: Linus Walleij @ 2022-08-16 13:08 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-kernel, Linus Walleij
Use the newly added callback for accelerated noinc MMIO
to provide writesb, writesw, writesl, writesq, readsb, readsw,
readsl and readsq.
A special quirk is needed to deal with big endian regmaps: there
are no accelerated operations defined for big endian, so fall
back to calling the big endian operations itereatively for this
case.
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ChangeLog v2->v3:
- Rebase on kernel v6.0-rc1
ChangeLog v1->v2:
- No changes.
---
drivers/base/regmap/regmap-mmio.c | 153 ++++++++++++++++++++++++++++++
1 file changed, 153 insertions(+)
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
index 71f16be7e717..031ee91020e8 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -17,6 +17,7 @@ struct regmap_mmio_context {
void __iomem *regs;
unsigned int val_bytes;
bool relaxed_mmio;
+ bool big_endian;
bool attached_clk;
struct clk *clk;
@@ -160,6 +161,79 @@ static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val)
return 0;
}
+static int regmap_mmio_noinc_write(void *context, unsigned int reg,
+ const void *val, size_t val_count)
+{
+ struct regmap_mmio_context *ctx = context;
+ int ret = 0;
+ int i;
+
+ if (!IS_ERR(ctx->clk)) {
+ ret = clk_enable(ctx->clk);
+ if (ret < 0)
+ return ret;
+ }
+
+ /*
+ * There are no native, assembly-optimized write single register
+ * operations for big endian, so fall back to emulation if this
+ * is needed. (Single bytes are fine, they are not affected by
+ * endianness.)
+ */
+ if (ctx->big_endian && (ctx->val_bytes > 1)) {
+ switch (ctx->val_bytes) {
+ case 2:
+ {
+ const u16 *valp = (const u16 *)val;
+ for (i = 0; i < val_count; i++)
+ iowrite16be(valp[i], ctx->regs + reg);
+ break;
+ }
+ case 4:
+ {
+ const u32 *valp = (const u32 *)val;
+ for (i = 0; i < val_count; i++)
+ iowrite32be(valp[i], ctx->regs + reg);
+ break;
+ }
+#ifdef CONFIG_64BIT
+ case 8:
+ /* This is just too esoteric */
+ fallthrough;
+#endif
+ default:
+ ret = -EINVAL;
+ goto out_clk;
+ }
+ }
+
+ switch (ctx->val_bytes) {
+ case 1:
+ writesb(ctx->regs + reg, (const u8 *)val, val_count);
+ break;
+ case 2:
+ writesw(ctx->regs + reg, (const u16 *)val, val_count);
+ break;
+ case 4:
+ writesl(ctx->regs + reg, (const u32 *)val, val_count);
+ break;
+#ifdef CONFIG_64BIT
+ case 8:
+ writesq(ctx->regs + reg, (const u64 *)val, val_count);
+ break;
+#endif
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+out_clk:
+ if (!IS_ERR(ctx->clk))
+ clk_disable(ctx->clk);
+
+ return ret;
+}
+
static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx,
unsigned int reg)
{
@@ -241,6 +315,82 @@ static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
return 0;
}
+static int regmap_mmio_noinc_read(void *context, unsigned int reg,
+ void *val, size_t val_count)
+{
+ struct regmap_mmio_context *ctx = context;
+ int ret = 0;
+ int i;
+
+ if (!IS_ERR(ctx->clk)) {
+ ret = clk_enable(ctx->clk);
+ if (ret < 0)
+ return ret;
+ }
+
+ /*
+ * There are no native, assembly-optimized write single register
+ * operations for big endian, so fall back to emulation if this
+ * is needed. (Single bytes are fine, they are not affected by
+ * endianness.)
+ */
+ if (ctx->big_endian && (ctx->val_bytes > 1)) {
+ switch (ctx->val_bytes) {
+ case 2:
+ {
+ u16 *valp = (u16 *)val;
+ for (i = 0; i < val_count; i++)
+ valp[i] = ioread16be(ctx->regs + reg);
+ break;
+ }
+ case 4:
+ {
+ u32 *valp = (u32 *)val;
+ for (i = 0; i < val_count; i++)
+ valp[i] = ioread32be(ctx->regs + reg);
+ break;
+ }
+#ifdef CONFIG_64BIT
+ case 8:
+ /* This is just too esoteric */
+ fallthrough;
+#endif
+ default:
+ ret = -EINVAL;
+ goto out_clk;
+ }
+ }
+
+ switch (ctx->val_bytes) {
+ case 1:
+ readsb(ctx->regs + reg, (u8 *)val, val_count);
+ break;
+ case 2:
+ readsw(ctx->regs + reg, (u16 *)val, val_count);
+ break;
+ case 4:
+ readsl(ctx->regs + reg, (u32 *)val, val_count);
+ break;
+#ifdef CONFIG_64BIT
+ case 8:
+ readsq(ctx->regs + reg, (u64 *)val, val_count);
+ break;
+#endif
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+out_clk:
+ if (!IS_ERR(ctx->clk))
+ clk_disable(ctx->clk);
+
+ return ret;
+
+ return 0;
+}
+
+
static void regmap_mmio_free_context(void *context)
{
struct regmap_mmio_context *ctx = context;
@@ -257,6 +407,8 @@ static const struct regmap_bus regmap_mmio = {
.fast_io = true,
.reg_write = regmap_mmio_write,
.reg_read = regmap_mmio_read,
+ .reg_noinc_write = regmap_mmio_noinc_write,
+ .reg_noinc_read = regmap_mmio_noinc_read,
.free_context = regmap_mmio_free_context,
.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
};
@@ -347,6 +499,7 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
#ifdef __BIG_ENDIAN
case REGMAP_ENDIAN_NATIVE:
#endif
+ ctx->big_endian = true;
switch (config->val_bits) {
case 8:
ctx->reg_read = regmap_mmio_read8;
--
2.37.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2 v3] regmap: mmio: Support accelerared noinc operations
2022-08-16 13:08 ` [PATCH 2/2 v3] regmap: mmio: Support accelerared " Linus Walleij
@ 2022-08-16 13:13 ` Mark Brown
2022-08-16 14:02 ` Linus Walleij
2022-08-16 19:44 ` kernel test robot
1 sibling, 1 reply; 8+ messages in thread
From: Mark Brown @ 2022-08-16 13:13 UTC (permalink / raw)
To: Linus Walleij; +Cc: linux-kernel
[-- Attachment #1: Type: text/plain, Size: 220 bytes --]
On Tue, Aug 16, 2022 at 03:08:23PM +0200, Linus Walleij wrote:
> ChangeLog v2->v3:
> - Rebase on kernel v6.0-rc1
This doesn't apply against current code, please check and resend - I
already applied some other patches.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2 v3] regmap: mmio: Support accelerared noinc operations
2022-08-16 13:13 ` Mark Brown
@ 2022-08-16 14:02 ` Linus Walleij
0 siblings, 0 replies; 8+ messages in thread
From: Linus Walleij @ 2022-08-16 14:02 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-kernel
On Tue, Aug 16, 2022 at 3:13 PM Mark Brown <broonie@kernel.org> wrote:
> On Tue, Aug 16, 2022 at 03:08:23PM +0200, Linus Walleij wrote:
>
> > ChangeLog v2->v3:
> > - Rebase on kernel v6.0-rc1
>
> This doesn't apply against current code, please check and resend - I
> already applied some other patches.
Oopsie I just assumed v6.0-rc1 was clean :D
I'll rebase on your regmap tree, just a sec.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2 v3] regmap: mmio: Support accelerared noinc operations
2022-08-16 13:08 ` [PATCH 2/2 v3] regmap: mmio: Support accelerared " Linus Walleij
2022-08-16 13:13 ` Mark Brown
@ 2022-08-16 19:44 ` kernel test robot
2022-08-16 20:50 ` Linus Walleij
1 sibling, 1 reply; 8+ messages in thread
From: kernel test robot @ 2022-08-16 19:44 UTC (permalink / raw)
To: Linus Walleij, Mark Brown; +Cc: llvm, kbuild-all, linux-kernel, Linus Walleij
Hi Linus,
I love your patch! Yet something to improve:
[auto build test ERROR on v6.0-rc1]
[also build test ERROR on linus/master]
[cannot apply to broonie-regmap/for-next next-20220816]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Linus-Walleij/regmap-Support-accelerated-noinc-operations/20220816-211403
base: 568035b01cfb107af8d2e4bd2fb9aea22cf5b868
config: hexagon-randconfig-r045-20220815 (https://download.01.org/0day-ci/archive/20220817/202208170316.UKonQfhi-lkp@intel.com/config)
compiler: clang version 16.0.0 (https://github.com/llvm/llvm-project aed5e3bea138ce581d682158eb61c27b3cfdd6ec)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/8ab63711dfb48f91d79fff115511f7895ca39180
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Linus-Walleij/regmap-Support-accelerated-noinc-operations/20220816-211403
git checkout 8ab63711dfb48f91d79fff115511f7895ca39180
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash drivers/base/regmap/
If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>
All errors (new ones prefixed by >>):
>> drivers/base/regmap/regmap-mmio.c:212:3: error: call to undeclared function 'writesb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
writesb(ctx->regs + reg, (const u8 *)val, val_count);
^
drivers/base/regmap/regmap-mmio.c:212:3: note: did you mean 'writeb'?
arch/hexagon/include/asm/io.h:122:20: note: 'writeb' declared here
static inline void writeb(u8 data, volatile void __iomem *addr)
^
>> drivers/base/regmap/regmap-mmio.c:366:3: error: call to undeclared function 'readsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
readsb(ctx->regs + reg, (u8 *)val, val_count);
^
drivers/base/regmap/regmap-mmio.c:366:3: note: did you mean 'readb'?
arch/hexagon/include/asm/io.h:83:18: note: 'readb' declared here
static inline u8 readb(const volatile void __iomem *addr)
^
2 errors generated.
vim +/writesb +212 drivers/base/regmap/regmap-mmio.c
163
164 static int regmap_mmio_noinc_write(void *context, unsigned int reg,
165 const void *val, size_t val_count)
166 {
167 struct regmap_mmio_context *ctx = context;
168 int ret = 0;
169 int i;
170
171 if (!IS_ERR(ctx->clk)) {
172 ret = clk_enable(ctx->clk);
173 if (ret < 0)
174 return ret;
175 }
176
177 /*
178 * There are no native, assembly-optimized write single register
179 * operations for big endian, so fall back to emulation if this
180 * is needed. (Single bytes are fine, they are not affected by
181 * endianness.)
182 */
183 if (ctx->big_endian && (ctx->val_bytes > 1)) {
184 switch (ctx->val_bytes) {
185 case 2:
186 {
187 const u16 *valp = (const u16 *)val;
188 for (i = 0; i < val_count; i++)
189 iowrite16be(valp[i], ctx->regs + reg);
190 break;
191 }
192 case 4:
193 {
194 const u32 *valp = (const u32 *)val;
195 for (i = 0; i < val_count; i++)
196 iowrite32be(valp[i], ctx->regs + reg);
197 break;
198 }
199 #ifdef CONFIG_64BIT
200 case 8:
201 /* This is just too esoteric */
202 fallthrough;
203 #endif
204 default:
205 ret = -EINVAL;
206 goto out_clk;
207 }
208 }
209
210 switch (ctx->val_bytes) {
211 case 1:
> 212 writesb(ctx->regs + reg, (const u8 *)val, val_count);
213 break;
214 case 2:
215 writesw(ctx->regs + reg, (const u16 *)val, val_count);
216 break;
217 case 4:
218 writesl(ctx->regs + reg, (const u32 *)val, val_count);
219 break;
220 #ifdef CONFIG_64BIT
221 case 8:
222 writesq(ctx->regs + reg, (const u64 *)val, val_count);
223 break;
224 #endif
225 default:
226 ret = -EINVAL;
227 break;
228 }
229
230 out_clk:
231 if (!IS_ERR(ctx->clk))
232 clk_disable(ctx->clk);
233
234 return ret;
235 }
236
237 static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx,
238 unsigned int reg)
239 {
240 return readb(ctx->regs + reg);
241 }
242
243 static unsigned int regmap_mmio_read8_relaxed(struct regmap_mmio_context *ctx,
244 unsigned int reg)
245 {
246 return readb_relaxed(ctx->regs + reg);
247 }
248
249 static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx,
250 unsigned int reg)
251 {
252 return readw(ctx->regs + reg);
253 }
254
255 static unsigned int regmap_mmio_read16le_relaxed(struct regmap_mmio_context *ctx,
256 unsigned int reg)
257 {
258 return readw_relaxed(ctx->regs + reg);
259 }
260
261 static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx,
262 unsigned int reg)
263 {
264 return ioread16be(ctx->regs + reg);
265 }
266
267 static unsigned int regmap_mmio_read32le(struct regmap_mmio_context *ctx,
268 unsigned int reg)
269 {
270 return readl(ctx->regs + reg);
271 }
272
273 static unsigned int regmap_mmio_read32le_relaxed(struct regmap_mmio_context *ctx,
274 unsigned int reg)
275 {
276 return readl_relaxed(ctx->regs + reg);
277 }
278
279 static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx,
280 unsigned int reg)
281 {
282 return ioread32be(ctx->regs + reg);
283 }
284
285 #ifdef CONFIG_64BIT
286 static unsigned int regmap_mmio_read64le(struct regmap_mmio_context *ctx,
287 unsigned int reg)
288 {
289 return readq(ctx->regs + reg);
290 }
291
292 static unsigned int regmap_mmio_read64le_relaxed(struct regmap_mmio_context *ctx,
293 unsigned int reg)
294 {
295 return readq_relaxed(ctx->regs + reg);
296 }
297 #endif
298
299 static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
300 {
301 struct regmap_mmio_context *ctx = context;
302 int ret;
303
304 if (!IS_ERR(ctx->clk)) {
305 ret = clk_enable(ctx->clk);
306 if (ret < 0)
307 return ret;
308 }
309
310 *val = ctx->reg_read(ctx, reg);
311
312 if (!IS_ERR(ctx->clk))
313 clk_disable(ctx->clk);
314
315 return 0;
316 }
317
318 static int regmap_mmio_noinc_read(void *context, unsigned int reg,
319 void *val, size_t val_count)
320 {
321 struct regmap_mmio_context *ctx = context;
322 int ret = 0;
323 int i;
324
325 if (!IS_ERR(ctx->clk)) {
326 ret = clk_enable(ctx->clk);
327 if (ret < 0)
328 return ret;
329 }
330
331 /*
332 * There are no native, assembly-optimized write single register
333 * operations for big endian, so fall back to emulation if this
334 * is needed. (Single bytes are fine, they are not affected by
335 * endianness.)
336 */
337 if (ctx->big_endian && (ctx->val_bytes > 1)) {
338 switch (ctx->val_bytes) {
339 case 2:
340 {
341 u16 *valp = (u16 *)val;
342 for (i = 0; i < val_count; i++)
343 valp[i] = ioread16be(ctx->regs + reg);
344 break;
345 }
346 case 4:
347 {
348 u32 *valp = (u32 *)val;
349 for (i = 0; i < val_count; i++)
350 valp[i] = ioread32be(ctx->regs + reg);
351 break;
352 }
353 #ifdef CONFIG_64BIT
354 case 8:
355 /* This is just too esoteric */
356 fallthrough;
357 #endif
358 default:
359 ret = -EINVAL;
360 goto out_clk;
361 }
362 }
363
364 switch (ctx->val_bytes) {
365 case 1:
> 366 readsb(ctx->regs + reg, (u8 *)val, val_count);
367 break;
368 case 2:
369 readsw(ctx->regs + reg, (u16 *)val, val_count);
370 break;
371 case 4:
372 readsl(ctx->regs + reg, (u32 *)val, val_count);
373 break;
374 #ifdef CONFIG_64BIT
375 case 8:
376 readsq(ctx->regs + reg, (u64 *)val, val_count);
377 break;
378 #endif
379 default:
380 ret = -EINVAL;
381 break;
382 }
383
384 out_clk:
385 if (!IS_ERR(ctx->clk))
386 clk_disable(ctx->clk);
387
388 return ret;
389
390 return 0;
391 }
392
--
0-DAY CI Kernel Test Service
https://01.org/lkp
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2 v3] regmap: mmio: Support accelerared noinc operations
2022-08-16 19:44 ` kernel test robot
@ 2022-08-16 20:50 ` Linus Walleij
0 siblings, 0 replies; 8+ messages in thread
From: Linus Walleij @ 2022-08-16 20:50 UTC (permalink / raw)
To: kernel test robot
Cc: Mark Brown, llvm, kbuild-all, linux-kernel, linux-hexagon
On Tue, Aug 16, 2022 at 9:45 PM kernel test robot <lkp@intel.com> wrote:
> >> drivers/base/regmap/regmap-mmio.c:212:3: error: call to undeclared function 'writesb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
> writesb(ctx->regs + reg, (const u8 *)val, val_count);
> ^
> drivers/base/regmap/regmap-mmio.c:212:3: note: did you mean 'writeb'?
> arch/hexagon/include/asm/io.h:122:20: note: 'writeb' declared here
> static inline void writeb(u8 data, volatile void __iomem *addr)
> ^
> >> drivers/base/regmap/regmap-mmio.c:366:3: error: call to undeclared function 'readsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
> readsb(ctx->regs + reg, (u8 *)val, val_count);
> ^
> drivers/base/regmap/regmap-mmio.c:366:3: note: did you mean 'readb'?
> arch/hexagon/include/asm/io.h:83:18: note: 'readb' declared here
> static inline u8 readb(const volatile void __iomem *addr)
> ^
> 2 errors generated.
Yeah Hexagon breaks the <asm/io.h> contract and does not provide
readsb/writesb.
OK I just fix Hexagon as part of patch 2, I hope.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2 v3] regmap: mmio: Support accelerared noinc operations
@ 2022-08-16 20:50 ` Linus Walleij
0 siblings, 0 replies; 8+ messages in thread
From: Linus Walleij @ 2022-08-16 20:50 UTC (permalink / raw)
To: kbuild-all
[-- Attachment #1: Type: text/plain, Size: 1318 bytes --]
On Tue, Aug 16, 2022 at 9:45 PM kernel test robot <lkp@intel.com> wrote:
> >> drivers/base/regmap/regmap-mmio.c:212:3: error: call to undeclared function 'writesb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
> writesb(ctx->regs + reg, (const u8 *)val, val_count);
> ^
> drivers/base/regmap/regmap-mmio.c:212:3: note: did you mean 'writeb'?
> arch/hexagon/include/asm/io.h:122:20: note: 'writeb' declared here
> static inline void writeb(u8 data, volatile void __iomem *addr)
> ^
> >> drivers/base/regmap/regmap-mmio.c:366:3: error: call to undeclared function 'readsb'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
> readsb(ctx->regs + reg, (u8 *)val, val_count);
> ^
> drivers/base/regmap/regmap-mmio.c:366:3: note: did you mean 'readb'?
> arch/hexagon/include/asm/io.h:83:18: note: 'readb' declared here
> static inline u8 readb(const volatile void __iomem *addr)
> ^
> 2 errors generated.
Yeah Hexagon breaks the <asm/io.h> contract and does not provide
readsb/writesb.
OK I just fix Hexagon as part of patch 2, I hope.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2 v3] regmap: Support accelerated noinc operations
2022-08-16 13:08 [PATCH 1/2 v3] regmap: Support accelerated noinc operations Linus Walleij
2022-08-16 13:08 ` [PATCH 2/2 v3] regmap: mmio: Support accelerared " Linus Walleij
@ 2022-08-17 13:34 ` Mark Brown
1 sibling, 0 replies; 8+ messages in thread
From: Mark Brown @ 2022-08-17 13:34 UTC (permalink / raw)
To: Linus Walleij; +Cc: linux-kernel
On Tue, 16 Aug 2022 15:08:22 +0200, Linus Walleij wrote:
> Several architectures have accelerated operations for MMIO
> operations writing to a single register, such as writesb, writesw,
> writesl, writesq, readsb, readsw, readsl and readsq but regmap
> currently cannot use them because we have no hooks for providing
> an accelerated noinc back-end for MMIO.
>
> Solve this by providing reg_[read/write]_noinc callbacks for
> the bus abstraction, so that the regmap-mmio bus can use this.
>
> [...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git for-next
Thanks!
[1/2] regmap: Support accelerated noinc operations
commit: c20cc099b30abd50f563e422aa72edcd7f92da55
[2/2] regmap: mmio: Support accelerared noinc operations
commit: 81c0386c1376da54f05d6916936db5220df9f97d
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2022-08-17 13:35 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-16 13:08 [PATCH 1/2 v3] regmap: Support accelerated noinc operations Linus Walleij
2022-08-16 13:08 ` [PATCH 2/2 v3] regmap: mmio: Support accelerared " Linus Walleij
2022-08-16 13:13 ` Mark Brown
2022-08-16 14:02 ` Linus Walleij
2022-08-16 19:44 ` kernel test robot
2022-08-16 20:50 ` Linus Walleij
2022-08-16 20:50 ` Linus Walleij
2022-08-17 13:34 ` [PATCH 1/2 v3] regmap: Support accelerated " Mark Brown
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.