persistent_ram.c revision 4a2212f2e6a4938180bfced93efb3adea4c6418d
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>
239cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross#include <linux/rslib.h>
24c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross#include <linux/slab.h>
25404a6043385de17273624b076599669db5ad891fColin Cross#include <linux/vmalloc.h>
26c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross#include "persistent_ram.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,
1939cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	size_t buffer_size)
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
2029cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	prz->ecc_block_size = 128;
2039cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	prz->ecc_size = 16;
2049cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	prz->ecc_symsize = 8;
2059cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	prz->ecc_poly = 0x11d;
2069cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2079cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	ecc_blocks = DIV_ROUND_UP(prz->buffer_size, prz->ecc_block_size);
2089cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	prz->buffer_size -= (ecc_blocks + 1) * prz->ecc_size;
2099cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2109cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	if (prz->buffer_size > buffer_size) {
2119cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		pr_err("persistent_ram: invalid size %zu, non-ecc datasize %zu\n",
2129cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		       buffer_size, prz->buffer_size);
2139cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		return -EINVAL;
2149cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	}
2159cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2169cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	prz->par_buffer = buffer->data + prz->buffer_size;
2179cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	prz->par_header = prz->par_buffer + ecc_blocks * prz->ecc_size;
2189cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2199cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	/*
2209cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	 * first consecutive root is 0
2219cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	 * primitive element to generate roots = 1
2229cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	 */
2239cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	prz->rs_decoder = init_rs(prz->ecc_symsize, prz->ecc_poly, 0, 1,
2249cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross				  prz->ecc_size);
2259cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	if (prz->rs_decoder == NULL) {
2269cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		pr_info("persistent_ram: init_rs failed\n");
2279cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		return -EINVAL;
228c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	}
2299cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2309cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	prz->corrected_bytes = 0;
2319cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	prz->bad_blocks = 0;
2329cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2339cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	numerr = persistent_ram_decode_rs8(prz, buffer, sizeof(*buffer),
2349cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross					   prz->par_header);
2359cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	if (numerr > 0) {
2369cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		pr_info("persistent_ram: error in header, %d\n", numerr);
2379cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		prz->corrected_bytes += numerr;
2389cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	} else if (numerr < 0) {
2399cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		pr_info("persistent_ram: uncorrectable error in header\n");
2409cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		prz->bad_blocks++;
2419cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	}
2429cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2439cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	return 0;
2449cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross}
2459cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2469cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Crossssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
2479cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	char *str, size_t len)
2489cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross{
2499cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	ssize_t ret;
2509cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2519cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	if (prz->corrected_bytes || prz->bad_blocks)
2529cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		ret = snprintf(str, len, ""
2539cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross			"\n%d Corrected bytes, %d unrecoverable blocks\n",
2549cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross			prz->corrected_bytes, prz->bad_blocks);
2559cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	else
2569cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross		ret = snprintf(str, len, "\nNo errors detected\n");
2579cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2589cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	return ret;
2599cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross}
2609cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
261a15d0b365e9bbf04dacb44fbe69d15f6594460e1Colin Crossstatic void notrace persistent_ram_update(struct persistent_ram_zone *prz,
262808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	const void *s, unsigned int start, unsigned int count)
2639cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross{
2649cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	struct persistent_ram_buffer *buffer = prz->buffer;
265808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	memcpy(buffer->data + start, s, count);
266808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	persistent_ram_update_ecc(prz, start, count);
2679cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross}
2689cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2694a2212f2e6a4938180bfced93efb3adea4c6418dColin Crossstatic void __devinit
2709cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Crosspersistent_ram_save_old(struct persistent_ram_zone *prz)
2719cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross{
2729cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	struct persistent_ram_buffer *buffer = prz->buffer;
273808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	size_t size = buffer_size(prz);
274808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	size_t start = buffer_start(prz);
2759cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	char *dest;
2769cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross
2779cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	persistent_ram_ecc_old(prz);
278c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
279808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	dest = kmalloc(size, GFP_KERNEL);
280c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	if (dest == NULL) {
281c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		pr_err("persistent_ram: failed to allocate buffer\n");
282c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		return;
283c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	}
284c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
285c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	prz->old_log = dest;
286808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	prz->old_log_size = size;
287808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	memcpy(prz->old_log, &buffer->data[start], size - start);
288808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	memcpy(prz->old_log + size - start, &buffer->data[0], start);
289c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross}
290c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
291a15d0b365e9bbf04dacb44fbe69d15f6594460e1Colin Crossint notrace persistent_ram_write(struct persistent_ram_zone *prz,
292c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	const void *s, unsigned int count)
293c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross{
294c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	int rem;
295c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	int c = count;
296808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	size_t start;
297c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
298808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	if (unlikely(c > prz->buffer_size)) {
299c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		s += c - prz->buffer_size;
300c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		c = prz->buffer_size;
301c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	}
302808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross
303808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	buffer_size_add_clamp(prz, c);
304808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross
305808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	start = buffer_start_add(prz, c);
306808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross
307808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	rem = prz->buffer_size - start;
308808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	if (unlikely(rem < c)) {
309808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		persistent_ram_update(prz, s, start, rem);
310c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		s += rem;
311c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		c -= rem;
312808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		start = 0;
313c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	}
314808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	persistent_ram_update(prz, s, start, c);
315c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
3169cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	persistent_ram_update_header_ecc(prz);
317c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
318c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	return count;
319c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross}
320c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
321c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Crosssize_t persistent_ram_old_size(struct persistent_ram_zone *prz)
322c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross{
323c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	return prz->old_log_size;
324c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross}
325c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
326c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Crossvoid *persistent_ram_old(struct persistent_ram_zone *prz)
327c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross{
328c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	return prz->old_log;
329c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross}
330c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
331c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Crossvoid persistent_ram_free_old(struct persistent_ram_zone *prz)
332c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross{
333c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	kfree(prz->old_log);
334c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	prz->old_log = NULL;
335c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	prz->old_log_size = 0;
336c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross}
337c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
338404a6043385de17273624b076599669db5ad891fColin Crossstatic int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
339404a6043385de17273624b076599669db5ad891fColin Cross		struct persistent_ram_zone *prz)
340c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross{
341404a6043385de17273624b076599669db5ad891fColin Cross	struct page **pages;
342404a6043385de17273624b076599669db5ad891fColin Cross	phys_addr_t page_start;
343404a6043385de17273624b076599669db5ad891fColin Cross	unsigned int page_count;
344404a6043385de17273624b076599669db5ad891fColin Cross	pgprot_t prot;
345404a6043385de17273624b076599669db5ad891fColin Cross	unsigned int i;
346404a6043385de17273624b076599669db5ad891fColin Cross
347404a6043385de17273624b076599669db5ad891fColin Cross	page_start = start - offset_in_page(start);
348404a6043385de17273624b076599669db5ad891fColin Cross	page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
349404a6043385de17273624b076599669db5ad891fColin Cross
350404a6043385de17273624b076599669db5ad891fColin Cross	prot = pgprot_noncached(PAGE_KERNEL);
351404a6043385de17273624b076599669db5ad891fColin Cross
352404a6043385de17273624b076599669db5ad891fColin Cross	pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL);
353404a6043385de17273624b076599669db5ad891fColin Cross	if (!pages) {
354404a6043385de17273624b076599669db5ad891fColin Cross		pr_err("%s: Failed to allocate array for %u pages\n", __func__,
355404a6043385de17273624b076599669db5ad891fColin Cross			page_count);
356404a6043385de17273624b076599669db5ad891fColin Cross		return -ENOMEM;
357404a6043385de17273624b076599669db5ad891fColin Cross	}
358404a6043385de17273624b076599669db5ad891fColin Cross
359404a6043385de17273624b076599669db5ad891fColin Cross	for (i = 0; i < page_count; i++) {
360404a6043385de17273624b076599669db5ad891fColin Cross		phys_addr_t addr = page_start + i * PAGE_SIZE;
361404a6043385de17273624b076599669db5ad891fColin Cross		pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
362404a6043385de17273624b076599669db5ad891fColin Cross	}
363404a6043385de17273624b076599669db5ad891fColin Cross	prz->vaddr = vmap(pages, page_count, VM_MAP, prot);
364404a6043385de17273624b076599669db5ad891fColin Cross	kfree(pages);
365404a6043385de17273624b076599669db5ad891fColin Cross	if (!prz->vaddr) {
366404a6043385de17273624b076599669db5ad891fColin Cross		pr_err("%s: Failed to map %u pages\n", __func__, page_count);
367404a6043385de17273624b076599669db5ad891fColin Cross		return -ENOMEM;
368404a6043385de17273624b076599669db5ad891fColin Cross	}
369404a6043385de17273624b076599669db5ad891fColin Cross
370404a6043385de17273624b076599669db5ad891fColin Cross	prz->buffer = prz->vaddr + offset_in_page(start);
371404a6043385de17273624b076599669db5ad891fColin Cross	prz->buffer_size = size - sizeof(struct persistent_ram_buffer);
372404a6043385de17273624b076599669db5ad891fColin Cross
373404a6043385de17273624b076599669db5ad891fColin Cross	return 0;
374404a6043385de17273624b076599669db5ad891fColin Cross}
375404a6043385de17273624b076599669db5ad891fColin Cross
3764a2212f2e6a4938180bfced93efb3adea4c6418dColin Crossstatic int __devinit persistent_ram_buffer_init(const char *name,
377404a6043385de17273624b076599669db5ad891fColin Cross		struct persistent_ram_zone *prz)
378404a6043385de17273624b076599669db5ad891fColin Cross{
379404a6043385de17273624b076599669db5ad891fColin Cross	int i;
380404a6043385de17273624b076599669db5ad891fColin Cross	struct persistent_ram *ram;
381404a6043385de17273624b076599669db5ad891fColin Cross	struct persistent_ram_descriptor *desc;
382404a6043385de17273624b076599669db5ad891fColin Cross	phys_addr_t start;
383404a6043385de17273624b076599669db5ad891fColin Cross
384404a6043385de17273624b076599669db5ad891fColin Cross	list_for_each_entry(ram, &persistent_ram_list, node) {
385404a6043385de17273624b076599669db5ad891fColin Cross		start = ram->start;
386404a6043385de17273624b076599669db5ad891fColin Cross		for (i = 0; i < ram->num_descs; i++) {
387404a6043385de17273624b076599669db5ad891fColin Cross			desc = &ram->descs[i];
388404a6043385de17273624b076599669db5ad891fColin Cross			if (!strcmp(desc->name, name))
389404a6043385de17273624b076599669db5ad891fColin Cross				return persistent_ram_buffer_map(start,
390404a6043385de17273624b076599669db5ad891fColin Cross						desc->size, prz);
391404a6043385de17273624b076599669db5ad891fColin Cross			start += desc->size;
392404a6043385de17273624b076599669db5ad891fColin Cross		}
393404a6043385de17273624b076599669db5ad891fColin Cross	}
394404a6043385de17273624b076599669db5ad891fColin Cross
395404a6043385de17273624b076599669db5ad891fColin Cross	return -EINVAL;
396404a6043385de17273624b076599669db5ad891fColin Cross}
397404a6043385de17273624b076599669db5ad891fColin Cross
3984a2212f2e6a4938180bfced93efb3adea4c6418dColin Crossstatic  __devinit
399404a6043385de17273624b076599669db5ad891fColin Crossstruct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc)
400404a6043385de17273624b076599669db5ad891fColin Cross{
401404a6043385de17273624b076599669db5ad891fColin Cross	struct persistent_ram_zone *prz;
4029cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	int ret;
403c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
404404a6043385de17273624b076599669db5ad891fColin Cross	prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
405404a6043385de17273624b076599669db5ad891fColin Cross	if (!prz) {
406404a6043385de17273624b076599669db5ad891fColin Cross		pr_err("persistent_ram: failed to allocate persistent ram zone\n");
407404a6043385de17273624b076599669db5ad891fColin Cross		return ERR_PTR(-ENOMEM);
408404a6043385de17273624b076599669db5ad891fColin Cross	}
409c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
410404a6043385de17273624b076599669db5ad891fColin Cross	INIT_LIST_HEAD(&prz->node);
411c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
412404a6043385de17273624b076599669db5ad891fColin Cross	ret = persistent_ram_buffer_init(dev_name(dev), prz);
413404a6043385de17273624b076599669db5ad891fColin Cross	if (ret) {
414404a6043385de17273624b076599669db5ad891fColin Cross		pr_err("persistent_ram: failed to initialize buffer\n");
415404a6043385de17273624b076599669db5ad891fColin Cross		return ERR_PTR(ret);
416c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	}
417c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
4189cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	prz->ecc = ecc;
419404a6043385de17273624b076599669db5ad891fColin Cross	ret = persistent_ram_init_ecc(prz, prz->buffer_size);
4209cc05ad97c5728aaf4db94490daf41f8958b5aeeColin Cross	if (ret)
421404a6043385de17273624b076599669db5ad891fColin Cross		return ERR_PTR(ret);
422c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
423404a6043385de17273624b076599669db5ad891fColin Cross	if (prz->buffer->sig == PERSISTENT_RAM_SIG) {
424808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		if (buffer_size(prz) > prz->buffer_size ||
425808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		    buffer_start(prz) > buffer_size(prz))
426808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross			pr_info("persistent_ram: found existing invalid buffer,"
427808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross				" size %ld, start %ld\n",
428808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross			       buffer_size(prz), buffer_start(prz));
429c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		else {
430808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross			pr_info("persistent_ram: found existing buffer,"
431808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross				" size %ld, start %ld\n",
432808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross			       buffer_size(prz), buffer_start(prz));
433c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross			persistent_ram_save_old(prz);
434c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross		}
435c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	} else {
436808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross		pr_info("persistent_ram: no valid data in buffer"
437808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross			" (sig = 0x%08x)\n", prz->buffer->sig);
438c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross	}
439c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
440404a6043385de17273624b076599669db5ad891fColin Cross	prz->buffer->sig = PERSISTENT_RAM_SIG;
441808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	atomic_set(&prz->buffer->start, 0);
442808d0387eb7df3f83352ca41f8c943cb3ed61246Colin Cross	atomic_set(&prz->buffer->size, 0);
443c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
444404a6043385de17273624b076599669db5ad891fColin Cross	return prz;
445404a6043385de17273624b076599669db5ad891fColin Cross}
446c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
4474a2212f2e6a4938180bfced93efb3adea4c6418dColin Crossstruct persistent_ram_zone * __devinit
448404a6043385de17273624b076599669db5ad891fColin Crosspersistent_ram_init_ringbuffer(struct device *dev, bool ecc)
449404a6043385de17273624b076599669db5ad891fColin Cross{
450404a6043385de17273624b076599669db5ad891fColin Cross	return __persistent_ram_init(dev, ecc);
451c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross}
452c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross
453404a6043385de17273624b076599669db5ad891fColin Crossint __init persistent_ram_early_init(struct persistent_ram *ram)
454c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross{
455404a6043385de17273624b076599669db5ad891fColin Cross	int ret;
456404a6043385de17273624b076599669db5ad891fColin Cross
457404a6043385de17273624b076599669db5ad891fColin Cross	ret = memblock_reserve(ram->start, ram->size);
458404a6043385de17273624b076599669db5ad891fColin Cross	if (ret) {
459404a6043385de17273624b076599669db5ad891fColin Cross		pr_err("Failed to reserve persistent memory from %08lx-%08lx\n",
460404a6043385de17273624b076599669db5ad891fColin Cross			(long)ram->start, (long)(ram->start + ram->size - 1));
461404a6043385de17273624b076599669db5ad891fColin Cross		return ret;
462404a6043385de17273624b076599669db5ad891fColin Cross	}
463404a6043385de17273624b076599669db5ad891fColin Cross
464404a6043385de17273624b076599669db5ad891fColin Cross	list_add_tail(&ram->node, &persistent_ram_list);
465404a6043385de17273624b076599669db5ad891fColin Cross
466404a6043385de17273624b076599669db5ad891fColin Cross	pr_info("Initialized persistent memory from %08lx-%08lx\n",
467404a6043385de17273624b076599669db5ad891fColin Cross		(long)ram->start, (long)(ram->start + ram->size - 1));
468404a6043385de17273624b076599669db5ad891fColin Cross
469404a6043385de17273624b076599669db5ad891fColin Cross	return 0;
470c672528aec4a1cf6f3df7a6022e6823a20b20f8eColin Cross}
471