diff options
author | Xiubo Li <Li.Xiubo@freescale.com> | 2014-04-01 22:20:17 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-04-14 11:58:54 -0400 |
commit | 88cb32c657ed13dc29561d0f4aa154e0fd25759f (patch) | |
tree | b1e737c0e70e8c1bc3a7ed9dc690a12fa99d8ad0 /drivers/base | |
parent | c9eaa447e77efe77b7fa4c953bd62de8297fd6c5 (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.c | 29 |
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 | ||
69 | static inline unsigned int | ||
70 | regmap_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 | |||
69 | static int regmap_mmio_gather_write(void *context, | 88 | static 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, | |||
118 | static int regmap_mmio_write(void *context, const void *data, size_t count) | 137 | static 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) { |