summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/devices/mtdram.c
diff options
context:
space:
mode:
authorNicolas Pitre <nicolas.pitre@linaro.org>2017-10-30 19:48:29 +0100
committerRichard Weinberger <richard@nod.at>2017-11-13 21:39:17 +0100
commit877b58ebc038f5e3f0afc5674fc35db75eaaa117 (patch)
tree4293283747fb813bb8d59b732badf000ee36fab1 /drivers/mtd/devices/mtdram.c
parentmtd: mtdswap: fix spelling mistake: 'TRESHOLD' -> 'THRESHOLD' (diff)
downloadlinux-877b58ebc038f5e3f0afc5674fc35db75eaaa117.tar.xz
linux-877b58ebc038f5e3f0afc5674fc35db75eaaa117.zip
mtd: mtdram: properly handle the phys argument in the point method
When the phys pointer is non null, the point method is expected to return the physical address for the pointed area. In the case of the mtdram driver we have to retrieve the physical address for the corresponding vmalloc area. However, there is no guarantee that the vmalloc area is made of physically contiguous pages. In that case we simply limit retlen to the actually contiguous pages. Signed-off-by: Nicolas Pitre <nico@linaro.org> Reviewed-by: Richard Weinberger <richard@nod.at> Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com> Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'drivers/mtd/devices/mtdram.c')
-rw-r--r--drivers/mtd/devices/mtdram.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c
index cbd8547d7aad..4418629e8dc0 100644
--- a/drivers/mtd/devices/mtdram.c
+++ b/drivers/mtd/devices/mtdram.c
@@ -13,6 +13,7 @@
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/vmalloc.h>
+#include <linux/mm.h>
#include <linux/init.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/mtdram.h>
@@ -69,6 +70,27 @@ static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
{
*virt = mtd->priv + from;
*retlen = len;
+
+ if (phys) {
+ /* limit retlen to the number of contiguous physical pages */
+ unsigned long page_ofs = offset_in_page(*virt);
+ void *addr = *virt - page_ofs;
+ unsigned long pfn1, pfn0 = vmalloc_to_pfn(addr);
+
+ *phys = __pfn_to_phys(pfn0) + page_ofs;
+ len += page_ofs;
+ while (len > PAGE_SIZE) {
+ len -= PAGE_SIZE;
+ addr += PAGE_SIZE;
+ pfn0++;
+ pfn1 = vmalloc_to_pfn(addr);
+ if (pfn1 != pfn0) {
+ *retlen = addr - *virt;
+ break;
+ }
+ }
+ }
+
return 0;
}