mirror of https://github.com/hak5/openwrt.git
mac80211: brcm: backport brcmfmac 5.2 patches
This includes some USB fixes and early work on FullMAC firmware crash recovery. Signed-off-by: Rafał Miłecki <rafal@milecki.pl>openwrt-19.07
parent
bd3a18bbe4
commit
083056c83f
|
@ -0,0 +1,29 @@
|
|||
From 0c7051610c577b60b01b3b5aec14d6765e177b0d Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Thu, 21 Feb 2019 11:33:24 +0100
|
||||
Subject: [PATCH] brcmfmac: fix size of the struct msgbuf_ring_status
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This updates host struct to match the in-firmawre definition. It's a
|
||||
cosmetic change as it only applies to the reserved struct space.
|
||||
|
||||
Fixes: c988b78244df ("brcmfmac: print firmware reported ring status errors")
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
|
||||
@@ -139,7 +139,7 @@ struct msgbuf_ring_status {
|
||||
struct msgbuf_common_hdr msg;
|
||||
struct msgbuf_completion_hdr compl_hdr;
|
||||
__le16 write_idx;
|
||||
- __le32 rsvd0[5];
|
||||
+ __le16 rsvd0[5];
|
||||
};
|
||||
|
||||
struct msgbuf_rx_event {
|
|
@ -0,0 +1,69 @@
|
|||
From c91377495192cda096e52dc09c266b0d05f16d86 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Thu, 21 Feb 2019 11:33:25 +0100
|
||||
Subject: [PATCH] brcmfmac: print firmware reported general status errors
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Firmware may report general errors using a special message type. Add
|
||||
basic support for it by simply decoding & printing an error number.
|
||||
|
||||
A sample situation in which firmware reports a buf error:
|
||||
CONSOLE: 027084.733 no host response IOCTL buffer available..so fail the request
|
||||
will now produce a "Firmware reported general error: 9" on the host.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
.../broadcom/brcm80211/brcmfmac/msgbuf.c | 24 +++++++++++++++++++
|
||||
1 file changed, 24 insertions(+)
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
|
||||
@@ -134,6 +134,14 @@ struct msgbuf_completion_hdr {
|
||||
__le16 flow_ring_id;
|
||||
};
|
||||
|
||||
+/* Data struct for the MSGBUF_TYPE_GEN_STATUS */
|
||||
+struct msgbuf_gen_status {
|
||||
+ struct msgbuf_common_hdr msg;
|
||||
+ struct msgbuf_completion_hdr compl_hdr;
|
||||
+ __le16 write_idx;
|
||||
+ __le32 rsvd0[3];
|
||||
+};
|
||||
+
|
||||
/* Data struct for the MSGBUF_TYPE_RING_STATUS */
|
||||
struct msgbuf_ring_status {
|
||||
struct msgbuf_common_hdr msg;
|
||||
@@ -1194,6 +1202,18 @@ brcmf_msgbuf_process_rx_complete(struct
|
||||
brcmf_netif_rx(ifp, skb);
|
||||
}
|
||||
|
||||
+static void brcmf_msgbuf_process_gen_status(struct brcmf_msgbuf *msgbuf,
|
||||
+ void *buf)
|
||||
+{
|
||||
+ struct msgbuf_gen_status *gen_status = buf;
|
||||
+ struct brcmf_pub *drvr = msgbuf->drvr;
|
||||
+ int err;
|
||||
+
|
||||
+ err = le16_to_cpu(gen_status->compl_hdr.status);
|
||||
+ if (err)
|
||||
+ bphy_err(drvr, "Firmware reported general error: %d\n", err);
|
||||
+}
|
||||
+
|
||||
static void brcmf_msgbuf_process_ring_status(struct brcmf_msgbuf *msgbuf,
|
||||
void *buf)
|
||||
{
|
||||
@@ -1273,6 +1293,10 @@ static void brcmf_msgbuf_process_msgtype
|
||||
|
||||
msg = (struct msgbuf_common_hdr *)buf;
|
||||
switch (msg->msgtype) {
|
||||
+ case MSGBUF_TYPE_GEN_STATUS:
|
||||
+ brcmf_dbg(MSGBUF, "MSGBUF_TYPE_GEN_STATUS\n");
|
||||
+ brcmf_msgbuf_process_gen_status(msgbuf, buf);
|
||||
+ break;
|
||||
case MSGBUF_TYPE_RING_STATUS:
|
||||
brcmf_dbg(MSGBUF, "MSGBUF_TYPE_RING_STATUS\n");
|
||||
brcmf_msgbuf_process_ring_status(msgbuf, buf);
|
|
@ -0,0 +1,32 @@
|
|||
From c9692820710f57c826b2e43a6fb1e4cd307508b0 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Tue, 26 Feb 2019 14:11:16 +0100
|
||||
Subject: [PATCH] brcmfmac: support repeated brcmf_fw_alloc_request() calls
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
During a normal brcmfmac lifetime brcmf_fw_alloc_request() is called
|
||||
once only during the probe. It's safe to assume provided array is clear.
|
||||
|
||||
Further brcmfmac improvements may require calling it multiple times
|
||||
though. This patch allows it by fixing invalid firmware paths like:
|
||||
brcm/brcmfmac4366c-pcie.binbrcm/brcmfmac4366c-pcie.bin
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Reviewed-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
|
||||
@@ -743,6 +743,7 @@ brcmf_fw_alloc_request(u32 chip, u32 chi
|
||||
|
||||
for (j = 0; j < n_fwnames; j++) {
|
||||
fwreq->items[j].path = fwnames[j].path;
|
||||
+ fwnames[j].path[0] = '\0';
|
||||
/* check if firmware path is provided by module parameter */
|
||||
if (brcmf_mp_global.firmware_path[0] != '\0') {
|
||||
strlcpy(fwnames[j].path, mp_path,
|
|
@ -0,0 +1,79 @@
|
|||
From a2ec87ddbf1637f854ffcfff9d12d392fa30758b Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Tue, 26 Feb 2019 14:11:18 +0100
|
||||
Subject: [PATCH] brcmfmac: add a function designated for handling firmware
|
||||
fails
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This improves handling PCIe firmware halts by printing a clear error
|
||||
message and replaces a similar code in the SDIO bus support.
|
||||
|
||||
It will also allow further improvements like trying to recover from a
|
||||
firmware crash.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Reviewed-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h | 2 ++
|
||||
.../net/wireless/broadcom/brcm80211/brcmfmac/core.c | 10 ++++++++++
|
||||
.../net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 2 +-
|
||||
.../net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 4 ++--
|
||||
4 files changed, 15 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
|
||||
@@ -262,6 +262,8 @@ void brcmf_detach(struct device *dev);
|
||||
void brcmf_dev_reset(struct device *dev);
|
||||
/* Request from bus module to initiate a coredump */
|
||||
void brcmf_dev_coredump(struct device *dev);
|
||||
+/* Indication that firmware has halted or crashed */
|
||||
+void brcmf_fw_crashed(struct device *dev);
|
||||
|
||||
/* Configure the "global" bus state used by upper layers */
|
||||
void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state);
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
||||
@@ -1294,6 +1294,16 @@ void brcmf_dev_coredump(struct device *d
|
||||
brcmf_dbg(TRACE, "failed to create coredump\n");
|
||||
}
|
||||
|
||||
+void brcmf_fw_crashed(struct device *dev)
|
||||
+{
|
||||
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
|
||||
+ struct brcmf_pub *drvr = bus_if->drvr;
|
||||
+
|
||||
+ bphy_err(drvr, "Firmware has halted or crashed\n");
|
||||
+
|
||||
+ brcmf_dev_coredump(dev);
|
||||
+}
|
||||
+
|
||||
void brcmf_detach(struct device *dev)
|
||||
{
|
||||
s32 i;
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
|
||||
@@ -730,7 +730,7 @@ static void brcmf_pcie_handle_mb_data(st
|
||||
}
|
||||
if (dtoh_mb_data & BRCMF_D2H_DEV_FWHALT) {
|
||||
brcmf_dbg(PCIE, "D2H_MB_DATA: FW HALT\n");
|
||||
- brcmf_dev_coredump(&devinfo->pdev->dev);
|
||||
+ brcmf_fw_crashed(&devinfo->pdev->dev);
|
||||
}
|
||||
}
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
||||
@@ -1090,8 +1090,8 @@ static u32 brcmf_sdio_hostmail(struct br
|
||||
|
||||
/* dongle indicates the firmware has halted/crashed */
|
||||
if (hmb_data & HMB_DATA_FWHALT) {
|
||||
- brcmf_err("mailbox indicates firmware halted\n");
|
||||
- brcmf_dev_coredump(&sdiod->func1->dev);
|
||||
+ brcmf_dbg(SDIO, "mailbox indicates firmware halted\n");
|
||||
+ brcmf_fw_crashed(&sdiod->func1->dev);
|
||||
}
|
||||
|
||||
/* Dongle recomposed rx frames, accept them again */
|
|
@ -0,0 +1,153 @@
|
|||
From 4684997d9eea29380000e062755aa6d368d789a3 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Tue, 26 Feb 2019 14:11:19 +0100
|
||||
Subject: [PATCH] brcmfmac: reset PCIe bus on a firmware crash
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This includes bus reset & reloading a firmware. It should be sufficient
|
||||
for a user space to (setup and) use a wireless device again.
|
||||
|
||||
Support for reset on USB & SDIO can be added later.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Reviewed-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
.../broadcom/brcm80211/brcmfmac/bus.h | 10 ++++++
|
||||
.../broadcom/brcm80211/brcmfmac/core.c | 12 +++++++
|
||||
.../broadcom/brcm80211/brcmfmac/core.h | 2 ++
|
||||
.../broadcom/brcm80211/brcmfmac/pcie.c | 35 +++++++++++++++++++
|
||||
4 files changed, 59 insertions(+)
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
|
||||
@@ -91,6 +91,7 @@ struct brcmf_bus_ops {
|
||||
int (*get_fwname)(struct device *dev, const char *ext,
|
||||
unsigned char *fw_name);
|
||||
void (*debugfs_create)(struct device *dev);
|
||||
+ int (*reset)(struct device *dev);
|
||||
};
|
||||
|
||||
|
||||
@@ -245,6 +246,15 @@ void brcmf_bus_debugfs_create(struct brc
|
||||
return bus->ops->debugfs_create(bus->dev);
|
||||
}
|
||||
|
||||
+static inline
|
||||
+int brcmf_bus_reset(struct brcmf_bus *bus)
|
||||
+{
|
||||
+ if (!bus->ops->reset)
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
+ return bus->ops->reset(bus->dev);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* interface functions from common layer
|
||||
*/
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
||||
@@ -1105,6 +1105,14 @@ static int brcmf_revinfo_read(struct seq
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void brcmf_core_bus_reset(struct work_struct *work)
|
||||
+{
|
||||
+ struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
|
||||
+ bus_reset);
|
||||
+
|
||||
+ brcmf_bus_reset(drvr->bus_if);
|
||||
+}
|
||||
+
|
||||
static int brcmf_bus_started(struct brcmf_pub *drvr, struct cfg80211_ops *ops)
|
||||
{
|
||||
int ret = -1;
|
||||
@@ -1176,6 +1184,8 @@ static int brcmf_bus_started(struct brcm
|
||||
#endif
|
||||
#endif /* CONFIG_INET */
|
||||
|
||||
+ INIT_WORK(&drvr->bus_reset, brcmf_core_bus_reset);
|
||||
+
|
||||
/* populate debugfs */
|
||||
brcmf_debugfs_add_entry(drvr, "revinfo", brcmf_revinfo_read);
|
||||
brcmf_feat_debugfs_create(drvr);
|
||||
@@ -1302,6 +1312,8 @@ void brcmf_fw_crashed(struct device *dev
|
||||
bphy_err(drvr, "Firmware has halted or crashed\n");
|
||||
|
||||
brcmf_dev_coredump(dev);
|
||||
+
|
||||
+ schedule_work(&drvr->bus_reset);
|
||||
}
|
||||
|
||||
void brcmf_detach(struct device *dev)
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
|
||||
@@ -143,6 +143,8 @@ struct brcmf_pub {
|
||||
struct notifier_block inet6addr_notifier;
|
||||
struct brcmf_mp_device *settings;
|
||||
|
||||
+ struct work_struct bus_reset;
|
||||
+
|
||||
u8 clmver[BRCMF_DCMD_SMLEN];
|
||||
};
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
|
||||
@@ -345,6 +345,10 @@ static const u32 brcmf_ring_itemsize[BRC
|
||||
BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE
|
||||
};
|
||||
|
||||
+static void brcmf_pcie_setup(struct device *dev, int ret,
|
||||
+ struct brcmf_fw_request *fwreq);
|
||||
+static struct brcmf_fw_request *
|
||||
+brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo);
|
||||
|
||||
static u32
|
||||
brcmf_pcie_read_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset)
|
||||
@@ -1409,6 +1413,36 @@ int brcmf_pcie_get_fwname(struct device
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int brcmf_pcie_reset(struct device *dev)
|
||||
+{
|
||||
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
|
||||
+ struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
|
||||
+ struct brcmf_pciedev_info *devinfo = buspub->devinfo;
|
||||
+ struct brcmf_fw_request *fwreq;
|
||||
+ int err;
|
||||
+
|
||||
+ brcmf_detach(dev);
|
||||
+
|
||||
+ brcmf_pcie_release_irq(devinfo);
|
||||
+ brcmf_pcie_release_scratchbuffers(devinfo);
|
||||
+ brcmf_pcie_release_ringbuffers(devinfo);
|
||||
+ brcmf_pcie_reset_device(devinfo);
|
||||
+
|
||||
+ fwreq = brcmf_pcie_prepare_fw_request(devinfo);
|
||||
+ if (!fwreq) {
|
||||
+ dev_err(dev, "Failed to prepare FW request\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ err = brcmf_fw_get_firmwares(dev, fwreq, brcmf_pcie_setup);
|
||||
+ if (err) {
|
||||
+ dev_err(dev, "Failed to prepare FW request\n");
|
||||
+ kfree(fwreq);
|
||||
+ }
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
|
||||
.txdata = brcmf_pcie_tx,
|
||||
.stop = brcmf_pcie_down,
|
||||
@@ -1418,6 +1452,7 @@ static const struct brcmf_bus_ops brcmf_
|
||||
.get_ramsize = brcmf_pcie_get_ramsize,
|
||||
.get_memdump = brcmf_pcie_get_memdump,
|
||||
.get_fwname = brcmf_pcie_get_fwname,
|
||||
+ .reset = brcmf_pcie_reset,
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
From c80d26e81ef1802f30364b4ad1955c1443a592b9 Mon Sep 17 00:00:00 2001
|
||||
From: Piotr Figiel <p.figiel@camlintechnologies.com>
|
||||
Date: Mon, 4 Mar 2019 15:42:49 +0000
|
||||
Subject: [PATCH] brcmfmac: fix WARNING during USB disconnect in case of
|
||||
unempty psq
|
||||
|
||||
brcmu_pkt_buf_free_skb emits WARNING when attempting to free a sk_buff
|
||||
which is part of any queue. After USB disconnect this may have happened
|
||||
when brcmf_fws_hanger_cleanup() is called as per-interface psq was never
|
||||
cleaned when removing the interface.
|
||||
Change brcmf_fws_macdesc_cleanup() in a way that it removes the
|
||||
corresponding packets from hanger table (to avoid double-free when
|
||||
brcmf_fws_hanger_cleanup() is called) and add a call to clean-up the
|
||||
interface specific packet queue.
|
||||
|
||||
Below is a WARNING during USB disconnect with Raspberry Pi WiFi dongle
|
||||
running in AP mode. This was reproducible when the interface was
|
||||
transmitting during the disconnect and is fixed with this commit.
|
||||
|
||||
------------[ cut here ]------------
|
||||
WARNING: CPU: 0 PID: 1171 at drivers/net/wireless/broadcom/brcm80211/brcmutil/utils.c:49 brcmu_pkt_buf_free_skb+0x3c/0x40
|
||||
Modules linked in: nf_log_ipv4 nf_log_common xt_LOG xt_limit iptable_mangle xt_connmark xt_tcpudp xt_conntrack nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 iptable_filter ip_tables x_tables usb_f_mass_storage usb_f_rndis u_ether cdc_acm smsc95xx usbnet ci_hdrc_imx ci_hdrc ulpi usbmisc_imx 8250_exar 8250_pci 8250 8250_base libcomposite configfs udc_core
|
||||
CPU: 0 PID: 1171 Comm: kworker/0:0 Not tainted 4.19.23-00075-gde33ed8 #99
|
||||
Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
|
||||
Workqueue: usb_hub_wq hub_event
|
||||
[<8010ff84>] (unwind_backtrace) from [<8010bb64>] (show_stack+0x10/0x14)
|
||||
[<8010bb64>] (show_stack) from [<80840278>] (dump_stack+0x88/0x9c)
|
||||
[<80840278>] (dump_stack) from [<8011f5ec>] (__warn+0xfc/0x114)
|
||||
[<8011f5ec>] (__warn) from [<8011f71c>] (warn_slowpath_null+0x40/0x48)
|
||||
[<8011f71c>] (warn_slowpath_null) from [<805a476c>] (brcmu_pkt_buf_free_skb+0x3c/0x40)
|
||||
[<805a476c>] (brcmu_pkt_buf_free_skb) from [<805bb6c4>] (brcmf_fws_cleanup+0x1e4/0x22c)
|
||||
[<805bb6c4>] (brcmf_fws_cleanup) from [<805bc854>] (brcmf_fws_del_interface+0x58/0x68)
|
||||
[<805bc854>] (brcmf_fws_del_interface) from [<805b66ac>] (brcmf_remove_interface+0x40/0x150)
|
||||
[<805b66ac>] (brcmf_remove_interface) from [<805b6870>] (brcmf_detach+0x6c/0xb0)
|
||||
[<805b6870>] (brcmf_detach) from [<805bdbb8>] (brcmf_usb_disconnect+0x30/0x4c)
|
||||
[<805bdbb8>] (brcmf_usb_disconnect) from [<805e5d64>] (usb_unbind_interface+0x5c/0x1e0)
|
||||
[<805e5d64>] (usb_unbind_interface) from [<804aab10>] (device_release_driver_internal+0x154/0x1ec)
|
||||
[<804aab10>] (device_release_driver_internal) from [<804a97f4>] (bus_remove_device+0xcc/0xf8)
|
||||
[<804a97f4>] (bus_remove_device) from [<804a6fc0>] (device_del+0x118/0x308)
|
||||
[<804a6fc0>] (device_del) from [<805e488c>] (usb_disable_device+0xa0/0x1c8)
|
||||
[<805e488c>] (usb_disable_device) from [<805dcf98>] (usb_disconnect+0x70/0x1d8)
|
||||
[<805dcf98>] (usb_disconnect) from [<805ddd84>] (hub_event+0x464/0xf50)
|
||||
[<805ddd84>] (hub_event) from [<80135a70>] (process_one_work+0x138/0x3f8)
|
||||
[<80135a70>] (process_one_work) from [<80135d5c>] (worker_thread+0x2c/0x554)
|
||||
[<80135d5c>] (worker_thread) from [<8013b1a0>] (kthread+0x124/0x154)
|
||||
[<8013b1a0>] (kthread) from [<801010e8>] (ret_from_fork+0x14/0x2c)
|
||||
Exception stack(0xecf8dfb0 to 0xecf8dff8)
|
||||
dfa0: 00000000 00000000 00000000 00000000
|
||||
dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
dfe0: 00000000 00000000 00000000 00000000 00000013 00000000
|
||||
---[ end trace 38d234018e9e2a90 ]---
|
||||
------------[ cut here ]------------
|
||||
|
||||
Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
.../broadcom/brcm80211/brcmfmac/fwsignal.c | 42 +++++++++++--------
|
||||
1 file changed, 24 insertions(+), 18 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
|
||||
@@ -580,24 +580,6 @@ static bool brcmf_fws_ifidx_match(struct
|
||||
return ifidx == *(int *)arg;
|
||||
}
|
||||
|
||||
-static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q,
|
||||
- int ifidx)
|
||||
-{
|
||||
- bool (*matchfn)(struct sk_buff *, void *) = NULL;
|
||||
- struct sk_buff *skb;
|
||||
- int prec;
|
||||
-
|
||||
- if (ifidx != -1)
|
||||
- matchfn = brcmf_fws_ifidx_match;
|
||||
- for (prec = 0; prec < q->num_prec; prec++) {
|
||||
- skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
|
||||
- while (skb) {
|
||||
- brcmu_pkt_buf_free_skb(skb);
|
||||
- skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
|
||||
- }
|
||||
- }
|
||||
-}
|
||||
-
|
||||
static void brcmf_fws_hanger_init(struct brcmf_fws_hanger *hanger)
|
||||
{
|
||||
int i;
|
||||
@@ -669,6 +651,28 @@ static inline int brcmf_fws_hanger_poppk
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q,
|
||||
+ int ifidx)
|
||||
+{
|
||||
+ bool (*matchfn)(struct sk_buff *, void *) = NULL;
|
||||
+ struct sk_buff *skb;
|
||||
+ int prec;
|
||||
+ u32 hslot;
|
||||
+
|
||||
+ if (ifidx != -1)
|
||||
+ matchfn = brcmf_fws_ifidx_match;
|
||||
+ for (prec = 0; prec < q->num_prec; prec++) {
|
||||
+ skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
|
||||
+ while (skb) {
|
||||
+ hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
|
||||
+ brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
|
||||
+ true);
|
||||
+ brcmu_pkt_buf_free_skb(skb);
|
||||
+ skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h,
|
||||
u32 slot_id)
|
||||
{
|
||||
@@ -2200,6 +2204,8 @@ void brcmf_fws_del_interface(struct brcm
|
||||
brcmf_fws_lock(fws);
|
||||
ifp->fws_desc = NULL;
|
||||
brcmf_dbg(TRACE, "deleting %s\n", entry->name);
|
||||
+ brcmf_fws_macdesc_cleanup(fws, &fws->desc.iface[ifp->ifidx],
|
||||
+ ifp->ifidx);
|
||||
brcmf_fws_macdesc_deinit(entry);
|
||||
brcmf_fws_cleanup(fws, ifp->ifidx);
|
||||
brcmf_fws_unlock(fws);
|
|
@ -0,0 +1,217 @@
|
|||
From 5cdb0ef6144f47440850553579aa923c20a63f23 Mon Sep 17 00:00:00 2001
|
||||
From: Piotr Figiel <p.figiel@camlintechnologies.com>
|
||||
Date: Mon, 4 Mar 2019 15:42:52 +0000
|
||||
Subject: [PATCH] brcmfmac: fix NULL pointer derefence during USB disconnect
|
||||
|
||||
In case USB disconnect happens at the moment transmitting workqueue is in
|
||||
progress the underlying interface may be gone causing a NULL pointer
|
||||
dereference. Add synchronization of the workqueue destruction with the
|
||||
detach implementation in core so that the transmitting workqueue is stopped
|
||||
during detach before the interfaces are removed.
|
||||
|
||||
Fix following Oops:
|
||||
|
||||
Unable to handle kernel NULL pointer dereference at virtual address 00000008
|
||||
pgd = 9e6a802d
|
||||
[00000008] *pgd=00000000
|
||||
Internal error: Oops: 5 [#1] PREEMPT SMP ARM
|
||||
Modules linked in: nf_log_ipv4 nf_log_common xt_LOG xt_limit iptable_mangle
|
||||
xt_connmark xt_tcpudp xt_conntrack nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4
|
||||
iptable_filter ip_tables x_tables usb_f_mass_storage usb_f_rndis u_ether
|
||||
usb_serial_simple usbserial cdc_acm brcmfmac brcmutil smsc95xx usbnet
|
||||
ci_hdrc_imx ci_hdrc ulpi usbmisc_imx 8250_exar 8250_pci 8250 8250_base
|
||||
libcomposite configfs udc_core
|
||||
CPU: 0 PID: 7 Comm: kworker/u8:0 Not tainted 4.19.23-00076-g03740aa-dirty #102
|
||||
Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
|
||||
Workqueue: brcmf_fws_wq brcmf_fws_dequeue_worker [brcmfmac]
|
||||
PC is at brcmf_txfinalize+0x34/0x90 [brcmfmac]
|
||||
LR is at brcmf_fws_dequeue_worker+0x218/0x33c [brcmfmac]
|
||||
pc : [<7f0dee64>] lr : [<7f0e4140>] psr: 60010093
|
||||
sp : ee8abef0 ip : 00000000 fp : edf38000
|
||||
r10: ffffffed r9 : edf38970 r8 : edf38004
|
||||
r7 : edf3e970 r6 : 00000000 r5 : ede69000 r4 : 00000000
|
||||
r3 : 00000a97 r2 : 00000000 r1 : 0000888e r0 : ede69000
|
||||
Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment none
|
||||
Control: 10c5387d Table: 7d03c04a DAC: 00000051
|
||||
Process kworker/u8:0 (pid: 7, stack limit = 0x24ec3e04)
|
||||
Stack: (0xee8abef0 to 0xee8ac000)
|
||||
bee0: ede69000 00000000 ed56c3e0 7f0e4140
|
||||
bf00: 00000001 00000000 edf38004 edf3e99c ed56c3e0 80d03d00 edfea43a edf3e970
|
||||
bf20: ee809880 ee804200 ee971100 00000000 edf3e974 00000000 ee804200 80135a70
|
||||
bf40: 80d03d00 ee804218 ee809880 ee809894 ee804200 80d03d00 ee804218 ee8aa000
|
||||
bf60: 00000088 80135d5c 00000000 ee829f00 ee829dc0 00000000 ee809880 80135d30
|
||||
bf80: ee829f1c ee873eac 00000000 8013b1a0 ee829dc0 8013b07c 00000000 00000000
|
||||
bfa0: 00000000 00000000 00000000 801010e8 00000000 00000000 00000000 00000000
|
||||
bfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
bfe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000
|
||||
[<7f0dee64>] (brcmf_txfinalize [brcmfmac]) from [<7f0e4140>] (brcmf_fws_dequeue_worker+0x218/0x33c [brcmfmac])
|
||||
[<7f0e4140>] (brcmf_fws_dequeue_worker [brcmfmac]) from [<80135a70>] (process_one_work+0x138/0x3f8)
|
||||
[<80135a70>] (process_one_work) from [<80135d5c>] (worker_thread+0x2c/0x554)
|
||||
[<80135d5c>] (worker_thread) from [<8013b1a0>] (kthread+0x124/0x154)
|
||||
[<8013b1a0>] (kthread) from [<801010e8>] (ret_from_fork+0x14/0x2c)
|
||||
Exception stack(0xee8abfb0 to 0xee8abff8)
|
||||
bfa0: 00000000 00000000 00000000 00000000
|
||||
bfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
bfe0: 00000000 00000000 00000000 00000000 00000013 00000000
|
||||
Code: e1530001 0a000007 e3560000 e1a00005 (05942008)
|
||||
---[ end trace 079239dd31c86e90 ]---
|
||||
|
||||
Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
.../wireless/broadcom/brcm80211/brcmfmac/bcdc.c | 11 +++++++++--
|
||||
.../wireless/broadcom/brcm80211/brcmfmac/bcdc.h | 6 ++++--
|
||||
.../wireless/broadcom/brcm80211/brcmfmac/core.c | 4 +++-
|
||||
.../broadcom/brcm80211/brcmfmac/fwsignal.c | 16 ++++++++++++----
|
||||
.../broadcom/brcm80211/brcmfmac/fwsignal.h | 3 ++-
|
||||
.../wireless/broadcom/brcm80211/brcmfmac/proto.c | 10 ++++++++--
|
||||
.../wireless/broadcom/brcm80211/brcmfmac/proto.h | 3 ++-
|
||||
7 files changed, 40 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
|
||||
@@ -490,11 +490,18 @@ fail:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
-void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr)
|
||||
+void brcmf_proto_bcdc_detach_pre_delif(struct brcmf_pub *drvr)
|
||||
+{
|
||||
+ struct brcmf_bcdc *bcdc = drvr->proto->pd;
|
||||
+
|
||||
+ brcmf_fws_detach_pre_delif(bcdc->fws);
|
||||
+}
|
||||
+
|
||||
+void brcmf_proto_bcdc_detach_post_delif(struct brcmf_pub *drvr)
|
||||
{
|
||||
struct brcmf_bcdc *bcdc = drvr->proto->pd;
|
||||
|
||||
drvr->proto->pd = NULL;
|
||||
- brcmf_fws_detach(bcdc->fws);
|
||||
+ brcmf_fws_detach_post_delif(bcdc->fws);
|
||||
kfree(bcdc);
|
||||
}
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h
|
||||
@@ -18,14 +18,16 @@
|
||||
|
||||
#ifdef CPTCFG_BRCMFMAC_PROTO_BCDC
|
||||
int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr);
|
||||
-void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr);
|
||||
+void brcmf_proto_bcdc_detach_pre_delif(struct brcmf_pub *drvr);
|
||||
+void brcmf_proto_bcdc_detach_post_delif(struct brcmf_pub *drvr);
|
||||
void brcmf_proto_bcdc_txflowblock(struct device *dev, bool state);
|
||||
void brcmf_proto_bcdc_txcomplete(struct device *dev, struct sk_buff *txp,
|
||||
bool success);
|
||||
struct brcmf_fws_info *drvr_to_fws(struct brcmf_pub *drvr);
|
||||
#else
|
||||
static inline int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) { return 0; }
|
||||
-static inline void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr) {}
|
||||
+static void brcmf_proto_bcdc_detach_pre_delif(struct brcmf_pub *drvr) {};
|
||||
+static inline void brcmf_proto_bcdc_detach_post_delif(struct brcmf_pub *drvr) {}
|
||||
#endif
|
||||
|
||||
#endif /* BRCMFMAC_BCDC_H */
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
||||
@@ -1342,6 +1342,8 @@ void brcmf_detach(struct device *dev)
|
||||
|
||||
brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN);
|
||||
|
||||
+ brcmf_proto_detach_pre_delif(drvr);
|
||||
+
|
||||
/* make sure primary interface removed last */
|
||||
for (i = BRCMF_MAX_IFS-1; i > -1; i--)
|
||||
brcmf_remove_interface(drvr->iflist[i], false);
|
||||
@@ -1351,7 +1353,7 @@ void brcmf_detach(struct device *dev)
|
||||
|
||||
brcmf_bus_stop(drvr->bus_if);
|
||||
|
||||
- brcmf_proto_detach(drvr);
|
||||
+ brcmf_proto_detach_post_delif(drvr);
|
||||
|
||||
bus_if->drvr = NULL;
|
||||
wiphy_free(drvr->wiphy);
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
|
||||
@@ -2443,17 +2443,25 @@ struct brcmf_fws_info *brcmf_fws_attach(
|
||||
return fws;
|
||||
|
||||
fail:
|
||||
- brcmf_fws_detach(fws);
|
||||
+ brcmf_fws_detach_pre_delif(fws);
|
||||
+ brcmf_fws_detach_post_delif(fws);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
-void brcmf_fws_detach(struct brcmf_fws_info *fws)
|
||||
+void brcmf_fws_detach_pre_delif(struct brcmf_fws_info *fws)
|
||||
{
|
||||
if (!fws)
|
||||
return;
|
||||
-
|
||||
- if (fws->fws_wq)
|
||||
+ if (fws->fws_wq) {
|
||||
destroy_workqueue(fws->fws_wq);
|
||||
+ fws->fws_wq = NULL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void brcmf_fws_detach_post_delif(struct brcmf_fws_info *fws)
|
||||
+{
|
||||
+ if (!fws)
|
||||
+ return;
|
||||
|
||||
/* cleanup */
|
||||
brcmf_fws_lock(fws);
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
|
||||
@@ -19,7 +19,8 @@
|
||||
#define FWSIGNAL_H_
|
||||
|
||||
struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr);
|
||||
-void brcmf_fws_detach(struct brcmf_fws_info *fws);
|
||||
+void brcmf_fws_detach_pre_delif(struct brcmf_fws_info *fws);
|
||||
+void brcmf_fws_detach_post_delif(struct brcmf_fws_info *fws);
|
||||
void brcmf_fws_debugfs_create(struct brcmf_pub *drvr);
|
||||
bool brcmf_fws_queue_skbs(struct brcmf_fws_info *fws);
|
||||
bool brcmf_fws_fc_active(struct brcmf_fws_info *fws);
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c
|
||||
@@ -67,16 +67,22 @@ fail:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
-void brcmf_proto_detach(struct brcmf_pub *drvr)
|
||||
+void brcmf_proto_detach_post_delif(struct brcmf_pub *drvr)
|
||||
{
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
if (drvr->proto) {
|
||||
if (drvr->bus_if->proto_type == BRCMF_PROTO_BCDC)
|
||||
- brcmf_proto_bcdc_detach(drvr);
|
||||
+ brcmf_proto_bcdc_detach_post_delif(drvr);
|
||||
else if (drvr->bus_if->proto_type == BRCMF_PROTO_MSGBUF)
|
||||
brcmf_proto_msgbuf_detach(drvr);
|
||||
kfree(drvr->proto);
|
||||
drvr->proto = NULL;
|
||||
}
|
||||
}
|
||||
+
|
||||
+void brcmf_proto_detach_pre_delif(struct brcmf_pub *drvr)
|
||||
+{
|
||||
+ if (drvr->proto && drvr->bus_if->proto_type == BRCMF_PROTO_BCDC)
|
||||
+ brcmf_proto_bcdc_detach_pre_delif(drvr);
|
||||
+}
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
|
||||
@@ -54,7 +54,8 @@ struct brcmf_proto {
|
||||
|
||||
|
||||
int brcmf_proto_attach(struct brcmf_pub *drvr);
|
||||
-void brcmf_proto_detach(struct brcmf_pub *drvr);
|
||||
+void brcmf_proto_detach_pre_delif(struct brcmf_pub *drvr);
|
||||
+void brcmf_proto_detach_post_delif(struct brcmf_pub *drvr);
|
||||
|
||||
static inline int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws,
|
||||
struct sk_buff *skb,
|
|
@ -0,0 +1,84 @@
|
|||
From db3b9e2e1d58080d0754bdf9293dabf8c6491b67 Mon Sep 17 00:00:00 2001
|
||||
From: Piotr Figiel <p.figiel@camlintechnologies.com>
|
||||
Date: Fri, 8 Mar 2019 15:25:04 +0000
|
||||
Subject: [PATCH] brcmfmac: fix race during disconnect when USB completion is
|
||||
in progress
|
||||
|
||||
It was observed that rarely during USB disconnect happening shortly after
|
||||
connect (before full initialization completes) usb_hub_wq would wait
|
||||
forever for the dev_init_lock to be unlocked. dev_init_lock would remain
|
||||
locked though because of infinite wait during usb_kill_urb:
|
||||
|
||||
[ 2730.656472] kworker/0:2 D 0 260 2 0x00000000
|
||||
[ 2730.660700] Workqueue: events request_firmware_work_func
|
||||
[ 2730.664807] [<809dca20>] (__schedule) from [<809dd164>] (schedule+0x4c/0xac)
|
||||
[ 2730.670587] [<809dd164>] (schedule) from [<8069af44>] (usb_kill_urb+0xdc/0x114)
|
||||
[ 2730.676815] [<8069af44>] (usb_kill_urb) from [<7f258b50>] (brcmf_usb_free_q+0x34/0xa8 [brcmfmac])
|
||||
[ 2730.684833] [<7f258b50>] (brcmf_usb_free_q [brcmfmac]) from [<7f2517d4>] (brcmf_detach+0xa0/0xb8 [brcmfmac])
|
||||
[ 2730.693557] [<7f2517d4>] (brcmf_detach [brcmfmac]) from [<7f251a34>] (brcmf_attach+0xac/0x3d8 [brcmfmac])
|
||||
[ 2730.702094] [<7f251a34>] (brcmf_attach [brcmfmac]) from [<7f2587ac>] (brcmf_usb_probe_phase2+0x468/0x4a0 [brcmfmac])
|
||||
[ 2730.711601] [<7f2587ac>] (brcmf_usb_probe_phase2 [brcmfmac]) from [<7f252888>] (brcmf_fw_request_done+0x194/0x220 [brcmfmac])
|
||||
[ 2730.721795] [<7f252888>] (brcmf_fw_request_done [brcmfmac]) from [<805748e4>] (request_firmware_work_func+0x4c/0x88)
|
||||
[ 2730.731125] [<805748e4>] (request_firmware_work_func) from [<80141474>] (process_one_work+0x228/0x808)
|
||||
[ 2730.739223] [<80141474>] (process_one_work) from [<80141a80>] (worker_thread+0x2c/0x564)
|
||||
[ 2730.746105] [<80141a80>] (worker_thread) from [<80147bcc>] (kthread+0x13c/0x16c)
|
||||
[ 2730.752227] [<80147bcc>] (kthread) from [<801010b4>] (ret_from_fork+0x14/0x20)
|
||||
|
||||
[ 2733.099695] kworker/0:3 D 0 1065 2 0x00000000
|
||||
[ 2733.103926] Workqueue: usb_hub_wq hub_event
|
||||
[ 2733.106914] [<809dca20>] (__schedule) from [<809dd164>] (schedule+0x4c/0xac)
|
||||
[ 2733.112693] [<809dd164>] (schedule) from [<809e2a8c>] (schedule_timeout+0x214/0x3e4)
|
||||
[ 2733.119621] [<809e2a8c>] (schedule_timeout) from [<809dde2c>] (wait_for_common+0xc4/0x1c0)
|
||||
[ 2733.126810] [<809dde2c>] (wait_for_common) from [<7f258d00>] (brcmf_usb_disconnect+0x1c/0x4c [brcmfmac])
|
||||
[ 2733.135206] [<7f258d00>] (brcmf_usb_disconnect [brcmfmac]) from [<8069e0c8>] (usb_unbind_interface+0x5c/0x1e4)
|
||||
[ 2733.143943] [<8069e0c8>] (usb_unbind_interface) from [<8056d3e8>] (device_release_driver_internal+0x164/0x1fc)
|
||||
[ 2733.152769] [<8056d3e8>] (device_release_driver_internal) from [<8056c078>] (bus_remove_device+0xd0/0xfc)
|
||||
[ 2733.161138] [<8056c078>] (bus_remove_device) from [<8056977c>] (device_del+0x11c/0x310)
|
||||
[ 2733.167939] [<8056977c>] (device_del) from [<8069cba8>] (usb_disable_device+0xa0/0x1cc)
|
||||
[ 2733.174743] [<8069cba8>] (usb_disable_device) from [<8069507c>] (usb_disconnect+0x74/0x1dc)
|
||||
[ 2733.181823] [<8069507c>] (usb_disconnect) from [<80695e88>] (hub_event+0x478/0xf88)
|
||||
[ 2733.188278] [<80695e88>] (hub_event) from [<80141474>] (process_one_work+0x228/0x808)
|
||||
[ 2733.194905] [<80141474>] (process_one_work) from [<80141a80>] (worker_thread+0x2c/0x564)
|
||||
[ 2733.201724] [<80141a80>] (worker_thread) from [<80147bcc>] (kthread+0x13c/0x16c)
|
||||
[ 2733.207913] [<80147bcc>] (kthread) from [<801010b4>] (ret_from_fork+0x14/0x20)
|
||||
|
||||
It was traced down to a case where usb_kill_urb would be called on an URB
|
||||
structure containing more or less random data, including large number in
|
||||
its use_count. During the debugging it appeared that in brcmf_usb_free_q()
|
||||
the traversal over URBs' lists is not synchronized with operations on those
|
||||
lists in brcmf_usb_rx_complete() leading to handling
|
||||
brcmf_usbdev_info structure (holding lists' head) as lists' element and in
|
||||
result causing above problem.
|
||||
|
||||
Fix it by walking through all URBs during brcmf_cancel_all_urbs using the
|
||||
arrays of requests instead of linked lists.
|
||||
|
||||
Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
|
||||
@@ -682,12 +682,18 @@ static int brcmf_usb_up(struct device *d
|
||||
|
||||
static void brcmf_cancel_all_urbs(struct brcmf_usbdev_info *devinfo)
|
||||
{
|
||||
+ int i;
|
||||
+
|
||||
if (devinfo->ctl_urb)
|
||||
usb_kill_urb(devinfo->ctl_urb);
|
||||
if (devinfo->bulk_urb)
|
||||
usb_kill_urb(devinfo->bulk_urb);
|
||||
- brcmf_usb_free_q(&devinfo->tx_postq, true);
|
||||
- brcmf_usb_free_q(&devinfo->rx_postq, true);
|
||||
+ if (devinfo->tx_reqs)
|
||||
+ for (i = 0; i < devinfo->bus_pub.ntxq; i++)
|
||||
+ usb_kill_urb(devinfo->tx_reqs[i].urb);
|
||||
+ if (devinfo->rx_reqs)
|
||||
+ for (i = 0; i < devinfo->bus_pub.nrxq; i++)
|
||||
+ usb_kill_urb(devinfo->rx_reqs[i].urb);
|
||||
}
|
||||
|
||||
static void brcmf_usb_down(struct device *dev)
|
|
@ -0,0 +1,54 @@
|
|||
From 2b78e5f5223666d403d4fdb30af4ad65c8da3cdb Mon Sep 17 00:00:00 2001
|
||||
From: Piotr Figiel <p.figiel@camlintechnologies.com>
|
||||
Date: Fri, 8 Mar 2019 15:25:06 +0000
|
||||
Subject: [PATCH] brcmfmac: remove pending parameter from brcmf_usb_free_q
|
||||
|
||||
brcmf_usb_free_q is no longer called with pending=true thus this boolean
|
||||
parameter is no longer needed.
|
||||
|
||||
Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
.../wireless/broadcom/brcm80211/brcmfmac/usb.c | 15 ++++++---------
|
||||
1 file changed, 6 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
|
||||
@@ -445,9 +445,10 @@ fail:
|
||||
|
||||
}
|
||||
|
||||
-static void brcmf_usb_free_q(struct list_head *q, bool pending)
|
||||
+static void brcmf_usb_free_q(struct list_head *q)
|
||||
{
|
||||
struct brcmf_usbreq *req, *next;
|
||||
+
|
||||
int i = 0;
|
||||
list_for_each_entry_safe(req, next, q, list) {
|
||||
if (!req->urb) {
|
||||
@@ -455,12 +456,8 @@ static void brcmf_usb_free_q(struct list
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
- if (pending) {
|
||||
- usb_kill_urb(req->urb);
|
||||
- } else {
|
||||
- usb_free_urb(req->urb);
|
||||
- list_del_init(&req->list);
|
||||
- }
|
||||
+ usb_free_urb(req->urb);
|
||||
+ list_del_init(&req->list);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1029,8 +1026,8 @@ static void brcmf_usb_detach(struct brcm
|
||||
brcmf_dbg(USB, "Enter, devinfo %p\n", devinfo);
|
||||
|
||||
/* free the URBS */
|
||||
- brcmf_usb_free_q(&devinfo->rx_freeq, false);
|
||||
- brcmf_usb_free_q(&devinfo->tx_freeq, false);
|
||||
+ brcmf_usb_free_q(&devinfo->rx_freeq);
|
||||
+ brcmf_usb_free_q(&devinfo->tx_freeq);
|
||||
|
||||
usb_free_urb(devinfo->ctl_urb);
|
||||
usb_free_urb(devinfo->bulk_urb);
|
|
@ -0,0 +1,29 @@
|
|||
From 504f06725d015954a0fcafdf1d90a6795ca8f769 Mon Sep 17 00:00:00 2001
|
||||
From: Piotr Figiel <p.figiel@camlintechnologies.com>
|
||||
Date: Fri, 8 Mar 2019 15:25:09 +0000
|
||||
Subject: [PATCH] brcmfmac: remove unused variable i from brcmf_usb_free_q
|
||||
|
||||
Variable i is not used so remove it.
|
||||
|
||||
Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 2 --
|
||||
1 file changed, 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
|
||||
@@ -449,13 +449,11 @@ static void brcmf_usb_free_q(struct list
|
||||
{
|
||||
struct brcmf_usbreq *req, *next;
|
||||
|
||||
- int i = 0;
|
||||
list_for_each_entry_safe(req, next, q, list) {
|
||||
if (!req->urb) {
|
||||
brcmf_err("bad req\n");
|
||||
break;
|
||||
}
|
||||
- i++;
|
||||
usb_free_urb(req->urb);
|
||||
list_del_init(&req->list);
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
From 24d413a31afaee9bbbf79226052c386b01780ce2 Mon Sep 17 00:00:00 2001
|
||||
From: Piotr Figiel <p.figiel@camlintechnologies.com>
|
||||
Date: Wed, 13 Mar 2019 09:52:01 +0000
|
||||
Subject: [PATCH] brcmfmac: fix Oops when bringing up interface during USB
|
||||
disconnect
|
||||
|
||||
Fix a race which leads to an Oops with NULL pointer dereference. The
|
||||
dereference is in brcmf_config_dongle() when cfg_to_ndev() attempts to get
|
||||
net_device structure of interface with index 0 via if2bss mapping. This
|
||||
shouldn't fail because of check for bus being ready in brcmf_netdev_open(),
|
||||
but it's not synchronised with USB disconnect and there is a race: after
|
||||
the check the bus can be marked down and the mapping for interface 0 may be
|
||||
gone.
|
||||
|
||||
Solve this by modifying disconnect handling so that the removal of mapping
|
||||
of ifidx to brcmf_if structure happens after netdev removal (which is
|
||||
synchronous with brcmf_netdev_open() thanks to rtln being locked in
|
||||
devinet_ioctl()). This assures brcmf_netdev_open() returns before the
|
||||
mapping is removed during disconnect.
|
||||
|
||||
Unable to handle kernel NULL pointer dereference at virtual address 00000008
|
||||
pgd = bcae2612
|
||||
[00000008] *pgd=8be73831
|
||||
Internal error: Oops: 17 [#1] PREEMPT SMP ARM
|
||||
Modules linked in: brcmfmac brcmutil nf_log_ipv4 nf_log_common xt_LOG xt_limit
|
||||
iptable_mangle xt_connmark xt_tcpudp xt_conntrack nf_conntrack nf_defrag_ipv6
|
||||
nf_defrag_ipv4 iptable_filter ip_tables x_tables usb_f_mass_storage usb_f_rndis
|
||||
u_ether usb_serial_simple usbserial cdc_acm smsc95xx usbnet ci_hdrc_imx ci_hdrc
|
||||
usbmisc_imx ulpi 8250_exar 8250_pci 8250 8250_base libcomposite configfs
|
||||
udc_core [last unloaded: brcmutil]
|
||||
CPU: 2 PID: 24478 Comm: ifconfig Not tainted 4.19.23-00078-ga62866d-dirty #115
|
||||
Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
|
||||
PC is at brcmf_cfg80211_up+0x94/0x29c [brcmfmac]
|
||||
LR is at brcmf_cfg80211_up+0x8c/0x29c [brcmfmac]
|
||||
pc : [<7f26a91c>] lr : [<7f26a914>] psr: a0070013
|
||||
sp : eca99d28 ip : 00000000 fp : ee9c6c00
|
||||
r10: 00000036 r9 : 00000000 r8 : ece4002c
|
||||
r7 : edb5b800 r6 : 00000000 r5 : 80f08448 r4 : edb5b968
|
||||
r3 : ffffffff r2 : 00000000 r1 : 00000002 r0 : 00000000
|
||||
Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none
|
||||
Control: 10c5387d Table: 7ca0c04a DAC: 00000051
|
||||
Process ifconfig (pid: 24478, stack limit = 0xd9e85a0e)
|
||||
Stack: (0xeca99d28 to 0xeca9a000)
|
||||
9d20: 00000000 80f873b0 0000000d 80f08448 eca99d68 50d45f32
|
||||
9d40: 7f27de94 ece40000 80f08448 80f08448 7f27de94 ece4002c 00000000 00000036
|
||||
9d60: ee9c6c00 7f27262c 00001002 50d45f32 ece40000 00000000 80f08448 80772008
|
||||
9d80: 00000001 00001043 00001002 ece40000 00000000 50d45f32 ece40000 00000001
|
||||
9da0: 80f08448 00001043 00001002 807723d0 00000000 50d45f32 80f08448 eca99e58
|
||||
9dc0: 80f87113 50d45f32 80f08448 ece40000 ece40138 00001002 80f08448 00000000
|
||||
9de0: 00000000 80772434 edbd5380 eca99e58 edbd5380 80f08448 ee9c6c0c 80805f70
|
||||
9e00: 00000000 ede08e00 00008914 ece40000 00000014 ee9c6c0c 600c0013 00001043
|
||||
9e20: 0208a8c0 ffffffff 00000000 50d45f32 eca98000 80f08448 7ee9fc38 00008914
|
||||
9e40: 80f68e40 00000051 eca98000 00000036 00000003 80808b9c 6e616c77 00000030
|
||||
9e60: 00000000 00000000 00001043 0208a8c0 ffffffff 00000000 80f08448 00000000
|
||||
9e80: 00000000 816d8b20 600c0013 00000001 ede09320 801763d4 00000000 50d45f32
|
||||
9ea0: eca98000 80f08448 7ee9fc38 50d45f32 00008914 80f08448 7ee9fc38 80f68e40
|
||||
9ec0: ed531540 8074721c 00000800 00000001 00000000 6e616c77 00000030 00000000
|
||||
9ee0: 00000000 00001002 0208a8c0 ffffffff 00000000 50d45f32 80f08448 7ee9fc38
|
||||
9f00: ed531560 ec8fc900 80285a6c 80285138 edb910c0 00000000 ecd91008 ede08e00
|
||||
9f20: 80f08448 00000000 00000000 816d8b20 600c0013 00000001 ede09320 801763d4
|
||||
9f40: 00000000 50d45f32 00021000 edb91118 edb910c0 80f08448 01b29000 edb91118
|
||||
9f60: eca99f7c 50d45f32 00021000 ec8fc900 00000003 ec8fc900 00008914 7ee9fc38
|
||||
9f80: eca98000 00000036 00000003 80285a6c 00086364 7ee9fe1c 000000c3 00000036
|
||||
9fa0: 801011c4 80101000 00086364 7ee9fe1c 00000003 00008914 7ee9fc38 00086364
|
||||
9fc0: 00086364 7ee9fe1c 000000c3 00000036 0008630c 7ee9fe1c 7ee9fc38 00000003
|
||||
9fe0: 000a42b8 7ee9fbd4 00019914 76e09acc 600c0010 00000003 00000000 00000000
|
||||
[<7f26a91c>] (brcmf_cfg80211_up [brcmfmac]) from [<7f27262c>] (brcmf_netdev_open+0x74/0xe8 [brcmfmac])
|
||||
[<7f27262c>] (brcmf_netdev_open [brcmfmac]) from [<80772008>] (__dev_open+0xcc/0x150)
|
||||
[<80772008>] (__dev_open) from [<807723d0>] (__dev_change_flags+0x168/0x1b4)
|
||||
[<807723d0>] (__dev_change_flags) from [<80772434>] (dev_change_flags+0x18/0x48)
|
||||
[<80772434>] (dev_change_flags) from [<80805f70>] (devinet_ioctl+0x67c/0x79c)
|
||||
[<80805f70>] (devinet_ioctl) from [<80808b9c>] (inet_ioctl+0x210/0x3d4)
|
||||
[<80808b9c>] (inet_ioctl) from [<8074721c>] (sock_ioctl+0x350/0x524)
|
||||
[<8074721c>] (sock_ioctl) from [<80285138>] (do_vfs_ioctl+0xb0/0x9b0)
|
||||
[<80285138>] (do_vfs_ioctl) from [<80285a6c>] (ksys_ioctl+0x34/0x5c)
|
||||
[<80285a6c>] (ksys_ioctl) from [<80101000>] (ret_fast_syscall+0x0/0x28)
|
||||
Exception stack(0xeca99fa8 to 0xeca99ff0)
|
||||
9fa0: 00086364 7ee9fe1c 00000003 00008914 7ee9fc38 00086364
|
||||
9fc0: 00086364 7ee9fe1c 000000c3 00000036 0008630c 7ee9fe1c 7ee9fc38 00000003
|
||||
9fe0: 000a42b8 7ee9fbd4 00019914 76e09acc
|
||||
Code: e5970328 eb002021 e1a02006 e3a01002 (e5909008)
|
||||
---[ end trace 5cbac2333f3ac5df ]---
|
||||
|
||||
Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
.../net/wireless/broadcom/brcm80211/brcmfmac/core.c | 10 +++++++---
|
||||
1 file changed, 7 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
||||
@@ -862,17 +862,17 @@ static void brcmf_del_if(struct brcmf_pu
|
||||
bool rtnl_locked)
|
||||
{
|
||||
struct brcmf_if *ifp;
|
||||
+ int ifidx;
|
||||
|
||||
ifp = drvr->iflist[bsscfgidx];
|
||||
- drvr->iflist[bsscfgidx] = NULL;
|
||||
if (!ifp) {
|
||||
bphy_err(drvr, "Null interface, bsscfgidx=%d\n", bsscfgidx);
|
||||
return;
|
||||
}
|
||||
brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, ifidx=%d\n", bsscfgidx,
|
||||
ifp->ifidx);
|
||||
- if (drvr->if2bss[ifp->ifidx] == bsscfgidx)
|
||||
- drvr->if2bss[ifp->ifidx] = BRCMF_BSSIDX_INVALID;
|
||||
+ ifidx = ifp->ifidx;
|
||||
+
|
||||
if (ifp->ndev) {
|
||||
if (bsscfgidx == 0) {
|
||||
if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
|
||||
@@ -900,6 +900,10 @@ static void brcmf_del_if(struct brcmf_pu
|
||||
brcmf_p2p_ifp_removed(ifp, rtnl_locked);
|
||||
kfree(ifp);
|
||||
}
|
||||
+
|
||||
+ drvr->iflist[bsscfgidx] = NULL;
|
||||
+ if (drvr->if2bss[ifidx] == bsscfgidx)
|
||||
+ drvr->if2bss[ifidx] = BRCMF_BSSIDX_INVALID;
|
||||
}
|
||||
|
||||
void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked)
|
|
@ -0,0 +1,182 @@
|
|||
From a9fd0953fa4a62887306be28641b4b0809f3b2fd Mon Sep 17 00:00:00 2001
|
||||
From: Piotr Figiel <p.figiel@camlintechnologies.com>
|
||||
Date: Wed, 13 Mar 2019 09:52:42 +0000
|
||||
Subject: [PATCH] brcmfmac: convert dev_init_lock mutex to completion
|
||||
|
||||
Leaving dev_init_lock mutex locked in probe causes BUG and a WARNING when
|
||||
kernel is compiled with CONFIG_PROVE_LOCKING. Convert mutex to completion
|
||||
which silences those warnings and improves code readability.
|
||||
|
||||
Fix below errors when connecting the USB WiFi dongle:
|
||||
|
||||
brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac43143 for chip BCM43143/2
|
||||
BUG: workqueue leaked lock or atomic: kworker/0:2/0x00000000/434
|
||||
last function: hub_event
|
||||
1 lock held by kworker/0:2/434:
|
||||
#0: 18d5dcdf (&devinfo->dev_init_lock){+.+.}, at: brcmf_usb_probe+0x78/0x550 [brcmfmac]
|
||||
CPU: 0 PID: 434 Comm: kworker/0:2 Not tainted 4.19.23-00084-g454a789-dirty #123
|
||||
Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
|
||||
Workqueue: usb_hub_wq hub_event
|
||||
[<8011237c>] (unwind_backtrace) from [<8010d74c>] (show_stack+0x10/0x14)
|
||||
[<8010d74c>] (show_stack) from [<809c4324>] (dump_stack+0xa8/0xd4)
|
||||
[<809c4324>] (dump_stack) from [<8014195c>] (process_one_work+0x710/0x808)
|
||||
[<8014195c>] (process_one_work) from [<80141a80>] (worker_thread+0x2c/0x564)
|
||||
[<80141a80>] (worker_thread) from [<80147bcc>] (kthread+0x13c/0x16c)
|
||||
[<80147bcc>] (kthread) from [<801010b4>] (ret_from_fork+0x14/0x20)
|
||||
Exception stack(0xed1d9fb0 to 0xed1d9ff8)
|
||||
9fa0: 00000000 00000000 00000000 00000000
|
||||
9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
9fe0: 00000000 00000000 00000000 00000000 00000013 00000000
|
||||
|
||||
======================================================
|
||||
WARNING: possible circular locking dependency detected
|
||||
4.19.23-00084-g454a789-dirty #123 Not tainted
|
||||
------------------------------------------------------
|
||||
kworker/0:2/434 is trying to acquire lock:
|
||||
e29cf799 ((wq_completion)"events"){+.+.}, at: process_one_work+0x174/0x808
|
||||
|
||||
but task is already holding lock:
|
||||
18d5dcdf (&devinfo->dev_init_lock){+.+.}, at: brcmf_usb_probe+0x78/0x550 [brcmfmac]
|
||||
|
||||
which lock already depends on the new lock.
|
||||
|
||||
the existing dependency chain (in reverse order) is:
|
||||
|
||||
-> #2 (&devinfo->dev_init_lock){+.+.}:
|
||||
mutex_lock_nested+0x1c/0x24
|
||||
brcmf_usb_probe+0x78/0x550 [brcmfmac]
|
||||
usb_probe_interface+0xc0/0x1bc
|
||||
really_probe+0x228/0x2c0
|
||||
__driver_attach+0xe4/0xe8
|
||||
bus_for_each_dev+0x68/0xb4
|
||||
bus_add_driver+0x19c/0x214
|
||||
driver_register+0x78/0x110
|
||||
usb_register_driver+0x84/0x148
|
||||
process_one_work+0x228/0x808
|
||||
worker_thread+0x2c/0x564
|
||||
kthread+0x13c/0x16c
|
||||
ret_from_fork+0x14/0x20
|
||||
(null)
|
||||
|
||||
-> #1 (brcmf_driver_work){+.+.}:
|
||||
worker_thread+0x2c/0x564
|
||||
kthread+0x13c/0x16c
|
||||
ret_from_fork+0x14/0x20
|
||||
(null)
|
||||
|
||||
-> #0 ((wq_completion)"events"){+.+.}:
|
||||
process_one_work+0x1b8/0x808
|
||||
worker_thread+0x2c/0x564
|
||||
kthread+0x13c/0x16c
|
||||
ret_from_fork+0x14/0x20
|
||||
(null)
|
||||
|
||||
other info that might help us debug this:
|
||||
|
||||
Chain exists of:
|
||||
(wq_completion)"events" --> brcmf_driver_work --> &devinfo->dev_init_lock
|
||||
|
||||
Possible unsafe locking scenario:
|
||||
|
||||
CPU0 CPU1
|
||||
---- ----
|
||||
lock(&devinfo->dev_init_lock);
|
||||
lock(brcmf_driver_work);
|
||||
lock(&devinfo->dev_init_lock);
|
||||
lock((wq_completion)"events");
|
||||
|
||||
*** DEADLOCK ***
|
||||
|
||||
1 lock held by kworker/0:2/434:
|
||||
#0: 18d5dcdf (&devinfo->dev_init_lock){+.+.}, at: brcmf_usb_probe+0x78/0x550 [brcmfmac]
|
||||
|
||||
stack backtrace:
|
||||
CPU: 0 PID: 434 Comm: kworker/0:2 Not tainted 4.19.23-00084-g454a789-dirty #123
|
||||
Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
|
||||
Workqueue: events request_firmware_work_func
|
||||
[<8011237c>] (unwind_backtrace) from [<8010d74c>] (show_stack+0x10/0x14)
|
||||
[<8010d74c>] (show_stack) from [<809c4324>] (dump_stack+0xa8/0xd4)
|
||||
[<809c4324>] (dump_stack) from [<80172838>] (print_circular_bug+0x210/0x330)
|
||||
[<80172838>] (print_circular_bug) from [<80175940>] (__lock_acquire+0x160c/0x1a30)
|
||||
[<80175940>] (__lock_acquire) from [<8017671c>] (lock_acquire+0xe0/0x268)
|
||||
[<8017671c>] (lock_acquire) from [<80141404>] (process_one_work+0x1b8/0x808)
|
||||
[<80141404>] (process_one_work) from [<80141a80>] (worker_thread+0x2c/0x564)
|
||||
[<80141a80>] (worker_thread) from [<80147bcc>] (kthread+0x13c/0x16c)
|
||||
[<80147bcc>] (kthread) from [<801010b4>] (ret_from_fork+0x14/0x20)
|
||||
Exception stack(0xed1d9fb0 to 0xed1d9ff8)
|
||||
9fa0: 00000000 00000000 00000000 00000000
|
||||
9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
9fe0: 00000000 00000000 00000000 00000000 00000013 00000000
|
||||
|
||||
Signed-off-by: Piotr Figiel <p.figiel@camlintechnologies.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
.../wireless/broadcom/brcm80211/brcmfmac/usb.c | 17 ++++++++---------
|
||||
1 file changed, 8 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
|
||||
@@ -160,7 +160,7 @@ struct brcmf_usbdev_info {
|
||||
|
||||
struct usb_device *usbdev;
|
||||
struct device *dev;
|
||||
- struct mutex dev_init_lock;
|
||||
+ struct completion dev_init_done;
|
||||
|
||||
int ctl_in_pipe, ctl_out_pipe;
|
||||
struct urb *ctl_urb; /* URB for control endpoint */
|
||||
@@ -1194,11 +1194,11 @@ static void brcmf_usb_probe_phase2(struc
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
- mutex_unlock(&devinfo->dev_init_lock);
|
||||
+ complete(&devinfo->dev_init_done);
|
||||
return;
|
||||
error:
|
||||
brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), ret);
|
||||
- mutex_unlock(&devinfo->dev_init_lock);
|
||||
+ complete(&devinfo->dev_init_done);
|
||||
device_release_driver(dev);
|
||||
}
|
||||
|
||||
@@ -1266,7 +1266,7 @@ static int brcmf_usb_probe_cb(struct brc
|
||||
if (ret)
|
||||
goto fail;
|
||||
/* we are done */
|
||||
- mutex_unlock(&devinfo->dev_init_lock);
|
||||
+ complete(&devinfo->dev_init_done);
|
||||
return 0;
|
||||
}
|
||||
bus->chip = bus_pub->devid;
|
||||
@@ -1326,11 +1326,10 @@ brcmf_usb_probe(struct usb_interface *in
|
||||
|
||||
devinfo->usbdev = usb;
|
||||
devinfo->dev = &usb->dev;
|
||||
- /* Take an init lock, to protect for disconnect while still loading.
|
||||
+ /* Init completion, to protect for disconnect while still loading.
|
||||
* Necessary because of the asynchronous firmware load construction
|
||||
*/
|
||||
- mutex_init(&devinfo->dev_init_lock);
|
||||
- mutex_lock(&devinfo->dev_init_lock);
|
||||
+ init_completion(&devinfo->dev_init_done);
|
||||
|
||||
usb_set_intfdata(intf, devinfo);
|
||||
|
||||
@@ -1408,7 +1407,7 @@ brcmf_usb_probe(struct usb_interface *in
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
- mutex_unlock(&devinfo->dev_init_lock);
|
||||
+ complete(&devinfo->dev_init_done);
|
||||
kfree(devinfo);
|
||||
usb_set_intfdata(intf, NULL);
|
||||
return ret;
|
||||
@@ -1423,7 +1422,7 @@ brcmf_usb_disconnect(struct usb_interfac
|
||||
devinfo = (struct brcmf_usbdev_info *)usb_get_intfdata(intf);
|
||||
|
||||
if (devinfo) {
|
||||
- mutex_lock(&devinfo->dev_init_lock);
|
||||
+ wait_for_completion(&devinfo->dev_init_done);
|
||||
/* Make sure that devinfo still exists. Firmware probe routines
|
||||
* may have released the device and cleared the intfdata.
|
||||
*/
|
|
@ -0,0 +1,35 @@
|
|||
From 46953f97224d56a12ccbe9c6acaa84ca0dab2780 Mon Sep 17 00:00:00 2001
|
||||
From: Kangjie Lu <kjlu@umn.edu>
|
||||
Date: Fri, 15 Mar 2019 12:04:32 -0500
|
||||
Subject: [PATCH] brcmfmac: fix missing checks for kmemdup
|
||||
|
||||
In case kmemdup fails, the fix sets conn_info->req_ie_len and
|
||||
conn_info->resp_ie_len to zero to avoid buffer overflows.
|
||||
|
||||
Signed-off-by: Kangjie Lu <kjlu@umn.edu>
|
||||
Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
||||
@@ -5456,6 +5456,8 @@ static s32 brcmf_get_assoc_ies(struct br
|
||||
conn_info->req_ie =
|
||||
kmemdup(cfg->extra_buf, conn_info->req_ie_len,
|
||||
GFP_KERNEL);
|
||||
+ if (!conn_info->req_ie)
|
||||
+ conn_info->req_ie_len = 0;
|
||||
} else {
|
||||
conn_info->req_ie_len = 0;
|
||||
conn_info->req_ie = NULL;
|
||||
@@ -5472,6 +5474,8 @@ static s32 brcmf_get_assoc_ies(struct br
|
||||
conn_info->resp_ie =
|
||||
kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
|
||||
GFP_KERNEL);
|
||||
+ if (!conn_info->resp_ie)
|
||||
+ conn_info->resp_ie_len = 0;
|
||||
} else {
|
||||
conn_info->resp_ie_len = 0;
|
||||
conn_info->resp_ie = NULL;
|
|
@ -0,0 +1,53 @@
|
|||
From 0cf83903aad03dc7f444a47990def48c4a9d3276 Mon Sep 17 00:00:00 2001
|
||||
From: "Gustavo A. R. Silva" <gustavo@embeddedor.com>
|
||||
Date: Wed, 3 Apr 2019 11:46:11 -0500
|
||||
Subject: [PATCH] brcmfmac: Use struct_size() in kzalloc()
|
||||
|
||||
One of the more common cases of allocation size calculations is finding
|
||||
the size of a structure that has a zero-sized array at the end, along
|
||||
with memory for some number of elements for that array. For example:
|
||||
|
||||
struct foo {
|
||||
int stuff;
|
||||
struct boo entry[];
|
||||
};
|
||||
|
||||
size = sizeof(struct foo) + count * sizeof(struct boo);
|
||||
instance = kzalloc(size, GFP_KERNEL)
|
||||
|
||||
Instead of leaving these open-coded and prone to type mistakes, we can
|
||||
now use the new struct_size() helper:
|
||||
|
||||
instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL)
|
||||
|
||||
Notice that, in this case, variable reqsz is not necessary,
|
||||
hence it is removed.
|
||||
|
||||
This code was detected with the help of Coccinelle.
|
||||
|
||||
Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | 4 +---
|
||||
1 file changed, 1 insertion(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
|
||||
@@ -711,7 +711,6 @@ brcmf_fw_alloc_request(u32 chip, u32 chi
|
||||
size_t mp_path_len;
|
||||
u32 i, j;
|
||||
char end = '\0';
|
||||
- size_t reqsz;
|
||||
|
||||
for (i = 0; i < table_size; i++) {
|
||||
if (mapping_table[i].chipid == chip &&
|
||||
@@ -726,8 +725,7 @@ brcmf_fw_alloc_request(u32 chip, u32 chi
|
||||
return NULL;
|
||||
}
|
||||
|
||||
- reqsz = sizeof(*fwreq) + n_fwnames * sizeof(struct brcmf_fw_item);
|
||||
- fwreq = kzalloc(reqsz, GFP_KERNEL);
|
||||
+ fwreq = kzalloc(struct_size(fwreq, items, n_fwnames), GFP_KERNEL);
|
||||
if (!fwreq)
|
||||
return NULL;
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
From e3062e05e1cfe378bb9b3fa0bef46711372bcf13 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Jirman <megous@megous.com>
|
||||
Date: Sat, 6 Apr 2019 01:45:13 +0200
|
||||
Subject: [PATCH] brcmfmac: Loading the correct firmware for brcm43456
|
||||
|
||||
SDIO based brcm43456 is currently misdetected as brcm43455 and the wrong
|
||||
firmware name is used. Correct the detection and load the correct
|
||||
firmware file. Chiprev for brcm43456 is "9".
|
||||
|
||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
||||
@@ -622,6 +622,7 @@ BRCMF_FW_DEF(43430A0, "brcmfmac43430a0-s
|
||||
/* Note the names are not postfixed with a1 for backward compatibility */
|
||||
BRCMF_FW_DEF(43430A1, "brcmfmac43430-sdio");
|
||||
BRCMF_FW_DEF(43455, "brcmfmac43455-sdio");
|
||||
+BRCMF_FW_DEF(43456, "brcmfmac43456-sdio");
|
||||
BRCMF_FW_DEF(4354, "brcmfmac4354-sdio");
|
||||
BRCMF_FW_DEF(4356, "brcmfmac4356-sdio");
|
||||
BRCMF_FW_DEF(4373, "brcmfmac4373-sdio");
|
||||
@@ -642,7 +643,8 @@ static const struct brcmf_firmware_mappi
|
||||
BRCMF_FW_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339),
|
||||
BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000001, 43430A0),
|
||||
BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFE, 43430A1),
|
||||
- BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFFC0, 43455),
|
||||
+ BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0x00000200, 43456),
|
||||
+ BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFDC0, 43455),
|
||||
BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354),
|
||||
BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356),
|
||||
BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373),
|
|
@ -0,0 +1,41 @@
|
|||
From a927e8d8ab57e696800e20cf09a72b7dfe3bbebb Mon Sep 17 00:00:00 2001
|
||||
From: Colin Ian King <colin.king@canonical.com>
|
||||
Date: Tue, 9 Apr 2019 12:43:33 +0100
|
||||
Subject: [PATCH] brcmfmac: fix leak of mypkt on error return path
|
||||
|
||||
Currently if the call to brcmf_sdiod_set_backplane_window fails then
|
||||
error return path leaks mypkt. Fix this by returning by a new
|
||||
error path labelled 'out' that calls brcmu_pkt_buf_free_skb to free
|
||||
mypkt. Also remove redundant check on err before calling
|
||||
brcmf_sdiod_skbuff_write.
|
||||
|
||||
Addresses-Coverity: ("Resource Leak")
|
||||
Fixes: a7c3aa1509e2 ("brcmfmac: Remove brcmf_sdiod_addrprep()")
|
||||
Signed-off-by: Colin Ian King <colin.king@canonical.com>
|
||||
Reviewed-by: Mukesh Ojha <mojha@codeaurora.org>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 8 +++-----
|
||||
1 file changed, 3 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
|
||||
@@ -617,15 +617,13 @@ int brcmf_sdiod_send_buf(struct brcmf_sd
|
||||
|
||||
err = brcmf_sdiod_set_backplane_window(sdiodev, addr);
|
||||
if (err)
|
||||
- return err;
|
||||
+ goto out;
|
||||
|
||||
addr &= SBSDIO_SB_OFT_ADDR_MASK;
|
||||
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
|
||||
|
||||
- if (!err)
|
||||
- err = brcmf_sdiod_skbuff_write(sdiodev, sdiodev->func2, addr,
|
||||
- mypkt);
|
||||
-
|
||||
+ err = brcmf_sdiod_skbuff_write(sdiodev, sdiodev->func2, addr, mypkt);
|
||||
+out:
|
||||
brcmu_pkt_buf_free_skb(mypkt);
|
||||
|
||||
return err;
|
|
@ -13,7 +13,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
|||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
||||
@@ -1408,6 +1408,7 @@ int __init brcmf_core_init(void)
|
||||
@@ -1436,6 +1436,7 @@ int __init brcmf_core_init(void)
|
||||
{
|
||||
if (!schedule_work(&brcmf_driver_work))
|
||||
return -EBUSY;
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Subject: [PATCH] brcmfmac: get RAM info right before downloading PCIe firmware
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
It's important as brcmf_chip_get_raminfo() also makes sure that memory
|
||||
is properly setup. Without it the firmware could report invalid RAM
|
||||
address like 0x04000001.
|
||||
|
||||
During a normal brcmfmac lifetime brcmf_chip_get_raminfo() is called on
|
||||
probe by the brcmf_chip_recognition(). This change allows implementing
|
||||
further improvements like handling errors by resetting a device with
|
||||
the brcmf_pcie_reset_device() and redownloading a firmware afterwards.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
---
|
||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 6 ++++--
|
||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h | 1 +
|
||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 6 ++++++
|
||||
3 files changed, 11 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
|
||||
@@ -707,8 +707,10 @@ static u32 brcmf_chip_tcm_rambase(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci)
|
||||
+int brcmf_chip_get_raminfo(struct brcmf_chip *pub)
|
||||
{
|
||||
+ struct brcmf_chip_priv *ci = container_of(pub, struct brcmf_chip_priv,
|
||||
+ pub);
|
||||
struct brcmf_core_priv *mem_core;
|
||||
struct brcmf_core *mem;
|
||||
|
||||
@@ -990,7 +992,7 @@ static int brcmf_chip_recognition(struct
|
||||
brcmf_chip_set_passive(&ci->pub);
|
||||
}
|
||||
|
||||
- return brcmf_chip_get_raminfo(ci);
|
||||
+ return brcmf_chip_get_raminfo(&ci->pub);
|
||||
}
|
||||
|
||||
static void brcmf_chip_disable_arm(struct brcmf_chip_priv *chip, u16 id)
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
|
||||
@@ -80,6 +80,7 @@ struct brcmf_buscore_ops {
|
||||
void (*activate)(void *ctx, struct brcmf_chip *chip, u32 rstvec);
|
||||
};
|
||||
|
||||
+int brcmf_chip_get_raminfo(struct brcmf_chip *pub);
|
||||
struct brcmf_chip *brcmf_chip_attach(void *ctx,
|
||||
const struct brcmf_buscore_ops *ops);
|
||||
void brcmf_chip_detach(struct brcmf_chip *chip);
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
|
||||
@@ -1762,6 +1762,12 @@ static void brcmf_pcie_setup(struct devi
|
||||
nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len;
|
||||
kfree(fwreq);
|
||||
|
||||
+ ret = brcmf_chip_get_raminfo(devinfo->ci);
|
||||
+ if (ret) {
|
||||
+ brcmf_err(bus, "Failed to get RAM info\n");
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
/* Some of the firmwares have the size of the memory of the device
|
||||
* defined inside the firmware. This is because part of the memory in
|
||||
* the device is shared and the devision is determined by FW. Parse
|
Loading…
Reference in New Issue