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