persistent_ram.c revision 404a6043385de17273624b076599669db5ad891f
1/*
2 * Copyright (C) 2012 Google, Inc.
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 *
13 */
14
15#include <linux/device.h>
16#include <linux/err.h>
17#include <linux/errno.h>
18#include <linux/kernel.h>
19#include <linux/init.h>
20#include <linux/io.h>
21#include <linux/list.h>
22#include <linux/memblock.h>
23#include <linux/rslib.h>
24#include <linux/slab.h>
25#include <linux/vmalloc.h>
26#include "persistent_ram.h"
27
28struct persistent_ram_buffer {
29	uint32_t    sig;
30	uint32_t    start;
31	uint32_t    size;
32	uint8_t     data[0];
33};
34
35#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
36
37static __initdata LIST_HEAD(persistent_ram_list);
38
39static void persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
40	uint8_t *data, size_t len, uint8_t *ecc)
41{
42	int i;
43	uint16_t par[prz->ecc_size];
44
45	/* Initialize the parity buffer */
46	memset(par, 0, sizeof(par));
47	encode_rs8(prz->rs_decoder, data, len, par, 0);
48	for (i = 0; i < prz->ecc_size; i++)
49		ecc[i] = par[i];
50}
51
52static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz,
53	void *data, size_t len, uint8_t *ecc)
54{
55	int i;
56	uint16_t par[prz->ecc_size];
57
58	for (i = 0; i < prz->ecc_size; i++)
59		par[i] = ecc[i];
60	return decode_rs8(prz->rs_decoder, data, par, len,
61				NULL, 0, NULL, 0, NULL);
62}
63
64static void persistent_ram_update_ecc(struct persistent_ram_zone *prz,
65	unsigned int count)
66{
67	struct persistent_ram_buffer *buffer = prz->buffer;
68	uint8_t *buffer_end = buffer->data + prz->buffer_size;
69	uint8_t *block;
70	uint8_t *par;
71	int ecc_block_size = prz->ecc_block_size;
72	int ecc_size = prz->ecc_size;
73	int size = prz->ecc_block_size;
74
75	if (!prz->ecc)
76		return;
77
78	block = buffer->data + (buffer->start & ~(ecc_block_size - 1));
79	par = prz->par_buffer +
80	      (buffer->start / ecc_block_size) * prz->ecc_size;
81	do {
82		if (block + ecc_block_size > buffer_end)
83			size = buffer_end - block;
84		persistent_ram_encode_rs8(prz, block, size, par);
85		block += ecc_block_size;
86		par += ecc_size;
87	} while (block < buffer->data + buffer->start + count);
88}
89
90static void persistent_ram_update_header_ecc(struct persistent_ram_zone *prz)
91{
92	struct persistent_ram_buffer *buffer = prz->buffer;
93
94	if (!prz->ecc)
95		return;
96
97	persistent_ram_encode_rs8(prz, (uint8_t *)buffer, sizeof(*buffer),
98				  prz->par_header);
99}
100
101static void persistent_ram_ecc_old(struct persistent_ram_zone *prz)
102{
103	struct persistent_ram_buffer *buffer = prz->buffer;
104	uint8_t *block;
105	uint8_t *par;
106
107	if (!prz->ecc)
108		return;
109
110	block = buffer->data;
111	par = prz->par_buffer;
112	while (block < buffer->data + buffer->size) {
113		int numerr;
114		int size = prz->ecc_block_size;
115		if (block + size > buffer->data + prz->buffer_size)
116			size = buffer->data + prz->buffer_size - block;
117		numerr = persistent_ram_decode_rs8(prz, block, size, par);
118		if (numerr > 0) {
119			pr_devel("persistent_ram: error in block %p, %d\n",
120			       block, numerr);
121			prz->corrected_bytes += numerr;
122		} else if (numerr < 0) {
123			pr_devel("persistent_ram: uncorrectable error in block %p\n",
124				block);
125			prz->bad_blocks++;
126		}
127		block += prz->ecc_block_size;
128		par += prz->ecc_size;
129	}
130}
131
132static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
133	size_t buffer_size)
134{
135	int numerr;
136	struct persistent_ram_buffer *buffer = prz->buffer;
137	int ecc_blocks;
138
139	if (!prz->ecc)
140		return 0;
141
142	prz->ecc_block_size = 128;
143	prz->ecc_size = 16;
144	prz->ecc_symsize = 8;
145	prz->ecc_poly = 0x11d;
146
147	ecc_blocks = DIV_ROUND_UP(prz->buffer_size, prz->ecc_block_size);
148	prz->buffer_size -= (ecc_blocks + 1) * prz->ecc_size;
149
150	if (prz->buffer_size > buffer_size) {
151		pr_err("persistent_ram: invalid size %zu, non-ecc datasize %zu\n",
152		       buffer_size, prz->buffer_size);
153		return -EINVAL;
154	}
155
156	prz->par_buffer = buffer->data + prz->buffer_size;
157	prz->par_header = prz->par_buffer + ecc_blocks * prz->ecc_size;
158
159	/*
160	 * first consecutive root is 0
161	 * primitive element to generate roots = 1
162	 */
163	prz->rs_decoder = init_rs(prz->ecc_symsize, prz->ecc_poly, 0, 1,
164				  prz->ecc_size);
165	if (prz->rs_decoder == NULL) {
166		pr_info("persistent_ram: init_rs failed\n");
167		return -EINVAL;
168	}
169
170	prz->corrected_bytes = 0;
171	prz->bad_blocks = 0;
172
173	numerr = persistent_ram_decode_rs8(prz, buffer, sizeof(*buffer),
174					   prz->par_header);
175	if (numerr > 0) {
176		pr_info("persistent_ram: error in header, %d\n", numerr);
177		prz->corrected_bytes += numerr;
178	} else if (numerr < 0) {
179		pr_info("persistent_ram: uncorrectable error in header\n");
180		prz->bad_blocks++;
181	}
182
183	return 0;
184}
185
186ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
187	char *str, size_t len)
188{
189	ssize_t ret;
190
191	if (prz->corrected_bytes || prz->bad_blocks)
192		ret = snprintf(str, len, ""
193			"\n%d Corrected bytes, %d unrecoverable blocks\n",
194			prz->corrected_bytes, prz->bad_blocks);
195	else
196		ret = snprintf(str, len, "\nNo errors detected\n");
197
198	return ret;
199}
200
201static void persistent_ram_update(struct persistent_ram_zone *prz,
202	const void *s, unsigned int count)
203{
204	struct persistent_ram_buffer *buffer = prz->buffer;
205	memcpy(buffer->data + buffer->start, s, count);
206	persistent_ram_update_ecc(prz, count);
207}
208
209static void __init
210persistent_ram_save_old(struct persistent_ram_zone *prz)
211{
212	struct persistent_ram_buffer *buffer = prz->buffer;
213	size_t old_log_size = buffer->size;
214	char *dest;
215
216	persistent_ram_ecc_old(prz);
217
218	dest = kmalloc(old_log_size, GFP_KERNEL);
219	if (dest == NULL) {
220		pr_err("persistent_ram: failed to allocate buffer\n");
221		return;
222	}
223
224	prz->old_log = dest;
225	prz->old_log_size = old_log_size;
226	memcpy(prz->old_log,
227	       &buffer->data[buffer->start], buffer->size - buffer->start);
228	memcpy(prz->old_log + buffer->size - buffer->start,
229	       &buffer->data[0], buffer->start);
230}
231
232int persistent_ram_write(struct persistent_ram_zone *prz,
233	const void *s, unsigned int count)
234{
235	int rem;
236	int c = count;
237	struct persistent_ram_buffer *buffer = prz->buffer;
238
239	if (c > prz->buffer_size) {
240		s += c - prz->buffer_size;
241		c = prz->buffer_size;
242	}
243	rem = prz->buffer_size - buffer->start;
244	if (rem < c) {
245		persistent_ram_update(prz, s, rem);
246		s += rem;
247		c -= rem;
248		buffer->start = 0;
249		buffer->size = prz->buffer_size;
250	}
251	persistent_ram_update(prz, s, c);
252
253	buffer->start += c;
254	if (buffer->size < prz->buffer_size)
255		buffer->size += c;
256	persistent_ram_update_header_ecc(prz);
257
258	return count;
259}
260
261size_t persistent_ram_old_size(struct persistent_ram_zone *prz)
262{
263	return prz->old_log_size;
264}
265
266void *persistent_ram_old(struct persistent_ram_zone *prz)
267{
268	return prz->old_log;
269}
270
271void persistent_ram_free_old(struct persistent_ram_zone *prz)
272{
273	kfree(prz->old_log);
274	prz->old_log = NULL;
275	prz->old_log_size = 0;
276}
277
278static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
279		struct persistent_ram_zone *prz)
280{
281	struct page **pages;
282	phys_addr_t page_start;
283	unsigned int page_count;
284	pgprot_t prot;
285	unsigned int i;
286
287	page_start = start - offset_in_page(start);
288	page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
289
290	prot = pgprot_noncached(PAGE_KERNEL);
291
292	pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL);
293	if (!pages) {
294		pr_err("%s: Failed to allocate array for %u pages\n", __func__,
295			page_count);
296		return -ENOMEM;
297	}
298
299	for (i = 0; i < page_count; i++) {
300		phys_addr_t addr = page_start + i * PAGE_SIZE;
301		pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
302	}
303	prz->vaddr = vmap(pages, page_count, VM_MAP, prot);
304	kfree(pages);
305	if (!prz->vaddr) {
306		pr_err("%s: Failed to map %u pages\n", __func__, page_count);
307		return -ENOMEM;
308	}
309
310	prz->buffer = prz->vaddr + offset_in_page(start);
311	prz->buffer_size = size - sizeof(struct persistent_ram_buffer);
312
313	return 0;
314}
315
316static int __init persistent_ram_buffer_init(const char *name,
317		struct persistent_ram_zone *prz)
318{
319	int i;
320	struct persistent_ram *ram;
321	struct persistent_ram_descriptor *desc;
322	phys_addr_t start;
323
324	list_for_each_entry(ram, &persistent_ram_list, node) {
325		start = ram->start;
326		for (i = 0; i < ram->num_descs; i++) {
327			desc = &ram->descs[i];
328			if (!strcmp(desc->name, name))
329				return persistent_ram_buffer_map(start,
330						desc->size, prz);
331			start += desc->size;
332		}
333	}
334
335	return -EINVAL;
336}
337
338static  __init
339struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc)
340{
341	struct persistent_ram_zone *prz;
342	int ret;
343
344	prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
345	if (!prz) {
346		pr_err("persistent_ram: failed to allocate persistent ram zone\n");
347		return ERR_PTR(-ENOMEM);
348	}
349
350	INIT_LIST_HEAD(&prz->node);
351
352	ret = persistent_ram_buffer_init(dev_name(dev), prz);
353	if (ret) {
354		pr_err("persistent_ram: failed to initialize buffer\n");
355		return ERR_PTR(ret);
356	}
357
358	prz->ecc = ecc;
359	ret = persistent_ram_init_ecc(prz, prz->buffer_size);
360	if (ret)
361		return ERR_PTR(ret);
362
363	if (prz->buffer->sig == PERSISTENT_RAM_SIG) {
364		if (prz->buffer->size > prz->buffer_size
365		    || prz->buffer->start > prz->buffer->size)
366			pr_info("persistent_ram: found existing invalid buffer, size %d, start %d\n",
367			       prz->buffer->size, prz->buffer->start);
368		else {
369			pr_info("persistent_ram: found existing buffer, size %d, start %d\n",
370			       prz->buffer->size, prz->buffer->start);
371			persistent_ram_save_old(prz);
372		}
373	} else {
374		pr_info("persistent_ram: no valid data in buffer (sig = 0x%08x)\n",
375			prz->buffer->sig);
376	}
377
378	prz->buffer->sig = PERSISTENT_RAM_SIG;
379	prz->buffer->start = 0;
380	prz->buffer->size = 0;
381
382	return prz;
383}
384
385struct persistent_ram_zone * __init
386persistent_ram_init_ringbuffer(struct device *dev, bool ecc)
387{
388	return __persistent_ram_init(dev, ecc);
389}
390
391int __init persistent_ram_early_init(struct persistent_ram *ram)
392{
393	int ret;
394
395	ret = memblock_reserve(ram->start, ram->size);
396	if (ret) {
397		pr_err("Failed to reserve persistent memory from %08lx-%08lx\n",
398			(long)ram->start, (long)(ram->start + ram->size - 1));
399		return ret;
400	}
401
402	list_add_tail(&ram->node, &persistent_ram_list);
403
404	pr_info("Initialized persistent memory from %08lx-%08lx\n",
405		(long)ram->start, (long)(ram->start + ram->size - 1));
406
407	return 0;
408}
409