summaryrefslogtreecommitdiff
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/bus.h10
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c167
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c157
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c40
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h3
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c5
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h31
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c14
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c19
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c39
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c18
12 files changed, 340 insertions, 165 deletions
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
index 163ddc49f951..0b76a615708e 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
@@ -71,6 +71,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.
*
* This structure provides an abstract interface towards the
* bus specific driver. For control messages to common driver
@@ -87,6 +88,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, uint chip, uint chiprev,
+ unsigned char *fw_name);
};
@@ -224,6 +227,13 @@ int brcmf_bus_get_memdump(struct brcmf_bus *bus, void *data, size_t len)
return bus->ops->get_memdump(bus->dev, data, len);
}
+static inline
+int brcmf_bus_get_fwname(struct brcmf_bus *bus, uint chip, uint chiprev,
+ unsigned char *fw_name)
+{
+ return bus->ops->get_fwname(bus->dev, chip, chiprev, fw_name);
+}
+
/*
* interface functions from common layer
*/
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 4157c90ad973..6e70df978159 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -472,47 +472,6 @@ send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key)
return err;
}
-static s32
-brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
-{
- s32 err;
- u32 mode;
-
- if (enable)
- mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
- else
- mode = 0;
-
- /* Try to set and enable ARP offload feature, this may fail, then it */
- /* is simply not supported and err 0 will be returned */
- err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
- if (err) {
- brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
- mode, err);
- err = 0;
- } else {
- err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
- if (err) {
- brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
- enable, err);
- err = 0;
- } else
- brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
- enable, mode);
- }
-
- err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
- if (err) {
- brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
- enable, err);
- err = 0;
- } else
- brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
- enable, mode);
-
- return err;
-}
-
static void
brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev)
{
@@ -1084,7 +1043,6 @@ brcmf_do_escan(struct brcmf_if *ifp, struct cfg80211_scan_request *request)
{
struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
s32 err;
- u32 passive_scan;
struct brcmf_scan_results *results;
struct escan_info *escan = &cfg->escan_info;
@@ -1092,13 +1050,7 @@ brcmf_do_escan(struct brcmf_if *ifp, struct cfg80211_scan_request *request)
escan->ifp = ifp;
escan->wiphy = cfg->wiphy;
escan->escan_state = WL_ESCAN_STATE_SCANNING;
- passive_scan = cfg->active_scan ? 0 : 1;
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
- passive_scan);
- if (err) {
- brcmf_err("error (%d)\n", err);
- return err;
- }
+
brcmf_scan_config_mpc(ifp, 0);
results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
results->version = 0;
@@ -1112,21 +1064,16 @@ brcmf_do_escan(struct brcmf_if *ifp, struct cfg80211_scan_request *request)
}
static s32
-brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
- struct cfg80211_scan_request *request,
- struct cfg80211_ssid *this_ssid)
+brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
{
- struct brcmf_if *ifp = vif->ifp;
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct cfg80211_ssid *ssids;
- u32 passive_scan;
- bool escan_req;
- bool spec_scan;
- s32 err;
- struct brcmf_ssid_le ssid_le;
- u32 SSID_len;
+ struct brcmf_cfg80211_vif *vif;
+ s32 err = 0;
- brcmf_dbg(SCAN, "START ESCAN\n");
+ brcmf_dbg(TRACE, "Enter\n");
+ vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
+ if (!check_vif_up(vif))
+ return -EIO;
if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
@@ -1142,8 +1089,8 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
cfg->scan_status);
return -EAGAIN;
}
- if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
- brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
+ if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state)) {
+ brcmf_err("Connecting: status (%lu)\n", vif->sme_state);
return -EAGAIN;
}
@@ -1151,96 +1098,38 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
- escan_req = false;
- if (request) {
- /* scan bss */
- ssids = request->ssids;
- escan_req = true;
- } else {
- /* scan in ibss */
- /* we don't do escan in ibss */
- ssids = this_ssid;
- }
+ brcmf_dbg(SCAN, "START ESCAN\n");
cfg->scan_request = request;
set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
- if (escan_req) {
- cfg->escan_info.run = brcmf_run_escan;
- err = brcmf_p2p_scan_prep(wiphy, request, vif);
- if (err)
- goto scan_out;
- err = brcmf_do_escan(vif->ifp, request);
- if (err)
- goto scan_out;
- } else {
- brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
- ssids->ssid, ssids->ssid_len);
- memset(&ssid_le, 0, sizeof(ssid_le));
- SSID_len = min_t(u8, sizeof(ssid_le.SSID), ssids->ssid_len);
- ssid_le.SSID_len = cpu_to_le32(0);
- spec_scan = false;
- if (SSID_len) {
- memcpy(ssid_le.SSID, ssids->ssid, SSID_len);
- ssid_le.SSID_len = cpu_to_le32(SSID_len);
- spec_scan = true;
- } else
- brcmf_dbg(SCAN, "Broadcast scan\n");
+ cfg->escan_info.run = brcmf_run_escan;
+ err = brcmf_p2p_scan_prep(wiphy, request, vif);
+ if (err)
+ goto scan_out;
- passive_scan = cfg->active_scan ? 0 : 1;
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
- passive_scan);
- if (err) {
- brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
- goto scan_out;
- }
- brcmf_scan_config_mpc(ifp, 0);
- err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, &ssid_le,
- sizeof(ssid_le));
- if (err) {
- if (err == -EBUSY)
- brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
- ssid_le.SSID);
- else
- brcmf_err("WLC_SCAN error (%d)\n", err);
+ err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBREQ_FLAG,
+ request->ie, request->ie_len);
+ if (err)
+ goto scan_out;
- brcmf_scan_config_mpc(ifp, 1);
- goto scan_out;
- }
- }
+ err = brcmf_do_escan(vif->ifp, request);
+ if (err)
+ goto scan_out;
/* Arm scan timeout timer */
- mod_timer(&cfg->escan_timeout, jiffies +
- BRCMF_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
+ mod_timer(&cfg->escan_timeout,
+ jiffies + msecs_to_jiffies(BRCMF_ESCAN_TIMER_INTERVAL_MS));
return 0;
scan_out:
+ brcmf_err("scan error (%d)\n", err);
clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
cfg->scan_request = NULL;
return err;
}
-static s32
-brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
-{
- struct brcmf_cfg80211_vif *vif;
- s32 err = 0;
-
- brcmf_dbg(TRACE, "Enter\n");
- vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
- if (!check_vif_up(vif))
- return -EIO;
-
- err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
-
- if (err)
- brcmf_err("scan error (%d)\n", err);
-
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-}
-
static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
{
s32 err = 0;
@@ -3261,9 +3150,8 @@ static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
brcmf_cfg80211_escan_handler);
cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
/* Init scan_timeout timer */
- init_timer(&cfg->escan_timeout);
- cfg->escan_timeout.data = (unsigned long) cfg;
- cfg->escan_timeout.function = brcmf_escan_timeout;
+ setup_timer(&cfg->escan_timeout, brcmf_escan_timeout,
+ (unsigned long)cfg);
INIT_WORK(&cfg->escan_timeout_work,
brcmf_cfg80211_escan_timeout_worker);
}
@@ -5877,7 +5765,6 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
cfg->scan_request = NULL;
cfg->pwr_save = true;
- cfg->active_scan = true; /* we do active scan per default */
cfg->dongle_up = false; /* dongle is not up yet */
err = brcmf_init_priv_mem(cfg);
if (err)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
index 7b2835e5e434..b5b5f0f10b63 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
@@ -283,7 +283,6 @@ struct brcmf_cfg80211_wowl {
* @scan_status: scan activity on the dongle.
* @pub: common driver information.
* @channel: current channel.
- * @active_scan: current scan mode.
* @int_escan_map: bucket map for which internal e-scan is done.
* @ibss_starter: indicates this sta is ibss starter.
* @pwr_save: indicate whether dongle to support power save mode.
@@ -316,7 +315,6 @@ struct brcmf_cfg80211_info {
unsigned long scan_status;
struct brcmf_pub *pub;
u32 channel;
- bool active_scan;
u32 int_escan_map;
bool ibss_starter;
bool pwr_save;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
index 7a2b49587b4d..6a59d0609d30 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -18,6 +18,7 @@
#include <linux/string.h>
#include <linux/netdevice.h>
#include <linux/module.h>
+#include <linux/firmware.h>
#include <brcmu_wifi.h>
#include <brcmu_utils.h>
#include "core.h"
@@ -28,6 +29,7 @@
#include "tracepoint.h"
#include "common.h"
#include "of.h"
+#include "firmware.h"
MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
@@ -104,12 +106,140 @@ void brcmf_c_set_joinpref_default(struct brcmf_if *ifp)
brcmf_err("Set join_pref error (%d)\n", err);
}
+static int brcmf_c_download(struct brcmf_if *ifp, u16 flag,
+ struct brcmf_dload_data_le *dload_buf,
+ u32 len)
+{
+ s32 err;
+
+ flag |= (DLOAD_HANDLER_VER << DLOAD_FLAG_VER_SHIFT);
+ dload_buf->flag = cpu_to_le16(flag);
+ dload_buf->dload_type = cpu_to_le16(DL_TYPE_CLM);
+ dload_buf->len = cpu_to_le32(len);
+ dload_buf->crc = cpu_to_le32(0);
+ len = sizeof(*dload_buf) + len - 1;
+
+ err = brcmf_fil_iovar_data_set(ifp, "clmload", dload_buf, len);
+
+ return err;
+}
+
+static int brcmf_c_get_clm_name(struct brcmf_if *ifp, u8 *clm_name)
+{
+ struct brcmf_bus *bus = ifp->drvr->bus_if;
+ struct brcmf_rev_info *ri = &ifp->drvr->revinfo;
+ u8 fw_name[BRCMF_FW_NAME_LEN];
+ u8 *ptr;
+ size_t len;
+ s32 err;
+
+ memset(fw_name, 0, BRCMF_FW_NAME_LEN);
+ err = brcmf_bus_get_fwname(bus, ri->chipnum, ri->chiprev, fw_name);
+ if (err) {
+ brcmf_err("get firmware name failed (%d)\n", err);
+ goto done;
+ }
+
+ /* generate CLM blob file name */
+ ptr = strrchr(fw_name, '.');
+ if (!ptr) {
+ err = -ENOENT;
+ goto done;
+ }
+
+ len = ptr - fw_name + 1;
+ if (len + strlen(".clm_blob") > BRCMF_FW_NAME_LEN) {
+ err = -E2BIG;
+ } else {
+ strlcpy(clm_name, fw_name, len);
+ strlcat(clm_name, ".clm_blob", BRCMF_FW_NAME_LEN);
+ }
+done:
+ return err;
+}
+
+static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
+{
+ struct device *dev = ifp->drvr->bus_if->dev;
+ 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;
+ u16 dl_flag = DL_BEGIN;
+ u32 status;
+ s32 err;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ memset(clm_name, 0, BRCMF_FW_NAME_LEN);
+ err = brcmf_c_get_clm_name(ifp, clm_name);
+ if (err) {
+ brcmf_err("get CLM blob file name failed (%d)\n", err);
+ return err;
+ }
+
+ err = request_firmware(&clm, clm_name, dev);
+ if (err) {
+ if (err == -ENOENT) {
+ brcmf_dbg(INFO, "continue with CLM data currently present in firmware\n");
+ return 0;
+ }
+ brcmf_err("request CLM blob file failed (%d)\n", err);
+ return err;
+ }
+
+ chunk_buf = kzalloc(sizeof(*chunk_buf) + MAX_CHUNK_LEN - 1, GFP_KERNEL);
+ if (!chunk_buf) {
+ err = -ENOMEM;
+ goto done;
+ }
+
+ datalen = clm->size;
+ cumulative_len = 0;
+ do {
+ if (datalen > MAX_CHUNK_LEN) {
+ chunk_len = MAX_CHUNK_LEN;
+ } else {
+ chunk_len = datalen;
+ dl_flag |= DL_END;
+ }
+ memcpy(chunk_buf->data, clm->data + cumulative_len, chunk_len);
+
+ err = brcmf_c_download(ifp, dl_flag, chunk_buf, chunk_len);
+
+ dl_flag &= ~DL_BEGIN;
+
+ cumulative_len += chunk_len;
+ datalen -= chunk_len;
+ } while ((datalen > 0) && (err == 0));
+
+ if (err) {
+ brcmf_err("clmload (%zu byte file) failed (%d); ",
+ clm->size, err);
+ /* Retrieve clmload_status and print */
+ err = brcmf_fil_iovar_int_get(ifp, "clmload_status", &status);
+ if (err)
+ brcmf_err("get clmload_status failed (%d)\n", err);
+ else
+ brcmf_dbg(INFO, "clmload_status=%d\n", status);
+ err = -EIO;
+ }
+
+ kfree(chunk_buf);
+done:
+ release_firmware(clm);
+ return err;
+}
+
int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
{
s8 eventmask[BRCMF_EVENTING_MASK_LEN];
u8 buf[BRCMF_DCMD_SMLEN];
struct brcmf_rev_info_le revinfo;
struct brcmf_rev_info *ri;
+ char *clmver;
char *ptr;
s32 err;
@@ -148,6 +278,13 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
}
ri->result = err;
+ /* Do any CLM downloading */
+ err = brcmf_c_process_clm_blob(ifp);
+ if (err < 0) {
+ brcmf_err("download CLM blob file failed, %d\n", err);
+ goto done;
+ }
+
/* query for 'ver' to get version info from firmware */
memset(buf, 0, sizeof(buf));
strcpy(buf, "ver");
@@ -167,6 +304,26 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
ptr = strrchr(buf, ' ') + 1;
strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver));
+ /* Query for 'clmver' to get CLM version info from firmware */
+ memset(buf, 0, sizeof(buf));
+ err = brcmf_fil_iovar_data_get(ifp, "clmver", buf, sizeof(buf));
+ if (err) {
+ brcmf_dbg(TRACE, "retrieving clmver failed, %d\n", err);
+ } else {
+ clmver = (char *)buf;
+ /* store CLM version for adding it to revinfo debugfs file */
+ memcpy(ifp->drvr->clmver, clmver, sizeof(ifp->drvr->clmver));
+
+ /* Replace all newline/linefeed characters with space
+ * character
+ */
+ ptr = clmver;
+ while ((ptr = strnchr(ptr, '\n', sizeof(buf))) != NULL)
+ *ptr = ' ';
+
+ brcmf_dbg(INFO, "CLM version = %s\n", clmver);
+ }
+
/* set mpc */
err = brcmf_fil_iovar_int_set(ifp, "mpc", 1);
if (err) {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index 5cc3a07dda9e..930e423f83a8 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -71,6 +71,43 @@ struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx)
return ifp;
}
+void brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
+{
+ s32 err;
+ u32 mode;
+
+ if (enable)
+ mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
+ else
+ mode = 0;
+
+ /* Try to set and enable ARP offload feature, this may fail, then it */
+ /* is simply not supported and err 0 will be returned */
+ err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
+ if (err) {
+ brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
+ mode, err);
+ } else {
+ err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
+ if (err) {
+ brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
+ enable, err);
+ } else {
+ brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
+ enable, mode);
+ }
+ }
+
+ err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
+ if (err) {
+ brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
+ enable, err);
+ } else {
+ brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
+ enable, mode);
+ }
+}
+
static void _brcmf_set_multicast_list(struct work_struct *work)
{
struct brcmf_if *ifp;
@@ -134,6 +171,7 @@ static void _brcmf_set_multicast_list(struct work_struct *work)
if (err < 0)
brcmf_err("Setting BRCMF_C_SET_PROMISC failed, %d\n",
err);
+ brcmf_configure_arp_nd_offload(ifp, !cmd_value);
}
#if IS_ENABLED(CONFIG_IPV6)
@@ -950,6 +988,8 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data)
seq_printf(s, "anarev: %u\n", ri->anarev);
seq_printf(s, "nvramrev: %08x\n", ri->nvramrev);
+ seq_printf(s, "clmver: %s\n", bus_if->drvr->clmver);
+
return 0;
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
index a4dd313140f3..df8a1ecb9924 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
@@ -141,6 +141,8 @@ struct brcmf_pub {
struct notifier_block inetaddr_notifier;
struct notifier_block inet6addr_notifier;
struct brcmf_mp_device *settings;
+
+ u8 clmver[BRCMF_DCMD_SMLEN];
};
/* forward declarations */
@@ -203,6 +205,7 @@ int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp);
/* Return pointer to interface name */
char *brcmf_ifname(struct brcmf_if *ifp);
struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx);
+void brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable);
int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx,
bool is_p2pdev, const char *name, u8 *mac_addr);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
index ef72baf6dd96..e7eaa57d11d9 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
@@ -257,11 +257,6 @@ static void brcmf_fweh_event_worker(struct work_struct *work)
brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data,
min_t(u32, emsg.datalen, 64),
"event payload, len=%d\n", emsg.datalen);
- if (emsg.datalen > event->datalen) {
- brcmf_err("event invalid length header=%d, msg=%d\n",
- event->datalen, emsg.datalen);
- goto event_free;
- }
/* special handling of interface event */
if (event->code == BRCMF_E_IF) {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
index e0d22fedb2b4..4b290705e3e6 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
@@ -155,6 +155,21 @@
#define BRCMF_MFP_CAPABLE 1
#define BRCMF_MFP_REQUIRED 2
+/* MAX_CHUNK_LEN is the maximum length for data passing to firmware in each
+ * ioctl. It is relatively small because firmware has small maximum size input
+ * playload restriction for ioctls.
+ */
+#define MAX_CHUNK_LEN 1400
+
+#define DLOAD_HANDLER_VER 1 /* Downloader version */
+#define DLOAD_FLAG_VER_MASK 0xf000 /* Downloader version mask */
+#define DLOAD_FLAG_VER_SHIFT 12 /* Downloader version shift */
+
+#define DL_BEGIN 0x0002
+#define DL_END 0x0004
+
+#define DL_TYPE_CLM 2
+
/* join preference types for join_pref iovar */
enum brcmf_join_pref_types {
BRCMF_JOIN_PREF_RSSI = 1,
@@ -827,6 +842,22 @@ struct brcmf_pno_macaddr_le {
};
/**
+ * struct brcmf_dload_data_le - data passing to firmware for downloading
+ * @flag: flags related to download data.
+ * @dload_type: type of download data.
+ * @len: length in bytes of download data.
+ * @crc: crc of download data.
+ * @data: download data.
+ */
+struct brcmf_dload_data_le {
+ __le16 flag;
+ __le16 dload_type;
+ __le32 len;
+ __le32 crc;
+ u8 data[1];
+};
+
+/**
* struct brcmf_pno_bssid_le - bssid configuration for PNO scan.
*
* @bssid: BSS network identifier.
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
index 2ce675ab40ef..2ee54133efa1 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
@@ -692,10 +692,7 @@ static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans,
/* determine the scan engine parameters */
sparams->bss_type = DOT11_BSSTYPE_ANY;
- if (p2p->cfg->active_scan)
- sparams->scan_type = 0;
- else
- sparams->scan_type = 1;
+ sparams->scan_type = BRCMF_SCANTYPE_ACTIVE;
eth_broadcast_addr(sparams->bssid);
sparams->home_time = cpu_to_le32(P2PAPI_SCAN_HOME_TIME_MS);
@@ -884,7 +881,7 @@ int brcmf_p2p_scan_prep(struct wiphy *wiphy,
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_p2p_info *p2p = &cfg->p2p;
- int err = 0;
+ int err;
if (brcmf_p2p_scan_is_p2p_request(request)) {
/* find my listen channel */
@@ -907,9 +904,7 @@ int brcmf_p2p_scan_prep(struct wiphy *wiphy,
/* override .run_escan() callback. */
cfg->escan_info.run = brcmf_p2p_run_escan;
}
- err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBREQ_FLAG,
- request->ie, request->ie_len);
- return err;
+ return 0;
}
@@ -1853,7 +1848,6 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
struct afx_hdl *afx_hdl = &p2p->afx_hdl;
struct brcmf_cfg80211_vif *vif = ifp->vif;
struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;
- u16 chanspec = be16_to_cpu(rxframe->chanspec);
struct brcmu_chan ch;
u8 *mgmt_frame;
u32 mgmt_frame_len;
@@ -1906,7 +1900,7 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);
brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n",
- mgmt_frame_len, e->datalen, chanspec, freq);
+ mgmt_frame_len, e->datalen, ch.chspec, freq);
return 0;
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index e6e9b00b79d7..3c87157f5b85 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -1350,6 +1350,24 @@ 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, u32 chip, u32 chiprev,
+ u8 *fw_name)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
+ struct brcmf_pciedev_info *devinfo = buspub->devinfo;
+ int ret = 0;
+
+ if (devinfo->fw_name[0] != '\0')
+ strlcpy(fw_name, devinfo->fw_name, BRCMF_FW_NAME_LEN);
+ else
+ ret = brcmf_fw_map_chip_to_name(chip, chiprev,
+ brcmf_pcie_fwnames,
+ ARRAY_SIZE(brcmf_pcie_fwnames),
+ fw_name, NULL);
+
+ return ret;
+}
static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
.txdata = brcmf_pcie_tx,
@@ -1359,6 +1377,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,
};
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index 785a0f33b7e6..e3495ea95553 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -260,10 +260,11 @@ struct rte_console {
#define I_HMB_HOST_INT I_HMB_SW3 /* Miscellaneous Interrupt */
/* tohostmailboxdata */
-#define HMB_DATA_NAKHANDLED 1 /* retransmit NAK'd frame */
-#define HMB_DATA_DEVREADY 2 /* talk to host after enable */
-#define HMB_DATA_FC 4 /* per prio flowcontrol update flag */
-#define HMB_DATA_FWREADY 8 /* fw ready for protocol activity */
+#define HMB_DATA_NAKHANDLED 0x0001 /* retransmit NAK'd frame */
+#define HMB_DATA_DEVREADY 0x0002 /* talk to host after enable */
+#define HMB_DATA_FC 0x0004 /* per prio flowcontrol update flag */
+#define HMB_DATA_FWREADY 0x0008 /* fw ready for protocol activity */
+#define HMB_DATA_FWHALT 0x0010 /* firmware halted */
#define HMB_DATA_FCDATA_MASK 0xff000000
#define HMB_DATA_FCDATA_SHIFT 24
@@ -1094,6 +1095,10 @@ static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus)
offsetof(struct sdpcmd_regs, tosbmailbox));
bus->sdcnt.f1regdata += 2;
+ /* dongle indicates the firmware has halted/crashed */
+ if (hmb_data & HMB_DATA_FWHALT)
+ brcmf_err("mailbox indicates firmware halted\n");
+
/* Dongle recomposed rx frames, accept them again */
if (hmb_data & HMB_DATA_NAKHANDLED) {
brcmf_dbg(SDIO, "Dongle reports NAK handled, expect rtx of %d\n",
@@ -1151,6 +1156,7 @@ static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus)
HMB_DATA_NAKHANDLED |
HMB_DATA_FC |
HMB_DATA_FWREADY |
+ HMB_DATA_FWHALT |
HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK))
brcmf_err("Unknown mailbox data content: 0x%02x\n",
hmb_data);
@@ -3979,6 +3985,24 @@ brcmf_sdio_watchdog(unsigned long data)
}
}
+static int brcmf_sdio_get_fwname(struct device *dev, u32 chip, u32 chiprev,
+ u8 *fw_name)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+ int ret = 0;
+
+ if (sdiodev->fw_name[0] != '\0')
+ strlcpy(fw_name, sdiodev->fw_name, BRCMF_FW_NAME_LEN);
+ else
+ ret = brcmf_fw_map_chip_to_name(chip, chiprev,
+ brcmf_sdio_fwnames,
+ ARRAY_SIZE(brcmf_sdio_fwnames),
+ fw_name, NULL);
+
+ return ret;
+}
+
static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
.stop = brcmf_sdio_bus_stop,
.preinit = brcmf_sdio_bus_preinit,
@@ -3989,6 +4013,7 @@ 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,
};
static void brcmf_sdio_firmware_callback(struct device *dev, int err,
@@ -4144,10 +4169,8 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
init_waitqueue_head(&bus->dcmd_resp_wait);
/* Set up the watchdog timer */
- init_timer(&bus->timer);
- bus->timer.data = (unsigned long)bus;
- bus->timer.function = brcmf_sdio_watchdog;
-
+ setup_timer(&bus->timer, brcmf_sdio_watchdog,
+ (unsigned long)bus);
/* Initialize watchdog thread */
init_completion(&bus->watchdog_wait);
bus->watchdog_tsk = kthread_run(brcmf_sdio_watchdog_thread,
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
index 11ffaa01599e..b27170c12482 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
@@ -1128,12 +1128,30 @@ static void brcmf_usb_wowl_config(struct device *dev, bool enabled)
device_set_wakeup_enable(devinfo->dev, false);
}
+static int brcmf_usb_get_fwname(struct device *dev, u32 chip, u32 chiprev,
+ u8 *fw_name)
+{
+ struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+ int ret = 0;
+
+ if (devinfo->fw_name[0] != '\0')
+ strlcpy(fw_name, devinfo->fw_name, BRCMF_FW_NAME_LEN);
+ else
+ ret = brcmf_fw_map_chip_to_name(chip, chiprev,
+ brcmf_usb_fwnames,
+ ARRAY_SIZE(brcmf_usb_fwnames),
+ fw_name, NULL);
+
+ return ret;
+}
+
static const struct brcmf_bus_ops brcmf_usb_bus_ops = {
.txdata = brcmf_usb_tx,
.stop = brcmf_usb_down,
.txctl = brcmf_usb_tx_ctlpkt,
.rxctl = brcmf_usb_rx_ctlpkt,
.wowl_config = brcmf_usb_wowl_config,
+ .get_fwname = brcmf_usb_get_fwname,
};
static int brcmf_usb_bus_setup(struct brcmf_usbdev_info *devinfo)