]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/4.6.6/x86-quirks-add-early-quirk-to-reset-apple-airport-card.patch
5.1-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.6.6 / x86-quirks-add-early-quirk-to-reset-apple-airport-card.patch
1 From abb2bafd295fe962bbadc329dbfb2146457283ac Mon Sep 17 00:00:00 2001
2 From: Lukas Wunner <lukas@wunner.de>
3 Date: Sun, 12 Jun 2016 12:31:53 +0200
4 Subject: x86/quirks: Add early quirk to reset Apple AirPort card
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 From: Lukas Wunner <lukas@wunner.de>
10
11 commit abb2bafd295fe962bbadc329dbfb2146457283ac upstream.
12
13 The EFI firmware on Macs contains a full-fledged network stack for
14 downloading OS X images from osrecovery.apple.com. Unfortunately
15 on Macs introduced 2011 and 2012, EFI brings up the Broadcom 4331
16 wireless card on every boot and leaves it enabled even after
17 ExitBootServices has been called. The card continues to assert its IRQ
18 line, causing spurious interrupts if the IRQ is shared. It also corrupts
19 memory by DMAing received packets, allowing for remote code execution
20 over the air. This only stops when a driver is loaded for the wireless
21 card, which may be never if the driver is not installed or blacklisted.
22
23 The issue seems to be constrained to the Broadcom 4331. Chris Milsted
24 has verified that the newer Broadcom 4360 built into the MacBookPro11,3
25 (2013/2014) does not exhibit this behaviour. The chances that Apple will
26 ever supply a firmware fix for the older machines appear to be zero.
27
28 The solution is to reset the card on boot by writing to a reset bit in
29 its mmio space. This must be done as an early quirk and not as a plain
30 vanilla PCI quirk to successfully combat memory corruption by DMAed
31 packets: Matthew Garrett found out in 2012 that the packets are written
32 to EfiBootServicesData memory (http://mjg59.dreamwidth.org/11235.html).
33 This type of memory is made available to the page allocator by
34 efi_free_boot_services(). Plain vanilla PCI quirks run much later, in
35 subsys initcall level. In-between a time window would be open for memory
36 corruption. Random crashes occurring in this time window and attributed
37 to DMAed packets have indeed been observed in the wild by Chris
38 Bainbridge.
39
40 When Matthew Garrett analyzed the memory corruption issue in 2012, he
41 sought to fix it with a grub quirk which transitions the card to D3hot:
42 http://git.savannah.gnu.org/cgit/grub.git/commit/?id=9d34bb85da56
43
44 This approach does not help users with other bootloaders and while it
45 may prevent DMAed packets, it does not cure the spurious interrupts
46 emanating from the card. Unfortunately the card's mmio space is
47 inaccessible in D3hot, so to reset it, we have to undo the effect of
48 Matthew's grub patch and transition the card back to D0.
49
50 Note that the quirk takes a few shortcuts to reduce the amount of code:
51 The size of BAR 0 and the location of the PM capability is identical
52 on all affected machines and therefore hardcoded. Only the address of
53 BAR 0 differs between models. Also, it is assumed that the BCMA core
54 currently mapped is the 802.11 core. The EFI driver seems to always take
55 care of this.
56
57 Michael Büsch, Bjorn Helgaas and Matt Fleming contributed feedback
58 towards finding the best solution to this problem.
59
60 The following should be a comprehensive list of affected models:
61 iMac13,1 2012 21.5" [Root Port 00:1c.3 = 8086:1e16]
62 iMac13,2 2012 27" [Root Port 00:1c.3 = 8086:1e16]
63 Macmini5,1 2011 i5 2.3 GHz [Root Port 00:1c.1 = 8086:1c12]
64 Macmini5,2 2011 i5 2.5 GHz [Root Port 00:1c.1 = 8086:1c12]
65 Macmini5,3 2011 i7 2.0 GHz [Root Port 00:1c.1 = 8086:1c12]
66 Macmini6,1 2012 i5 2.5 GHz [Root Port 00:1c.1 = 8086:1e12]
67 Macmini6,2 2012 i7 2.3 GHz [Root Port 00:1c.1 = 8086:1e12]
68 MacBookPro8,1 2011 13" [Root Port 00:1c.1 = 8086:1c12]
69 MacBookPro8,2 2011 15" [Root Port 00:1c.1 = 8086:1c12]
70 MacBookPro8,3 2011 17" [Root Port 00:1c.1 = 8086:1c12]
71 MacBookPro9,1 2012 15" [Root Port 00:1c.1 = 8086:1e12]
72 MacBookPro9,2 2012 13" [Root Port 00:1c.1 = 8086:1e12]
73 MacBookPro10,1 2012 15" [Root Port 00:1c.1 = 8086:1e12]
74 MacBookPro10,2 2012 13" [Root Port 00:1c.1 = 8086:1e12]
75
76 For posterity, spurious interrupts caused by the Broadcom 4331 wireless
77 card resulted in splats like this (stacktrace omitted):
78
79 irq 17: nobody cared (try booting with the "irqpoll" option)
80 handlers:
81 [<ffffffff81374370>] pcie_isr
82 [<ffffffffc0704550>] sdhci_irq [sdhci] threaded [<ffffffffc07013c0>] sdhci_thread_irq [sdhci]
83 [<ffffffffc0a0b960>] azx_interrupt [snd_hda_codec]
84 Disabling IRQ #17
85
86 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=79301
87 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=111781
88 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=728916
89 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=895951#c16
90 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1009819
91 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1098621
92 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1149632#c5
93 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1279130
94 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1332732
95 Tested-by: Konstantin Simanov <k.simanov@stlk.ru> # [MacBookPro8,1]
96 Tested-by: Lukas Wunner <lukas@wunner.de> # [MacBookPro9,1]
97 Tested-by: Bryan Paradis <bryan.paradis@gmail.com> # [MacBookPro9,2]
98 Tested-by: Andrew Worsley <amworsley@gmail.com> # [MacBookPro10,1]
99 Tested-by: Chris Bainbridge <chris.bainbridge@gmail.com> # [MacBookPro10,2]
100 Signed-off-by: Lukas Wunner <lukas@wunner.de>
101 Acked-by: Rafał Miłecki <zajec5@gmail.com>
102 Acked-by: Matt Fleming <matt@codeblueprint.co.uk>
103 Cc: Andy Lutomirski <luto@kernel.org>
104 Cc: Bjorn Helgaas <bhelgaas@google.com>
105 Cc: Borislav Petkov <bp@alien8.de>
106 Cc: Brian Gerst <brgerst@gmail.com>
107 Cc: Chris Milsted <cmilsted@redhat.com>
108 Cc: Denys Vlasenko <dvlasenk@redhat.com>
109 Cc: H. Peter Anvin <hpa@zytor.com>
110 Cc: Josh Poimboeuf <jpoimboe@redhat.com>
111 Cc: Linus Torvalds <torvalds@linux-foundation.org>
112 Cc: Matthew Garrett <mjg59@srcf.ucam.org>
113 Cc: Michael Buesch <m@bues.ch>
114 Cc: Peter Zijlstra <peterz@infradead.org>
115 Cc: Thomas Gleixner <tglx@linutronix.de>
116 Cc: Yinghai Lu <yinghai@kernel.org>
117 Cc: b43-dev@lists.infradead.org
118 Cc: linux-pci@vger.kernel.org
119 Cc: linux-wireless@vger.kernel.org
120 Link: http://lkml.kernel.org/r/48d0972ac82a53d460e5fce77a07b2560db95203.1465690253.git.lukas@wunner.de
121 [ Did minor readability edits. ]
122 Signed-off-by: Ingo Molnar <mingo@kernel.org>
123 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
124
125 ---
126 arch/x86/kernel/early-quirks.c | 64 +++++++++++++++++++++++++++++++++++++++++
127 drivers/bcma/bcma_private.h | 2 -
128 include/linux/bcma/bcma.h | 1
129 3 files changed, 65 insertions(+), 2 deletions(-)
130
131 --- a/arch/x86/kernel/early-quirks.c
132 +++ b/arch/x86/kernel/early-quirks.c
133 @@ -11,7 +11,11 @@
134
135 #include <linux/pci.h>
136 #include <linux/acpi.h>
137 +#include <linux/delay.h>
138 +#include <linux/dmi.h>
139 #include <linux/pci_ids.h>
140 +#include <linux/bcma/bcma.h>
141 +#include <linux/bcma/bcma_regs.h>
142 #include <drm/i915_drm.h>
143 #include <asm/pci-direct.h>
144 #include <asm/dma.h>
145 @@ -21,6 +25,9 @@
146 #include <asm/iommu.h>
147 #include <asm/gart.h>
148 #include <asm/irq_remapping.h>
149 +#include <asm/early_ioremap.h>
150 +
151 +#define dev_err(msg) pr_err("pci 0000:%02x:%02x.%d: %s", bus, slot, func, msg)
152
153 static void __init fix_hypertransport_config(int num, int slot, int func)
154 {
155 @@ -597,6 +604,61 @@ static void __init force_disable_hpet(in
156 #endif
157 }
158
159 +#define BCM4331_MMIO_SIZE 16384
160 +#define BCM4331_PM_CAP 0x40
161 +#define bcma_aread32(reg) ioread32(mmio + 1 * BCMA_CORE_SIZE + reg)
162 +#define bcma_awrite32(reg, val) iowrite32(val, mmio + 1 * BCMA_CORE_SIZE + reg)
163 +
164 +static void __init apple_airport_reset(int bus, int slot, int func)
165 +{
166 + void __iomem *mmio;
167 + u16 pmcsr;
168 + u64 addr;
169 + int i;
170 +
171 + if (!dmi_match(DMI_SYS_VENDOR, "Apple Inc."))
172 + return;
173 +
174 + /* Card may have been put into PCI_D3hot by grub quirk */
175 + pmcsr = read_pci_config_16(bus, slot, func, BCM4331_PM_CAP + PCI_PM_CTRL);
176 +
177 + if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0) {
178 + pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
179 + write_pci_config_16(bus, slot, func, BCM4331_PM_CAP + PCI_PM_CTRL, pmcsr);
180 + mdelay(10);
181 +
182 + pmcsr = read_pci_config_16(bus, slot, func, BCM4331_PM_CAP + PCI_PM_CTRL);
183 + if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0) {
184 + dev_err("Cannot power up Apple AirPort card\n");
185 + return;
186 + }
187 + }
188 +
189 + addr = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0);
190 + addr |= (u64)read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_1) << 32;
191 + addr &= PCI_BASE_ADDRESS_MEM_MASK;
192 +
193 + mmio = early_ioremap(addr, BCM4331_MMIO_SIZE);
194 + if (!mmio) {
195 + dev_err("Cannot iomap Apple AirPort card\n");
196 + return;
197 + }
198 +
199 + pr_info("Resetting Apple AirPort card (left enabled by EFI)\n");
200 +
201 + for (i = 0; bcma_aread32(BCMA_RESET_ST) && i < 30; i++)
202 + udelay(10);
203 +
204 + bcma_awrite32(BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
205 + bcma_aread32(BCMA_RESET_CTL);
206 + udelay(1);
207 +
208 + bcma_awrite32(BCMA_RESET_CTL, 0);
209 + bcma_aread32(BCMA_RESET_CTL);
210 + udelay(10);
211 +
212 + early_iounmap(mmio, BCM4331_MMIO_SIZE);
213 +}
214
215 #define QFLAG_APPLY_ONCE 0x1
216 #define QFLAG_APPLIED 0x2
217 @@ -639,6 +701,8 @@ static struct chipset early_qrk[] __init
218 */
219 { PCI_VENDOR_ID_INTEL, 0x0f00,
220 PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, force_disable_hpet},
221 + { PCI_VENDOR_ID_BROADCOM, 0x4331,
222 + PCI_CLASS_NETWORK_OTHER, PCI_ANY_ID, 0, apple_airport_reset},
223 {}
224 };
225
226 --- a/drivers/bcma/bcma_private.h
227 +++ b/drivers/bcma/bcma_private.h
228 @@ -8,8 +8,6 @@
229 #include <linux/bcma/bcma.h>
230 #include <linux/delay.h>
231
232 -#define BCMA_CORE_SIZE 0x1000
233 -
234 #define bcma_err(bus, fmt, ...) \
235 pr_err("bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
236 #define bcma_warn(bus, fmt, ...) \
237 --- a/include/linux/bcma/bcma.h
238 +++ b/include/linux/bcma/bcma.h
239 @@ -158,6 +158,7 @@ struct bcma_host_ops {
240 #define BCMA_CORE_DEFAULT 0xFFF
241
242 #define BCMA_MAX_NR_CORES 16
243 +#define BCMA_CORE_SIZE 0x1000
244
245 /* Chip IDs of PCIe devices */
246 #define BCMA_CHIP_ID_BCM4313 0x4313