OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | From 8edeb93cec4b7ca6771348fafbf4676920b052c9 Mon Sep 17 00:00:00 2001 |
2 | From: Phil Elwell <phil@raspberrypi.org> |
||
3 | Date: Mon, 16 Jul 2018 14:40:13 +0100 |
||
4 | Subject: [PATCH 362/454] dwc-otg: FIQ: Fix "bad mode in data abort handler" |
||
5 | |||
6 | Create a semi-static mapping for the USB registers early in the boot |
||
7 | process, before additional kernel threads are started, so all threads |
||
8 | will have the mappings from the start. This avoids the need for |
||
9 | data aborts to lazily update them. |
||
10 | |||
11 | See: https://github.com/raspberrypi/linux/issues/2450 |
||
12 | |||
13 | Signed-off-by: Floris Bos <bos@je-eigen-domein.nl> |
||
14 | --- |
||
15 | arch/arm/mach-bcm/board_bcm2835.c | 69 +++++++++++++++++++++++ |
||
16 | drivers/usb/host/dwc_otg/dwc_otg_driver.c | 2 +- |
||
17 | 2 files changed, 70 insertions(+), 1 deletion(-) |
||
18 | |||
19 | --- a/arch/arm/mach-bcm/board_bcm2835.c |
||
20 | +++ b/arch/arm/mach-bcm/board_bcm2835.c |
||
21 | @@ -15,6 +15,7 @@ |
||
22 | #include <linux/init.h> |
||
23 | #include <linux/irqchip.h> |
||
24 | #include <linux/of_address.h> |
||
25 | +#include <linux/of_fdt.h> |
||
26 | #include <linux/clk/bcm2835.h> |
||
27 | #include <asm/system_info.h> |
||
28 | |||
29 | @@ -24,6 +25,9 @@ |
||
30 | #include "platsmp.h" |
||
31 | #include <linux/dma-mapping.h> |
||
32 | |||
33 | +#define BCM2835_USB_VIRT_BASE 0xf0980000 |
||
34 | +#define BCM2835_USB_VIRT_MPHI 0xf0006000 |
||
35 | + |
||
36 | static void __init bcm2835_init(void) |
||
37 | { |
||
38 | struct device_node *np = of_find_node_by_path("/system"); |
||
39 | @@ -44,6 +48,70 @@ static void __init bcm2835_init_early(vo |
||
40 | init_dma_coherent_pool_size(SZ_1M); |
||
41 | } |
||
42 | |||
43 | +/* |
||
44 | + * We need to map registers that are going to be accessed by the FIQ |
||
45 | + * very early, before any kernel threads are spawned. Because if done |
||
46 | + * later, the mapping tables are not updated instantly but lazily upon |
||
47 | + * first access through a data abort handler. While that is fine |
||
48 | + * when executing regular kernel code, if the first access in a specific |
||
49 | + * thread happens while running FIQ code this will result in a panic. |
||
50 | + * |
||
51 | + * For more background see the following old mailing list thread: |
||
52 | + * https://www.spinics.net/lists/arm-kernel/msg325250.html |
||
53 | + */ |
||
54 | +static int __init bcm2835_map_usb(unsigned long node, const char *uname, |
||
55 | + int depth, void *data) |
||
56 | +{ |
||
57 | + struct map_desc map[2]; |
||
58 | + const __be32 *reg; |
||
59 | + int len; |
||
60 | + unsigned long p2b_offset = *((unsigned long *) data); |
||
61 | + |
||
62 | + if (!of_flat_dt_is_compatible(node, "brcm,bcm2708-usb")) |
||
63 | + return 0; |
||
64 | + reg = of_get_flat_dt_prop(node, "reg", &len); |
||
65 | + if (!reg || len != (sizeof(unsigned long) * 4)) |
||
66 | + return 0; |
||
67 | + |
||
68 | + /* Use information about the physical addresses of the |
||
69 | + * registers from the device tree, but use legacy |
||
70 | + * iotable_init() static mapping function to map them, |
||
71 | + * as ioremap() is not functional at this stage in boot. |
||
72 | + */ |
||
73 | + map[0].virtual = (unsigned long) BCM2835_USB_VIRT_BASE; |
||
74 | + map[0].pfn = __phys_to_pfn(be32_to_cpu(reg[0]) - p2b_offset); |
||
75 | + map[0].length = be32_to_cpu(reg[1]); |
||
76 | + map[0].type = MT_DEVICE; |
||
77 | + map[1].virtual = (unsigned long) BCM2835_USB_VIRT_MPHI; |
||
78 | + map[1].pfn = __phys_to_pfn(be32_to_cpu(reg[2]) - p2b_offset); |
||
79 | + map[1].length = be32_to_cpu(reg[3]); |
||
80 | + map[1].type = MT_DEVICE; |
||
81 | + iotable_init(map, 2); |
||
82 | + |
||
83 | + return 1; |
||
84 | +} |
||
85 | + |
||
86 | +static void __init bcm2835_map_io(void) |
||
87 | +{ |
||
88 | + const __be32 *ranges; |
||
89 | + int soc, len; |
||
90 | + unsigned long p2b_offset; |
||
91 | + |
||
92 | + debug_ll_io_init(); |
||
93 | + |
||
94 | + /* Find out how to map bus to physical address first from soc/ranges */ |
||
95 | + soc = of_get_flat_dt_subnode_by_name(of_get_flat_dt_root(), "soc"); |
||
96 | + if (soc < 0) |
||
97 | + return; |
||
98 | + ranges = of_get_flat_dt_prop(soc, "ranges", &len); |
||
99 | + if (!ranges || len < (sizeof(unsigned long) * 3)) |
||
100 | + return; |
||
101 | + p2b_offset = be32_to_cpu(ranges[0]) - be32_to_cpu(ranges[1]); |
||
102 | + |
||
103 | + /* Now search for bcm2708-usb node in device tree */ |
||
104 | + of_scan_flat_dt(bcm2835_map_usb, &p2b_offset); |
||
105 | +} |
||
106 | + |
||
107 | static const char * const bcm2835_compat[] = { |
||
108 | #ifdef CONFIG_ARCH_MULTI_V6 |
||
109 | "brcm,bcm2835", |
||
110 | @@ -56,6 +124,7 @@ static const char * const bcm2835_compat |
||
111 | }; |
||
112 | |||
113 | DT_MACHINE_START(BCM2835, "BCM2835") |
||
114 | + .map_io = bcm2835_map_io, |
||
115 | .init_machine = bcm2835_init, |
||
116 | .init_early = bcm2835_init_early, |
||
117 | .dt_compat = bcm2835_compat, |
||
118 | --- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c |
||
119 | +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c |
||
120 | @@ -837,7 +837,7 @@ static int dwc_otg_driver_probe( |
||
121 | retval = -ENOMEM; |
||
122 | goto fail; |
||
123 | } |
||
124 | - dev_dbg(&_dev->dev, "base=0x%08x\n", |
||
125 | + dev_info(&_dev->dev, "base=0x%08x\n", |
||
126 | (unsigned)dwc_otg_device->os_dep.base); |
||
127 | #endif |
||
128 |