Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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#define pr_fmt(fmt) "persistent_ram: " fmt
 16
 17#include <linux/device.h>
 18#include <linux/err.h>
 19#include <linux/errno.h>
 20#include <linux/init.h>
 21#include <linux/io.h>
 22#include <linux/kernel.h>
 23#include <linux/list.h>
 24#include <linux/memblock.h>
 25#include <linux/pstore_ram.h>
 26#include <linux/rslib.h>
 27#include <linux/slab.h>
 28#include <linux/uaccess.h>
 29#include <linux/vmalloc.h>
 30#include <asm/page.h>
 31
 32struct persistent_ram_buffer {
 33	uint32_t    sig;
 34	atomic_t    start;
 35	atomic_t    size;
 36	uint8_t     data[0];
 37};
 38
 39#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
 40
 41static inline size_t buffer_size(struct persistent_ram_zone *prz)
 42{
 43	return atomic_read(&prz->buffer->size);
 44}
 45
 46static inline size_t buffer_start(struct persistent_ram_zone *prz)
 47{
 48	return atomic_read(&prz->buffer->start);
 49}
 50
 51/* increase and wrap the start pointer, returning the old value */
 52static size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
 53{
 54	int old;
 55	int new;
 56	unsigned long flags = 0;
 57
 58	if (!(prz->flags & PRZ_FLAG_NO_LOCK))
 59		raw_spin_lock_irqsave(&prz->buffer_lock, flags);
 60
 61	old = atomic_read(&prz->buffer->start);
 62	new = old + a;
 63	while (unlikely(new >= prz->buffer_size))
 64		new -= prz->buffer_size;
 65	atomic_set(&prz->buffer->start, new);
 66
 67	if (!(prz->flags & PRZ_FLAG_NO_LOCK))
 68		raw_spin_unlock_irqrestore(&prz->buffer_lock, flags);
 69
 70	return old;
 71}
 72
 73/* increase the size counter until it hits the max size */
 74static void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
 75{
 76	size_t old;
 77	size_t new;
 78	unsigned long flags = 0;
 79
 80	if (!(prz->flags & PRZ_FLAG_NO_LOCK))
 81		raw_spin_lock_irqsave(&prz->buffer_lock, flags);
 82
 83	old = atomic_read(&prz->buffer->size);
 84	if (old == prz->buffer_size)
 85		goto exit;
 86
 87	new = old + a;
 88	if (new > prz->buffer_size)
 89		new = prz->buffer_size;
 90	atomic_set(&prz->buffer->size, new);
 91
 92exit:
 93	if (!(prz->flags & PRZ_FLAG_NO_LOCK))
 94		raw_spin_unlock_irqrestore(&prz->buffer_lock, flags);
 95}
 96
 97static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
 98	uint8_t *data, size_t len, uint8_t *ecc)
 99{
100	int i;
101	uint16_t par[prz->ecc_info.ecc_size];
102
103	/* Initialize the parity buffer */
104	memset(par, 0, sizeof(par));
105	encode_rs8(prz->rs_decoder, data, len, par, 0);
106	for (i = 0; i < prz->ecc_info.ecc_size; i++)
107		ecc[i] = par[i];
108}
109
110static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz,
111	void *data, size_t len, uint8_t *ecc)
112{
113	int i;
114	uint16_t par[prz->ecc_info.ecc_size];
115
116	for (i = 0; i < prz->ecc_info.ecc_size; i++)
117		par[i] = ecc[i];
118	return decode_rs8(prz->rs_decoder, data, par, len,
119				NULL, 0, NULL, 0, NULL);
120}
121
122static void notrace persistent_ram_update_ecc(struct persistent_ram_zone *prz,
123	unsigned int start, unsigned int count)
124{
125	struct persistent_ram_buffer *buffer = prz->buffer;
126	uint8_t *buffer_end = buffer->data + prz->buffer_size;
127	uint8_t *block;
128	uint8_t *par;
129	int ecc_block_size = prz->ecc_info.block_size;
130	int ecc_size = prz->ecc_info.ecc_size;
131	int size = ecc_block_size;
132
133	if (!ecc_size)
134		return;
135
136	block = buffer->data + (start & ~(ecc_block_size - 1));
137	par = prz->par_buffer + (start / ecc_block_size) * ecc_size;
138
139	do {
140		if (block + ecc_block_size > buffer_end)
141			size = buffer_end - block;
142		persistent_ram_encode_rs8(prz, block, size, par);
143		block += ecc_block_size;
144		par += ecc_size;
145	} while (block < buffer->data + start + count);
146}
147
148static void persistent_ram_update_header_ecc(struct persistent_ram_zone *prz)
149{
150	struct persistent_ram_buffer *buffer = prz->buffer;
151
152	if (!prz->ecc_info.ecc_size)
153		return;
154
155	persistent_ram_encode_rs8(prz, (uint8_t *)buffer, sizeof(*buffer),
156				  prz->par_header);
157}
158
159static void persistent_ram_ecc_old(struct persistent_ram_zone *prz)
160{
161	struct persistent_ram_buffer *buffer = prz->buffer;
162	uint8_t *block;
163	uint8_t *par;
164
165	if (!prz->ecc_info.ecc_size)
166		return;
167
168	block = buffer->data;
169	par = prz->par_buffer;
170	while (block < buffer->data + buffer_size(prz)) {
171		int numerr;
172		int size = prz->ecc_info.block_size;
173		if (block + size > buffer->data + prz->buffer_size)
174			size = buffer->data + prz->buffer_size - block;
175		numerr = persistent_ram_decode_rs8(prz, block, size, par);
176		if (numerr > 0) {
177			pr_devel("error in block %p, %d\n", block, numerr);
178			prz->corrected_bytes += numerr;
179		} else if (numerr < 0) {
180			pr_devel("uncorrectable error in block %p\n", block);
181			prz->bad_blocks++;
182		}
183		block += prz->ecc_info.block_size;
184		par += prz->ecc_info.ecc_size;
185	}
186}
187
188static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
189				   struct persistent_ram_ecc_info *ecc_info)
190{
191	int numerr;
192	struct persistent_ram_buffer *buffer = prz->buffer;
193	int ecc_blocks;
194	size_t ecc_total;
195
196	if (!ecc_info || !ecc_info->ecc_size)
197		return 0;
198
199	prz->ecc_info.block_size = ecc_info->block_size ?: 128;
200	prz->ecc_info.ecc_size = ecc_info->ecc_size ?: 16;
201	prz->ecc_info.symsize = ecc_info->symsize ?: 8;
202	prz->ecc_info.poly = ecc_info->poly ?: 0x11d;
203
204	ecc_blocks = DIV_ROUND_UP(prz->buffer_size - prz->ecc_info.ecc_size,
205				  prz->ecc_info.block_size +
206				  prz->ecc_info.ecc_size);
207	ecc_total = (ecc_blocks + 1) * prz->ecc_info.ecc_size;
208	if (ecc_total >= prz->buffer_size) {
209		pr_err("%s: invalid ecc_size %u (total %zu, buffer size %zu)\n",
210		       __func__, prz->ecc_info.ecc_size,
211		       ecc_total, prz->buffer_size);
212		return -EINVAL;
213	}
214
215	prz->buffer_size -= ecc_total;
216	prz->par_buffer = buffer->data + prz->buffer_size;
217	prz->par_header = prz->par_buffer +
218			  ecc_blocks * prz->ecc_info.ecc_size;
219
220	/*
221	 * first consecutive root is 0
222	 * primitive element to generate roots = 1
223	 */
224	prz->rs_decoder = init_rs(prz->ecc_info.symsize, prz->ecc_info.poly,
225				  0, 1, prz->ecc_info.ecc_size);
226	if (prz->rs_decoder == NULL) {
227		pr_info("init_rs failed\n");
228		return -EINVAL;
229	}
230
231	prz->corrected_bytes = 0;
232	prz->bad_blocks = 0;
233
234	numerr = persistent_ram_decode_rs8(prz, buffer, sizeof(*buffer),
235					   prz->par_header);
236	if (numerr > 0) {
237		pr_info("error in header, %d\n", numerr);
238		prz->corrected_bytes += numerr;
239	} else if (numerr < 0) {
240		pr_info("uncorrectable error in header\n");
241		prz->bad_blocks++;
242	}
243
244	return 0;
245}
246
247ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
248	char *str, size_t len)
249{
250	ssize_t ret;
251
252	if (!prz->ecc_info.ecc_size)
253		return 0;
254
255	if (prz->corrected_bytes || prz->bad_blocks)
256		ret = snprintf(str, len, ""
257			"\n%d Corrected bytes, %d unrecoverable blocks\n",
258			prz->corrected_bytes, prz->bad_blocks);
259	else
260		ret = snprintf(str, len, "\nNo errors detected\n");
261
262	return ret;
263}
264
265static void notrace persistent_ram_update(struct persistent_ram_zone *prz,
266	const void *s, unsigned int start, unsigned int count)
267{
268	struct persistent_ram_buffer *buffer = prz->buffer;
269	memcpy_toio(buffer->data + start, s, count);
270	persistent_ram_update_ecc(prz, start, count);
271}
272
273static int notrace persistent_ram_update_user(struct persistent_ram_zone *prz,
274	const void __user *s, unsigned int start, unsigned int count)
275{
276	struct persistent_ram_buffer *buffer = prz->buffer;
277	int ret = unlikely(__copy_from_user(buffer->data + start, s, count)) ?
278		-EFAULT : 0;
279	persistent_ram_update_ecc(prz, start, count);
280	return ret;
281}
282
283void persistent_ram_save_old(struct persistent_ram_zone *prz)
284{
285	struct persistent_ram_buffer *buffer = prz->buffer;
286	size_t size = buffer_size(prz);
287	size_t start = buffer_start(prz);
288
289	if (!size)
290		return;
291
292	if (!prz->old_log) {
293		persistent_ram_ecc_old(prz);
294		prz->old_log = kmalloc(size, GFP_KERNEL);
295	}
296	if (!prz->old_log) {
297		pr_err("failed to allocate buffer\n");
298		return;
299	}
300
301	prz->old_log_size = size;
302	memcpy_fromio(prz->old_log, &buffer->data[start], size - start);
303	memcpy_fromio(prz->old_log + size - start, &buffer->data[0], start);
304}
305
306int notrace persistent_ram_write(struct persistent_ram_zone *prz,
307	const void *s, unsigned int count)
308{
309	int rem;
310	int c = count;
311	size_t start;
312
313	if (unlikely(c > prz->buffer_size)) {
314		s += c - prz->buffer_size;
315		c = prz->buffer_size;
316	}
317
318	buffer_size_add(prz, c);
319
320	start = buffer_start_add(prz, c);
321
322	rem = prz->buffer_size - start;
323	if (unlikely(rem < c)) {
324		persistent_ram_update(prz, s, start, rem);
325		s += rem;
326		c -= rem;
327		start = 0;
328	}
329	persistent_ram_update(prz, s, start, c);
330
331	persistent_ram_update_header_ecc(prz);
332
333	return count;
334}
335
336int notrace persistent_ram_write_user(struct persistent_ram_zone *prz,
337	const void __user *s, unsigned int count)
338{
339	int rem, ret = 0, c = count;
340	size_t start;
341
342	if (unlikely(!access_ok(VERIFY_READ, s, count)))
343		return -EFAULT;
344	if (unlikely(c > prz->buffer_size)) {
345		s += c - prz->buffer_size;
346		c = prz->buffer_size;
347	}
348
349	buffer_size_add(prz, c);
350
351	start = buffer_start_add(prz, c);
352
353	rem = prz->buffer_size - start;
354	if (unlikely(rem < c)) {
355		ret = persistent_ram_update_user(prz, s, start, rem);
356		s += rem;
357		c -= rem;
358		start = 0;
359	}
360	if (likely(!ret))
361		ret = persistent_ram_update_user(prz, s, start, c);
362
363	persistent_ram_update_header_ecc(prz);
364
365	return unlikely(ret) ? ret : count;
366}
367
368size_t persistent_ram_old_size(struct persistent_ram_zone *prz)
369{
370	return prz->old_log_size;
371}
372
373void *persistent_ram_old(struct persistent_ram_zone *prz)
374{
375	return prz->old_log;
376}
377
378void persistent_ram_free_old(struct persistent_ram_zone *prz)
379{
380	kfree(prz->old_log);
381	prz->old_log = NULL;
382	prz->old_log_size = 0;
383}
384
385void persistent_ram_zap(struct persistent_ram_zone *prz)
386{
387	atomic_set(&prz->buffer->start, 0);
388	atomic_set(&prz->buffer->size, 0);
389	persistent_ram_update_header_ecc(prz);
390}
391
392static void *persistent_ram_vmap(phys_addr_t start, size_t size,
393		unsigned int memtype)
394{
395	struct page **pages;
396	phys_addr_t page_start;
397	unsigned int page_count;
398	pgprot_t prot;
399	unsigned int i;
400	void *vaddr;
401
402	page_start = start - offset_in_page(start);
403	page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
404
405	if (memtype)
406		prot = pgprot_noncached(PAGE_KERNEL);
407	else
408		prot = pgprot_writecombine(PAGE_KERNEL);
409
410	pages = kmalloc_array(page_count, sizeof(struct page *), GFP_KERNEL);
411	if (!pages) {
412		pr_err("%s: Failed to allocate array for %u pages\n",
413		       __func__, page_count);
414		return NULL;
415	}
416
417	for (i = 0; i < page_count; i++) {
418		phys_addr_t addr = page_start + i * PAGE_SIZE;
419		pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
420	}
421	vaddr = vmap(pages, page_count, VM_MAP, prot);
422	kfree(pages);
423
424	return vaddr;
425}
426
427static void *persistent_ram_iomap(phys_addr_t start, size_t size,
428		unsigned int memtype)
429{
430	void *va;
431
432	if (!request_mem_region(start, size, "persistent_ram")) {
433		pr_err("request mem region (0x%llx@0x%llx) failed\n",
434			(unsigned long long)size, (unsigned long long)start);
435		return NULL;
436	}
437
438	if (memtype)
439		va = ioremap(start, size);
440	else
441		va = ioremap_wc(start, size);
442
443	return va;
444}
445
446static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
447		struct persistent_ram_zone *prz, int memtype)
448{
449	prz->paddr = start;
450	prz->size = size;
451
452	if (pfn_valid(start >> PAGE_SHIFT))
453		prz->vaddr = persistent_ram_vmap(start, size, memtype);
454	else
455		prz->vaddr = persistent_ram_iomap(start, size, memtype);
456
457	if (!prz->vaddr) {
458		pr_err("%s: Failed to map 0x%llx pages at 0x%llx\n", __func__,
459			(unsigned long long)size, (unsigned long long)start);
460		return -ENOMEM;
461	}
462
463	prz->buffer = prz->vaddr + offset_in_page(start);
464	prz->buffer_size = size - sizeof(struct persistent_ram_buffer);
465
466	return 0;
467}
468
469static int persistent_ram_post_init(struct persistent_ram_zone *prz, u32 sig,
470				    struct persistent_ram_ecc_info *ecc_info,
471				    unsigned long flags)
472{
473	int ret;
474
475	ret = persistent_ram_init_ecc(prz, ecc_info);
476	if (ret)
477		return ret;
478
479	sig ^= PERSISTENT_RAM_SIG;
480
481	if (prz->buffer->sig == sig) {
482		if (buffer_size(prz) > prz->buffer_size ||
483		    buffer_start(prz) > buffer_size(prz))
484			pr_info("found existing invalid buffer, size %zu, start %zu\n",
485				buffer_size(prz), buffer_start(prz));
486		else {
487			pr_debug("found existing buffer, size %zu, start %zu\n",
488				 buffer_size(prz), buffer_start(prz));
489			persistent_ram_save_old(prz);
490			return 0;
491		}
492	} else {
493		pr_debug("no valid data in buffer (sig = 0x%08x)\n",
494			 prz->buffer->sig);
495	}
496
497	prz->buffer->sig = sig;
498	persistent_ram_zap(prz);
499	prz->buffer_lock = __RAW_SPIN_LOCK_UNLOCKED(buffer_lock);
500	prz->flags = flags;
501
502	return 0;
503}
504
505void persistent_ram_free(struct persistent_ram_zone *prz)
506{
507	if (!prz)
508		return;
509
510	if (prz->vaddr) {
511		if (pfn_valid(prz->paddr >> PAGE_SHIFT)) {
512			vunmap(prz->vaddr);
513		} else {
514			iounmap(prz->vaddr);
515			release_mem_region(prz->paddr, prz->size);
516		}
517		prz->vaddr = NULL;
518	}
519	persistent_ram_free_old(prz);
520	kfree(prz);
521}
522
523struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
524			u32 sig, struct persistent_ram_ecc_info *ecc_info,
525			unsigned int memtype, u32 flags)
526{
527	struct persistent_ram_zone *prz;
528	int ret = -ENOMEM;
529
530	prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
531	if (!prz) {
532		pr_err("failed to allocate persistent ram zone\n");
533		goto err;
534	}
535
536	ret = persistent_ram_buffer_map(start, size, prz, memtype);
537	if (ret)
538		goto err;
539
540	ret = persistent_ram_post_init(prz, sig, ecc_info, flags);
541	if (ret)
542		goto err;
543
544	return prz;
545err:
546	persistent_ram_free(prz);
547	return ERR_PTR(ret);
548}