diff options
author | David Howells <dhowells@redhat.com> | 2009-02-12 05:40:00 -0500 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-03-24 05:00:19 -0400 |
commit | 402d326519c1a4859c527702383f4e60f606ef52 (patch) | |
tree | beb302d56d7671d372ae73f2664feed2a5b1226d /drivers/mtd | |
parent | 9ce969082e490d0a5a81862b364337c93dc3482a (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>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/Makefile | 2 | ||||
-rw-r--r-- | drivers/mtd/chips/map_ram.c | 17 | ||||
-rw-r--r-- | drivers/mtd/chips/map_rom.c | 17 | ||||
-rw-r--r-- | drivers/mtd/devices/mtdram.c | 14 | ||||
-rw-r--r-- | drivers/mtd/internal.h | 17 | ||||
-rw-r--r-- | drivers/mtd/mtdbdi.c | 43 | ||||
-rw-r--r-- | drivers/mtd/mtdchar.c | 63 | ||||
-rw-r--r-- | drivers/mtd/mtdcore.c | 15 | ||||
-rw-r--r-- | drivers/mtd/mtdpart.c | 15 |
9 files changed, 201 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. |
6 | obj-$(CONFIG_MTD) += mtd.o | 6 | obj-$(CONFIG_MTD) += mtd.o |
7 | mtd-y := mtdcore.o mtdsuper.o | 7 | mtd-y := mtdcore.o mtdsuper.o mtdbdi.o |
8 | mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o | 8 | mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o |
9 | 9 | ||
10 | obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o | 10 | obj-$(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 | |||
21 | static int mapram_erase (struct mtd_info *, struct erase_info *); | 21 | static int mapram_erase (struct mtd_info *, struct erase_info *); |
22 | static void mapram_nop (struct mtd_info *); | 22 | static void mapram_nop (struct mtd_info *); |
23 | static struct mtd_info *map_ram_probe(struct map_info *map); | 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 | static struct mtd_chip_driver mapram_chipdrv = { | 28 | static 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 | */ | ||
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 | } | ||
98 | |||
82 | static int mapram_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) | 99 | static 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 | |||
20 | static void maprom_nop (struct mtd_info *); | 20 | static void maprom_nop (struct mtd_info *); |
21 | static struct mtd_info *map_rom_probe(struct map_info *map); | 21 | static struct mtd_info *map_rom_probe(struct map_info *map); |
22 | static int maprom_erase (struct mtd_info *mtd, struct erase_info *info); | 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 | static struct mtd_chip_driver maprom_chipdrv = { | 26 | static 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 | */ | ||
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 | } | ||
72 | |||
56 | static int maprom_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) | 73 | static 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 | */ | ||
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 | static int ram_read(struct mtd_info *mtd, loff_t from, size_t len, | 81 | static 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 | */ | ||
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; | ||
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 | */ | ||
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 | }; | ||
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 | ||
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 | static const struct file_operations mtd_fops = { | 841 | static 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 | ||
794 | static int __init init_mtdchar(void) | 855 | static 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 | ||
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 | static int part_read_oob(struct mtd_info *mtd, loff_t from, | 99 | static 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) |