12cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos/* 22cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos * Register cache access API - LZO caching support 32cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos * 42cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos * Copyright 2011 Wolfson Microelectronics plc 52cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos * 62cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com> 72cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos * 82cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos * This program is free software; you can redistribute it and/or modify 92cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos * it under the terms of the GNU General Public License version 2 as 102cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos * published by the Free Software Foundation. 112cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos */ 122cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 132cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos#include <linux/slab.h> 142cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos#include <linux/lzo.h> 152cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 162cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos#include "internal.h" 172cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 18c2b1ecd13c6a7b19f1c0c48b68f61ab083f3ec3fLars-Peter Clausenstatic int regcache_lzo_exit(struct regmap *map); 19c2b1ecd13c6a7b19f1c0c48b68f61ab083f3ec3fLars-Peter Clausen 202cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamosstruct regcache_lzo_ctx { 212cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos void *wmem; 222cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos void *dst; 232cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos const void *src; 242cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos size_t src_len; 252cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos size_t dst_len; 262cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos size_t decompressed_size; 272cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos unsigned long *sync_bmp; 282cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos int sync_bmp_nbits; 292cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos}; 302cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 312cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos#define LZO_BLOCK_NUM 8 3282732bdd663ee9dc1ad4b0409881fe89a9d827caMark Brownstatic int regcache_lzo_block_count(struct regmap *map) 332cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos{ 342cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return LZO_BLOCK_NUM; 352cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos} 362cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 372cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamosstatic int regcache_lzo_prepare(struct regcache_lzo_ctx *lzo_ctx) 382cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos{ 392cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_ctx->wmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL); 402cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (!lzo_ctx->wmem) 412cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return -ENOMEM; 422cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return 0; 432cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos} 442cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 452cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamosstatic int regcache_lzo_compress(struct regcache_lzo_ctx *lzo_ctx) 462cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos{ 472cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos size_t compress_size; 482cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos int ret; 492cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 502cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos ret = lzo1x_1_compress(lzo_ctx->src, lzo_ctx->src_len, 512cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_ctx->dst, &compress_size, lzo_ctx->wmem); 522cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (ret != LZO_E_OK || compress_size > lzo_ctx->dst_len) 532cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return -EINVAL; 542cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_ctx->dst_len = compress_size; 552cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return 0; 562cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos} 572cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 582cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamosstatic int regcache_lzo_decompress(struct regcache_lzo_ctx *lzo_ctx) 592cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos{ 602cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos size_t dst_len; 612cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos int ret; 622cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 632cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos dst_len = lzo_ctx->dst_len; 642cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos ret = lzo1x_decompress_safe(lzo_ctx->src, lzo_ctx->src_len, 652cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_ctx->dst, &dst_len); 662cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (ret != LZO_E_OK || dst_len != lzo_ctx->dst_len) 672cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return -EINVAL; 682cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return 0; 692cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos} 702cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 712cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamosstatic int regcache_lzo_compress_cache_block(struct regmap *map, 722cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos struct regcache_lzo_ctx *lzo_ctx) 732cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos{ 742cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos int ret; 752cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 762cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_ctx->dst_len = lzo1x_worst_compress(PAGE_SIZE); 772cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL); 782cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (!lzo_ctx->dst) { 792cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_ctx->dst_len = 0; 802cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return -ENOMEM; 812cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos } 822cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 832cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos ret = regcache_lzo_compress(lzo_ctx); 842cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (ret < 0) 852cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return ret; 862cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return 0; 872cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos} 882cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 892cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamosstatic int regcache_lzo_decompress_cache_block(struct regmap *map, 902cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos struct regcache_lzo_ctx *lzo_ctx) 912cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos{ 922cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos int ret; 932cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 942cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_ctx->dst_len = lzo_ctx->decompressed_size; 952cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL); 962cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (!lzo_ctx->dst) { 972cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_ctx->dst_len = 0; 982cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return -ENOMEM; 992cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos } 1002cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 1012cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos ret = regcache_lzo_decompress(lzo_ctx); 1022cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (ret < 0) 1032cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return ret; 1042cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return 0; 1052cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos} 1062cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 1072cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamosstatic inline int regcache_lzo_get_blkindex(struct regmap *map, 1082cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos unsigned int reg) 1092cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos{ 1102cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return (reg * map->cache_word_size) / 11182732bdd663ee9dc1ad4b0409881fe89a9d827caMark Brown DIV_ROUND_UP(map->cache_size_raw, 11282732bdd663ee9dc1ad4b0409881fe89a9d827caMark Brown regcache_lzo_block_count(map)); 1132cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos} 1142cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 1152cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamosstatic inline int regcache_lzo_get_blkpos(struct regmap *map, 1162cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos unsigned int reg) 1172cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos{ 11882732bdd663ee9dc1ad4b0409881fe89a9d827caMark Brown return reg % (DIV_ROUND_UP(map->cache_size_raw, 11982732bdd663ee9dc1ad4b0409881fe89a9d827caMark Brown regcache_lzo_block_count(map)) / 1202cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos map->cache_word_size); 1212cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos} 1222cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 1232cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamosstatic inline int regcache_lzo_get_blksize(struct regmap *map) 1242cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos{ 12582732bdd663ee9dc1ad4b0409881fe89a9d827caMark Brown return DIV_ROUND_UP(map->cache_size_raw, 12682732bdd663ee9dc1ad4b0409881fe89a9d827caMark Brown regcache_lzo_block_count(map)); 1272cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos} 1282cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 1292cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamosstatic int regcache_lzo_init(struct regmap *map) 1302cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos{ 1312cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos struct regcache_lzo_ctx **lzo_blocks; 1322cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos size_t bmp_size; 1332cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos int ret, i, blksize, blkcount; 1342cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos const char *p, *end; 1352cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos unsigned long *sync_bmp; 1362cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 1372cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos ret = 0; 1382cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 13982732bdd663ee9dc1ad4b0409881fe89a9d827caMark Brown blkcount = regcache_lzo_block_count(map); 1402cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos map->cache = kzalloc(blkcount * sizeof *lzo_blocks, 1412cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos GFP_KERNEL); 1422cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (!map->cache) 1432cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return -ENOMEM; 1442cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_blocks = map->cache; 1452cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 1462cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* 1472cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos * allocate a bitmap to be used when syncing the cache with 1482cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos * the hardware. Each time a register is modified, the corresponding 1492cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos * bit is set in the bitmap, so we know that we have to sync 1502cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos * that register. 1512cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos */ 1522cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos bmp_size = map->num_reg_defaults_raw; 1532cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long), 1542cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos GFP_KERNEL); 1552cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (!sync_bmp) { 1562cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos ret = -ENOMEM; 1572cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos goto err; 1582cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos } 1592cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos bitmap_zero(sync_bmp, bmp_size); 1602cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 1612cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* allocate the lzo blocks and initialize them */ 1622cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos for (i = 0; i < blkcount; i++) { 1632cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_blocks[i] = kzalloc(sizeof **lzo_blocks, 1642cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos GFP_KERNEL); 1652cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (!lzo_blocks[i]) { 1662cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos kfree(sync_bmp); 1672cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos ret = -ENOMEM; 1682cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos goto err; 1692cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos } 1702cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_blocks[i]->sync_bmp = sync_bmp; 1712cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_blocks[i]->sync_bmp_nbits = bmp_size; 1722cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* alloc the working space for the compressed block */ 1732cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos ret = regcache_lzo_prepare(lzo_blocks[i]); 1742cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (ret < 0) 1752cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos goto err; 1762cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos } 1772cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 1782cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos blksize = regcache_lzo_get_blksize(map); 1792cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos p = map->reg_defaults_raw; 1802cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos end = map->reg_defaults_raw + map->cache_size_raw; 1812cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* compress the register map and fill the lzo blocks */ 1822cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos for (i = 0; i < blkcount; i++, p += blksize) { 1832cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_blocks[i]->src = p; 1842cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (p + blksize > end) 1852cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_blocks[i]->src_len = end - p; 1862cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos else 1872cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_blocks[i]->src_len = blksize; 1882cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos ret = regcache_lzo_compress_cache_block(map, 1892cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_blocks[i]); 1902cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (ret < 0) 1912cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos goto err; 1922cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_blocks[i]->decompressed_size = 1932cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_blocks[i]->src_len; 1942cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos } 1952cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 1962cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return 0; 1972cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamoserr: 198c2b1ecd13c6a7b19f1c0c48b68f61ab083f3ec3fLars-Peter Clausen regcache_lzo_exit(map); 1992cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return ret; 2002cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos} 2012cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 2022cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamosstatic int regcache_lzo_exit(struct regmap *map) 2032cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos{ 2042cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos struct regcache_lzo_ctx **lzo_blocks; 2052cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos int i, blkcount; 2062cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 2072cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_blocks = map->cache; 2082cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (!lzo_blocks) 2092cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return 0; 2102cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 21182732bdd663ee9dc1ad4b0409881fe89a9d827caMark Brown blkcount = regcache_lzo_block_count(map); 2122cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* 2132cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos * the pointer to the bitmap used for syncing the cache 2142cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos * is shared amongst all lzo_blocks. Ensure it is freed 2152cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos * only once. 2162cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos */ 2172cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (lzo_blocks[0]) 2182cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos kfree(lzo_blocks[0]->sync_bmp); 2192cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos for (i = 0; i < blkcount; i++) { 2202cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (lzo_blocks[i]) { 2212cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos kfree(lzo_blocks[i]->wmem); 2222cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos kfree(lzo_blocks[i]->dst); 2232cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos } 2242cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* each lzo_block is a pointer returned by kmalloc or NULL */ 2252cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos kfree(lzo_blocks[i]); 2262cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos } 2272cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos kfree(lzo_blocks); 2282cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos map->cache = NULL; 2292cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return 0; 2302cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos} 2312cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 2322cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamosstatic int regcache_lzo_read(struct regmap *map, 2332cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos unsigned int reg, unsigned int *value) 2342cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos{ 2352cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos struct regcache_lzo_ctx *lzo_block, **lzo_blocks; 2362cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos int ret, blkindex, blkpos; 2372cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos size_t blksize, tmp_dst_len; 2382cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos void *tmp_dst; 2392cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 2402cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* index of the compressed lzo block */ 2412cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos blkindex = regcache_lzo_get_blkindex(map, reg); 2422cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* register index within the decompressed block */ 2432cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos blkpos = regcache_lzo_get_blkpos(map, reg); 2442cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* size of the compressed block */ 2452cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos blksize = regcache_lzo_get_blksize(map); 2462cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_blocks = map->cache; 2472cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_block = lzo_blocks[blkindex]; 2482cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 2492cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* save the pointer and length of the compressed block */ 2502cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos tmp_dst = lzo_block->dst; 2512cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos tmp_dst_len = lzo_block->dst_len; 2522cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 2532cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* prepare the source to be the compressed block */ 2542cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_block->src = lzo_block->dst; 2552cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_block->src_len = lzo_block->dst_len; 2562cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 2572cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* decompress the block */ 2582cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos ret = regcache_lzo_decompress_cache_block(map, lzo_block); 2592cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (ret >= 0) 2602cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* fetch the value from the cache */ 2612cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos *value = regcache_get_val(lzo_block->dst, blkpos, 2622cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos map->cache_word_size); 2632cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 2642cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos kfree(lzo_block->dst); 2652cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* restore the pointer and length of the compressed block */ 2662cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_block->dst = tmp_dst; 2672cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_block->dst_len = tmp_dst_len; 2686e6ace00a045251bd172b9b9c2379857bbff3dc7Mark Brown 2696e6ace00a045251bd172b9b9c2379857bbff3dc7Mark Brown return ret; 2702cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos} 2712cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 2722cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamosstatic int regcache_lzo_write(struct regmap *map, 2732cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos unsigned int reg, unsigned int value) 2742cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos{ 2752cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos struct regcache_lzo_ctx *lzo_block, **lzo_blocks; 2762cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos int ret, blkindex, blkpos; 2772cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos size_t blksize, tmp_dst_len; 2782cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos void *tmp_dst; 2792cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 2802cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* index of the compressed lzo block */ 2812cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos blkindex = regcache_lzo_get_blkindex(map, reg); 2822cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* register index within the decompressed block */ 2832cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos blkpos = regcache_lzo_get_blkpos(map, reg); 2842cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* size of the compressed block */ 2852cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos blksize = regcache_lzo_get_blksize(map); 2862cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_blocks = map->cache; 2872cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_block = lzo_blocks[blkindex]; 2882cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 2892cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* save the pointer and length of the compressed block */ 2902cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos tmp_dst = lzo_block->dst; 2912cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos tmp_dst_len = lzo_block->dst_len; 2922cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 2932cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* prepare the source to be the compressed block */ 2942cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_block->src = lzo_block->dst; 2952cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_block->src_len = lzo_block->dst_len; 2962cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 2972cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* decompress the block */ 2982cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos ret = regcache_lzo_decompress_cache_block(map, lzo_block); 2992cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (ret < 0) { 3002cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos kfree(lzo_block->dst); 3012cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos goto out; 3022cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos } 3032cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 3042cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* write the new value to the cache */ 3052cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (regcache_set_val(lzo_block->dst, blkpos, value, 3062cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos map->cache_word_size)) { 3072cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos kfree(lzo_block->dst); 3082cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos goto out; 3092cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos } 3102cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 3112cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* prepare the source to be the decompressed block */ 3122cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_block->src = lzo_block->dst; 3132cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_block->src_len = lzo_block->dst_len; 3142cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 3152cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* compress the block */ 3162cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos ret = regcache_lzo_compress_cache_block(map, lzo_block); 3172cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (ret < 0) { 3182cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos kfree(lzo_block->dst); 3192cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos kfree(lzo_block->src); 3202cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos goto out; 3212cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos } 3222cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 3232cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos /* set the bit so we know we have to sync this register */ 3242cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos set_bit(reg, lzo_block->sync_bmp); 3252cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos kfree(tmp_dst); 3262cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos kfree(lzo_block->src); 3272cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return 0; 3282cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamosout: 3292cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_block->dst = tmp_dst; 3302cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_block->dst_len = tmp_dst_len; 3312cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return ret; 3322cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos} 3332cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 3342cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamosstatic int regcache_lzo_sync(struct regmap *map) 3352cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos{ 3362cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos struct regcache_lzo_ctx **lzo_blocks; 3372cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos unsigned int val; 3382cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos int i; 3392cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos int ret; 3402cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 3412cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos lzo_blocks = map->cache; 3422cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) { 3432cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos ret = regcache_read(map, i, &val); 3442cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (ret) 3452cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return ret; 3462cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos map->cache_bypass = 1; 34713753a9088af23c61e2f5c10a8f3ea136d8ebab5Dimitris Papastamos ret = _regmap_write(map, i, val); 3482cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos map->cache_bypass = 0; 3492cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos if (ret) 3502cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return ret; 3512cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos dev_dbg(map->dev, "Synced register %#x, value %#x\n", 3522cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos i, val); 3532cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos } 3542cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 3552cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos return 0; 3562cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos} 3572cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos 3582cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamosstruct regcache_ops regcache_lzo_ops = { 35950b776fc71c13663eb7434f634f2b796de5c9885Mark Brown .type = REGCACHE_COMPRESSED, 3602cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos .name = "lzo", 3612cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos .init = regcache_lzo_init, 3622cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos .exit = regcache_lzo_exit, 3632cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos .read = regcache_lzo_read, 3642cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos .write = regcache_lzo_write, 3652cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos .sync = regcache_lzo_sync 3662cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos}; 367