aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorXiubo Li <Li.Xiubo@freescale.com>2014-04-01 22:20:17 -0400
committerMark Brown <broonie@linaro.org>2014-04-14 11:58:54 -0400
commit88cb32c657ed13dc29561d0f4aa154e0fd25759f (patch)
treeb1e737c0e70e8c1bc3a7ed9dc690a12fa99d8ad0 /drivers/base
parentc9eaa447e77efe77b7fa4c953bd62de8297fd6c5 (diff)
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 <Li.Xiubo@freescale.com> Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/regmap/regmap-mmio.c29
1 files changed, 24 insertions, 5 deletions
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)
66 BUG_ON(count % 2 != 0); 66 BUG_ON(count % 2 != 0);
67} 67}
68 68
69static inline unsigned int
70regmap_mmio_get_offset(const void *reg, size_t reg_size)
71{
72 switch (reg_size) {
73 case 1:
74 return *(u8 *)reg;
75 case 2:
76 return *(u16 *)reg;
77 case 4:
78 return *(u32 *)reg;
79#ifdef CONFIG_64BIT
80 case 8:
81 return *(u64 *)reg;
82#endif
83 default:
84 BUG();
85 }
86}
87
69static int regmap_mmio_gather_write(void *context, 88static int regmap_mmio_gather_write(void *context,
70 const void *reg, size_t reg_size, 89 const void *reg, size_t reg_size,
71 const void *val, size_t val_size) 90 const void *val, size_t val_size)
72{ 91{
73 struct regmap_mmio_context *ctx = context; 92 struct regmap_mmio_context *ctx = context;
74 u32 offset; 93 unsigned int offset;
75 int ret; 94 int ret;
76 95
77 regmap_mmio_regsize_check(reg_size); 96 regmap_mmio_regsize_check(reg_size);
@@ -82,7 +101,7 @@ static int regmap_mmio_gather_write(void *context,
82 return ret; 101 return ret;
83 } 102 }
84 103
85 offset = *(u32 *)reg; 104 offset = regmap_mmio_get_offset(reg, reg_size);
86 105
87 while (val_size) { 106 while (val_size) {
88 switch (ctx->val_bytes) { 107 switch (ctx->val_bytes) {
@@ -118,7 +137,7 @@ static int regmap_mmio_gather_write(void *context,
118static int regmap_mmio_write(void *context, const void *data, size_t count) 137static int regmap_mmio_write(void *context, const void *data, size_t count)
119{ 138{
120 struct regmap_mmio_context *ctx = context; 139 struct regmap_mmio_context *ctx = context;
121 u32 offset = ctx->reg_bytes + ctx->pad_bytes; 140 unsigned int offset = ctx->reg_bytes + ctx->pad_bytes;
122 141
123 regmap_mmio_count_check(count); 142 regmap_mmio_count_check(count);
124 143
@@ -131,7 +150,7 @@ static int regmap_mmio_read(void *context,
131 void *val, size_t val_size) 150 void *val, size_t val_size)
132{ 151{
133 struct regmap_mmio_context *ctx = context; 152 struct regmap_mmio_context *ctx = context;
134 u32 offset; 153 unsigned int offset;
135 int ret; 154 int ret;
136 155
137 regmap_mmio_regsize_check(reg_size); 156 regmap_mmio_regsize_check(reg_size);
@@ -142,7 +161,7 @@ static int regmap_mmio_read(void *context,
142 return ret; 161 return ret;
143 } 162 }
144 163
145 offset = *(u32 *)reg; 164 offset = regmap_mmio_get_offset(reg, reg_size);
146 165
147 while (val_size) { 166 while (val_size) {
148 switch (ctx->val_bytes) { 167 switch (ctx->val_bytes) {