Skip to content

Commit

Permalink
NOMMU: Add support for direct mapping through mtdconcat if possible
Browse files Browse the repository at this point in the history
Add support for direct mapping through mtdconcat, if possible, by attaching the
samebacking_dev_info structure to the master.

It has some restrictions:

 (1) It won't permit direct mapping of concatenated devices that have differing
     BDIs.

 (2) It doesn't support maps that span the 'gap' between devices, although it
     possibly could if the devices spanned across return compatible
     (ie. contiguous) addresses from their get_unmapped_area() ops.

Signed-off-by: Gavin Lambert <gavinl@compacsort.com>
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>
  • Loading branch information
David Howells authored and David Woodhouse committed Mar 24, 2009
1 parent 402d326 commit 6e232cf
Showing 1 changed file with 47 additions and 0 deletions.
47 changes: 47 additions & 0 deletions drivers/mtd/mtdconcat.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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++) {
Expand All @@ -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;
Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit 6e232cf

Please sign in to comment.