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