aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-4.19/950-0203-dwc-otg-FIQ-Fix-bad-mode-in-data-abort-handler.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm2708/patches-4.19/950-0203-dwc-otg-FIQ-Fix-bad-mode-in-data-abort-handler.patch')
-rw-r--r--target/linux/brcm2708/patches-4.19/950-0203-dwc-otg-FIQ-Fix-bad-mode-in-data-abort-handler.patch128
1 files changed, 128 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.19/950-0203-dwc-otg-FIQ-Fix-bad-mode-in-data-abort-handler.patch b/target/linux/brcm2708/patches-4.19/950-0203-dwc-otg-FIQ-Fix-bad-mode-in-data-abort-handler.patch
new file mode 100644
index 0000000000..51c7732beb
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.19/950-0203-dwc-otg-FIQ-Fix-bad-mode-in-data-abort-handler.patch
@@ -0,0 +1,128 @@
+From f36b3119d83e03c9d0c684b8712b66a979c48124 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 16 Jul 2018 14:40:13 +0100
+Subject: [PATCH] dwc-otg: FIQ: Fix "bad mode in data abort handler"
+
+Create a semi-static mapping for the USB registers early in the boot
+process, before additional kernel threads are started, so all threads
+will have the mappings from the start. This avoids the need for
+data aborts to lazily update them.
+
+See: https://github.com/raspberrypi/linux/issues/2450
+
+Signed-off-by: Floris Bos <bos@je-eigen-domein.nl>
+---
+ arch/arm/mach-bcm/board_bcm2835.c | 69 +++++++++++++++++++++++
+ drivers/usb/host/dwc_otg/dwc_otg_driver.c | 2 +-
+ 2 files changed, 70 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/mach-bcm/board_bcm2835.c
++++ b/arch/arm/mach-bcm/board_bcm2835.c
+@@ -15,6 +15,7 @@
+ #include <linux/init.h>
+ #include <linux/irqchip.h>
+ #include <linux/of_address.h>
++#include <linux/of_fdt.h>
+ #include <asm/system_info.h>
+
+ #include <asm/mach/arch.h>
+@@ -22,6 +23,9 @@
+
+ #include "platsmp.h"
+
++#define BCM2835_USB_VIRT_BASE 0xf0980000
++#define BCM2835_USB_VIRT_MPHI 0xf0006000
++
+ static void __init bcm2835_init(void)
+ {
+ struct device_node *np = of_find_node_by_path("/system");
+@@ -34,6 +38,70 @@ static void __init bcm2835_init(void)
+ system_serial_low = val64;
+ }
+
++/*
++ * We need to map registers that are going to be accessed by the FIQ
++ * very early, before any kernel threads are spawned. Because if done
++ * later, the mapping tables are not updated instantly but lazily upon
++ * first access through a data abort handler. While that is fine
++ * when executing regular kernel code, if the first access in a specific
++ * thread happens while running FIQ code this will result in a panic.
++ *
++ * For more background see the following old mailing list thread:
++ * https://www.spinics.net/lists/arm-kernel/msg325250.html
++ */
++static int __init bcm2835_map_usb(unsigned long node, const char *uname,
++ int depth, void *data)
++{
++ struct map_desc map[2];
++ const __be32 *reg;
++ int len;
++ unsigned long p2b_offset = *((unsigned long *) data);
++
++ if (!of_flat_dt_is_compatible(node, "brcm,bcm2708-usb"))
++ return 0;
++ reg = of_get_flat_dt_prop(node, "reg", &len);
++ if (!reg || len != (sizeof(unsigned long) * 4))
++ return 0;
++
++ /* Use information about the physical addresses of the
++ * registers from the device tree, but use legacy
++ * iotable_init() static mapping function to map them,
++ * as ioremap() is not functional at this stage in boot.
++ */
++ map[0].virtual = (unsigned long) BCM2835_USB_VIRT_BASE;
++ map[0].pfn = __phys_to_pfn(be32_to_cpu(reg[0]) - p2b_offset);
++ map[0].length = be32_to_cpu(reg[1]);
++ map[0].type = MT_DEVICE;
++ map[1].virtual = (unsigned long) BCM2835_USB_VIRT_MPHI;
++ map[1].pfn = __phys_to_pfn(be32_to_cpu(reg[2]) - p2b_offset);
++ map[1].length = be32_to_cpu(reg[3]);
++ map[1].type = MT_DEVICE;
++ iotable_init(map, 2);
++
++ return 1;
++}
++
++static void __init bcm2835_map_io(void)
++{
++ const __be32 *ranges;
++ int soc, len;
++ unsigned long p2b_offset;
++
++ debug_ll_io_init();
++
++ /* Find out how to map bus to physical address first from soc/ranges */
++ soc = of_get_flat_dt_subnode_by_name(of_get_flat_dt_root(), "soc");
++ if (soc < 0)
++ return;
++ ranges = of_get_flat_dt_prop(soc, "ranges", &len);
++ if (!ranges || len < (sizeof(unsigned long) * 3))
++ return;
++ p2b_offset = be32_to_cpu(ranges[0]) - be32_to_cpu(ranges[1]);
++
++ /* Now search for bcm2708-usb node in device tree */
++ of_scan_flat_dt(bcm2835_map_usb, &p2b_offset);
++}
++
+ static const char * const bcm2835_compat[] = {
+ #ifdef CONFIG_ARCH_MULTI_V6
+ "brcm,bcm2835",
+@@ -46,6 +114,7 @@ static const char * const bcm2835_compat
+ };
+
+ DT_MACHINE_START(BCM2835, "BCM2835")
++ .map_io = bcm2835_map_io,
+ .init_machine = bcm2835_init,
+ .dt_compat = bcm2835_compat,
+ .smp = smp_ops(bcm2836_smp_ops),
+--- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
+@@ -837,7 +837,7 @@ static int dwc_otg_driver_probe(
+ retval = -ENOMEM;
+ goto fail;
+ }
+- dev_dbg(&_dev->dev, "base=0x%08x\n",
++ dev_info(&_dev->dev, "base=0x%08x\n",
+ (unsigned)dwc_otg_device->os_dep.base);
+ #endif
+