|
@@ -13,6 +13,7 @@
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/sched.h>
|
|
|
#include <linux/types.h>
|
|
|
+#include <linux/backing-dev.h>
|
|
|
|
|
|
#include <linux/mtd/mtd.h>
|
|
|
#include <linux/mtd/concat.h>
|
|
@@ -683,6 +684,40 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * try to support NOMMU mmaps on concatenated devices
|
|
|
+ * - we don't support subdev spanning as we can't guarantee it'll work
|
|
|
+ */
|
|
|
+static unsigned long concat_get_unmapped_area(struct mtd_info *mtd,
|
|
|
+ unsigned long len,
|
|
|
+ unsigned long offset,
|
|
|
+ unsigned long flags)
|
|
|
+{
|
|
|
+ struct mtd_concat *concat = CONCAT(mtd);
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < concat->num_subdev; i++) {
|
|
|
+ struct mtd_info *subdev = concat->subdev[i];
|
|
|
+
|
|
|
+ if (offset >= subdev->size) {
|
|
|
+ offset -= subdev->size;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* we've found the subdev over which the mapping will reside */
|
|
|
+ if (offset + len > subdev->size)
|
|
|
+ return (unsigned long) -EINVAL;
|
|
|
+
|
|
|
+ if (subdev->get_unmapped_area)
|
|
|
+ return subdev->get_unmapped_area(subdev, len, offset,
|
|
|
+ flags);
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return (unsigned long) -ENOSYS;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* This function constructs a virtual MTD device by concatenating
|
|
|
* num_devs MTD devices. A pointer to the new device object is
|
|
@@ -740,6 +775,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
|
|
|
|
|
concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks;
|
|
|
|
|
|
+ concat->mtd.backing_dev_info = subdev[0]->backing_dev_info;
|
|
|
+
|
|
|
concat->subdev[0] = subdev[0];
|
|
|
|
|
|
for (i = 1; i < num_devs; i++) {
|
|
@@ -766,6 +803,15 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
|
|
concat->mtd.flags |=
|
|
|
subdev[i]->flags & MTD_WRITEABLE;
|
|
|
}
|
|
|
+
|
|
|
+ /* only permit direct mapping if the BDIs are all the same
|
|
|
+ * - copy-mapping is still permitted
|
|
|
+ */
|
|
|
+ if (concat->mtd.backing_dev_info !=
|
|
|
+ subdev[i]->backing_dev_info)
|
|
|
+ concat->mtd.backing_dev_info =
|
|
|
+ &default_backing_dev_info;
|
|
|
+
|
|
|
concat->mtd.size += subdev[i]->size;
|
|
|
concat->mtd.ecc_stats.badblocks +=
|
|
|
subdev[i]->ecc_stats.badblocks;
|
|
@@ -796,6 +842,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
|
|
concat->mtd.unlock = concat_unlock;
|
|
|
concat->mtd.suspend = concat_suspend;
|
|
|
concat->mtd.resume = concat_resume;
|
|
|
+ concat->mtd.get_unmapped_area = concat_get_unmapped_area;
|
|
|
|
|
|
/*
|
|
|
* Combine the erase block size info of the subdevices:
|