dmc: fix panic problem when show memory in highmem [1/1]
authorTao Zeng <tao.zeng@amlogic.com>
Thu, 27 Dec 2018 06:31:29 +0000 (14:31 +0800)
committerTao Zeng <tao.zeng@amlogic.com>
Thu, 27 Dec 2018 07:04:22 +0000 (15:04 +0800)
PD#SWPL-2767

Problem:
If DMC violation address is in highmem, then it will panic
when show memory using page_address();

Solution:
map violation address for highmem

Verify:
p212

Change-Id: Ib6213eaab42b129c8c0a381511a0b3376b0d3e66
Signed-off-by: Tao Zeng <tao.zeng@amlogic.com>
drivers/amlogic/ddr_tool/dmc_g12.c
drivers/amlogic/ddr_tool/dmc_gx.c

index 9afc61e..8e35e21 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/irqreturn.h>
 #include <linux/module.h>
 #include <linux/mm.h>
+#include <linux/highmem.h>
 
 #include <linux/cpu.h>
 #include <linux/smp.h>
@@ -76,12 +77,31 @@ static size_t g12_dmc_dump_reg(char *buf)
        return sz;
 }
 
+static void show_violation_mem(unsigned long addr)
+{
+       struct page *page;
+       unsigned long *p, *q;
+
+       if (!pfn_valid(__phys_to_pfn(addr)))
+               return;
+
+       page = phys_to_page(addr);
+       p = kmap_atomic(page);
+       if (!p)
+               return;
+
+       q = p + ((addr & (PAGE_SIZE - 1)) / sizeof(*p));
+       pr_info(DMC_TAG "[%08lx]:%016lx, f:%8lx, m:%p, a:%ps\n",
+               (unsigned long)q, *q, page->flags & 0xffffffff,
+               page->mapping,
+               (void *)get_page_trace(page));
+       kunmap_atomic(p);
+}
+
 static void check_violation(struct dmc_monitor *mon)
 {
        int i, port, subport;
        unsigned long addr, status;
-       struct page *page;
-       unsigned long *p;
        char id_str[4];
        char off1 = 21, off2 = 10;
 
@@ -112,14 +132,7 @@ static void check_violation(struct dmc_monitor *mon)
                pr_info(DMC_TAG", addr:%08lx, s:%08lx, ID:%s, sub:%s, c:%ld\n",
                        addr, status, to_ports(port),
                        to_sub_ports(port, subport, id_str), mon->same_page);
-               if (pfn_valid(__phys_to_pfn(addr))) {
-                       page = phys_to_page(addr);
-                       p = (page_address(page) + (addr & (PAGE_SIZE - 1)));
-                       pr_info(DMC_TAG" [%08lx]:%016lx, f:%8lx, m:%p, a:%pf\n",
-                               addr, *p, page->flags & 0xffffffff,
-                               page->mapping,
-                               (void *)get_page_trace(page));
-               }
+               show_violation_mem(addr);
                if (!port) /* dump stack for CPU write */
                        dump_stack();
 
index e0b1203..7871970 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/irqreturn.h>
 #include <linux/module.h>
 #include <linux/mm.h>
+#include <linux/highmem.h>
 
 #include <linux/cpu.h>
 #include <linux/smp.h>
@@ -80,12 +81,31 @@ static size_t gx_dmc_dump_reg(char *buf)
        return sz;
 }
 
+static void show_violation_mem(unsigned long addr)
+{
+       struct page *page;
+       unsigned long *p, *q;
+
+       if (!pfn_valid(__phys_to_pfn(addr)))
+               return;
+
+       page = phys_to_page(addr);
+       p = kmap_atomic(page);
+       if (!p)
+               return;
+
+       q = p + ((addr & (PAGE_SIZE - 1)) / sizeof(*p));
+       pr_info(DMC_TAG "[%08lx]:%016lx, f:%8lx, m:%p, a:%ps\n",
+               (unsigned long)q, *q, page->flags & 0xffffffff,
+               page->mapping,
+               (void *)get_page_trace(page));
+       kunmap_atomic(p);
+}
+
 static void check_violation(struct dmc_monitor *mon)
 {
        int i, port, subport;
        unsigned long addr, status;
-       struct page *page;
-       unsigned long *p;
        char id_str[4];
 
        for (i = 1; i < 8; i += 2) {
@@ -109,14 +129,7 @@ static void check_violation(struct dmc_monitor *mon)
                pr_info(DMC_TAG", addr:%08lx, s:%08lx, ID:%s, sub:%s, c:%ld\n",
                        addr, status, to_ports(port),
                        to_sub_ports(port, subport, id_str), mon->same_page);
-               if (pfn_valid(__phys_to_pfn(addr))) {
-                       page = phys_to_page(addr);
-                       p = (page_address(page) + (addr & (PAGE_SIZE - 1)));
-                       pr_info(DMC_TAG" [%08lx]:%016lx, f:%8lx, m:%p, a:%pf\n",
-                               addr, *p, page->flags & 0xffffffff,
-                               page->mapping,
-                               (void *)get_page_trace(page));
-               }
+               show_violation_mem(addr);
                if (!port) /* dump stack for CPU write */
                        dump_stack();