Skip to content

Commit bfa0b38

Browse files
committed
regmap: maple: Implement block sync for the maple tree cache
For register maps where we can write multiple values in a single bus operation it is generally much faster to do so. Improve the performance of maple tree cache syncs on such devices by identifying blocks of adjacent registers that need to be written out and combining them into a single operation. Combining writes does mean that we need to allocate a scratch buffer and format the data into it but it is expected that for most cases where caches are in use the cost of I/O will be much greater than the cost of doing the allocation and format. Signed-off-by: Mark Brown <broonie@kernel.org> Link: https://lore.kernel.org/r/20230609-regcache-maple-sync-raw-v1-1-8ddeb4e2b9ab@kernel.org Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent b7c2686 commit bfa0b38

3 files changed

Lines changed: 80 additions & 8 deletions

File tree

drivers/base/regmap/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,8 @@ int regcache_sync_block(struct regmap *map, void *block,
257257
unsigned long *cache_present,
258258
unsigned int block_base, unsigned int start,
259259
unsigned int end);
260+
bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg,
261+
unsigned int val);
260262

261263
static inline const void *regcache_get_val_addr(struct regmap *map,
262264
const void *base,

drivers/base/regmap/regcache-maple.c

Lines changed: 76 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,55 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min,
186186
return ret;
187187
}
188188

189+
static int regcache_maple_sync_block(struct regmap *map, unsigned long *entry,
190+
struct ma_state *mas,
191+
unsigned int min, unsigned int max)
192+
{
193+
void *buf;
194+
unsigned long r;
195+
size_t val_bytes = map->format.val_bytes;
196+
int ret = 0;
197+
198+
mas_pause(mas);
199+
rcu_read_unlock();
200+
201+
/*
202+
* Use a raw write if writing more than one register to a
203+
* device that supports raw writes to reduce transaction
204+
* overheads.
205+
*/
206+
if (max - min > 1 && regmap_can_raw_write(map)) {
207+
buf = kmalloc(val_bytes * (max - min), map->alloc_flags);
208+
if (!buf) {
209+
ret = -ENOMEM;
210+
goto out;
211+
}
212+
213+
/* Render the data for a raw write */
214+
for (r = min; r < max; r++) {
215+
regcache_set_val(map, buf, r - min,
216+
entry[r - mas->index]);
217+
}
218+
219+
ret = _regmap_raw_write(map, min, buf, (max - min) * val_bytes,
220+
false);
221+
222+
kfree(buf);
223+
} else {
224+
for (r = min; r < max; r++) {
225+
ret = _regmap_write(map, r,
226+
entry[r - mas->index]);
227+
if (ret != 0)
228+
goto out;
229+
}
230+
}
231+
232+
out:
233+
rcu_read_lock();
234+
235+
return ret;
236+
}
237+
189238
static int regcache_maple_sync(struct regmap *map, unsigned int min,
190239
unsigned int max)
191240
{
@@ -194,27 +243,48 @@ static int regcache_maple_sync(struct regmap *map, unsigned int min,
194243
MA_STATE(mas, mt, min, max);
195244
unsigned long lmin = min;
196245
unsigned long lmax = max;
197-
unsigned int r;
246+
unsigned int r, v, sync_start;
198247
int ret;
248+
bool sync_needed = false;
199249

200250
map->cache_bypass = true;
201251

202252
rcu_read_lock();
203253

204254
mas_for_each(&mas, entry, max) {
205255
for (r = max(mas.index, lmin); r <= min(mas.last, lmax); r++) {
206-
mas_pause(&mas);
207-
rcu_read_unlock();
208-
ret = regcache_sync_val(map, r, entry[r - mas.index]);
256+
v = entry[r - mas.index];
257+
258+
if (regcache_reg_needs_sync(map, r, v)) {
259+
if (!sync_needed) {
260+
sync_start = r;
261+
sync_needed = true;
262+
}
263+
continue;
264+
}
265+
266+
if (!sync_needed)
267+
continue;
268+
269+
ret = regcache_maple_sync_block(map, entry, &mas,
270+
sync_start, r);
209271
if (ret != 0)
210272
goto out;
211-
rcu_read_lock();
273+
sync_needed = false;
274+
}
275+
276+
if (sync_needed) {
277+
ret = regcache_maple_sync_block(map, entry, &mas,
278+
sync_start, r);
279+
if (ret != 0)
280+
goto out;
281+
sync_needed = false;
212282
}
213283
}
214284

285+
out:
215286
rcu_read_unlock();
216287

217-
out:
218288
map->cache_bypass = false;
219289

220290
return ret;

drivers/base/regmap/regcache.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,8 @@ int regcache_write(struct regmap *map,
279279
return 0;
280280
}
281281

282-
static bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg,
283-
unsigned int val)
282+
bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg,
283+
unsigned int val)
284284
{
285285
int ret;
286286

0 commit comments

Comments
 (0)