diff options
Diffstat (limited to 'target/linux/brcm2708/patches-4.19/950-0223-dwc-otg-FIQ-Fix-bad-mode-in-data-abort-handler.patch')
-rw-r--r-- | target/linux/brcm2708/patches-4.19/950-0223-dwc-otg-FIQ-Fix-bad-mode-in-data-abort-handler.patch | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.19/950-0223-dwc-otg-FIQ-Fix-bad-mode-in-data-abort-handler.patch b/target/linux/brcm2708/patches-4.19/950-0223-dwc-otg-FIQ-Fix-bad-mode-in-data-abort-handler.patch new file mode 100644 index 0000000000..1bf0b58c40 --- /dev/null +++ b/target/linux/brcm2708/patches-4.19/950-0223-dwc-otg-FIQ-Fix-bad-mode-in-data-abort-handler.patch @@ -0,0 +1,128 @@ +From 71ffaebfc05366238b7b3777e572dc77ec6f78f6 Mon Sep 17 00:00:00 2001 +From: Phil Elwell <phil@raspberrypi.org> +Date: Mon, 16 Jul 2018 14:40:13 +0100 +Subject: [PATCH 223/703] 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 + |