Merge tag 'regmap-fix-v7.0-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap

Pull regmap fix from Mark Brown:
 "A fix from Andy Shevchenko for an issue with caching of page selector
  registers which are located inside the page they are switching"

* tag 'regmap-fix-v7.0-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: Synchronize cache for the page selector
This commit is contained in:
Linus Torvalds
2026-03-27 16:34:25 -07:00

View File

@@ -1545,6 +1545,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
unsigned int val_num)
{
void *orig_work_buf;
unsigned int selector_reg;
unsigned int win_offset;
unsigned int win_page;
bool page_chg;
@@ -1563,10 +1564,31 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
return -EINVAL;
}
/* It is possible to have selector register inside data window.
In that case, selector register is located on every page and
it needs no page switching, when accessed alone. */
/*
* Calculate the address of the selector register in the corresponding
* data window if it is located on every page.
*/
page_chg = in_range(range->selector_reg, range->window_start, range->window_len);
if (page_chg)
selector_reg = range->range_min + win_page * range->window_len +
range->selector_reg - range->window_start;
/*
* It is possible to have selector register inside data window.
* In that case, selector register is located on every page and it
* needs no page switching, when accessed alone.
*
* Nevertheless we should synchronize the cache values for it.
* This can't be properly achieved if the selector register is
* the first and the only one to be read inside the data window.
* That's why we update it in that case as well.
*
* However, we specifically avoid updating it for the default page,
* when it's overlapped with the real data window, to prevent from
* infinite looping.
*/
if (val_num > 1 ||
(page_chg && selector_reg != range->selector_reg) ||
range->window_start + win_offset != range->selector_reg) {
/* Use separate work_buf during page switching */
orig_work_buf = map->work_buf;
@@ -1575,7 +1597,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
ret = _regmap_update_bits(map, range->selector_reg,
range->selector_mask,
win_page << range->selector_shift,
&page_chg, false);
NULL, false);
map->work_buf = orig_work_buf;