persistent_ram.c revision 6411d5781dee41da3e2e29b024140e8f4a0f0ac7
1c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross/*
2c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross * Copyright (C) 2012 Google, Inc.
3c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross *
4c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross * This software is licensed under the terms of the GNU General Public
5c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross * License version 2, as published by the Free Software Foundation, and
6c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross * may be copied, distributed, and modified under those terms.
7c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross *
8c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross * This program is distributed in the hope that it will be useful,
9c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross * but WITHOUT ANY WARRANTY; without even the implied warranty of
10c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross * GNU General Public License for more details.
12c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross *
13c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross */
14c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
15404a6043385de17273624b076599669db5ad891fColin Cross#include <linux/device.h>
16404a6043385de17273624b076599669db5ad891fColin Cross#include <linux/err.h>
17c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross#include <linux/errno.h>
18c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross#include <linux/kernel.h>
19c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross#include <linux/init.h>
20c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross#include <linux/io.h>
21404a6043385de17273624b076599669db5ad891fColin Cross#include <linux/list.h>
22404a6043385de17273624b076599669db5ad891fColin Cross#include <linux/memblock.h>
23a3a0f312f78c4321a33314edb18b565f97ba489fColin Cross#include <linux/persistent_ram.h>
249cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross#include <linux/rslib.h>
25c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross#include <linux/slab.h>
26404a6043385de17273624b076599669db5ad891fColin Cross#include <linux/vmalloc.h>
27c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
28c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Crossstruct persistent_ram_buffer {
29c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	uint32_t    sig;
30808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	atomic_t    start;
31808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	atomic_t    size;
32c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	uint8_t     data[0];
33c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross};
34c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
35c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
36c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
374a2212f2e6a4938180bfced93efb3adea4c6418dColin Crossstatic __devinitdata LIST_HEAD(persistent_ram_list);
38c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
39808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Crossstatic inline size_t buffer_size(struct persistent_ram_zone *prz)
40808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross{
41808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	return atomic_read(&prz->buffer->size);
42808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross}
43808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross
44808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Crossstatic inline size_t buffer_start(struct persistent_ram_zone *prz)
45808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross{
46808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	return atomic_read(&prz->buffer->start);
47808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross}
48808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross
49808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross/* increase and wrap the start pointer, returning the old value */
50808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Crossstatic inline size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
51808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross{
52808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	int old;
53808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	int new;
54808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross
55808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	do {
56808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		old = atomic_read(&prz->buffer->start);
57808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		new = old + a;
58808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		while (unlikely(new > prz->buffer_size))
59808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross			new -= prz->buffer_size;
60808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	} while (atomic_cmpxchg(&prz->buffer->start, old, new) != old);
61808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross
62808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	return old;
63808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross}
64808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross
65808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross/* increase the size counter until it hits the max size */
66808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Crossstatic inline void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
67808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross{
68808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	size_t old;
69808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	size_t new;
70808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross
71808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	if (atomic_read(&prz->buffer->size) == prz->buffer_size)
72808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		return;
73808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross
74808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	do {
75808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		old = atomic_read(&prz->buffer->size);
76808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		new = old + a;
77808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		if (new > prz->buffer_size)
78808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross			new = prz->buffer_size;
79808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	} while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
80808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross}
81808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross
82808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross/* increase the size counter, retuning an error if it hits the max size */
83808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Crossstatic inline ssize_t buffer_size_add_clamp(struct persistent_ram_zone *prz,
84808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	size_t a)
85808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross{
86808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	size_t old;
87808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	size_t new;
88808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross
89808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	do {
90808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		old = atomic_read(&prz->buffer->size);
91808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		new = old + a;
92808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		if (new > prz->buffer_size)
93808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross			return -ENOMEM;
94808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	} while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
95808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross
96808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	return 0;
97808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross}
98808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross
99a15d0b365e9bbf04dacb44fbe69d15f6594460e1Colin Crossstatic void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
100c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	uint8_t *data, size_t len, uint8_t *ecc)
101c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross{
102c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	int i;
1039cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	uint16_t par[prz->ecc_size];
1049cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
105c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	/* Initialize the parity buffer */
106c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	memset(par, 0, sizeof(par));
107c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	encode_rs8(prz->rs_decoder, data, len, par, 0);
1089cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	for (i = 0; i < prz->ecc_size; i++)
109c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		ecc[i] = par[i];
110c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross}
111c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
112c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Crossstatic int persistent_ram_decode_rs8(struct persistent_ram_zone *prz,
113c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	void *data, size_t len, uint8_t *ecc)
114c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross{
115c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	int i;
1169cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	uint16_t par[prz->ecc_size];
1179cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
1189cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	for (i = 0; i < prz->ecc_size; i++)
119c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		par[i] = ecc[i];
120c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	return decode_rs8(prz->rs_decoder, data, par, len,
121c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross				NULL, 0, NULL, 0, NULL);
122c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross}
123c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
124a15d0b365e9bbf04dacb44fbe69d15f6594460e1Colin Crossstatic void notrace persistent_ram_update_ecc(struct persistent_ram_zone *prz,
125808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	unsigned int start, unsigned int count)
126c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross{
127c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	struct persistent_ram_buffer *buffer = prz->buffer;
128c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	uint8_t *buffer_end = buffer->data + prz->buffer_size;
129c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	uint8_t *block;
130c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	uint8_t *par;
1319cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	int ecc_block_size = prz->ecc_block_size;
1329cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	int ecc_size = prz->ecc_size;
1339cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	int size = prz->ecc_block_size;
1349cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
1359cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	if (!prz->ecc)
1369cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		return;
1379cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
138808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	block = buffer->data + (start & ~(ecc_block_size - 1));
139808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	par = prz->par_buffer + (start / ecc_block_size) * prz->ecc_size;
140808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross
141c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	do {
1429cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		if (block + ecc_block_size > buffer_end)
143c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross			size = buffer_end - block;
144c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		persistent_ram_encode_rs8(prz, block, size, par);
1459cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		block += ecc_block_size;
1469cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		par += ecc_size;
147808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	} while (block < buffer->data + start + count);
148c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross}
149c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
1509cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Crossstatic void persistent_ram_update_header_ecc(struct persistent_ram_zone *prz)
151c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross{
152c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	struct persistent_ram_buffer *buffer = prz->buffer;
153c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
1549cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	if (!prz->ecc)
1559cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		return;
1569cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
157c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	persistent_ram_encode_rs8(prz, (uint8_t *)buffer, sizeof(*buffer),
158c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross				  prz->par_header);
159c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross}
160c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
1619cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Crossstatic void persistent_ram_ecc_old(struct persistent_ram_zone *prz)
162c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross{
163c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	struct persistent_ram_buffer *buffer = prz->buffer;
164c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	uint8_t *block;
165c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	uint8_t *par;
166c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
1679cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	if (!prz->ecc)
1689cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		return;
1699cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
170c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	block = buffer->data;
171c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	par = prz->par_buffer;
172808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	while (block < buffer->data + buffer_size(prz)) {
173c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		int numerr;
1749cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		int size = prz->ecc_block_size;
175c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		if (block + size > buffer->data + prz->buffer_size)
176c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross			size = buffer->data + prz->buffer_size - block;
177c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		numerr = persistent_ram_decode_rs8(prz, block, size, par);
178c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		if (numerr > 0) {
1799cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross			pr_devel("persistent_ram: error in block %p, %d\n",
180c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross			       block, numerr);
181c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross			prz->corrected_bytes += numerr;
182c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		} else if (numerr < 0) {
1839cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross			pr_devel("persistent_ram: uncorrectable error in block %p\n",
184c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross				block);
185c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross			prz->bad_blocks++;
186c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		}
1879cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		block += prz->ecc_block_size;
1889cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		par += prz->ecc_size;
1899cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	}
1909cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross}
1919cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
1929cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Crossstatic int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
1936411d5781dee41da3e2e29b024140e8f4a0f0ac7Arve Hjønnevåg	size_t buffer_size, struct persistent_ram *ram)
1949cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross{
1959cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	int numerr;
1969cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	struct persistent_ram_buffer *buffer = prz->buffer;
1979cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	int ecc_blocks;
1989cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
1999cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	if (!prz->ecc)
2009cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		return 0;
2019cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2026411d5781dee41da3e2e29b024140e8f4a0f0ac7Arve Hjønnevåg	prz->ecc_block_size = ram->ecc_block_size ?: 128;
2036411d5781dee41da3e2e29b024140e8f4a0f0ac7Arve Hjønnevåg	prz->ecc_size = ram->ecc_size ?: 16;
2046411d5781dee41da3e2e29b024140e8f4a0f0ac7Arve Hjønnevåg	prz->ecc_symsize = ram->ecc_symsize ?: 8;
2056411d5781dee41da3e2e29b024140e8f4a0f0ac7Arve Hjønnevåg	prz->ecc_poly = ram->ecc_poly ?: 0x11d;
2069cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2076ce7d7aa4b53b6171c835a6964a24201ac89ee64Arve Hjønnevåg	ecc_blocks = DIV_ROUND_UP(prz->buffer_size - prz->ecc_size,
2086ce7d7aa4b53b6171c835a6964a24201ac89ee64Arve Hjønnevåg				  prz->ecc_block_size + prz->ecc_size);
2099cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	prz->buffer_size -= (ecc_blocks + 1) * prz->ecc_size;
2109cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2119cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	if (prz->buffer_size > buffer_size) {
2129cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		pr_err("persistent_ram: invalid size %zu, non-ecc datasize %zu\n",
2139cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		       buffer_size, prz->buffer_size);
2149cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		return -EINVAL;
2159cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	}
2169cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2179cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	prz->par_buffer = buffer->data + prz->buffer_size;
2189cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	prz->par_header = prz->par_buffer + ecc_blocks * prz->ecc_size;
2199cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2209cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	/*
2219cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	 * first consecutive root is 0
2229cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	 * primitive element to generate roots = 1
2239cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	 */
2249cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	prz->rs_decoder = init_rs(prz->ecc_symsize, prz->ecc_poly, 0, 1,
2259cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross				  prz->ecc_size);
2269cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	if (prz->rs_decoder == NULL) {
2279cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		pr_info("persistent_ram: init_rs failed\n");
2289cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		return -EINVAL;
229c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	}
2309cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2319cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	prz->corrected_bytes = 0;
2329cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	prz->bad_blocks = 0;
2339cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2349cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	numerr = persistent_ram_decode_rs8(prz, buffer, sizeof(*buffer),
2359cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross					   prz->par_header);
2369cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	if (numerr > 0) {
2379cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		pr_info("persistent_ram: error in header, %d\n", numerr);
2389cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		prz->corrected_bytes += numerr;
2399cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	} else if (numerr < 0) {
2409cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		pr_info("persistent_ram: uncorrectable error in header\n");
2419cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		prz->bad_blocks++;
2429cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	}
2439cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2449cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	return 0;
2459cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross}
2469cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2479cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Crossssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
2489cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	char *str, size_t len)
2499cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross{
2509cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	ssize_t ret;
2519cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2529cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	if (prz->corrected_bytes || prz->bad_blocks)
2539cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		ret = snprintf(str, len, ""
2549cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross			"\n%d Corrected bytes, %d unrecoverable blocks\n",
2559cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross			prz->corrected_bytes, prz->bad_blocks);
2569cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	else
2579cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		ret = snprintf(str, len, "\nNo errors detected\n");
2589cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2599cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	return ret;
2609cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross}
2619cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
262a15d0b365e9bbf04dacb44fbe69d15f6594460e1Colin Crossstatic void notrace persistent_ram_update(struct persistent_ram_zone *prz,
263808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	const void *s, unsigned int start, unsigned int count)
2649cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross{
2659cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	struct persistent_ram_buffer *buffer = prz->buffer;
266808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	memcpy(buffer->data + start, s, count);
267808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	persistent_ram_update_ecc(prz, start, count);
2689cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross}
2699cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2704a2212f2e6a4938180bfced93efb3adea4c6418dColin Crossstatic void __devinit
2719cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Crosspersistent_ram_save_old(struct persistent_ram_zone *prz)
2729cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross{
2739cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	struct persistent_ram_buffer *buffer = prz->buffer;
274808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	size_t size = buffer_size(prz);
275808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	size_t start = buffer_start(prz);
2769cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	char *dest;
2779cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2789cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	persistent_ram_ecc_old(prz);
279c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
280808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	dest = kmalloc(size, GFP_KERNEL);
281c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	if (dest == NULL) {
282c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		pr_err("persistent_ram: failed to allocate buffer\n");
283c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		return;
284c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	}
285c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
286c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	prz->old_log = dest;
287808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	prz->old_log_size = size;
288808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	memcpy(prz->old_log, &buffer->data[start], size - start);
289808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	memcpy(prz->old_log + size - start, &buffer->data[0], start);
290c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross}
291c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
292a15d0b365e9bbf04dacb44fbe69d15f6594460e1Colin Crossint notrace persistent_ram_write(struct persistent_ram_zone *prz,
293c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	const void *s, unsigned int count)
294c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross{
295c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	int rem;
296c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	int c = count;
297808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	size_t start;
298c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
299808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	if (unlikely(c > prz->buffer_size)) {
300c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		s += c - prz->buffer_size;
301c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		c = prz->buffer_size;
302c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	}
303808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross
304808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	buffer_size_add_clamp(prz, c);
305808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross
306808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	start = buffer_start_add(prz, c);
307808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross
308808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	rem = prz->buffer_size - start;
309808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	if (unlikely(rem < c)) {
310808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		persistent_ram_update(prz, s, start, rem);
311c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		s += rem;
312c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		c -= rem;
313808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		start = 0;
314c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	}
315808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	persistent_ram_update(prz, s, start, c);
316c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
3179cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	persistent_ram_update_header_ecc(prz);
318c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
319c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	return count;
320c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross}
321c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
322c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Crosssize_t persistent_ram_old_size(struct persistent_ram_zone *prz)
323c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross{
324c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	return prz->old_log_size;
325c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross}
326c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
327c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Crossvoid *persistent_ram_old(struct persistent_ram_zone *prz)
328c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross{
329c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	return prz->old_log;
330c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross}
331c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
332c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Crossvoid persistent_ram_free_old(struct persistent_ram_zone *prz)
333c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross{
334c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	kfree(prz->old_log);
335c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	prz->old_log = NULL;
336c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	prz->old_log_size = 0;
337c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross}
338c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
339404a6043385de17273624b076599669db5ad891fColin Crossstatic int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
340404a6043385de17273624b076599669db5ad891fColin Cross		struct persistent_ram_zone *prz)
341c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross{
342404a6043385de17273624b076599669db5ad891fColin Cross	struct page **pages;
343404a6043385de17273624b076599669db5ad891fColin Cross	phys_addr_t page_start;
344404a6043385de17273624b076599669db5ad891fColin Cross	unsigned int page_count;
345404a6043385de17273624b076599669db5ad891fColin Cross	pgprot_t prot;
346404a6043385de17273624b076599669db5ad891fColin Cross	unsigned int i;
347404a6043385de17273624b076599669db5ad891fColin Cross
348404a6043385de17273624b076599669db5ad891fColin Cross	page_start = start - offset_in_page(start);
349404a6043385de17273624b076599669db5ad891fColin Cross	page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
350404a6043385de17273624b076599669db5ad891fColin Cross
351404a6043385de17273624b076599669db5ad891fColin Cross	prot = pgprot_noncached(PAGE_KERNEL);
352404a6043385de17273624b076599669db5ad891fColin Cross
353404a6043385de17273624b076599669db5ad891fColin Cross	pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL);
354404a6043385de17273624b076599669db5ad891fColin Cross	if (!pages) {
355404a6043385de17273624b076599669db5ad891fColin Cross		pr_err("%s: Failed to allocate array for %u pages\n", __func__,
356404a6043385de17273624b076599669db5ad891fColin Cross			page_count);
357404a6043385de17273624b076599669db5ad891fColin Cross		return -ENOMEM;
358404a6043385de17273624b076599669db5ad891fColin Cross	}
359404a6043385de17273624b076599669db5ad891fColin Cross
360404a6043385de17273624b076599669db5ad891fColin Cross	for (i = 0; i < page_count; i++) {
361404a6043385de17273624b076599669db5ad891fColin Cross		phys_addr_t addr = page_start + i * PAGE_SIZE;
362404a6043385de17273624b076599669db5ad891fColin Cross		pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
363404a6043385de17273624b076599669db5ad891fColin Cross	}
364404a6043385de17273624b076599669db5ad891fColin Cross	prz->vaddr = vmap(pages, page_count, VM_MAP, prot);
365404a6043385de17273624b076599669db5ad891fColin Cross	kfree(pages);
366404a6043385de17273624b076599669db5ad891fColin Cross	if (!prz->vaddr) {
367404a6043385de17273624b076599669db5ad891fColin Cross		pr_err("%s: Failed to map %u pages\n", __func__, page_count);
368404a6043385de17273624b076599669db5ad891fColin Cross		return -ENOMEM;
369404a6043385de17273624b076599669db5ad891fColin Cross	}
370404a6043385de17273624b076599669db5ad891fColin Cross
371404a6043385de17273624b076599669db5ad891fColin Cross	prz->buffer = prz->vaddr + offset_in_page(start);
372404a6043385de17273624b076599669db5ad891fColin Cross	prz->buffer_size = size - sizeof(struct persistent_ram_buffer);
373404a6043385de17273624b076599669db5ad891fColin Cross
374404a6043385de17273624b076599669db5ad891fColin Cross	return 0;
375404a6043385de17273624b076599669db5ad891fColin Cross}
376404a6043385de17273624b076599669db5ad891fColin Cross
3774a2212f2e6a4938180bfced93efb3adea4c6418dColin Crossstatic int __devinit persistent_ram_buffer_init(const char *name,
3786411d5781dee41da3e2e29b024140e8f4a0f0ac7Arve Hjønnevåg		struct persistent_ram_zone *prz, struct persistent_ram **ramp)
379404a6043385de17273624b076599669db5ad891fColin Cross{
380404a6043385de17273624b076599669db5ad891fColin Cross	int i;
381404a6043385de17273624b076599669db5ad891fColin Cross	struct persistent_ram *ram;
382404a6043385de17273624b076599669db5ad891fColin Cross	struct persistent_ram_descriptor *desc;
383404a6043385de17273624b076599669db5ad891fColin Cross	phys_addr_t start;
384404a6043385de17273624b076599669db5ad891fColin Cross
385404a6043385de17273624b076599669db5ad891fColin Cross	list_for_each_entry(ram, &persistent_ram_list, node) {
386404a6043385de17273624b076599669db5ad891fColin Cross		start = ram->start;
387404a6043385de17273624b076599669db5ad891fColin Cross		for (i = 0; i < ram->num_descs; i++) {
388404a6043385de17273624b076599669db5ad891fColin Cross			desc = &ram->descs[i];
3896411d5781dee41da3e2e29b024140e8f4a0f0ac7Arve Hjønnevåg			if (!strcmp(desc->name, name)) {
3906411d5781dee41da3e2e29b024140e8f4a0f0ac7Arve Hjønnevåg				*ramp = ram;
391404a6043385de17273624b076599669db5ad891fColin Cross				return persistent_ram_buffer_map(start,
392404a6043385de17273624b076599669db5ad891fColin Cross						desc->size, prz);
3936411d5781dee41da3e2e29b024140e8f4a0f0ac7Arve Hjønnevåg			}
394404a6043385de17273624b076599669db5ad891fColin Cross			start += desc->size;
395404a6043385de17273624b076599669db5ad891fColin Cross		}
396404a6043385de17273624b076599669db5ad891fColin Cross	}
397404a6043385de17273624b076599669db5ad891fColin Cross
398404a6043385de17273624b076599669db5ad891fColin Cross	return -EINVAL;
399404a6043385de17273624b076599669db5ad891fColin Cross}
400404a6043385de17273624b076599669db5ad891fColin Cross
4014a2212f2e6a4938180bfced93efb3adea4c6418dColin Crossstatic  __devinit
402404a6043385de17273624b076599669db5ad891fColin Crossstruct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc)
403404a6043385de17273624b076599669db5ad891fColin Cross{
4046411d5781dee41da3e2e29b024140e8f4a0f0ac7Arve Hjønnevåg	struct persistent_ram *ram;
405404a6043385de17273624b076599669db5ad891fColin Cross	struct persistent_ram_zone *prz;
406474a89885f77953b12bce9f23660c31ef5c2630eJesper Juhl	int ret = -ENOMEM;
407c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
408404a6043385de17273624b076599669db5ad891fColin Cross	prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
409404a6043385de17273624b076599669db5ad891fColin Cross	if (!prz) {
410404a6043385de17273624b076599669db5ad891fColin Cross		pr_err("persistent_ram: failed to allocate persistent ram zone\n");
411474a89885f77953b12bce9f23660c31ef5c2630eJesper Juhl		goto err;
412404a6043385de17273624b076599669db5ad891fColin Cross	}
413c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
414404a6043385de17273624b076599669db5ad891fColin Cross	INIT_LIST_HEAD(&prz->node);
415c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
4166411d5781dee41da3e2e29b024140e8f4a0f0ac7Arve Hjønnevåg	ret = persistent_ram_buffer_init(dev_name(dev), prz, &ram);
417404a6043385de17273624b076599669db5ad891fColin Cross	if (ret) {
418404a6043385de17273624b076599669db5ad891fColin Cross		pr_err("persistent_ram: failed to initialize buffer\n");
419474a89885f77953b12bce9f23660c31ef5c2630eJesper Juhl		goto err;
420c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	}
421c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
4229cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	prz->ecc = ecc;
4236411d5781dee41da3e2e29b024140e8f4a0f0ac7Arve Hjønnevåg	ret = persistent_ram_init_ecc(prz, prz->buffer_size, ram);
4249cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	if (ret)
425474a89885f77953b12bce9f23660c31ef5c2630eJesper Juhl		goto err;
426c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
427404a6043385de17273624b076599669db5ad891fColin Cross	if (prz->buffer->sig == PERSISTENT_RAM_SIG) {
428808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		if (buffer_size(prz) > prz->buffer_size ||
429808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		    buffer_start(prz) > buffer_size(prz))
430808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross			pr_info("persistent_ram: found existing invalid buffer,"
4318543065b05c5a2aadbaf476a3af3099753fd710eColin Cross				" size %zu, start %zu\n",
432808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross			       buffer_size(prz), buffer_start(prz));
433c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		else {
434808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross			pr_info("persistent_ram: found existing buffer,"
4358543065b05c5a2aadbaf476a3af3099753fd710eColin Cross				" size %zu, start %zu\n",
436808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross			       buffer_size(prz), buffer_start(prz));
437c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross			persistent_ram_save_old(prz);
438c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		}
439c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	} else {
440808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		pr_info("persistent_ram: no valid data in buffer"
441808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross			" (sig = 0x%08x)\n", prz->buffer->sig);
442c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	}
443c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
444404a6043385de17273624b076599669db5ad891fColin Cross	prz->buffer->sig = PERSISTENT_RAM_SIG;
445808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	atomic_set(&prz->buffer->start, 0);
446808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	atomic_set(&prz->buffer->size, 0);
447c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
448404a6043385de17273624b076599669db5ad891fColin Cross	return prz;
449474a89885f77953b12bce9f23660c31ef5c2630eJesper Juhlerr:
450474a89885f77953b12bce9f23660c31ef5c2630eJesper Juhl	kfree(prz);
451474a89885f77953b12bce9f23660c31ef5c2630eJesper Juhl	return ERR_PTR(ret);
452404a6043385de17273624b076599669db5ad891fColin Cross}
453c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
4544a2212f2e6a4938180bfced93efb3adea4c6418dColin Crossstruct persistent_ram_zone * __devinit
455404a6043385de17273624b076599669db5ad891fColin Crosspersistent_ram_init_ringbuffer(struct device *dev, bool ecc)
456404a6043385de17273624b076599669db5ad891fColin Cross{
457404a6043385de17273624b076599669db5ad891fColin Cross	return __persistent_ram_init(dev, ecc);
458c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross}
459c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
460404a6043385de17273624b076599669db5ad891fColin Crossint __init persistent_ram_early_init(struct persistent_ram *ram)
461c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross{
462404a6043385de17273624b076599669db5ad891fColin Cross	int ret;
463404a6043385de17273624b076599669db5ad891fColin Cross
464404a6043385de17273624b076599669db5ad891fColin Cross	ret = memblock_reserve(ram->start, ram->size);
465404a6043385de17273624b076599669db5ad891fColin Cross	if (ret) {
466404a6043385de17273624b076599669db5ad891fColin Cross		pr_err("Failed to reserve persistent memory from %08lx-%08lx\n",
467404a6043385de17273624b076599669db5ad891fColin Cross			(long)ram->start, (long)(ram->start + ram->size - 1));
468404a6043385de17273624b076599669db5ad891fColin Cross		return ret;
469404a6043385de17273624b076599669db5ad891fColin Cross	}
470404a6043385de17273624b076599669db5ad891fColin Cross
471404a6043385de17273624b076599669db5ad891fColin Cross	list_add_tail(&ram->node, &persistent_ram_list);
472404a6043385de17273624b076599669db5ad891fColin Cross
473404a6043385de17273624b076599669db5ad891fColin Cross	pr_info("Initialized persistent memory from %08lx-%08lx\n",
474404a6043385de17273624b076599669db5ad891fColin Cross		(long)ram->start, (long)(ram->start + ram->size - 1));
475404a6043385de17273624b076599669db5ad891fColin Cross
476404a6043385de17273624b076599669db5ad891fColin Cross	return 0;
477c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross}
478