Skip to content

Commit

Permalink
Explicitly disable BCM4331 chips present in 2011-2012 Apple Mac systems.
Browse files Browse the repository at this point in the history
The Mac EFI firmware enables the wireless controller, but does not disable it,
so it continues to receive packets and signal interrupts. This
was originally seen as an interrupt storm that consumes about 50% of
CPU0 on affected machines. The issue was originally discovered in 2012 by
Matthew Garret with a partial fix in Grub, then Lukas Wunner added a fix for
the Linux kernel in 2016.

This piggy-backs on the most-related driver (bwi) for the purpose of detection
and mapping the control registers, but does not actually register the driver if
the affected chip is detected.

See this archived discussion for further analysis of the bug:
https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1165355.html

ok kettenis stsp
  • Loading branch information
busterb committed May 10, 2019
1 parent ec1695e commit 1109d94
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 15 deletions.
9 changes: 8 additions & 1 deletion sys/dev/ic/bwireg.h
@@ -1,4 +1,4 @@
/* $OpenBSD: bwireg.h,v 1.9 2014/06/07 11:55:02 stsp Exp $ */
/* $OpenBSD: bwireg.h,v 1.10 2019/05/10 16:44:36 bcook Exp $ */

/*
* Copyright (c) 2007 The DragonFly Project. All rights reserved.
Expand Down Expand Up @@ -331,6 +331,13 @@
*/
#define BWI_GPIO_CTRL 0x0000006c

/*
* Core reset
*/
#define BWI_RESET_CTRL 0x1800
#define BWI_RESET_STATUS 0x1804
#define BWI_RESET_CTRL_RESET (1 << 0)

/*
* Extended PCI registers
*/
Expand Down
59 changes: 45 additions & 14 deletions sys/dev/pci/if_bwi_pci.c
@@ -1,4 +1,4 @@
/* $OpenBSD: if_bwi_pci.c,v 1.16 2015/11/24 17:11:39 mpi Exp $ */
/* $OpenBSD: if_bwi_pci.c,v 1.17 2019/05/10 16:44:36 bcook Exp $ */

/*
* Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org>
Expand Down Expand Up @@ -45,6 +45,7 @@
#include <net80211/ieee80211_radiotap.h>

#include <dev/ic/bwivar.h>
#include <dev/ic/bwireg.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
Expand Down Expand Up @@ -86,7 +87,8 @@ const struct pci_matchid bwi_pci_devices[] = {
{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4312 },
{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4318 },
{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4319 },
{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43XG }
{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43XG },
{ PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4331 },
};

int
Expand All @@ -108,6 +110,28 @@ bwi_pci_match(struct device *parent, void *match, void *aux)
sizeof(bwi_pci_devices) / sizeof(bwi_pci_devices[0])));
}

void
bwi_reset_bcm4331(struct bwi_softc *sc)
{
int i;

/*
* The BCM4331 is not actually supported by this driver, but buggy EFI
* revisions in 2011-2012 Macs leave this chip enabled by default,
* causing it to emit spurious interrupts when the shared interrupt
* line is enabled.
*/
for (i = 0; CSR_READ_4(sc, BWI_RESET_STATUS) && i < 30; i++)
delay(10);

CSR_WRITE_4(sc, BWI_RESET_CTRL, BWI_RESET_CTRL_RESET);
CSR_READ_4(sc, BWI_RESET_CTRL);
delay(1);
CSR_WRITE_4(sc, BWI_RESET_CTRL, 0);
CSR_READ_4(sc, BWI_RESET_CTRL);
delay(10);
}

void
bwi_pci_attach(struct device *parent, struct device *self, void *aux)
{
Expand All @@ -123,13 +147,31 @@ bwi_pci_attach(struct device *parent, struct device *self, void *aux)
psc->psc_pcitag = pa->pa_tag;

/* map control / status registers */
memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, BWI_PCI_BAR0);
memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, BWI_PCI_BAR0);
if (pci_mapreg_map(pa, BWI_PCI_BAR0, memtype, 0, &sc->sc_mem_bt,
&sc->sc_mem_bh, NULL, &psc->psc_mapsize, 0)) {
printf(": can't map mem space\n");
return;
}

/* we need to access PCI config space from the driver */
sc->sc_conf_write = bwi_pci_conf_write;
sc->sc_conf_read = bwi_pci_conf_read;

reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);

sc->sc_pci_revid = PCI_REVISION(pa->pa_class);
sc->sc_pci_did = PCI_PRODUCT(pa->pa_id);
sc->sc_pci_subvid = PCI_VENDOR(reg);
sc->sc_pci_subdid = PCI_PRODUCT(reg);

if (sc->sc_pci_did == PCI_PRODUCT_BROADCOM_BCM4331) {
printf(": disabling\n");
bwi_reset_bcm4331(sc);
bus_space_unmap(sc->sc_mem_bt, sc->sc_mem_bh, psc->psc_mapsize);
return;
}

/* map interrupt */
if (pci_intr_map(pa, &ih) != 0) {
printf(": can't map interrupt\n");
Expand All @@ -149,17 +191,6 @@ bwi_pci_attach(struct device *parent, struct device *self, void *aux)
}
printf(": %s", intrstr);

/* we need to access PCI config space from the driver */
sc->sc_conf_write = bwi_pci_conf_write;
sc->sc_conf_read = bwi_pci_conf_read;

reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);

sc->sc_pci_revid = PCI_REVISION(pa->pa_class);
sc->sc_pci_did = PCI_PRODUCT(pa->pa_id);
sc->sc_pci_subvid = PCI_VENDOR(reg);
sc->sc_pci_subdid = PCI_PRODUCT(reg);

bwi_attach(sc);
}

Expand Down

0 comments on commit 1109d94

Please sign in to comment.