Skip to content

Commit f01ee60

Browse files
nvswarrenbroonie
authored andcommitted
regmap: implement register striding
regmap_config.reg_stride is introduced. All extant register addresses are a multiple of this value. Users of serial-oriented regmap busses will typically set this to 1. Users of the MMIO regmap bus will typically set this based on the value size of their registers, in bytes, so 4 for a 32-bit register. Throughout the regmap code, actual register addresses are used. Wherever the register address is used to index some array of values, the address is divided by the stride to determine the index, or vice-versa. Error- checking is added to all entry-points for register address data to ensure that register addresses actually satisfy the specified stride. The MMIO bus ensures that the specified stride is large enough for the register size. Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
1 parent c0cc6fe commit f01ee60

File tree

9 files changed

+109
-42
lines changed

9 files changed

+109
-42
lines changed

drivers/base/regmap/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ struct regmap {
6262

6363
/* number of bits to (left) shift the reg value when formatting*/
6464
int reg_shift;
65+
int reg_stride;
6566

6667
/* regcache specific members */
6768
const struct regcache_ops *cache_ops;

drivers/base/regmap/regcache-lzo.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,17 +108,18 @@ static int regcache_lzo_decompress_cache_block(struct regmap *map,
108108
static inline int regcache_lzo_get_blkindex(struct regmap *map,
109109
unsigned int reg)
110110
{
111-
return (reg * map->cache_word_size) /
111+
return ((reg / map->reg_stride) * map->cache_word_size) /
112112
DIV_ROUND_UP(map->cache_size_raw,
113113
regcache_lzo_block_count(map));
114114
}
115115

116116
static inline int regcache_lzo_get_blkpos(struct regmap *map,
117117
unsigned int reg)
118118
{
119-
return reg % (DIV_ROUND_UP(map->cache_size_raw,
120-
regcache_lzo_block_count(map)) /
121-
map->cache_word_size);
119+
return (reg / map->reg_stride) %
120+
(DIV_ROUND_UP(map->cache_size_raw,
121+
regcache_lzo_block_count(map)) /
122+
map->cache_word_size);
122123
}
123124

124125
static inline int regcache_lzo_get_blksize(struct regmap *map)
@@ -322,7 +323,7 @@ static int regcache_lzo_write(struct regmap *map,
322323
}
323324

324325
/* set the bit so we know we have to sync this register */
325-
set_bit(reg, lzo_block->sync_bmp);
326+
set_bit(reg / map->reg_stride, lzo_block->sync_bmp);
326327
kfree(tmp_dst);
327328
kfree(lzo_block->src);
328329
return 0;

drivers/base/regmap/regcache-rbtree.c

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,12 @@ struct regcache_rbtree_ctx {
3939
};
4040

4141
static inline void regcache_rbtree_get_base_top_reg(
42+
struct regmap *map,
4243
struct regcache_rbtree_node *rbnode,
4344
unsigned int *base, unsigned int *top)
4445
{
4546
*base = rbnode->base_reg;
46-
*top = rbnode->base_reg + rbnode->blklen - 1;
47+
*top = rbnode->base_reg + ((rbnode->blklen - 1) * map->reg_stride);
4748
}
4849

4950
static unsigned int regcache_rbtree_get_register(
@@ -70,15 +71,17 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
7071

7172
rbnode = rbtree_ctx->cached_rbnode;
7273
if (rbnode) {
73-
regcache_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
74+
regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
75+
&top_reg);
7476
if (reg >= base_reg && reg <= top_reg)
7577
return rbnode;
7678
}
7779

7880
node = rbtree_ctx->root.rb_node;
7981
while (node) {
8082
rbnode = container_of(node, struct regcache_rbtree_node, node);
81-
regcache_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
83+
regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
84+
&top_reg);
8285
if (reg >= base_reg && reg <= top_reg) {
8386
rbtree_ctx->cached_rbnode = rbnode;
8487
return rbnode;
@@ -92,7 +95,7 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
9295
return NULL;
9396
}
9497

95-
static int regcache_rbtree_insert(struct rb_root *root,
98+
static int regcache_rbtree_insert(struct regmap *map, struct rb_root *root,
9699
struct regcache_rbtree_node *rbnode)
97100
{
98101
struct rb_node **new, *parent;
@@ -106,7 +109,7 @@ static int regcache_rbtree_insert(struct rb_root *root,
106109
rbnode_tmp = container_of(*new, struct regcache_rbtree_node,
107110
node);
108111
/* base and top registers of the current rbnode */
109-
regcache_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp,
112+
regcache_rbtree_get_base_top_reg(map, rbnode_tmp, &base_reg_tmp,
110113
&top_reg_tmp);
111114
/* base register of the rbnode to be added */
112115
base_reg = rbnode->base_reg;
@@ -138,19 +141,20 @@ static int rbtree_show(struct seq_file *s, void *ignored)
138141
unsigned int base, top;
139142
int nodes = 0;
140143
int registers = 0;
141-
int average;
144+
int this_registers, average;
142145

143146
map->lock(map);
144147

145148
for (node = rb_first(&rbtree_ctx->root); node != NULL;
146149
node = rb_next(node)) {
147150
n = container_of(node, struct regcache_rbtree_node, node);
148151

149-
regcache_rbtree_get_base_top_reg(n, &base, &top);
150-
seq_printf(s, "%x-%x (%d)\n", base, top, top - base + 1);
152+
regcache_rbtree_get_base_top_reg(map, n, &base, &top);
153+
this_registers = ((top - base) / map->reg_stride) + 1;
154+
seq_printf(s, "%x-%x (%d)\n", base, top, this_registers);
151155

152156
nodes++;
153-
registers += top - base + 1;
157+
registers += this_registers;
154158
}
155159

156160
if (nodes)
@@ -255,7 +259,7 @@ static int regcache_rbtree_read(struct regmap *map,
255259

256260
rbnode = regcache_rbtree_lookup(map, reg);
257261
if (rbnode) {
258-
reg_tmp = reg - rbnode->base_reg;
262+
reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
259263
*value = regcache_rbtree_get_register(rbnode, reg_tmp,
260264
map->cache_word_size);
261265
} else {
@@ -310,7 +314,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
310314
*/
311315
rbnode = regcache_rbtree_lookup(map, reg);
312316
if (rbnode) {
313-
reg_tmp = reg - rbnode->base_reg;
317+
reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
314318
val = regcache_rbtree_get_register(rbnode, reg_tmp,
315319
map->cache_word_size);
316320
if (val == value)
@@ -321,13 +325,15 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
321325
/* look for an adjacent register to the one we are about to add */
322326
for (node = rb_first(&rbtree_ctx->root); node;
323327
node = rb_next(node)) {
324-
rbnode_tmp = rb_entry(node, struct regcache_rbtree_node, node);
328+
rbnode_tmp = rb_entry(node, struct regcache_rbtree_node,
329+
node);
325330
for (i = 0; i < rbnode_tmp->blklen; i++) {
326-
reg_tmp = rbnode_tmp->base_reg + i;
327-
if (abs(reg_tmp - reg) != 1)
331+
reg_tmp = rbnode_tmp->base_reg +
332+
(i * map->reg_stride);
333+
if (abs(reg_tmp - reg) != map->reg_stride)
328334
continue;
329335
/* decide where in the block to place our register */
330-
if (reg_tmp + 1 == reg)
336+
if (reg_tmp + map->reg_stride == reg)
331337
pos = i + 1;
332338
else
333339
pos = i;
@@ -357,7 +363,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
357363
return -ENOMEM;
358364
}
359365
regcache_rbtree_set_register(rbnode, 0, value, map->cache_word_size);
360-
regcache_rbtree_insert(&rbtree_ctx->root, rbnode);
366+
regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
361367
rbtree_ctx->cached_rbnode = rbnode;
362368
}
363369

@@ -397,7 +403,7 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
397403
end = rbnode->blklen;
398404

399405
for (i = base; i < end; i++) {
400-
regtmp = rbnode->base_reg + i;
406+
regtmp = rbnode->base_reg + (i * map->reg_stride);
401407
val = regcache_rbtree_get_register(rbnode, i,
402408
map->cache_word_size);
403409

drivers/base/regmap/regcache.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ static int regcache_hw_init(struct regmap *map)
5959
for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++) {
6060
val = regcache_get_val(map->reg_defaults_raw,
6161
i, map->cache_word_size);
62-
if (regmap_volatile(map, i))
62+
if (regmap_volatile(map, i * map->reg_stride))
6363
continue;
6464
count++;
6565
}
@@ -76,9 +76,9 @@ static int regcache_hw_init(struct regmap *map)
7676
for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) {
7777
val = regcache_get_val(map->reg_defaults_raw,
7878
i, map->cache_word_size);
79-
if (regmap_volatile(map, i))
79+
if (regmap_volatile(map, i * map->reg_stride))
8080
continue;
81-
map->reg_defaults[j].reg = i;
81+
map->reg_defaults[j].reg = i * map->reg_stride;
8282
map->reg_defaults[j].def = val;
8383
j++;
8484
}
@@ -98,6 +98,10 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
9898
int i;
9999
void *tmp_buf;
100100

101+
for (i = 0; i < config->num_reg_defaults; i++)
102+
if (config->reg_defaults[i].reg % map->reg_stride)
103+
return -EINVAL;
104+
101105
if (map->cache_type == REGCACHE_NONE) {
102106
map->cache_bypass = true;
103107
return 0;
@@ -278,6 +282,10 @@ int regcache_sync(struct regmap *map)
278282
/* Apply any patch first */
279283
map->cache_bypass = 1;
280284
for (i = 0; i < map->patch_regs; i++) {
285+
if (map->patch[i].reg % map->reg_stride) {
286+
ret = -EINVAL;
287+
goto out;
288+
}
281289
ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def);
282290
if (ret != 0) {
283291
dev_err(map->dev, "Failed to write %x = %x: %d\n",

drivers/base/regmap/regmap-debugfs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
8080
val_len = 2 * map->format.val_bytes;
8181
tot_len = reg_len + val_len + 3; /* : \n */
8282

83-
for (i = 0; i < map->max_register + 1; i++) {
83+
for (i = 0; i <= map->max_register; i += map->reg_stride) {
8484
if (!regmap_readable(map, i))
8585
continue;
8686

@@ -197,7 +197,7 @@ static ssize_t regmap_access_read_file(struct file *file,
197197
reg_len = regmap_calc_reg_len(map->max_register, buf, count);
198198
tot_len = reg_len + 10; /* ': R W V P\n' */
199199

200-
for (i = 0; i < map->max_register + 1; i++) {
200+
for (i = 0; i <= map->max_register; i += map->reg_stride) {
201201
/* Ignore registers which are neither readable nor writable */
202202
if (!regmap_readable(map, i) && !regmap_writeable(map, i))
203203
continue;

drivers/base/regmap/regmap-irq.c

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,12 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
5858
* suppress pointless writes.
5959
*/
6060
for (i = 0; i < d->chip->num_regs; i++) {
61-
ret = regmap_update_bits(d->map, d->chip->mask_base + i,
61+
ret = regmap_update_bits(d->map, d->chip->mask_base +
62+
(i * map->map->reg_stride),
6263
d->mask_buf_def[i], d->mask_buf[i]);
6364
if (ret != 0)
6465
dev_err(d->map->dev, "Failed to sync masks in %x\n",
65-
d->chip->mask_base + i);
66+
d->chip->mask_base + (i * map->reg_stride));
6667
}
6768

6869
mutex_unlock(&d->lock);
@@ -73,15 +74,15 @@ static void regmap_irq_enable(struct irq_data *data)
7374
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
7475
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq);
7576

76-
d->mask_buf[irq_data->reg_offset] &= ~irq_data->mask;
77+
d->mask_buf[irq_data->reg_offset / map->reg_stride] &= ~irq_data->mask;
7778
}
7879

7980
static void regmap_irq_disable(struct irq_data *data)
8081
{
8182
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
8283
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq);
8384

84-
d->mask_buf[irq_data->reg_offset] |= irq_data->mask;
85+
d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask;
8586
}
8687

8788
static struct irq_chip regmap_irq_chip = {
@@ -136,17 +137,19 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
136137
data->status_buf[i] &= ~data->mask_buf[i];
137138

138139
if (data->status_buf[i] && chip->ack_base) {
139-
ret = regmap_write(map, chip->ack_base + i,
140+
ret = regmap_write(map, chip->ack_base +
141+
(i * map->reg_stride),
140142
data->status_buf[i]);
141143
if (ret != 0)
142144
dev_err(map->dev, "Failed to ack 0x%x: %d\n",
143-
chip->ack_base + i, ret);
145+
chip->ack_base + (i * map->reg_stride),
146+
ret);
144147
}
145148
}
146149

147150
for (i = 0; i < chip->num_irqs; i++) {
148-
if (data->status_buf[chip->irqs[i].reg_offset] &
149-
chip->irqs[i].mask) {
151+
if (data->status_buf[chip->irqs[i].reg_offset /
152+
map->reg_stride] & chip->irqs[i].mask) {
150153
handle_nested_irq(data->irq_base + i);
151154
handled = true;
152155
}
@@ -181,6 +184,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
181184
int cur_irq, i;
182185
int ret = -ENOMEM;
183186

187+
for (i = 0; i < chip->num_irqs; i++) {
188+
if (chip->irqs[i].reg_offset % map->reg_stride)
189+
return -EINVAL;
190+
if (chip->irqs[i].reg_offset / map->reg_stride >=
191+
chip->num_regs)
192+
return -EINVAL;
193+
}
194+
184195
irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0);
185196
if (irq_base < 0) {
186197
dev_warn(map->dev, "Failed to allocate IRQs: %d\n",
@@ -218,16 +229,17 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
218229
mutex_init(&d->lock);
219230

220231
for (i = 0; i < chip->num_irqs; i++)
221-
d->mask_buf_def[chip->irqs[i].reg_offset]
232+
d->mask_buf_def[chip->irqs[i].reg_offset / map->reg_stride]
222233
|= chip->irqs[i].mask;
223234

224235
/* Mask all the interrupts by default */
225236
for (i = 0; i < chip->num_regs; i++) {
226237
d->mask_buf[i] = d->mask_buf_def[i];
227-
ret = regmap_write(map, chip->mask_base + i, d->mask_buf[i]);
238+
ret = regmap_write(map, chip->mask_base + (i * map->reg_stride),
239+
d->mask_buf[i]);
228240
if (ret != 0) {
229241
dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
230-
chip->mask_base + i, ret);
242+
chip->mask_base + (i * map->reg_stride), ret);
231243
goto err_alloc;
232244
}
233245
}

drivers/base/regmap/regmap-mmio.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
130130
const struct regmap_config *config)
131131
{
132132
struct regmap_mmio_context *ctx;
133+
int min_stride;
133134

134135
if (config->reg_bits != 32)
135136
return ERR_PTR(-EINVAL);
@@ -139,16 +140,28 @@ struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
139140

140141
switch (config->val_bits) {
141142
case 8:
143+
/* The core treats 0 as 1 */
144+
min_stride = 0;
145+
break;
142146
case 16:
147+
min_stride = 2;
148+
break;
143149
case 32:
150+
min_stride = 4;
151+
break;
144152
#ifdef CONFIG_64BIT
145153
case 64:
154+
min_stride = 8;
155+
break;
146156
#endif
147157
break;
148158
default:
149159
return ERR_PTR(-EINVAL);
150160
}
151161

162+
if (config->reg_stride < min_stride)
163+
return ERR_PTR(-EINVAL);
164+
152165
ctx = kzalloc(GFP_KERNEL, sizeof(*ctx));
153166
if (!ctx)
154167
return ERR_PTR(-ENOMEM);

0 commit comments

Comments
 (0)