regmap: cache: Remove unused 'blksize' variable
[pandora-kernel.git] / drivers / base / regmap / regcache-lzo.c
1 /*
2  * Register cache access API - LZO caching support
3  *
4  * Copyright 2011 Wolfson Microelectronics plc
5  *
6  * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/slab.h>
14 #include <linux/lzo.h>
15
16 #include "internal.h"
17
18 struct regcache_lzo_ctx {
19         void *wmem;
20         void *dst;
21         const void *src;
22         size_t src_len;
23         size_t dst_len;
24         size_t decompressed_size;
25         unsigned long *sync_bmp;
26         int sync_bmp_nbits;
27 };
28
29 #define LZO_BLOCK_NUM 8
30 static int regcache_lzo_block_count(void)
31 {
32         return LZO_BLOCK_NUM;
33 }
34
35 static int regcache_lzo_prepare(struct regcache_lzo_ctx *lzo_ctx)
36 {
37         lzo_ctx->wmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
38         if (!lzo_ctx->wmem)
39                 return -ENOMEM;
40         return 0;
41 }
42
43 static int regcache_lzo_compress(struct regcache_lzo_ctx *lzo_ctx)
44 {
45         size_t compress_size;
46         int ret;
47
48         ret = lzo1x_1_compress(lzo_ctx->src, lzo_ctx->src_len,
49                                lzo_ctx->dst, &compress_size, lzo_ctx->wmem);
50         if (ret != LZO_E_OK || compress_size > lzo_ctx->dst_len)
51                 return -EINVAL;
52         lzo_ctx->dst_len = compress_size;
53         return 0;
54 }
55
56 static int regcache_lzo_decompress(struct regcache_lzo_ctx *lzo_ctx)
57 {
58         size_t dst_len;
59         int ret;
60
61         dst_len = lzo_ctx->dst_len;
62         ret = lzo1x_decompress_safe(lzo_ctx->src, lzo_ctx->src_len,
63                                     lzo_ctx->dst, &dst_len);
64         if (ret != LZO_E_OK || dst_len != lzo_ctx->dst_len)
65                 return -EINVAL;
66         return 0;
67 }
68
69 static int regcache_lzo_compress_cache_block(struct regmap *map,
70                 struct regcache_lzo_ctx *lzo_ctx)
71 {
72         int ret;
73
74         lzo_ctx->dst_len = lzo1x_worst_compress(PAGE_SIZE);
75         lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
76         if (!lzo_ctx->dst) {
77                 lzo_ctx->dst_len = 0;
78                 return -ENOMEM;
79         }
80
81         ret = regcache_lzo_compress(lzo_ctx);
82         if (ret < 0)
83                 return ret;
84         return 0;
85 }
86
87 static int regcache_lzo_decompress_cache_block(struct regmap *map,
88                 struct regcache_lzo_ctx *lzo_ctx)
89 {
90         int ret;
91
92         lzo_ctx->dst_len = lzo_ctx->decompressed_size;
93         lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
94         if (!lzo_ctx->dst) {
95                 lzo_ctx->dst_len = 0;
96                 return -ENOMEM;
97         }
98
99         ret = regcache_lzo_decompress(lzo_ctx);
100         if (ret < 0)
101                 return ret;
102         return 0;
103 }
104
105 static inline int regcache_lzo_get_blkindex(struct regmap *map,
106                                             unsigned int reg)
107 {
108         return (reg * map->cache_word_size) /
109                 DIV_ROUND_UP(map->cache_size_raw, regcache_lzo_block_count());
110 }
111
112 static inline int regcache_lzo_get_blkpos(struct regmap *map,
113                                           unsigned int reg)
114 {
115         return reg % (DIV_ROUND_UP(map->cache_size_raw, regcache_lzo_block_count()) /
116                       map->cache_word_size);
117 }
118
119 static inline int regcache_lzo_get_blksize(struct regmap *map)
120 {
121         return DIV_ROUND_UP(map->cache_size_raw, regcache_lzo_block_count());
122 }
123
124 static int regcache_lzo_init(struct regmap *map)
125 {
126         struct regcache_lzo_ctx **lzo_blocks;
127         size_t bmp_size;
128         int ret, i, blksize, blkcount;
129         const char *p, *end;
130         unsigned long *sync_bmp;
131
132         ret = 0;
133
134         blkcount = regcache_lzo_block_count();
135         map->cache = kzalloc(blkcount * sizeof *lzo_blocks,
136                              GFP_KERNEL);
137         if (!map->cache)
138                 return -ENOMEM;
139         lzo_blocks = map->cache;
140
141         /*
142          * allocate a bitmap to be used when syncing the cache with
143          * the hardware.  Each time a register is modified, the corresponding
144          * bit is set in the bitmap, so we know that we have to sync
145          * that register.
146          */
147         bmp_size = map->num_reg_defaults_raw;
148         sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long),
149                            GFP_KERNEL);
150         if (!sync_bmp) {
151                 ret = -ENOMEM;
152                 goto err;
153         }
154         bitmap_zero(sync_bmp, bmp_size);
155
156         /* allocate the lzo blocks and initialize them */
157         for (i = 0; i < blkcount; i++) {
158                 lzo_blocks[i] = kzalloc(sizeof **lzo_blocks,
159                                         GFP_KERNEL);
160                 if (!lzo_blocks[i]) {
161                         kfree(sync_bmp);
162                         ret = -ENOMEM;
163                         goto err;
164                 }
165                 lzo_blocks[i]->sync_bmp = sync_bmp;
166                 lzo_blocks[i]->sync_bmp_nbits = bmp_size;
167                 /* alloc the working space for the compressed block */
168                 ret = regcache_lzo_prepare(lzo_blocks[i]);
169                 if (ret < 0)
170                         goto err;
171         }
172
173         blksize = regcache_lzo_get_blksize(map);
174         p = map->reg_defaults_raw;
175         end = map->reg_defaults_raw + map->cache_size_raw;
176         /* compress the register map and fill the lzo blocks */
177         for (i = 0; i < blkcount; i++, p += blksize) {
178                 lzo_blocks[i]->src = p;
179                 if (p + blksize > end)
180                         lzo_blocks[i]->src_len = end - p;
181                 else
182                         lzo_blocks[i]->src_len = blksize;
183                 ret = regcache_lzo_compress_cache_block(map,
184                                                        lzo_blocks[i]);
185                 if (ret < 0)
186                         goto err;
187                 lzo_blocks[i]->decompressed_size =
188                         lzo_blocks[i]->src_len;
189         }
190
191         return 0;
192 err:
193         regcache_exit(map);
194         return ret;
195 }
196
197 static int regcache_lzo_exit(struct regmap *map)
198 {
199         struct regcache_lzo_ctx **lzo_blocks;
200         int i, blkcount;
201
202         lzo_blocks = map->cache;
203         if (!lzo_blocks)
204                 return 0;
205
206         blkcount = regcache_lzo_block_count();
207         /*
208          * the pointer to the bitmap used for syncing the cache
209          * is shared amongst all lzo_blocks.  Ensure it is freed
210          * only once.
211          */
212         if (lzo_blocks[0])
213                 kfree(lzo_blocks[0]->sync_bmp);
214         for (i = 0; i < blkcount; i++) {
215                 if (lzo_blocks[i]) {
216                         kfree(lzo_blocks[i]->wmem);
217                         kfree(lzo_blocks[i]->dst);
218                 }
219                 /* each lzo_block is a pointer returned by kmalloc or NULL */
220                 kfree(lzo_blocks[i]);
221         }
222         kfree(lzo_blocks);
223         map->cache = NULL;
224         return 0;
225 }
226
227 static int regcache_lzo_read(struct regmap *map,
228                              unsigned int reg, unsigned int *value)
229 {
230         struct regcache_lzo_ctx *lzo_block, **lzo_blocks;
231         int ret, blkindex, blkpos;
232         size_t tmp_dst_len;
233         void *tmp_dst;
234
235         /* index of the compressed lzo block */
236         blkindex = regcache_lzo_get_blkindex(map, reg);
237         /* register index within the decompressed block */
238         blkpos = regcache_lzo_get_blkpos(map, reg);
239         lzo_blocks = map->cache;
240         lzo_block = lzo_blocks[blkindex];
241
242         /* save the pointer and length of the compressed block */
243         tmp_dst = lzo_block->dst;
244         tmp_dst_len = lzo_block->dst_len;
245
246         /* prepare the source to be the compressed block */
247         lzo_block->src = lzo_block->dst;
248         lzo_block->src_len = lzo_block->dst_len;
249
250         /* decompress the block */
251         ret = regcache_lzo_decompress_cache_block(map, lzo_block);
252         if (ret >= 0)
253                 /* fetch the value from the cache */
254                 *value = regcache_get_val(lzo_block->dst, blkpos,
255                                           map->cache_word_size);
256
257         kfree(lzo_block->dst);
258         /* restore the pointer and length of the compressed block */
259         lzo_block->dst = tmp_dst;
260         lzo_block->dst_len = tmp_dst_len;
261
262         return ret;
263 }
264
265 static int regcache_lzo_write(struct regmap *map,
266                               unsigned int reg, unsigned int value)
267 {
268         struct regcache_lzo_ctx *lzo_block, **lzo_blocks;
269         int ret, blkindex, blkpos;
270         size_t tmp_dst_len;
271         void *tmp_dst;
272
273         /* index of the compressed lzo block */
274         blkindex = regcache_lzo_get_blkindex(map, reg);
275         /* register index within the decompressed block */
276         blkpos = regcache_lzo_get_blkpos(map, reg);
277         lzo_blocks = map->cache;
278         lzo_block = lzo_blocks[blkindex];
279
280         /* save the pointer and length of the compressed block */
281         tmp_dst = lzo_block->dst;
282         tmp_dst_len = lzo_block->dst_len;
283
284         /* prepare the source to be the compressed block */
285         lzo_block->src = lzo_block->dst;
286         lzo_block->src_len = lzo_block->dst_len;
287
288         /* decompress the block */
289         ret = regcache_lzo_decompress_cache_block(map, lzo_block);
290         if (ret < 0) {
291                 kfree(lzo_block->dst);
292                 goto out;
293         }
294
295         /* write the new value to the cache */
296         if (regcache_set_val(lzo_block->dst, blkpos, value,
297                              map->cache_word_size)) {
298                 kfree(lzo_block->dst);
299                 goto out;
300         }
301
302         /* prepare the source to be the decompressed block */
303         lzo_block->src = lzo_block->dst;
304         lzo_block->src_len = lzo_block->dst_len;
305
306         /* compress the block */
307         ret = regcache_lzo_compress_cache_block(map, lzo_block);
308         if (ret < 0) {
309                 kfree(lzo_block->dst);
310                 kfree(lzo_block->src);
311                 goto out;
312         }
313
314         /* set the bit so we know we have to sync this register */
315         set_bit(reg, lzo_block->sync_bmp);
316         kfree(tmp_dst);
317         kfree(lzo_block->src);
318         return 0;
319 out:
320         lzo_block->dst = tmp_dst;
321         lzo_block->dst_len = tmp_dst_len;
322         return ret;
323 }
324
325 static int regcache_lzo_sync(struct regmap *map)
326 {
327         struct regcache_lzo_ctx **lzo_blocks;
328         unsigned int val;
329         int i;
330         int ret;
331
332         lzo_blocks = map->cache;
333         for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
334                 ret = regcache_read(map, i, &val);
335                 if (ret)
336                         return ret;
337                 map->cache_bypass = 1;
338                 ret = _regmap_write(map, i, val);
339                 map->cache_bypass = 0;
340                 if (ret)
341                         return ret;
342                 dev_dbg(map->dev, "Synced register %#x, value %#x\n",
343                         i, val);
344         }
345
346         return 0;
347 }
348
349 struct regcache_ops regcache_lzo_ops = {
350         .type = REGCACHE_LZO,
351         .name = "lzo",
352         .init = regcache_lzo_init,
353         .exit = regcache_lzo_exit,
354         .read = regcache_lzo_read,
355         .write = regcache_lzo_write,
356         .sync = regcache_lzo_sync
357 };