linux/fs/pstore/ram_core.c
<<
>>
Prefs
   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#define pr_fmt(fmt) "persistent_ram: " fmt
  16
  17#include <linux/device.h>
  18#include <linux/err.h>
  19#include <linux/errno.h>
  20#include <linux/init.h>
  21#include <linux/io.h>
  22#include <linux/kernel.h>
  23#include <linux/list.h>
  24#include <linux/memblock.h>
  25#include <linux/pstore_ram.h>
  26#include <linux/rslib.h>
  27#include <linux/slab.h>
  28#include <linux/uaccess.h>
  29#include <linux/vmalloc.h>
  30#include <asm/page.h>
  31
  32struct persistent_ram_buffer {
  33        uint32_t    sig;
  34        atomic_t    start;
  35        atomic_t    size;
  36        uint8_t     data[0];
  37};
  38
  39#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
  40
  41static inline size_t buffer_size(struct persistent_ram_zone *prz)
  42{
  43        return atomic_read(&prz->buffer->size);
  44}
  45
  46static inline size_t buffer_start(struct persistent_ram_zone *prz)
  47{
  48        return atomic_read(&prz->buffer->start);
  49}
  50
  51static DEFINE_RAW_SPINLOCK(buffer_lock);
  52
  53/* increase and wrap the start pointer, returning the old value */
  54static size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
  55{
  56        int old;
  57        int new;
  58        unsigned long flags;
  59
  60        raw_spin_lock_irqsave(&buffer_lock, flags);
  61
  62        old = atomic_read(&prz->buffer->start);
  63        new = old + a;
  64        while (unlikely(new >= prz->buffer_size))
  65                new -= prz->buffer_size;
  66        atomic_set(&prz->buffer->start, new);
  67
  68        raw_spin_unlock_irqrestore(&buffer_lock, flags);
  69
  70        return old;
  71}
  72
  73/* increase the size counter until it hits the max size */
  74static void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
  75{
  76        size_t old;
  77        size_t new;
  78        unsigned long flags;
  79
  80        raw_spin_lock_irqsave(&buffer_lock, flags);
  81
  82        old = atomic_read(&prz->buffer->size);
  83        if (old == prz->buffer_size)
  84                goto exit;
  85
  86        new = old + a;
  87        if (new > prz->buffer_size)
  88                new = prz->buffer_size;
  89        atomic_set(&prz->buffer->size, new);
  90
  91exit:
  92        raw_spin_unlock_irqrestore(&buffer_lock, flags);
  93}
  94
  95static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
  96        uint8_t *data, size_t len, uint8_t *ecc)
  97{
  98        int i;
  99        uint16_t par[prz->ecc_info.ecc_size];
 100
 101        /* Initialize the parity buffer */
 102        memset(par, 0, sizeof(par));
 103        encode_rs8(prz->rs_decoder, data, len, par, 0);
 104        for (i = 0; i < prz->ecc_info.ecc_size; i++)
 105                ecc[i] = par[i];
 106}
 107
 108static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz,
 109        void *data, size_t len, uint8_t *ecc)
 110{
 111        int i;
 112        uint16_t par[prz->ecc_info.ecc_size];
 113
 114        for (i = 0; i < prz->ecc_info.ecc_size; i++)
 115                par[i] = ecc[i];
 116        return decode_rs8(prz->rs_decoder, data, par, len,
 117                                NULL, 0, NULL, 0, NULL);
 118}
 119
 120static void notrace persistent_ram_update_ecc(struct persistent_ram_zone *prz,
 121        unsigned int start, unsigned int count)
 122{
 123        struct persistent_ram_buffer *buffer = prz->buffer;
 124        uint8_t *buffer_end = buffer->data + prz->buffer_size;
 125        uint8_t *block;
 126        uint8_t *par;
 127        int ecc_block_size = prz->ecc_info.block_size;
 128        int ecc_size = prz->ecc_info.ecc_size;
 129        int size = ecc_block_size;
 130
 131        if (!ecc_size)
 132                return;
 133
 134        block = buffer->data + (start & ~(ecc_block_size - 1));
 135        par = prz->par_buffer + (start / ecc_block_size) * ecc_size;
 136
 137        do {
 138                if (block + ecc_block_size > buffer_end)
 139                        size = buffer_end - block;
 140                persistent_ram_encode_rs8(prz, block, size, par);
 141                block += ecc_block_size;
 142                par += ecc_size;
 143        } while (block < buffer->data + start + count);
 144}
 145
 146static void persistent_ram_update_header_ecc(struct persistent_ram_zone *prz)
 147{
 148        struct persistent_ram_buffer *buffer = prz->buffer;
 149
 150        if (!prz->ecc_info.ecc_size)
 151                return;
 152
 153        persistent_ram_encode_rs8(prz, (uint8_t *)buffer, sizeof(*buffer),
 154                                  prz->par_header);
 155}
 156
 157static void persistent_ram_ecc_old(struct persistent_ram_zone *prz)
 158{
 159        struct persistent_ram_buffer *buffer = prz->buffer;
 160        uint8_t *block;
 161        uint8_t *par;
 162
 163        if (!prz->ecc_info.ecc_size)
 164                return;
 165
 166        block = buffer->data;
 167        par = prz->par_buffer;
 168        while (block < buffer->data + buffer_size(prz)) {
 169                int numerr;
 170                int size = prz->ecc_info.block_size;
 171                if (block + size > buffer->data + prz->buffer_size)
 172                        size = buffer->data + prz->buffer_size - block;
 173                numerr = persistent_ram_decode_rs8(prz, block, size, par);
 174                if (numerr > 0) {
 175                        pr_devel("error in block %p, %d\n", block, numerr);
 176                        prz->corrected_bytes += numerr;
 177                } else if (numerr < 0) {
 178                        pr_devel("uncorrectable error in block %p\n", block);
 179                        prz->bad_blocks++;
 180                }
 181                block += prz->ecc_info.block_size;
 182                par += prz->ecc_info.ecc_size;
 183        }
 184}
 185
 186static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
 187                                   struct persistent_ram_ecc_info *ecc_info)
 188{
 189        int numerr;
 190        struct persistent_ram_buffer *buffer = prz->buffer;
 191        int ecc_blocks;
 192        size_t ecc_total;
 193
 194        if (!ecc_info || !ecc_info->ecc_size)
 195                return 0;
 196
 197        prz->ecc_info.block_size = ecc_info->block_size ?: 128;
 198        prz->ecc_info.ecc_size = ecc_info->ecc_size ?: 16;
 199        prz->ecc_info.symsize = ecc_info->symsize ?: 8;
 200        prz->ecc_info.poly = ecc_info->poly ?: 0x11d;
 201
 202        ecc_blocks = DIV_ROUND_UP(prz->buffer_size - prz->ecc_info.ecc_size,
 203                                  prz->ecc_info.block_size +
 204                                  prz->ecc_info.ecc_size);
 205        ecc_total = (ecc_blocks + 1) * prz->ecc_info.ecc_size;
 206        if (ecc_total >= prz->buffer_size) {
 207                pr_err("%s: invalid ecc_size %u (total %zu, buffer size %zu)\n",
 208                       __func__, prz->ecc_info.ecc_size,
 209                       ecc_total, prz->buffer_size);
 210                return -EINVAL;
 211        }
 212
 213        prz->buffer_size -= ecc_total;
 214        prz->par_buffer = buffer->data + prz->buffer_size;
 215        prz->par_header = prz->par_buffer +
 216                          ecc_blocks * prz->ecc_info.ecc_size;
 217
 218        /*
 219         * first consecutive root is 0
 220         * primitive element to generate roots = 1
 221         */
 222        prz->rs_decoder = init_rs(prz->ecc_info.symsize, prz->ecc_info.poly,
 223                                  0, 1, prz->ecc_info.ecc_size);
 224        if (prz->rs_decoder == NULL) {
 225                pr_info("init_rs failed\n");
 226                return -EINVAL;
 227        }
 228
 229        prz->corrected_bytes = 0;
 230        prz->bad_blocks = 0;
 231
 232        numerr = persistent_ram_decode_rs8(prz, buffer, sizeof(*buffer),
 233                                           prz->par_header);
 234        if (numerr > 0) {
 235                pr_info("error in header, %d\n", numerr);
 236                prz->corrected_bytes += numerr;
 237        } else if (numerr < 0) {
 238                pr_info("uncorrectable error in header\n");
 239                prz->bad_blocks++;
 240        }
 241
 242        return 0;
 243}
 244
 245ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
 246        char *str, size_t len)
 247{
 248        ssize_t ret;
 249
 250        if (!prz->ecc_info.ecc_size)
 251                return 0;
 252
 253        if (prz->corrected_bytes || prz->bad_blocks)
 254                ret = snprintf(str, len, ""
 255                        "\n%d Corrected bytes, %d unrecoverable blocks\n",
 256                        prz->corrected_bytes, prz->bad_blocks);
 257        else
 258                ret = snprintf(str, len, "\nNo errors detected\n");
 259
 260        return ret;
 261}
 262
 263static void notrace persistent_ram_update(struct persistent_ram_zone *prz,
 264        const void *s, unsigned int start, unsigned int count)
 265{
 266        struct persistent_ram_buffer *buffer = prz->buffer;
 267        memcpy_toio(buffer->data + start, s, count);
 268        persistent_ram_update_ecc(prz, start, count);
 269}
 270
 271static int notrace persistent_ram_update_user(struct persistent_ram_zone *prz,
 272        const void __user *s, unsigned int start, unsigned int count)
 273{
 274        struct persistent_ram_buffer *buffer = prz->buffer;
 275        int ret = unlikely(__copy_from_user(buffer->data + start, s, count)) ?
 276                -EFAULT : 0;
 277        persistent_ram_update_ecc(prz, start, count);
 278        return ret;
 279}
 280
 281void persistent_ram_save_old(struct persistent_ram_zone *prz)
 282{
 283        struct persistent_ram_buffer *buffer = prz->buffer;
 284        size_t size = buffer_size(prz);
 285        size_t start = buffer_start(prz);
 286
 287        if (!size)
 288                return;
 289
 290        if (!prz->old_log) {
 291                persistent_ram_ecc_old(prz);
 292                prz->old_log = kmalloc(size, GFP_KERNEL);
 293        }
 294        if (!prz->old_log) {
 295                pr_err("failed to allocate buffer\n");
 296                return;
 297        }
 298
 299        prz->old_log_size = size;
 300        memcpy_fromio(prz->old_log, &buffer->data[start], size - start);
 301        memcpy_fromio(prz->old_log + size - start, &buffer->data[0], start);
 302}
 303
 304int notrace persistent_ram_write(struct persistent_ram_zone *prz,
 305        const void *s, unsigned int count)
 306{
 307        int rem;
 308        int c = count;
 309        size_t start;
 310
 311        if (unlikely(c > prz->buffer_size)) {
 312                s += c - prz->buffer_size;
 313                c = prz->buffer_size;
 314        }
 315
 316        buffer_size_add(prz, c);
 317
 318        start = buffer_start_add(prz, c);
 319
 320        rem = prz->buffer_size - start;
 321        if (unlikely(rem < c)) {
 322                persistent_ram_update(prz, s, start, rem);
 323                s += rem;
 324                c -= rem;
 325                start = 0;
 326        }
 327        persistent_ram_update(prz, s, start, c);
 328
 329        persistent_ram_update_header_ecc(prz);
 330
 331        return count;
 332}
 333
 334int notrace persistent_ram_write_user(struct persistent_ram_zone *prz,
 335        const void __user *s, unsigned int count)
 336{
 337        int rem, ret = 0, c = count;
 338        size_t start;
 339
 340        if (unlikely(!access_ok(VERIFY_READ, s, count)))
 341                return -EFAULT;
 342        if (unlikely(c > prz->buffer_size)) {
 343                s += c - prz->buffer_size;
 344                c = prz->buffer_size;
 345        }
 346
 347        buffer_size_add(prz, c);
 348
 349        start = buffer_start_add(prz, c);
 350
 351        rem = prz->buffer_size - start;
 352        if (unlikely(rem < c)) {
 353                ret = persistent_ram_update_user(prz, s, start, rem);
 354                s += rem;
 355                c -= rem;
 356                start = 0;
 357        }
 358        if (likely(!ret))
 359                ret = persistent_ram_update_user(prz, s, start, c);
 360
 361        persistent_ram_update_header_ecc(prz);
 362
 363        return unlikely(ret) ? ret : count;
 364}
 365
 366size_t persistent_ram_old_size(struct persistent_ram_zone *prz)
 367{
 368        return prz->old_log_size;
 369}
 370
 371void *persistent_ram_old(struct persistent_ram_zone *prz)
 372{
 373        return prz->old_log;
 374}
 375
 376void persistent_ram_free_old(struct persistent_ram_zone *prz)
 377{
 378        kfree(prz->old_log);
 379        prz->old_log = NULL;
 380        prz->old_log_size = 0;
 381}
 382
 383void persistent_ram_zap(struct persistent_ram_zone *prz)
 384{
 385        atomic_set(&prz->buffer->start, 0);
 386        atomic_set(&prz->buffer->size, 0);
 387        persistent_ram_update_header_ecc(prz);
 388}
 389
 390static void *persistent_ram_vmap(phys_addr_t start, size_t size,
 391                unsigned int memtype)
 392{
 393        struct page **pages;
 394        phys_addr_t page_start;
 395        unsigned int page_count;
 396        pgprot_t prot;
 397        unsigned int i;
 398        void *vaddr;
 399
 400        page_start = start - offset_in_page(start);
 401        page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
 402
 403        if (memtype)
 404                prot = pgprot_noncached(PAGE_KERNEL);
 405        else
 406                prot = pgprot_writecombine(PAGE_KERNEL);
 407
 408        pages = kmalloc_array(page_count, sizeof(struct page *), GFP_KERNEL);
 409        if (!pages) {
 410                pr_err("%s: Failed to allocate array for %u pages\n",
 411                       __func__, page_count);
 412                return NULL;
 413        }
 414
 415        for (i = 0; i < page_count; i++) {
 416                phys_addr_t addr = page_start + i * PAGE_SIZE;
 417                pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
 418        }
 419        vaddr = vmap(pages, page_count, VM_MAP, prot);
 420        kfree(pages);
 421
 422        return vaddr;
 423}
 424
 425static void *persistent_ram_iomap(phys_addr_t start, size_t size,
 426                unsigned int memtype)
 427{
 428        void *va;
 429
 430        if (!request_mem_region(start, size, "persistent_ram")) {
 431                pr_err("request mem region (0x%llx@0x%llx) failed\n",
 432                        (unsigned long long)size, (unsigned long long)start);
 433                return NULL;
 434        }
 435
 436        if (memtype)
 437                va = ioremap(start, size);
 438        else
 439                va = ioremap_wc(start, size);
 440
 441        return va;
 442}
 443
 444static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
 445                struct persistent_ram_zone *prz, int memtype)
 446{
 447        prz->paddr = start;
 448        prz->size = size;
 449
 450        if (pfn_valid(start >> PAGE_SHIFT))
 451                prz->vaddr = persistent_ram_vmap(start, size, memtype);
 452        else
 453                prz->vaddr = persistent_ram_iomap(start, size, memtype);
 454
 455        if (!prz->vaddr) {
 456                pr_err("%s: Failed to map 0x%llx pages at 0x%llx\n", __func__,
 457                        (unsigned long long)size, (unsigned long long)start);
 458                return -ENOMEM;
 459        }
 460
 461        prz->buffer = prz->vaddr + offset_in_page(start);
 462        prz->buffer_size = size - sizeof(struct persistent_ram_buffer);
 463
 464        return 0;
 465}
 466
 467static int persistent_ram_post_init(struct persistent_ram_zone *prz, u32 sig,
 468                                    struct persistent_ram_ecc_info *ecc_info)
 469{
 470        int ret;
 471
 472        ret = persistent_ram_init_ecc(prz, ecc_info);
 473        if (ret)
 474                return ret;
 475
 476        sig ^= PERSISTENT_RAM_SIG;
 477
 478        if (prz->buffer->sig == sig) {
 479                if (buffer_size(prz) > prz->buffer_size ||
 480                    buffer_start(prz) > buffer_size(prz))
 481                        pr_info("found existing invalid buffer, size %zu, start %zu\n",
 482                                buffer_size(prz), buffer_start(prz));
 483                else {
 484                        pr_debug("found existing buffer, size %zu, start %zu\n",
 485                                 buffer_size(prz), buffer_start(prz));
 486                        persistent_ram_save_old(prz);
 487                        return 0;
 488                }
 489        } else {
 490                pr_debug("no valid data in buffer (sig = 0x%08x)\n",
 491                         prz->buffer->sig);
 492        }
 493
 494        prz->buffer->sig = sig;
 495        persistent_ram_zap(prz);
 496
 497        return 0;
 498}
 499
 500void persistent_ram_free(struct persistent_ram_zone *prz)
 501{
 502        if (!prz)
 503                return;
 504
 505        if (prz->vaddr) {
 506                if (pfn_valid(prz->paddr >> PAGE_SHIFT)) {
 507                        vunmap(prz->vaddr);
 508                } else {
 509                        iounmap(prz->vaddr);
 510                        release_mem_region(prz->paddr, prz->size);
 511                }
 512                prz->vaddr = NULL;
 513        }
 514        persistent_ram_free_old(prz);
 515        kfree(prz);
 516}
 517
 518struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
 519                        u32 sig, struct persistent_ram_ecc_info *ecc_info,
 520                        unsigned int memtype)
 521{
 522        struct persistent_ram_zone *prz;
 523        int ret = -ENOMEM;
 524
 525        prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
 526        if (!prz) {
 527                pr_err("failed to allocate persistent ram zone\n");
 528                goto err;
 529        }
 530
 531        ret = persistent_ram_buffer_map(start, size, prz, memtype);
 532        if (ret)
 533                goto err;
 534
 535        ret = persistent_ram_post_init(prz, sig, ecc_info);
 536        if (ret)
 537                goto err;
 538
 539        return prz;
 540err:
 541        persistent_ram_free(prz);
 542        return ERR_PTR(ret);
 543}
 544