linux/drivers/mtd/devices/phram.c
<<
>>
Prefs
   1/**
   2 * Copyright (c) ????           Jochen Schäuble <psionic@psionic.de>
   3 * Copyright (c) 2003-2004      Joern Engel <joern@wh.fh-wedel.de>
   4 *
   5 * Usage:
   6 *
   7 * one commend line parameter per device, each in the form:
   8 *   phram=<name>,<start>,<len>
   9 * <name> may be up to 63 characters.
  10 * <start> and <len> can be octal, decimal or hexadecimal.  If followed
  11 * by "ki", "Mi" or "Gi", the numbers will be interpreted as kilo, mega or
  12 * gigabytes.
  13 *
  14 * Example:
  15 *      phram=swap,64Mi,128Mi phram=test,900Mi,1Mi
  16 */
  17
  18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  19
  20#include <linux/io.h>
  21#include <linux/init.h>
  22#include <linux/kernel.h>
  23#include <linux/list.h>
  24#include <linux/module.h>
  25#include <linux/moduleparam.h>
  26#include <linux/slab.h>
  27#include <linux/mtd/mtd.h>
  28
  29struct phram_mtd_list {
  30        struct mtd_info mtd;
  31        struct list_head list;
  32};
  33
  34static LIST_HEAD(phram_list);
  35
  36static int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
  37{
  38        u_char *start = mtd->priv;
  39
  40        memset(start + instr->addr, 0xff, instr->len);
  41
  42        /*
  43         * This'll catch a few races. Free the thing before returning :)
  44         * I don't feel at all ashamed. This kind of thing is possible anyway
  45         * with flash, but unlikely.
  46         */
  47        instr->state = MTD_ERASE_DONE;
  48        mtd_erase_callback(instr);
  49        return 0;
  50}
  51
  52static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
  53                size_t *retlen, void **virt, resource_size_t *phys)
  54{
  55        *virt = mtd->priv + from;
  56        *retlen = len;
  57        return 0;
  58}
  59
  60static int phram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
  61{
  62        return 0;
  63}
  64
  65static int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
  66                size_t *retlen, u_char *buf)
  67{
  68        u_char *start = mtd->priv;
  69
  70        memcpy(buf, start + from, len);
  71        *retlen = len;
  72        return 0;
  73}
  74
  75static int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
  76                size_t *retlen, const u_char *buf)
  77{
  78        u_char *start = mtd->priv;
  79
  80        memcpy(start + to, buf, len);
  81        *retlen = len;
  82        return 0;
  83}
  84
  85static void unregister_devices(void)
  86{
  87        struct phram_mtd_list *this, *safe;
  88
  89        list_for_each_entry_safe(this, safe, &phram_list, list) {
  90                mtd_device_unregister(&this->mtd);
  91                iounmap(this->mtd.priv);
  92                kfree(this->mtd.name);
  93                kfree(this);
  94        }
  95}
  96
  97static int register_device(char *name, phys_addr_t start, size_t len)
  98{
  99        struct phram_mtd_list *new;
 100        int ret = -ENOMEM;
 101
 102        new = kzalloc(sizeof(*new), GFP_KERNEL);
 103        if (!new)
 104                goto out0;
 105
 106        ret = -EIO;
 107        new->mtd.priv = ioremap(start, len);
 108        if (!new->mtd.priv) {
 109                pr_err("ioremap failed\n");
 110                goto out1;
 111        }
 112
 113
 114        new->mtd.name = name;
 115        new->mtd.size = len;
 116        new->mtd.flags = MTD_CAP_RAM;
 117        new->mtd._erase = phram_erase;
 118        new->mtd._point = phram_point;
 119        new->mtd._unpoint = phram_unpoint;
 120        new->mtd._read = phram_read;
 121        new->mtd._write = phram_write;
 122        new->mtd.owner = THIS_MODULE;
 123        new->mtd.type = MTD_RAM;
 124        new->mtd.erasesize = PAGE_SIZE;
 125        new->mtd.writesize = 1;
 126
 127        ret = -EAGAIN;
 128        if (mtd_device_register(&new->mtd, NULL, 0)) {
 129                pr_err("Failed to register new device\n");
 130                goto out2;
 131        }
 132
 133        list_add_tail(&new->list, &phram_list);
 134        return 0;
 135
 136out2:
 137        iounmap(new->mtd.priv);
 138out1:
 139        kfree(new);
 140out0:
 141        return ret;
 142}
 143
 144static int parse_num64(uint64_t *num64, char *token)
 145{
 146        size_t len;
 147        int shift = 0;
 148        int ret;
 149
 150        len = strlen(token);
 151        /* By dwmw2 editorial decree, "ki", "Mi" or "Gi" are to be used. */
 152        if (len > 2) {
 153                if (token[len - 1] == 'i') {
 154                        switch (token[len - 2]) {
 155                        case 'G':
 156                                shift += 10;
 157                        case 'M':
 158                                shift += 10;
 159                        case 'k':
 160                                shift += 10;
 161                                token[len - 2] = 0;
 162                                break;
 163                        default:
 164                                return -EINVAL;
 165                        }
 166                }
 167        }
 168
 169        ret = kstrtou64(token, 0, num64);
 170        *num64 <<= shift;
 171
 172        return ret;
 173}
 174
 175static int parse_name(char **pname, const char *token)
 176{
 177        size_t len;
 178        char *name;
 179
 180        len = strlen(token) + 1;
 181        if (len > 64)
 182                return -ENOSPC;
 183
 184        name = kstrdup(token, GFP_KERNEL);
 185        if (!name)
 186                return -ENOMEM;
 187
 188        *pname = name;
 189        return 0;
 190}
 191
 192
 193static inline void kill_final_newline(char *str)
 194{
 195        char *newline = strrchr(str, '\n');
 196
 197        if (newline && !newline[1])
 198                *newline = 0;
 199}
 200
 201
 202#define parse_err(fmt, args...) do {    \
 203        pr_err(fmt , ## args);  \
 204        return 1;               \
 205} while (0)
 206
 207#ifndef MODULE
 208static int phram_init_called;
 209/*
 210 * This shall contain the module parameter if any. It is of the form:
 211 * - phram=<device>,<address>,<size> for module case
 212 * - phram.phram=<device>,<address>,<size> for built-in case
 213 * We leave 64 bytes for the device name, 20 for the address and 20 for the
 214 * size.
 215 * Example: phram.phram=rootfs,0xa0000000,512Mi
 216 */
 217static char phram_paramline[64 + 20 + 20];
 218#endif
 219
 220static int phram_setup(const char *val)
 221{
 222        char buf[64 + 20 + 20], *str = buf;
 223        char *token[3];
 224        char *name;
 225        uint64_t start;
 226        uint64_t len;
 227        int i, ret;
 228
 229        if (strnlen(val, sizeof(buf)) >= sizeof(buf))
 230                parse_err("parameter too long\n");
 231
 232        strcpy(str, val);
 233        kill_final_newline(str);
 234
 235        for (i = 0; i < 3; i++)
 236                token[i] = strsep(&str, ",");
 237
 238        if (str)
 239                parse_err("too many arguments\n");
 240
 241        if (!token[2])
 242                parse_err("not enough arguments\n");
 243
 244        ret = parse_name(&name, token[0]);
 245        if (ret)
 246                return ret;
 247
 248        ret = parse_num64(&start, token[1]);
 249        if (ret) {
 250                kfree(name);
 251                parse_err("illegal start address\n");
 252        }
 253
 254        ret = parse_num64(&len, token[2]);
 255        if (ret) {
 256                kfree(name);
 257                parse_err("illegal device length\n");
 258        }
 259
 260        ret = register_device(name, start, len);
 261        if (!ret)
 262                pr_info("%s device: %#llx at %#llx\n", name, len, start);
 263        else
 264                kfree(name);
 265
 266        return ret;
 267}
 268
 269static int phram_param_call(const char *val, struct kernel_param *kp)
 270{
 271#ifdef MODULE
 272        return phram_setup(val);
 273#else
 274        /*
 275         * If more parameters are later passed in via
 276         * /sys/module/phram/parameters/phram
 277         * and init_phram() has already been called,
 278         * we can parse the argument now.
 279         */
 280
 281        if (phram_init_called)
 282                return phram_setup(val);
 283
 284        /*
 285         * During early boot stage, we only save the parameters
 286         * here. We must parse them later: if the param passed
 287         * from kernel boot command line, phram_param_call() is
 288         * called so early that it is not possible to resolve
 289         * the device (even kmalloc() fails). Defer that work to
 290         * phram_setup().
 291         */
 292
 293        if (strlen(val) >= sizeof(phram_paramline))
 294                return -ENOSPC;
 295        strcpy(phram_paramline, val);
 296
 297        return 0;
 298#endif
 299}
 300
 301module_param_call(phram, phram_param_call, NULL, NULL, 000);
 302MODULE_PARM_DESC(phram, "Memory region to map. \"phram=<name>,<start>,<length>\"");
 303
 304
 305static int __init init_phram(void)
 306{
 307        int ret = 0;
 308
 309#ifndef MODULE
 310        if (phram_paramline[0])
 311                ret = phram_setup(phram_paramline);
 312        phram_init_called = 1;
 313#endif
 314
 315        return ret;
 316}
 317
 318static void __exit cleanup_phram(void)
 319{
 320        unregister_devices();
 321}
 322
 323module_init(init_phram);
 324module_exit(cleanup_phram);
 325
 326MODULE_LICENSE("GPL");
 327MODULE_AUTHOR("Joern Engel <joern@wh.fh-wedel.de>");
 328MODULE_DESCRIPTION("MTD driver for physical RAM");
 329