From: Rafał Miłecki <rafal@xxxxxxxxxx> This workarounds what seems to be a hardware bug present in some early Broadcom MIPS CPUs. For some reason using kmap_coherent() for copying a memory causes a "Data bus error" or SoC reboot. Example: [ 23.530761] Data bus error, epc == 8032f6e8, ra == 8001127c [ 23.536422] Oops[#1]: [ 23.538747] CPU: 0 PID: 761 Comm: pidof Not tainted 4.14.96 #0 [ 23.544647] task: 818e3700 task.stack: 81bd2000 [ 23.549216] $ 0 : 00000000 10008c00 81bd3e27 00000000 [ 23.554530] $ 4 : 81bd3e27 fffd2fb2 00000001 818e3700 [ 23.559845] $ 8 : 00000002 00000003 00000001 ffffff80 [ 23.565151] $12 : 7fe8a708 00000000 00000000 77fa92c0 [ 23.570466] $16 : 8100a920 803f9060 7fd22fb2 81bd3e27 [ 23.575781] $20 : 00000001 80548fb2 819d8700 00000000 [ 23.581097] $24 : 00000fa3 80018ec0 [ 23.586403] $28 : 81bd2000 81bd3d58 80000000 8001127c [ 23.591720] Hi : 00000000 [ 23.594634] Lo : 00000000 [ 23.597590] epc : 8032f6e8 __copy_user+0x1c4/0x2bc [ 23.602633] ra : 8001127c copy_from_user_page+0xa8/0x130 [ 23.608257] Status: 10008c03 KERNEL EXL IE [ 23.612511] Cause : 0080001c (ExcCode 07) [ 23.616560] PrId : 00029006 (Broadcom BMIPS3300) [ 23.621301] Modules linked in: pppoe ppp_async b43 pppox ppp_generic nf_conntrack_ipv6 mac80211 iptable_nat ipt_REJECT ipt_MASQUERADE cfg80211 xt_time xt_tcpudp xt_state xt_nat xt_multiport xt_mark xt_mac xt_limit xt_conntrack xt_comment xt_TCPMSS xt_REDIRECT xt_LOG d [ 23.688445] Process pidof (pid: 761, threadinfo=81bd2000, task=818e3700, tls=77faada8) [ 23.696417] Stack : 819d8738 0000a806 7fd22fb3 7fd22fb2 81bd3e27 00000001 7fd22fb2 81bd3e27 [ 23.704907] 00000001 81bd3e27 819d8738 800a8f84 00000000 00000000 80416598 00000000 [ 23.713389] 80548fb2 00000001 81bd3db0 00000000 00000000 80470000 81a25f60 8100a920 [ 23.721873] 7fd22fb3 7fd22fb3 819d8700 000003ff 7fe8a7e8 81bd3f08 81b06000 0000000c [ 23.730356] 7fd22fa7 800a9044 00000000 80088d2c 80d69010 00000002 00000001 00008000 [ 23.738838] ... [ 23.741330] Call Trace: [ 23.743833] [<8032f6e8>] __copy_user+0x1c4/0x2bc [ 23.748536] [<8001127c>] copy_from_user_page+0xa8/0x130 [ 23.753870] [<800a8f84>] __access_remote_vm+0x1a0/0x1a8 [ 23.759176] [<800a9044>] access_remote_vm+0x28/0x34 [ 23.764142] [<8010b60c>] proc_pid_cmdline_read+0x190/0x410 [ 23.769714] [<800c008c>] __vfs_read+0x28/0x150 [ 23.774222] [<800c0254>] vfs_read+0xa0/0x148 [ 23.778559] [<800c0774>] SyS_read+0x58/0xc0 [ 23.782809] [<8000eb58>] syscall_common+0x34/0x58 [ 23.787570] Code: 00000000 10c0000d 00000000 <80a80000> 24c6ffff 10c00009 a0880000 80a80001 24c6ffff [ 23.797495] [ 23.799272] ---[ end trace 3f76d2c13fe73eb8 ]--- Using ptrace (which involves copy_to_user_page()) results in immediate reboot without printing anything over a serial console. This problem has been noticed on: 1) ASUS WL-500g Premium SoC: BCM4704, CPU: 00029006 (Broadcom BMIPS3300) 2) ASUS WL-500gP V2 SoC: BCM5354, CPU: 00029029 (Broadcom BMIPS3300) 3) Linksys WRT300N V1 SoC: BCM4704, CPU: 00029006 (Broadcom BMIPS3300) It doesn't exist on: 1) Linksys WRT54G v3.1 SoC: BCM4712, CPU: 00029007 (Broadcom BMIPS3300) Signed-off-by: Rafał Miłecki <rafal@xxxxxxxxxx> Link: https://dev.archive.openwrt.org/ticket/1485 --- arch/mips/include/asm/cpu-features.h | 3 +++ .../mips/include/asm/mach-bcm47xx/cpu-feature-overrides.h | 8 ++++++++ arch/mips/mm/init.c | 6 +++--- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index 6998a9796499..351f649eacc3 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -246,6 +246,9 @@ #ifndef cpu_has_local_ebase #define cpu_has_local_ebase 1 #endif +#ifndef cpu_has_kmap_coherent +#define cpu_has_kmap_coherent 1 +#endif /* * I-Cache snoops remote store. This only matters on SMP. Some multiprocessors diff --git a/arch/mips/include/asm/mach-bcm47xx/cpu-feature-overrides.h b/arch/mips/include/asm/mach-bcm47xx/cpu-feature-overrides.h index b23ff47ea475..553505dea60b 100644 --- a/arch/mips/include/asm/mach-bcm47xx/cpu-feature-overrides.h +++ b/arch/mips/include/asm/mach-bcm47xx/cpu-feature-overrides.h @@ -80,4 +80,12 @@ #define cpu_scache_line_size() 0 #define cpu_has_vz 0 +/* + * Workaround for the bugged BCM4704 & BCM5354: + * copy_from_user_page() + kmap_coherent() causes "Data bus error" + * copy_to_user_page() + kmap_coherent() causes immediate reboot + */ +#define cpu_has_kmap_coherent (cpu_data[0].processor_id != 0x29006 && \ + cpu_data[0].processor_id != 0x29029) + #endif /* __ASM_MACH_BCM47XX_CPU_FEATURE_OVERRIDES_H */ diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index c3b45e248806..67007bf15543 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -174,7 +174,7 @@ void copy_user_highpage(struct page *to, struct page *from, void *vfrom, *vto; vto = kmap_atomic(to); - if (cpu_has_dc_aliases && + if (cpu_has_kmap_coherent && cpu_has_dc_aliases && page_mapcount(from) && !Page_dcache_dirty(from)) { vfrom = kmap_coherent(from, vaddr); copy_page(vto, vfrom); @@ -196,7 +196,7 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page, unsigned long vaddr, void *dst, const void *src, unsigned long len) { - if (cpu_has_dc_aliases && + if (cpu_has_kmap_coherent && cpu_has_dc_aliases && page_mapcount(page) && !Page_dcache_dirty(page)) { void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); memcpy(vto, src, len); @@ -214,7 +214,7 @@ void copy_from_user_page(struct vm_area_struct *vma, struct page *page, unsigned long vaddr, void *dst, const void *src, unsigned long len) { - if (cpu_has_dc_aliases && + if (cpu_has_kmap_coherent && cpu_has_dc_aliases && page_mapcount(page) && !Page_dcache_dirty(page)) { void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); memcpy(dst, vfrom, len); -- 2.20.1