Skip to content

Commit 3005200

Browse files
committed
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
2 parents dd09eb4 + 09e70e4 commit 3005200

1 file changed

Lines changed: 26 additions & 4 deletions

File tree

drivers/base/regmap/regmap.c

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,6 +1545,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
15451545
unsigned int val_num)
15461546
{
15471547
void *orig_work_buf;
1548+
unsigned int selector_reg;
15481549
unsigned int win_offset;
15491550
unsigned int win_page;
15501551
bool page_chg;
@@ -1563,10 +1564,31 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
15631564
return -EINVAL;
15641565
}
15651566

1566-
/* It is possible to have selector register inside data window.
1567-
In that case, selector register is located on every page and
1568-
it needs no page switching, when accessed alone. */
1567+
/*
1568+
* Calculate the address of the selector register in the corresponding
1569+
* data window if it is located on every page.
1570+
*/
1571+
page_chg = in_range(range->selector_reg, range->window_start, range->window_len);
1572+
if (page_chg)
1573+
selector_reg = range->range_min + win_page * range->window_len +
1574+
range->selector_reg - range->window_start;
1575+
1576+
/*
1577+
* It is possible to have selector register inside data window.
1578+
* In that case, selector register is located on every page and it
1579+
* needs no page switching, when accessed alone.
1580+
*
1581+
* Nevertheless we should synchronize the cache values for it.
1582+
* This can't be properly achieved if the selector register is
1583+
* the first and the only one to be read inside the data window.
1584+
* That's why we update it in that case as well.
1585+
*
1586+
* However, we specifically avoid updating it for the default page,
1587+
* when it's overlapped with the real data window, to prevent from
1588+
* infinite looping.
1589+
*/
15691590
if (val_num > 1 ||
1591+
(page_chg && selector_reg != range->selector_reg) ||
15701592
range->window_start + win_offset != range->selector_reg) {
15711593
/* Use separate work_buf during page switching */
15721594
orig_work_buf = map->work_buf;
@@ -1575,7 +1597,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
15751597
ret = _regmap_update_bits(map, range->selector_reg,
15761598
range->selector_mask,
15771599
win_page << range->selector_shift,
1578-
&page_chg, false);
1600+
NULL, false);
15791601

15801602
map->work_buf = orig_work_buf;
15811603

0 commit comments

Comments
 (0)