From 867b647f83ddb938891b92a54f84c6a644cfde68 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 10 Jan 2016 00:19:16 +0000 Subject: [PATCH] mac80211: brcmfmac: support dumping stations It allows user-space fetch associated STAs and e.g. iwinfo/luci display them. SVN-Revision: 48167 --- .../371-brcmfmac-include-linux-atomic.h.patch | 23 ++ ...device-memory-to-devcoredump-subsyst.patch | 347 ++++++++++++++++++ ...e-condition-between-USB-probe-load-a.patch | 108 ++++++ ...firmware_path-to-alternative_fw_path.patch | 28 ++ ...cmfmac-remove-conversational-comment.patch | 25 ++ ...p2p-attach-use-single-method-for-p2p.patch | 226 ++++++++++++ ...ac-Fix-station-info-rate-information.patch | 36 ++ ...-Add-RSSI-information-to-get_station.patch | 50 +++ ...dump_station-support-to-cfg80221-ops.patch | 107 ++++++ ...cmf_c_preinit_dcmds-prototype-to-cor.patch | 42 +++ ...fmac-Remove-unused-state-AP-creating.patch | 55 +++ ...Properly-set-carrier-state-of-netdev.patch | 122 ++++++ ...-register-wiphy-s-during-module_init.patch | 2 +- 13 files changed, 1170 insertions(+), 1 deletion(-) create mode 100644 package/kernel/mac80211/patches/371-brcmfmac-include-linux-atomic.h.patch create mode 100644 package/kernel/mac80211/patches/372-0001-brcmfmac-expose-device-memory-to-devcoredump-subsyst.patch create mode 100644 package/kernel/mac80211/patches/372-0002-brcmfmac-Fix-race-condition-between-USB-probe-load-a.patch create mode 100644 package/kernel/mac80211/patches/372-0003-brcmfmac-rename-firmware_path-to-alternative_fw_path.patch create mode 100644 package/kernel/mac80211/patches/372-0004-brcmfmac-remove-conversational-comment.patch create mode 100644 package/kernel/mac80211/patches/372-0005-brcmfmac-Rework-p2p-attach-use-single-method-for-p2p.patch create mode 100644 package/kernel/mac80211/patches/372-0006-brcmfmac-Fix-station-info-rate-information.patch create mode 100644 package/kernel/mac80211/patches/372-0007-brcmfmac-Add-RSSI-information-to-get_station.patch create mode 100644 package/kernel/mac80211/patches/372-0008-brcmfmac-Add-dump_station-support-to-cfg80221-ops.patch create mode 100644 package/kernel/mac80211/patches/372-0009-brcmfmac-Move-brcmf_c_preinit_dcmds-prototype-to-cor.patch create mode 100644 package/kernel/mac80211/patches/372-0010-brcmfmac-Remove-unused-state-AP-creating.patch create mode 100644 package/kernel/mac80211/patches/372-0011-brcmfmac-Properly-set-carrier-state-of-netdev.patch diff --git a/package/kernel/mac80211/patches/371-brcmfmac-include-linux-atomic.h.patch b/package/kernel/mac80211/patches/371-brcmfmac-include-linux-atomic.h.patch new file mode 100644 index 0000000000..9311a9dbe4 --- /dev/null +++ b/package/kernel/mac80211/patches/371-brcmfmac-include-linux-atomic.h.patch @@ -0,0 +1,23 @@ +From: Hauke Mehrtens +Date: Sat, 19 Sep 2015 12:47:20 +0200 +Subject: [PATCH] brcmfmac: include linux/atomic.h + +brcmfmac uses atomic_or() and other atomic_* functions, but does not +include linux/atomic.h. This file gets included by some other header +file so this normally does not cause problems. + +Signed-off-by: Hauke Mehrtens +Acked-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +@@ -15,6 +15,7 @@ + */ + + #include ++#include + #include + #include + #include diff --git a/package/kernel/mac80211/patches/372-0001-brcmfmac-expose-device-memory-to-devcoredump-subsyst.patch b/package/kernel/mac80211/patches/372-0001-brcmfmac-expose-device-memory-to-devcoredump-subsyst.patch new file mode 100644 index 0000000000..cf3f278871 --- /dev/null +++ b/package/kernel/mac80211/patches/372-0001-brcmfmac-expose-device-memory-to-devcoredump-subsyst.patch @@ -0,0 +1,347 @@ +From: Arend van Spriel +Date: Thu, 8 Oct 2015 20:33:11 +0200 +Subject: [PATCH] brcmfmac: expose device memory to devcoredump subsystem + +Upon PSM watchdog event received from firmware the driver will obtain +a memory snapshot of the device and expose it to user-space through +the devcoredump framework. This will trigger a uevent. + +Reviewed-by: Hante Meuleman +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/Kconfig ++++ b/drivers/net/wireless/brcm80211/Kconfig +@@ -85,5 +85,6 @@ config BRCM_TRACING + config BRCMDBG + bool "Broadcom driver debug functions" + depends on BRCMSMAC || BRCMFMAC ++ select WANT_DEV_COREDUMP + ---help--- + Selecting this enables additional code for debug purposes. +--- a/drivers/net/wireless/brcm80211/brcmfmac/bus.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/bus.h +@@ -65,6 +65,8 @@ struct brcmf_bus_dcmd { + * @rxctl: receive a control response message from dongle. + * @gettxq: obtain a reference of bus transmit queue (optional). + * @wowl_config: specify if dongle is configured for wowl when going to suspend ++ * @get_ramsize: obtain size of device memory. ++ * @get_memdump: obtain device memory dump in provided buffer. + * + * This structure provides an abstract interface towards the + * bus specific driver. For control messages to common driver +@@ -79,6 +81,8 @@ struct brcmf_bus_ops { + int (*rxctl)(struct device *dev, unsigned char *msg, uint len); + struct pktq * (*gettxq)(struct device *dev); + void (*wowl_config)(struct device *dev, bool enabled); ++ size_t (*get_ramsize)(struct device *dev); ++ int (*get_memdump)(struct device *dev, void *data, size_t len); + }; + + +@@ -185,6 +189,23 @@ void brcmf_bus_wowl_config(struct brcmf_ + bus->ops->wowl_config(bus->dev, enabled); + } + ++static inline size_t brcmf_bus_get_ramsize(struct brcmf_bus *bus) ++{ ++ if (!bus->ops->get_ramsize) ++ return 0; ++ ++ return bus->ops->get_ramsize(bus->dev); ++} ++ ++static inline ++int brcmf_bus_get_memdump(struct brcmf_bus *bus, void *data, size_t len) ++{ ++ if (!bus->ops->get_memdump) ++ return -EOPNOTSUPP; ++ ++ return bus->ops->get_memdump(bus->dev, data, len); ++} ++ + /* + * interface functions from common layer + */ +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -957,8 +957,8 @@ int brcmf_attach(struct device *dev) + drvr->bus_if = dev_get_drvdata(dev); + drvr->bus_if->drvr = drvr; + +- /* create device debugfs folder */ +- brcmf_debugfs_attach(drvr); ++ /* attach debug facilities */ ++ brcmf_debug_attach(drvr); + + /* Attach and link in the protocol */ + ret = brcmf_proto_attach(drvr); +@@ -1155,7 +1155,7 @@ void brcmf_detach(struct device *dev) + + brcmf_proto_detach(drvr); + +- brcmf_debugfs_detach(drvr); ++ brcmf_debug_detach(drvr); + bus_if->drvr = NULL; + kfree(drvr); + } +--- a/drivers/net/wireless/brcm80211/brcmfmac/debug.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.c +@@ -16,15 +16,45 @@ + #include + #include + #include ++#include + + #include + #include + #include "core.h" + #include "bus.h" ++#include "fweh.h" + #include "debug.h" + + static struct dentry *root_folder; + ++static int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data, ++ size_t len) ++{ ++ void *dump; ++ size_t ramsize; ++ ++ ramsize = brcmf_bus_get_ramsize(bus); ++ if (ramsize) { ++ dump = vzalloc(len + ramsize); ++ if (!dump) ++ return -ENOMEM; ++ memcpy(dump, data, len); ++ brcmf_bus_get_memdump(bus, dump + len, ramsize); ++ dev_coredumpv(bus->dev, dump, len + ramsize, GFP_KERNEL); ++ } ++ return 0; ++} ++ ++static int brcmf_debug_psm_watchdog_notify(struct brcmf_if *ifp, ++ const struct brcmf_event_msg *evtmsg, ++ void *data) ++{ ++ brcmf_dbg(TRACE, "enter: idx=%d\n", ifp->bssidx); ++ ++ return brcmf_debug_create_memdump(ifp->drvr->bus_if, data, ++ evtmsg->datalen); ++} ++ + void brcmf_debugfs_init(void) + { + root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL); +@@ -41,7 +71,7 @@ void brcmf_debugfs_exit(void) + root_folder = NULL; + } + +-int brcmf_debugfs_attach(struct brcmf_pub *drvr) ++int brcmf_debug_attach(struct brcmf_pub *drvr) + { + struct device *dev = drvr->bus_if->dev; + +@@ -49,12 +79,18 @@ int brcmf_debugfs_attach(struct brcmf_pu + return -ENODEV; + + drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder); ++ if (IS_ERR(drvr->dbgfs_dir)) ++ return PTR_ERR(drvr->dbgfs_dir); + +- return PTR_ERR_OR_ZERO(drvr->dbgfs_dir); ++ ++ return brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG, ++ brcmf_debug_psm_watchdog_notify); + } + +-void brcmf_debugfs_detach(struct brcmf_pub *drvr) ++void brcmf_debug_detach(struct brcmf_pub *drvr) + { ++ brcmf_fweh_unregister(drvr, BRCMF_E_PSM_WATCHDOG); ++ + if (!IS_ERR_OR_NULL(drvr->dbgfs_dir)) + debugfs_remove_recursive(drvr->dbgfs_dir); + } +--- a/drivers/net/wireless/brcm80211/brcmfmac/debug.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.h +@@ -109,8 +109,8 @@ struct brcmf_pub; + #ifdef DEBUG + void brcmf_debugfs_init(void); + void brcmf_debugfs_exit(void); +-int brcmf_debugfs_attach(struct brcmf_pub *drvr); +-void brcmf_debugfs_detach(struct brcmf_pub *drvr); ++int brcmf_debug_attach(struct brcmf_pub *drvr); ++void brcmf_debug_detach(struct brcmf_pub *drvr); + struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr); + int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn, + int (*read_fn)(struct seq_file *seq, void *data)); +@@ -121,11 +121,11 @@ static inline void brcmf_debugfs_init(vo + static inline void brcmf_debugfs_exit(void) + { + } +-static inline int brcmf_debugfs_attach(struct brcmf_pub *drvr) ++static inline int brcmf_debug_attach(struct brcmf_pub *drvr) + { + return 0; + } +-static inline void brcmf_debugfs_detach(struct brcmf_pub *drvr) ++static inline void brcmf_debug_detach(struct brcmf_pub *drvr) + { + } + static inline +--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +@@ -448,6 +448,47 @@ brcmf_pcie_copy_mem_todev(struct brcmf_p + } + + ++static void ++brcmf_pcie_copy_dev_tomem(struct brcmf_pciedev_info *devinfo, u32 mem_offset, ++ void *dstaddr, u32 len) ++{ ++ void __iomem *address = devinfo->tcm + mem_offset; ++ __le32 *dst32; ++ __le16 *dst16; ++ u8 *dst8; ++ ++ if (((ulong)address & 4) || ((ulong)dstaddr & 4) || (len & 4)) { ++ if (((ulong)address & 2) || ((ulong)dstaddr & 2) || (len & 2)) { ++ dst8 = (u8 *)dstaddr; ++ while (len) { ++ *dst8 = ioread8(address); ++ address++; ++ dst8++; ++ len--; ++ } ++ } else { ++ len = len / 2; ++ dst16 = (__le16 *)dstaddr; ++ while (len) { ++ *dst16 = cpu_to_le16(ioread16(address)); ++ address += 2; ++ dst16++; ++ len--; ++ } ++ } ++ } else { ++ len = len / 4; ++ dst32 = (__le32 *)dstaddr; ++ while (len) { ++ *dst32 = cpu_to_le32(ioread32(address)); ++ address += 4; ++ dst32++; ++ len--; ++ } ++ } ++} ++ ++ + #define WRITECC32(devinfo, reg, value) brcmf_pcie_write_reg32(devinfo, \ + CHIPCREGOFFS(reg), value) + +@@ -1352,12 +1393,36 @@ static void brcmf_pcie_wowl_config(struc + } + + ++static size_t brcmf_pcie_get_ramsize(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; ++ ++ return devinfo->ci->ramsize - devinfo->ci->srsize; ++} ++ ++ ++static int brcmf_pcie_get_memdump(struct device *dev, void *data, size_t len) ++{ ++ 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; ++ ++ brcmf_dbg(PCIE, "dump at 0x%08X: len=%zu\n", devinfo->ci->rambase, len); ++ brcmf_pcie_copy_dev_tomem(devinfo, devinfo->ci->rambase, data, len); ++ return 0; ++} ++ ++ + static struct brcmf_bus_ops brcmf_pcie_bus_ops = { + .txdata = brcmf_pcie_tx, + .stop = brcmf_pcie_down, + .txctl = brcmf_pcie_tx_ctlpkt, + .rxctl = brcmf_pcie_rx_ctlpkt, + .wowl_config = brcmf_pcie_wowl_config, ++ .get_ramsize = brcmf_pcie_get_ramsize, ++ .get_memdump = brcmf_pcie_get_memdump, + }; + + +--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +@@ -3539,6 +3539,51 @@ done: + return err; + } + ++static size_t brcmf_sdio_bus_get_ramsize(struct device *dev) ++{ ++ struct brcmf_bus *bus_if = dev_get_drvdata(dev); ++ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; ++ struct brcmf_sdio *bus = sdiodev->bus; ++ ++ return bus->ci->ramsize - bus->ci->srsize; ++} ++ ++static int brcmf_sdio_bus_get_memdump(struct device *dev, void *data, ++ size_t mem_size) ++{ ++ struct brcmf_bus *bus_if = dev_get_drvdata(dev); ++ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; ++ struct brcmf_sdio *bus = sdiodev->bus; ++ int err; ++ int address; ++ int offset; ++ int len; ++ ++ brcmf_dbg(INFO, "dump at 0x%08x: size=%zu\n", bus->ci->rambase, ++ mem_size); ++ ++ address = bus->ci->rambase; ++ offset = err = 0; ++ sdio_claim_host(sdiodev->func[1]); ++ while (offset < mem_size) { ++ len = ((offset + MEMBLOCK) < mem_size) ? MEMBLOCK : ++ mem_size - offset; ++ err = brcmf_sdiod_ramrw(sdiodev, false, address, data, len); ++ if (err) { ++ brcmf_err("error %d on reading %d membytes at 0x%08x\n", ++ err, len, address); ++ goto done; ++ } ++ data += len; ++ offset += len; ++ address += len; ++ } ++ ++done: ++ sdio_release_host(sdiodev->func[1]); ++ return err; ++} ++ + void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus) + { + if (!bus->dpc_triggered) { +@@ -3987,7 +4032,9 @@ static struct brcmf_bus_ops brcmf_sdio_b + .txctl = brcmf_sdio_bus_txctl, + .rxctl = brcmf_sdio_bus_rxctl, + .gettxq = brcmf_sdio_bus_gettxq, +- .wowl_config = brcmf_sdio_wowl_config ++ .wowl_config = brcmf_sdio_wowl_config, ++ .get_ramsize = brcmf_sdio_bus_get_ramsize, ++ .get_memdump = brcmf_sdio_bus_get_memdump, + }; + + static void brcmf_sdio_firmware_callback(struct device *dev, diff --git a/package/kernel/mac80211/patches/372-0002-brcmfmac-Fix-race-condition-between-USB-probe-load-a.patch b/package/kernel/mac80211/patches/372-0002-brcmfmac-Fix-race-condition-between-USB-probe-load-a.patch new file mode 100644 index 0000000000..5b82bcac9a --- /dev/null +++ b/package/kernel/mac80211/patches/372-0002-brcmfmac-Fix-race-condition-between-USB-probe-load-a.patch @@ -0,0 +1,108 @@ +From: Hante Meuleman +Date: Thu, 8 Oct 2015 20:33:12 +0200 +Subject: [PATCH] brcmfmac: Fix race condition between USB probe/load and + disconnect. + +When a USB device gets disconnected due to for example removal +then it is possible that it is still in the loading phase due to +the asynchronous load routines. These routines can then possible +access memory which has been freed. Fix this by mutex locking the +device init phase. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c +@@ -144,6 +144,7 @@ struct brcmf_usbdev_info { + + struct usb_device *usbdev; + struct device *dev; ++ struct mutex dev_init_lock; + + int ctl_in_pipe, ctl_out_pipe; + struct urb *ctl_urb; /* URB for control endpoint */ +@@ -1204,6 +1205,8 @@ static void brcmf_usb_probe_phase2(struc + int ret; + + brcmf_dbg(USB, "Start fw downloading\n"); ++ ++ devinfo = bus->bus_priv.usb->devinfo; + ret = check_file(fw->data); + if (ret < 0) { + brcmf_err("invalid firmware\n"); +@@ -1211,7 +1214,6 @@ static void brcmf_usb_probe_phase2(struc + goto error; + } + +- devinfo = bus->bus_priv.usb->devinfo; + devinfo->image = fw->data; + devinfo->image_len = fw->size; + +@@ -1224,9 +1226,11 @@ static void brcmf_usb_probe_phase2(struc + if (ret) + goto error; + ++ mutex_unlock(&devinfo->dev_init_lock); + return; + error: + brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), ret); ++ mutex_unlock(&devinfo->dev_init_lock); + device_release_driver(dev); + } + +@@ -1264,6 +1268,7 @@ static int brcmf_usb_probe_cb(struct brc + if (ret) + goto fail; + /* we are done */ ++ mutex_unlock(&devinfo->dev_init_lock); + return 0; + } + bus->chip = bus_pub->devid; +@@ -1317,6 +1322,12 @@ 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. ++ * Necessary because of the asynchronous firmware load construction ++ */ ++ mutex_init(&devinfo->dev_init_lock); ++ mutex_lock(&devinfo->dev_init_lock); ++ + usb_set_intfdata(intf, devinfo); + + /* Check that the device supports only one configuration */ +@@ -1391,6 +1402,7 @@ brcmf_usb_probe(struct usb_interface *in + return 0; + + fail: ++ mutex_unlock(&devinfo->dev_init_lock); + kfree(devinfo); + usb_set_intfdata(intf, NULL); + return ret; +@@ -1403,8 +1415,19 @@ brcmf_usb_disconnect(struct usb_interfac + + brcmf_dbg(USB, "Enter\n"); + devinfo = (struct brcmf_usbdev_info *)usb_get_intfdata(intf); +- brcmf_usb_disconnect_cb(devinfo); +- kfree(devinfo); ++ ++ if (devinfo) { ++ mutex_lock(&devinfo->dev_init_lock); ++ /* Make sure that devinfo still exists. Firmware probe routines ++ * may have released the device and cleared the intfdata. ++ */ ++ if (!usb_get_intfdata(intf)) ++ goto done; ++ ++ brcmf_usb_disconnect_cb(devinfo); ++ kfree(devinfo); ++ } ++done: + brcmf_dbg(USB, "Exit\n"); + } + diff --git a/package/kernel/mac80211/patches/372-0003-brcmfmac-rename-firmware_path-to-alternative_fw_path.patch b/package/kernel/mac80211/patches/372-0003-brcmfmac-rename-firmware_path-to-alternative_fw_path.patch new file mode 100644 index 0000000000..f877c232a2 --- /dev/null +++ b/package/kernel/mac80211/patches/372-0003-brcmfmac-rename-firmware_path-to-alternative_fw_path.patch @@ -0,0 +1,28 @@ +From: Franky Lin +Date: Thu, 8 Oct 2015 20:33:13 +0200 +Subject: [PATCH] brcmfmac: rename firmware_path to alternative_fw_path + +In brcmfmac the module parameter "firmware_path" is used as an +alternative relative path under the search path used by firmware_class +or ueventhelper. Rename the parameter to alternative_fw_path to avoid +confusion. + +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Arend Van Spriel +Reviewed-by: Hante Meuleman +Signed-off-by: Franky Lin +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c +@@ -28,7 +28,7 @@ + #define BRCMF_FW_NVRAM_PCIEDEV_LEN 10 /* pcie/1/4/ + \0 */ + + char brcmf_firmware_path[BRCMF_FW_PATH_LEN]; +-module_param_string(firmware_path, brcmf_firmware_path, ++module_param_string(alternative_fw_path, brcmf_firmware_path, + BRCMF_FW_PATH_LEN, 0440); + + enum nvram_parser_state { diff --git a/package/kernel/mac80211/patches/372-0004-brcmfmac-remove-conversational-comment.patch b/package/kernel/mac80211/patches/372-0004-brcmfmac-remove-conversational-comment.patch new file mode 100644 index 0000000000..0bfd9effc8 --- /dev/null +++ b/package/kernel/mac80211/patches/372-0004-brcmfmac-remove-conversational-comment.patch @@ -0,0 +1,25 @@ +From: Arend van Spriel +Date: Thu, 8 Oct 2015 20:33:14 +0200 +Subject: [PATCH] brcmfmac: remove conversational comment + +Removing a comment that was only useful during the review of +the change that introduced it and which should never have been +submitted. + +Reviewed-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +@@ -873,9 +873,6 @@ brcmf_msgbuf_process_txstatus(struct brc + commonring = msgbuf->flowrings[flowid]; + atomic_dec(&commonring->outstanding_tx); + +- /* Hante: i believe this was a bug as tx_status->msg.ifidx was used +- * in brcmf_txfinalize as index in drvr->iflist. Can you confirm/deny? +- */ + brcmf_txfinalize(brcmf_get_ifp(msgbuf->drvr, tx_status->msg.ifidx), + skb, true); + } diff --git a/package/kernel/mac80211/patches/372-0005-brcmfmac-Rework-p2p-attach-use-single-method-for-p2p.patch b/package/kernel/mac80211/patches/372-0005-brcmfmac-Rework-p2p-attach-use-single-method-for-p2p.patch new file mode 100644 index 0000000000..3ffada8d56 --- /dev/null +++ b/package/kernel/mac80211/patches/372-0005-brcmfmac-Rework-p2p-attach-use-single-method-for-p2p.patch @@ -0,0 +1,226 @@ +From: Hante Meuleman +Date: Thu, 8 Oct 2015 20:33:15 +0200 +Subject: [PATCH] brcmfmac: Rework p2p attach, use single method for p2p dev + creation. + +When module param p2pon is used a p2p device is created at init. +This patch reworks how this is done by using the same method as +for a dynamically (by user space) created p2p device. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Franky (Zhenhui) Lin +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -6237,6 +6237,17 @@ struct brcmf_cfg80211_info *brcmf_cfg802 + else + *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + } ++ /* p2p might require that "if-events" get processed by fweh. So ++ * activate the already registered event handlers now and activate ++ * the rest when initialization has completed. drvr->config needs to ++ * be assigned before activating events. ++ */ ++ drvr->config = cfg; ++ err = brcmf_fweh_activate_events(ifp); ++ if (err) { ++ brcmf_err("FWEH activation failed (%d)\n", err); ++ goto wiphy_unreg_out; ++ } + + err = brcmf_p2p_attach(cfg, p2pdev_forced); + if (err) { +@@ -6259,6 +6270,13 @@ struct brcmf_cfg80211_info *brcmf_cfg802 + brcmf_notify_tdls_peer_event); + } + ++ /* (re-) activate FWEH event handling */ ++ err = brcmf_fweh_activate_events(ifp); ++ if (err) { ++ brcmf_err("FWEH activation failed (%d)\n", err); ++ goto wiphy_unreg_out; ++ } ++ + return cfg; + + wiphy_unreg_out: +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -828,8 +828,8 @@ struct brcmf_if *brcmf_add_if(struct brc + } else { + brcmf_dbg(INFO, "allocate netdev interface\n"); + /* Allocate netdev, including space for private structure */ +- ndev = alloc_netdev(sizeof(*ifp), name, NET_NAME_UNKNOWN, +- ether_setup); ++ ndev = alloc_netdev(sizeof(*ifp), is_p2pdev ? "p2p%d" : name, ++ NET_NAME_UNKNOWN, ether_setup); + if (!ndev) + return ERR_PTR(-ENOMEM); + +@@ -1021,12 +1021,7 @@ int brcmf_bus_start(struct device *dev) + if (IS_ERR(ifp)) + return PTR_ERR(ifp); + +- if (brcmf_p2p_enable) +- p2p_ifp = brcmf_add_if(drvr, 1, 0, false, "p2p%d", NULL); +- else +- p2p_ifp = NULL; +- if (IS_ERR(p2p_ifp)) +- p2p_ifp = NULL; ++ p2p_ifp = NULL; + + /* signal bus ready */ + brcmf_bus_change_state(bus_if, BRCMF_BUS_UP); +@@ -1060,11 +1055,13 @@ int brcmf_bus_start(struct device *dev) + goto fail; + } + +- ret = brcmf_fweh_activate_events(ifp); +- if (ret < 0) +- goto fail; +- + ret = brcmf_net_attach(ifp, false); ++ ++ if ((!ret) && (brcmf_p2p_enable)) { ++ p2p_ifp = drvr->iflist[1]; ++ if (p2p_ifp) ++ ret = brcmf_net_p2p_attach(p2p_ifp); ++ } + fail: + if (ret < 0) { + brcmf_err("failed: %d\n", ret); +@@ -1076,20 +1073,12 @@ fail: + brcmf_fws_del_interface(ifp); + brcmf_fws_deinit(drvr); + } +- if (drvr->iflist[0]) { ++ if (ifp) + brcmf_net_detach(ifp->ndev); +- drvr->iflist[0] = NULL; +- } +- if (p2p_ifp) { ++ if (p2p_ifp) + brcmf_net_detach(p2p_ifp->ndev); +- drvr->iflist[1] = NULL; +- } + return ret; + } +- if ((brcmf_p2p_enable) && (p2p_ifp)) +- if (brcmf_net_p2p_attach(p2p_ifp) < 0) +- brcmf_p2p_enable = 0; +- + return 0; + } + +--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +@@ -213,7 +213,8 @@ static void brcmf_fweh_handle_if_event(s + is_p2pdev, emsg->ifname, emsg->addr); + if (IS_ERR(ifp)) + return; +- brcmf_fws_add_interface(ifp); ++ if (!is_p2pdev) ++ brcmf_fws_add_interface(ifp); + if (!drvr->fweh.evt_handler[BRCMF_E_IF]) + if (brcmf_net_attach(ifp, false) < 0) + return; +--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +@@ -2350,83 +2350,30 @@ void brcmf_p2p_stop_device(struct wiphy + * brcmf_p2p_attach() - attach for P2P. + * + * @cfg: driver private data for cfg80211 interface. ++ * @p2pdev_forced: create p2p device interface at attach. + */ + s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg, bool p2pdev_forced) + { +- struct brcmf_if *pri_ifp; +- struct brcmf_if *p2p_ifp; +- struct brcmf_cfg80211_vif *p2p_vif; + struct brcmf_p2p_info *p2p; +- struct brcmf_pub *drvr; +- s32 bssidx; ++ struct brcmf_if *pri_ifp; + s32 err = 0; ++ void *err_ptr; + + p2p = &cfg->p2p; + p2p->cfg = cfg; + +- drvr = cfg->pub; +- +- pri_ifp = brcmf_get_ifp(drvr, 0); ++ pri_ifp = brcmf_get_ifp(cfg->pub, 0); + p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif; + + if (p2pdev_forced) { +- p2p_ifp = drvr->iflist[1]; ++ err_ptr = brcmf_p2p_create_p2pdev(p2p, NULL, NULL); ++ if (IS_ERR(err_ptr)) { ++ brcmf_err("P2P device creation failed.\n"); ++ err = PTR_ERR(err_ptr); ++ } + } else { +- p2p_ifp = NULL; + p2p->p2pdev_dynamically = true; + } +- if (p2p_ifp) { +- p2p_vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_P2P_DEVICE, +- false); +- if (IS_ERR(p2p_vif)) { +- brcmf_err("could not create discovery vif\n"); +- err = -ENOMEM; +- goto exit; +- } +- +- p2p_vif->ifp = p2p_ifp; +- p2p_ifp->vif = p2p_vif; +- p2p_vif->wdev.netdev = p2p_ifp->ndev; +- p2p_ifp->ndev->ieee80211_ptr = &p2p_vif->wdev; +- SET_NETDEV_DEV(p2p_ifp->ndev, wiphy_dev(cfg->wiphy)); +- +- p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif; +- +- brcmf_p2p_generate_bss_mac(p2p, NULL); +- memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN); +- brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr); +- +- brcmf_fweh_p2pdev_setup(pri_ifp, true); +- +- /* Initialize P2P Discovery in the firmware */ +- err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1); +- if (err < 0) { +- brcmf_err("set p2p_disc error\n"); +- brcmf_free_vif(p2p_vif); +- goto exit; +- } +- /* obtain bsscfg index for P2P discovery */ +- err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx); +- if (err < 0) { +- brcmf_err("retrieving discover bsscfg index failed\n"); +- brcmf_free_vif(p2p_vif); +- goto exit; +- } +- /* Verify that firmware uses same bssidx as driver !! */ +- if (p2p_ifp->bssidx != bssidx) { +- brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n", +- bssidx, p2p_ifp->bssidx); +- brcmf_free_vif(p2p_vif); +- goto exit; +- } +- +- init_completion(&p2p->send_af_done); +- INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler); +- init_completion(&p2p->afx_hdl.act_frm_scan); +- init_completion(&p2p->wait_next_af); +-exit: +- brcmf_fweh_p2pdev_setup(pri_ifp, false); +- } + return err; + } + diff --git a/package/kernel/mac80211/patches/372-0006-brcmfmac-Fix-station-info-rate-information.patch b/package/kernel/mac80211/patches/372-0006-brcmfmac-Fix-station-info-rate-information.patch new file mode 100644 index 0000000000..0abcf1eef4 --- /dev/null +++ b/package/kernel/mac80211/patches/372-0006-brcmfmac-Fix-station-info-rate-information.patch @@ -0,0 +1,36 @@ +From: Hante Meuleman +Date: Thu, 8 Oct 2015 20:33:16 +0200 +Subject: [PATCH] brcmfmac: Fix station info rate information. + +Txrate and rxrate in get_station got assigned first with value +in kbps and then divided by 100 to get it in 100kbps unit. The +problem with that is that type of rate is u16 which resulted +in incorrect values for high data rate values. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -2477,13 +2477,13 @@ brcmf_cfg80211_get_station(struct wiphy + sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts); + if (sinfo->tx_packets) { + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); +- sinfo->txrate.legacy = le32_to_cpu(sta_info_le.tx_rate); +- sinfo->txrate.legacy /= 100; ++ sinfo->txrate.legacy = ++ le32_to_cpu(sta_info_le.tx_rate) / 100; + } + if (sinfo->rx_packets) { + sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE); +- sinfo->rxrate.legacy = le32_to_cpu(sta_info_le.rx_rate); +- sinfo->rxrate.legacy /= 100; ++ sinfo->rxrate.legacy = ++ le32_to_cpu(sta_info_le.rx_rate) / 100; + } + if (le16_to_cpu(sta_info_le.ver) >= 4) { + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES); diff --git a/package/kernel/mac80211/patches/372-0007-brcmfmac-Add-RSSI-information-to-get_station.patch b/package/kernel/mac80211/patches/372-0007-brcmfmac-Add-RSSI-information-to-get_station.patch new file mode 100644 index 0000000000..bb03d679df --- /dev/null +++ b/package/kernel/mac80211/patches/372-0007-brcmfmac-Add-RSSI-information-to-get_station.patch @@ -0,0 +1,50 @@ +From: Hante Meuleman +Date: Thu, 8 Oct 2015 20:33:17 +0200 +Subject: [PATCH] brcmfmac: Add RSSI information to get_station. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -2431,6 +2431,9 @@ brcmf_cfg80211_get_station(struct wiphy + struct brcmf_sta_info_le sta_info_le; + u32 sta_flags; + u32 is_tdls_peer; ++ s32 total_rssi; ++ s32 count_rssi; ++ u32 i; + + brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac); + if (!check_vif_up(ifp->vif)) +@@ -2491,6 +2494,26 @@ brcmf_cfg80211_get_station(struct wiphy + sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES); + sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes); + } ++ total_rssi = 0; ++ count_rssi = 0; ++ for (i = 0; i < BRCMF_ANT_MAX; i++) { ++ if (sta_info_le.rssi[i]) { ++ sinfo->chain_signal_avg[count_rssi] = ++ sta_info_le.rssi[i]; ++ sinfo->chain_signal[count_rssi] = ++ sta_info_le.rssi[i]; ++ total_rssi += sta_info_le.rssi[i]; ++ count_rssi++; ++ } ++ } ++ if (count_rssi) { ++ sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL); ++ sinfo->chains = count_rssi; ++ ++ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); ++ total_rssi /= count_rssi; ++ sinfo->signal = total_rssi; ++ } + } + done: + brcmf_dbg(TRACE, "Exit\n"); diff --git a/package/kernel/mac80211/patches/372-0008-brcmfmac-Add-dump_station-support-to-cfg80221-ops.patch b/package/kernel/mac80211/patches/372-0008-brcmfmac-Add-dump_station-support-to-cfg80221-ops.patch new file mode 100644 index 0000000000..a6bafd2497 --- /dev/null +++ b/package/kernel/mac80211/patches/372-0008-brcmfmac-Add-dump_station-support-to-cfg80221-ops.patch @@ -0,0 +1,107 @@ +From: Hante Meuleman +Date: Thu, 8 Oct 2015 20:33:18 +0200 +Subject: [PATCH] brcmfmac: Add dump_station support to cfg80221 ops. + +With this feature it becomes possible to request a station +assoc list. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -2520,6 +2520,35 @@ done: + return err; + } + ++static int ++brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev, ++ int idx, u8 *mac, struct station_info *sinfo) ++{ ++ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); ++ struct brcmf_if *ifp = netdev_priv(ndev); ++ s32 err; ++ ++ brcmf_dbg(TRACE, "Enter, idx %d\n", idx); ++ ++ if (idx == 0) { ++ cfg->assoclist.count = cpu_to_le32(BRCMF_MAX_ASSOCLIST); ++ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_ASSOCLIST, ++ &cfg->assoclist, ++ sizeof(cfg->assoclist)); ++ if (err) { ++ brcmf_err("BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n", ++ err); ++ cfg->assoclist.count = 0; ++ return -EOPNOTSUPP; ++ } ++ } ++ if (idx < le32_to_cpu(cfg->assoclist.count)) { ++ memcpy(mac, cfg->assoclist.mac[idx], ETH_ALEN); ++ return brcmf_cfg80211_get_station(wiphy, ndev, mac, sinfo); ++ } ++ return -ENOENT; ++} ++ + static s32 + brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, + bool enabled, s32 timeout) +@@ -4619,6 +4648,7 @@ static struct cfg80211_ops wl_cfg80211_o + .join_ibss = brcmf_cfg80211_join_ibss, + .leave_ibss = brcmf_cfg80211_leave_ibss, + .get_station = brcmf_cfg80211_get_station, ++ .dump_station = brcmf_cfg80211_dump_station, + .set_tx_power = brcmf_cfg80211_set_tx_power, + .get_tx_power = brcmf_cfg80211_get_tx_power, + .add_key = brcmf_cfg80211_add_key, +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h +@@ -407,6 +407,7 @@ struct brcmf_cfg80211_info { + struct brcmu_d11inf d11inf; + bool wowl_enabled; + u32 pre_wowl_pmmode; ++ struct brcmf_assoclist_le assoclist; + }; + + /** +--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h +@@ -72,6 +72,7 @@ + #define BRCMF_C_GET_BSS_INFO 136 + #define BRCMF_C_GET_BANDLIST 140 + #define BRCMF_C_SET_SCB_TIMEOUT 158 ++#define BRCMF_C_GET_ASSOCLIST 159 + #define BRCMF_C_GET_PHYLIST 180 + #define BRCMF_C_SET_SCAN_CHANNEL_TIME 185 + #define BRCMF_C_SET_SCAN_UNASSOC_TIME 187 +--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h +@@ -119,6 +119,8 @@ + #define BRCMF_COUNTRY_BUF_SZ 4 + #define BRCMF_ANT_MAX 4 + ++#define BRCMF_MAX_ASSOCLIST 128 ++ + /* join preference types for join_pref iovar */ + enum brcmf_join_pref_types { + BRCMF_JOIN_PREF_RSSI = 1, +@@ -621,4 +623,15 @@ struct brcmf_rev_info_le { + __le32 nvramrev; + }; + ++/** ++ * struct brcmf_assoclist_le - request assoc list. ++ * ++ * @count: indicates number of stations. ++ * @mac: MAC addresses of stations. ++ */ ++struct brcmf_assoclist_le { ++ __le32 count; ++ u8 mac[BRCMF_MAX_ASSOCLIST][ETH_ALEN]; ++}; ++ + #endif /* FWIL_TYPES_H_ */ diff --git a/package/kernel/mac80211/patches/372-0009-brcmfmac-Move-brcmf_c_preinit_dcmds-prototype-to-cor.patch b/package/kernel/mac80211/patches/372-0009-brcmfmac-Move-brcmf_c_preinit_dcmds-prototype-to-cor.patch new file mode 100644 index 0000000000..dc549040ec --- /dev/null +++ b/package/kernel/mac80211/patches/372-0009-brcmfmac-Move-brcmf_c_preinit_dcmds-prototype-to-cor.patch @@ -0,0 +1,42 @@ +From: Hante Meuleman +Date: Thu, 8 Oct 2015 20:33:19 +0200 +Subject: [PATCH] brcmfmac: Move brcmf_c_preinit_dcmds prototype to correct + file. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/common.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/common.h +@@ -17,4 +17,7 @@ + + extern const u8 ALLFFMAC[ETH_ALEN]; + ++/* Sets dongle media info (drv_version, mac address). */ ++int brcmf_c_preinit_dcmds(struct brcmf_if *ifp); ++ + #endif /* BRCMFMAC_COMMON_H */ +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -33,6 +33,7 @@ + #include "feature.h" + #include "proto.h" + #include "pcie.h" ++#include "common.h" + + MODULE_AUTHOR("Broadcom Corporation"); + MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h +@@ -214,7 +214,4 @@ void brcmf_txflowblock_if(struct brcmf_i + void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success); + void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb); + +-/* Sets dongle media info (drv_version, mac address). */ +-int brcmf_c_preinit_dcmds(struct brcmf_if *ifp); +- + #endif /* BRCMFMAC_CORE_H */ diff --git a/package/kernel/mac80211/patches/372-0010-brcmfmac-Remove-unused-state-AP-creating.patch b/package/kernel/mac80211/patches/372-0010-brcmfmac-Remove-unused-state-AP-creating.patch new file mode 100644 index 0000000000..c6a7363aa6 --- /dev/null +++ b/package/kernel/mac80211/patches/372-0010-brcmfmac-Remove-unused-state-AP-creating.patch @@ -0,0 +1,55 @@ +From: Hante Meuleman +Date: Thu, 8 Oct 2015 20:33:20 +0200 +Subject: [PATCH] brcmfmac: Remove unused state AP creating. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -839,7 +839,6 @@ brcmf_cfg80211_change_iface(struct wiphy + err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO); + } + if (!err) { +- set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state); + brcmf_dbg(INFO, "IF Type = AP\n"); + } + } else { +@@ -4250,7 +4249,6 @@ brcmf_cfg80211_start_ap(struct wiphy *wi + + brcmf_dbg(TRACE, "GO mode configuration complete\n"); + } +- clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); + set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); + + exit: +@@ -4315,7 +4313,6 @@ static int brcmf_cfg80211_stop_ap(struct + } + brcmf_set_mpc(ifp, 1); + brcmf_configure_arp_offload(ifp, true); +- set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); + clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); + + return err; +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h +@@ -143,7 +143,6 @@ struct brcmf_cfg80211_profile { + * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress. + * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully. + * @BRCMF_VIF_STATUS_DISCONNECTING: disconnect/disable in progress. +- * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation. + * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started. + */ + enum brcmf_vif_status { +@@ -151,7 +150,6 @@ enum brcmf_vif_status { + BRCMF_VIF_STATUS_CONNECTING, + BRCMF_VIF_STATUS_CONNECTED, + BRCMF_VIF_STATUS_DISCONNECTING, +- BRCMF_VIF_STATUS_AP_CREATING, + BRCMF_VIF_STATUS_AP_CREATED + }; + diff --git a/package/kernel/mac80211/patches/372-0011-brcmfmac-Properly-set-carrier-state-of-netdev.patch b/package/kernel/mac80211/patches/372-0011-brcmfmac-Properly-set-carrier-state-of-netdev.patch new file mode 100644 index 0000000000..c0948ded40 --- /dev/null +++ b/package/kernel/mac80211/patches/372-0011-brcmfmac-Properly-set-carrier-state-of-netdev.patch @@ -0,0 +1,122 @@ +From: Hante Meuleman +Date: Thu, 8 Oct 2015 20:33:21 +0200 +Subject: [PATCH] brcmfmac: Properly set carrier state of netdev. + +Use the netif_carrier api to correctly set carrier state on the +different modes. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Franky (Zhenhui) Lin +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -4250,6 +4250,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi + brcmf_dbg(TRACE, "GO mode configuration complete\n"); + } + set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); ++ brcmf_net_setcarrier(ifp, true); + + exit: + if ((err) && (!mbss)) { +@@ -4314,6 +4315,7 @@ static int brcmf_cfg80211_stop_ap(struct + brcmf_set_mpc(ifp, 1); + brcmf_configure_arp_offload(ifp, true); + clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); ++ brcmf_net_setcarrier(ifp, false); + + return err; + } +@@ -5023,6 +5025,7 @@ brcmf_notify_connect_status(struct brcmf + &ifp->vif->sme_state); + } else + brcmf_bss_connect_done(cfg, ndev, e, true); ++ brcmf_net_setcarrier(ifp, true); + } else if (brcmf_is_linkdown(e)) { + brcmf_dbg(CONN, "Linkdown\n"); + if (!brcmf_is_ibssmode(ifp->vif)) { +@@ -5032,6 +5035,7 @@ brcmf_notify_connect_status(struct brcmf + brcmf_init_prof(ndev_to_prof(ndev)); + if (ndev != cfg_to_ndev(cfg)) + complete(&cfg->vif_disabled); ++ brcmf_net_setcarrier(ifp, false); + } else if (brcmf_is_nonetwork(cfg, e)) { + if (brcmf_is_ibssmode(ifp->vif)) + clear_bit(BRCMF_VIF_STATUS_CONNECTING, +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -635,8 +635,7 @@ static int brcmf_netdev_stop(struct net_ + + brcmf_cfg80211_down(ndev); + +- /* Set state and stop OS transmissions */ +- netif_stop_queue(ndev); ++ brcmf_net_setcarrier(ifp, false); + + return 0; + } +@@ -670,8 +669,8 @@ static int brcmf_netdev_open(struct net_ + return -EIO; + } + +- /* Allow transmit calls */ +- netif_start_queue(ndev); ++ /* Clear, carrier, set when connected or AP mode. */ ++ netif_carrier_off(ndev); + return 0; + } + +@@ -736,6 +735,24 @@ static void brcmf_net_detach(struct net_ + brcmf_cfg80211_free_netdev(ndev); + } + ++void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on) ++{ ++ struct net_device *ndev; ++ ++ brcmf_dbg(TRACE, "Enter, idx=%d carrier=%d\n", ifp->bssidx, on); ++ ++ ndev = ifp->ndev; ++ brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_DISCONNECTED, !on); ++ if (on) { ++ if (!netif_carrier_ok(ndev)) ++ netif_carrier_on(ndev); ++ ++ } else { ++ if (netif_carrier_ok(ndev)) ++ netif_carrier_off(ndev); ++ } ++} ++ + static int brcmf_net_p2p_open(struct net_device *ndev) + { + brcmf_dbg(TRACE, "Enter\n"); +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h +@@ -154,10 +154,13 @@ struct brcmf_fws_mac_descriptor; + * netif stopped due to firmware signalling flow control. + * @BRCMF_NETIF_STOP_REASON_FLOW: + * netif stopped due to flowring full. ++ * @BRCMF_NETIF_STOP_REASON_DISCONNECTED: ++ * netif stopped due to not being connected (STA mode). + */ + enum brcmf_netif_stop_reason { +- BRCMF_NETIF_STOP_REASON_FWS_FC = 1, +- BRCMF_NETIF_STOP_REASON_FLOW = 2 ++ BRCMF_NETIF_STOP_REASON_FWS_FC = BIT(0), ++ BRCMF_NETIF_STOP_REASON_FLOW = BIT(1), ++ BRCMF_NETIF_STOP_REASON_DISCONNECTED = BIT(2) + }; + + /** +@@ -213,5 +216,6 @@ void brcmf_txflowblock_if(struct brcmf_i + enum brcmf_netif_stop_reason reason, bool state); + void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success); + void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb); ++void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on); + + #endif /* BRCMFMAC_CORE_H */ diff --git a/package/kernel/mac80211/patches/861-brcmfmac-register-wiphy-s-during-module_init.patch b/package/kernel/mac80211/patches/861-brcmfmac-register-wiphy-s-during-module_init.patch index ed37fb6d0e..7bb6bed585 100644 --- a/package/kernel/mac80211/patches/861-brcmfmac-register-wiphy-s-during-module_init.patch +++ b/package/kernel/mac80211/patches/861-brcmfmac-register-wiphy-s-during-module_init.patch @@ -13,7 +13,7 @@ Signed-off-by: Rafał Miłecki --- a/drivers/net/wireless/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c -@@ -1229,6 +1229,7 @@ static int __init brcmfmac_module_init(v +@@ -1236,6 +1236,7 @@ static int __init brcmfmac_module_init(v #endif if (!schedule_work(&brcmf_driver_work)) return -EBUSY; -- 2.30.2