]> git.baikalelectronics.ru Git - kernel.git/commitdiff
mtd: mtdram: properly handle the phys argument in the point method
authorNicolas Pitre <nicolas.pitre@linaro.org>
Mon, 30 Oct 2017 18:48:29 +0000 (14:48 -0400)
committerRichard Weinberger <richard@nod.at>
Mon, 13 Nov 2017 20:39:17 +0000 (21:39 +0100)
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>
drivers/mtd/devices/mtdram.c

index cbd8547d7aad8654b14ae20e8d00a69b2c861463..4418629e8dc01e8ec9369427171f255374cbb7ec 100644 (file)
@@ -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;
 }