persistent_ram.c revision 404a6043385de17273624b076599669db5ad891f
1/* 2 * Copyright (C) 2012 Google, Inc. 3 * 4 * This software is licensed under the terms of the GNU General Public 5 * License version 2, as published by the Free Software Foundation, and 6 * may be copied, distributed, and modified under those terms. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 */ 14 15#include <linux/device.h> 16#include <linux/err.h> 17#include <linux/errno.h> 18#include <linux/kernel.h> 19#include <linux/init.h> 20#include <linux/io.h> 21#include <linux/list.h> 22#include <linux/memblock.h> 23#include <linux/rslib.h> 24#include <linux/slab.h> 25#include <linux/vmalloc.h> 26#include "persistent_ram.h" 27 28struct persistent_ram_buffer { 29 uint32_t sig; 30 uint32_t start; 31 uint32_t size; 32 uint8_t data[0]; 33}; 34 35#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */ 36 37static __initdata LIST_HEAD(persistent_ram_list); 38 39static void persistent_ram_encode_rs8(struct persistent_ram_zone *prz, 40 uint8_t *data, size_t len, uint8_t *ecc) 41{ 42 int i; 43 uint16_t par[prz->ecc_size]; 44 45 /* Initialize the parity buffer */ 46 memset(par, 0, sizeof(par)); 47 encode_rs8(prz->rs_decoder, data, len, par, 0); 48 for (i = 0; i < prz->ecc_size; i++) 49 ecc[i] = par[i]; 50} 51 52static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz, 53 void *data, size_t len, uint8_t *ecc) 54{ 55 int i; 56 uint16_t par[prz->ecc_size]; 57 58 for (i = 0; i < prz->ecc_size; i++) 59 par[i] = ecc[i]; 60 return decode_rs8(prz->rs_decoder, data, par, len, 61 NULL, 0, NULL, 0, NULL); 62} 63 64static void persistent_ram_update_ecc(struct persistent_ram_zone *prz, 65 unsigned int count) 66{ 67 struct persistent_ram_buffer *buffer = prz->buffer; 68 uint8_t *buffer_end = buffer->data + prz->buffer_size; 69 uint8_t *block; 70 uint8_t *par; 71 int ecc_block_size = prz->ecc_block_size; 72 int ecc_size = prz->ecc_size; 73 int size = prz->ecc_block_size; 74 75 if (!prz->ecc) 76 return; 77 78 block = buffer->data + (buffer->start & ~(ecc_block_size - 1)); 79 par = prz->par_buffer + 80 (buffer->start / ecc_block_size) * prz->ecc_size; 81 do { 82 if (block + ecc_block_size > buffer_end) 83 size = buffer_end - block; 84 persistent_ram_encode_rs8(prz, block, size, par); 85 block += ecc_block_size; 86 par += ecc_size; 87 } while (block < buffer->data + buffer->start + count); 88} 89 90static void persistent_ram_update_header_ecc(struct persistent_ram_zone *prz) 91{ 92 struct persistent_ram_buffer *buffer = prz->buffer; 93 94 if (!prz->ecc) 95 return; 96 97 persistent_ram_encode_rs8(prz, (uint8_t *)buffer, sizeof(*buffer), 98 prz->par_header); 99} 100 101static void persistent_ram_ecc_old(struct persistent_ram_zone *prz) 102{ 103 struct persistent_ram_buffer *buffer = prz->buffer; 104 uint8_t *block; 105 uint8_t *par; 106 107 if (!prz->ecc) 108 return; 109 110 block = buffer->data; 111 par = prz->par_buffer; 112 while (block < buffer->data + buffer->size) { 113 int numerr; 114 int size = prz->ecc_block_size; 115 if (block + size > buffer->data + prz->buffer_size) 116 size = buffer->data + prz->buffer_size - block; 117 numerr = persistent_ram_decode_rs8(prz, block, size, par); 118 if (numerr > 0) { 119 pr_devel("persistent_ram: error in block %p, %d\n", 120 block, numerr); 121 prz->corrected_bytes += numerr; 122 } else if (numerr < 0) { 123 pr_devel("persistent_ram: uncorrectable error in block %p\n", 124 block); 125 prz->bad_blocks++; 126 } 127 block += prz->ecc_block_size; 128 par += prz->ecc_size; 129 } 130} 131 132static int persistent_ram_init_ecc(struct persistent_ram_zone *prz, 133 size_t buffer_size) 134{ 135 int numerr; 136 struct persistent_ram_buffer *buffer = prz->buffer; 137 int ecc_blocks; 138 139 if (!prz->ecc) 140 return 0; 141 142 prz->ecc_block_size = 128; 143 prz->ecc_size = 16; 144 prz->ecc_symsize = 8; 145 prz->ecc_poly = 0x11d; 146 147 ecc_blocks = DIV_ROUND_UP(prz->buffer_size, prz->ecc_block_size); 148 prz->buffer_size -= (ecc_blocks + 1) * prz->ecc_size; 149 150 if (prz->buffer_size > buffer_size) { 151 pr_err("persistent_ram: invalid size %zu, non-ecc datasize %zu\n", 152 buffer_size, prz->buffer_size); 153 return -EINVAL; 154 } 155 156 prz->par_buffer = buffer->data + prz->buffer_size; 157 prz->par_header = prz->par_buffer + ecc_blocks * prz->ecc_size; 158 159 /* 160 * first consecutive root is 0 161 * primitive element to generate roots = 1 162 */ 163 prz->rs_decoder = init_rs(prz->ecc_symsize, prz->ecc_poly, 0, 1, 164 prz->ecc_size); 165 if (prz->rs_decoder == NULL) { 166 pr_info("persistent_ram: init_rs failed\n"); 167 return -EINVAL; 168 } 169 170 prz->corrected_bytes = 0; 171 prz->bad_blocks = 0; 172 173 numerr = persistent_ram_decode_rs8(prz, buffer, sizeof(*buffer), 174 prz->par_header); 175 if (numerr > 0) { 176 pr_info("persistent_ram: error in header, %d\n", numerr); 177 prz->corrected_bytes += numerr; 178 } else if (numerr < 0) { 179 pr_info("persistent_ram: uncorrectable error in header\n"); 180 prz->bad_blocks++; 181 } 182 183 return 0; 184} 185 186ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz, 187 char *str, size_t len) 188{ 189 ssize_t ret; 190 191 if (prz->corrected_bytes || prz->bad_blocks) 192 ret = snprintf(str, len, "" 193 "\n%d Corrected bytes, %d unrecoverable blocks\n", 194 prz->corrected_bytes, prz->bad_blocks); 195 else 196 ret = snprintf(str, len, "\nNo errors detected\n"); 197 198 return ret; 199} 200 201static void persistent_ram_update(struct persistent_ram_zone *prz, 202 const void *s, unsigned int count) 203{ 204 struct persistent_ram_buffer *buffer = prz->buffer; 205 memcpy(buffer->data + buffer->start, s, count); 206 persistent_ram_update_ecc(prz, count); 207} 208 209static void __init 210persistent_ram_save_old(struct persistent_ram_zone *prz) 211{ 212 struct persistent_ram_buffer *buffer = prz->buffer; 213 size_t old_log_size = buffer->size; 214 char *dest; 215 216 persistent_ram_ecc_old(prz); 217 218 dest = kmalloc(old_log_size, GFP_KERNEL); 219 if (dest == NULL) { 220 pr_err("persistent_ram: failed to allocate buffer\n"); 221 return; 222 } 223 224 prz->old_log = dest; 225 prz->old_log_size = old_log_size; 226 memcpy(prz->old_log, 227 &buffer->data[buffer->start], buffer->size - buffer->start); 228 memcpy(prz->old_log + buffer->size - buffer->start, 229 &buffer->data[0], buffer->start); 230} 231 232int persistent_ram_write(struct persistent_ram_zone *prz, 233 const void *s, unsigned int count) 234{ 235 int rem; 236 int c = count; 237 struct persistent_ram_buffer *buffer = prz->buffer; 238 239 if (c > prz->buffer_size) { 240 s += c - prz->buffer_size; 241 c = prz->buffer_size; 242 } 243 rem = prz->buffer_size - buffer->start; 244 if (rem < c) { 245 persistent_ram_update(prz, s, rem); 246 s += rem; 247 c -= rem; 248 buffer->start = 0; 249 buffer->size = prz->buffer_size; 250 } 251 persistent_ram_update(prz, s, c); 252 253 buffer->start += c; 254 if (buffer->size < prz->buffer_size) 255 buffer->size += c; 256 persistent_ram_update_header_ecc(prz); 257 258 return count; 259} 260 261size_t persistent_ram_old_size(struct persistent_ram_zone *prz) 262{ 263 return prz->old_log_size; 264} 265 266void *persistent_ram_old(struct persistent_ram_zone *prz) 267{ 268 return prz->old_log; 269} 270 271void persistent_ram_free_old(struct persistent_ram_zone *prz) 272{ 273 kfree(prz->old_log); 274 prz->old_log = NULL; 275 prz->old_log_size = 0; 276} 277 278static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size, 279 struct persistent_ram_zone *prz) 280{ 281 struct page **pages; 282 phys_addr_t page_start; 283 unsigned int page_count; 284 pgprot_t prot; 285 unsigned int i; 286 287 page_start = start - offset_in_page(start); 288 page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE); 289 290 prot = pgprot_noncached(PAGE_KERNEL); 291 292 pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL); 293 if (!pages) { 294 pr_err("%s: Failed to allocate array for %u pages\n", __func__, 295 page_count); 296 return -ENOMEM; 297 } 298 299 for (i = 0; i < page_count; i++) { 300 phys_addr_t addr = page_start + i * PAGE_SIZE; 301 pages[i] = pfn_to_page(addr >> PAGE_SHIFT); 302 } 303 prz->vaddr = vmap(pages, page_count, VM_MAP, prot); 304 kfree(pages); 305 if (!prz->vaddr) { 306 pr_err("%s: Failed to map %u pages\n", __func__, page_count); 307 return -ENOMEM; 308 } 309 310 prz->buffer = prz->vaddr + offset_in_page(start); 311 prz->buffer_size = size - sizeof(struct persistent_ram_buffer); 312 313 return 0; 314} 315 316static int __init persistent_ram_buffer_init(const char *name, 317 struct persistent_ram_zone *prz) 318{ 319 int i; 320 struct persistent_ram *ram; 321 struct persistent_ram_descriptor *desc; 322 phys_addr_t start; 323 324 list_for_each_entry(ram, &persistent_ram_list, node) { 325 start = ram->start; 326 for (i = 0; i < ram->num_descs; i++) { 327 desc = &ram->descs[i]; 328 if (!strcmp(desc->name, name)) 329 return persistent_ram_buffer_map(start, 330 desc->size, prz); 331 start += desc->size; 332 } 333 } 334 335 return -EINVAL; 336} 337 338static __init 339struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc) 340{ 341 struct persistent_ram_zone *prz; 342 int ret; 343 344 prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL); 345 if (!prz) { 346 pr_err("persistent_ram: failed to allocate persistent ram zone\n"); 347 return ERR_PTR(-ENOMEM); 348 } 349 350 INIT_LIST_HEAD(&prz->node); 351 352 ret = persistent_ram_buffer_init(dev_name(dev), prz); 353 if (ret) { 354 pr_err("persistent_ram: failed to initialize buffer\n"); 355 return ERR_PTR(ret); 356 } 357 358 prz->ecc = ecc; 359 ret = persistent_ram_init_ecc(prz, prz->buffer_size); 360 if (ret) 361 return ERR_PTR(ret); 362 363 if (prz->buffer->sig == PERSISTENT_RAM_SIG) { 364 if (prz->buffer->size > prz->buffer_size 365 || prz->buffer->start > prz->buffer->size) 366 pr_info("persistent_ram: found existing invalid buffer, size %d, start %d\n", 367 prz->buffer->size, prz->buffer->start); 368 else { 369 pr_info("persistent_ram: found existing buffer, size %d, start %d\n", 370 prz->buffer->size, prz->buffer->start); 371 persistent_ram_save_old(prz); 372 } 373 } else { 374 pr_info("persistent_ram: no valid data in buffer (sig = 0x%08x)\n", 375 prz->buffer->sig); 376 } 377 378 prz->buffer->sig = PERSISTENT_RAM_SIG; 379 prz->buffer->start = 0; 380 prz->buffer->size = 0; 381 382 return prz; 383} 384 385struct persistent_ram_zone * __init 386persistent_ram_init_ringbuffer(struct device *dev, bool ecc) 387{ 388 return __persistent_ram_init(dev, ecc); 389} 390 391int __init persistent_ram_early_init(struct persistent_ram *ram) 392{ 393 int ret; 394 395 ret = memblock_reserve(ram->start, ram->size); 396 if (ret) { 397 pr_err("Failed to reserve persistent memory from %08lx-%08lx\n", 398 (long)ram->start, (long)(ram->start + ram->size - 1)); 399 return ret; 400 } 401 402 list_add_tail(&ram->node, &persistent_ram_list); 403 404 pr_info("Initialized persistent memory from %08lx-%08lx\n", 405 (long)ram->start, (long)(ram->start + ram->size - 1)); 406 407 return 0; 408} 409