aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/mtdconcat.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/mtdconcat.c')
-rw-r--r--drivers/mtd/mtdconcat.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 3dbb1b38db66..792b547786b8 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.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/types.h> 15#include <linux/types.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/concat.h> 19#include <linux/mtd/concat.h>
@@ -684,6 +685,40 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
684} 685}
685 686
686/* 687/*
688 * try to support NOMMU mmaps on concatenated devices
689 * - we don't support subdev spanning as we can't guarantee it'll work
690 */
691static unsigned long concat_get_unmapped_area(struct mtd_info *mtd,
692 unsigned long len,
693 unsigned long offset,
694 unsigned long flags)
695{
696 struct mtd_concat *concat = CONCAT(mtd);
697 int i;
698
699 for (i = 0; i < concat->num_subdev; i++) {
700 struct mtd_info *subdev = concat->subdev[i];
701
702 if (offset >= subdev->size) {
703 offset -= subdev->size;
704 continue;
705 }
706
707 /* we've found the subdev over which the mapping will reside */
708 if (offset + len > subdev->size)
709 return (unsigned long) -EINVAL;
710
711 if (subdev->get_unmapped_area)
712 return subdev->get_unmapped_area(subdev, len, offset,
713 flags);
714
715 break;
716 }
717
718 return (unsigned long) -ENOSYS;
719}
720
721/*
687 * This function constructs a virtual MTD device by concatenating 722 * This function constructs a virtual MTD device by concatenating
688 * num_devs MTD devices. A pointer to the new device object is 723 * num_devs MTD devices. A pointer to the new device object is
689 * stored to *new_dev upon success. This function does _not_ 724 * stored to *new_dev upon success. This function does _not_
@@ -740,6 +775,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
740 775
741 concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks; 776 concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks;
742 777
778 concat->mtd.backing_dev_info = subdev[0]->backing_dev_info;
779
743 concat->subdev[0] = subdev[0]; 780 concat->subdev[0] = subdev[0];
744 781
745 for (i = 1; i < num_devs; i++) { 782 for (i = 1; i < num_devs; i++) {
@@ -766,6 +803,15 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
766 concat->mtd.flags |= 803 concat->mtd.flags |=
767 subdev[i]->flags & MTD_WRITEABLE; 804 subdev[i]->flags & MTD_WRITEABLE;
768 } 805 }
806
807 /* only permit direct mapping if the BDIs are all the same
808 * - copy-mapping is still permitted
809 */
810 if (concat->mtd.backing_dev_info !=
811 subdev[i]->backing_dev_info)
812 concat->mtd.backing_dev_info =
813 &default_backing_dev_info;
814
769 concat->mtd.size += subdev[i]->size; 815 concat->mtd.size += subdev[i]->size;
770 concat->mtd.ecc_stats.badblocks += 816 concat->mtd.ecc_stats.badblocks +=
771 subdev[i]->ecc_stats.badblocks; 817 subdev[i]->ecc_stats.badblocks;
@@ -796,6 +842,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
796 concat->mtd.unlock = concat_unlock; 842 concat->mtd.unlock = concat_unlock;
797 concat->mtd.suspend = concat_suspend; 843 concat->mtd.suspend = concat_suspend;
798 concat->mtd.resume = concat_resume; 844 concat->mtd.resume = concat_resume;
845 concat->mtd.get_unmapped_area = concat_get_unmapped_area;
799 846
800 /* 847 /*
801 * Combine the erase block size info of the subdevices: 848 * Combine the erase block size info of the subdevices: