aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/broadcom/brcm80211/brcmfmac
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/broadcom/brcm80211/brcmfmac')
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c11
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c89
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h21
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c134
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c12
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c74
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h5
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c45
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c18
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c4
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c147
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h4
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c5
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c4
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c34
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h28
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h21
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c28
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h5
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c30
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h4
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c33
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c22
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c512
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c14
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h6
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c63
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h18
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h12
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c23
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/xtlv.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/xtlv.h2
33 files changed, 983 insertions, 449 deletions
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
index 3984fd7d918e..9ec0c60b6da1 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
@@ -87,6 +87,8 @@ struct brcmf_proto_bcdc_header {
* plus any space that might be needed
* for bus alignment padding.
*/
+#define ROUND_UP_MARGIN 2048
+
struct brcmf_bcdc {
u16 reqid;
u8 bus_header[BUS_HEADER_LEN];
@@ -368,8 +370,7 @@ brcmf_proto_bcdc_txcomplete(struct device *dev, struct sk_buff *txp,
/* await txstatus signal for firmware if active */
if (brcmf_fws_fc_active(bcdc->fws)) {
- if (!success)
- brcmf_fws_bustxfail(bcdc->fws, txp);
+ brcmf_fws_bustxcomplete(bcdc->fws, txp, success);
} else {
if (brcmf_proto_bcdc_hdrpull(bus_if->drvr, false, txp, &ifp))
brcmu_pkt_buf_free_skb(txp);
@@ -397,9 +398,9 @@ brcmf_proto_bcdc_add_tdls_peer(struct brcmf_pub *drvr, int ifidx,
}
static void brcmf_proto_bcdc_rxreorder(struct brcmf_if *ifp,
- struct sk_buff *skb, bool inirq)
+ struct sk_buff *skb)
{
- brcmf_fws_rxreorder(ifp, skb, inirq);
+ brcmf_fws_rxreorder(ifp, skb);
}
static void
@@ -471,7 +472,7 @@ int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;
drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN +
- sizeof(struct brcmf_proto_bcdc_dcmd);
+ sizeof(struct brcmf_proto_bcdc_dcmd) + ROUND_UP_MARGIN;
return 0;
fail:
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
index ac02244a6fdf..d0daef674e72 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -784,9 +784,11 @@ void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
sdiodev->txglomsz = sdiodev->settings->bus.sdio.txglomsz;
}
-#ifdef CONFIG_PM_SLEEP
static int brcmf_sdiod_freezer_attach(struct brcmf_sdio_dev *sdiodev)
{
+ if (!IS_ENABLED(CONFIG_PM_SLEEP))
+ return 0;
+
sdiodev->freezer = kzalloc(sizeof(*sdiodev->freezer), GFP_KERNEL);
if (!sdiodev->freezer)
return -ENOMEM;
@@ -802,6 +804,7 @@ static void brcmf_sdiod_freezer_detach(struct brcmf_sdio_dev *sdiodev)
if (sdiodev->freezer) {
WARN_ON(atomic_read(&sdiodev->freezer->freezing));
kfree(sdiodev->freezer);
+ sdiodev->freezer = NULL;
}
}
@@ -833,7 +836,8 @@ static void brcmf_sdiod_freezer_off(struct brcmf_sdio_dev *sdiodev)
bool brcmf_sdiod_freezing(struct brcmf_sdio_dev *sdiodev)
{
- return atomic_read(&sdiodev->freezer->freezing);
+ return IS_ENABLED(CONFIG_PM_SLEEP) &&
+ atomic_read(&sdiodev->freezer->freezing);
}
void brcmf_sdiod_try_freeze(struct brcmf_sdio_dev *sdiodev)
@@ -847,24 +851,16 @@ void brcmf_sdiod_try_freeze(struct brcmf_sdio_dev *sdiodev)
void brcmf_sdiod_freezer_count(struct brcmf_sdio_dev *sdiodev)
{
- atomic_inc(&sdiodev->freezer->thread_count);
+ if (IS_ENABLED(CONFIG_PM_SLEEP))
+ atomic_inc(&sdiodev->freezer->thread_count);
}
void brcmf_sdiod_freezer_uncount(struct brcmf_sdio_dev *sdiodev)
{
- atomic_dec(&sdiodev->freezer->thread_count);
-}
-#else
-static int brcmf_sdiod_freezer_attach(struct brcmf_sdio_dev *sdiodev)
-{
- return 0;
+ if (IS_ENABLED(CONFIG_PM_SLEEP))
+ atomic_dec(&sdiodev->freezer->thread_count);
}
-static void brcmf_sdiod_freezer_detach(struct brcmf_sdio_dev *sdiodev)
-{
-}
-#endif /* CONFIG_PM_SLEEP */
-
int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
{
sdiodev->state = BRCMF_SDIOD_DOWN;
@@ -875,13 +871,9 @@ int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
brcmf_sdiod_freezer_detach(sdiodev);
- /* Disable Function 2 */
- sdio_claim_host(sdiodev->func2);
- sdio_disable_func(sdiodev->func2);
- sdio_release_host(sdiodev->func2);
-
- /* Disable Function 1 */
+ /* Disable functions 2 then 1. */
sdio_claim_host(sdiodev->func1);
+ sdio_disable_func(sdiodev->func2);
sdio_disable_func(sdiodev->func1);
sdio_release_host(sdiodev->func1);
@@ -911,7 +903,7 @@ int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
if (ret) {
brcmf_err("Failed to set F1 blocksize\n");
sdio_release_host(sdiodev->func1);
- goto out;
+ return ret;
}
switch (sdiodev->func2->device) {
case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373:
@@ -933,7 +925,7 @@ int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
if (ret) {
brcmf_err("Failed to set F2 blocksize\n");
sdio_release_host(sdiodev->func1);
- goto out;
+ return ret;
} else {
brcmf_dbg(SDIO, "set F2 blocksize to %d\n", f2_blksz);
}
@@ -991,6 +983,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = {
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43439),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_89359),
{ /* end: all zeroes */ }
@@ -1119,18 +1112,29 @@ void brcmf_sdio_wowl_config(struct device *dev, bool enabled)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+ mmc_pm_flag_t pm_caps = sdio_get_host_pm_caps(sdiodev->func1);
+
+ /* Power must be preserved to be able to support WOWL. */
+ if (!(pm_caps & MMC_PM_KEEP_POWER))
+ goto notsup;
- brcmf_dbg(SDIO, "Configuring WOWL, enabled=%d\n", enabled);
- sdiodev->wowl_enabled = enabled;
+ if (sdiodev->settings->bus.sdio.oob_irq_supported ||
+ pm_caps & MMC_PM_WAKE_SDIO_IRQ) {
+ sdiodev->wowl_enabled = enabled;
+ brcmf_dbg(SDIO, "Configuring WOWL, enabled=%d\n", enabled);
+ return;
+ }
+
+notsup:
+ brcmf_dbg(SDIO, "WOWL not supported\n");
}
-#ifdef CONFIG_PM_SLEEP
static int brcmf_ops_sdio_suspend(struct device *dev)
{
struct sdio_func *func;
struct brcmf_bus *bus_if;
struct brcmf_sdio_dev *sdiodev;
- mmc_pm_flag_t pm_caps, sdio_flags;
+ mmc_pm_flag_t sdio_flags;
int ret = 0;
func = container_of(dev, struct sdio_func, dev);
@@ -1142,20 +1146,15 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
bus_if = dev_get_drvdata(dev);
sdiodev = bus_if->bus_priv.sdio;
- pm_caps = sdio_get_host_pm_caps(func);
-
- if (pm_caps & MMC_PM_KEEP_POWER) {
- /* preserve card power during suspend */
+ if (sdiodev->wowl_enabled) {
brcmf_sdiod_freezer_on(sdiodev);
brcmf_sdio_wd_timer(sdiodev->bus, 0);
sdio_flags = MMC_PM_KEEP_POWER;
- if (sdiodev->wowl_enabled) {
- if (sdiodev->settings->bus.sdio.oob_irq_supported)
- enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
- else
- sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;
- }
+ if (sdiodev->settings->bus.sdio.oob_irq_supported)
+ enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
+ else
+ sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;
if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags))
brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
@@ -1176,21 +1175,19 @@ static int brcmf_ops_sdio_resume(struct device *dev)
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct sdio_func *func = container_of(dev, struct sdio_func, dev);
- mmc_pm_flag_t pm_caps = sdio_get_host_pm_caps(func);
int ret = 0;
brcmf_dbg(SDIO, "Enter: F%d\n", func->num);
if (func->num != 2)
return 0;
- if (!(pm_caps & MMC_PM_KEEP_POWER)) {
+ if (!sdiodev->wowl_enabled) {
/* bus was powered off and device removed, probe again */
ret = brcmf_sdiod_probe(sdiodev);
if (ret)
brcmf_err("Failed to probe device on resume\n");
} else {
- if (sdiodev->wowl_enabled &&
- sdiodev->settings->bus.sdio.oob_irq_supported)
+ if (sdiodev->settings->bus.sdio.oob_irq_supported)
disable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
brcmf_sdiod_freezer_off(sdiodev);
@@ -1199,11 +1196,9 @@ static int brcmf_ops_sdio_resume(struct device *dev)
return ret;
}
-static const struct dev_pm_ops brcmf_sdio_pm_ops = {
- .suspend = brcmf_ops_sdio_suspend,
- .resume = brcmf_ops_sdio_resume,
-};
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(brcmf_sdio_pm_ops,
+ brcmf_ops_sdio_suspend,
+ brcmf_ops_sdio_resume);
static struct sdio_driver brcmf_sdmmc_driver = {
.probe = brcmf_ops_sdio_probe,
@@ -1212,9 +1207,7 @@ static struct sdio_driver brcmf_sdmmc_driver = {
.id_table = brcmf_sdmmc_ids,
.drv = {
.owner = THIS_MODULE,
-#ifdef CONFIG_PM_SLEEP
- .pm = &brcmf_sdio_pm_ops,
-#endif /* CONFIG_PM_SLEEP */
+ .pm = pm_sleep_ptr(&brcmf_sdio_pm_ops),
.coredump = brcmf_dev_coredump,
},
};
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
index 3f5da3bb6aa5..2208ab3aa795 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
@@ -6,6 +6,8 @@
#ifndef BRCMFMAC_BUS_H
#define BRCMFMAC_BUS_H
+#include <linux/kernel.h>
+#include <linux/firmware.h>
#include "debug.h"
/* IDs of the 6 default common rings of msgbuf protocol */
@@ -34,6 +36,11 @@ enum brcmf_bus_protocol_type {
BRCMF_PROTO_MSGBUF
};
+/* Firmware blobs that may be available */
+enum brcmf_blob_type {
+ BRCMF_BLOB_CLM,
+};
+
struct brcmf_mp_device;
struct brcmf_bus_dcmd {
@@ -60,7 +67,7 @@ struct brcmf_bus_dcmd {
* @wowl_config: specify if dongle is configured for wowl when going to suspend
* @get_ramsize: obtain size of device memory.
* @get_memdump: obtain device memory dump in provided buffer.
- * @get_fwname: obtain firmware name.
+ * @get_blob: obtain a firmware blob.
*
* This structure provides an abstract interface towards the
* bus specific driver. For control messages to common driver
@@ -77,8 +84,8 @@ struct brcmf_bus_ops {
void (*wowl_config)(struct device *dev, bool enabled);
size_t (*get_ramsize)(struct device *dev);
int (*get_memdump)(struct device *dev, void *data, size_t len);
- int (*get_fwname)(struct device *dev, const char *ext,
- unsigned char *fw_name);
+ int (*get_blob)(struct device *dev, const struct firmware **fw,
+ enum brcmf_blob_type type);
void (*debugfs_create)(struct device *dev);
int (*reset)(struct device *dev);
};
@@ -89,7 +96,7 @@ struct brcmf_bus_ops {
*
* @commonrings: commonrings which are always there.
* @flowrings: commonrings which are dynamically created and destroyed for data.
- * @rx_dataoffset: if set then all rx data has this this offset.
+ * @rx_dataoffset: if set then all rx data has this offset.
* @max_rxbufpost: maximum number of buffers to post for rx.
* @max_flowrings: maximum number of tx flow rings supported.
* @max_submissionrings: maximum number of submission rings(h2d) supported.
@@ -220,10 +227,10 @@ int brcmf_bus_get_memdump(struct brcmf_bus *bus, void *data, size_t len)
}
static inline
-int brcmf_bus_get_fwname(struct brcmf_bus *bus, const char *ext,
- unsigned char *fw_name)
+int brcmf_bus_get_blob(struct brcmf_bus *bus, const struct firmware **fw,
+ enum brcmf_blob_type type)
{
- return bus->ops->get_fwname(bus->dev, ext, fw_name);
+ return bus->ops->get_blob(bus->dev, fw, type);
}
static inline
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index fb727778312c..dfcfb3333369 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -16,6 +16,7 @@
#include <brcmu_utils.h>
#include <defs.h>
#include <brcmu_wifi.h>
+#include <brcm_hw_ids.h>
#include "core.h"
#include "debug.h"
#include "tracepoint.h"
@@ -2166,7 +2167,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
offsetof(struct brcmf_assoc_params_le, chanspec_list);
if (cfg->channel)
join_params_size += sizeof(u16);
- ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
+ ext_join_params = kzalloc(sizeof(*ext_join_params), GFP_KERNEL);
if (ext_join_params == NULL) {
err = -ENOMEM;
goto done;
@@ -2360,7 +2361,8 @@ done:
static s32
brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
- u8 key_idx, bool unicast, bool multicast)
+ int link_id, u8 key_idx, bool unicast,
+ bool multicast)
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
@@ -2394,7 +2396,8 @@ done:
static s32
brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
- u8 key_idx, bool pairwise, const u8 *mac_addr)
+ int link_id, u8 key_idx, bool pairwise,
+ const u8 *mac_addr)
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_wsec_key *key;
@@ -2431,8 +2434,8 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
static s32
brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
- u8 key_idx, bool pairwise, const u8 *mac_addr,
- struct key_params *params)
+ int link_id, u8 key_idx, bool pairwise,
+ const u8 *mac_addr, struct key_params *params)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
@@ -2456,8 +2459,8 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
}
if (params->key_len == 0)
- return brcmf_cfg80211_del_key(wiphy, ndev, key_idx, pairwise,
- mac_addr);
+ return brcmf_cfg80211_del_key(wiphy, ndev, -1, key_idx,
+ pairwise, mac_addr);
if (params->key_len > sizeof(key->data)) {
bphy_err(drvr, "Too long key length (%u)\n", params->key_len);
@@ -2552,8 +2555,9 @@ done:
}
static s32
-brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx,
- bool pairwise, const u8 *mac_addr, void *cookie,
+brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
+ int link_id, u8 key_idx, bool pairwise,
+ const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie,
struct key_params *params))
{
@@ -2609,7 +2613,8 @@ done:
static s32
brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
- struct net_device *ndev, u8 key_idx)
+ struct net_device *ndev, int link_id,
+ u8 key_idx)
{
struct brcmf_if *ifp = netdev_priv(ndev);
@@ -3159,10 +3164,7 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
struct brcmf_if *ifp)
{
struct brcmf_pub *drvr = cfg->pub;
- struct brcmf_bss_info_le *bi;
- const struct brcmf_tlv *tim;
- size_t ie_len;
- u8 *ie;
+ struct brcmf_bss_info_le *bi = NULL;
s32 err = 0;
brcmf_dbg(TRACE, "Enter\n");
@@ -3176,29 +3178,8 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
bphy_err(drvr, "Could not get bss info %d\n", err);
goto update_bss_info_out;
}
-
bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
err = brcmf_inform_single_bss(cfg, bi);
- if (err)
- goto update_bss_info_out;
-
- ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
- ie_len = le32_to_cpu(bi->ie_length);
-
- tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
- if (!tim) {
- /*
- * active scan was done so we could not get dtim
- * information out of probe response.
- * so we speficially query dtim information to dongle.
- */
- u32 var;
- err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
- if (err) {
- bphy_err(drvr, "wl dtim_assoc failed (%d)\n", err);
- goto update_bss_info_out;
- }
- }
update_bss_info_out:
brcmf_dbg(TRACE, "Exit");
@@ -3901,6 +3882,24 @@ static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
cfg->wowl.active = true;
}
+static int brcmf_keepalive_start(struct brcmf_if *ifp, unsigned int interval)
+{
+ struct brcmf_mkeep_alive_pkt_le kalive = {0};
+ int ret = 0;
+
+ /* Configure Null function/data keepalive */
+ kalive.version = cpu_to_le16(1);
+ kalive.period_msec = cpu_to_le32(interval * MSEC_PER_SEC);
+ kalive.len_bytes = cpu_to_le16(0);
+ kalive.keep_alive_id = 0;
+
+ ret = brcmf_fil_iovar_data_set(ifp, "mkeep_alive", &kalive, sizeof(kalive));
+ if (ret)
+ brcmf_err("keep-alive packet config failed, ret=%d\n", ret);
+
+ return ret;
+}
+
static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
struct cfg80211_wowlan *wowl)
{
@@ -3947,6 +3946,9 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
} else {
/* Configure WOWL paramaters */
brcmf_configure_wowl(cfg, ifp, wowl);
+
+ /* Prevent disassociation due to inactivity with keep-alive */
+ brcmf_keepalive_start(ifp, 30);
}
exit:
@@ -3962,7 +3964,6 @@ brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
struct brcmf_pmk_list_le *pmk_list;
int i;
u32 npmk;
- s32 err;
pmk_list = &cfg->pmk_list;
npmk = le32_to_cpu(pmk_list->npmk);
@@ -3971,10 +3972,8 @@ brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
for (i = 0; i < npmk; i++)
brcmf_dbg(CONN, "PMK[%d]: %pM\n", i, &pmk_list->pmk[i].bssid);
- err = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list,
- sizeof(*pmk_list));
-
- return err;
+ return brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list,
+ sizeof(*pmk_list));
}
static s32
@@ -4601,7 +4600,7 @@ exit:
s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
{
- s32 pktflags[] = {
+ static const s32 pktflags[] = {
BRCMF_VNDR_IE_PRBREQ_FLAG,
BRCMF_VNDR_IE_PRBRSP_FLAG,
BRCMF_VNDR_IE_BEACON_FLAG
@@ -4943,7 +4942,8 @@ exit:
return err;
}
-static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
+static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev,
+ unsigned int link_id)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
@@ -5019,13 +5019,10 @@ brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_beacon_data *info)
{
struct brcmf_if *ifp = netdev_priv(ndev);
- s32 err;
brcmf_dbg(TRACE, "Enter\n");
- err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
-
- return err;
+ return brcmf_config_ap_mgmt_ie(ifp->vif, info);
}
static int
@@ -5280,6 +5277,7 @@ exit:
static int brcmf_cfg80211_get_channel(struct wiphy *wiphy,
struct wireless_dev *wdev,
+ unsigned int link_id,
struct cfg80211_chan_def *chandef)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
@@ -5993,8 +5991,8 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
done:
kfree(buf);
- roam_info.channel = notify_channel;
- roam_info.bssid = profile->bssid;
+ roam_info.links[0].channel = notify_channel;
+ roam_info.links[0].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;
@@ -6037,7 +6035,7 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
} else {
conn_params.status = WLAN_STATUS_AUTH_TIMEOUT;
}
- conn_params.bssid = profile->bssid;
+ conn_params.links[0].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;
@@ -6407,6 +6405,7 @@ static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
cfg->dongle_up = false; /* dongle down */
brcmf_abort_scanning(cfg);
brcmf_deinit_priv_mem(cfg);
+ brcmf_clear_assoc_ies(cfg);
}
static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
@@ -7455,6 +7454,21 @@ int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
vif_event_equals(event, action), timeout);
}
+static bool brmcf_use_iso3166_ccode_fallback(struct brcmf_pub *drvr)
+{
+ if (drvr->settings->trivial_ccode_map)
+ return true;
+
+ switch (drvr->bus_if->chip) {
+ case BRCM_CC_43430_CHIP_ID:
+ case BRCM_CC_4345_CHIP_ID:
+ case BRCM_CC_43602_CHIP_ID:
+ return true;
+ default:
+ return false;
+ }
+}
+
static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
struct brcmf_fil_country_le *ccreq)
{
@@ -7463,18 +7477,28 @@ static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
s32 found_index;
int i;
- country_codes = drvr->settings->country_codes;
- if (!country_codes) {
- brcmf_dbg(TRACE, "No country codes configured for device\n");
- return -EINVAL;
- }
-
if ((alpha2[0] == ccreq->country_abbrev[0]) &&
(alpha2[1] == ccreq->country_abbrev[1])) {
brcmf_dbg(TRACE, "Country code already set\n");
return -EAGAIN;
}
+ country_codes = drvr->settings->country_codes;
+ if (!country_codes) {
+ if (brmcf_use_iso3166_ccode_fallback(drvr)) {
+ brcmf_dbg(TRACE, "No country codes configured for device, using ISO3166 code and 0 rev\n");
+ memset(ccreq, 0, sizeof(*ccreq));
+ ccreq->country_abbrev[0] = alpha2[0];
+ ccreq->country_abbrev[1] = alpha2[1];
+ ccreq->ccode[0] = alpha2[0];
+ ccreq->ccode[1] = alpha2[1];
+ return 0;
+ }
+
+ brcmf_dbg(TRACE, "No country codes configured for device\n");
+ return -EINVAL;
+ }
+
found_index = -1;
for (i = 0; i < country_codes->table_size; i++) {
cc = &country_codes->table[i];
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
index 1ee49f9e325d..121893bbaa1d 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
@@ -641,6 +641,7 @@ static void brcmf_chip_socram_ramsize(struct brcmf_core_priv *sr, u32 *ramsize,
*srsize = (32 * 1024);
break;
case BRCM_CC_43430_CHIP_ID:
+ case CY_CC_43439_CHIP_ID:
/* assume sr for now as we can not check
* firmware sr capability at this point.
*/
@@ -704,6 +705,7 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci)
{
switch (ci->pub.chip) {
case BRCM_CC_4345_CHIP_ID:
+ case BRCM_CC_43454_CHIP_ID:
return 0x198000;
case BRCM_CC_4335_CHIP_ID:
case BRCM_CC_4339_CHIP_ID:
@@ -731,6 +733,10 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci)
return 0x160000;
case CY_CC_43752_CHIP_ID:
return 0x170000;
+ case BRCM_CC_4378_CHIP_ID:
+ return 0x352000;
+ case CY_CC_89459_CHIP_ID:
+ return ((ci->pub.chiprev < 9) ? 0x180000 : 0x160000);
default:
brcmf_err("unknown chip: %s\n", ci->pub.name);
break;
@@ -1257,7 +1263,8 @@ brcmf_chip_cm3_set_passive(struct brcmf_chip_priv *chip)
brcmf_chip_resetcore(core, 0, 0, 0);
/* disable bank #3 remap for this device */
- if (chip->pub.chip == BRCM_CC_43430_CHIP_ID) {
+ if (chip->pub.chip == BRCM_CC_43430_CHIP_ID ||
+ chip->pub.chip == CY_CC_43439_CHIP_ID) {
sr = container_of(core, struct brcmf_core_priv, pub);
brcmf_chip_core_write32(sr, SOCRAMREGOFFS(bankidx), 3);
brcmf_chip_core_write32(sr, SOCRAMREGOFFS(bankpda), 0);
@@ -1401,6 +1408,7 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub)
case BRCM_CC_4354_CHIP_ID:
case BRCM_CC_4356_CHIP_ID:
case BRCM_CC_4345_CHIP_ID:
+ case BRCM_CC_43454_CHIP_ID:
/* explicitly check SR engine enable bit */
pmu_cc3_mask = BIT(2);
fallthrough;
@@ -1414,10 +1422,12 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub)
reg = chip->ops->read32(chip->ctx, addr);
return (reg & pmu_cc3_mask) != 0;
case BRCM_CC_43430_CHIP_ID:
+ case CY_CC_43439_CHIP_ID:
addr = CORE_CC_REG(base, sr_control1);
reg = chip->ops->read32(chip->ctx, addr);
return reg != 0;
case CY_CC_4373_CHIP_ID:
+ case CY_CC_89459_CHIP_ID:
/* explicitly check SR engine enable bit */
addr = CORE_CC_REG(base, sr_control0);
reg = chip->ops->read32(chip->ctx, addr);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
index e3758bd86acf..74020fa10065 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -123,7 +123,6 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
struct brcmf_bus *bus = drvr->bus_if;
struct brcmf_dload_data_le *chunk_buf;
const struct firmware *clm = NULL;
- u8 clm_name[BRCMF_FW_NAME_LEN];
u32 chunk_len;
u32 datalen;
u32 cumulative_len;
@@ -133,15 +132,8 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
brcmf_dbg(TRACE, "Enter\n");
- memset(clm_name, 0, sizeof(clm_name));
- err = brcmf_bus_get_fwname(bus, ".clm_blob", clm_name);
- if (err) {
- bphy_err(drvr, "get CLM blob file name failed (%d)\n", err);
- return err;
- }
-
- err = firmware_request_nowarn(&clm, clm_name, bus->dev);
- if (err) {
+ err = brcmf_bus_get_blob(bus, &clm, BRCMF_BLOB_CLM);
+ if (err || !clm) {
brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n",
err);
return 0;
@@ -190,6 +182,31 @@ done:
return err;
}
+int brcmf_c_set_cur_etheraddr(struct brcmf_if *ifp, const u8 *addr)
+{
+ s32 err;
+
+ err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", addr, ETH_ALEN);
+ if (err < 0)
+ bphy_err(ifp->drvr, "Setting cur_etheraddr failed, %d\n", err);
+
+ return err;
+}
+
+/* On some boards there is no eeprom to hold the nvram, in this case instead
+ * a board specific nvram is loaded from /lib/firmware. On most boards the
+ * macaddr setting in the /lib/firmware nvram file is ignored because the
+ * wifibt chip has a unique MAC programmed into the chip itself.
+ * But in some cases the actual MAC from the /lib/firmware nvram file gets
+ * used, leading to MAC conflicts.
+ * The MAC addresses in the troublesome nvram files seem to all come from
+ * the same nvram file template, so we only need to check for 1 known
+ * address to detect this.
+ */
+static const u8 brcmf_default_mac_address[ETH_ALEN] = {
+ 0x00, 0x90, 0x4c, 0xc5, 0x12, 0x38
+};
+
int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
{
struct brcmf_pub *drvr = ifp->drvr;
@@ -202,13 +219,30 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
char *ptr;
s32 err;
- /* retreive mac address */
- err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
- sizeof(ifp->mac_addr));
- if (err < 0) {
- bphy_err(drvr, "Retrieving cur_etheraddr failed, %d\n", err);
- goto done;
+ if (is_valid_ether_addr(ifp->mac_addr)) {
+ /* set mac address */
+ err = brcmf_c_set_cur_etheraddr(ifp, ifp->mac_addr);
+ if (err < 0)
+ goto done;
+ } else {
+ /* retrieve mac address */
+ err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
+ sizeof(ifp->mac_addr));
+ if (err < 0) {
+ bphy_err(drvr, "Retrieving cur_etheraddr failed, %d\n", err);
+ goto done;
+ }
+
+ if (ether_addr_equal_unaligned(ifp->mac_addr, brcmf_default_mac_address)) {
+ bphy_err(drvr, "Default MAC is used, replacing with random MAC to avoid conflicts\n");
+ eth_random_addr(ifp->mac_addr);
+ ifp->ndev->addr_assign_type = NET_ADDR_RANDOM;
+ err = brcmf_c_set_cur_etheraddr(ifp, ifp->mac_addr);
+ if (err < 0)
+ goto done;
+ }
}
+
memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac));
memcpy(ifp->drvr->wiphy->perm_addr, ifp->drvr->mac, ETH_ALEN);
@@ -219,7 +253,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
&revinfo, sizeof(revinfo));
if (err < 0) {
bphy_err(drvr, "retrieving revision info failed, %d\n", err);
- strlcpy(ri->chipname, "UNKNOWN", sizeof(ri->chipname));
+ strscpy(ri->chipname, "UNKNOWN", sizeof(ri->chipname));
} else {
ri->vendorid = le32_to_cpu(revinfo.vendorid);
ri->deviceid = le32_to_cpu(revinfo.deviceid);
@@ -272,7 +306,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
/* locate firmware version number for ethtool */
ptr = strrchr(buf, ' ') + 1;
- strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver));
+ strscpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver));
/* Query for 'clmver' to get CLM version info from firmware */
memset(buf, 0, sizeof(buf));
@@ -382,11 +416,11 @@ static void brcmf_mp_attach(void)
* if not set then if available use the platform data version. To make
* sure it gets initialized at all, always copy the module param version
*/
- strlcpy(brcmf_mp_global.firmware_path, brcmf_firmware_path,
+ strscpy(brcmf_mp_global.firmware_path, brcmf_firmware_path,
BRCMF_FW_ALTPATH_LEN);
if ((brcmfmac_pdata) && (brcmfmac_pdata->fw_alternative_path) &&
(brcmf_mp_global.firmware_path[0] == '\0')) {
- strlcpy(brcmf_mp_global.firmware_path,
+ strscpy(brcmf_mp_global.firmware_path,
brcmfmac_pdata->fw_alternative_path,
BRCMF_FW_ALTPATH_LEN);
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
index 8b5f49997c8b..aa25abffcc7d 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
@@ -38,6 +38,7 @@ extern struct brcmf_mp_global_t brcmf_mp_global;
* @fcmode: FWS flow control.
* @roamoff: Firmware roaming off?
* @ignore_probe_fail: Ignore probe failure.
+ * @trivial_ccode_map: Assume firmware uses ISO3166 country codes with rev 0
* @country_codes: If available, pointer to struct for translating country codes
* @bus: Bus specific platform data. Only SDIO at the mmoment.
*/
@@ -48,8 +49,11 @@ struct brcmf_mp_device {
bool roamoff;
bool iapp;
bool ignore_probe_fail;
+ bool trivial_ccode_map;
struct brcmfmac_pd_cc *country_codes;
const char *board_type;
+ unsigned char mac[ETH_ALEN];
+ const char *antenna_sku;
union {
struct brcmfmac_sdio_pd sdio;
} bus;
@@ -64,6 +68,7 @@ void brcmf_release_module_param(struct brcmf_mp_device *module_param);
/* Sets dongle media info (drv_version, mac address). */
int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
+int brcmf_c_set_cur_etheraddr(struct brcmf_if *ifp, const u8 *addr);
#ifdef CONFIG_DMI
void brcmf_dmi_probe(struct brcmf_mp_device *settings, 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 fed9cd5f29a2..595ae3ae561e 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -7,6 +7,7 @@
#include <linux/etherdevice.h>
#include <linux/module.h>
#include <linux/inetdevice.h>
+#include <linux/property.h>
#include <net/cfg80211.h>
#include <net/rtnetlink.h>
#include <net/addrconf.h>
@@ -232,16 +233,12 @@ static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct sockaddr *sa = (struct sockaddr *)addr;
- struct brcmf_pub *drvr = ifp->drvr;
int err;
brcmf_dbg(TRACE, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx);
- err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", sa->sa_data,
- ETH_ALEN);
- if (err < 0) {
- bphy_err(drvr, "Setting cur_etheraddr failed, %d\n", err);
- } else {
+ err = brcmf_c_set_cur_etheraddr(ifp, sa->sa_data);
+ if (err >= 0) {
brcmf_dbg(TRACE, "updated to %pM\n", sa->sa_data);
memcpy(ifp->mac_addr, sa->sa_data, ETH_ALEN);
eth_hw_addr_set(ifp->ndev, ifp->mac_addr);
@@ -295,6 +292,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
struct brcmf_pub *drvr = ifp->drvr;
struct ethhdr *eh;
int head_delta;
+ unsigned int tx_bytes = skb->len;
brcmf_dbg(DATA, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx);
@@ -369,7 +367,7 @@ done:
ndev->stats.tx_dropped++;
} else {
ndev->stats.tx_packets++;
- ndev->stats.tx_bytes += skb->len;
+ ndev->stats.tx_bytes += tx_bytes;
}
/* Return ok: we always eat the packet */
@@ -400,7 +398,7 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp,
spin_unlock_irqrestore(&ifp->netif_stop_lock, flags);
}
-void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb, bool inirq)
+void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
{
/* Most of Broadcom's firmwares send 802.11f ADD frame every time a new
* STA connects to the AP interface. This is an obsoleted standard most
@@ -423,15 +421,7 @@ void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb, bool inirq)
ifp->ndev->stats.rx_packets++;
brcmf_dbg(DATA, "rx proto=0x%X\n", ntohs(skb->protocol));
- if (inirq) {
- netif_rx(skb);
- } else {
- /* If the receive is not processed inside an ISR,
- * the softirqd must be woken explicitly to service
- * the NET_RX_SOFTIRQ. This is handled by netif_rx_ni().
- */
- netif_rx_ni(skb);
- }
+ netif_rx(skb);
}
void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb)
@@ -480,7 +470,7 @@ void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb)
skb->pkt_type = PACKET_OTHERHOST;
skb->protocol = htons(ETH_P_802_2);
- brcmf_netif_rx(ifp, skb, false);
+ brcmf_netif_rx(ifp, skb);
}
static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb,
@@ -515,7 +505,7 @@ void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event,
return;
if (brcmf_proto_is_reorder_skb(skb)) {
- brcmf_proto_rxreorder(ifp, skb, inirq);
+ brcmf_proto_rxreorder(ifp, skb);
} else {
/* Process special event packets */
if (handle_event) {
@@ -524,7 +514,7 @@ void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event,
brcmf_fweh_process_skb(ifp->drvr, skb,
BCMILCP_SUBTYPE_VENDOR_LONG, gfp);
}
- brcmf_netif_rx(ifp, skb, inirq);
+ brcmf_netif_rx(ifp, skb);
}
}
@@ -572,10 +562,10 @@ static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
if (drvr->revinfo.result == 0)
brcmu_dotrev_str(drvr->revinfo.driverrev, drev);
- strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
- strlcpy(info->version, drev, sizeof(info->version));
- strlcpy(info->fw_version, drvr->fwver, sizeof(info->fw_version));
- strlcpy(info->bus_info, dev_name(drvr->bus_if->dev),
+ strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+ strscpy(info->version, drev, sizeof(info->version));
+ strscpy(info->fw_version, drvr->fwver, sizeof(info->fw_version));
+ strscpy(info->bus_info, dev_name(drvr->bus_if->dev),
sizeof(info->bus_info));
}
@@ -1205,7 +1195,8 @@ static int brcmf_bus_started(struct brcmf_pub *drvr, struct cfg80211_ops *ops)
brcmf_dbg(TRACE, "\n");
/* add primary networking interface */
- ifp = brcmf_add_if(drvr, 0, 0, false, "wlan%d", NULL);
+ ifp = brcmf_add_if(drvr, 0, 0, false, "wlan%d",
+ is_valid_ether_addr(drvr->settings->mac) ? drvr->settings->mac : NULL);
if (IS_ERR(ifp))
return PTR_ERR(ifp);
@@ -1490,8 +1481,10 @@ int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp)
!brcmf_get_pend_8021x_cnt(ifp),
MAX_WAIT_FOR_8021X_TX);
- if (!err)
+ if (!err) {
bphy_err(drvr, "Timed out waiting for no pending 802.1x packets\n");
+ atomic_set(&ifp->pend_8021x_cnt, 0);
+ }
return !err;
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
index 8212c9de14f1..340346c122d3 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
@@ -208,7 +208,7 @@ void brcmf_remove_interface(struct brcmf_if *ifp, bool locked);
void brcmf_txflowblock_if(struct brcmf_if *ifp,
enum brcmf_netif_stop_reason reason, bool state);
void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
-void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb, bool inirq);
+void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb);
void brcmf_net_detach(struct net_device *ndev, bool locked);
int brcmf_net_mon_attach(struct brcmf_if *ifp);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c
index 0af452dca766..86ff174936a9 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c
@@ -24,6 +24,13 @@ static const struct brcmf_dmi_data acepc_t8_data = {
BRCM_CC_4345_CHIP_ID, 6, "acepc-t8"
};
+/* The Chuwi Hi8 Pro uses the same Ampak AP6212 module as the Chuwi Vi8 Plus
+ * and the nvram for the Vi8 Plus is already in linux-firmware, so use that.
+ */
+static const struct brcmf_dmi_data chuwi_hi8_pro_data = {
+ BRCM_CC_43430_CHIP_ID, 0, "ilife-S806"
+};
+
static const struct brcmf_dmi_data gpd_win_pocket_data = {
BRCM_CC_4356_CHIP_ID, 2, "gpd-win-pocket"
};
@@ -76,6 +83,17 @@ static const struct dmi_system_id dmi_platform_data[] = {
.driver_data = (void *)&acepc_t8_data,
},
{
+ /* Chuwi Hi8 Pro with D2D3_Hi8Pro.233 BIOS */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Hampoo"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "MRD"),
+ /* Above strings are too generic, also match on BIOS date */
+ DMI_MATCH(DMI_BIOS_DATE, "05/10/2016"),
+ },
+ .driver_data = (void *)&chuwi_hi8_pro_data,
+ },
+ {
/* Cyberbook T116 rugged tablet */
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Default string"),
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
index 7c68d9849324..2c2f3e026c13 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
@@ -248,7 +248,9 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
brcmf_feat_firmware_capabilities(ifp);
memset(&gscan_cfg, 0, sizeof(gscan_cfg));
if (drvr->bus_if->chip != BRCM_CC_43430_CHIP_ID &&
- drvr->bus_if->chip != BRCM_CC_4345_CHIP_ID)
+ drvr->bus_if->chip != BRCM_CC_4345_CHIP_ID &&
+ drvr->bus_if->chip != BRCM_CC_43454_CHIP_ID &&
+ drvr->bus_if->chip != CY_CC_43439_CHIP_ID)
brcmf_feat_iovar_data_set(ifp, BRCMF_FEAT_GSCAN,
"pfn_gscan_cfg",
&gscan_cfg, sizeof(gscan_cfg));
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
index 0eb13e5df517..f2207793f6e2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
@@ -21,6 +21,8 @@
#define BRCMF_FW_NVRAM_DEVPATH_LEN 19 /* devpath0=pcie/1/4/ */
#define BRCMF_FW_NVRAM_PCIEDEV_LEN 10 /* pcie/1/4/ + \0 */
#define BRCMF_FW_DEFAULT_BOARDREV "boardrev=0xff"
+#define BRCMF_FW_MACADDR_FMT "macaddr=%pM"
+#define BRCMF_FW_MACADDR_LEN (7 + ETH_ALEN * 3)
enum nvram_parser_state {
IDLE,
@@ -44,6 +46,7 @@ enum nvram_parser_state {
* @multi_dev_v1: detect pcie multi device v1 (compressed).
* @multi_dev_v2: detect pcie multi device v2.
* @boardrev_found: nvram contains boardrev information.
+ * @strip_mac: strip the MAC address.
*/
struct nvram_parser {
enum nvram_parser_state state;
@@ -57,6 +60,7 @@ struct nvram_parser {
bool multi_dev_v1;
bool multi_dev_v2;
bool boardrev_found;
+ bool strip_mac;
};
/*
@@ -121,6 +125,10 @@ static enum nvram_parser_state brcmf_nvram_handle_key(struct nvram_parser *nvp)
nvp->multi_dev_v2 = true;
if (strncmp(&nvp->data[nvp->entry], "boardrev", 8) == 0)
nvp->boardrev_found = true;
+ /* strip macaddr if platform MAC overrides */
+ if (nvp->strip_mac &&
+ strncmp(&nvp->data[nvp->entry], "macaddr", 7) == 0)
+ st = COMMENT;
} else if (!is_nvram_char(c) || c == ' ') {
brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n",
nvp->line, nvp->column);
@@ -207,6 +215,9 @@ static int brcmf_init_nvram_parser(struct nvram_parser *nvp,
size = BRCMF_FW_MAX_NVRAM_SIZE;
else
size = data_len;
+ /* Add space for properties we may add */
+ size += strlen(BRCMF_FW_DEFAULT_BOARDREV) + 1;
+ size += BRCMF_FW_MACADDR_LEN + 1;
/* Alloc for extra 0 byte + roundup by 4 + length field */
size += 1 + 3 + sizeof(u32);
nvp->nvram = kzalloc(size, GFP_KERNEL);
@@ -366,22 +377,37 @@ static void brcmf_fw_add_defaults(struct nvram_parser *nvp)
nvp->nvram_len++;
}
+static void brcmf_fw_add_macaddr(struct nvram_parser *nvp, u8 *mac)
+{
+ int len;
+
+ len = scnprintf(&nvp->nvram[nvp->nvram_len], BRCMF_FW_MACADDR_LEN + 1,
+ BRCMF_FW_MACADDR_FMT, mac);
+ WARN_ON(len != BRCMF_FW_MACADDR_LEN);
+ nvp->nvram_len += len + 1;
+}
+
/* brcmf_nvram_strip :Takes a buffer of "<var>=<value>\n" lines read from a fil
* and ending in a NUL. Removes carriage returns, empty lines, comment lines,
* and converts newlines to NULs. Shortens buffer as needed and pads with NULs.
* End of buffer is completed with token identifying length of buffer.
*/
static void *brcmf_fw_nvram_strip(const u8 *data, size_t data_len,
- u32 *new_length, u16 domain_nr, u16 bus_nr)
+ u32 *new_length, u16 domain_nr, u16 bus_nr,
+ struct device *dev)
{
struct nvram_parser nvp;
u32 pad;
u32 token;
__le32 token_le;
+ u8 mac[ETH_ALEN];
if (brcmf_init_nvram_parser(&nvp, data, data_len) < 0)
return NULL;
+ if (eth_platform_get_mac_address(dev, mac) == 0)
+ nvp.strip_mac = true;
+
while (nvp.pos < data_len) {
nvp.state = nv_parser_states[nvp.state](&nvp);
if (nvp.state == END)
@@ -402,6 +428,9 @@ static void *brcmf_fw_nvram_strip(const u8 *data, size_t data_len,
brcmf_fw_add_defaults(&nvp);
+ if (nvp.strip_mac)
+ brcmf_fw_add_macaddr(&nvp, mac);
+
pad = nvp.nvram_len;
*new_length = roundup(nvp.nvram_len + 1, 4);
while (pad != *new_length) {
@@ -428,6 +457,7 @@ struct brcmf_fw {
struct device *dev;
struct brcmf_fw_request *req;
u32 curpos;
+ unsigned int board_index;
void (*done)(struct device *dev, int err, struct brcmf_fw_request *req);
};
@@ -457,43 +487,34 @@ static void brcmf_fw_fix_efi_nvram_ccode(char *data, unsigned long data_len)
static u8 *brcmf_fw_nvram_from_efi(size_t *data_len_ret)
{
- const u16 name[] = { 'n', 'v', 'r', 'a', 'm', 0 };
- struct efivar_entry *nvram_efivar;
+ efi_guid_t guid = EFI_GUID(0x74b00bd9, 0x805a, 0x4d61, 0xb5, 0x1f,
+ 0x43, 0x26, 0x81, 0x23, 0xd1, 0x13);
unsigned long data_len = 0;
+ efi_status_t status;
u8 *data = NULL;
- int err;
- nvram_efivar = kzalloc(sizeof(*nvram_efivar), GFP_KERNEL);
- if (!nvram_efivar)
+ if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
return NULL;
- memcpy(&nvram_efivar->var.VariableName, name, sizeof(name));
- nvram_efivar->var.VendorGuid = EFI_GUID(0x74b00bd9, 0x805a, 0x4d61,
- 0xb5, 0x1f, 0x43, 0x26,
- 0x81, 0x23, 0xd1, 0x13);
-
- err = efivar_entry_size(nvram_efivar, &data_len);
- if (err)
+ status = efi.get_variable(L"nvram", &guid, NULL, &data_len, NULL);
+ if (status != EFI_BUFFER_TOO_SMALL)
goto fail;
data = kmalloc(data_len, GFP_KERNEL);
if (!data)
goto fail;
- err = efivar_entry_get(nvram_efivar, NULL, &data_len, data);
- if (err)
+ status = efi.get_variable(L"nvram", &guid, NULL, &data_len, data);
+ if (status != EFI_SUCCESS)
goto fail;
brcmf_fw_fix_efi_nvram_ccode(data, data_len);
brcmf_info("Using nvram EFI variable\n");
- kfree(nvram_efivar);
*data_len_ret = data_len;
return data;
-
fail:
kfree(data);
- kfree(nvram_efivar);
return NULL;
}
#else
@@ -544,7 +565,8 @@ static int brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
if (data)
nvram = brcmf_fw_nvram_strip(data, data_len, &nvram_length,
fwctx->req->domain_nr,
- fwctx->req->bus_nr);
+ fwctx->req->bus_nr,
+ fwctx->dev);
if (free_bcm47xx_nvram)
bcm47xx_nvram_release_contents(data);
@@ -594,39 +616,50 @@ static int brcmf_fw_complete_request(const struct firmware *fw,
static char *brcm_alt_fw_path(const char *path, const char *board_type)
{
- char alt_path[BRCMF_FW_NAME_LEN];
- char suffix[5];
+ char base[BRCMF_FW_NAME_LEN];
+ const char *suffix;
+ char *ret;
- strscpy(alt_path, path, BRCMF_FW_NAME_LEN);
- /* At least one character + suffix */
- if (strlen(alt_path) < 5)
+ if (!board_type)
return NULL;
- /* strip .txt or .bin at the end */
- strscpy(suffix, alt_path + strlen(alt_path) - 4, 5);
- alt_path[strlen(alt_path) - 4] = 0;
- strlcat(alt_path, ".", BRCMF_FW_NAME_LEN);
- strlcat(alt_path, board_type, BRCMF_FW_NAME_LEN);
- strlcat(alt_path, suffix, BRCMF_FW_NAME_LEN);
+ suffix = strrchr(path, '.');
+ if (!suffix || suffix == path)
+ return NULL;
+
+ /* strip extension at the end */
+ strscpy(base, path, BRCMF_FW_NAME_LEN);
+ base[suffix - path] = 0;
+
+ ret = kasprintf(GFP_KERNEL, "%s.%s%s", base, board_type, suffix);
+ if (!ret)
+ brcmf_err("out of memory allocating firmware path for '%s'\n",
+ path);
- return kstrdup(alt_path, GFP_KERNEL);
+ brcmf_dbg(TRACE, "FW alt path: %s\n", ret);
+
+ return ret;
}
static int brcmf_fw_request_firmware(const struct firmware **fw,
struct brcmf_fw *fwctx)
{
struct brcmf_fw_item *cur = &fwctx->req->items[fwctx->curpos];
+ unsigned int i;
int ret;
- /* Files can be board-specific, first try a board-specific path */
- if (cur->type == BRCMF_FW_TYPE_NVRAM && fwctx->req->board_type) {
+ /* Files can be board-specific, first try board-specific paths */
+ for (i = 0; i < ARRAY_SIZE(fwctx->req->board_types); i++) {
char *alt_path;
- alt_path = brcm_alt_fw_path(cur->path, fwctx->req->board_type);
+ if (!fwctx->req->board_types[i])
+ goto fallback;
+ alt_path = brcm_alt_fw_path(cur->path,
+ fwctx->req->board_types[i]);
if (!alt_path)
goto fallback;
- ret = request_firmware(fw, alt_path, fwctx->dev);
+ ret = firmware_request_nowarn(fw, alt_path, fwctx->dev);
kfree(alt_path);
if (ret == 0)
return ret;
@@ -660,15 +693,40 @@ static void brcmf_fw_request_done_alt_path(const struct firmware *fw, void *ctx)
{
struct brcmf_fw *fwctx = ctx;
struct brcmf_fw_item *first = &fwctx->req->items[0];
+ const char *board_type, *alt_path;
int ret = 0;
- /* Fall back to canonical path if board firmware not found */
- if (!fw)
- ret = request_firmware_nowait(THIS_MODULE, true, first->path,
+ if (fw) {
+ brcmf_fw_request_done(fw, ctx);
+ return;
+ }
+
+ /* Try next board firmware */
+ if (fwctx->board_index < ARRAY_SIZE(fwctx->req->board_types)) {
+ board_type = fwctx->req->board_types[fwctx->board_index++];
+ if (!board_type)
+ goto fallback;
+ alt_path = brcm_alt_fw_path(first->path, board_type);
+ if (!alt_path)
+ goto fallback;
+
+ ret = request_firmware_nowait(THIS_MODULE, true, alt_path,
fwctx->dev, GFP_KERNEL, fwctx,
- brcmf_fw_request_done);
+ brcmf_fw_request_done_alt_path);
+ kfree(alt_path);
+
+ if (ret < 0)
+ brcmf_fw_request_done(fw, ctx);
+ return;
+ }
- if (fw || ret < 0)
+fallback:
+ /* Fall back to canonical path if board firmware not found */
+ ret = request_firmware_nowait(THIS_MODULE, true, first->path,
+ fwctx->dev, GFP_KERNEL, fwctx,
+ brcmf_fw_request_done);
+
+ if (ret < 0)
brcmf_fw_request_done(fw, ctx);
}
@@ -693,7 +751,7 @@ int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req,
{
struct brcmf_fw_item *first = &req->items[0];
struct brcmf_fw *fwctx;
- char *alt_path;
+ char *alt_path = NULL;
int ret;
brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));
@@ -712,8 +770,11 @@ int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req,
fwctx->done = fw_cb;
/* First try alternative board-specific path if any */
- alt_path = brcm_alt_fw_path(first->path, fwctx->req->board_type);
+ if (fwctx->req->board_types[0])
+ alt_path = brcm_alt_fw_path(first->path,
+ fwctx->req->board_types[0]);
if (alt_path) {
+ fwctx->board_index++;
ret = request_firmware_nowait(THIS_MODULE, true, alt_path,
fwctx->dev, GFP_KERNEL, fwctx,
brcmf_fw_request_done_alt_path);
@@ -774,7 +835,7 @@ brcmf_fw_alloc_request(u32 chip, u32 chiprev,
fwnames[j].path[0] = '\0';
/* check if firmware path is provided by module parameter */
if (brcmf_mp_global.firmware_path[0] != '\0') {
- strlcpy(fwnames[j].path, mp_path,
+ strscpy(fwnames[j].path, mp_path,
BRCMF_FW_NAME_LEN);
if (end != '/') {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
index e290dec9c53d..1266cbaee072 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
@@ -11,6 +11,8 @@
#define BRCMF_FW_DEFAULT_PATH "brcm/"
+#define BRCMF_FW_MAX_BOARD_TYPES 8
+
/**
* struct brcmf_firmware_mapping - Used to map chipid/revmask to firmware
* filename and nvram filename. Each bus type implementation should create
@@ -66,7 +68,7 @@ struct brcmf_fw_request {
u16 domain_nr;
u16 bus_nr;
u32 n_items;
- const char *board_type;
+ const char *board_types[BRCMF_FW_MAX_BOARD_TYPES];
struct brcmf_fw_item items[];
};
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
index 096f6b969dd8..e1127d7e086d 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
@@ -419,7 +419,6 @@ void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,
flowid = flow->hash[i].flowid;
if (flow->rings[flowid]->status != RING_OPEN)
continue;
- flow->rings[flowid]->status = RING_CLOSING;
brcmf_msgbuf_delete_flowring(drvr, flowid);
}
}
@@ -458,10 +457,8 @@ void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx,
if ((sta || (memcmp(hash[i].mac, peer, ETH_ALEN) == 0)) &&
(hash[i].ifidx == ifidx)) {
flowid = flow->hash[i].flowid;
- if (flow->rings[flowid]->status == RING_OPEN) {
- flow->rings[flowid]->status = RING_CLOSING;
+ if (flow->rings[flowid]->status == RING_OPEN)
brcmf_msgbuf_delete_flowring(drvr, flowid);
- }
}
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
index bc3f4e4edcdf..dac7eb77799b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
@@ -228,6 +228,10 @@ static void brcmf_fweh_event_worker(struct work_struct *work)
brcmf_fweh_event_name(event->code), event->code,
event->emsg.ifidx, event->emsg.bsscfgidx,
event->emsg.addr);
+ if (event->emsg.bsscfgidx >= BRCMF_MAX_IFS) {
+ bphy_err(drvr, "invalid bsscfg index: %u\n", event->emsg.bsscfgidx);
+ goto event_free;
+ }
/* convert event message */
emsg_be = &event->emsg;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
index d5578ca681bb..72fe8bce6eaf 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
@@ -192,7 +192,7 @@ brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data)
}
static u32
-brcmf_create_iovar(char *name, const char *data, u32 datalen,
+brcmf_create_iovar(const char *name, const char *data, u32 datalen,
char *buf, u32 buflen)
{
u32 len;
@@ -213,7 +213,7 @@ brcmf_create_iovar(char *name, const char *data, u32 datalen,
s32
-brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, const void *data,
+brcmf_fil_iovar_data_set(struct brcmf_if *ifp, const char *name, const void *data,
u32 len)
{
struct brcmf_pub *drvr = ifp->drvr;
@@ -241,7 +241,7 @@ brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, const void *data,
}
s32
-brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data,
+brcmf_fil_iovar_data_get(struct brcmf_if *ifp, const char *name, void *data,
u32 len)
{
struct brcmf_pub *drvr = ifp->drvr;
@@ -272,7 +272,7 @@ brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data,
}
s32
-brcmf_fil_iovar_int_set(struct brcmf_if *ifp, char *name, u32 data)
+brcmf_fil_iovar_int_set(struct brcmf_if *ifp, const char *name, u32 data)
{
__le32 data_le = cpu_to_le32(data);
@@ -280,7 +280,7 @@ brcmf_fil_iovar_int_set(struct brcmf_if *ifp, char *name, u32 data)
}
s32
-brcmf_fil_iovar_int_get(struct brcmf_if *ifp, char *name, u32 *data)
+brcmf_fil_iovar_int_get(struct brcmf_if *ifp, const char *name, u32 *data)
{
__le32 data_le = cpu_to_le32(*data);
s32 err;
@@ -292,7 +292,7 @@ brcmf_fil_iovar_int_get(struct brcmf_if *ifp, char *name, u32 *data)
}
static u32
-brcmf_create_bsscfg(s32 bsscfgidx, char *name, char *data, u32 datalen,
+brcmf_create_bsscfg(s32 bsscfgidx, const char *name, char *data, u32 datalen,
char *buf, u32 buflen)
{
const s8 *prefix = "bsscfg:";
@@ -337,7 +337,7 @@ brcmf_create_bsscfg(s32 bsscfgidx, char *name, char *data, u32 datalen,
}
s32
-brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name,
+brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, const char *name,
void *data, u32 len)
{
struct brcmf_pub *drvr = ifp->drvr;
@@ -366,7 +366,7 @@ brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name,
}
s32
-brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name,
+brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, const char *name,
void *data, u32 len)
{
struct brcmf_pub *drvr = ifp->drvr;
@@ -396,7 +396,7 @@ brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name,
}
s32
-brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, char *name, u32 data)
+brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, const char *name, u32 data)
{
__le32 data_le = cpu_to_le32(data);
@@ -405,7 +405,7 @@ brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, char *name, u32 data)
}
s32
-brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, char *name, u32 *data)
+brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, const char *name, u32 *data)
{
__le32 data_le = cpu_to_le32(*data);
s32 err;
@@ -417,7 +417,7 @@ brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, char *name, u32 *data)
return err;
}
-static u32 brcmf_create_xtlv(char *name, u16 id, char *data, u32 len,
+static u32 brcmf_create_xtlv(const char *name, u16 id, char *data, u32 len,
char *buf, u32 buflen)
{
u32 iolen;
@@ -438,7 +438,7 @@ static u32 brcmf_create_xtlv(char *name, u16 id, char *data, u32 len,
return iolen;
}
-s32 brcmf_fil_xtlv_data_set(struct brcmf_if *ifp, char *name, u16 id,
+s32 brcmf_fil_xtlv_data_set(struct brcmf_if *ifp, const char *name, u16 id,
void *data, u32 len)
{
struct brcmf_pub *drvr = ifp->drvr;
@@ -466,7 +466,7 @@ s32 brcmf_fil_xtlv_data_set(struct brcmf_if *ifp, char *name, u16 id,
return err;
}
-s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, char *name, u16 id,
+s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, const char *name, u16 id,
void *data, u32 len)
{
struct brcmf_pub *drvr = ifp->drvr;
@@ -495,7 +495,7 @@ s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, char *name, u16 id,
return err;
}
-s32 brcmf_fil_xtlv_int_set(struct brcmf_if *ifp, char *name, u16 id, u32 data)
+s32 brcmf_fil_xtlv_int_set(struct brcmf_if *ifp, const char *name, u16 id, u32 data)
{
__le32 data_le = cpu_to_le32(data);
@@ -503,7 +503,7 @@ s32 brcmf_fil_xtlv_int_set(struct brcmf_if *ifp, char *name, u16 id, u32 data)
sizeof(data_le));
}
-s32 brcmf_fil_xtlv_int_get(struct brcmf_if *ifp, char *name, u16 id, u32 *data)
+s32 brcmf_fil_xtlv_int_get(struct brcmf_if *ifp, const char *name, u16 id, u32 *data)
{
__le32 data_le = cpu_to_le32(*data);
s32 err;
@@ -514,12 +514,12 @@ s32 brcmf_fil_xtlv_int_get(struct brcmf_if *ifp, char *name, u16 id, u32 *data)
return err;
}
-s32 brcmf_fil_xtlv_int8_get(struct brcmf_if *ifp, char *name, u16 id, u8 *data)
+s32 brcmf_fil_xtlv_int8_get(struct brcmf_if *ifp, const char *name, u16 id, u8 *data)
{
return brcmf_fil_xtlv_data_get(ifp, name, id, data, sizeof(*data));
}
-s32 brcmf_fil_xtlv_int16_get(struct brcmf_if *ifp, char *name, u16 id, u16 *data)
+s32 brcmf_fil_xtlv_int16_get(struct brcmf_if *ifp, const char *name, u16 id, u16 *data)
{
__le16 data_le = cpu_to_le16(*data);
s32 err;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
index cb26f8c59c21..bc693157c4b1 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
@@ -84,26 +84,26 @@ s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len);
s32 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data);
s32 brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data);
-s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, const void *data,
+s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, const char *name, const void *data,
u32 len);
-s32 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data,
+s32 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, const char *name, void *data,
u32 len);
-s32 brcmf_fil_iovar_int_set(struct brcmf_if *ifp, char *name, u32 data);
-s32 brcmf_fil_iovar_int_get(struct brcmf_if *ifp, char *name, u32 *data);
+s32 brcmf_fil_iovar_int_set(struct brcmf_if *ifp, const char *name, u32 data);
+s32 brcmf_fil_iovar_int_get(struct brcmf_if *ifp, const char *name, u32 *data);
-s32 brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name, void *data,
+s32 brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, const char *name, void *data,
u32 len);
-s32 brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name, void *data,
+s32 brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, const char *name, void *data,
u32 len);
-s32 brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, char *name, u32 data);
-s32 brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, char *name, u32 *data);
-s32 brcmf_fil_xtlv_data_set(struct brcmf_if *ifp, char *name, u16 id,
+s32 brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, const char *name, u32 data);
+s32 brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, const char *name, u32 *data);
+s32 brcmf_fil_xtlv_data_set(struct brcmf_if *ifp, const char *name, u16 id,
void *data, u32 len);
-s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, char *name, u16 id,
+s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, const char *name, u16 id,
void *data, u32 len);
-s32 brcmf_fil_xtlv_int_set(struct brcmf_if *ifp, char *name, u16 id, u32 data);
-s32 brcmf_fil_xtlv_int_get(struct brcmf_if *ifp, char *name, u16 id, u32 *data);
-s32 brcmf_fil_xtlv_int8_get(struct brcmf_if *ifp, char *name, u16 id, u8 *data);
-s32 brcmf_fil_xtlv_int16_get(struct brcmf_if *ifp, char *name, u16 id, u16 *data);
+s32 brcmf_fil_xtlv_int_set(struct brcmf_if *ifp, const char *name, u16 id, u32 data);
+s32 brcmf_fil_xtlv_int_get(struct brcmf_if *ifp, const char *name, u16 id, u32 *data);
+s32 brcmf_fil_xtlv_int8_get(struct brcmf_if *ifp, const char *name, u16 id, u8 *data);
+s32 brcmf_fil_xtlv_int16_get(struct brcmf_if *ifp, const char *name, u16 id, u16 *data);
#endif /* _fwil_h_ */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
index ff2ef557f0ea..f518e025d6e4 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
@@ -135,7 +135,7 @@
/* Link Down indication in WoWL mode: */
#define BRCMF_WOWL_LINKDOWN (1 << 31)
-#define BRCMF_WOWL_MAXPATTERNS 8
+#define BRCMF_WOWL_MAXPATTERNS 16
#define BRCMF_WOWL_MAXPATTERNSIZE 128
#define BRCMF_COUNTRY_BUF_SZ 4
@@ -1052,4 +1052,23 @@ struct brcmf_gscan_config {
struct brcmf_gscan_bucket_config bucket[1];
};
+/**
+ * struct brcmf_mkeep_alive_pkt_le - configuration data for keep-alive frame.
+ *
+ * @version: version for mkeep_alive
+ * @length: length of fixed parameters in the structure.
+ * @period_msec: keep-alive period in milliseconds.
+ * @len_bytes: size of the data.
+ * @keep_alive_id: ID (0 - 3).
+ * @data: keep-alive frame data.
+ */
+struct brcmf_mkeep_alive_pkt_le {
+ __le16 version;
+ __le16 length;
+ __le32 period_msec;
+ __le16 len_bytes;
+ u8 keep_alive_id;
+ u8 data[];
+} __packed;
+
#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 19b0f318f93e..36af81975855 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
@@ -688,7 +688,7 @@ static void brcmf_fws_macdesc_set_name(struct brcmf_fws_info *fws,
struct brcmf_fws_mac_descriptor *desc)
{
if (desc == &fws->desc.other)
- strlcpy(desc->name, "MAC-OTHER", sizeof(desc->name));
+ strscpy(desc->name, "MAC-OTHER", sizeof(desc->name));
else if (desc->mac_handle)
scnprintf(desc->name, sizeof(desc->name), "MAC-%d:%d",
desc->mac_handle, desc->interface_id);
@@ -1664,7 +1664,7 @@ static void brcmf_rxreorder_get_skb_list(struct brcmf_ampdu_rx_reorder *rfi,
rfi->pend_pkts -= skb_queue_len(skb_list);
}
-void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *pkt, bool inirq)
+void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *pkt)
{
struct brcmf_pub *drvr = ifp->drvr;
u8 *reorder_data;
@@ -1682,7 +1682,7 @@ void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *pkt, bool inirq)
/* validate flags and flow id */
if (flags == 0xFF) {
bphy_err(drvr, "invalid flags...so ignore this packet\n");
- brcmf_netif_rx(ifp, pkt, inirq);
+ brcmf_netif_rx(ifp, pkt);
return;
}
@@ -1694,7 +1694,7 @@ void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *pkt, bool inirq)
if (rfi == NULL) {
brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
flow_id);
- brcmf_netif_rx(ifp, pkt, inirq);
+ brcmf_netif_rx(ifp, pkt);
return;
}
@@ -1719,7 +1719,7 @@ void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *pkt, bool inirq)
rfi = kzalloc(buf_size, GFP_ATOMIC);
if (rfi == NULL) {
bphy_err(drvr, "failed to alloc buffer\n");
- brcmf_netif_rx(ifp, pkt, inirq);
+ brcmf_netif_rx(ifp, pkt);
return;
}
@@ -1833,7 +1833,7 @@ void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *pkt, bool inirq)
netif_rx:
skb_queue_walk_safe(&reorder_list, pkt, pnext) {
__skb_unlink(pkt, &reorder_list);
- brcmf_netif_rx(ifp, pkt, inirq);
+ brcmf_netif_rx(ifp, pkt);
}
}
@@ -2475,7 +2475,8 @@ bool brcmf_fws_fc_active(struct brcmf_fws_info *fws)
return fws->fcmode != BRCMF_FWS_FCMODE_NONE;
}
-void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
+void brcmf_fws_bustxcomplete(struct brcmf_fws_info *fws, struct sk_buff *skb,
+ bool success)
{
u32 hslot;
@@ -2483,11 +2484,14 @@ void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
brcmu_pkt_buf_free_skb(skb);
return;
}
- brcmf_fws_lock(fws);
- hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
- brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0, 0,
- 1);
- brcmf_fws_unlock(fws);
+
+ if (!success) {
+ brcmf_fws_lock(fws);
+ hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
+ brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot,
+ 0, 0, 1);
+ brcmf_fws_unlock(fws);
+ }
}
void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
index 50e424b5880d..f9c36cd8f1de 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
@@ -40,8 +40,9 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb);
void brcmf_fws_reset_interface(struct brcmf_if *ifp);
void brcmf_fws_add_interface(struct brcmf_if *ifp);
void brcmf_fws_del_interface(struct brcmf_if *ifp);
-void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb);
+void brcmf_fws_bustxcomplete(struct brcmf_fws_info *fws, struct sk_buff *skb,
+ bool success);
void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked);
-void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb, bool inirq);
+void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb);
#endif /* FWSIGNAL_H_ */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
index 7c8e08ee8f0f..cec53f934940 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
@@ -71,6 +71,7 @@
#define BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS 32
#define BRCMF_MSGBUF_UPDATE_RX_PTR_THRS 48
+#define BRCMF_MAX_TXSTATUS_WAIT_RETRIES 10
struct msgbuf_common_hdr {
u8 msgtype;
@@ -536,8 +537,7 @@ static int brcmf_msgbuf_hdrpull(struct brcmf_pub *drvr, bool do_fws,
return -ENODEV;
}
-static void brcmf_msgbuf_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb,
- bool inirq)
+static void brcmf_msgbuf_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb)
{
}
@@ -807,8 +807,12 @@ static int brcmf_msgbuf_tx_queue_data(struct brcmf_pub *drvr, int ifidx,
flowid = brcmf_flowring_lookup(flow, eh->h_dest, skb->priority, ifidx);
if (flowid == BRCMF_FLOWRING_INVALID_ID) {
flowid = brcmf_msgbuf_flowring_create(msgbuf, ifidx, skb);
- if (flowid == BRCMF_FLOWRING_INVALID_ID)
+ if (flowid == BRCMF_FLOWRING_INVALID_ID) {
return -ENOMEM;
+ } else {
+ brcmf_flowring_enqueue(flow, flowid, skb);
+ return 0;
+ }
}
queue_count = brcmf_flowring_enqueue(flow, flowid, skb);
force = ((queue_count % BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS) == 0);
@@ -1191,7 +1195,7 @@ brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)
}
skb->protocol = eth_type_trans(skb, ifp->ndev);
- brcmf_netif_rx(ifp, skb, false);
+ brcmf_netif_rx(ifp, skb);
}
static void brcmf_msgbuf_process_gen_status(struct brcmf_msgbuf *msgbuf,
@@ -1396,9 +1400,27 @@ void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid)
struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
struct msgbuf_tx_flowring_delete_req *delete;
struct brcmf_commonring *commonring;
+ struct brcmf_commonring *commonring_del = msgbuf->flowrings[flowid];
+ struct brcmf_flowring *flow = msgbuf->flow;
void *ret_ptr;
u8 ifidx;
int err;
+ int retry = BRCMF_MAX_TXSTATUS_WAIT_RETRIES;
+
+ /* make sure it is not in txflow */
+ brcmf_commonring_lock(commonring_del);
+ flow->rings[flowid]->status = RING_CLOSING;
+ brcmf_commonring_unlock(commonring_del);
+
+ /* wait for commonring txflow finished */
+ while (retry && atomic_read(&commonring_del->outstanding_tx)) {
+ usleep_range(5000, 10000);
+ retry--;
+ }
+ if (!retry) {
+ brcmf_err("timed out waiting for txstatus\n");
+ atomic_set(&commonring_del->outstanding_tx, 0);
+ }
/* no need to submit if firmware can not be reached */
if (drvr->bus_if->state != BRCMF_BUS_UP) {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h
index 2e322edbb907..6a849f4a94dd 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h
@@ -8,10 +8,10 @@
#ifdef CONFIG_BRCMFMAC_PROTO_MSGBUF
#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_MAX_ITEM 64
-#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT_MAX_ITEM 512
+#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT_MAX_ITEM 1024
#define BRCMF_D2H_MSGRING_CONTROL_COMPLETE_MAX_ITEM 64
#define BRCMF_D2H_MSGRING_TX_COMPLETE_MAX_ITEM 1024
-#define BRCMF_D2H_MSGRING_RX_COMPLETE_MAX_ITEM 512
+#define BRCMF_D2H_MSGRING_RX_COMPLETE_MAX_ITEM 1024
#define BRCMF_H2D_TXFLOWRING_MAX_ITEM 512
#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_ITEMSIZE 40
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
index 513c7e6421b2..a83699de01ec 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
@@ -5,6 +5,7 @@
#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_irq.h>
+#include <linux/of_net.h>
#include <defs.h>
#include "debug.h"
@@ -23,6 +24,12 @@ static int brcmf_of_get_country_codes(struct device *dev,
count = of_property_count_strings(np, "brcm,ccode-map");
if (count < 0) {
+ /* If no explicit country code map is specified, check whether
+ * the trivial map should be used.
+ */
+ settings->trivial_ccode_map =
+ of_property_read_bool(np, "brcm,ccode-map-trivial");
+
/* The property is optional, so return success if it doesn't
* exist. Otherwise propagate the error code.
*/
@@ -63,28 +70,36 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
{
struct brcmfmac_sdio_pd *sdio = &settings->bus.sdio;
struct device_node *root, *np = dev->of_node;
+ const char *prop;
int irq;
int err;
u32 irqf;
u32 val;
+ /* Apple ARM64 platforms have their own idea of board type, passed in
+ * via the device tree. They also have an antenna SKU parameter
+ */
+ if (!of_property_read_string(np, "brcm,board-type", &prop))
+ settings->board_type = prop;
+
+ if (!of_property_read_string(np, "apple,antenna-sku", &prop))
+ settings->antenna_sku = prop;
+
/* Set board-type to the first string of the machine compatible prop */
root = of_find_node_by_path("/");
- if (root) {
- int i, len;
+ if (root && !settings->board_type) {
char *board_type;
const char *tmp;
of_property_read_string_index(root, "compatible", 0, &tmp);
/* get rid of '/' in the compatible string to be able to find the FW */
- len = strlen(tmp) + 1;
- board_type = devm_kzalloc(dev, len, GFP_KERNEL);
- strscpy(board_type, tmp, len);
- for (i = 0; i < board_type[i]; i++) {
- if (board_type[i] == '/')
- board_type[i] = '-';
+ board_type = devm_kstrdup(dev, tmp, GFP_KERNEL);
+ if (!board_type) {
+ of_node_put(root);
+ return;
}
+ strreplace(board_type, '/', '-');
settings->board_type = board_type;
of_node_put(root);
@@ -97,6 +112,8 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
if (err)
brcmf_err("failed to get OF country code map (err=%d)\n", err);
+ of_get_mac_address(np, settings->mac);
+
if (bus_type != BRCMF_BUSTYPE_SDIO)
return;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
index 4735063e4c03..10d9d9c63b28 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
@@ -90,8 +90,8 @@
#define P2PSD_ACTION_CATEGORY 0x04 /* Public action frame */
#define P2PSD_ACTION_ID_GAS_IREQ 0x0a /* GAS Initial Request AF */
#define P2PSD_ACTION_ID_GAS_IRESP 0x0b /* GAS Initial Response AF */
-#define P2PSD_ACTION_ID_GAS_CREQ 0x0c /* GAS Comback Request AF */
-#define P2PSD_ACTION_ID_GAS_CRESP 0x0d /* GAS Comback Response AF */
+#define P2PSD_ACTION_ID_GAS_CREQ 0x0c /* GAS Comeback Request AF */
+#define P2PSD_ACTION_ID_GAS_CRESP 0x0d /* GAS Comeback Response AF */
#define BRCMF_P2P_DISABLE_TIMEOUT msecs_to_jiffies(500)
@@ -158,7 +158,7 @@ struct brcmf_p2p_pub_act_frame {
u8 oui_type;
u8 subtype;
u8 dialog_token;
- u8 elts[1];
+ u8 elts[];
};
/**
@@ -177,7 +177,7 @@ struct brcmf_p2p_action_frame {
u8 type;
u8 subtype;
u8 dialog_token;
- u8 elts[1];
+ u8 elts[];
};
/**
@@ -192,7 +192,7 @@ struct brcmf_p2psd_gas_pub_act_frame {
u8 category;
u8 action;
u8 dialog_token;
- u8 query_data[1];
+ u8 query_data[];
};
/**
@@ -225,7 +225,7 @@ static bool brcmf_p2p_is_pub_action(void *frame, u32 frame_len)
return false;
pact_frm = (struct brcmf_p2p_pub_act_frame *)frame;
- if (frame_len < sizeof(struct brcmf_p2p_pub_act_frame) - 1)
+ if (frame_len < sizeof(*pact_frm))
return false;
if (pact_frm->category == P2P_PUB_AF_CATEGORY &&
@@ -253,7 +253,7 @@ static bool brcmf_p2p_is_p2p_action(void *frame, u32 frame_len)
return false;
act_frm = (struct brcmf_p2p_action_frame *)frame;
- if (frame_len < sizeof(struct brcmf_p2p_action_frame) - 1)
+ if (frame_len < sizeof(*act_frm))
return false;
if (act_frm->category == P2P_AF_CATEGORY &&
@@ -280,7 +280,7 @@ static bool brcmf_p2p_is_gas_action(void *frame, u32 frame_len)
return false;
sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;
- if (frame_len < sizeof(struct brcmf_p2psd_gas_pub_act_frame) - 1)
+ if (frame_len < sizeof(*sd_act_frm))
return false;
if (sd_act_frm->category != P2PSD_ACTION_CATEGORY)
@@ -396,11 +396,11 @@ static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len)
(tx) ? "TX" : "RX");
break;
case P2PSD_ACTION_ID_GAS_CREQ:
- brcmf_dbg(TRACE, "%s P2P GAS Comback Request\n",
+ brcmf_dbg(TRACE, "%s P2P GAS Comeback Request\n",
(tx) ? "TX" : "RX");
break;
case P2PSD_ACTION_ID_GAS_CRESP:
- brcmf_dbg(TRACE, "%s P2P GAS Comback Response\n",
+ brcmf_dbg(TRACE, "%s P2P GAS Comeback Response\n",
(tx) ? "TX" : "RX");
break;
default:
@@ -1128,7 +1128,7 @@ static void brcmf_p2p_afx_handler(struct work_struct *work)
if (afx_hdl->is_listen && afx_hdl->my_listen_chan)
/* 100ms ~ 300ms */
err = brcmf_p2p_discover_listen(p2p, afx_hdl->my_listen_chan,
- 100 * (1 + prandom_u32() % 3));
+ 100 * (1 + prandom_u32_max(3)));
else
err = brcmf_p2p_act_frm_search(p2p, afx_hdl->peer_listen_chan);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index 8b149996fc00..80083f9ea311 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -12,6 +12,7 @@
#include <linux/interrupt.h>
#include <linux/bcma/bcma.h>
#include <linux/sched.h>
+#include <linux/io.h>
#include <asm/unaligned.h>
#include <soc.h>
@@ -58,6 +59,16 @@ BRCMF_FW_DEF(4365C, "brcmfmac4365c-pcie");
BRCMF_FW_DEF(4366B, "brcmfmac4366b-pcie");
BRCMF_FW_DEF(4366C, "brcmfmac4366c-pcie");
BRCMF_FW_DEF(4371, "brcmfmac4371-pcie");
+BRCMF_FW_CLM_DEF(4378B1, "brcmfmac4378b1-pcie");
+BRCMF_FW_DEF(4355, "brcmfmac89459-pcie");
+
+/* firmware config files */
+MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.txt");
+MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.txt");
+
+/* per-board firmware binaries */
+MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.bin");
+MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.clm_blob");
static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
BRCMF_FW_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602),
@@ -79,6 +90,8 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
BRCMF_FW_ENTRY(BRCM_CC_43664_CHIP_ID, 0xFFFFFFF0, 4366C),
BRCMF_FW_ENTRY(BRCM_CC_43666_CHIP_ID, 0xFFFFFFF0, 4366C),
BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371),
+ BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0xFFFFFFFF, 4378B1), /* revision ID 3 */
+ BRCMF_FW_ENTRY(CY_CC_89459_CHIP_ID, 0xFFFFFFFF, 4355),
};
#define BRCMF_PCIE_FW_UP_TIMEOUT 5000 /* msec */
@@ -110,6 +123,12 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
#define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0 0x140
#define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1 0x144
+#define BRCMF_PCIE_64_PCIE2REG_INTMASK 0xC14
+#define BRCMF_PCIE_64_PCIE2REG_MAILBOXINT 0xC30
+#define BRCMF_PCIE_64_PCIE2REG_MAILBOXMASK 0xC34
+#define BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_0 0xA20
+#define BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_1 0xA24
+
#define BRCMF_PCIE2_INTA 0x01
#define BRCMF_PCIE2_INTB 0x02
@@ -129,6 +148,8 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
#define BRCMF_PCIE_MB_INT_D2H3_DB0 0x400000
#define BRCMF_PCIE_MB_INT_D2H3_DB1 0x800000
+#define BRCMF_PCIE_MB_INT_FN0 (BRCMF_PCIE_MB_INT_FN0_0 | \
+ BRCMF_PCIE_MB_INT_FN0_1)
#define BRCMF_PCIE_MB_INT_D2H_DB (BRCMF_PCIE_MB_INT_D2H0_DB0 | \
BRCMF_PCIE_MB_INT_D2H0_DB1 | \
BRCMF_PCIE_MB_INT_D2H1_DB0 | \
@@ -138,6 +159,40 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
BRCMF_PCIE_MB_INT_D2H3_DB0 | \
BRCMF_PCIE_MB_INT_D2H3_DB1)
+#define BRCMF_PCIE_64_MB_INT_D2H0_DB0 0x1
+#define BRCMF_PCIE_64_MB_INT_D2H0_DB1 0x2
+#define BRCMF_PCIE_64_MB_INT_D2H1_DB0 0x4
+#define BRCMF_PCIE_64_MB_INT_D2H1_DB1 0x8
+#define BRCMF_PCIE_64_MB_INT_D2H2_DB0 0x10
+#define BRCMF_PCIE_64_MB_INT_D2H2_DB1 0x20
+#define BRCMF_PCIE_64_MB_INT_D2H3_DB0 0x40
+#define BRCMF_PCIE_64_MB_INT_D2H3_DB1 0x80
+#define BRCMF_PCIE_64_MB_INT_D2H4_DB0 0x100
+#define BRCMF_PCIE_64_MB_INT_D2H4_DB1 0x200
+#define BRCMF_PCIE_64_MB_INT_D2H5_DB0 0x400
+#define BRCMF_PCIE_64_MB_INT_D2H5_DB1 0x800
+#define BRCMF_PCIE_64_MB_INT_D2H6_DB0 0x1000
+#define BRCMF_PCIE_64_MB_INT_D2H6_DB1 0x2000
+#define BRCMF_PCIE_64_MB_INT_D2H7_DB0 0x4000
+#define BRCMF_PCIE_64_MB_INT_D2H7_DB1 0x8000
+
+#define BRCMF_PCIE_64_MB_INT_D2H_DB (BRCMF_PCIE_64_MB_INT_D2H0_DB0 | \
+ BRCMF_PCIE_64_MB_INT_D2H0_DB1 | \
+ BRCMF_PCIE_64_MB_INT_D2H1_DB0 | \
+ BRCMF_PCIE_64_MB_INT_D2H1_DB1 | \
+ BRCMF_PCIE_64_MB_INT_D2H2_DB0 | \
+ BRCMF_PCIE_64_MB_INT_D2H2_DB1 | \
+ BRCMF_PCIE_64_MB_INT_D2H3_DB0 | \
+ BRCMF_PCIE_64_MB_INT_D2H3_DB1 | \
+ BRCMF_PCIE_64_MB_INT_D2H4_DB0 | \
+ BRCMF_PCIE_64_MB_INT_D2H4_DB1 | \
+ BRCMF_PCIE_64_MB_INT_D2H5_DB0 | \
+ BRCMF_PCIE_64_MB_INT_D2H5_DB1 | \
+ BRCMF_PCIE_64_MB_INT_D2H6_DB0 | \
+ BRCMF_PCIE_64_MB_INT_D2H6_DB1 | \
+ BRCMF_PCIE_64_MB_INT_D2H7_DB0 | \
+ BRCMF_PCIE_64_MB_INT_D2H7_DB1)
+
#define BRCMF_PCIE_SHARED_VERSION_7 7
#define BRCMF_PCIE_MIN_SHARED_VERSION 5
#define BRCMF_PCIE_MAX_SHARED_VERSION BRCMF_PCIE_SHARED_VERSION_7
@@ -247,12 +302,24 @@ struct brcmf_pcie_core_info {
u32 wrapbase;
};
+#define BRCMF_OTP_MAX_PARAM_LEN 16
+
+struct brcmf_otp_params {
+ char module[BRCMF_OTP_MAX_PARAM_LEN];
+ char vendor[BRCMF_OTP_MAX_PARAM_LEN];
+ char version[BRCMF_OTP_MAX_PARAM_LEN];
+ bool valid;
+};
+
struct brcmf_pciedev_info {
enum brcmf_pcie_state state;
bool in_irq;
struct pci_dev *pdev;
char fw_name[BRCMF_FW_NAME_LEN];
char nvram_name[BRCMF_FW_NAME_LEN];
+ char clm_name[BRCMF_FW_NAME_LEN];
+ const struct firmware *clm_fw;
+ const struct brcmf_pcie_reginfo *reginfo;
void __iomem *regs;
void __iomem *tcm;
u32 ram_base;
@@ -272,6 +339,7 @@ struct brcmf_pciedev_info {
void (*write_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
u16 value);
struct brcmf_mp_device *settings;
+ struct brcmf_otp_params otp;
};
struct brcmf_pcie_ringbuf {
@@ -338,11 +406,49 @@ static const u32 brcmf_ring_itemsize[BRCMF_NROF_COMMON_MSGRINGS] = {
BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE
};
+struct brcmf_pcie_reginfo {
+ u32 intmask;
+ u32 mailboxint;
+ u32 mailboxmask;
+ u32 h2d_mailbox_0;
+ u32 h2d_mailbox_1;
+ u32 int_d2h_db;
+ u32 int_fn0;
+};
+
+static const struct brcmf_pcie_reginfo brcmf_reginfo_default = {
+ .intmask = BRCMF_PCIE_PCIE2REG_INTMASK,
+ .mailboxint = BRCMF_PCIE_PCIE2REG_MAILBOXINT,
+ .mailboxmask = BRCMF_PCIE_PCIE2REG_MAILBOXMASK,
+ .h2d_mailbox_0 = BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0,
+ .h2d_mailbox_1 = BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1,
+ .int_d2h_db = BRCMF_PCIE_MB_INT_D2H_DB,
+ .int_fn0 = BRCMF_PCIE_MB_INT_FN0,
+};
+
+static const struct brcmf_pcie_reginfo brcmf_reginfo_64 = {
+ .intmask = BRCMF_PCIE_64_PCIE2REG_INTMASK,
+ .mailboxint = BRCMF_PCIE_64_PCIE2REG_MAILBOXINT,
+ .mailboxmask = BRCMF_PCIE_64_PCIE2REG_MAILBOXMASK,
+ .h2d_mailbox_0 = BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_0,
+ .h2d_mailbox_1 = BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_1,
+ .int_d2h_db = BRCMF_PCIE_64_MB_INT_D2H_DB,
+ .int_fn0 = 0,
+};
+
static void brcmf_pcie_setup(struct device *dev, int ret,
struct brcmf_fw_request *fwreq);
static struct brcmf_fw_request *
brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo);
+static u16
+brcmf_pcie_read_reg16(struct brcmf_pciedev_info *devinfo, u32 reg_offset)
+{
+ void __iomem *address = devinfo->regs + reg_offset;
+
+ return ioread16(address);
+}
+
static u32
brcmf_pcie_read_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset)
{
@@ -448,47 +554,6 @@ brcmf_pcie_write_ram32(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
static void
-brcmf_pcie_copy_mem_todev(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
- void *srcaddr, u32 len)
-{
- void __iomem *address = devinfo->tcm + mem_offset;
- __le32 *src32;
- __le16 *src16;
- u8 *src8;
-
- if (((ulong)address & 4) || ((ulong)srcaddr & 4) || (len & 4)) {
- if (((ulong)address & 2) || ((ulong)srcaddr & 2) || (len & 2)) {
- src8 = (u8 *)srcaddr;
- while (len) {
- iowrite8(*src8, address);
- address++;
- src8++;
- len--;
- }
- } else {
- len = len / 2;
- src16 = (__le16 *)srcaddr;
- while (len) {
- iowrite16(le16_to_cpu(*src16), address);
- address += 2;
- src16++;
- len--;
- }
- }
- } else {
- len = len / 4;
- src32 = (__le32 *)srcaddr;
- while (len) {
- iowrite32(le32_to_cpu(*src32), address);
- address += 4;
- src32++;
- len--;
- }
- }
-}
-
-
-static void
brcmf_pcie_copy_dev_tomem(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
void *dstaddr, u32 len)
{
@@ -529,6 +594,8 @@ brcmf_pcie_copy_dev_tomem(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
}
+#define READCC32(devinfo, reg) brcmf_pcie_read_reg32(devinfo, \
+ CHIPCREGOFFS(reg))
#define WRITECC32(devinfo, reg, value) brcmf_pcie_write_reg32(devinfo, \
CHIPCREGOFFS(reg), value)
@@ -777,6 +844,8 @@ static void brcmf_pcie_bus_console_read(struct brcmf_pciedev_info *devinfo,
return;
console = &devinfo->shared.console;
+ if (!console->base_addr)
+ return;
addr = console->base_addr + BRCMF_CONSOLE_WRITEIDX_OFFSET;
newidx = brcmf_pcie_read_tcm32(devinfo, addr);
while (newidx != console->read_idx) {
@@ -810,30 +879,29 @@ static void brcmf_pcie_bus_console_read(struct brcmf_pciedev_info *devinfo,
static void brcmf_pcie_intr_disable(struct brcmf_pciedev_info *devinfo)
{
- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, 0);
+ brcmf_pcie_write_reg32(devinfo, devinfo->reginfo->mailboxmask, 0);
}
static void brcmf_pcie_intr_enable(struct brcmf_pciedev_info *devinfo)
{
- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK,
- BRCMF_PCIE_MB_INT_D2H_DB |
- BRCMF_PCIE_MB_INT_FN0_0 |
- BRCMF_PCIE_MB_INT_FN0_1);
+ brcmf_pcie_write_reg32(devinfo, devinfo->reginfo->mailboxmask,
+ devinfo->reginfo->int_d2h_db |
+ devinfo->reginfo->int_fn0);
}
static void brcmf_pcie_hostready(struct brcmf_pciedev_info *devinfo)
{
if (devinfo->shared.flags & BRCMF_PCIE_SHARED_HOSTRDY_DB1)
brcmf_pcie_write_reg32(devinfo,
- BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1, 1);
+ devinfo->reginfo->h2d_mailbox_1, 1);
}
static irqreturn_t brcmf_pcie_quick_check_isr(int irq, void *arg)
{
struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg;
- if (brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT)) {
+ if (brcmf_pcie_read_reg32(devinfo, devinfo->reginfo->mailboxint)) {
brcmf_pcie_intr_disable(devinfo);
brcmf_dbg(PCIE, "Enter\n");
return IRQ_WAKE_THREAD;
@@ -848,15 +916,14 @@ static irqreturn_t brcmf_pcie_isr_thread(int irq, void *arg)
u32 status;
devinfo->in_irq = true;
- status = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT);
+ status = brcmf_pcie_read_reg32(devinfo, devinfo->reginfo->mailboxint);
brcmf_dbg(PCIE, "Enter %x\n", status);
if (status) {
- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT,
+ brcmf_pcie_write_reg32(devinfo, devinfo->reginfo->mailboxint,
status);
- if (status & (BRCMF_PCIE_MB_INT_FN0_0 |
- BRCMF_PCIE_MB_INT_FN0_1))
+ if (status & devinfo->reginfo->int_fn0)
brcmf_pcie_handle_mb_data(devinfo);
- if (status & BRCMF_PCIE_MB_INT_D2H_DB) {
+ if (status & devinfo->reginfo->int_d2h_db) {
if (devinfo->state == BRCMFMAC_PCIE_STATE_UP)
brcmf_proto_msgbuf_rx_trigger(
&devinfo->pdev->dev);
@@ -915,8 +982,8 @@ static void brcmf_pcie_release_irq(struct brcmf_pciedev_info *devinfo)
if (devinfo->in_irq)
brcmf_err(bus, "Still in IRQ (processing) !!!\n");
- status = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT);
- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, status);
+ status = brcmf_pcie_read_reg32(devinfo, devinfo->reginfo->mailboxint);
+ brcmf_pcie_write_reg32(devinfo, devinfo->reginfo->mailboxint, status);
devinfo->irq_allocated = false;
}
@@ -968,7 +1035,7 @@ static int brcmf_pcie_ring_mb_ring_bell(void *ctx)
brcmf_dbg(PCIE, "RING !\n");
/* Any arbitrary value will do, lets use 1 */
- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0, 1);
+ brcmf_pcie_write_reg32(devinfo, devinfo->reginfo->h2d_mailbox_0, 1);
return 0;
}
@@ -1348,6 +1415,18 @@ static void brcmf_pcie_down(struct device *dev)
{
}
+static int brcmf_pcie_preinit(struct device *dev)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
+
+ brcmf_dbg(PCIE, "Enter\n");
+
+ brcmf_pcie_intr_enable(buspub->devinfo);
+ brcmf_pcie_hostready(buspub->devinfo);
+
+ return 0;
+}
static int brcmf_pcie_tx(struct device *dev, struct sk_buff *skb)
{
@@ -1401,23 +1480,25 @@ static int brcmf_pcie_get_memdump(struct device *dev, void *data, size_t len)
return 0;
}
-static
-int brcmf_pcie_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
+static int brcmf_pcie_get_blob(struct device *dev, const struct firmware **fw,
+ enum brcmf_blob_type type)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_fw_request *fwreq;
- struct brcmf_fw_name fwnames[] = {
- { ext, fw_name },
- };
+ struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
+ struct brcmf_pciedev_info *devinfo = buspub->devinfo;
- fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev,
- brcmf_pcie_fwnames,
- ARRAY_SIZE(brcmf_pcie_fwnames),
- fwnames, ARRAY_SIZE(fwnames));
- if (!fwreq)
- return -ENOMEM;
+ switch (type) {
+ case BRCMF_BLOB_CLM:
+ *fw = devinfo->clm_fw;
+ devinfo->clm_fw = NULL;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ if (!*fw)
+ return -ENOENT;
- kfree(fwreq);
return 0;
}
@@ -1456,6 +1537,7 @@ static int brcmf_pcie_reset(struct device *dev)
}
static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
+ .preinit = brcmf_pcie_preinit,
.txdata = brcmf_pcie_tx,
.stop = brcmf_pcie_down,
.txctl = brcmf_pcie_tx_ctlpkt,
@@ -1463,7 +1545,7 @@ static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
.wowl_config = brcmf_pcie_wowl_config,
.get_ramsize = brcmf_pcie_get_ramsize,
.get_memdump = brcmf_pcie_get_memdump,
- .get_fwname = brcmf_pcie_get_fwname,
+ .get_blob = brcmf_pcie_get_blob,
.reset = brcmf_pcie_reset,
};
@@ -1540,6 +1622,7 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo,
shared->max_rxbufpost, shared->rx_dataoffset);
brcmf_pcie_bus_console_init(devinfo);
+ brcmf_pcie_bus_console_read(devinfo, false);
return 0;
}
@@ -1563,8 +1646,8 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
return err;
brcmf_dbg(PCIE, "Download FW %s\n", devinfo->fw_name);
- brcmf_pcie_copy_mem_todev(devinfo, devinfo->ci->rambase,
- (void *)fw->data, fw->size);
+ memcpy_toio(devinfo->tcm + devinfo->ci->rambase,
+ (void *)fw->data, fw->size);
resetintr = get_unaligned_le32(fw->data);
release_firmware(fw);
@@ -1578,7 +1661,7 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
brcmf_dbg(PCIE, "Download NVRAM %s\n", devinfo->nvram_name);
address = devinfo->ci->rambase + devinfo->ci->ramsize -
nvram_len;
- brcmf_pcie_copy_mem_todev(devinfo, address, nvram, nvram_len);
+ memcpy_toio(devinfo->tcm + address, nvram, nvram_len);
brcmf_fw_nvram_free(nvram);
} else {
brcmf_dbg(PCIE, "No matching NVRAM file found %s\n",
@@ -1715,15 +1798,22 @@ static int brcmf_pcie_buscoreprep(void *ctx)
static int brcmf_pcie_buscore_reset(void *ctx, struct brcmf_chip *chip)
{
struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx;
- u32 val;
+ struct brcmf_core *core;
+ u32 val, reg;
devinfo->ci = chip;
brcmf_pcie_reset_device(devinfo);
- val = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT);
+ /* reginfo is not ready yet */
+ core = brcmf_chip_get_core(chip, BCMA_CORE_PCIE2);
+ if (core->rev >= 64)
+ reg = BRCMF_PCIE_64_PCIE2REG_MAILBOXINT;
+ else
+ reg = BRCMF_PCIE_PCIE2REG_MAILBOXINT;
+
+ val = brcmf_pcie_read_reg32(devinfo, reg);
if (val != 0xffffffff)
- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT,
- val);
+ brcmf_pcie_write_reg32(devinfo, reg, val);
return 0;
}
@@ -1746,8 +1836,206 @@ static const struct brcmf_buscore_ops brcmf_pcie_buscore_ops = {
.write32 = brcmf_pcie_buscore_write32,
};
+#define BRCMF_OTP_SYS_VENDOR 0x15
+#define BRCMF_OTP_BRCM_CIS 0x80
+
+#define BRCMF_OTP_VENDOR_HDR 0x00000008
+
+static int
+brcmf_pcie_parse_otp_sys_vendor(struct brcmf_pciedev_info *devinfo,
+ u8 *data, size_t size)
+{
+ int idx = 4;
+ const char *chip_params;
+ const char *board_params;
+ const char *p;
+
+ /* 4-byte header and two empty strings */
+ if (size < 6)
+ return -EINVAL;
+
+ if (get_unaligned_le32(data) != BRCMF_OTP_VENDOR_HDR)
+ return -EINVAL;
+
+ chip_params = &data[idx];
+
+ /* Skip first string, including terminator */
+ idx += strnlen(chip_params, size - idx) + 1;
+ if (idx >= size)
+ return -EINVAL;
+
+ board_params = &data[idx];
+
+ /* Skip to terminator of second string */
+ idx += strnlen(board_params, size - idx);
+ if (idx >= size)
+ return -EINVAL;
+
+ /* At this point both strings are guaranteed NUL-terminated */
+ brcmf_dbg(PCIE, "OTP: chip_params='%s' board_params='%s'\n",
+ chip_params, board_params);
+
+ p = skip_spaces(board_params);
+ while (*p) {
+ char tag = *p++;
+ const char *end;
+ size_t len;
+
+ if (*p++ != '=') /* implicit NUL check */
+ return -EINVAL;
+
+ /* *p might be NUL here, if so end == p and len == 0 */
+ end = strchrnul(p, ' ');
+ len = end - p;
+
+ /* leave 1 byte for NUL in destination string */
+ if (len > (BRCMF_OTP_MAX_PARAM_LEN - 1))
+ return -EINVAL;
+
+ /* Copy len characters plus a NUL terminator */
+ switch (tag) {
+ case 'M':
+ strscpy(devinfo->otp.module, p, len + 1);
+ break;
+ case 'V':
+ strscpy(devinfo->otp.vendor, p, len + 1);
+ break;
+ case 'm':
+ strscpy(devinfo->otp.version, p, len + 1);
+ break;
+ }
+
+ /* Skip to next arg, if any */
+ p = skip_spaces(end);
+ }
+
+ brcmf_dbg(PCIE, "OTP: module=%s vendor=%s version=%s\n",
+ devinfo->otp.module, devinfo->otp.vendor,
+ devinfo->otp.version);
+
+ if (!devinfo->otp.module[0] ||
+ !devinfo->otp.vendor[0] ||
+ !devinfo->otp.version[0])
+ return -EINVAL;
+
+ devinfo->otp.valid = true;
+ return 0;
+}
+
+static int
+brcmf_pcie_parse_otp(struct brcmf_pciedev_info *devinfo, u8 *otp, size_t size)
+{
+ int p = 0;
+ int ret = -EINVAL;
+
+ brcmf_dbg(PCIE, "parse_otp size=%zd\n", size);
+
+ while (p < (size - 1)) {
+ u8 type = otp[p];
+ u8 length = otp[p + 1];
+
+ if (type == 0)
+ break;
+
+ if ((p + 2 + length) > size)
+ break;
+
+ switch (type) {
+ case BRCMF_OTP_SYS_VENDOR:
+ brcmf_dbg(PCIE, "OTP @ 0x%x (%d): SYS_VENDOR\n",
+ p, length);
+ ret = brcmf_pcie_parse_otp_sys_vendor(devinfo,
+ &otp[p + 2],
+ length);
+ break;
+ case BRCMF_OTP_BRCM_CIS:
+ brcmf_dbg(PCIE, "OTP @ 0x%x (%d): BRCM_CIS\n",
+ p, length);
+ break;
+ default:
+ brcmf_dbg(PCIE, "OTP @ 0x%x (%d): Unknown type 0x%x\n",
+ p, length, type);
+ break;
+ }
+
+ p += 2 + length;
+ }
+
+ return ret;
+}
+
+static int brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo)
+{
+ const struct pci_dev *pdev = devinfo->pdev;
+ struct brcmf_bus *bus = dev_get_drvdata(&pdev->dev);
+ u32 coreid, base, words, idx, sromctl;
+ u16 *otp;
+ struct brcmf_core *core;
+ int ret;
+
+ switch (devinfo->ci->chip) {
+ case BRCM_CC_4378_CHIP_ID:
+ coreid = BCMA_CORE_GCI;
+ base = 0x1120;
+ words = 0x170;
+ break;
+ default:
+ /* OTP not supported on this chip */
+ return 0;
+ }
+
+ core = brcmf_chip_get_core(devinfo->ci, coreid);
+ if (!core) {
+ brcmf_err(bus, "No OTP core\n");
+ return -ENODEV;
+ }
+
+ if (coreid == BCMA_CORE_CHIPCOMMON) {
+ /* Chips with OTP accessed via ChipCommon need additional
+ * handling to access the OTP
+ */
+ brcmf_pcie_select_core(devinfo, coreid);
+ sromctl = READCC32(devinfo, sromcontrol);
+
+ if (!(sromctl & BCMA_CC_SROM_CONTROL_OTP_PRESENT)) {
+ /* Chip lacks OTP, try without it... */
+ brcmf_err(bus,
+ "OTP unavailable, using default firmware\n");
+ return 0;
+ }
+
+ /* Map OTP to shadow area */
+ WRITECC32(devinfo, sromcontrol,
+ sromctl | BCMA_CC_SROM_CONTROL_OTPSEL);
+ }
+
+ otp = kcalloc(words, sizeof(u16), GFP_KERNEL);
+ if (!otp)
+ return -ENOMEM;
+
+ /* Map bus window to SROM/OTP shadow area in core */
+ base = brcmf_pcie_buscore_prep_addr(devinfo->pdev, base + core->base);
+
+ brcmf_dbg(PCIE, "OTP data:\n");
+ for (idx = 0; idx < words; idx++) {
+ otp[idx] = brcmf_pcie_read_reg16(devinfo, base + 2 * idx);
+ brcmf_dbg(PCIE, "[%8x] 0x%04x\n", base + 2 * idx, otp[idx]);
+ }
+
+ if (coreid == BCMA_CORE_CHIPCOMMON) {
+ brcmf_pcie_select_core(devinfo, coreid);
+ WRITECC32(devinfo, sromcontrol, sromctl);
+ }
+
+ ret = brcmf_pcie_parse_otp(devinfo, (u8 *)otp, 2 * words);
+ kfree(otp);
+
+ return ret;
+}
+
#define BRCMF_PCIE_FW_CODE 0
#define BRCMF_PCIE_FW_NVRAM 1
+#define BRCMF_PCIE_FW_CLM 2
static void brcmf_pcie_setup(struct device *dev, int ret,
struct brcmf_fw_request *fwreq)
@@ -1772,11 +2060,14 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
fw = fwreq->items[BRCMF_PCIE_FW_CODE].binary;
nvram = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.data;
nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len;
+ devinfo->clm_fw = fwreq->items[BRCMF_PCIE_FW_CLM].binary;
kfree(fwreq);
ret = brcmf_chip_get_raminfo(devinfo->ci);
if (ret) {
brcmf_err(bus, "Failed to get RAM info\n");
+ release_firmware(fw);
+ brcmf_fw_nvram_free(nvram);
goto fail;
}
@@ -1826,9 +2117,6 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
init_waitqueue_head(&devinfo->mbdata_resp_wait);
- brcmf_pcie_intr_enable(devinfo);
- brcmf_pcie_hostready(devinfo);
-
ret = brcmf_attach(&devinfo->pdev->dev);
if (ret)
goto fail;
@@ -1848,6 +2136,7 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
struct brcmf_fw_name fwnames[] = {
{ ".bin", devinfo->fw_name },
{ ".txt", devinfo->nvram_name },
+ { ".clm_blob", devinfo->clm_name },
};
fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev,
@@ -1860,11 +2149,51 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
fwreq->items[BRCMF_PCIE_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL;
- fwreq->board_type = devinfo->settings->board_type;
+ fwreq->items[BRCMF_PCIE_FW_CLM].type = BRCMF_FW_TYPE_BINARY;
+ fwreq->items[BRCMF_PCIE_FW_CLM].flags = BRCMF_FW_REQF_OPTIONAL;
/* NVRAM reserves PCI domain 0 for Broadcom's SDK faked bus */
fwreq->domain_nr = pci_domain_nr(devinfo->pdev->bus) + 1;
fwreq->bus_nr = devinfo->pdev->bus->number;
+ /* Apple platforms with fancy firmware/NVRAM selection */
+ if (devinfo->settings->board_type &&
+ devinfo->settings->antenna_sku &&
+ devinfo->otp.valid) {
+ const struct brcmf_otp_params *otp = &devinfo->otp;
+ struct device *dev = &devinfo->pdev->dev;
+ const char **bt = fwreq->board_types;
+
+ brcmf_dbg(PCIE, "Apple board: %s\n",
+ devinfo->settings->board_type);
+
+ /* Example: apple,shikoku-RASP-m-6.11-X3 */
+ bt[0] = devm_kasprintf(dev, GFP_KERNEL, "%s-%s-%s-%s-%s",
+ devinfo->settings->board_type,
+ otp->module, otp->vendor, otp->version,
+ devinfo->settings->antenna_sku);
+ bt[1] = devm_kasprintf(dev, GFP_KERNEL, "%s-%s-%s-%s",
+ devinfo->settings->board_type,
+ otp->module, otp->vendor, otp->version);
+ bt[2] = devm_kasprintf(dev, GFP_KERNEL, "%s-%s-%s",
+ devinfo->settings->board_type,
+ otp->module, otp->vendor);
+ bt[3] = devm_kasprintf(dev, GFP_KERNEL, "%s-%s",
+ devinfo->settings->board_type,
+ otp->module);
+ bt[4] = devm_kasprintf(dev, GFP_KERNEL, "%s-%s",
+ devinfo->settings->board_type,
+ devinfo->settings->antenna_sku);
+ bt[5] = devinfo->settings->board_type;
+
+ if (!bt[0] || !bt[1] || !bt[2] || !bt[3] || !bt[4]) {
+ kfree(fwreq);
+ return NULL;
+ }
+ } else {
+ brcmf_dbg(PCIE, "Board: %s\n", devinfo->settings->board_type);
+ fwreq->board_types[0] = devinfo->settings->board_type;
+ }
+
return fwreq;
}
@@ -1875,6 +2204,7 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
struct brcmf_fw_request *fwreq;
struct brcmf_pciedev_info *devinfo;
struct brcmf_pciedev *pcie_bus_dev;
+ struct brcmf_core *core;
struct brcmf_bus *bus;
brcmf_dbg(PCIE, "Enter %x:%x\n", pdev->vendor, pdev->device);
@@ -1894,6 +2224,12 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto fail;
}
+ core = brcmf_chip_get_core(devinfo->ci, BCMA_CORE_PCIE2);
+ if (core->rev >= 64)
+ devinfo->reginfo = &brcmf_reginfo_64;
+ else
+ devinfo->reginfo = &brcmf_reginfo_default;
+
pcie_bus_dev = kzalloc(sizeof(*pcie_bus_dev), GFP_KERNEL);
if (pcie_bus_dev == NULL) {
ret = -ENOMEM;
@@ -1936,6 +2272,12 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret)
goto fail_bus;
+ ret = brcmf_pcie_read_otp(devinfo);
+ if (ret) {
+ brcmf_err(bus, "failed to parse OTP\n");
+ goto fail_brcmf;
+ }
+
fwreq = brcmf_pcie_prepare_fw_request(devinfo);
if (!fwreq) {
ret = -ENOMEM;
@@ -1980,6 +2322,7 @@ brcmf_pcie_remove(struct pci_dev *pdev)
return;
devinfo = bus->bus_priv.pcie->devinfo;
+ brcmf_pcie_bus_console_read(devinfo, false);
devinfo->state = BRCMFMAC_PCIE_STATE_DOWN;
if (devinfo->ci)
@@ -1998,6 +2341,7 @@ brcmf_pcie_remove(struct pci_dev *pdev)
brcmf_pcie_release_ringbuffers(devinfo);
brcmf_pcie_reset_device(devinfo);
brcmf_pcie_release_resource(devinfo);
+ release_firmware(devinfo->clm_fw);
if (devinfo->ci)
brcmf_chip_detach(devinfo->ci);
@@ -2055,7 +2399,7 @@ static int brcmf_pcie_pm_leave_D3(struct device *dev)
brcmf_dbg(PCIE, "Enter, dev=%p, bus=%p\n", dev, bus);
/* Check if device is still up and running, if so we are ready */
- if (brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_INTMASK) != 0) {
+ if (brcmf_pcie_read_reg32(devinfo, devinfo->reginfo->intmask) != 0) {
brcmf_dbg(PCIE, "Try to wakeup device....\n");
if (brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_D0_INFORM))
goto cleanup;
@@ -2106,6 +2450,7 @@ static const struct pci_device_id brcmf_pcie_devid_table[] = {
BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_RAW_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4358_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4359_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_DEVICE_ID),
@@ -2121,6 +2466,9 @@ static const struct pci_device_id brcmf_pcie_devid_table[] = {
BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_2G_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4371_DEVICE_ID),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID),
+ BRCMF_PCIE_DEVICE(CY_PCIE_89459_DEVICE_ID),
+ BRCMF_PCIE_DEVICE(CY_PCIE_89459_RAW_DEVICE_ID),
{ /* end: all zeroes */ }
};
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
index fabfbb0b40b0..170c61c8136c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
@@ -158,12 +158,12 @@ 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;
+ int err, i, ri;
- 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;
+ for (ri = 0; ri < pi->n_reqs; ri++)
+ if (pi->reqs[ri]->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
+ mac_addr = pi->reqs[ri]->mac_addr;
+ mac_mask = pi->reqs[ri]->mac_addr_mask;
break;
}
@@ -177,7 +177,7 @@ static int brcmf_pno_set_random(struct brcmf_if *ifp, struct brcmf_pno_info *pi)
memcpy(pfn_mac.mac, mac_addr, ETH_ALEN);
for (i = 0; i < ETH_ALEN; i++) {
pfn_mac.mac[i] &= mac_mask[i];
- pfn_mac.mac[i] |= get_random_int() & ~(mac_mask[i]);
+ pfn_mac.mac[i] |= get_random_u8() & ~(mac_mask[i]);
}
/* Clear multi bit */
pfn_mac.mac[0] &= 0xFE;
@@ -185,7 +185,7 @@ static int brcmf_pno_set_random(struct brcmf_if *ifp, struct brcmf_pno_info *pi)
pfn_mac.mac[0] |= 0x02;
brcmf_dbg(SCAN, "enabling random mac: reqid=%llu mac=%pM\n",
- pi->reqs[i]->reqid, pfn_mac.mac);
+ pi->reqs[ri]->reqid, pfn_mac.mac);
err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac,
sizeof(pfn_mac));
if (err)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
index f4a79e217da5..bd08d3aaa8f4 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
@@ -32,7 +32,7 @@ struct brcmf_proto {
u8 peer[ETH_ALEN]);
void (*add_tdls_peer)(struct brcmf_pub *drvr, int ifidx,
u8 peer[ETH_ALEN]);
- void (*rxreorder)(struct brcmf_if *ifp, struct sk_buff *skb, bool inirq);
+ 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);
@@ -109,9 +109,9 @@ static inline bool brcmf_proto_is_reorder_skb(struct sk_buff *skb)
}
static inline void
-brcmf_proto_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb, bool inirq)
+brcmf_proto_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb)
{
- ifp->drvr->proto->rxreorder(ifp, skb, inirq);
+ ifp->drvr->proto->rxreorder(ifp, skb);
}
static inline void
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index 8effeb7a7269..465d95d83759 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -557,7 +557,7 @@ enum brcmf_sdio_frmtype {
BRCMF_SDIO_FT_SUB,
};
-#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
+#define SDIOD_DRVSTR_KEY(chip, pmu) (((unsigned int)(chip) << 16) | (pmu))
/* SDIO Pad drive strength to select value mappings */
struct sdiod_drive_str {
@@ -618,6 +618,7 @@ BRCMF_FW_DEF(43430A0, "brcmfmac43430a0-sdio");
/* Note the names are not postfixed with a1 for backward compatibility */
BRCMF_FW_CLM_DEF(43430A1, "brcmfmac43430-sdio");
BRCMF_FW_DEF(43430B0, "brcmfmac43430b0-sdio");
+BRCMF_FW_CLM_DEF(43439, "brcmfmac43439-sdio");
BRCMF_FW_CLM_DEF(43455, "brcmfmac43455-sdio");
BRCMF_FW_DEF(43456, "brcmfmac43456-sdio");
BRCMF_FW_CLM_DEF(4354, "brcmfmac4354-sdio");
@@ -629,7 +630,6 @@ BRCMF_FW_CLM_DEF(43752, "brcmfmac43752-sdio");
/* firmware config files */
MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-sdio.*.txt");
-MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.txt");
/* per-board firmware binaries */
MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-sdio.*.bin");
@@ -652,11 +652,13 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFC, 43430B0),
BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0x00000200, 43456),
BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFDC0, 43455),
+ BRCMF_FW_ENTRY(BRCM_CC_43454_CHIP_ID, 0x00000040, 43455),
BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354),
BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356),
BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359),
BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373),
BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012),
+ BRCMF_FW_ENTRY(CY_CC_43439_CHIP_ID, 0xFFFFFFFF, 43439),
BRCMF_FW_ENTRY(CY_CC_43752_CHIP_ID, 0xFFFFFFFF, 43752)
};
@@ -1617,7 +1619,7 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
/* Do an SDIO read for the superframe. Configurable iovar to
* read directly into the chained packet, or allocate a large
- * packet and and copy into the chain.
+ * packet and copy into the chain.
*/
sdio_claim_host(bus->sdiodev->func1);
errcode = brcmf_sdiod_recv_chain(bus->sdiodev,
@@ -4020,15 +4022,14 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
*/
brcmf_sdiod_sgtable_alloc(sdiodev);
-#ifdef CONFIG_PM_SLEEP
/* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ
* is true or when platform data OOB irq is true).
*/
- if ((sdio_get_host_pm_caps(sdiodev->func1) & MMC_PM_KEEP_POWER) &&
+ if (IS_ENABLED(CONFIG_PM_SLEEP) &&
+ (sdio_get_host_pm_caps(sdiodev->func1) & MMC_PM_KEEP_POWER) &&
((sdio_get_host_pm_caps(sdiodev->func1) & MMC_PM_WAKE_SDIO_IRQ) ||
(sdiodev->settings->bus.sdio.oob_irq_supported)))
sdiodev->bus_if->wowl_supported = true;
-#endif
if (brcmf_sdio_kso_init(bus)) {
brcmf_err("error enabling KSO\n");
@@ -4130,29 +4131,29 @@ brcmf_sdio_watchdog(struct timer_list *t)
}
}
-static
-int brcmf_sdio_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
+static int brcmf_sdio_get_blob(struct device *dev, const struct firmware **fw,
+ enum brcmf_blob_type type)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_fw_request *fwreq;
- struct brcmf_fw_name fwnames[] = {
- { ext, fw_name },
- };
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
- fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev,
- brcmf_sdio_fwnames,
- ARRAY_SIZE(brcmf_sdio_fwnames),
- fwnames, ARRAY_SIZE(fwnames));
- if (!fwreq)
- return -ENOMEM;
+ switch (type) {
+ case BRCMF_BLOB_CLM:
+ *fw = sdiodev->clm_fw;
+ sdiodev->clm_fw = NULL;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ if (!*fw)
+ return -ENOENT;
- kfree(fwreq);
return 0;
}
static int brcmf_sdio_bus_reset(struct device *dev)
{
- int ret = 0;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
@@ -4165,18 +4166,11 @@ static int brcmf_sdio_bus_reset(struct device *dev)
/* reset the adapter */
sdio_claim_host(sdiodev->func1);
- mmc_hw_reset(sdiodev->func1->card->host);
+ mmc_hw_reset(sdiodev->func1->card);
sdio_release_host(sdiodev->func1);
brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_DOWN);
-
- ret = brcmf_sdiod_probe(sdiodev);
- if (ret) {
- brcmf_err("Failed to probe after sdio device reset: ret %d\n",
- ret);
- }
-
- return ret;
+ return 0;
}
static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
@@ -4189,13 +4183,14 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
.wowl_config = brcmf_sdio_wowl_config,
.get_ramsize = brcmf_sdio_bus_get_ramsize,
.get_memdump = brcmf_sdio_bus_get_memdump,
- .get_fwname = brcmf_sdio_get_fwname,
+ .get_blob = brcmf_sdio_get_blob,
.debugfs_create = brcmf_sdio_debugfs_create,
.reset = brcmf_sdio_bus_reset
};
#define BRCMF_SDIO_FW_CODE 0
#define BRCMF_SDIO_FW_NVRAM 1
+#define BRCMF_SDIO_FW_CLM 2
static void brcmf_sdio_firmware_callback(struct device *dev, int err,
struct brcmf_fw_request *fwreq)
@@ -4218,6 +4213,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
code = fwreq->items[BRCMF_SDIO_FW_CODE].binary;
nvram = fwreq->items[BRCMF_SDIO_FW_NVRAM].nv_data.data;
nvram_len = fwreq->items[BRCMF_SDIO_FW_NVRAM].nv_data.len;
+ sdiod->clm_fw = fwreq->items[BRCMF_SDIO_FW_CLM].binary;
kfree(fwreq);
/* try to download image and nvram to the dongle */
@@ -4416,6 +4412,7 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus)
struct brcmf_fw_name fwnames[] = {
{ ".bin", bus->sdiodev->fw_name },
{ ".txt", bus->sdiodev->nvram_name },
+ { ".clm_blob", bus->sdiodev->clm_name },
};
fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev,
@@ -4427,7 +4424,9 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus)
fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
fwreq->items[BRCMF_SDIO_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
- fwreq->board_type = bus->sdiodev->settings->board_type;
+ fwreq->items[BRCMF_SDIO_FW_CLM].type = BRCMF_FW_TYPE_BINARY;
+ fwreq->items[BRCMF_SDIO_FW_CLM].flags = BRCMF_FW_REQF_OPTIONAL;
+ fwreq->board_types[0] = bus->sdiodev->settings->board_type;
return fwreq;
}
@@ -4583,6 +4582,8 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
if (bus->sdiodev->settings)
brcmf_release_module_param(bus->sdiodev->settings);
+ release_firmware(bus->sdiodev->clm_fw);
+ bus->sdiodev->clm_fw = NULL;
kfree(bus->rxbuf);
kfree(bus->hdrbuf);
kfree(bus);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
index 15d2c02fa3ec..b76d34d36bde 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
@@ -186,9 +186,11 @@ struct brcmf_sdio_dev {
struct sg_table sgtable;
char fw_name[BRCMF_FW_NAME_LEN];
char nvram_name[BRCMF_FW_NAME_LEN];
+ char clm_name[BRCMF_FW_NAME_LEN];
bool wowl_enabled;
enum brcmf_sdiod_state state;
struct brcmf_sdiod_freezer *freezer;
+ const struct firmware *clm_fw;
};
/* sdio core registers */
@@ -346,26 +348,10 @@ int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, struct sdio_func *func);
void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev);
void brcmf_sdiod_change_state(struct brcmf_sdio_dev *sdiodev,
enum brcmf_sdiod_state state);
-#ifdef CONFIG_PM_SLEEP
bool brcmf_sdiod_freezing(struct brcmf_sdio_dev *sdiodev);
void brcmf_sdiod_try_freeze(struct brcmf_sdio_dev *sdiodev);
void brcmf_sdiod_freezer_count(struct brcmf_sdio_dev *sdiodev);
void brcmf_sdiod_freezer_uncount(struct brcmf_sdio_dev *sdiodev);
-#else
-static inline bool brcmf_sdiod_freezing(struct brcmf_sdio_dev *sdiodev)
-{
- return false;
-}
-static inline void brcmf_sdiod_try_freeze(struct brcmf_sdio_dev *sdiodev)
-{
-}
-static inline void brcmf_sdiod_freezer_count(struct brcmf_sdio_dev *sdiodev)
-{
-}
-static inline void brcmf_sdiod_freezer_uncount(struct brcmf_sdio_dev *sdiodev)
-{
-}
-#endif /* CONFIG_PM_SLEEP */
int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev);
int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h
index 338c66d0c5f8..5a139d7ed47a 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h
@@ -33,13 +33,11 @@ TRACE_EVENT(brcmf_err,
TP_ARGS(func, vaf),
TP_STRUCT__entry(
__string(func, func)
- __dynamic_array(char, msg, MAX_MSG_LEN)
+ __vstring(msg, vaf->fmt, vaf->va)
),
TP_fast_assign(
__assign_str(func, func);
- WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
- MAX_MSG_LEN, vaf->fmt,
- *vaf->va) >= MAX_MSG_LEN);
+ __assign_vstr(msg, vaf->fmt, vaf->va);
),
TP_printk("%s: %s", __get_str(func), __get_str(msg))
);
@@ -50,14 +48,12 @@ TRACE_EVENT(brcmf_dbg,
TP_STRUCT__entry(
__field(u32, level)
__string(func, func)
- __dynamic_array(char, msg, MAX_MSG_LEN)
+ __vstring(msg, vaf->fmt, vaf->va)
),
TP_fast_assign(
__entry->level = level;
__assign_str(func, func);
- WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
- MAX_MSG_LEN, vaf->fmt,
- *vaf->va) >= MAX_MSG_LEN);
+ __assign_vstr(msg, vaf->fmt, vaf->va);
),
TP_printk("%s: %s", __get_str(func), __get_str(msg))
);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
index 9fb68c2dc7e3..85e18fb9c497 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
@@ -1154,24 +1154,11 @@ error:
return NULL;
}
-static
-int brcmf_usb_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
+static int brcmf_usb_get_blob(struct device *dev, const struct firmware **fw,
+ enum brcmf_blob_type type)
{
- struct brcmf_bus *bus = dev_get_drvdata(dev);
- struct brcmf_fw_request *fwreq;
- struct brcmf_fw_name fwnames[] = {
- { ext, fw_name },
- };
-
- fwreq = brcmf_fw_alloc_request(bus->chip, bus->chiprev,
- brcmf_usb_fwnames,
- ARRAY_SIZE(brcmf_usb_fwnames),
- fwnames, ARRAY_SIZE(fwnames));
- if (!fwreq)
- return -ENOMEM;
-
- kfree(fwreq);
- return 0;
+ /* No blobs for USB devices... */
+ return -ENOENT;
}
static const struct brcmf_bus_ops brcmf_usb_bus_ops = {
@@ -1180,7 +1167,7 @@ static const struct brcmf_bus_ops brcmf_usb_bus_ops = {
.txdata = brcmf_usb_tx,
.txctl = brcmf_usb_tx_ctlpkt,
.rxctl = brcmf_usb_rx_ctlpkt,
- .get_fwname = brcmf_usb_get_fwname,
+ .get_blob = brcmf_usb_get_blob,
};
#define BRCMF_USB_FW_CODE 0
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/xtlv.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/xtlv.c
index 2f3c451148db..2f8908074303 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/xtlv.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/xtlv.c
@@ -4,6 +4,8 @@
*/
#include <asm/unaligned.h>
+
+#include <linux/math.h>
#include <linux/string.h>
#include <linux/bug.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/xtlv.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/xtlv.h
index e1930ce1b642..b2c7ae8966a1 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/xtlv.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/xtlv.h
@@ -15,7 +15,7 @@
struct brcmf_xtlv {
u16 id;
u16 len;
- u8 data[0];
+ u8 data[];
};
enum brcmf_xtlv_option {