Commit 402d326519c1a4859c527702383f4e60f606ef52

Authored by David Howells
Committed by David Woodhouse
1 parent 9ce969082e

NOMMU: Present backing device capabilities for MTD chardevs

Present backing device capabilities for MTD character device files to allow
NOMMU mmap to do direct mapping where possible.

Signed-off-by: David Howells <dhowells@redhat.com>
Tested-by: Bernd Schmidt <bernd.schmidt@analog.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>

Showing 10 changed files with 215 additions and 2 deletions Side-by-side Diff

drivers/mtd/Makefile
... ... @@ -4,7 +4,7 @@
4 4  
5 5 # Core functionality.
6 6 obj-$(CONFIG_MTD) += mtd.o
7   -mtd-y := mtdcore.o mtdsuper.o
  7 +mtd-y := mtdcore.o mtdsuper.o mtdbdi.o
8 8 mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
9 9  
10 10 obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
drivers/mtd/chips/map_ram.c
... ... @@ -21,6 +21,8 @@
21 21 static int mapram_erase (struct mtd_info *, struct erase_info *);
22 22 static void mapram_nop (struct mtd_info *);
23 23 static struct mtd_info *map_ram_probe(struct map_info *map);
  24 +static unsigned long mapram_unmapped_area(struct mtd_info *, unsigned long,
  25 + unsigned long, unsigned long);
24 26  
25 27  
26 28 static struct mtd_chip_driver mapram_chipdrv = {
... ... @@ -64,6 +66,7 @@
64 66 mtd->type = MTD_RAM;
65 67 mtd->size = map->size;
66 68 mtd->erase = mapram_erase;
  69 + mtd->get_unmapped_area = mapram_unmapped_area;
67 70 mtd->read = mapram_read;
68 71 mtd->write = mapram_write;
69 72 mtd->sync = mapram_nop;
... ... @@ -78,6 +81,20 @@
78 81 return mtd;
79 82 }
80 83  
  84 +
  85 +/*
  86 + * Allow NOMMU mmap() to directly map the device (if not NULL)
  87 + * - return the address to which the offset maps
  88 + * - return -ENOSYS to indicate refusal to do the mapping
  89 + */
  90 +static unsigned long mapram_unmapped_area(struct mtd_info *mtd,
  91 + unsigned long len,
  92 + unsigned long offset,
  93 + unsigned long flags)
  94 +{
  95 + struct map_info *map = mtd->priv;
  96 + return (unsigned long) map->virt + offset;
  97 +}
81 98  
82 99 static int mapram_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
83 100 {
drivers/mtd/chips/map_rom.c
... ... @@ -20,6 +20,8 @@
20 20 static void maprom_nop (struct mtd_info *);
21 21 static struct mtd_info *map_rom_probe(struct map_info *map);
22 22 static int maprom_erase (struct mtd_info *mtd, struct erase_info *info);
  23 +static unsigned long maprom_unmapped_area(struct mtd_info *, unsigned long,
  24 + unsigned long, unsigned long);
23 25  
24 26 static struct mtd_chip_driver maprom_chipdrv = {
25 27 .probe = map_rom_probe,
... ... @@ -40,6 +42,7 @@
40 42 mtd->name = map->name;
41 43 mtd->type = MTD_ROM;
42 44 mtd->size = map->size;
  45 + mtd->get_unmapped_area = maprom_unmapped_area;
43 46 mtd->read = maprom_read;
44 47 mtd->write = maprom_write;
45 48 mtd->sync = maprom_nop;
... ... @@ -52,6 +55,20 @@
52 55 return mtd;
53 56 }
54 57  
  58 +
  59 +/*
  60 + * Allow NOMMU mmap() to directly map the device (if not NULL)
  61 + * - return the address to which the offset maps
  62 + * - return -ENOSYS to indicate refusal to do the mapping
  63 + */
  64 +static unsigned long maprom_unmapped_area(struct mtd_info *mtd,
  65 + unsigned long len,
  66 + unsigned long offset,
  67 + unsigned long flags)
  68 +{
  69 + struct map_info *map = mtd->priv;
  70 + return (unsigned long) map->virt + offset;
  71 +}
55 72  
56 73 static int maprom_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
57 74 {
drivers/mtd/devices/mtdram.c
... ... @@ -65,6 +65,19 @@
65 65 {
66 66 }
67 67  
  68 +/*
  69 + * Allow NOMMU mmap() to directly map the device (if not NULL)
  70 + * - return the address to which the offset maps
  71 + * - return -ENOSYS to indicate refusal to do the mapping
  72 + */
  73 +static unsigned long ram_get_unmapped_area(struct mtd_info *mtd,
  74 + unsigned long len,
  75 + unsigned long offset,
  76 + unsigned long flags)
  77 +{
  78 + return (unsigned long) mtd->priv + offset;
  79 +}
  80 +
68 81 static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
69 82 size_t *retlen, u_char *buf)
70 83 {
... ... @@ -116,6 +129,7 @@
116 129 mtd->erase = ram_erase;
117 130 mtd->point = ram_point;
118 131 mtd->unpoint = ram_unpoint;
  132 + mtd->get_unmapped_area = ram_get_unmapped_area;
119 133 mtd->read = ram_read;
120 134 mtd->write = ram_write;
121 135  
drivers/mtd/internal.h
  1 +/* Internal MTD definitions
  2 + *
  3 + * Copyright ยฉ 2006 Red Hat, Inc. All Rights Reserved.
  4 + * Written by David Howells (dhowells@redhat.com)
  5 + *
  6 + * This program is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU General Public License
  8 + * as published by the Free Software Foundation; either version
  9 + * 2 of the License, or (at your option) any later version.
  10 + */
  11 +
  12 +/*
  13 + * mtdbdi.c
  14 + */
  15 +extern struct backing_dev_info mtd_bdi_unmappable;
  16 +extern struct backing_dev_info mtd_bdi_ro_mappable;
  17 +extern struct backing_dev_info mtd_bdi_rw_mappable;
drivers/mtd/mtdbdi.c
  1 +/* MTD backing device capabilities
  2 + *
  3 + * Copyright ยฉ 2006 Red Hat, Inc. All Rights Reserved.
  4 + * Written by David Howells (dhowells@redhat.com)
  5 + *
  6 + * This program is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU General Public License
  8 + * as published by the Free Software Foundation; either version
  9 + * 2 of the License, or (at your option) any later version.
  10 + */
  11 +
  12 +#include <linux/backing-dev.h>
  13 +#include <linux/mtd/mtd.h>
  14 +#include "internal.h"
  15 +
  16 +/*
  17 + * backing device capabilities for non-mappable devices (such as NAND flash)
  18 + * - permits private mappings, copies are taken of the data
  19 + */
  20 +struct backing_dev_info mtd_bdi_unmappable = {
  21 + .capabilities = BDI_CAP_MAP_COPY,
  22 +};
  23 +
  24 +/*
  25 + * backing device capabilities for R/O mappable devices (such as ROM)
  26 + * - permits private mappings, copies are taken of the data
  27 + * - permits non-writable shared mappings
  28 + */
  29 +struct backing_dev_info mtd_bdi_ro_mappable = {
  30 + .capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT |
  31 + BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP),
  32 +};
  33 +
  34 +/*
  35 + * backing device capabilities for writable mappable devices (such as RAM)
  36 + * - permits private mappings, copies are taken of the data
  37 + * - permits non-writable shared mappings
  38 + */
  39 +struct backing_dev_info mtd_bdi_rw_mappable = {
  40 + .capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT |
  41 + BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP |
  42 + BDI_CAP_WRITE_MAP),
  43 +};
drivers/mtd/mtdchar.c
... ... @@ -13,6 +13,7 @@
13 13 #include <linux/slab.h>
14 14 #include <linux/sched.h>
15 15 #include <linux/smp_lock.h>
  16 +#include <linux/backing-dev.h>
16 17  
17 18 #include <linux/mtd/mtd.h>
18 19 #include <linux/mtd/compatmac.h>
19 20  
... ... @@ -107,12 +108,15 @@
107 108 goto out;
108 109 }
109 110  
110   - if (MTD_ABSENT == mtd->type) {
  111 + if (mtd->type == MTD_ABSENT) {
111 112 put_mtd_device(mtd);
112 113 ret = -ENODEV;
113 114 goto out;
114 115 }
115 116  
  117 + if (mtd->backing_dev_info)
  118 + file->f_mapping->backing_dev_info = mtd->backing_dev_info;
  119 +
116 120 /* You can't open it RW if it's not a writeable device */
117 121 if ((file->f_mode & FMODE_WRITE) && !(mtd->flags & MTD_WRITEABLE)) {
118 122 put_mtd_device(mtd);
... ... @@ -781,6 +785,59 @@
781 785 return ret;
782 786 } /* memory_ioctl */
783 787  
  788 +/*
  789 + * try to determine where a shared mapping can be made
  790 + * - only supported for NOMMU at the moment (MMU can't doesn't copy private
  791 + * mappings)
  792 + */
  793 +#ifndef CONFIG_MMU
  794 +static unsigned long mtd_get_unmapped_area(struct file *file,
  795 + unsigned long addr,
  796 + unsigned long len,
  797 + unsigned long pgoff,
  798 + unsigned long flags)
  799 +{
  800 + struct mtd_file_info *mfi = file->private_data;
  801 + struct mtd_info *mtd = mfi->mtd;
  802 +
  803 + if (mtd->get_unmapped_area) {
  804 + unsigned long offset;
  805 +
  806 + if (addr != 0)
  807 + return (unsigned long) -EINVAL;
  808 +
  809 + if (len > mtd->size || pgoff >= (mtd->size >> PAGE_SHIFT))
  810 + return (unsigned long) -EINVAL;
  811 +
  812 + offset = pgoff << PAGE_SHIFT;
  813 + if (offset > mtd->size - len)
  814 + return (unsigned long) -EINVAL;
  815 +
  816 + return mtd->get_unmapped_area(mtd, len, offset, flags);
  817 + }
  818 +
  819 + /* can't map directly */
  820 + return (unsigned long) -ENOSYS;
  821 +}
  822 +#endif
  823 +
  824 +/*
  825 + * set up a mapping for shared memory segments
  826 + */
  827 +static int mtd_mmap(struct file *file, struct vm_area_struct *vma)
  828 +{
  829 +#ifdef CONFIG_MMU
  830 + struct mtd_file_info *mfi = file->private_data;
  831 + struct mtd_info *mtd = mfi->mtd;
  832 +
  833 + if (mtd->type == MTD_RAM || mtd->type == MTD_ROM)
  834 + return 0;
  835 + return -ENOSYS;
  836 +#else
  837 + return vma->vm_flags & VM_SHARED ? 0 : -ENOSYS;
  838 +#endif
  839 +}
  840 +
784 841 static const struct file_operations mtd_fops = {
785 842 .owner = THIS_MODULE,
786 843 .llseek = mtd_lseek,
... ... @@ -789,6 +846,10 @@
789 846 .ioctl = mtd_ioctl,
790 847 .open = mtd_open,
791 848 .release = mtd_close,
  849 + .mmap = mtd_mmap,
  850 +#ifndef CONFIG_MMU
  851 + .get_unmapped_area = mtd_get_unmapped_area,
  852 +#endif
792 853 };
793 854  
794 855 static int __init init_mtdchar(void)
drivers/mtd/mtdcore.c
... ... @@ -19,6 +19,7 @@
19 19 #include <linux/proc_fs.h>
20 20  
21 21 #include <linux/mtd/mtd.h>
  22 +#include "internal.h"
22 23  
23 24 #include "mtdcore.h"
24 25  
... ... @@ -45,6 +46,20 @@
45 46 int add_mtd_device(struct mtd_info *mtd)
46 47 {
47 48 int i;
  49 +
  50 + if (!mtd->backing_dev_info) {
  51 + switch (mtd->type) {
  52 + case MTD_RAM:
  53 + mtd->backing_dev_info = &mtd_bdi_rw_mappable;
  54 + break;
  55 + case MTD_ROM:
  56 + mtd->backing_dev_info = &mtd_bdi_ro_mappable;
  57 + break;
  58 + default:
  59 + mtd->backing_dev_info = &mtd_bdi_unmappable;
  60 + break;
  61 + }
  62 + }
48 63  
49 64 BUG_ON(mtd->writesize == 0);
50 65 mutex_lock(&mtd_table_mutex);
drivers/mtd/mtdpart.c
... ... @@ -84,6 +84,18 @@
84 84 part->master->unpoint(part->master, from + part->offset, len);
85 85 }
86 86  
  87 +static unsigned long part_get_unmapped_area(struct mtd_info *mtd,
  88 + unsigned long len,
  89 + unsigned long offset,
  90 + unsigned long flags)
  91 +{
  92 + struct mtd_part *part = PART(mtd);
  93 +
  94 + offset += part->offset;
  95 + return part->master->get_unmapped_area(part->master, len, offset,
  96 + flags);
  97 +}
  98 +
87 99 static int part_read_oob(struct mtd_info *mtd, loff_t from,
88 100 struct mtd_oob_ops *ops)
89 101 {
... ... @@ -342,6 +354,7 @@
342 354  
343 355 slave->mtd.name = part->name;
344 356 slave->mtd.owner = master->owner;
  357 + slave->mtd.backing_dev_info = master->backing_dev_info;
345 358  
346 359 slave->mtd.read = part_read;
347 360 slave->mtd.write = part_write;
... ... @@ -354,6 +367,8 @@
354 367 slave->mtd.unpoint = part_unpoint;
355 368 }
356 369  
  370 + if (master->get_unmapped_area)
  371 + slave->mtd.get_unmapped_area = part_get_unmapped_area;
357 372 if (master->read_oob)
358 373 slave->mtd.read_oob = part_read_oob;
359 374 if (master->write_oob)
include/linux/mtd/mtd.h
... ... @@ -162,6 +162,20 @@
162 162 /* We probably shouldn't allow XIP if the unpoint isn't a NULL */
163 163 void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
164 164  
  165 + /* Allow NOMMU mmap() to directly map the device (if not NULL)
  166 + * - return the address to which the offset maps
  167 + * - return -ENOSYS to indicate refusal to do the mapping
  168 + */
  169 + unsigned long (*get_unmapped_area) (struct mtd_info *mtd,
  170 + unsigned long len,
  171 + unsigned long offset,
  172 + unsigned long flags);
  173 +
  174 + /* Backing device capabilities for this device
  175 + * - provides mmap capabilities
  176 + */
  177 + struct backing_dev_info *backing_dev_info;
  178 +
165 179  
166 180 int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
167 181 int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);