mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-30 13:04:37 -04:00
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:
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user