X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?p=kvmfornfv.git;a=blobdiff_plain;f=kernel%2Fdrivers%2Fbase%2Fregmap%2Fregcache.c;h=4c07802986b2c92862e1f0242eebddcb42e2b45d;hp=7eb7b3b98794849c6718c068504c7ac1acf3a2c9;hb=e09b41010ba33a20a87472ee821fa407a5b8da36;hpb=f93b97fd65072de626c074dbe099a1fff05ce060 diff --git a/kernel/drivers/base/regmap/regcache.c b/kernel/drivers/base/regmap/regcache.c index 7eb7b3b98..4c0780298 100644 --- a/kernel/drivers/base/regmap/regcache.c +++ b/kernel/drivers/base/regmap/regcache.c @@ -54,11 +54,11 @@ static int regcache_hw_init(struct regmap *map) return -ENOMEM; if (!map->reg_defaults_raw) { - u32 cache_bypass = map->cache_bypass; + bool cache_bypass = map->cache_bypass; dev_warn(map->dev, "No cache defaults, reading back from HW\n"); /* Bypass the cache access till data read from HW*/ - map->cache_bypass = 1; + map->cache_bypass = true; tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL); if (!tmp_buf) { ret = -ENOMEM; @@ -249,6 +249,22 @@ int regcache_write(struct regmap *map, return 0; } +static bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg, + unsigned int val) +{ + int ret; + + /* If we don't know the chip just got reset, then sync everything. */ + if (!map->no_sync_defaults) + return true; + + /* Is this the hardware default? If so skip. */ + ret = regcache_lookup_reg(map, reg); + if (ret >= 0 && val == map->reg_defaults[ret].def) + return false; + return true; +} + static int regcache_default_sync(struct regmap *map, unsigned int min, unsigned int max) { @@ -266,14 +282,12 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, if (ret) return ret; - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, reg); - if (ret >= 0 && val == map->reg_defaults[ret].def) + if (!regcache_reg_needs_sync(map, reg, val)) continue; - map->cache_bypass = 1; + map->cache_bypass = true; ret = _regmap_write(map, reg, val); - map->cache_bypass = 0; + map->cache_bypass = false; if (ret) { dev_err(map->dev, "Unable to sync register %#x. %d\n", reg, ret); @@ -301,7 +315,7 @@ int regcache_sync(struct regmap *map) int ret = 0; unsigned int i; const char *name; - unsigned int bypass; + bool bypass; BUG_ON(!map->cache_ops); @@ -319,7 +333,7 @@ int regcache_sync(struct regmap *map) map->async = true; /* Apply any patch first */ - map->cache_bypass = 1; + map->cache_bypass = true; for (i = 0; i < map->patch_regs; i++) { ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def); if (ret != 0) { @@ -328,7 +342,7 @@ int regcache_sync(struct regmap *map) goto out; } } - map->cache_bypass = 0; + map->cache_bypass = false; if (map->cache_ops->sync) ret = map->cache_ops->sync(map, 0, map->max_register); @@ -342,6 +356,7 @@ out: /* Restore the bypass state */ map->async = false; map->cache_bypass = bypass; + map->no_sync_defaults = false; map->unlock(map->lock_arg); regmap_async_complete(map); @@ -369,7 +384,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min, { int ret = 0; const char *name; - unsigned int bypass; + bool bypass; BUG_ON(!map->cache_ops); @@ -397,6 +412,7 @@ out: /* Restore the bypass state */ map->cache_bypass = bypass; map->async = false; + map->no_sync_defaults = false; map->unlock(map->lock_arg); regmap_async_complete(map); @@ -461,18 +477,23 @@ void regcache_cache_only(struct regmap *map, bool enable) EXPORT_SYMBOL_GPL(regcache_cache_only); /** - * regcache_mark_dirty: Mark the register cache as dirty + * regcache_mark_dirty: Indicate that HW registers were reset to default values * * @map: map to mark * - * Mark the register cache as dirty, for example due to the device - * having been powered down for suspend. If the cache is not marked - * as dirty then the cache sync will be suppressed. + * Inform regcache that the device has been powered down or reset, so that + * on resume, regcache_sync() knows to write out all non-default values + * stored in the cache. + * + * If this function is not called, regcache_sync() will assume that + * the hardware state still matches the cache state, modulo any writes that + * happened when cache_only was true. */ void regcache_mark_dirty(struct regmap *map) { map->lock(map->lock_arg); map->cache_dirty = true; + map->no_sync_defaults = true; map->unlock(map->lock_arg); } EXPORT_SYMBOL_GPL(regcache_mark_dirty); @@ -613,17 +634,14 @@ static int regcache_sync_block_single(struct regmap *map, void *block, continue; val = regcache_get_val(map, block, i); - - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, regtmp); - if (ret >= 0 && val == map->reg_defaults[ret].def) + if (!regcache_reg_needs_sync(map, regtmp, val)) continue; - map->cache_bypass = 1; + map->cache_bypass = true; ret = _regmap_write(map, regtmp, val); - map->cache_bypass = 0; + map->cache_bypass = false; if (ret != 0) { dev_err(map->dev, "Unable to sync register %#x. %d\n", regtmp, ret); @@ -650,14 +668,14 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data, dev_dbg(map->dev, "Writing %zu bytes for %d registers from 0x%x-0x%x\n", count * val_bytes, count, base, cur - map->reg_stride); - map->cache_bypass = 1; + map->cache_bypass = true; ret = _regmap_raw_write(map, base, *data, count * val_bytes); if (ret) dev_err(map->dev, "Unable to sync registers %#x-%#x. %d\n", base, cur - map->reg_stride, ret); - map->cache_bypass = 0; + map->cache_bypass = false; *data = NULL; @@ -688,10 +706,7 @@ static int regcache_sync_block_raw(struct regmap *map, void *block, } val = regcache_get_val(map, block, i); - - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, regtmp); - if (ret >= 0 && val == map->reg_defaults[ret].def) { + if (!regcache_reg_needs_sync(map, regtmp, val)) { ret = regcache_sync_block_raw_flush(map, &data, base, regtmp); if (ret != 0) @@ -714,7 +729,7 @@ int regcache_sync_block(struct regmap *map, void *block, unsigned int block_base, unsigned int start, unsigned int end) { - if (regmap_can_raw_write(map) && !map->use_single_rw) + if (regmap_can_raw_write(map) && !map->use_single_write) return regcache_sync_block_raw(map, block, cache_present, block_base, start, end); else