aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2009-02-12 05:40:00 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-03-24 05:00:19 -0400
commit402d326519c1a4859c527702383f4e60f606ef52 (patch)
treebeb302d56d7671d372ae73f2664feed2a5b1226d
parent9ce969082e490d0a5a81862b364337c93dc3482a (diff)
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>
-rw-r--r--drivers/mtd/Makefile2
-rw-r--r--drivers/mtd/chips/map_ram.c17
-rw-r--r--drivers/mtd/chips/map_rom.c17
-rw-r--r--drivers/mtd/devices/mtdram.c14
-rw-r--r--drivers/mtd/internal.h17
-rw-r--r--drivers/mtd/mtdbdi.c43
-rw-r--r--drivers/mtd/mtdchar.c63
-rw-r--r--drivers/mtd/mtdcore.c15
-rw-r--r--drivers/mtd/mtdpart.c15
-rw-r--r--include/linux/mtd/mtd.h14
10 files changed, 215 insertions, 2 deletions
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 4521b1ecce45..82d1e4de475b 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -4,7 +4,7 @@
4 4
5# Core functionality. 5# Core functionality.
6obj-$(CONFIG_MTD) += mtd.o 6obj-$(CONFIG_MTD) += mtd.o
7mtd-y := mtdcore.o mtdsuper.o 7mtd-y := mtdcore.o mtdsuper.o mtdbdi.o
8mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o 8mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
9 9
10obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o 10obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
diff --git a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c
index 072dd8abf33a..6bdc50c727e7 100644
--- a/drivers/mtd/chips/map_ram.c
+++ b/drivers/mtd/chips/map_ram.c
@@ -21,6 +21,8 @@ static int mapram_write (struct mtd_info *, loff_t, size_t, size_t *, const u_ch
21static int mapram_erase (struct mtd_info *, struct erase_info *); 21static int mapram_erase (struct mtd_info *, struct erase_info *);
22static void mapram_nop (struct mtd_info *); 22static void mapram_nop (struct mtd_info *);
23static struct mtd_info *map_ram_probe(struct map_info *map); 23static struct mtd_info *map_ram_probe(struct map_info *map);
24static unsigned long mapram_unmapped_area(struct mtd_info *, unsigned long,
25 unsigned long, unsigned long);
24 26
25 27
26static struct mtd_chip_driver mapram_chipdrv = { 28static struct mtd_chip_driver mapram_chipdrv = {
@@ -64,6 +66,7 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
64 mtd->type = MTD_RAM; 66 mtd->type = MTD_RAM;
65 mtd->size = map->size; 67 mtd->size = map->size;
66 mtd->erase = mapram_erase; 68 mtd->erase = mapram_erase;
69 mtd->get_unmapped_area = mapram_unmapped_area;
67 mtd->read = mapram_read; 70 mtd->read = mapram_read;
68 mtd->write = mapram_write; 71 mtd->write = mapram_write;
69 mtd->sync = mapram_nop; 72 mtd->sync = mapram_nop;
@@ -79,6 +82,20 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
79} 82}
80 83
81 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 */
90static 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}
98
82static int mapram_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) 99static int mapram_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
83{ 100{
84 struct map_info *map = mtd->priv; 101 struct map_info *map = mtd->priv;
diff --git a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c
index c76d6e5f47ee..076090a67b90 100644
--- a/drivers/mtd/chips/map_rom.c
+++ b/drivers/mtd/chips/map_rom.c
@@ -20,6 +20,8 @@ static int maprom_write (struct mtd_info *, loff_t, size_t, size_t *, const u_ch
20static void maprom_nop (struct mtd_info *); 20static void maprom_nop (struct mtd_info *);
21static struct mtd_info *map_rom_probe(struct map_info *map); 21static struct mtd_info *map_rom_probe(struct map_info *map);
22static int maprom_erase (struct mtd_info *mtd, struct erase_info *info); 22static int maprom_erase (struct mtd_info *mtd, struct erase_info *info);
23static unsigned long maprom_unmapped_area(struct mtd_info *, unsigned long,
24 unsigned long, unsigned long);
23 25
24static struct mtd_chip_driver maprom_chipdrv = { 26static struct mtd_chip_driver maprom_chipdrv = {
25 .probe = map_rom_probe, 27 .probe = map_rom_probe,
@@ -40,6 +42,7 @@ static struct mtd_info *map_rom_probe(struct map_info *map)
40 mtd->name = map->name; 42 mtd->name = map->name;
41 mtd->type = MTD_ROM; 43 mtd->type = MTD_ROM;
42 mtd->size = map->size; 44 mtd->size = map->size;
45 mtd->get_unmapped_area = maprom_unmapped_area;
43 mtd->read = maprom_read; 46 mtd->read = maprom_read;
44 mtd->write = maprom_write; 47 mtd->write = maprom_write;
45 mtd->sync = maprom_nop; 48 mtd->sync = maprom_nop;
@@ -53,6 +56,20 @@ static struct mtd_info *map_rom_probe(struct map_info *map)
53} 56}
54 57
55 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 */
64static 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}
72
56static int maprom_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) 73static int maprom_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
57{ 74{
58 struct map_info *map = mtd->priv; 75 struct map_info *map = mtd->priv;
diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c
index 3aaca88847d3..fce5ff7589aa 100644
--- a/drivers/mtd/devices/mtdram.c
+++ b/drivers/mtd/devices/mtdram.c
@@ -65,6 +65,19 @@ static void ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
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 */
73static 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
68static int ram_read(struct mtd_info *mtd, loff_t from, size_t len, 81static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
69 size_t *retlen, u_char *buf) 82 size_t *retlen, u_char *buf)
70{ 83{
@@ -116,6 +129,7 @@ int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
116 mtd->erase = ram_erase; 129 mtd->erase = ram_erase;
117 mtd->point = ram_point; 130 mtd->point = ram_point;
118 mtd->unpoint = ram_unpoint; 131 mtd->unpoint = ram_unpoint;
132 mtd->get_unmapped_area = ram_get_unmapped_area;
119 mtd->read = ram_read; 133 mtd->read = ram_read;
120 mtd->write = ram_write; 134 mtd->write = ram_write;
121 135
diff --git a/drivers/mtd/internal.h b/drivers/mtd/internal.h
new file mode 100644
index 000000000000..c658fe7216b5
--- /dev/null
+++ b/drivers/mtd/internal.h
@@ -0,0 +1,17 @@
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 */
15extern struct backing_dev_info mtd_bdi_unmappable;
16extern struct backing_dev_info mtd_bdi_ro_mappable;
17extern struct backing_dev_info mtd_bdi_rw_mappable;
diff --git a/drivers/mtd/mtdbdi.c b/drivers/mtd/mtdbdi.c
new file mode 100644
index 000000000000..5ca5aed0b225
--- /dev/null
+++ b/drivers/mtd/mtdbdi.c
@@ -0,0 +1,43 @@
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 */
20struct 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 */
29struct 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 */
39struct 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};
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 2c8a16f49ca2..f478f1fc3949 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -13,6 +13,7 @@
13#include <linux/slab.h> 13#include <linux/slab.h>
14#include <linux/sched.h> 14#include <linux/sched.h>
15#include <linux/smp_lock.h> 15#include <linux/smp_lock.h>
16#include <linux/backing-dev.h>
16 17
17#include <linux/mtd/mtd.h> 18#include <linux/mtd/mtd.h>
18#include <linux/mtd/compatmac.h> 19#include <linux/mtd/compatmac.h>
@@ -107,12 +108,15 @@ static int mtd_open(struct inode *inode, struct file *file)
107 goto out; 108 goto out;
108 } 109 }
109 110
110 if (MTD_ABSENT == mtd->type) { 111 if (mtd->type == MTD_ABSENT) {
111 put_mtd_device(mtd); 112 put_mtd_device(mtd);
112 ret = -ENODEV; 113 ret = -ENODEV;
113 goto out; 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 /* You can't open it RW if it's not a writeable device */ 120 /* You can't open it RW if it's not a writeable device */
117 if ((file->f_mode & FMODE_WRITE) && !(mtd->flags & MTD_WRITEABLE)) { 121 if ((file->f_mode & FMODE_WRITE) && !(mtd->flags & MTD_WRITEABLE)) {
118 put_mtd_device(mtd); 122 put_mtd_device(mtd);
@@ -781,6 +785,59 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
781 return ret; 785 return ret;
782} /* memory_ioctl */ 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
794static 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 */
827static 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
784static const struct file_operations mtd_fops = { 841static const struct file_operations mtd_fops = {
785 .owner = THIS_MODULE, 842 .owner = THIS_MODULE,
786 .llseek = mtd_lseek, 843 .llseek = mtd_lseek,
@@ -789,6 +846,10 @@ static const struct file_operations mtd_fops = {
789 .ioctl = mtd_ioctl, 846 .ioctl = mtd_ioctl,
790 .open = mtd_open, 847 .open = mtd_open,
791 .release = mtd_close, 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
794static int __init init_mtdchar(void) 855static int __init init_mtdchar(void)
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 76fe0a1e7a5e..65a7f3703881 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -19,6 +19,7 @@
19#include <linux/proc_fs.h> 19#include <linux/proc_fs.h>
20 20
21#include <linux/mtd/mtd.h> 21#include <linux/mtd/mtd.h>
22#include "internal.h"
22 23
23#include "mtdcore.h" 24#include "mtdcore.h"
24 25
@@ -46,6 +47,20 @@ int add_mtd_device(struct mtd_info *mtd)
46{ 47{
47 int i; 48 int i;
48 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 }
63
49 BUG_ON(mtd->writesize == 0); 64 BUG_ON(mtd->writesize == 0);
50 mutex_lock(&mtd_table_mutex); 65 mutex_lock(&mtd_table_mutex);
51 66
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 144e6b613a77..06d5b9d8853a 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -84,6 +84,18 @@ static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
84 part->master->unpoint(part->master, from + part->offset, len); 84 part->master->unpoint(part->master, from + part->offset, len);
85} 85}
86 86
87static 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
87static int part_read_oob(struct mtd_info *mtd, loff_t from, 99static int part_read_oob(struct mtd_info *mtd, loff_t from,
88 struct mtd_oob_ops *ops) 100 struct mtd_oob_ops *ops)
89{ 101{
@@ -342,6 +354,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
342 354
343 slave->mtd.name = part->name; 355 slave->mtd.name = part->name;
344 slave->mtd.owner = master->owner; 356 slave->mtd.owner = master->owner;
357 slave->mtd.backing_dev_info = master->backing_dev_info;
345 358
346 slave->mtd.read = part_read; 359 slave->mtd.read = part_read;
347 slave->mtd.write = part_write; 360 slave->mtd.write = part_write;
@@ -354,6 +367,8 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
354 slave->mtd.unpoint = part_unpoint; 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 if (master->read_oob) 372 if (master->read_oob)
358 slave->mtd.read_oob = part_read_oob; 373 slave->mtd.read_oob = part_read_oob;
359 if (master->write_oob) 374 if (master->write_oob)
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 3aa5d77c2cdb..0c079fd307a5 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -162,6 +162,20 @@ struct mtd_info {
162 /* We probably shouldn't allow XIP if the unpoint isn't a NULL */ 162 /* We probably shouldn't allow XIP if the unpoint isn't a NULL */
163 void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len); 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 int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); 180 int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
167 int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); 181 int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);