aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/broadcom
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/broadcom')
-rw-r--r--drivers/net/wireless/broadcom/b43/main.c12
-rw-r--r--drivers/net/wireless/broadcom/b43/xmit.c2
-rw-r--r--drivers/net/wireless/broadcom/b43legacy/dma.c2
-rw-r--r--drivers/net/wireless/broadcom/b43legacy/main.c4
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/Kconfig10
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile4
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c82
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h4
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c17
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c4
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h29
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c441
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h25
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c28
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c143
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h5
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c39
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h44
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c23
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h6
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c35
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h4
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c6
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h30
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h1
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h92
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c53
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h4
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c7
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h6
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c12
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c21
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c454
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h55
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h36
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c58
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c18
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c10
41 files changed, 1381 insertions, 451 deletions
diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c
index 52f3541ecbcf..b37e7391f55d 100644
--- a/drivers/net/wireless/broadcom/b43/main.c
+++ b/drivers/net/wireless/broadcom/b43/main.c
@@ -71,8 +71,18 @@ MODULE_FIRMWARE("b43/ucode11.fw");
MODULE_FIRMWARE("b43/ucode13.fw");
MODULE_FIRMWARE("b43/ucode14.fw");
MODULE_FIRMWARE("b43/ucode15.fw");
+MODULE_FIRMWARE("b43/ucode16_lp.fw");
MODULE_FIRMWARE("b43/ucode16_mimo.fw");
+MODULE_FIRMWARE("b43/ucode24_lcn.fw");
+MODULE_FIRMWARE("b43/ucode25_lcn.fw");
+MODULE_FIRMWARE("b43/ucode25_mimo.fw");
+MODULE_FIRMWARE("b43/ucode26_mimo.fw");
+MODULE_FIRMWARE("b43/ucode29_mimo.fw");
+MODULE_FIRMWARE("b43/ucode33_lcn40.fw");
+MODULE_FIRMWARE("b43/ucode30_mimo.fw");
MODULE_FIRMWARE("b43/ucode5.fw");
+MODULE_FIRMWARE("b43/ucode40.fw");
+MODULE_FIRMWARE("b43/ucode42.fw");
MODULE_FIRMWARE("b43/ucode9.fw");
static int modparam_bad_frames_preempt;
@@ -5598,6 +5608,8 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+ wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
wl->hw_registred = false;
hw->max_rates = 2;
SET_IEEE80211_DEV(hw, dev->dev);
diff --git a/drivers/net/wireless/broadcom/b43/xmit.c b/drivers/net/wireless/broadcom/b43/xmit.c
index b068d5aeee24..1b9c191e2a22 100644
--- a/drivers/net/wireless/broadcom/b43/xmit.c
+++ b/drivers/net/wireless/broadcom/b43/xmit.c
@@ -694,7 +694,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
if (unlikely(phystat0 & (B43_RX_PHYST0_PLCPHCF | B43_RX_PHYST0_PLCPFV)))
status.flag |= RX_FLAG_FAILED_PLCP_CRC;
if (phystat0 & B43_RX_PHYST0_SHORTPRMBL)
- status.flag |= RX_FLAG_SHORTPRE;
+ status.enc_flags |= RX_ENC_FLAG_SHORTPRE;
if (macstat & B43_RX_MAC_DECERR) {
/* Decryption with the given key failed.
* Drop the packet. We also won't be able to decrypt it with
diff --git a/drivers/net/wireless/broadcom/b43legacy/dma.c b/drivers/net/wireless/broadcom/b43legacy/dma.c
index f9dd892b9f27..cfa617ddb2f1 100644
--- a/drivers/net/wireless/broadcom/b43legacy/dma.c
+++ b/drivers/net/wireless/broadcom/b43legacy/dma.c
@@ -1072,7 +1072,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
goto out_unmap_hdr;
}
- memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
+ skb_put_data(bounce_skb, skb->data, skb->len);
memcpy(bounce_skb->cb, skb->cb, sizeof(skb->cb));
bounce_skb->dev = skb->dev;
skb_set_queue_mapping(bounce_skb, skb_get_queue_mapping(skb));
diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c
index e97ab2b91663..f1e3dad57629 100644
--- a/drivers/net/wireless/broadcom/b43legacy/main.c
+++ b/drivers/net/wireless/broadcom/b43legacy/main.c
@@ -36,7 +36,7 @@
#include <linux/etherdevice.h>
#include <linux/firmware.h>
#include <linux/workqueue.h>
-#include <linux/sched.h>
+#include <linux/sched/signal.h>
#include <linux/skbuff.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
@@ -3850,6 +3850,8 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
else
SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac);
+ wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
/* Get and initialize struct b43legacy_wl */
wl = hw_to_b43legacy_wl(hw);
memset(wl, 0, sizeof(*wl));
diff --git a/drivers/net/wireless/broadcom/brcm80211/Kconfig b/drivers/net/wireless/broadcom/brcm80211/Kconfig
index ab42b1fea03c..9d99eb42d917 100644
--- a/drivers/net/wireless/broadcom/brcm80211/Kconfig
+++ b/drivers/net/wireless/broadcom/brcm80211/Kconfig
@@ -18,14 +18,14 @@ config BRCMSMAC
module, the driver will be called brcmsmac.ko.
config BRCMFMAC
- tristate "Broadcom IEEE802.11n embedded FullMAC WLAN driver"
+ tristate "Broadcom FullMAC WLAN driver"
depends on CFG80211
select BRCMUTIL
---help---
- This module adds support for embedded wireless adapters based on
- Broadcom IEEE802.11n FullMAC chipsets. It has to work with at least
- one of the bus interface support. If you choose to build a module,
- it'll be called brcmfmac.ko.
+ This module adds support for wireless adapters based on Broadcom
+ FullMAC chipsets. It has to work with at least one of the bus
+ interface support. If you choose to build a module, it'll be called
+ brcmfmac.ko.
config BRCMFMAC_PROTO_BCDC
bool
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
index 0383ba559edc..1f5a9b948abf 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
@@ -25,7 +25,6 @@ brcmfmac-objs += \
chip.o \
fwil.o \
fweh.o \
- fwsignal.o \
p2p.o \
proto.o \
common.o \
@@ -36,7 +35,8 @@ brcmfmac-objs += \
vendor.o \
pno.o
brcmfmac-$(CONFIG_BRCMFMAC_PROTO_BCDC) += \
- bcdc.o
+ bcdc.o \
+ fwsignal.o
brcmfmac-$(CONFIG_BRCMFMAC_PROTO_MSGBUF) += \
commonring.o \
flowring.o \
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
index 384b1873e7e3..9f2d0b0cf6e5 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
@@ -103,9 +103,17 @@ struct brcmf_bcdc {
u8 bus_header[BUS_HEADER_LEN];
struct brcmf_proto_bcdc_dcmd msg;
unsigned char buf[BRCMF_DCMD_MAXLEN];
+ struct brcmf_fws_info *fws;
};
+struct brcmf_fws_info *drvr_to_fws(struct brcmf_pub *drvr)
+{
+ struct brcmf_bcdc *bcdc = drvr->proto->pd;
+
+ return bcdc->fws;
+}
+
static int
brcmf_proto_bcdc_msg(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
uint len, bool set)
@@ -330,8 +338,9 @@ static int brcmf_proto_bcdc_tx_queue_data(struct brcmf_pub *drvr, int ifidx,
struct sk_buff *skb)
{
struct brcmf_if *ifp = brcmf_get_ifp(drvr, ifidx);
+ struct brcmf_bcdc *bcdc = drvr->proto->pd;
- if (!brcmf_fws_queue_skbs(drvr->fws))
+ if (!brcmf_fws_queue_skbs(bcdc->fws))
return brcmf_proto_txdata(drvr, ifidx, 0, skb);
return brcmf_fws_process_skb(ifp, skb);
@@ -345,6 +354,36 @@ brcmf_proto_bcdc_txdata(struct brcmf_pub *drvr, int ifidx, u8 offset,
return brcmf_bus_txdata(drvr->bus_if, pktbuf);
}
+void brcmf_proto_bcdc_txflowblock(struct device *dev, bool state)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_pub *drvr = bus_if->drvr;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ brcmf_fws_bus_blocked(drvr, state);
+}
+
+void
+brcmf_proto_bcdc_txcomplete(struct device *dev, struct sk_buff *txp,
+ bool success)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_bcdc *bcdc = bus_if->drvr->proto->pd;
+ struct brcmf_if *ifp;
+
+ /* await txstatus signal for firmware if active */
+ if (brcmf_fws_fc_active(bcdc->fws)) {
+ if (!success)
+ brcmf_fws_bustxfail(bcdc->fws, txp);
+ } else {
+ if (brcmf_proto_bcdc_hdrpull(bus_if->drvr, false, txp, &ifp))
+ brcmu_pkt_buf_free_skb(txp);
+ else
+ brcmf_txfinalize(ifp, txp, success);
+ }
+}
+
static void
brcmf_proto_bcdc_configure_addr_mode(struct brcmf_pub *drvr, int ifidx,
enum proto_addr_mode addr_mode)
@@ -369,6 +408,38 @@ static void brcmf_proto_bcdc_rxreorder(struct brcmf_if *ifp,
brcmf_fws_rxreorder(ifp, skb);
}
+static void
+brcmf_proto_bcdc_add_if(struct brcmf_if *ifp)
+{
+ brcmf_fws_add_interface(ifp);
+}
+
+static void
+brcmf_proto_bcdc_del_if(struct brcmf_if *ifp)
+{
+ brcmf_fws_del_interface(ifp);
+}
+
+static void
+brcmf_proto_bcdc_reset_if(struct brcmf_if *ifp)
+{
+ brcmf_fws_reset_interface(ifp);
+}
+
+static int
+brcmf_proto_bcdc_init_done(struct brcmf_pub *drvr)
+{
+ struct brcmf_bcdc *bcdc = drvr->proto->pd;
+ struct brcmf_fws_info *fws;
+
+ fws = brcmf_fws_attach(drvr);
+ if (IS_ERR(fws))
+ return PTR_ERR(fws);
+
+ bcdc->fws = fws;
+ return 0;
+}
+
int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
{
struct brcmf_bcdc *bcdc;
@@ -392,6 +463,10 @@ int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
drvr->proto->delete_peer = brcmf_proto_bcdc_delete_peer;
drvr->proto->add_tdls_peer = brcmf_proto_bcdc_add_tdls_peer;
drvr->proto->rxreorder = brcmf_proto_bcdc_rxreorder;
+ drvr->proto->add_if = brcmf_proto_bcdc_add_if;
+ drvr->proto->del_if = brcmf_proto_bcdc_del_if;
+ drvr->proto->reset_if = brcmf_proto_bcdc_reset_if;
+ drvr->proto->init_done = brcmf_proto_bcdc_init_done;
drvr->proto->pd = bcdc;
drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;
@@ -406,6 +481,9 @@ fail:
void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr)
{
- kfree(drvr->proto->pd);
+ struct brcmf_bcdc *bcdc = drvr->proto->pd;
+
drvr->proto->pd = NULL;
+ brcmf_fws_detach(bcdc->fws);
+ kfree(bcdc);
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h
index 6003179c0ceb..3b0e9eff21b5 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h
@@ -19,6 +19,10 @@
#ifdef CONFIG_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_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) {}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
index 72139b579b18..984c1d0560b1 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -21,6 +21,7 @@
#include <linux/pci_ids.h>
#include <linux/sched.h>
#include <linux/completion.h>
+#include <linux/interrupt.h>
#include <linux/scatterlist.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/core.h>
@@ -107,12 +108,14 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
int ret = 0;
u8 data;
u32 addr, gpiocontrol;
- unsigned long flags;
pdata = &sdiodev->settings->bus.sdio;
if (pdata->oob_irq_supported) {
brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n",
pdata->oob_irq_nr);
+ spin_lock_init(&sdiodev->irq_en_lock);
+ sdiodev->irq_en = true;
+
ret = request_irq(pdata->oob_irq_nr, brcmf_sdiod_oob_irqhandler,
pdata->oob_irq_flags, "brcmf_oob_intr",
&sdiodev->func[1]->dev);
@@ -121,10 +124,6 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
return ret;
}
sdiodev->oob_irq_requested = true;
- spin_lock_init(&sdiodev->irq_en_lock);
- spin_lock_irqsave(&sdiodev->irq_en_lock, flags);
- sdiodev->irq_en = true;
- spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags);
ret = enable_irq_wake(pdata->oob_irq_nr);
if (ret != 0) {
@@ -705,7 +704,7 @@ done:
int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
struct sk_buff_head *pktq, uint totlen)
{
- struct sk_buff *glom_skb;
+ struct sk_buff *glom_skb = NULL;
struct sk_buff *skb;
u32 addr = sdiodev->sbwad;
int err = 0;
@@ -726,10 +725,8 @@ int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
return -ENOMEM;
err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr,
glom_skb);
- if (err) {
- brcmu_pkt_buf_free_skb(glom_skb);
+ if (err)
goto done;
- }
skb_queue_walk(pktq, skb) {
memcpy(skb->data, glom_skb->data, skb->len);
@@ -740,6 +737,7 @@ int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
pktq);
done:
+ brcmu_pkt_buf_free_skb(glom_skb);
return err;
}
@@ -1104,6 +1102,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = {
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4339),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356),
{ /* end: all zeroes */ }
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
index 14a70d4b4e86..3559fb5b8fb0 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
@@ -380,9 +380,7 @@ int brcmf_btcoex_attach(struct brcmf_cfg80211_info *cfg)
/* Set up timer for BT */
btci->timer_on = false;
btci->timeout = BRCMF_BTCOEX_OPPR_WIN_TIME;
- init_timer(&btci->timer);
- btci->timer.data = (ulong)btci;
- btci->timer.function = brcmf_btcoex_timerfunc;
+ setup_timer(&btci->timer, brcmf_btcoex_timerfunc, (ulong)btci);
btci->cfg = cfg;
btci->saved_regs_part1 = false;
btci->saved_regs_part2 = false;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
index e21f7600122b..163ddc49f951 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
@@ -113,6 +113,17 @@ struct brcmf_bus_msgbuf {
/**
+ * struct brcmf_bus_stats - bus statistic counters.
+ *
+ * @pktcowed: packets cowed for extra headroom/unorphan.
+ * @pktcow_failed: packets dropped due to failed cow-ing.
+ */
+struct brcmf_bus_stats {
+ atomic_t pktcowed;
+ atomic_t pktcow_failed;
+};
+
+/**
* struct brcmf_bus - interface structure between common and bus layer
*
* @bus_priv: pointer to private bus device.
@@ -120,11 +131,10 @@ struct brcmf_bus_msgbuf {
* @dev: device pointer of bus device.
* @drvr: public driver information.
* @state: operational state of the bus interface.
+ * @stats: statistics shared between common and bus layer.
* @maxctl: maximum size for rxctl request message.
- * @tx_realloc: number of tx packets realloced for headroom.
- * @dstats: dongle-based statistical data.
- * @dcmd_list: bus/device specific dongle initialization commands.
* @chip: device identifier of the dongle chip.
+ * @always_use_fws_queue: bus wants use queue also when fwsignal is inactive.
* @wowl_supported: is wowl supported by bus driver.
* @chiprev: revision of the dongle chip.
*/
@@ -138,8 +148,8 @@ struct brcmf_bus {
struct device *dev;
struct brcmf_pub *drvr;
enum brcmf_bus_state state;
+ struct brcmf_bus_stats stats;
uint maxctl;
- unsigned long tx_realloc;
u32 chip;
u32 chiprev;
bool always_use_fws_queue;
@@ -218,9 +228,6 @@ int brcmf_bus_get_memdump(struct brcmf_bus *bus, void *data, size_t len)
* interface functions from common layer
*/
-bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt,
- int prec);
-
/* Receive frame for delivery to OS. Callee disposes of rxp. */
void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_event);
/* Receive async event packet from firmware. Callee disposes of rxp. */
@@ -232,22 +239,16 @@ int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings);
void brcmf_detach(struct device *dev);
/* Indication from bus module that dongle should be reset */
void brcmf_dev_reset(struct device *dev);
-/* Indication from bus module to change flow-control state */
-void brcmf_txflowblock(struct device *dev, bool state);
-
-/* Notify the bus has transferred the tx packet to firmware */
-void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success);
/* Configure the "global" bus state used by upper layers */
void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state);
-int brcmf_bus_start(struct device *dev);
+int brcmf_bus_started(struct device *dev);
s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len);
void brcmf_bus_add_txhdrlen(struct device *dev, uint len);
#ifdef CONFIG_BRCMFMAC_SDIO
void brcmf_sdio_exit(void);
-void brcmf_sdio_init(void);
void brcmf_sdio_register(void);
#endif
#ifdef CONFIG_BRCMFMAC_USB
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 7ffc4aba5bab..7e689c86d565 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -138,7 +138,6 @@ static struct ieee80211_rate __wl_rates[] = {
.band = NL80211_BAND_2GHZ, \
.center_freq = (_freq), \
.hw_value = (_channel), \
- .flags = IEEE80211_CHAN_DISABLED, \
.max_antenna_gain = 0, \
.max_power = 30, \
}
@@ -147,7 +146,6 @@ static struct ieee80211_rate __wl_rates[] = {
.band = NL80211_BAND_5GHZ, \
.center_freq = 5000 + (5 * (_channel)), \
.hw_value = (_channel), \
- .flags = IEEE80211_CHAN_DISABLED, \
.max_antenna_gain = 0, \
.max_power = 30, \
}
@@ -328,7 +326,7 @@ u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
* triples, returning a pointer to the substring whose first element
* matches tag
*/
-const struct brcmf_tlv *
+static const struct brcmf_tlv *
brcmf_parse_tlvs(const void *buf, int buflen, uint key)
{
const struct brcmf_tlv *elt = buf;
@@ -577,12 +575,11 @@ static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp)
*
* @wiphy: wiphy device of new interface.
* @name: name of the new interface.
- * @flags: not used.
* @params: contains mac address for AP device.
*/
static
struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name,
- u32 *flags, struct vif_params *params)
+ struct vif_params *params)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
@@ -628,6 +625,7 @@ struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name,
err = brcmf_net_attach(ifp, true);
if (err) {
brcmf_err("Registering netdevice failed\n");
+ free_netdev(ifp->ndev);
goto fail;
}
@@ -655,7 +653,6 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
const char *name,
unsigned char name_assign_type,
enum nl80211_iftype type,
- u32 *flags,
struct vif_params *params)
{
struct wireless_dev *wdev;
@@ -676,12 +673,12 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
case NL80211_IFTYPE_MESH_POINT:
return ERR_PTR(-EOPNOTSUPP);
case NL80211_IFTYPE_AP:
- wdev = brcmf_ap_add_vif(wiphy, name, flags, params);
+ wdev = brcmf_ap_add_vif(wiphy, name, params);
break;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_P2P_DEVICE:
- wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, flags, params);
+ wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, params);
break;
case NL80211_IFTYPE_UNSPECIFIED:
default:
@@ -723,6 +720,8 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
{
struct brcmf_scan_params_le params_le;
struct cfg80211_scan_request *scan_request;
+ u64 reqid;
+ u32 bucket;
s32 err = 0;
brcmf_dbg(SCAN, "Enter\n");
@@ -753,7 +752,7 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
&params_le, sizeof(params_le));
if (err)
- brcmf_err("Scan abort failed\n");
+ brcmf_err("Scan abort failed\n");
}
brcmf_scan_config_mpc(ifp, 1);
@@ -762,11 +761,21 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
* e-scan can be initiated internally
* which takes precedence.
*/
- if (cfg->internal_escan) {
- brcmf_dbg(SCAN, "scheduled scan completed\n");
- cfg->internal_escan = false;
- if (!aborted)
- cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
+ if (cfg->int_escan_map) {
+ brcmf_dbg(SCAN, "scheduled scan completed (%x)\n",
+ cfg->int_escan_map);
+ while (cfg->int_escan_map) {
+ bucket = __ffs(cfg->int_escan_map);
+ cfg->int_escan_map &= ~BIT(bucket);
+ reqid = brcmf_pno_find_reqid_by_bucket(cfg->pno,
+ bucket);
+ if (!aborted) {
+ brcmf_dbg(SCAN, "report results: reqid=%llu\n",
+ reqid);
+ cfg80211_sched_scan_results(cfg_to_wiphy(cfg),
+ reqid);
+ }
+ }
} else if (scan_request) {
struct cfg80211_scan_info info = {
.aborted = aborted,
@@ -860,7 +869,7 @@ int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
static s32
brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
- enum nl80211_iftype type, u32 *flags,
+ enum nl80211_iftype type,
struct vif_params *params)
{
struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
@@ -1015,7 +1024,7 @@ static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
if (!ssid_le.SSID_len)
brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
else
- brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
+ brcmf_dbg(SCAN, "%d: scan for %.32s size=%d\n",
i, ssid_le.SSID, ssid_le.SSID_len);
memcpy(ptr, &ssid_le, sizeof(ssid_le));
ptr += sizeof(ssid_le);
@@ -1348,6 +1357,27 @@ static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e)
return reason;
}
+static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len)
+{
+ struct brcmf_wsec_pmk_le pmk;
+ int i, err;
+
+ /* convert to firmware key format */
+ pmk.key_len = cpu_to_le16(pmk_len << 1);
+ pmk.flags = cpu_to_le16(BRCMF_WSEC_PASSPHRASE);
+ for (i = 0; i < pmk_len; i++)
+ snprintf(&pmk.key[2 * i], 3, "%02x", pmk_data[i]);
+
+ /* store psk in firmware */
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK,
+ &pmk, sizeof(pmk));
+ if (err < 0)
+ brcmf_err("failed to change PSK in firmware (len=%u)\n",
+ pmk_len);
+
+ return err;
+}
+
static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
@@ -1370,6 +1400,10 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
+ if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_NONE) {
+ brcmf_set_pmk(vif->ifp, NULL, 0);
+ vif->profile.use_fwsup = BRCMF_PROFILE_FWSUP_NONE;
+ }
brcmf_dbg(TRACE, "Exit\n");
}
@@ -1683,6 +1717,7 @@ static s32
brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
{
struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
s32 val;
s32 err;
const struct brcmf_tlv *rsn_ie;
@@ -1693,6 +1728,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
u32 mfp;
u16 count;
+ profile->use_fwsup = BRCMF_PROFILE_FWSUP_NONE;
+
if (!sme->crypto.n_akm_suites)
return 0;
@@ -1705,6 +1742,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
switch (sme->crypto.akm_suites[0]) {
case WLAN_AKM_SUITE_8021X:
val = WPA_AUTH_UNSPECIFIED;
+ if (sme->want_1x)
+ profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
break;
case WLAN_AKM_SUITE_PSK:
val = WPA_AUTH_PSK;
@@ -1718,9 +1757,13 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
switch (sme->crypto.akm_suites[0]) {
case WLAN_AKM_SUITE_8021X:
val = WPA2_AUTH_UNSPECIFIED;
+ if (sme->want_1x)
+ profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
break;
case WLAN_AKM_SUITE_8021X_SHA256:
val = WPA2_AUTH_1X_SHA256;
+ if (sme->want_1x)
+ profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
break;
case WLAN_AKM_SUITE_PSK_SHA256:
val = WPA2_AUTH_PSK_SHA256;
@@ -1735,6 +1778,9 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
}
}
+ if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X)
+ brcmf_dbg(INFO, "using 1X offload\n");
+
if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
goto skip_mfp_config;
/* The MFP mode (1 or 2) needs to be determined, parse IEs. The
@@ -1907,6 +1953,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
struct ieee80211_channel *chan = sme->channel;
struct brcmf_join_params join_params;
size_t join_params_size;
@@ -2003,6 +2050,31 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
goto done;
}
+ if (sme->crypto.psk) {
+ if (WARN_ON(profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE)) {
+ err = -EINVAL;
+ goto done;
+ }
+ brcmf_dbg(INFO, "using PSK offload\n");
+ profile->use_fwsup = BRCMF_PROFILE_FWSUP_PSK;
+ }
+
+ if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE) {
+ /* enable firmware supplicant for this interface */
+ err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1);
+ if (err < 0) {
+ brcmf_err("failed to enable fw supplicant\n");
+ goto done;
+ }
+ }
+
+ if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) {
+ err = brcmf_set_pmk(ifp, sme->crypto.psk,
+ BRCMF_WSEC_MAX_PSK_LEN);
+ if (err)
+ goto done;
+ }
+
/* Join with specific BSSID and cached SSID
* If SSID is zero join based on BSSID only
*/
@@ -3015,7 +3087,7 @@ void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
struct escan_info *escan = &cfg->escan_info;
set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
- if (cfg->internal_escan || cfg->scan_request) {
+ if (cfg->int_escan_map || cfg->scan_request) {
escan->escan_state = WL_ESCAN_STATE_IDLE;
brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
}
@@ -3038,7 +3110,7 @@ static void brcmf_escan_timeout(unsigned long data)
struct brcmf_cfg80211_info *cfg =
(struct brcmf_cfg80211_info *)data;
- if (cfg->internal_escan || cfg->scan_request) {
+ if (cfg->int_escan_map || cfg->scan_request) {
brcmf_err("timer expired\n");
schedule_work(&cfg->escan_timeout_work);
}
@@ -3099,6 +3171,9 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
status = e->status;
+ if (status == BRCMF_E_STATUS_ABORT)
+ goto exit;
+
if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
brcmf_err("scan not ready, bsscfgidx=%d\n", ifp->bsscfgidx);
return -EPERM;
@@ -3121,7 +3196,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
goto exit;
- if (!cfg->internal_escan && !cfg->scan_request) {
+ if (!cfg->int_escan_map && !cfg->scan_request) {
brcmf_dbg(SCAN, "result without cfg80211 request\n");
goto exit;
}
@@ -3167,7 +3242,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
goto exit;
- if (cfg->internal_escan || cfg->scan_request) {
+ if (cfg->int_escan_map || cfg->scan_request) {
brcmf_inform_bss(cfg);
aborted = status != BRCMF_E_STATUS_SUCCESS;
brcmf_notify_escan_complete(cfg, ifp, aborted, false);
@@ -3215,7 +3290,7 @@ static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req,
{
struct ieee80211_channel *chan;
enum nl80211_band band;
- int freq;
+ int freq, i;
if (channel <= CH_MAX_2G_CHANNEL)
band = NL80211_BAND_2GHZ;
@@ -3230,24 +3305,40 @@ static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req,
if (!chan)
return -EINVAL;
- req->channels[req->n_channels++] = chan;
- memcpy(req->ssids[req->n_ssids].ssid, ssid, ssid_len);
- req->ssids[req->n_ssids++].ssid_len = ssid_len;
+ for (i = 0; i < req->n_channels; i++) {
+ if (req->channels[i] == chan)
+ break;
+ }
+ if (i == req->n_channels)
+ req->channels[req->n_channels++] = chan;
+ for (i = 0; i < req->n_ssids; i++) {
+ if (req->ssids[i].ssid_len == ssid_len &&
+ !memcmp(req->ssids[i].ssid, ssid, ssid_len))
+ break;
+ }
+ if (i == req->n_ssids) {
+ memcpy(req->ssids[req->n_ssids].ssid, ssid, ssid_len);
+ req->ssids[req->n_ssids++].ssid_len = ssid_len;
+ }
return 0;
}
-static int brcmf_start_internal_escan(struct brcmf_if *ifp,
+static int brcmf_start_internal_escan(struct brcmf_if *ifp, u32 fwmap,
struct cfg80211_scan_request *request)
{
struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
int err;
if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
+ if (cfg->int_escan_map)
+ brcmf_dbg(SCAN, "aborting internal scan: map=%u\n",
+ cfg->int_escan_map);
/* Abort any on-going scan */
brcmf_abort_scanning(cfg);
}
+ brcmf_dbg(SCAN, "start internal scan: map=%u\n", fwmap);
set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
cfg->escan_info.run = brcmf_run_escan;
err = brcmf_do_escan(ifp, request);
@@ -3255,7 +3346,7 @@ static int brcmf_start_internal_escan(struct brcmf_if *ifp,
clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
return err;
}
- cfg->internal_escan = true;
+ cfg->int_escan_map = fwmap;
return 0;
}
@@ -3297,8 +3388,10 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
struct wiphy *wiphy = cfg_to_wiphy(cfg);
int i, err = 0;
struct brcmf_pno_scanresults_le *pfn_result;
+ u32 bucket_map;
u32 result_count;
u32 status;
+ u32 datalen;
brcmf_dbg(SCAN, "Enter\n");
@@ -3325,6 +3418,14 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
goto out_err;
}
+
+ netinfo_start = brcmf_get_netinfo_array(pfn_result);
+ datalen = e->datalen - ((void *)netinfo_start - (void *)pfn_result);
+ if (datalen < result_count * sizeof(*netinfo)) {
+ brcmf_err("insufficient event data\n");
+ goto out_err;
+ }
+
request = brcmf_alloc_internal_escan_request(wiphy,
result_count);
if (!request) {
@@ -3332,20 +3433,15 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
goto out_err;
}
- data += sizeof(struct brcmf_pno_scanresults_le);
- netinfo_start = brcmf_get_netinfo_array(pfn_result);
-
+ bucket_map = 0;
for (i = 0; i < result_count; i++) {
netinfo = &netinfo_start[i];
- if (!netinfo) {
- brcmf_err("Invalid netinfo ptr. index: %d\n",
- i);
- err = -EINVAL;
- goto out_err;
- }
+ if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN)
+ netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n",
netinfo->SSID, netinfo->channel);
+ bucket_map |= brcmf_pno_get_bucket_map(cfg->pno, netinfo);
err = brcmf_internal_escan_add_info(request,
netinfo->SSID,
netinfo->SSID_len,
@@ -3354,12 +3450,15 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
goto out_err;
}
- err = brcmf_start_internal_escan(ifp, request);
+ if (!bucket_map)
+ goto free_req;
+
+ err = brcmf_start_internal_escan(ifp, bucket_map, request);
if (!err)
goto free_req;
out_err:
- cfg80211_sched_scan_stopped(wiphy);
+ cfg80211_sched_scan_stopped(wiphy, 0);
free_req:
kfree(request);
return err;
@@ -3373,11 +3472,11 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
- brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
+ brcmf_dbg(SCAN, "Enter: n_match_sets=%d n_ssids=%d\n",
req->n_match_sets, req->n_ssids);
if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
- brcmf_err("Scanning suppressed: status (%lu)\n",
+ brcmf_err("Scanning suppressed: status=%lu\n",
cfg->scan_status);
return -EAGAIN;
}
@@ -3392,14 +3491,14 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
}
static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
- struct net_device *ndev)
+ struct net_device *ndev, u64 reqid)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
brcmf_dbg(SCAN, "enter\n");
- brcmf_pno_clean(ifp);
- if (cfg->internal_escan)
+ brcmf_pno_stop_sched_scan(ifp, reqid);
+ if (cfg->int_escan_map)
brcmf_notify_escan_complete(cfg, ifp, true, true);
return 0;
}
@@ -3480,8 +3579,7 @@ brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
return -EINVAL;
}
- data += sizeof(struct brcmf_pno_scanresults_le);
- netinfo = (struct brcmf_pno_net_info_le *)data;
+ netinfo = brcmf_get_netinfo_array(pfn_result);
memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
cfg->wowl.nd->n_channels = 1;
@@ -3595,7 +3693,7 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
cfg->wowl.pre_pmmode);
cfg->wowl.active = false;
if (cfg->wowl.nd_enabled) {
- brcmf_cfg80211_sched_scan_stop(cfg->wiphy, ifp->ndev);
+ brcmf_cfg80211_sched_scan_stop(cfg->wiphy, ifp->ndev, 0);
brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
brcmf_notify_sched_scan_results);
@@ -3679,7 +3777,7 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
/* Stop scheduled scan */
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
- brcmf_cfg80211_sched_scan_stop(wiphy, ndev);
+ brcmf_cfg80211_sched_scan_stop(wiphy, ndev, 0);
/* end any scanning */
if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
@@ -3971,7 +4069,7 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
pval |= AES_ENABLED;
break;
default:
- brcmf_err("Ivalid unicast security info\n");
+ brcmf_err("Invalid unicast security info\n");
}
offset++;
}
@@ -4015,7 +4113,7 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
wpa_auth |= WPA2_AUTH_1X_SHA256;
break;
default:
- brcmf_err("Ivalid key mgmt info\n");
+ brcmf_err("Invalid key mgmt info\n");
}
offset++;
}
@@ -4662,9 +4760,6 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
if (err < 0)
brcmf_err("setting AP mode failed %d\n", err);
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
- if (err < 0)
- brcmf_err("setting INFRA mode failed %d\n", err);
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
brcmf_fil_iovar_int_set(ifp, "mbss", 0);
brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
@@ -4839,6 +4934,11 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
GFP_KERNEL);
} else if (ieee80211_is_action(mgmt->frame_control)) {
+ if (len > BRCMF_FIL_ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN) {
+ brcmf_err("invalid action frame length\n");
+ err = -EINVAL;
+ goto exit;
+ }
af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
if (af_params == NULL) {
brcmf_err("unable to allocate frame\n");
@@ -4878,7 +4978,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
kfree(af_params);
} else {
brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
- brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
+ brcmf_dbg_hex_dump(true, buf, len, "payload, len=%zu\n", len);
}
exit:
@@ -5071,6 +5171,29 @@ static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
return ret;
}
+static int
+brcmf_cfg80211_update_conn_params(struct wiphy *wiphy,
+ struct net_device *ndev,
+ struct cfg80211_connect_params *sme,
+ u32 changed)
+{
+ struct brcmf_if *ifp;
+ int err;
+
+ if (!(changed & UPDATE_ASSOC_IES))
+ return 0;
+
+ ifp = netdev_priv(ndev);
+ err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
+ sme->ie, sme->ie_len);
+ if (err)
+ brcmf_err("Set Assoc REQ IE Failed\n");
+ else
+ brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
+
+ return err;
+}
+
#ifdef CONFIG_PM
static int
brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
@@ -5096,6 +5219,34 @@ brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
}
#endif
+static int brcmf_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
+ const struct cfg80211_pmk_conf *conf)
+{
+ struct brcmf_if *ifp;
+
+ brcmf_dbg(TRACE, "enter\n");
+
+ /* expect using firmware supplicant for 1X */
+ ifp = netdev_priv(dev);
+ if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X))
+ return -EINVAL;
+
+ return brcmf_set_pmk(ifp, conf->pmk, conf->pmk_len);
+}
+
+static int brcmf_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *aa)
+{
+ struct brcmf_if *ifp;
+
+ brcmf_dbg(TRACE, "enter\n");
+ ifp = netdev_priv(dev);
+ if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X))
+ return -EINVAL;
+
+ return brcmf_set_pmk(ifp, NULL, 0);
+}
+
static struct cfg80211_ops brcmf_cfg80211_ops = {
.add_virtual_intf = brcmf_cfg80211_add_iface,
.del_virtual_intf = brcmf_cfg80211_del_iface,
@@ -5138,6 +5289,9 @@ static struct cfg80211_ops brcmf_cfg80211_ops = {
.crit_proto_start = brcmf_cfg80211_crit_proto_start,
.crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
.tdls_oper = brcmf_cfg80211_tdls_oper,
+ .update_connect_params = brcmf_cfg80211_update_conn_params,
+ .set_pmk = brcmf_cfg80211_set_pmk,
+ .del_pmk = brcmf_cfg80211_del_pmk,
};
struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
@@ -5189,19 +5343,33 @@ void brcmf_cfg80211_free_netdev(struct net_device *ndev)
if (vif)
brcmf_free_vif(vif);
- free_netdev(ndev);
}
-static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
+static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif,
+ const struct brcmf_event_msg *e)
{
u32 event = e->event_code;
u32 status = e->status;
+ if (vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_PSK &&
+ event == BRCMF_E_PSK_SUP &&
+ status == BRCMF_E_STATUS_FWSUP_COMPLETED)
+ set_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
brcmf_dbg(CONN, "Processing set ssid\n");
- return true;
+ memcpy(vif->profile.bssid, e->addr, ETH_ALEN);
+ if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_PSK)
+ return true;
+
+ set_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
}
+ if (test_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state) &&
+ test_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state)) {
+ clear_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
+ clear_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
+ return true;
+ }
return false;
}
@@ -5236,6 +5404,13 @@ static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
return true;
}
+ if (event == BRCMF_E_PSK_SUP &&
+ status != BRCMF_E_STATUS_FWSUP_COMPLETED) {
+ brcmf_dbg(CONN, "Processing failed supplicant state: %u\n",
+ status);
+ return true;
+ }
+
return false;
}
@@ -5323,6 +5498,7 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
struct ieee80211_supported_band *band;
struct brcmf_bss_info_le *bi;
struct brcmu_chan ch;
+ struct cfg80211_roam_info roam_info = {};
u32 freq;
s32 err = 0;
u8 *buf;
@@ -5361,9 +5537,15 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
done:
kfree(buf);
- cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
- conn_info->req_ie, conn_info->req_ie_len,
- conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
+
+ roam_info.channel = notify_channel;
+ roam_info.bssid = profile->bssid;
+ roam_info.req_ie = conn_info->req_ie;
+ roam_info.req_ie_len = conn_info->req_ie_len;
+ roam_info.resp_ie = conn_info->resp_ie;
+ roam_info.resp_ie_len = conn_info->resp_ie_len;
+
+ cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
brcmf_dbg(CONN, "Report roaming result\n");
set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
@@ -5379,27 +5561,28 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
+ struct cfg80211_connect_resp_params conn_params;
brcmf_dbg(TRACE, "Enter\n");
if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
&ifp->vif->sme_state)) {
+ memset(&conn_params, 0, sizeof(conn_params));
if (completed) {
brcmf_get_assoc_ies(cfg, ifp);
- memcpy(profile->bssid, e->addr, ETH_ALEN);
brcmf_update_bss_info(cfg, ifp);
set_bit(BRCMF_VIF_STATUS_CONNECTED,
&ifp->vif->sme_state);
+ conn_params.status = WLAN_STATUS_SUCCESS;
+ } else {
+ conn_params.status = WLAN_STATUS_AUTH_TIMEOUT;
}
- cfg80211_connect_result(ndev,
- (u8 *)profile->bssid,
- conn_info->req_ie,
- conn_info->req_ie_len,
- conn_info->resp_ie,
- conn_info->resp_ie_len,
- completed ? WLAN_STATUS_SUCCESS :
- WLAN_STATUS_AUTH_TIMEOUT,
- GFP_KERNEL);
+ conn_params.bssid = profile->bssid;
+ conn_params.req_ie = conn_info->req_ie;
+ conn_params.req_ie_len = conn_info->req_ie_len;
+ conn_params.resp_ie = conn_info->resp_ie;
+ conn_params.resp_ie_len = conn_info->resp_ie_len;
+ cfg80211_connect_done(ndev, &conn_params, GFP_KERNEL);
brcmf_dbg(CONN, "Report connect result - connection %s\n",
completed ? "succeeded" : "failed");
}
@@ -5465,7 +5648,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
if (brcmf_is_apmode(ifp->vif)) {
err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
- } else if (brcmf_is_linkup(e)) {
+ } else if (brcmf_is_linkup(ifp->vif, e)) {
brcmf_dbg(CONN, "Linkup\n");
if (brcmf_is_ibssmode(ifp->vif)) {
brcmf_inform_ibss(cfg, ndev, e->addr);
@@ -5633,6 +5816,8 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
brcmf_p2p_notify_action_tx_complete);
brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
brcmf_p2p_notify_action_tx_complete);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_PSK_SUP,
+ brcmf_notify_connect_status);
}
static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
@@ -5825,7 +6010,6 @@ static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
u32 i, j;
u32 total;
u32 chaninfo;
- u32 index;
pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
@@ -5873,33 +6057,39 @@ static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
ch.bw == BRCMU_CHAN_BW_80)
continue;
- channel = band->channels;
- index = band->n_channels;
+ channel = NULL;
for (j = 0; j < band->n_channels; j++) {
- if (channel[j].hw_value == ch.control_ch_num) {
- index = j;
+ if (band->channels[j].hw_value == ch.control_ch_num) {
+ channel = &band->channels[j];
break;
}
}
- channel[index].center_freq =
- ieee80211_channel_to_frequency(ch.control_ch_num,
- band->band);
- channel[index].hw_value = ch.control_ch_num;
+ if (!channel) {
+ /* It seems firmware supports some channel we never
+ * considered. Something new in IEEE standard?
+ */
+ brcmf_err("Ignoring unexpected firmware channel %d\n",
+ ch.control_ch_num);
+ continue;
+ }
+
+ if (channel->orig_flags & IEEE80211_CHAN_DISABLED)
+ continue;
/* assuming the chanspecs order is HT20,
* HT40 upper, HT40 lower, and VHT80.
*/
if (ch.bw == BRCMU_CHAN_BW_80) {
- channel[index].flags &= ~IEEE80211_CHAN_NO_80MHZ;
+ channel->flags &= ~IEEE80211_CHAN_NO_80MHZ;
} else if (ch.bw == BRCMU_CHAN_BW_40) {
- brcmf_update_bw40_channel_flag(&channel[index], &ch);
+ brcmf_update_bw40_channel_flag(channel, &ch);
} else {
/* enable the channel and disable other bandwidths
* for now as mentioned order assure they are enabled
* for subsequent chanspecs.
*/
- channel[index].flags = IEEE80211_CHAN_NO_HT40 |
- IEEE80211_CHAN_NO_80MHZ;
+ channel->flags = IEEE80211_CHAN_NO_HT40 |
+ IEEE80211_CHAN_NO_80MHZ;
ch.bw = BRCMU_CHAN_BW_20;
cfg->d11inf.encchspec(&ch);
chaninfo = ch.chspec;
@@ -5907,11 +6097,11 @@ static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
&chaninfo);
if (!err) {
if (chaninfo & WL_CHAN_RADAR)
- channel[index].flags |=
+ channel->flags |=
(IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR);
if (chaninfo & WL_CHAN_PASSIVE)
- channel[index].flags |=
+ channel->flags |=
IEEE80211_CHAN_NO_IR;
}
}
@@ -6330,18 +6520,8 @@ err:
return -ENOMEM;
}
-static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
-{
- /* scheduled scan settings */
- wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
- wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
- wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
- wiphy->max_sched_scan_plan_interval = BRCMF_PNO_SCHED_SCAN_MAX_PERIOD;
- wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
-}
-
#ifdef CONFIG_PM
-static struct wiphy_wowlan_support brcmf_wowlan_support = {
+static const struct wiphy_wowlan_support brcmf_wowlan_support = {
.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
.n_patterns = BRCMF_WOWL_MAXPATTERNS,
.pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
@@ -6354,19 +6534,29 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
{
#ifdef CONFIG_PM
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct wiphy_wowlan_support *wowl;
+
+ wowl = kmemdup(&brcmf_wowlan_support, sizeof(brcmf_wowlan_support),
+ GFP_KERNEL);
+ if (!wowl) {
+ brcmf_err("only support basic wowlan features\n");
+ wiphy->wowlan = &brcmf_wowlan_support;
+ return;
+ }
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
- brcmf_wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT;
+ wowl->flags |= WIPHY_WOWLAN_NET_DETECT;
+ wowl->max_nd_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
init_waitqueue_head(&cfg->wowl.nd_data_wait);
}
}
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
- brcmf_wowlan_support.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
- brcmf_wowlan_support.flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
+ wowl->flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
+ wowl->flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
}
- wiphy->wowlan = &brcmf_wowlan_support;
+ wiphy->wowlan = wowl;
#endif
}
@@ -6376,6 +6566,7 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
const struct ieee80211_iface_combination *combo;
struct ieee80211_supported_band *band;
u16 max_interfaces = 0;
+ bool gscan;
__le32 bandlist[3];
u32 n_bands;
int err, i;
@@ -6415,18 +6606,26 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
BIT(NL80211_BSS_SELECT_ATTR_BAND_PREF) |
BIT(NL80211_BSS_SELECT_ATTR_RSSI_ADJUST);
- wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
+ wiphy->flags |= WIPHY_FLAG_NETNS_OK |
+ WIPHY_FLAG_PS_ON_BY_DEFAULT |
WIPHY_FLAG_OFFCHAN_TX |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS))
wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
if (!ifp->drvr->settings->roamoff)
wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP)) {
+ wiphy_ext_feature_set(wiphy,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
+ wiphy_ext_feature_set(wiphy,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X);
+ }
wiphy->mgmt_stypes = brcmf_txrx_stypes;
wiphy->max_remain_on_channel_duration = 5000;
- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
- brcmf_wiphy_pno_params(wiphy);
-
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
+ gscan = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_GSCAN);
+ brcmf_pno_wiphy_params(wiphy, gscan);
+ }
/* vendor commands/events support */
wiphy->vendor_commands = brcmf_vendor_cmds;
wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
@@ -6477,8 +6676,10 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
wiphy->bands[NL80211_BAND_5GHZ] = band;
}
}
- err = brcmf_setup_wiphybands(wiphy);
- return err;
+
+ wiphy_read_of_freq_limits(wiphy);
+
+ return 0;
}
static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
@@ -6512,7 +6713,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
if (err)
goto default_conf_out;
err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
- NULL, NULL);
+ NULL);
if (err)
goto default_conf_out;
@@ -6699,10 +6900,14 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
s32 err;
int i;
+ /* The country code gets set to "00" by default at boot, ignore */
+ if (req->alpha2[0] == '0' && req->alpha2[1] == '0')
+ return;
+
/* ignore non-ISO3166 country codes */
for (i = 0; i < sizeof(req->alpha2); i++)
if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
- brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n",
+ brcmf_err("not an ISO3166 code (0x%02x 0x%02x)\n",
req->alpha2[0], req->alpha2[1]);
return;
}
@@ -6748,6 +6953,10 @@ static void brcmf_free_wiphy(struct wiphy *wiphy)
kfree(wiphy->bands[NL80211_BAND_5GHZ]->channels);
kfree(wiphy->bands[NL80211_BAND_5GHZ]);
}
+#if IS_ENABLED(CONFIG_PM)
+ if (wiphy->wowlan != &brcmf_wowlan_support)
+ kfree(wiphy->wowlan);
+#endif
wiphy_free(wiphy);
}
@@ -6782,7 +6991,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
if (!wiphy) {
brcmf_err("Could not allocate wiphy device\n");
- return NULL;
+ goto ops_out;
}
memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
set_wiphy_dev(wiphy, busdev);
@@ -6843,6 +7052,12 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
goto priv_out;
}
+ err = brcmf_setup_wiphybands(wiphy);
+ if (err) {
+ brcmf_err("Setting wiphy bands failed (%d)\n", err);
+ goto wiphy_unreg_out;
+ }
+
/* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
* setup 40MHz in 2GHz band and enable OBSS scanning.
*/
@@ -6877,6 +7092,13 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
brcmf_p2p_detach(&cfg->p2p);
goto wiphy_unreg_out;
}
+ err = brcmf_pno_attach(cfg);
+ if (err) {
+ brcmf_err("PNO initialisation failed (%d)\n", err);
+ brcmf_btcoex_detach(cfg);
+ brcmf_p2p_detach(&cfg->p2p);
+ goto wiphy_unreg_out;
+ }
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) {
err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
@@ -6909,6 +7131,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
return cfg;
detach:
+ brcmf_pno_detach(cfg);
brcmf_btcoex_detach(cfg);
brcmf_p2p_detach(&cfg->p2p);
wiphy_unreg_out:
@@ -6919,6 +7142,7 @@ priv_out:
ifp->vif = NULL;
wiphy_out:
brcmf_free_wiphy(wiphy);
+ops_out:
kfree(ops);
return NULL;
}
@@ -6928,6 +7152,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
if (!cfg)
return;
+ brcmf_pno_detach(cfg);
brcmf_btcoex_detach(cfg);
wiphy_unregister(cfg->wiphy);
kfree(cfg->ops);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
index 0c9a7081fca9..7b2835e5e434 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
@@ -24,6 +24,8 @@
#include "fwil_types.h"
#include "p2p.h"
+#define BRCMF_SCAN_IE_LEN_MAX 2048
+
#define WL_NUM_SCAN_MAX 10
#define WL_TLV_INFO_MAX 1024
#define WL_BSS_INFO_MAX 2048
@@ -113,6 +115,12 @@ struct brcmf_cfg80211_security {
u32 cipher_group;
};
+enum brcmf_profile_fwsup {
+ BRCMF_PROFILE_FWSUP_NONE,
+ BRCMF_PROFILE_FWSUP_PSK,
+ BRCMF_PROFILE_FWSUP_1X
+};
+
/**
* struct brcmf_cfg80211_profile - profile information.
*
@@ -124,6 +132,7 @@ struct brcmf_cfg80211_profile {
u8 bssid[ETH_ALEN];
struct brcmf_cfg80211_security sec;
struct brcmf_wsec_key key[BRCMF_MAX_DEFAULT_KEYS];
+ enum brcmf_profile_fwsup use_fwsup;
};
/**
@@ -131,16 +140,20 @@ struct brcmf_cfg80211_profile {
*
* @BRCMF_VIF_STATUS_READY: ready for operation.
* @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress.
- * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully.
+ * @BRCMF_VIF_STATUS_CONNECTED: connected/joined successfully.
* @BRCMF_VIF_STATUS_DISCONNECTING: disconnect/disable in progress.
* @BRCMF_VIF_STATUS_AP_CREATED: AP operation started.
+ * @BRCMF_VIF_STATUS_EAP_SUCCUSS: EAPOL handshake successful.
+ * @BRCMF_VIF_STATUS_ASSOC_SUCCESS: successful SET_SSID received.
*/
enum brcmf_vif_status {
BRCMF_VIF_STATUS_READY,
BRCMF_VIF_STATUS_CONNECTING,
BRCMF_VIF_STATUS_CONNECTED,
BRCMF_VIF_STATUS_DISCONNECTING,
- BRCMF_VIF_STATUS_AP_CREATED
+ BRCMF_VIF_STATUS_AP_CREATED,
+ BRCMF_VIF_STATUS_EAP_SUCCESS,
+ BRCMF_VIF_STATUS_ASSOC_SUCCESS,
};
/**
@@ -271,7 +284,7 @@ struct brcmf_cfg80211_wowl {
* @pub: common driver information.
* @channel: current channel.
* @active_scan: current scan mode.
- * @internal_escan: indicates internally initiated e-scan is running.
+ * @int_escan_map: bucket map for which internal e-scan is done.
* @ibss_starter: indicates this sta is ibss starter.
* @pwr_save: indicate whether dongle to support power save mode.
* @dongle_up: indicate whether dongle up or not.
@@ -287,6 +300,7 @@ struct brcmf_cfg80211_wowl {
* @vif_cnt: number of vif instances.
* @vif_event: vif event signalling.
* @wowl: wowl related information.
+ * @pno: information of pno module.
*/
struct brcmf_cfg80211_info {
struct wiphy *wiphy;
@@ -303,7 +317,7 @@ struct brcmf_cfg80211_info {
struct brcmf_pub *pub;
u32 channel;
bool active_scan;
- bool internal_escan;
+ u32 int_escan_map;
bool ibss_starter;
bool pwr_save;
bool dongle_up;
@@ -320,6 +334,7 @@ struct brcmf_cfg80211_info {
struct brcmu_d11inf d11inf;
struct brcmf_assoclist_le assoclist;
struct brcmf_cfg80211_wowl wowl;
+ struct brcmf_pno_info *pno;
};
/**
@@ -396,8 +411,6 @@ void brcmf_free_vif(struct brcmf_cfg80211_vif *vif);
s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
const u8 *vndr_ie_buf, u32 vndr_ie_len);
s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif);
-const struct brcmf_tlv *
-brcmf_parse_tlvs(const void *buf, int buflen, uint key);
u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
struct ieee80211_channel *ch);
bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
index 3e15d64c6481..7a2b49587b4d 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -74,7 +74,7 @@ module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
MODULE_PARM_DESC(roamoff, "Do not use internal roaming engine");
#ifdef DEBUG
-/* always succeed brcmf_bus_start() */
+/* always succeed brcmf_bus_started() */
static int brcmf_ignore_probe_fail;
module_param_named(ignore_probe_fail, brcmf_ignore_probe_fail, int, 0);
MODULE_PARM_DESC(ignore_probe_fail, "always succeed probe for debugging");
@@ -161,7 +161,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
strsep(&ptr, "\n");
/* Print fw version info */
- brcmf_err("Firmware version = %s\n", buf);
+ brcmf_info("Firmware version = %s\n", buf);
/* locate firmware version number for ethtool */
ptr = strrchr(buf, ' ') + 1;
@@ -218,6 +218,22 @@ done:
return err;
}
+#ifndef CONFIG_BRCM_TRACING
+void __brcmf_err(const char *func, const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+ pr_err("%s: %pV", func, &vaf);
+
+ va_end(args);
+}
+#endif
+
#if defined(CONFIG_BRCM_TRACING) || defined(CONFIG_BRCMDBG)
void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...)
{
@@ -299,11 +315,9 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
}
}
}
- if ((bus_type == BRCMF_BUSTYPE_SDIO) && (!found)) {
- /* No platform data for this device. In case of SDIO try OF
- * (Open Firwmare) Device Tree.
- */
- brcmf_of_probe(dev, &settings->bus.sdio);
+ if (!found) {
+ /* No platform data for this device, try OF (Open Firwmare) */
+ brcmf_of_probe(dev, bus_type, settings);
}
return settings;
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
index bd095abca393..a62f8e70b320 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
@@ -65,6 +65,8 @@ struct brcmf_mp_device {
} bus;
};
+void brcmf_c_set_joinpref_default(struct brcmf_if *ifp);
+
struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
enum brcmf_bus_type bus_type,
u32 chip, u32 chiprev);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index 9e6f60a0ec3e..2153e8062b4c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -30,9 +30,9 @@
#include "debug.h"
#include "fwil_types.h"
#include "p2p.h"
+#include "pno.h"
#include "cfg80211.h"
#include "fwil.h"
-#include "fwsignal.h"
#include "feature.h"
#include "proto.h"
#include "pcie.h"
@@ -198,7 +198,8 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
int ret;
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
- struct ethhdr *eh = (struct ethhdr *)(skb->data);
+ struct ethhdr *eh;
+ int head_delta;
brcmf_dbg(DATA, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx);
@@ -211,20 +212,19 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
goto done;
}
- /* Make sure there's enough room for any header */
- if (skb_headroom(skb) < drvr->hdrlen) {
- struct sk_buff *skb2;
-
- brcmf_dbg(INFO, "%s: insufficient headroom\n",
- brcmf_ifname(ifp));
- drvr->bus_if->tx_realloc++;
- skb2 = skb_realloc_headroom(skb, drvr->hdrlen);
- dev_kfree_skb(skb);
- skb = skb2;
- if (skb == NULL) {
- brcmf_err("%s: skb_realloc_headroom failed\n",
+ /* Make sure there's enough writeable headroom */
+ if (skb_headroom(skb) < drvr->hdrlen || skb_header_cloned(skb)) {
+ head_delta = drvr->hdrlen - skb_headroom(skb);
+
+ brcmf_dbg(INFO, "%s: insufficient headroom (%d)\n",
+ brcmf_ifname(ifp), head_delta);
+ atomic_inc(&drvr->bus_if->stats.pktcowed);
+ ret = pskb_expand_head(skb, ALIGN(head_delta, NET_SKB_PAD), 0,
+ GFP_ATOMIC);
+ if (ret < 0) {
+ brcmf_err("%s: failed to expand headroom\n",
brcmf_ifname(ifp));
- ret = -ENOMEM;
+ atomic_inc(&drvr->bus_if->stats.pktcow_failed);
goto done;
}
}
@@ -236,6 +236,8 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
goto done;
}
+ eh = (struct ethhdr *)(skb->data);
+
if (eh->h_proto == htons(ETH_P_PAE))
atomic_inc(&ifp->pend_8021x_cnt);
@@ -249,10 +251,10 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
done:
if (ret) {
- ifp->stats.tx_dropped++;
+ ndev->stats.tx_dropped++;
} else {
- ifp->stats.tx_packets++;
- ifp->stats.tx_bytes += skb->len;
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += skb->len;
}
/* Return ok: we always eat the packet */
@@ -283,28 +285,18 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp,
spin_unlock_irqrestore(&ifp->netif_stop_lock, flags);
}
-void brcmf_txflowblock(struct device *dev, bool state)
-{
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_pub *drvr = bus_if->drvr;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- brcmf_fws_bus_blocked(drvr, state);
-}
-
void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
{
if (skb->pkt_type == PACKET_MULTICAST)
- ifp->stats.multicast++;
+ ifp->ndev->stats.multicast++;
if (!(ifp->ndev->flags & IFF_UP)) {
brcmu_pkt_buf_free_skb(skb);
return;
}
- ifp->stats.rx_bytes += skb->len;
- ifp->stats.rx_packets++;
+ ifp->ndev->stats.rx_bytes += skb->len;
+ ifp->ndev->stats.rx_packets++;
brcmf_dbg(DATA, "rx proto=0x%X\n", ntohs(skb->protocol));
if (in_interrupt())
@@ -327,7 +319,7 @@ static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb,
if (ret || !(*ifp) || !(*ifp)->ndev) {
if (ret != -ENODATA && *ifp)
- (*ifp)->stats.rx_errors++;
+ (*ifp)->ndev->stats.rx_errors++;
brcmu_pkt_buf_free_skb(skb);
return -ENODATA;
}
@@ -388,38 +380,11 @@ void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
}
if (!success)
- ifp->stats.tx_errors++;
+ ifp->ndev->stats.tx_errors++;
brcmu_pkt_buf_free_skb(txp);
}
-void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
-{
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_pub *drvr = bus_if->drvr;
- struct brcmf_if *ifp;
-
- /* await txstatus signal for firmware if active */
- if (brcmf_fws_fc_active(drvr->fws)) {
- if (!success)
- brcmf_fws_bustxfail(drvr->fws, txp);
- } else {
- if (brcmf_proto_hdrpull(drvr, false, txp, &ifp))
- brcmu_pkt_buf_free_skb(txp);
- else
- brcmf_txfinalize(ifp, txp, success);
- }
-}
-
-static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
-
- brcmf_dbg(TRACE, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx);
-
- return &ifp->stats;
-}
-
static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
struct ethtool_drvinfo *info)
{
@@ -492,7 +457,6 @@ static int brcmf_netdev_open(struct net_device *ndev)
static const struct net_device_ops brcmf_netdev_ops_pri = {
.ndo_open = brcmf_netdev_open,
.ndo_stop = brcmf_netdev_stop,
- .ndo_get_stats = brcmf_netdev_get_stats,
.ndo_start_xmit = brcmf_netdev_start_xmit,
.ndo_set_mac_address = brcmf_netdev_set_mac_address,
.ndo_set_rx_mode = brcmf_netdev_set_multicast_list
@@ -514,8 +478,9 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
ndev->needed_headroom += drvr->hdrlen;
ndev->ethtool_ops = &brcmf_ethtool_ops;
- /* set the mac address */
+ /* set the mac address & netns */
memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
+ dev_net_set(ndev, wiphy_net(cfg_to_wiphy(drvr->config)));
INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
INIT_WORK(&ifp->ndoffload_work, _brcmf_update_ndtable);
@@ -529,13 +494,13 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
goto fail;
}
+ ndev->priv_destructor = brcmf_cfg80211_free_netdev;
brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
return 0;
fail:
drvr->iflist[ifp->bsscfgidx] = NULL;
ndev->netdev_ops = NULL;
- free_netdev(ndev);
return -EBADE;
}
@@ -548,6 +513,7 @@ static void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked)
unregister_netdev(ndev);
} else {
brcmf_cfg80211_free_netdev(ndev);
+ free_netdev(ndev);
}
}
@@ -624,7 +590,6 @@ static int brcmf_net_p2p_attach(struct brcmf_if *ifp)
fail:
ifp->drvr->iflist[ifp->bsscfgidx] = NULL;
ndev->netdev_ops = NULL;
- free_netdev(ndev);
return -EBADE;
}
@@ -669,7 +634,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx,
if (!ndev)
return ERR_PTR(-ENOMEM);
- ndev->destructor = brcmf_cfg80211_free_netdev;
+ ndev->needs_free_netdev = true;
ifp = netdev_priv(ndev);
ifp->ndev = ndev;
/* store mapping ifidx to bsscfgidx */
@@ -744,10 +709,28 @@ void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked)
return;
brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, ifidx=%d\n", ifp->bsscfgidx,
ifp->ifidx);
- brcmf_fws_del_interface(ifp);
+ brcmf_proto_del_if(ifp->drvr, ifp);
brcmf_del_if(ifp->drvr, ifp->bsscfgidx, rtnl_locked);
}
+static int brcmf_psm_watchdog_notify(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *evtmsg,
+ void *data)
+{
+ int err;
+
+ brcmf_dbg(TRACE, "enter: bsscfgidx=%d\n", ifp->bsscfgidx);
+
+ brcmf_err("PSM's watchdog has fired!\n");
+
+ err = brcmf_debug_create_memdump(ifp->drvr->bus_if, data,
+ evtmsg->datalen);
+ if (err)
+ brcmf_err("Failed to get memory dump, %d\n", err);
+
+ return err;
+}
+
#ifdef CONFIG_INET
#define ARPOL_MAX_ENTRIES 8
static int brcmf_inetaddr_changed(struct notifier_block *nb,
@@ -927,6 +910,10 @@ int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings)
goto fail;
}
+ /* Attach to events important for core code */
+ brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG,
+ brcmf_psm_watchdog_notify);
+
/* attach firmware event handler */
brcmf_fweh_attach(drvr);
@@ -966,7 +953,7 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data)
return 0;
}
-int brcmf_bus_start(struct device *dev)
+int brcmf_bus_started(struct device *dev)
{
int ret = -1;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
@@ -1002,11 +989,11 @@ int brcmf_bus_start(struct device *dev)
}
brcmf_feat_attach(drvr);
- ret = brcmf_fws_init(drvr);
+ ret = brcmf_proto_init_done(drvr);
if (ret < 0)
goto fail;
- brcmf_fws_add_interface(ifp);
+ brcmf_proto_add_if(drvr, ifp);
drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev,
drvr->settings->p2p_enable);
@@ -1050,10 +1037,6 @@ fail:
brcmf_cfg80211_detach(drvr->config);
drvr->config = NULL;
}
- if (drvr->fws) {
- brcmf_fws_del_interface(ifp);
- brcmf_fws_deinit(drvr);
- }
brcmf_net_detach(ifp->ndev, false);
if (p2p_ifp)
brcmf_net_detach(p2p_ifp->ndev, false);
@@ -1075,16 +1058,6 @@ void brcmf_bus_add_txhdrlen(struct device *dev, uint len)
}
}
-static void brcmf_bus_detach(struct brcmf_pub *drvr)
-{
- brcmf_dbg(TRACE, "Enter\n");
-
- if (drvr) {
- /* Stop the bus module */
- brcmf_bus_stop(drvr->bus_if);
- }
-}
-
void brcmf_dev_reset(struct device *dev)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
@@ -1129,9 +1102,7 @@ void brcmf_detach(struct device *dev)
brcmf_cfg80211_detach(drvr->config);
- brcmf_fws_deinit(drvr);
-
- brcmf_bus_detach(drvr);
+ brcmf_bus_stop(drvr->bus_if);
brcmf_proto_detach(drvr);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
index c94dcab260d0..a4dd313140f3 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
@@ -127,8 +127,6 @@ struct brcmf_pub {
struct brcmf_fweh_info fweh;
- struct brcmf_fws_info *fws;
-
struct brcmf_ampdu_rx_reorder
*reorder_flows[BRCMF_AMPDU_RX_REORDER_MAXFLOWS];
@@ -171,7 +169,6 @@ enum brcmf_netif_stop_reason {
* @drvr: points to device related information.
* @vif: points to cfg80211 specific interface information.
* @ndev: associated network device.
- * @stats: interface specific network statistics.
* @multicast_work: worker object for multicast provisioning.
* @ndoffload_work: worker object for neighbor discovery offload configuration.
* @fws_desc: interface specific firmware-signalling descriptor.
@@ -187,7 +184,6 @@ struct brcmf_if {
struct brcmf_pub *drvr;
struct brcmf_cfg80211_vif *vif;
struct net_device *ndev;
- struct net_device_stats stats;
struct work_struct multicast_work;
struct work_struct ndoffload_work;
struct brcmf_fws_mac_descriptor *fws_desc;
@@ -216,7 +212,6 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp,
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);
-void brcmf_c_set_joinpref_default(struct brcmf_if *ifp);
int __init brcmf_core_init(void);
void __exit brcmf_core_exit(void);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c
index e64557c35553..1447a8352383 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c
@@ -27,32 +27,31 @@
static struct dentry *root_folder;
-static int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data,
- size_t len)
+int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data,
+ size_t len)
{
void *dump;
size_t ramsize;
+ int err;
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);
+ if (!ramsize)
+ return -ENOTSUPP;
+
+ dump = vzalloc(len + ramsize);
+ if (!dump)
+ return -ENOMEM;
+
+ memcpy(dump, data, len);
+ err = brcmf_bus_get_memdump(bus, dump + len, ramsize);
+ if (err) {
+ vfree(dump);
+ return err;
}
- 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: bsscfgidx=%d\n", ifp->bsscfgidx);
+ dev_coredumpv(bus->dev, dump, len + ramsize, GFP_KERNEL);
- return brcmf_debug_create_memdump(ifp->drvr->bus_if, data,
- evtmsg->datalen);
+ return 0;
}
void brcmf_debugfs_init(void)
@@ -82,9 +81,7 @@ int brcmf_debug_attach(struct brcmf_pub *drvr)
if (IS_ERR(drvr->dbgfs_dir))
return PTR_ERR(drvr->dbgfs_dir);
-
- return brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG,
- brcmf_debug_psm_watchdog_notify);
+ return 0;
}
void brcmf_debug_detach(struct brcmf_pub *drvr)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
index 6687812770cc..35919d9e8e13 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
@@ -45,28 +45,24 @@
#undef pr_fmt
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-/* Macro for error messages. net_ratelimit() is used when driver
- * debugging is not selected. When debugging the driver error
- * messages are as important as other tracing or even more so.
+__printf(2, 3)
+void __brcmf_err(const char *func, const char *fmt, ...);
+/* Macro for error messages. When debugging / tracing the driver all error
+ * messages are important to us.
*/
-#ifndef CONFIG_BRCM_TRACING
-#ifdef CONFIG_BRCMDBG
-#define brcmf_err(fmt, ...) pr_err("%s: " fmt, __func__, ##__VA_ARGS__)
-#else
#define brcmf_err(fmt, ...) \
do { \
- if (net_ratelimit()) \
- pr_err("%s: " fmt, __func__, ##__VA_ARGS__); \
+ if (IS_ENABLED(CONFIG_BRCMDBG) || \
+ IS_ENABLED(CONFIG_BRCM_TRACING) || \
+ net_ratelimit()) \
+ __brcmf_err(__func__, fmt, ##__VA_ARGS__); \
} while (0)
-#endif
-#else
-__printf(2, 3)
-void __brcmf_err(const char *func, const char *fmt, ...);
-#define brcmf_err(fmt, ...) \
- __brcmf_err(__func__, fmt, ##__VA_ARGS__)
-#endif
#if defined(DEBUG) || defined(CONFIG_BRCM_TRACING)
+
+/* For debug/tracing purposes treat info messages as errors */
+#define brcmf_info brcmf_err
+
__printf(3, 4)
void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...);
#define brcmf_dbg(level, fmt, ...) \
@@ -82,9 +78,15 @@ do { \
#define BRCMF_EVENT_ON() (brcmf_msg_level & BRCMF_EVENT_VAL)
#define BRCMF_FIL_ON() (brcmf_msg_level & BRCMF_FIL_VAL)
#define BRCMF_FWCON_ON() (brcmf_msg_level & BRCMF_FWCON_VAL)
+#define BRCMF_SCAN_ON() (brcmf_msg_level & BRCMF_SCAN_VAL)
#else /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */
+#define brcmf_info(fmt, ...) \
+ do { \
+ pr_info("%s: " fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+
#define brcmf_dbg(level, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
#define BRCMF_DATA_ON() 0
@@ -95,6 +97,7 @@ do { \
#define BRCMF_EVENT_ON() 0
#define BRCMF_FIL_ON() 0
#define BRCMF_FWCON_ON() 0
+#define BRCMF_SCAN_ON() 0
#endif /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */
@@ -107,6 +110,7 @@ do { \
extern int brcmf_msg_level;
+struct brcmf_bus;
struct brcmf_pub;
#ifdef DEBUG
void brcmf_debugfs_init(void);
@@ -116,6 +120,8 @@ 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));
+int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data,
+ size_t len);
#else
static inline void brcmf_debugfs_init(void)
{
@@ -136,6 +142,12 @@ int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
{
return 0;
}
+static inline
+int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data,
+ size_t len)
+{
+ return 0;
+}
#endif
#endif /* BRCMFMAC_DEBUG_H */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
index 62985f2c0853..d21258d277ce 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
@@ -27,6 +27,7 @@
#include "feature.h"
#include "common.h"
+#define BRCMF_FW_UNSUPPORTED 23
/*
* expand feature list to array of feature strings.
@@ -113,6 +114,22 @@ static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp,
}
}
+static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp,
+ enum brcmf_feat_id id, char *name,
+ const void *data, size_t len)
+{
+ int err;
+
+ err = brcmf_fil_iovar_data_set(ifp, name, data, len);
+ if (err != -BRCMF_FW_UNSUPPORTED) {
+ brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
+ ifp->drvr->feat_flags |= BIT(id);
+ } else {
+ brcmf_dbg(TRACE, "%s feature check failed: %d\n",
+ brcmf_feat_names[id], err);
+ }
+}
+
static void brcmf_feat_firmware_capabilities(struct brcmf_if *ifp)
{
char caps[256];
@@ -136,11 +153,14 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
{
struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
struct brcmf_pno_macaddr_le pfn_mac;
+ struct brcmf_gscan_config gscan_cfg;
u32 wowl_cap;
s32 err;
brcmf_feat_firmware_capabilities(ifp);
-
+ memset(&gscan_cfg, 0, sizeof(gscan_cfg));
+ brcmf_feat_iovar_data_set(ifp, BRCMF_FEAT_GSCAN, "pfn_gscan_cfg",
+ &gscan_cfg, sizeof(gscan_cfg));
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn");
if (drvr->bus_if->wowl_supported)
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
@@ -175,6 +195,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
drvr->settings->feature_disable);
ifp->drvr->feat_flags &= ~drvr->settings->feature_disable;
}
+ brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa");
/* set chip related quirks */
switch (drvr->bus_if->chip) {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
index db4733a95e28..1ab4f1617112 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
@@ -31,6 +31,8 @@
* WOWL_GTK: (WOWL) GTK rekeying offload
* WOWL_ARP_ND: ARP and Neighbor Discovery offload support during WOWL.
* MFP: 802.11w Management Frame Protection.
+ * GSCAN: enhanced scan offload feature.
+ * FWSUP: Firmware supplicant.
*/
#define BRCMF_FEAT_LIST \
BRCMF_FEAT_DEF(MBSS) \
@@ -44,7 +46,9 @@
BRCMF_FEAT_DEF(WOWL_ND) \
BRCMF_FEAT_DEF(WOWL_GTK) \
BRCMF_FEAT_DEF(WOWL_ARP_ND) \
- BRCMF_FEAT_DEF(MFP)
+ BRCMF_FEAT_DEF(MFP) \
+ BRCMF_FEAT_DEF(GSCAN) \
+ BRCMF_FEAT_DEF(FWSUP)
/*
* Quirks:
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
index c7c1e9906500..d231042f19d6 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
@@ -442,7 +442,7 @@ struct brcmf_fw {
const char *nvram_name;
u16 domain_nr;
u16 bus_nr;
- void (*done)(struct device *dev, const struct firmware *fw,
+ void (*done)(struct device *dev, int err, const struct firmware *fw,
void *nvram_image, u32 nvram_len);
};
@@ -477,52 +477,51 @@ static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL))
goto fail;
- fwctx->done(fwctx->dev, fwctx->code, nvram, nvram_length);
+ fwctx->done(fwctx->dev, 0, fwctx->code, nvram, nvram_length);
kfree(fwctx);
return;
fail:
brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
release_firmware(fwctx->code);
- device_release_driver(fwctx->dev);
+ fwctx->done(fwctx->dev, -ENOENT, NULL, NULL, 0);
kfree(fwctx);
}
static void brcmf_fw_request_code_done(const struct firmware *fw, void *ctx)
{
struct brcmf_fw *fwctx = ctx;
- int ret;
+ int ret = 0;
brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
- if (!fw)
+ if (!fw) {
+ ret = -ENOENT;
goto fail;
-
- /* only requested code so done here */
- if (!(fwctx->flags & BRCMF_FW_REQUEST_NVRAM)) {
- fwctx->done(fwctx->dev, fw, NULL, 0);
- kfree(fwctx);
- return;
}
+ /* only requested code so done here */
+ if (!(fwctx->flags & BRCMF_FW_REQUEST_NVRAM))
+ goto done;
+
fwctx->code = fw;
ret = request_firmware_nowait(THIS_MODULE, true, fwctx->nvram_name,
fwctx->dev, GFP_KERNEL, fwctx,
brcmf_fw_request_nvram_done);
- if (!ret)
- return;
-
- brcmf_fw_request_nvram_done(NULL, fwctx);
+ /* pass NULL to nvram callback for bcm47xx fallback */
+ if (ret)
+ brcmf_fw_request_nvram_done(NULL, fwctx);
return;
fail:
brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
- device_release_driver(fwctx->dev);
+done:
+ fwctx->done(fwctx->dev, ret, fw, NULL, 0);
kfree(fwctx);
}
int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
const char *code, const char *nvram,
- void (*fw_cb)(struct device *dev,
+ void (*fw_cb)(struct device *dev, int err,
const struct firmware *fw,
void *nvram_image, u32 nvram_len),
u16 domain_nr, u16 bus_nr)
@@ -555,7 +554,7 @@ int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
const char *code, const char *nvram,
- void (*fw_cb)(struct device *dev,
+ void (*fw_cb)(struct device *dev, int err,
const struct firmware *fw,
void *nvram_image, u32 nvram_len))
{
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
index d3c9f0d52ae3..8fa4b7e1ab3d 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
@@ -73,13 +73,13 @@ void brcmf_fw_nvram_free(void *nvram);
*/
int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
const char *code, const char *nvram,
- void (*fw_cb)(struct device *dev,
+ void (*fw_cb)(struct device *dev, int err,
const struct firmware *fw,
void *nvram_image, u32 nvram_len),
u16 domain_nr, u16 bus_nr);
int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
const char *code, const char *nvram,
- void (*fw_cb)(struct device *dev,
+ void (*fw_cb)(struct device *dev, int err,
const struct firmware *fw,
void *nvram_image, u32 nvram_len));
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
index c79306b57532..4eb1e1ce9ace 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
@@ -22,9 +22,9 @@
#include "core.h"
#include "debug.h"
#include "tracepoint.h"
-#include "fwsignal.h"
#include "fweh.h"
#include "fwil.h"
+#include "proto.h"
/**
* struct brcmf_fweh_queue_item - event item on event queue.
@@ -172,14 +172,14 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
if (IS_ERR(ifp))
return;
if (!is_p2pdev)
- brcmf_fws_add_interface(ifp);
+ brcmf_proto_add_if(drvr, ifp);
if (!drvr->fweh.evt_handler[BRCMF_E_IF])
if (brcmf_net_attach(ifp, false) < 0)
return;
}
if (ifp && ifevent->action == BRCMF_E_IF_CHANGE)
- brcmf_fws_reset_interface(ifp);
+ brcmf_proto_reset_if(drvr, ifp);
err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
index 5fba4b49f3b3..816f80ea925b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
@@ -142,6 +142,16 @@ enum brcmf_fweh_event_code {
#define BRCMF_E_STATUS_CS_ABORT 15
#define BRCMF_E_STATUS_ERROR 16
+/* status field values for PSK_SUP event */
+#define BRCMF_E_STATUS_FWSUP_WAIT_M1 4
+#define BRCMF_E_STATUS_FWSUP_PREP_M2 5
+#define BRCMF_E_STATUS_FWSUP_COMPLETED 6
+#define BRCMF_E_STATUS_FWSUP_TIMEOUT 7
+#define BRCMF_E_STATUS_FWSUP_WAIT_M3 8
+#define BRCMF_E_STATUS_FWSUP_PREP_M4 9
+#define BRCMF_E_STATUS_FWSUP_WAIT_G1 10
+#define BRCMF_E_STATUS_FWSUP_PREP_G2 11
+
/* reason field values in struct brcmf_event_msg */
#define BRCMF_E_REASON_INITIAL_ASSOC 0
#define BRCMF_E_REASON_LOW_RSSI 1
@@ -161,6 +171,26 @@ enum brcmf_fweh_event_code {
#define BRCMF_E_REASON_TDLS_PEER_CONNECTED 1
#define BRCMF_E_REASON_TDLS_PEER_DISCONNECTED 2
+/* reason field values for PSK_SUP event */
+#define BRCMF_E_REASON_FWSUP_OTHER 0
+#define BRCMF_E_REASON_FWSUP_DECRYPT_KEY_DATA 1
+#define BRCMF_E_REASON_FWSUP_BAD_UCAST_WEP128 2
+#define BRCMF_E_REASON_FWSUP_BAD_UCAST_WEP40 3
+#define BRCMF_E_REASON_FWSUP_UNSUP_KEY_LEN 4
+#define BRCMF_E_REASON_FWSUP_PW_KEY_CIPHER 5
+#define BRCMF_E_REASON_FWSUP_MSG3_TOO_MANY_IE 6
+#define BRCMF_E_REASON_FWSUP_MSG3_IE_MISMATCH 7
+#define BRCMF_E_REASON_FWSUP_NO_INSTALL_FLAG 8
+#define BRCMF_E_REASON_FWSUP_MSG3_NO_GTK 9
+#define BRCMF_E_REASON_FWSUP_GRP_KEY_CIPHER 10
+#define BRCMF_E_REASON_FWSUP_GRP_MSG1_NO_GTK 11
+#define BRCMF_E_REASON_FWSUP_GTK_DECRYPT_FAIL 12
+#define BRCMF_E_REASON_FWSUP_SEND_FAIL 13
+#define BRCMF_E_REASON_FWSUP_DEAUTH 14
+#define BRCMF_E_REASON_FWSUP_WPA_PSK_TMO 15
+#define BRCMF_E_REASON_FWSUP_WPA_PSK_M1_TMO 16
+#define BRCMF_E_REASON_FWSUP_WPA_PSK_M3_TMO 17
+
/* action field values for brcmf_ifevent */
#define BRCMF_E_IF_ADD 1
#define BRCMF_E_IF_DEL 2
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
index 3a9a76dd9222..63b1287e2e6d 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
@@ -85,6 +85,7 @@
#define BRCMF_C_SET_SCAN_PASSIVE_TIME 258
#define BRCMF_C_GET_VAR 262
#define BRCMF_C_SET_VAR 263
+#define BRCMF_C_SET_WSEC_PMK 268
s32 brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len);
s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
index 9a1eb5ab6c4b..8391989b1882 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
@@ -45,6 +45,9 @@
#define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff
#define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16
+#define BRCMF_WSEC_MAX_PSK_LEN 32
+#define BRCMF_WSEC_PASSPHRASE BIT(0)
+
/* primary (ie tx) key */
#define BRCMF_PRIMARY_KEY (1 << 1)
#define DOT11_BSSTYPE_ANY 2
@@ -470,6 +473,19 @@ struct brcmf_wsec_key_le {
u8 ea[ETH_ALEN]; /* per station */
};
+/**
+ * struct brcmf_wsec_pmk_le - firmware pmk material.
+ *
+ * @key_len: number of octets in key material.
+ * @flags: key handling qualifiers.
+ * @key: PMK key material.
+ */
+struct brcmf_wsec_pmk_le {
+ __le16 key_len;
+ __le16 flags;
+ u8 key[2 * BRCMF_WSEC_MAX_PSK_LEN + 1];
+};
+
/* Used to get specific STA parameters */
struct brcmf_scb_val_le {
__le32 val;
@@ -806,6 +822,17 @@ struct brcmf_pno_macaddr_le {
};
/**
+ * struct brcmf_pno_bssid_le - bssid configuration for PNO scan.
+ *
+ * @bssid: BSS network identifier.
+ * @flags: flags for this BSSID.
+ */
+struct brcmf_pno_bssid_le {
+ u8 bssid[ETH_ALEN];
+ __le16 flags;
+};
+
+/**
* struct brcmf_pktcnt_le - packet counters.
*
* @rx_good_pkt: packets (MSDUs & MMPDUs) received from this station
@@ -835,4 +862,69 @@ struct brcmf_gtk_keyinfo_le {
u8 replay_counter[BRCMF_RSN_REPLAY_LEN];
};
+#define BRCMF_PNO_REPORT_NO_BATCH BIT(2)
+
+/**
+ * struct brcmf_gscan_bucket_config - configuration data for channel bucket.
+ *
+ * @bucket_end_index: last channel index in @channel_list in
+ * @struct brcmf_pno_config_le.
+ * @bucket_freq_multiple: scan interval expressed in N * @scan_freq.
+ * @flag: channel bucket report flags.
+ * @reserved: for future use.
+ * @repeat: number of scan at interval for exponential scan.
+ * @max_freq_multiple: maximum scan interval for exponential scan.
+ */
+struct brcmf_gscan_bucket_config {
+ u8 bucket_end_index;
+ u8 bucket_freq_multiple;
+ u8 flag;
+ u8 reserved;
+ __le16 repeat;
+ __le16 max_freq_multiple;
+};
+
+/* version supported which must match firmware */
+#define BRCMF_GSCAN_CFG_VERSION 2
+
+/**
+ * enum brcmf_gscan_cfg_flags - bit values for gscan flags.
+ *
+ * @BRCMF_GSCAN_CFG_FLAGS_ALL_RESULTS: send probe responses/beacons to host.
+ * @BRCMF_GSCAN_CFG_ALL_BUCKETS_IN_1ST_SCAN: all buckets will be included in
+ * first scan cycle.
+ * @BRCMF_GSCAN_CFG_FLAGS_CHANGE_ONLY: indicated only flags member is changed.
+ */
+enum brcmf_gscan_cfg_flags {
+ BRCMF_GSCAN_CFG_FLAGS_ALL_RESULTS = BIT(0),
+ BRCMF_GSCAN_CFG_ALL_BUCKETS_IN_1ST_SCAN = BIT(3),
+ BRCMF_GSCAN_CFG_FLAGS_CHANGE_ONLY = BIT(7),
+};
+
+/**
+ * struct brcmf_gscan_config - configuration data for gscan.
+ *
+ * @version: version of the api to match firmware.
+ * @flags: flags according %enum brcmf_gscan_cfg_flags.
+ * @buffer_threshold: percentage threshold of buffer to generate an event.
+ * @swc_nbssid_threshold: number of BSSIDs with significant change that
+ * will generate an event.
+ * @swc_rssi_window_size: size of rssi cache buffer (max=8).
+ * @count_of_channel_buckets: number of array members in @bucket.
+ * @retry_threshold: !unknown!
+ * @lost_ap_window: !unknown!
+ * @bucket: array of channel buckets.
+ */
+struct brcmf_gscan_config {
+ __le16 version;
+ u8 flags;
+ u8 buffer_threshold;
+ u8 swc_nbssid_threshold;
+ u8 swc_rssi_window_size;
+ u8 count_of_channel_buckets;
+ u8 retry_threshold;
+ __le16 lost_ap_window;
+ struct brcmf_gscan_bucket_config bucket[1];
+};
+
#endif /* FWIL_TYPES_H_ */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
index 5f1a5929cb30..f59642b2c935 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
@@ -36,6 +36,7 @@
#include "p2p.h"
#include "cfg80211.h"
#include "proto.h"
+#include "bcdc.h"
#include "common.h"
/**
@@ -1586,7 +1587,7 @@ static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp,
const struct brcmf_event_msg *e,
void *data)
{
- struct brcmf_fws_info *fws = ifp->drvr->fws;
+ struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
int i;
u8 *credits = data;
@@ -1617,7 +1618,7 @@ static int brcmf_fws_notify_bcmc_credit_support(struct brcmf_if *ifp,
const struct brcmf_event_msg *e,
void *data)
{
- struct brcmf_fws_info *fws = ifp->drvr->fws;
+ struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
if (fws) {
brcmf_fws_lock(fws);
@@ -1826,7 +1827,7 @@ netif_rx:
void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb)
{
struct brcmf_skb_reorder_data *rd;
- struct brcmf_fws_info *fws = ifp->drvr->fws;
+ struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
u8 *signal_data;
s16 data_len;
u8 type;
@@ -2091,8 +2092,7 @@ static int brcmf_fws_assign_htod(struct brcmf_fws_info *fws, struct sk_buff *p,
int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
{
- struct brcmf_pub *drvr = ifp->drvr;
- struct brcmf_fws_info *fws = drvr->fws;
+ struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
struct ethhdr *eh = (struct ethhdr *)(skb->data);
int fifo = BRCMF_FWS_FIFO_BCMC;
@@ -2142,10 +2142,10 @@ void brcmf_fws_reset_interface(struct brcmf_if *ifp)
void brcmf_fws_add_interface(struct brcmf_if *ifp)
{
- struct brcmf_fws_info *fws = ifp->drvr->fws;
+ struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
struct brcmf_fws_mac_descriptor *entry;
- if (!ifp->ndev)
+ if (!ifp->ndev || !brcmf_fws_queue_skbs(fws))
return;
entry = &fws->desc.iface[ifp->ifidx];
@@ -2160,16 +2160,17 @@ void brcmf_fws_add_interface(struct brcmf_if *ifp)
void brcmf_fws_del_interface(struct brcmf_if *ifp)
{
struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
+ struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
if (!entry)
return;
- brcmf_fws_lock(ifp->drvr->fws);
+ brcmf_fws_lock(fws);
ifp->fws_desc = NULL;
brcmf_dbg(TRACE, "deleting %s\n", entry->name);
brcmf_fws_macdesc_deinit(entry);
- brcmf_fws_cleanup(ifp->drvr->fws, ifp->ifidx);
- brcmf_fws_unlock(ifp->drvr->fws);
+ brcmf_fws_cleanup(fws, ifp->ifidx);
+ brcmf_fws_unlock(fws);
}
static void brcmf_fws_dequeue_worker(struct work_struct *worker)
@@ -2243,7 +2244,7 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data)
{
struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
- struct brcmf_fws_stats *fwstats = &bus_if->drvr->fws->stats;
+ struct brcmf_fws_stats *fwstats = &(drvr_to_fws(bus_if->drvr)->stats);
seq_printf(seq,
"header_pulls: %u\n"
@@ -2308,7 +2309,7 @@ static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data)
}
#endif
-int brcmf_fws_init(struct brcmf_pub *drvr)
+struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr)
{
struct brcmf_fws_info *fws;
struct brcmf_if *ifp;
@@ -2316,17 +2317,15 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
int rc;
u32 mode;
- drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL);
- if (!drvr->fws) {
+ fws = kzalloc(sizeof(*fws), GFP_KERNEL);
+ if (!fws) {
rc = -ENOMEM;
goto fail;
}
- fws = drvr->fws;
-
spin_lock_init(&fws->spinlock);
- /* set linkage back */
+ /* store drvr reference */
fws->drvr = drvr;
fws->fcmode = drvr->settings->fcmode;
@@ -2334,7 +2333,7 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
(fws->fcmode == BRCMF_FWS_FCMODE_NONE)) {
fws->avoid_queueing = true;
brcmf_dbg(INFO, "FWS queueing will be avoided\n");
- return 0;
+ return fws;
}
fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq");
@@ -2396,6 +2395,7 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
brcmf_fws_hanger_init(&fws->hanger);
brcmf_fws_macdesc_init(&fws->desc.other, NULL, 0);
brcmf_fws_macdesc_set_name(fws, &fws->desc.other);
+ brcmf_dbg(INFO, "added %s\n", fws->desc.other.name);
brcmu_pktq_init(&fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT,
BRCMF_FWS_PSQ_LEN);
@@ -2405,27 +2405,24 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
brcmf_dbg(INFO, "%s bdcv2 tlv signaling [%x]\n",
fws->fw_signals ? "enabled" : "disabled", tlv);
- return 0;
+ return fws;
fail:
- brcmf_fws_deinit(drvr);
- return rc;
+ brcmf_fws_detach(fws);
+ return ERR_PTR(rc);
}
-void brcmf_fws_deinit(struct brcmf_pub *drvr)
+void brcmf_fws_detach(struct brcmf_fws_info *fws)
{
- struct brcmf_fws_info *fws = drvr->fws;
-
if (!fws)
return;
- if (drvr->fws->fws_wq)
- destroy_workqueue(drvr->fws->fws_wq);
+ if (fws->fws_wq)
+ destroy_workqueue(fws->fws_wq);
/* cleanup */
brcmf_fws_lock(fws);
brcmf_fws_cleanup(fws, -1);
- drvr->fws = NULL;
brcmf_fws_unlock(fws);
/* free top structure */
@@ -2461,7 +2458,7 @@ void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked)
{
- struct brcmf_fws_info *fws = drvr->fws;
+ struct brcmf_fws_info *fws = drvr_to_fws(drvr);
struct brcmf_if *ifp;
int i;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
index 96df66073b2a..ba07bd972002 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
@@ -18,8 +18,8 @@
#ifndef FWSIGNAL_H_
#define FWSIGNAL_H_
-int brcmf_fws_init(struct brcmf_pub *drvr);
-void brcmf_fws_deinit(struct brcmf_pub *drvr);
+struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr);
+void brcmf_fws_detach(struct brcmf_fws_info *fws);
bool brcmf_fws_queue_skbs(struct brcmf_fws_info *fws);
bool brcmf_fws_fc_active(struct brcmf_fws_info *fws);
void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
index 425c41dc0a59..aee6e5937c41 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
@@ -23,14 +23,17 @@
#include "common.h"
#include "of.h"
-void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd *sdio)
+void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
+ struct brcmf_mp_device *settings)
{
+ struct brcmfmac_sdio_pd *sdio = &settings->bus.sdio;
struct device_node *np = dev->of_node;
int irq;
u32 irqf;
u32 val;
- if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac"))
+ if (!np || bus_type != BRCMF_BUSTYPE_SDIO ||
+ !of_device_is_compatible(np, "brcm,bcm4329-fmac"))
return;
if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
index a9d94c15d0f5..95b7032d54b1 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
@@ -14,9 +14,11 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef CONFIG_OF
-void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd *sdio);
+void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
+ struct brcmf_mp_device *settings);
#else
-static void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd *sdio)
+static void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
+ struct brcmf_mp_device *settings)
{
}
#endif /* CONFIG_OF */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
index de19c7c92bc6..2ce675ab40ef 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
@@ -2141,12 +2141,11 @@ fail:
* @name: name of the new interface.
* @name_assign_type: origin of the interface name
* @type: nl80211 interface type.
- * @flags: not used.
* @params: contains mac address for P2P device.
*/
struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
unsigned char name_assign_type,
- enum nl80211_iftype type, u32 *flags,
+ enum nl80211_iftype type,
struct vif_params *params)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
@@ -2209,6 +2208,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
err = brcmf_net_attach(ifp, true);
if (err) {
brcmf_err("Registering netdevice failed\n");
+ free_netdev(ifp->ndev);
goto fail;
}
@@ -2238,14 +2238,16 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
struct brcmf_p2p_info *p2p = &cfg->p2p;
struct brcmf_cfg80211_vif *vif;
+ enum nl80211_iftype iftype;
bool wait_for_disable = false;
int err;
brcmf_dbg(TRACE, "delete P2P vif\n");
vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+ iftype = vif->wdev.iftype;
brcmf_cfg80211_arm_vif_event(cfg, vif);
- switch (vif->wdev.iftype) {
+ switch (iftype) {
case NL80211_IFTYPE_P2P_CLIENT:
if (test_bit(BRCMF_VIF_STATUS_DISCONNECTING, &vif->sme_state))
wait_for_disable = true;
@@ -2275,7 +2277,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
BRCMF_P2P_DISABLE_TIMEOUT);
err = 0;
- if (vif->wdev.iftype != NL80211_IFTYPE_P2P_DEVICE) {
+ if (iftype != NL80211_IFTYPE_P2P_DEVICE) {
brcmf_vif_clear_mgmt_ies(vif);
err = brcmf_p2p_release_p2p_if(vif);
}
@@ -2291,7 +2293,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
brcmf_remove_interface(vif->ifp, true);
brcmf_cfg80211_arm_vif_event(cfg, NULL);
- if (vif->wdev.iftype != NL80211_IFTYPE_P2P_DEVICE)
+ if (iftype != NL80211_IFTYPE_P2P_DEVICE)
p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL;
return err;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h
index 8ce9447533ef..0e8b34d2d85c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h
@@ -150,7 +150,7 @@ s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg, bool p2pdev_forced);
void brcmf_p2p_detach(struct brcmf_p2p_info *p2p);
struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
unsigned char name_assign_type,
- enum nl80211_iftype type, u32 *flags,
+ enum nl80211_iftype type,
struct vif_params *params);
int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev);
int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index 048027f2085b..f878706613e6 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -601,7 +601,6 @@ static void brcmf_pcie_attach(struct brcmf_pciedev_info *devinfo)
{
u32 config;
- brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2);
/* BAR1 window may not be sized properly */
brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2);
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGADDR, 0x4e0);
@@ -1572,7 +1571,7 @@ static int brcmf_pcie_attach_bus(struct brcmf_pciedev_info *devinfo)
if (ret) {
brcmf_err("brcmf_attach failed\n");
} else {
- ret = brcmf_bus_start(&devinfo->pdev->dev);
+ ret = brcmf_bus_started(&devinfo->pdev->dev);
if (ret)
brcmf_err("dongle is not responding\n");
}
@@ -1651,16 +1650,23 @@ static const struct brcmf_buscore_ops brcmf_pcie_buscore_ops = {
.write32 = brcmf_pcie_buscore_write32,
};
-static void brcmf_pcie_setup(struct device *dev, const struct firmware *fw,
+static void brcmf_pcie_setup(struct device *dev, int ret,
+ const struct firmware *fw,
void *nvram, u32 nvram_len)
{
- struct brcmf_bus *bus = dev_get_drvdata(dev);
- struct brcmf_pciedev *pcie_bus_dev = bus->bus_priv.pcie;
- struct brcmf_pciedev_info *devinfo = pcie_bus_dev->devinfo;
+ struct brcmf_bus *bus;
+ struct brcmf_pciedev *pcie_bus_dev;
+ struct brcmf_pciedev_info *devinfo;
struct brcmf_commonring **flowrings;
- int ret;
u32 i;
+ /* check firmware loading result */
+ if (ret)
+ goto fail;
+
+ bus = dev_get_drvdata(dev);
+ pcie_bus_dev = bus->bus_priv.pcie;
+ devinfo = pcie_bus_dev->devinfo;
brcmf_pcie_attach(devinfo);
/* Some of the firmwares have the size of the memory of the device
@@ -1878,6 +1884,7 @@ static int brcmf_pcie_pm_enter_D3(struct device *dev)
BRCMF_PCIE_MBDATA_TIMEOUT);
if (!devinfo->mbdata_completed) {
brcmf_err("Timeout on response for entering D3 substate\n");
+ brcmf_bus_change_state(bus, BRCMF_BUS_UP);
return -EIO;
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
index 9a25e79a46cf..ffa243e2e2d0 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
@@ -14,6 +14,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/netdevice.h>
+#include <linux/gcd.h>
#include <net/cfg80211.h>
#include "core.h"
@@ -35,6 +36,67 @@
#define BRCMF_PNO_HIDDEN_BIT 2
#define BRCMF_PNO_SCHED_SCAN_PERIOD 30
+#define BRCMF_PNO_MAX_BUCKETS 16
+#define GSCAN_BATCH_NO_THR_SET 101
+#define GSCAN_RETRY_THRESHOLD 3
+
+struct brcmf_pno_info {
+ int n_reqs;
+ struct cfg80211_sched_scan_request *reqs[BRCMF_PNO_MAX_BUCKETS];
+ struct mutex req_lock;
+};
+
+#define ifp_to_pno(_ifp) ((_ifp)->drvr->config->pno)
+
+static int brcmf_pno_store_request(struct brcmf_pno_info *pi,
+ struct cfg80211_sched_scan_request *req)
+{
+ if (WARN(pi->n_reqs == BRCMF_PNO_MAX_BUCKETS,
+ "pno request storage full\n"))
+ return -ENOSPC;
+
+ brcmf_dbg(SCAN, "reqid=%llu\n", req->reqid);
+ mutex_lock(&pi->req_lock);
+ pi->reqs[pi->n_reqs++] = req;
+ mutex_unlock(&pi->req_lock);
+ return 0;
+}
+
+static int brcmf_pno_remove_request(struct brcmf_pno_info *pi, u64 reqid)
+{
+ int i, err = 0;
+
+ mutex_lock(&pi->req_lock);
+
+ /* find request */
+ for (i = 0; i < pi->n_reqs; i++) {
+ if (pi->reqs[i]->reqid == reqid)
+ break;
+ }
+ /* request not found */
+ if (WARN(i == pi->n_reqs, "reqid not found\n")) {
+ err = -ENOENT;
+ goto done;
+ }
+
+ brcmf_dbg(SCAN, "reqid=%llu\n", reqid);
+ pi->n_reqs--;
+
+ /* if last we are done */
+ if (!pi->n_reqs || i == pi->n_reqs)
+ goto done;
+
+ /* fill the gap with remaining requests */
+ while (i <= pi->n_reqs - 1) {
+ pi->reqs[i] = pi->reqs[i + 1];
+ i++;
+ }
+
+done:
+ mutex_unlock(&pi->req_lock);
+ return err;
+}
+
static int brcmf_pno_channel_config(struct brcmf_if *ifp,
struct brcmf_pno_config_le *cfg)
{
@@ -57,16 +119,11 @@ static int brcmf_pno_config(struct brcmf_if *ifp, u32 scan_freq,
/* set extra pno params */
flags = BIT(BRCMF_PNO_IMMEDIATE_SCAN_BIT) |
- BIT(BRCMF_PNO_REPORT_SEPARATELY_BIT) |
BIT(BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
pfn_param.repeat = BRCMF_PNO_REPEAT;
pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
/* set up pno scan fr */
- if (scan_freq < BRCMF_PNO_SCHED_SCAN_MIN_PERIOD) {
- brcmf_dbg(SCAN, "scan period too small, using minimum\n");
- scan_freq = BRCMF_PNO_SCHED_SCAN_MIN_PERIOD;
- }
pfn_param.scan_freq = cpu_to_le32(scan_freq);
if (mscan) {
@@ -101,12 +158,24 @@ exit:
return err;
}
-static int brcmf_pno_set_random(struct brcmf_if *ifp, u8 *mac_addr,
- u8 *mac_mask)
+static int brcmf_pno_set_random(struct brcmf_if *ifp, struct brcmf_pno_info *pi)
{
struct brcmf_pno_macaddr_le pfn_mac;
+ u8 *mac_addr = NULL;
+ u8 *mac_mask = NULL;
int err, i;
+ for (i = 0; i < pi->n_reqs; i++)
+ if (pi->reqs[i]->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
+ mac_addr = pi->reqs[i]->mac_addr;
+ mac_mask = pi->reqs[i]->mac_addr_mask;
+ break;
+ }
+
+ /* no random mac requested */
+ if (!mac_addr)
+ return 0;
+
pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
pfn_mac.flags = BRCMF_PFN_MAC_OUI_ONLY | BRCMF_PFN_SET_MAC_UNASSOC;
@@ -120,6 +189,8 @@ static int brcmf_pno_set_random(struct brcmf_if *ifp, u8 *mac_addr,
/* Set locally administered */
pfn_mac.mac[0] |= 0x02;
+ brcmf_dbg(SCAN, "enabling random mac: reqid=%llu mac=%pM\n",
+ pi->reqs[i]->reqid, pfn_mac.mac);
err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac,
sizeof(pfn_mac));
if (err)
@@ -132,6 +203,7 @@ static int brcmf_pno_add_ssid(struct brcmf_if *ifp, struct cfg80211_ssid *ssid,
bool active)
{
struct brcmf_pno_net_param_le pfn;
+ int err;
pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
@@ -142,7 +214,28 @@ static int brcmf_pno_add_ssid(struct brcmf_if *ifp, struct cfg80211_ssid *ssid,
pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
pfn.ssid.SSID_len = cpu_to_le32(ssid->ssid_len);
memcpy(pfn.ssid.SSID, ssid->ssid, ssid->ssid_len);
- return brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn, sizeof(pfn));
+
+ brcmf_dbg(SCAN, "adding ssid=%.32s (active=%d)\n", ssid->ssid, active);
+ err = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn, sizeof(pfn));
+ if (err < 0)
+ brcmf_err("adding failed: err=%d\n", err);
+ return err;
+}
+
+static int brcmf_pno_add_bssid(struct brcmf_if *ifp, const u8 *bssid)
+{
+ struct brcmf_pno_bssid_le bssid_cfg;
+ int err;
+
+ memcpy(bssid_cfg.bssid, bssid, ETH_ALEN);
+ bssid_cfg.flags = 0;
+
+ brcmf_dbg(SCAN, "adding bssid=%pM\n", bssid);
+ err = brcmf_fil_iovar_data_set(ifp, "pfn_add_bssid", &bssid_cfg,
+ sizeof(bssid_cfg));
+ if (err < 0)
+ brcmf_err("adding failed: err=%d\n", err);
+ return err;
}
static bool brcmf_is_ssid_active(struct cfg80211_ssid *ssid,
@@ -163,7 +256,7 @@ static bool brcmf_is_ssid_active(struct cfg80211_ssid *ssid,
return false;
}
-int brcmf_pno_clean(struct brcmf_if *ifp)
+static int brcmf_pno_clean(struct brcmf_if *ifp)
{
int ret;
@@ -179,65 +272,320 @@ int brcmf_pno_clean(struct brcmf_if *ifp)
return ret;
}
-int brcmf_pno_start_sched_scan(struct brcmf_if *ifp,
- struct cfg80211_sched_scan_request *req)
+static int brcmf_pno_get_bucket_channels(struct cfg80211_sched_scan_request *r,
+ struct brcmf_pno_config_le *pno_cfg)
{
- struct brcmu_d11inf *d11inf;
- struct brcmf_pno_config_le pno_cfg;
- struct cfg80211_ssid *ssid;
+ u32 n_chan = le32_to_cpu(pno_cfg->channel_num);
u16 chan;
- int i, ret;
+ int i, err = 0;
- /* clean up everything */
- ret = brcmf_pno_clean(ifp);
- if (ret < 0) {
- brcmf_err("failed error=%d\n", ret);
- return ret;
+ for (i = 0; i < r->n_channels; i++) {
+ if (n_chan >= BRCMF_NUMCHANNELS) {
+ err = -ENOSPC;
+ goto done;
+ }
+ chan = r->channels[i]->hw_value;
+ brcmf_dbg(SCAN, "[%d] Chan : %u\n", n_chan, chan);
+ pno_cfg->channel_list[n_chan++] = cpu_to_le16(chan);
}
+ /* return number of channels */
+ err = n_chan;
+done:
+ pno_cfg->channel_num = cpu_to_le32(n_chan);
+ return err;
+}
- /* configure pno */
- ret = brcmf_pno_config(ifp, req->scan_plans[0].interval, 0, 0);
- if (ret < 0)
- return ret;
-
- /* configure random mac */
- if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
- ret = brcmf_pno_set_random(ifp, req->mac_addr,
- req->mac_addr_mask);
- if (ret < 0)
- return ret;
+static int brcmf_pno_prep_fwconfig(struct brcmf_pno_info *pi,
+ struct brcmf_pno_config_le *pno_cfg,
+ struct brcmf_gscan_bucket_config **buckets,
+ u32 *scan_freq)
+{
+ struct cfg80211_sched_scan_request *sr;
+ struct brcmf_gscan_bucket_config *fw_buckets;
+ int i, err, chidx;
+
+ brcmf_dbg(SCAN, "n_reqs=%d\n", pi->n_reqs);
+ if (WARN_ON(!pi->n_reqs))
+ return -ENODATA;
+
+ /*
+ * actual scan period is determined using gcd() for each
+ * scheduled scan period.
+ */
+ *scan_freq = pi->reqs[0]->scan_plans[0].interval;
+ for (i = 1; i < pi->n_reqs; i++) {
+ sr = pi->reqs[i];
+ *scan_freq = gcd(sr->scan_plans[0].interval, *scan_freq);
+ }
+ if (*scan_freq < BRCMF_PNO_SCHED_SCAN_MIN_PERIOD) {
+ brcmf_dbg(SCAN, "scan period too small, using minimum\n");
+ *scan_freq = BRCMF_PNO_SCHED_SCAN_MIN_PERIOD;
}
- /* configure channels to use */
- d11inf = &ifp->drvr->config->d11inf;
- for (i = 0; i < req->n_channels; i++) {
- chan = req->channels[i]->hw_value;
- pno_cfg.channel_list[i] = cpu_to_le16(chan);
+ *buckets = NULL;
+ fw_buckets = kcalloc(pi->n_reqs, sizeof(*fw_buckets), GFP_KERNEL);
+ if (!fw_buckets)
+ return -ENOMEM;
+
+ memset(pno_cfg, 0, sizeof(*pno_cfg));
+ for (i = 0; i < pi->n_reqs; i++) {
+ sr = pi->reqs[i];
+ chidx = brcmf_pno_get_bucket_channels(sr, pno_cfg);
+ if (chidx < 0) {
+ err = chidx;
+ goto fail;
+ }
+ fw_buckets[i].bucket_end_index = chidx - 1;
+ fw_buckets[i].bucket_freq_multiple =
+ sr->scan_plans[0].interval / *scan_freq;
+ /* assure period is non-zero */
+ if (!fw_buckets[i].bucket_freq_multiple)
+ fw_buckets[i].bucket_freq_multiple = 1;
+ fw_buckets[i].flag = BRCMF_PNO_REPORT_NO_BATCH;
}
- if (req->n_channels) {
- pno_cfg.channel_num = cpu_to_le32(req->n_channels);
- brcmf_pno_channel_config(ifp, &pno_cfg);
+
+ if (BRCMF_SCAN_ON()) {
+ brcmf_err("base period=%u\n", *scan_freq);
+ for (i = 0; i < pi->n_reqs; i++) {
+ brcmf_err("[%d] period %u max %u repeat %u flag %x idx %u\n",
+ i, fw_buckets[i].bucket_freq_multiple,
+ le16_to_cpu(fw_buckets[i].max_freq_multiple),
+ fw_buckets[i].repeat, fw_buckets[i].flag,
+ fw_buckets[i].bucket_end_index);
+ }
}
+ *buckets = fw_buckets;
+ return pi->n_reqs;
- /* configure each match set */
- for (i = 0; i < req->n_match_sets; i++) {
- ssid = &req->match_sets[i].ssid;
- if (!ssid->ssid_len) {
- brcmf_err("skip broadcast ssid\n");
- continue;
+fail:
+ kfree(fw_buckets);
+ return err;
+}
+
+static int brcmf_pno_config_networks(struct brcmf_if *ifp,
+ struct brcmf_pno_info *pi)
+{
+ struct cfg80211_sched_scan_request *r;
+ struct cfg80211_match_set *ms;
+ bool active;
+ int i, j, err = 0;
+
+ for (i = 0; i < pi->n_reqs; i++) {
+ r = pi->reqs[i];
+
+ for (j = 0; j < r->n_match_sets; j++) {
+ ms = &r->match_sets[j];
+ if (ms->ssid.ssid_len) {
+ active = brcmf_is_ssid_active(&ms->ssid, r);
+ err = brcmf_pno_add_ssid(ifp, &ms->ssid,
+ active);
+ }
+ if (!err && is_valid_ether_addr(ms->bssid))
+ err = brcmf_pno_add_bssid(ifp, ms->bssid);
+
+ if (err < 0)
+ return err;
}
+ }
+ return 0;
+}
+
+static int brcmf_pno_config_sched_scans(struct brcmf_if *ifp)
+{
+ struct brcmf_pno_info *pi;
+ struct brcmf_gscan_config *gscan_cfg;
+ struct brcmf_gscan_bucket_config *buckets;
+ struct brcmf_pno_config_le pno_cfg;
+ size_t gsz;
+ u32 scan_freq;
+ int err, n_buckets;
+
+ pi = ifp_to_pno(ifp);
+ n_buckets = brcmf_pno_prep_fwconfig(pi, &pno_cfg, &buckets,
+ &scan_freq);
+ if (n_buckets < 0)
+ return n_buckets;
+
+ gsz = sizeof(*gscan_cfg) + (n_buckets - 1) * sizeof(*buckets);
+ gscan_cfg = kzalloc(gsz, GFP_KERNEL);
+ if (!gscan_cfg) {
+ err = -ENOMEM;
+ goto free_buckets;
+ }
- ret = brcmf_pno_add_ssid(ifp, ssid,
- brcmf_is_ssid_active(ssid, req));
- if (ret < 0)
- brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
- ret == 0 ? "set" : "failed", ssid->ssid);
+ /* clean up everything */
+ err = brcmf_pno_clean(ifp);
+ if (err < 0) {
+ brcmf_err("failed error=%d\n", err);
+ goto free_gscan;
}
+
+ /* configure pno */
+ err = brcmf_pno_config(ifp, scan_freq, 0, 0);
+ if (err < 0)
+ goto free_gscan;
+
+ err = brcmf_pno_channel_config(ifp, &pno_cfg);
+ if (err < 0)
+ goto clean;
+
+ gscan_cfg->version = cpu_to_le16(BRCMF_GSCAN_CFG_VERSION);
+ gscan_cfg->retry_threshold = GSCAN_RETRY_THRESHOLD;
+ gscan_cfg->buffer_threshold = GSCAN_BATCH_NO_THR_SET;
+ gscan_cfg->flags = BRCMF_GSCAN_CFG_ALL_BUCKETS_IN_1ST_SCAN;
+
+ gscan_cfg->count_of_channel_buckets = n_buckets;
+ memcpy(&gscan_cfg->bucket[0], buckets,
+ n_buckets * sizeof(*buckets));
+
+ err = brcmf_fil_iovar_data_set(ifp, "pfn_gscan_cfg", gscan_cfg, gsz);
+
+ if (err < 0)
+ goto clean;
+
+ /* configure random mac */
+ err = brcmf_pno_set_random(ifp, pi);
+ if (err < 0)
+ goto clean;
+
+ err = brcmf_pno_config_networks(ifp, pi);
+ if (err < 0)
+ goto clean;
+
/* Enable the PNO */
- ret = brcmf_fil_iovar_int_set(ifp, "pfn", 1);
+ err = brcmf_fil_iovar_int_set(ifp, "pfn", 1);
+
+clean:
+ if (err < 0)
+ brcmf_pno_clean(ifp);
+free_gscan:
+ kfree(gscan_cfg);
+free_buckets:
+ kfree(buckets);
+ return err;
+}
+
+int brcmf_pno_start_sched_scan(struct brcmf_if *ifp,
+ struct cfg80211_sched_scan_request *req)
+{
+ struct brcmf_pno_info *pi;
+ int ret;
+
+ brcmf_dbg(TRACE, "reqid=%llu\n", req->reqid);
+
+ pi = ifp_to_pno(ifp);
+ ret = brcmf_pno_store_request(pi, req);
if (ret < 0)
- brcmf_err("PNO enable failed!! ret=%d\n", ret);
+ return ret;
- return ret;
+ ret = brcmf_pno_config_sched_scans(ifp);
+ if (ret < 0) {
+ brcmf_pno_remove_request(pi, req->reqid);
+ if (pi->n_reqs)
+ (void)brcmf_pno_config_sched_scans(ifp);
+ return ret;
+ }
+ return 0;
}
+int brcmf_pno_stop_sched_scan(struct brcmf_if *ifp, u64 reqid)
+{
+ struct brcmf_pno_info *pi;
+ int err;
+
+ brcmf_dbg(TRACE, "reqid=%llu\n", reqid);
+
+ pi = ifp_to_pno(ifp);
+ err = brcmf_pno_remove_request(pi, reqid);
+ if (err)
+ return err;
+
+ brcmf_pno_clean(ifp);
+
+ if (pi->n_reqs)
+ (void)brcmf_pno_config_sched_scans(ifp);
+
+ return 0;
+}
+
+int brcmf_pno_attach(struct brcmf_cfg80211_info *cfg)
+{
+ struct brcmf_pno_info *pi;
+
+ brcmf_dbg(TRACE, "enter\n");
+ pi = kzalloc(sizeof(*pi), GFP_KERNEL);
+ if (!pi)
+ return -ENOMEM;
+
+ cfg->pno = pi;
+ mutex_init(&pi->req_lock);
+ return 0;
+}
+
+void brcmf_pno_detach(struct brcmf_cfg80211_info *cfg)
+{
+ struct brcmf_pno_info *pi;
+
+ brcmf_dbg(TRACE, "enter\n");
+ pi = cfg->pno;
+ cfg->pno = NULL;
+
+ WARN_ON(pi->n_reqs);
+ mutex_destroy(&pi->req_lock);
+ kfree(pi);
+}
+
+void brcmf_pno_wiphy_params(struct wiphy *wiphy, bool gscan)
+{
+ /* scheduled scan settings */
+ wiphy->max_sched_scan_reqs = gscan ? BRCMF_PNO_MAX_BUCKETS : 1;
+ wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
+ wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
+ wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
+ wiphy->max_sched_scan_plan_interval = BRCMF_PNO_SCHED_SCAN_MAX_PERIOD;
+}
+
+u64 brcmf_pno_find_reqid_by_bucket(struct brcmf_pno_info *pi, u32 bucket)
+{
+ u64 reqid = 0;
+
+ mutex_lock(&pi->req_lock);
+
+ if (bucket < pi->n_reqs)
+ reqid = pi->reqs[bucket]->reqid;
+
+ mutex_unlock(&pi->req_lock);
+ return reqid;
+}
+
+u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi,
+ struct brcmf_pno_net_info_le *ni)
+{
+ struct cfg80211_sched_scan_request *req;
+ struct cfg80211_match_set *ms;
+ u32 bucket_map = 0;
+ int i, j;
+
+ mutex_lock(&pi->req_lock);
+ for (i = 0; i < pi->n_reqs; i++) {
+ req = pi->reqs[i];
+
+ if (!req->n_match_sets)
+ continue;
+ for (j = 0; j < req->n_match_sets; j++) {
+ ms = &req->match_sets[j];
+ if (ms->ssid.ssid_len == ni->SSID_len &&
+ !memcmp(ms->ssid.ssid, ni->SSID, ni->SSID_len)) {
+ bucket_map |= BIT(i);
+ break;
+ }
+ if (is_valid_ether_addr(ms->bssid) &&
+ !memcmp(ms->bssid, ni->bssid, ETH_ALEN)) {
+ bucket_map |= BIT(i);
+ break;
+ }
+ }
+ }
+ mutex_unlock(&pi->req_lock);
+ return bucket_map;
+}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h
index bae55b2af78c..cd9e35ae3b21 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h
@@ -21,12 +21,8 @@
#define BRCMF_PNO_SCHED_SCAN_MIN_PERIOD 10
#define BRCMF_PNO_SCHED_SCAN_MAX_PERIOD 508
-/**
- * brcmf_pno_clean - disable and clear pno in firmware.
- *
- * @ifp: interface object used.
- */
-int brcmf_pno_clean(struct brcmf_if *ifp);
+/* forward declaration */
+struct brcmf_pno_info;
/**
* brcmf_pno_start_sched_scan - initiate scheduled scan on device.
@@ -37,4 +33,51 @@ int brcmf_pno_clean(struct brcmf_if *ifp);
int brcmf_pno_start_sched_scan(struct brcmf_if *ifp,
struct cfg80211_sched_scan_request *req);
+/**
+ * brcmf_pno_stop_sched_scan - terminate scheduled scan on device.
+ *
+ * @ifp: interface object used.
+ * @reqid: unique identifier of scan to be stopped.
+ */
+int brcmf_pno_stop_sched_scan(struct brcmf_if *ifp, u64 reqid);
+
+/**
+ * brcmf_pno_wiphy_params - fill scheduled scan parameters in wiphy instance.
+ *
+ * @wiphy: wiphy instance to be used.
+ * @gscan: indicates whether the device has support for g-scan feature.
+ */
+void brcmf_pno_wiphy_params(struct wiphy *wiphy, bool gscan);
+
+/**
+ * brcmf_pno_attach - allocate and attach module information.
+ *
+ * @cfg: cfg80211 context used.
+ */
+int brcmf_pno_attach(struct brcmf_cfg80211_info *cfg);
+
+/**
+ * brcmf_pno_detach - detach and free module information.
+ *
+ * @cfg: cfg80211 context used.
+ */
+void brcmf_pno_detach(struct brcmf_cfg80211_info *cfg);
+
+/**
+ * brcmf_pno_find_reqid_by_bucket - find request id for given bucket index.
+ *
+ * @pi: pno instance used.
+ * @bucket: index of firmware bucket.
+ */
+u64 brcmf_pno_find_reqid_by_bucket(struct brcmf_pno_info *pi, u32 bucket);
+
+/**
+ * brcmf_pno_get_bucket_map - determine bucket map for given netinfo.
+ *
+ * @pi: pno instance used.
+ * @netinfo: netinfo to compare with bucket configuration.
+ */
+u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi,
+ struct brcmf_pno_net_info_le *netinfo);
+
#endif /* _BRCMF_PNO_H */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
index 34b59feedeba..2404f8a7c31c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
@@ -44,6 +44,10 @@ struct brcmf_proto {
void (*add_tdls_peer)(struct brcmf_pub *drvr, int ifidx,
u8 peer[ETH_ALEN]);
void (*rxreorder)(struct brcmf_if *ifp, struct sk_buff *skb);
+ void (*add_if)(struct brcmf_if *ifp);
+ void (*del_if)(struct brcmf_if *ifp);
+ void (*reset_if)(struct brcmf_if *ifp);
+ int (*init_done)(struct brcmf_pub *drvr);
void *pd;
};
@@ -118,4 +122,36 @@ brcmf_proto_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb)
ifp->drvr->proto->rxreorder(ifp, skb);
}
+static inline void
+brcmf_proto_add_if(struct brcmf_pub *drvr, struct brcmf_if *ifp)
+{
+ if (!drvr->proto->add_if)
+ return;
+ drvr->proto->add_if(ifp);
+}
+
+static inline void
+brcmf_proto_del_if(struct brcmf_pub *drvr, struct brcmf_if *ifp)
+{
+ if (!drvr->proto->del_if)
+ return;
+ drvr->proto->del_if(ifp);
+}
+
+static inline void
+brcmf_proto_reset_if(struct brcmf_pub *drvr, struct brcmf_if *ifp)
+{
+ if (!drvr->proto->reset_if)
+ return;
+ drvr->proto->reset_if(ifp);
+}
+
+static inline int
+brcmf_proto_init_done(struct brcmf_pub *drvr)
+{
+ if (!drvr->proto->init_done)
+ return 0;
+ return drvr->proto->init_done(drvr);
+}
+
#endif /* BRCMFMAC_PROTO_H */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index dfb0658713d9..fbcbb4325936 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -22,7 +22,7 @@
#include <linux/pci_ids.h>
#include <linux/netdevice.h>
#include <linux/interrupt.h>
-#include <linux/sched.h>
+#include <linux/sched/signal.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio_func.h>
@@ -44,6 +44,7 @@
#include "firmware.h"
#include "core.h"
#include "common.h"
+#include "bcdc.h"
#define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500)
#define CTL_DONE_TIMEOUT msecs_to_jiffies(2500)
@@ -539,7 +540,11 @@ static int qcount[NUMPRIO];
/* Limit on rounding up frames */
static const uint max_roundup = 512;
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+#define ALIGNMENT 8
+#else
#define ALIGNMENT 4
+#endif
enum brcmf_sdio_frmtype {
BRCMF_SDIO_FT_NORMAL,
@@ -607,7 +612,9 @@ BRCMF_FW_NVRAM_DEF(43340, "brcmfmac43340-sdio.bin", "brcmfmac43340-sdio.txt");
BRCMF_FW_NVRAM_DEF(4335, "brcmfmac4335-sdio.bin", "brcmfmac4335-sdio.txt");
BRCMF_FW_NVRAM_DEF(43362, "brcmfmac43362-sdio.bin", "brcmfmac43362-sdio.txt");
BRCMF_FW_NVRAM_DEF(4339, "brcmfmac4339-sdio.bin", "brcmfmac4339-sdio.txt");
-BRCMF_FW_NVRAM_DEF(43430, "brcmfmac43430-sdio.bin", "brcmfmac43430-sdio.txt");
+BRCMF_FW_NVRAM_DEF(43430A0, "brcmfmac43430a0-sdio.bin", "brcmfmac43430a0-sdio.txt");
+/* Note the names are not postfixed with a1 for backward compatibility */
+BRCMF_FW_NVRAM_DEF(43430A1, "brcmfmac43430-sdio.bin", "brcmfmac43430-sdio.txt");
BRCMF_FW_NVRAM_DEF(43455, "brcmfmac43455-sdio.bin", "brcmfmac43455-sdio.txt");
BRCMF_FW_NVRAM_DEF(4354, "brcmfmac4354-sdio.bin", "brcmfmac4354-sdio.txt");
BRCMF_FW_NVRAM_DEF(4356, "brcmfmac4356-sdio.bin", "brcmfmac4356-sdio.txt");
@@ -625,7 +632,8 @@ static struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, 4335),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFF, 43430),
+ BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000001, 43430A0),
+ BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFE, 43430A1),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFFC0, 43455),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356)
@@ -1661,7 +1669,7 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
pfirst->len, pfirst->next,
pfirst->prev);
skb_unlink(pfirst, &bus->glom);
- if (brcmf_sdio_fromevntchan(pfirst->data))
+ if (brcmf_sdio_fromevntchan(&dptr[SDPCM_HWHDR_LEN]))
brcmf_rx_event(bus->sdiodev->dev, pfirst);
else
brcmf_rx_frame(bus->sdiodev->dev, pfirst,
@@ -2029,6 +2037,7 @@ brcmf_sdio_wait_event_wakeup(struct brcmf_sdio *bus)
static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt)
{
+ struct brcmf_bus_stats *stats;
u16 head_pad;
u8 *dat_buf;
@@ -2038,16 +2047,18 @@ static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt)
head_pad = ((unsigned long)dat_buf % bus->head_align);
if (head_pad) {
if (skb_headroom(pkt) < head_pad) {
- bus->sdiodev->bus_if->tx_realloc++;
- head_pad = 0;
- if (skb_cow(pkt, head_pad))
+ stats = &bus->sdiodev->bus_if->stats;
+ atomic_inc(&stats->pktcowed);
+ if (skb_cow_head(pkt, head_pad)) {
+ atomic_inc(&stats->pktcow_failed);
return -ENOMEM;
+ }
}
skb_push(pkt, head_pad);
dat_buf = (u8 *)(pkt->data);
- memset(dat_buf, 0, head_pad + bus->tx_hdrlen);
}
- return head_pad;
+ memset(dat_buf, 0, head_pad + bus->tx_hdrlen);
+ return 0;
}
/**
@@ -2265,7 +2276,8 @@ done:
bus->tx_seq = (bus->tx_seq + pktq->qlen) % SDPCM_SEQ_WRAP;
skb_queue_walk_safe(pktq, pkt_next, tmp) {
__skb_unlink(pkt_next, pktq);
- brcmf_txcomplete(bus->sdiodev->dev, pkt_next, ret == 0);
+ brcmf_proto_bcdc_txcomplete(bus->sdiodev->dev, pkt_next,
+ ret == 0);
}
return ret;
}
@@ -2328,7 +2340,7 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
if ((bus->sdiodev->state == BRCMF_SDIOD_DATA) &&
bus->txoff && (pktq_len(&bus->txq) < TXLOW)) {
bus->txoff = false;
- brcmf_txflowblock(bus->sdiodev->dev, false);
+ brcmf_proto_bcdc_txflowblock(bus->sdiodev->dev, false);
}
return cnt;
@@ -2753,7 +2765,7 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
if (pktq_len(&bus->txq) >= TXHI) {
bus->txoff = true;
- brcmf_txflowblock(dev, true);
+ brcmf_proto_bcdc_txflowblock(dev, true);
}
spin_unlock_bh(&bus->txq_lock);
@@ -3416,7 +3428,7 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
/* otherwise, set txglomalign */
value = sdiodev->settings->bus.sdio.sd_sgentry_align;
/* SDIO ADMA requires at least 32 bit alignment */
- value = max_t(u32, value, 4);
+ value = max_t(u32, value, ALIGNMENT);
err = brcmf_iovar_data_set(dev, "bus:txglomalign", &value,
sizeof(u32));
}
@@ -3976,21 +3988,26 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
.get_memdump = brcmf_sdio_bus_get_memdump,
};
-static void brcmf_sdio_firmware_callback(struct device *dev,
+static void brcmf_sdio_firmware_callback(struct device *dev, int err,
const struct firmware *code,
void *nvram, u32 nvram_len)
{
- 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 = 0;
+ struct brcmf_bus *bus_if;
+ struct brcmf_sdio_dev *sdiodev;
+ struct brcmf_sdio *bus;
u8 saveclk;
- brcmf_dbg(TRACE, "Enter: dev=%s\n", dev_name(dev));
+ brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err);
+ bus_if = dev_get_drvdata(dev);
+ sdiodev = bus_if->bus_priv.sdio;
+ if (err)
+ goto fail;
if (!bus_if->drvr)
return;
+ bus = sdiodev->bus;
+
/* try to download image and nvram to the dongle */
bus->alp_only = true;
err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len);
@@ -4065,7 +4082,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev,
sdio_release_host(sdiodev->func[1]);
- err = brcmf_bus_start(dev);
+ err = brcmf_bus_started(dev);
if (err != 0) {
brcmf_err("dongle is not responding\n");
goto fail;
@@ -4077,6 +4094,7 @@ release:
fail:
brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), err);
device_release_driver(dev);
+ device_release_driver(&sdiodev->func[2]->dev);
}
struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
index 2f978a39b58a..0eea48e73331 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
@@ -29,6 +29,7 @@
#include "usb.h"
#include "core.h"
#include "common.h"
+#include "bcdc.h"
#define IOCTL_RESP_TIMEOUT msecs_to_jiffies(2000)
@@ -482,13 +483,13 @@ static void brcmf_usb_tx_complete(struct urb *urb)
req->skb);
brcmf_usb_del_fromq(devinfo, req);
- brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0);
+ brcmf_proto_bcdc_txcomplete(devinfo->dev, req->skb, urb->status == 0);
req->skb = NULL;
brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req, &devinfo->tx_freecount);
spin_lock_irqsave(&devinfo->tx_flowblock_lock, flags);
if (devinfo->tx_freecount > devinfo->tx_high_watermark &&
devinfo->tx_flowblock) {
- brcmf_txflowblock(devinfo->dev, false);
+ brcmf_proto_bcdc_txflowblock(devinfo->dev, false);
devinfo->tx_flowblock = false;
}
spin_unlock_irqrestore(&devinfo->tx_flowblock_lock, flags);
@@ -635,7 +636,7 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
spin_lock_irqsave(&devinfo->tx_flowblock_lock, flags);
if (devinfo->tx_freecount < devinfo->tx_low_watermark &&
!devinfo->tx_flowblock) {
- brcmf_txflowblock(dev, true);
+ brcmf_proto_bcdc_txflowblock(dev, true);
devinfo->tx_flowblock = true;
}
spin_unlock_irqrestore(&devinfo->tx_flowblock_lock, flags);
@@ -1148,7 +1149,7 @@ static int brcmf_usb_bus_setup(struct brcmf_usbdev_info *devinfo)
if (ret)
goto fail;
- ret = brcmf_bus_start(devinfo->dev);
+ ret = brcmf_bus_started(devinfo->dev);
if (ret)
goto fail;
@@ -1158,17 +1159,18 @@ fail:
return ret;
}
-static void brcmf_usb_probe_phase2(struct device *dev,
+static void brcmf_usb_probe_phase2(struct device *dev, int ret,
const struct firmware *fw,
void *nvram, u32 nvlen)
{
struct brcmf_bus *bus = dev_get_drvdata(dev);
- struct brcmf_usbdev_info *devinfo;
- int ret;
+ struct brcmf_usbdev_info *devinfo = bus->bus_priv.usb->devinfo;
+
+ if (ret)
+ goto error;
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");
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
index 7c2a9a9bc372..ddfdfe177e24 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
@@ -1082,6 +1082,8 @@ static int ieee_hw_init(struct ieee80211_hw *hw)
* hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
*/
+ wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
hw->rate_control_algorithm = "minstrel_ht";
hw->sta_data_size = 0;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c
index c2a938b59044..0a14942b8216 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c
@@ -7092,9 +7092,9 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
rspec = brcms_c_compute_rspec(rxh, plcp);
if (is_mcs_rate(rspec)) {
rx_status->rate_idx = rspec & RSPEC_RATE_MASK;
- rx_status->flag |= RX_FLAG_HT;
+ rx_status->encoding = RX_ENC_HT;
if (rspec_is40mhz(rspec))
- rx_status->flag |= RX_FLAG_40MHZ;
+ rx_status->bw = RATE_INFO_BW_40;
} else {
switch (rspec2rate(rspec)) {
case BRCM_RATE_1M:
@@ -7149,9 +7149,9 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
/* Determine short preamble and rate_idx */
if (is_cck_rate(rspec)) {
if (rxh->PhyRxStatus_0 & PRXS0_SHORTH)
- rx_status->flag |= RX_FLAG_SHORTPRE;
+ rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
} else if (is_ofdm_rate(rspec)) {
- rx_status->flag |= RX_FLAG_SHORTPRE;
+ rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
} else {
brcms_err(wlc->hw->d11core, "%s: Unknown modulation\n",
__func__);
@@ -7159,7 +7159,7 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
}
if (plcp3_issgi(plcp[3]))
- rx_status->flag |= RX_FLAG_SHORT_GI;
+ rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
if (rxh->RxStatus1 & RXS_DECERR) {
rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC;