regmap: Fix for v7.0
A fix from Andy Shevchenko for an issue with caching of page selector registers which are located inside the page they are switching. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmnGzFoACgkQJNaLcl1U h9CIHgf9EUlo+kHud/8a2NPDZAQK9OHpfEGd5vHGemd9H2NUbKuq3wwHYSaKdF4x W+71HKr5GBIOG5hdmpQ2eynKtNdsvmLaTvjOtO4W8eJzI7hFR0I+O4dWEnJe5My9 tHciXphh515LXud7h5qGX04QZSzD0NzntVxDJyGGmLtSwQwJjIIi6mqCzPY1BJ9h +adQNYqj9DXM9EVSsRsYhcxc64QzyXK4ThW6/BNOEVGTuBOKv6AjnoDvEG8xVg+L /8Af01CwLS8vqlVl8nd9TyJOuIGW2GoeYjxkbvsRwEapF/bcnPyPU3fnEb653dxm H9tAsSrrUJ2Y+rzZpZdXmPyuJvD4SQ== =/tG2 -----END PGP SIGNATURE----- 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:
commit
30052002e6
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue