From: Xiubo Li 
Date: Wed, 2 Apr 2014 02:20:17 +0000 (+0800)
Subject: regmap: mmio: Fix the bug of 'offset' value parsing.
X-Git-Tag: v3.16-rc1~30^2~30^2~1^4
X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=88cb32c657ed13dc29561d0f4aa154e0fd25759f;p=users%2Fhch%2Fconfigfs.git
regmap: mmio: Fix the bug of 'offset' value parsing.
'offset = *(u32 *)reg;'
This will be okey for 32/64-bits register device, but for 8/16-bits
register ones, the 'offset' value will overflow, for example:
The IMX2 Watchdog, whose registers and values are all 16-bits:
If the IO base virtual address is ctx->regs = 0x888c0000, and the now
doing the 0x00 register accessing:
Using 'offset = *(u32 *)reg' the offset value will possiblly be 0x77310000,
Using 'offset = *(u16 *)reg' the offset value will be 0x0000.
In the regmap_mmio_gather_write(), ctx->regs + 0x7731000 will be 0xffbd0000,
but actually it should be ctx->regs + 0x0000 = 0x888c0000.
Signed-off-by: Xiubo Li 
Signed-off-by: Mark Brown 
---
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
index 1e03e7f8bacb..dff32c6b2474 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -66,12 +66,31 @@ static inline void regmap_mmio_count_check(size_t count)
 	BUG_ON(count % 2 != 0);
 }
 
+static inline unsigned int
+regmap_mmio_get_offset(const void *reg, size_t reg_size)
+{
+	switch (reg_size) {
+	case 1:
+		return *(u8 *)reg;
+	case 2:
+		return *(u16 *)reg;
+	case 4:
+		return *(u32 *)reg;
+#ifdef CONFIG_64BIT
+	case 8:
+		return *(u64 *)reg;
+#endif
+	default:
+		BUG();
+	}
+}
+
 static int regmap_mmio_gather_write(void *context,
 				    const void *reg, size_t reg_size,
 				    const void *val, size_t val_size)
 {
 	struct regmap_mmio_context *ctx = context;
-	u32 offset;
+	unsigned int offset;
 	int ret;
 
 	regmap_mmio_regsize_check(reg_size);
@@ -82,7 +101,7 @@ static int regmap_mmio_gather_write(void *context,
 			return ret;
 	}
 
-	offset = *(u32 *)reg;
+	offset = regmap_mmio_get_offset(reg, reg_size);
 
 	while (val_size) {
 		switch (ctx->val_bytes) {
@@ -118,7 +137,7 @@ static int regmap_mmio_gather_write(void *context,
 static int regmap_mmio_write(void *context, const void *data, size_t count)
 {
 	struct regmap_mmio_context *ctx = context;
-	u32 offset = ctx->reg_bytes + ctx->pad_bytes;
+	unsigned int offset = ctx->reg_bytes + ctx->pad_bytes;
 
 	regmap_mmio_count_check(count);
 
@@ -131,7 +150,7 @@ static int regmap_mmio_read(void *context,
 			    void *val, size_t val_size)
 {
 	struct regmap_mmio_context *ctx = context;
-	u32 offset;
+	unsigned int offset;
 	int ret;
 
 	regmap_mmio_regsize_check(reg_size);
@@ -142,7 +161,7 @@ static int regmap_mmio_read(void *context,
 			return ret;
 	}
 
-	offset = *(u32 *)reg;
+	offset = regmap_mmio_get_offset(reg, reg_size);
 
 	while (val_size) {
 		switch (ctx->val_bytes) {