brcmfmac: merge in latest driver from Cypress (including required wifi core module updates)
parent
9b0d59aedb
commit
a808e2e497
|
@ -20,7 +20,6 @@ config BRCMSMAC
|
|||
config BRCMFMAC
|
||||
tristate "Broadcom FullMAC WLAN driver"
|
||||
depends on CFG80211
|
||||
select WIRELESS_EXT
|
||||
select BRCMUTIL
|
||||
---help---
|
||||
This module adds support for wireless adapters based on Broadcom
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "sdio.h"
|
||||
#include "core.h"
|
||||
#include "common.h"
|
||||
#include "cfg80211.h"
|
||||
|
||||
#define SDIOH_API_ACCESS_RETRY_LIMIT 2
|
||||
|
||||
|
@ -55,6 +56,7 @@
|
|||
#define SDIO_FUNC1_BLOCKSIZE 64
|
||||
#define SDIO_FUNC2_BLOCKSIZE 512
|
||||
#define SDIO_4373_FUNC2_BLOCKSIZE 256
|
||||
#define SDIO_4359_FUNC2_BLOCKSIZE 256
|
||||
/* Maximum milliseconds to wait for F2 to come up */
|
||||
#define SDIO_WAIT_F2RDY 3000
|
||||
|
||||
|
@ -1052,8 +1054,15 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (sdiodev->func[0]->device == SDIO_DEVICE_ID_CYPRESS_4373) {
|
||||
switch (sdiodev->func[0]->device) {
|
||||
case SDIO_DEVICE_ID_CYPRESS_4373:
|
||||
f2_blksz = SDIO_4373_FUNC2_BLOCKSIZE;
|
||||
break;
|
||||
case SDIO_DEVICE_ID_BROADCOM_4359:
|
||||
f2_blksz = SDIO_4359_FUNC2_BLOCKSIZE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = sdio_set_block_size(sdiodev->func[2], f2_blksz);
|
||||
|
@ -1110,12 +1119,12 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = {
|
|||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43364),
|
||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339),
|
||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4339),
|
||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43428),
|
||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430),
|
||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345),
|
||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455),
|
||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354),
|
||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356),
|
||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359),
|
||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_4373),
|
||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_43012),
|
||||
{ /* end: all zeroes */ }
|
||||
|
@ -1184,6 +1193,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
|
|||
dev_set_drvdata(&func->dev, bus_if);
|
||||
dev_set_drvdata(&sdiodev->func[1]->dev, bus_if);
|
||||
sdiodev->dev = &sdiodev->func[1]->dev;
|
||||
dev_set_drvdata(&sdiodev->func[2]->dev, bus_if);
|
||||
|
||||
brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_DOWN);
|
||||
|
||||
|
@ -1200,6 +1210,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
|
|||
fail:
|
||||
dev_set_drvdata(&func->dev, NULL);
|
||||
dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
|
||||
dev_set_drvdata(&sdiodev->func[2]->dev, NULL);
|
||||
kfree(sdiodev->func[0]);
|
||||
kfree(sdiodev);
|
||||
kfree(bus_if);
|
||||
|
@ -1256,14 +1267,26 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
|
|||
struct brcmf_bus *bus_if;
|
||||
struct brcmf_sdio_dev *sdiodev;
|
||||
mmc_pm_flag_t sdio_flags;
|
||||
struct brcmf_cfg80211_info *config;
|
||||
int retry = BRCMF_PM_WAIT_MAXRETRY;
|
||||
|
||||
func = container_of(dev, struct sdio_func, dev);
|
||||
bus_if = dev_get_drvdata(dev);
|
||||
config = bus_if->drvr->config;
|
||||
|
||||
brcmf_dbg(SDIO, "Enter: F%d\n", func->num);
|
||||
|
||||
while (retry &&
|
||||
config->pm_state == BRCMF_CFG80211_PM_STATE_SUSPENDING) {
|
||||
usleep_range(10000, 20000);
|
||||
retry--;
|
||||
}
|
||||
if (!retry && config->pm_state == BRCMF_CFG80211_PM_STATE_SUSPENDING)
|
||||
brcmf_err("timed out wait for cfg80211 suspended\n");
|
||||
|
||||
if (func->num != SDIO_FUNC_1)
|
||||
return 0;
|
||||
|
||||
|
||||
bus_if = dev_get_drvdata(dev);
|
||||
sdiodev = bus_if->bus_priv.sdio;
|
||||
|
||||
brcmf_sdiod_freezer_on(sdiodev);
|
||||
|
|
|
@ -160,6 +160,7 @@ struct brcmf_bus {
|
|||
|
||||
const struct brcmf_bus_ops *ops;
|
||||
struct brcmf_bus_msgbuf *msgbuf;
|
||||
bool allow_skborphan;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -256,6 +257,7 @@ void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state);
|
|||
int brcmf_bus_started(struct device *dev);
|
||||
s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len);
|
||||
void brcmf_bus_add_txhdrlen(struct device *dev, uint len);
|
||||
int brcmf_fwlog_attach(struct device *dev);
|
||||
|
||||
#ifdef CONFIG_BRCMFMAC_SDIO
|
||||
void brcmf_sdio_exit(void);
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "p2p.h"
|
||||
#include "btcoex.h"
|
||||
#include "pno.h"
|
||||
#include "fwsignal.h"
|
||||
#include "cfg80211.h"
|
||||
#include "feature.h"
|
||||
#include "fwil.h"
|
||||
|
@ -1367,6 +1368,30 @@ static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int brcmf_set_sae_password(struct brcmf_if *ifp, const u8 *pwd_data,
|
||||
u16 pwd_len)
|
||||
{
|
||||
struct brcmf_wsec_sae_pwd_le sae_pwd;
|
||||
int err;
|
||||
|
||||
if (pwd_len > BRCMF_WSEC_MAX_SAE_PASSWORD_LEN) {
|
||||
brcmf_err("sae_password must be less than %d\n",
|
||||
BRCMF_WSEC_MAX_SAE_PASSWORD_LEN);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sae_pwd.key_len = cpu_to_le16(pwd_len);
|
||||
memcpy(sae_pwd.key, pwd_data, pwd_len);
|
||||
|
||||
err = brcmf_fil_iovar_data_set(ifp, "sae_password", &sae_pwd,
|
||||
sizeof(sae_pwd));
|
||||
if (err < 0)
|
||||
brcmf_err("failed to set SAE password in firmware (len=%u)\n",
|
||||
pwd_len);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
|
||||
{
|
||||
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
|
||||
|
@ -1581,6 +1606,8 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev,
|
|||
val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
|
||||
else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
|
||||
val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
|
||||
else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_3)
|
||||
val = WPA3_AUTH_SAE_PSK;
|
||||
else
|
||||
val = WPA_AUTH_DISABLED;
|
||||
brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
|
||||
|
@ -1611,6 +1638,10 @@ static s32 brcmf_set_auth_type(struct net_device *ndev,
|
|||
val = 1;
|
||||
brcmf_dbg(CONN, "shared key\n");
|
||||
break;
|
||||
case NL80211_AUTHTYPE_SAE:
|
||||
val = 3;
|
||||
brcmf_dbg(CONN, "SAE authentication\n");
|
||||
break;
|
||||
default:
|
||||
val = 2;
|
||||
brcmf_dbg(CONN, "automatic, auth type (%d)\n", sme->auth_type);
|
||||
|
@ -1718,6 +1749,7 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
|
|||
u16 count;
|
||||
|
||||
profile->use_fwsup = BRCMF_PROFILE_FWSUP_NONE;
|
||||
profile->is_ft = false;
|
||||
|
||||
if (!sme->crypto.n_akm_suites)
|
||||
return 0;
|
||||
|
@ -1762,11 +1794,24 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
|
|||
break;
|
||||
case WLAN_AKM_SUITE_FT_8021X:
|
||||
val = WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT;
|
||||
profile->is_ft = true;
|
||||
if (sme->want_1x)
|
||||
profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
|
||||
break;
|
||||
case WLAN_AKM_SUITE_FT_PSK:
|
||||
val = WPA2_AUTH_PSK | WPA2_AUTH_FT;
|
||||
profile->is_ft = true;
|
||||
break;
|
||||
default:
|
||||
brcmf_err("invalid cipher group (%d)\n",
|
||||
sme->crypto.cipher_group);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (val & WPA3_AUTH_SAE_PSK) {
|
||||
switch (sme->crypto.akm_suites[0]) {
|
||||
case WLAN_AKM_SUITE_SAE:
|
||||
val = WPA3_AUTH_SAE_PSK;
|
||||
profile->use_fwsup = BRCMF_PROFILE_FWSUP_SAE;
|
||||
break;
|
||||
default:
|
||||
brcmf_err("invalid cipher group (%d)\n",
|
||||
|
@ -1777,6 +1822,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
|
|||
|
||||
if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X)
|
||||
brcmf_dbg(INFO, "using 1X offload\n");
|
||||
else if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_SAE)
|
||||
brcmf_dbg(INFO, "using SAE offload\n");
|
||||
|
||||
if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
|
||||
goto skip_mfp_config;
|
||||
|
@ -1842,7 +1889,8 @@ brcmf_set_sharedkey(struct net_device *ndev,
|
|||
brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
|
||||
sec->wpa_versions, sec->cipher_pairwise);
|
||||
|
||||
if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
|
||||
if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2 |
|
||||
NL80211_WPA_VERSION_3))
|
||||
return 0;
|
||||
|
||||
if (!(sec->cipher_pairwise &
|
||||
|
@ -2047,7 +2095,8 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
|
|||
goto done;
|
||||
}
|
||||
|
||||
if (sme->crypto.psk) {
|
||||
if (sme->crypto.psk &&
|
||||
profile->use_fwsup != BRCMF_PROFILE_FWSUP_SAE) {
|
||||
if (WARN_ON(profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE)) {
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
|
@ -2065,12 +2114,23 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
|
|||
}
|
||||
}
|
||||
|
||||
if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) {
|
||||
if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK)
|
||||
err = brcmf_set_pmk(ifp, sme->crypto.psk,
|
||||
BRCMF_WSEC_MAX_PSK_LEN);
|
||||
if (err)
|
||||
else if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_SAE) {
|
||||
/* clean up user-space RSNE */
|
||||
if (brcmf_fil_iovar_data_set(ifp, "wpaie", NULL, 0)) {
|
||||
brcmf_err("failed to clean up user-space RSNE\n");
|
||||
goto done;
|
||||
}
|
||||
err = brcmf_set_sae_password(ifp, sme->crypto.sae_pwd,
|
||||
sme->crypto.sae_pwd_len);
|
||||
if (!err && sme->crypto.psk)
|
||||
err = brcmf_set_pmk(ifp, sme->crypto.psk,
|
||||
BRCMF_WSEC_MAX_PSK_LEN);
|
||||
}
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
/* Join with specific BSSID and cached SSID
|
||||
* If SSID is zero join based on BSSID only
|
||||
|
@ -2825,7 +2885,7 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
|
|||
goto done;
|
||||
}
|
||||
|
||||
pm = enabled ? PM_FAST : PM_OFF;
|
||||
pm = enabled ? ifp->drvr->settings->default_pm : PM_OFF;
|
||||
/* Do not enable the power save after assoc if it is a p2p interface */
|
||||
if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
|
||||
brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
|
||||
|
@ -2863,7 +2923,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
|
|||
|
||||
if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
|
||||
brcmf_err("Bss info is larger than buffer. Discarding\n");
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!bi->ctl_ch) {
|
||||
|
@ -3589,6 +3649,8 @@ brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
|
|||
}
|
||||
|
||||
netinfo = brcmf_get_netinfo_array(pfn_result);
|
||||
if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN)
|
||||
netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
|
||||
memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
|
||||
cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
|
||||
cfg->wowl.nd->n_channels = 1;
|
||||
|
@ -3689,10 +3751,24 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
|
|||
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
|
||||
struct net_device *ndev = cfg_to_ndev(cfg);
|
||||
struct brcmf_if *ifp = netdev_priv(ndev);
|
||||
struct brcmf_pub *drvr = ifp->drvr;
|
||||
struct brcmf_bus *bus_if = drvr->bus_if;
|
||||
struct brcmf_cfg80211_info *config = drvr->config;
|
||||
int retry = BRCMF_PM_WAIT_MAXRETRY;
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
config->pm_state = BRCMF_CFG80211_PM_STATE_RESUMING;
|
||||
|
||||
if (cfg->wowl.active) {
|
||||
/* wait for bus resumed */
|
||||
while (retry && bus_if->state != BRCMF_BUS_UP) {
|
||||
usleep_range(10000, 20000);
|
||||
retry--;
|
||||
}
|
||||
if (!retry && bus_if->state != BRCMF_BUS_UP)
|
||||
brcmf_err("timed out wait for bus resume\n");
|
||||
|
||||
brcmf_report_wowl_wakeind(wiphy, ifp);
|
||||
brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
|
||||
brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
|
||||
|
@ -3713,6 +3789,7 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
|
|||
brcmf_pktfilter_enable(ifp->ndev, false);
|
||||
|
||||
}
|
||||
config->pm_state = BRCMF_CFG80211_PM_STATE_RESUMED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3782,9 +3859,12 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
|
|||
struct net_device *ndev = cfg_to_ndev(cfg);
|
||||
struct brcmf_if *ifp = netdev_priv(ndev);
|
||||
struct brcmf_cfg80211_vif *vif;
|
||||
struct brcmf_cfg80211_info *config = ifp->drvr->config;
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
config->pm_state = BRCMF_CFG80211_PM_STATE_SUSPENDING;
|
||||
|
||||
/* if the primary net_device is not READY there is nothing
|
||||
* we can do but pray resume goes smoothly.
|
||||
*/
|
||||
|
@ -3820,15 +3900,19 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
|
|||
brcmf_set_mpc(ifp, 1);
|
||||
|
||||
} else {
|
||||
/* Configure WOWL parameters */
|
||||
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
|
||||
/* Configure WOWL parameters */
|
||||
brcmf_configure_wowl(cfg, ifp, wowl);
|
||||
}
|
||||
|
||||
exit:
|
||||
brcmf_dbg(TRACE, "Exit\n");
|
||||
/* set cfg80211 pm state to cfg80211 suspended state */
|
||||
config->pm_state = BRCMF_CFG80211_PM_STATE_SUSPENDED;
|
||||
|
||||
/* clear any scanning activity */
|
||||
cfg->scan_status = 0;
|
||||
|
||||
brcmf_dbg(TRACE, "Exit\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -4361,6 +4445,11 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
|
|||
mgmt_ie_len = &saved_ie->assoc_req_ie_len;
|
||||
mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
|
||||
break;
|
||||
case BRCMF_VNDR_IE_ASSOCRSP_FLAG:
|
||||
mgmt_ie_buf = saved_ie->assoc_res_ie;
|
||||
mgmt_ie_len = &saved_ie->assoc_res_ie_len;
|
||||
mgmt_ie_buf_len = sizeof(saved_ie->assoc_res_ie);
|
||||
break;
|
||||
default:
|
||||
err = -EPERM;
|
||||
brcmf_err("not suitable type\n");
|
||||
|
@ -4510,6 +4599,15 @@ brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
|
|||
else
|
||||
brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
|
||||
|
||||
/* Set Assoc Response IEs to FW */
|
||||
err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_ASSOCRSP_FLAG,
|
||||
beacon->assocresp_ies,
|
||||
beacon->assocresp_ies_len);
|
||||
if (err)
|
||||
brcmf_err("Set Assoc Resp IE Failed\n");
|
||||
else
|
||||
brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc Resp\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -5342,6 +5440,7 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
|
|||
struct brcmf_cfg80211_vif *vif_walk;
|
||||
struct brcmf_cfg80211_vif *vif;
|
||||
bool mbss;
|
||||
struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);
|
||||
|
||||
brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
|
||||
sizeof(*vif));
|
||||
|
@ -5354,7 +5453,8 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
|
|||
|
||||
brcmf_init_prof(&vif->profile);
|
||||
|
||||
if (type == NL80211_IFTYPE_AP) {
|
||||
if (type == NL80211_IFTYPE_AP &&
|
||||
brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
|
||||
mbss = false;
|
||||
list_for_each_entry(vif_walk, &cfg->vif_list, list) {
|
||||
if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {
|
||||
|
@ -5393,25 +5493,28 @@ static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif,
|
|||
u32 event = e->event_code;
|
||||
u32 status = e->status;
|
||||
|
||||
if (vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_PSK &&
|
||||
event == BRCMF_E_PSK_SUP &&
|
||||
status == BRCMF_E_STATUS_FWSUP_COMPLETED)
|
||||
if (event == BRCMF_E_PSK_SUP &&
|
||||
status == BRCMF_E_STATUS_FWSUP_COMPLETED) {
|
||||
set_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
|
||||
if (vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_1X)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
|
||||
brcmf_dbg(CONN, "Processing set ssid\n");
|
||||
memcpy(vif->profile.bssid, e->addr, ETH_ALEN);
|
||||
if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_PSK)
|
||||
if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_PSK &&
|
||||
vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_SAE)
|
||||
return true;
|
||||
|
||||
set_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
|
||||
}
|
||||
|
||||
if (test_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state) &&
|
||||
test_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state)) {
|
||||
clear_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
|
||||
clear_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
|
||||
test_and_clear_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS,
|
||||
&vif->sme_state))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -5504,6 +5607,25 @@ u8 brcmf_map_prio_to_aci(void *config, u8 prio)
|
|||
return prio;
|
||||
}
|
||||
|
||||
static void brcmf_init_wmm_prio(u8 *priority)
|
||||
{
|
||||
/* Initialize AC priority array to default
|
||||
* 802.1d priority as per following table:
|
||||
* 802.1d prio 0,3 maps to BE
|
||||
* 802.1d prio 1,2 maps to BK
|
||||
* 802.1d prio 4,5 maps to VI
|
||||
* 802.1d prio 6,7 maps to VO
|
||||
*/
|
||||
priority[0] = BRCMF_FWS_FIFO_AC_BE;
|
||||
priority[3] = BRCMF_FWS_FIFO_AC_BE;
|
||||
priority[1] = BRCMF_FWS_FIFO_AC_BK;
|
||||
priority[2] = BRCMF_FWS_FIFO_AC_BK;
|
||||
priority[4] = BRCMF_FWS_FIFO_AC_VI;
|
||||
priority[5] = BRCMF_FWS_FIFO_AC_VI;
|
||||
priority[6] = BRCMF_FWS_FIFO_AC_VO;
|
||||
priority[7] = BRCMF_FWS_FIFO_AC_VO;
|
||||
}
|
||||
|
||||
static void brcmf_wifi_prioritize_acparams(const
|
||||
struct brcmf_cfg80211_edcf_acparam *acp, u8 *priority)
|
||||
{
|
||||
|
@ -5556,22 +5678,30 @@ static void brcmf_wifi_prioritize_acparams(const
|
|||
* Use ACI prio to get the new priority value for
|
||||
* each 802.1d traffic type, in this range.
|
||||
*/
|
||||
if (!(aci_prio[AC_BE] == aci_prio[AC_BK] &&
|
||||
aci_prio[AC_BK] == aci_prio[AC_VI] &&
|
||||
aci_prio[AC_VI] == aci_prio[AC_VO])) {
|
||||
|
||||
/* 802.1d 0,3 maps to BE */
|
||||
priority[0] = aci_prio[AC_BE];
|
||||
priority[3] = aci_prio[AC_BE];
|
||||
/* 802.1d 0,3 maps to BE */
|
||||
priority[0] = aci_prio[AC_BE];
|
||||
priority[3] = aci_prio[AC_BE];
|
||||
|
||||
/* 802.1d 1,2 maps to BK */
|
||||
priority[1] = aci_prio[AC_BK];
|
||||
priority[2] = aci_prio[AC_BK];
|
||||
/* 802.1d 1,2 maps to BK */
|
||||
priority[1] = aci_prio[AC_BK];
|
||||
priority[2] = aci_prio[AC_BK];
|
||||
|
||||
/* 802.1d 4,5 maps to VO */
|
||||
priority[4] = aci_prio[AC_VI];
|
||||
priority[5] = aci_prio[AC_VI];
|
||||
/* 802.1d 4,5 maps to VO */
|
||||
priority[4] = aci_prio[AC_VI];
|
||||
priority[5] = aci_prio[AC_VI];
|
||||
|
||||
/* 802.1d 6,7 maps to VO */
|
||||
priority[6] = aci_prio[AC_VO];
|
||||
priority[7] = aci_prio[AC_VO];
|
||||
/* 802.1d 6,7 maps to VO */
|
||||
priority[6] = aci_prio[AC_VO];
|
||||
priority[7] = aci_prio[AC_VO];
|
||||
|
||||
} else {
|
||||
/* Initialize to default priority */
|
||||
brcmf_init_wmm_prio(priority);
|
||||
}
|
||||
|
||||
brcmf_dbg(CONN, "Adj prio BE 0->%d, BK 1->%d, BK 2->%d, BE 3->%d\n",
|
||||
priority[0], priority[1], priority[2], priority[3]);
|
||||
|
@ -5651,6 +5781,47 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
|
|||
return err;
|
||||
}
|
||||
|
||||
static bool
|
||||
brcmf_has_pmkid(const u8 *parse, u32 len)
|
||||
{
|
||||
const struct brcmf_tlv *rsn_ie;
|
||||
const u8 *ie;
|
||||
u32 ie_len;
|
||||
u32 offset;
|
||||
u16 count;
|
||||
|
||||
rsn_ie = brcmf_parse_tlvs(parse, len, WLAN_EID_RSN);
|
||||
if (!rsn_ie)
|
||||
goto done;
|
||||
ie = (const u8 *)rsn_ie;
|
||||
ie_len = rsn_ie->len + TLV_HDR_LEN;
|
||||
/* Skip group data cipher suite */
|
||||
offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN;
|
||||
if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
|
||||
goto done;
|
||||
/* Skip pairwise cipher suite(s) */
|
||||
count = ie[offset] + (ie[offset + 1] << 8);
|
||||
offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
|
||||
if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
|
||||
goto done;
|
||||
/* Skip auth key management suite(s) */
|
||||
count = ie[offset] + (ie[offset + 1] << 8);
|
||||
offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
|
||||
if (offset + RSN_CAP_LEN >= ie_len)
|
||||
goto done;
|
||||
/* Skip rsn capabilities */
|
||||
offset += RSN_CAP_LEN;
|
||||
if (offset + RSN_PMKID_COUNT_LEN > ie_len)
|
||||
goto done;
|
||||
/* Extract PMKID count */
|
||||
count = ie[offset] + (ie[offset + 1] << 8);
|
||||
if (count)
|
||||
return true;
|
||||
|
||||
done:
|
||||
return false;
|
||||
}
|
||||
|
||||
static s32
|
||||
brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
|
||||
struct net_device *ndev,
|
||||
|
@ -5711,6 +5882,11 @@ done:
|
|||
roam_info.resp_ie = conn_info->resp_ie;
|
||||
roam_info.resp_ie_len = conn_info->resp_ie_len;
|
||||
|
||||
if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X &&
|
||||
(brcmf_has_pmkid(roam_info.req_ie, roam_info.req_ie_len) ||
|
||||
profile->is_ft))
|
||||
roam_info.authorized = true;
|
||||
|
||||
cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
|
||||
brcmf_dbg(CONN, "Report roaming result\n");
|
||||
|
||||
|
@ -5748,10 +5924,22 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
|
|||
conn_params.req_ie_len = conn_info->req_ie_len;
|
||||
conn_params.resp_ie = conn_info->resp_ie;
|
||||
conn_params.resp_ie_len = conn_info->resp_ie_len;
|
||||
|
||||
if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X &&
|
||||
brcmf_has_pmkid(conn_params.req_ie, conn_params.req_ie_len))
|
||||
conn_params.authorized = true;
|
||||
|
||||
cfg80211_connect_done(ndev, &conn_params, GFP_KERNEL);
|
||||
brcmf_dbg(CONN, "Report connect result - connection %s\n",
|
||||
completed ? "succeeded" : "failed");
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(BRCMF_VIF_STATUS_EAP_SUCCESS,
|
||||
&ifp->vif->sme_state) &&
|
||||
profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X) {
|
||||
cfg80211_port_authorized(ndev, profile->bssid, GFP_KERNEL);
|
||||
brcmf_dbg(CONN, "Report port authorized\n");
|
||||
}
|
||||
brcmf_dbg(TRACE, "Exit\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -5951,25 +6139,6 @@ static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
|
|||
conf->retry_long = (u32)-1;
|
||||
}
|
||||
|
||||
static void brcmf_init_wmm_prio(u8 *priority)
|
||||
{
|
||||
/* Initialize AC priority array to default
|
||||
* 802.1d priority as per following table:
|
||||
* 802.1d prio 0,3 maps to BE
|
||||
* 802.1d prio 1,2 maps to BK
|
||||
* 802.1d prio 4,5 maps to VI
|
||||
* 802.1d prio 6,7 maps to VO
|
||||
*/
|
||||
priority[0] = AC_BE;
|
||||
priority[3] = AC_BE;
|
||||
priority[1] = AC_BK;
|
||||
priority[2] = AC_BK;
|
||||
priority[4] = AC_VI;
|
||||
priority[5] = AC_VI;
|
||||
priority[6] = AC_VO;
|
||||
priority[7] = AC_VO;
|
||||
}
|
||||
|
||||
static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
|
||||
{
|
||||
brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
|
||||
|
@ -6581,6 +6750,16 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
|
|||
.tx = 0xffff,
|
||||
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
|
||||
},
|
||||
[NL80211_IFTYPE_AP] = {
|
||||
.tx = 0xffff,
|
||||
.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
|
||||
BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
|
||||
BIT(IEEE80211_STYPE_DISASSOC >> 4) |
|
||||
BIT(IEEE80211_STYPE_AUTH >> 4) |
|
||||
BIT(IEEE80211_STYPE_DEAUTH >> 4) |
|
||||
BIT(IEEE80211_STYPE_ACTION >> 4)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -6602,6 +6781,9 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
|
|||
* #STA <= 1, #AP <= 1, channels = 1, 2 total
|
||||
* #AP <= 4, matching BI, channels = 1, 4 total
|
||||
*
|
||||
* no p2p and rsdb:
|
||||
* #STA <= 1, #AP <= 2, channels = 2, 3 total
|
||||
*
|
||||
* p2p, no mchan, and mbss:
|
||||
*
|
||||
* #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
|
||||
|
@ -6613,6 +6795,16 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
|
|||
* #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
|
||||
* #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
|
||||
* #AP <= 4, matching BI, channels = 1, 4 total
|
||||
*
|
||||
* p2p, rsdb, and no mbss:
|
||||
* #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 2, AP <= 2,
|
||||
* channels = 2, 4 total
|
||||
*
|
||||
* p2p, rsdb, mbss
|
||||
* #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 2, AP <= 2,
|
||||
* channels = 2, 4 total
|
||||
* #AP <= 4, matching BI, channels = 1, 4 total
|
||||
*
|
||||
*/
|
||||
static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
|
||||
{
|
||||
|
@ -6620,13 +6812,14 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
|
|||
struct ieee80211_iface_limit *c0_limits = NULL;
|
||||
struct ieee80211_iface_limit *p2p_limits = NULL;
|
||||
struct ieee80211_iface_limit *mbss_limits = NULL;
|
||||
bool mbss, p2p;
|
||||
bool mbss, p2p, rsdb;
|
||||
int i, c, n_combos;
|
||||
|
||||
mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
|
||||
p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
|
||||
rsdb = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB);
|
||||
|
||||
n_combos = 1 + !!p2p + !!mbss;
|
||||
n_combos = 1 + !!(p2p && !rsdb) + !!mbss;
|
||||
combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
|
||||
if (!combo)
|
||||
goto err;
|
||||
|
@ -6637,16 +6830,36 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
|
|||
|
||||
c = 0;
|
||||
i = 0;
|
||||
c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
|
||||
if (p2p && rsdb)
|
||||
c0_limits = kcalloc(4, sizeof(*c0_limits), GFP_KERNEL);
|
||||
else if (p2p)
|
||||
c0_limits = kcalloc(3, sizeof(*c0_limits), GFP_KERNEL);
|
||||
else
|
||||
c0_limits = kcalloc(2, sizeof(*c0_limits), GFP_KERNEL);
|
||||
if (!c0_limits)
|
||||
goto err;
|
||||
c0_limits[i].max = 1;
|
||||
c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
|
||||
if (p2p) {
|
||||
if (p2p && rsdb) {
|
||||
combo[c].num_different_channels = 2;
|
||||
wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO) |
|
||||
BIT(NL80211_IFTYPE_P2P_DEVICE);
|
||||
c0_limits[i].max = 1;
|
||||
c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
|
||||
c0_limits[i].max = 1;
|
||||
c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
|
||||
c0_limits[i].max = 2;
|
||||
c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO);
|
||||
c0_limits[i].max = 2;
|
||||
c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
|
||||
combo[c].max_interfaces = 4;
|
||||
} else if (p2p) {
|
||||
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
|
||||
combo[c].num_different_channels = 2;
|
||||
else
|
||||
combo[c].num_different_channels = 1;
|
||||
c0_limits[i].max = 1;
|
||||
c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
|
||||
wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO) |
|
||||
BIT(NL80211_IFTYPE_P2P_DEVICE);
|
||||
|
@ -6655,16 +6868,26 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
|
|||
c0_limits[i].max = 1;
|
||||
c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO);
|
||||
combo[c].max_interfaces = i;
|
||||
} else if (rsdb) {
|
||||
combo[c].num_different_channels = 2;
|
||||
c0_limits[i].max = 1;
|
||||
c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
|
||||
c0_limits[i].max = 2;
|
||||
c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
|
||||
combo[c].max_interfaces = 3;
|
||||
} else {
|
||||
combo[c].num_different_channels = 1;
|
||||
c0_limits[i].max = 1;
|
||||
c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
|
||||
c0_limits[i].max = 1;
|
||||
c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
|
||||
combo[c].max_interfaces = i;
|
||||
}
|
||||
combo[c].max_interfaces = i;
|
||||
combo[c].n_limits = i;
|
||||
combo[c].limits = c0_limits;
|
||||
|
||||
if (p2p) {
|
||||
if (p2p && !rsdb) {
|
||||
c++;
|
||||
i = 0;
|
||||
p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
|
||||
|
@ -6776,6 +6999,7 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
|
|||
static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
|
||||
{
|
||||
struct brcmf_pub *drvr = ifp->drvr;
|
||||
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
|
||||
const struct ieee80211_iface_combination *combo;
|
||||
struct ieee80211_supported_band *band;
|
||||
u16 max_interfaces = 0;
|
||||
|
@ -6833,6 +7057,9 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
|
|||
NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
|
||||
wiphy_ext_feature_set(wiphy,
|
||||
NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X);
|
||||
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SAE))
|
||||
wiphy_ext_feature_set(wiphy,
|
||||
NL80211_EXT_FEATURE_SAE_OFFLOAD);
|
||||
}
|
||||
wiphy->mgmt_stypes = brcmf_txrx_stypes;
|
||||
wiphy->max_remain_on_channel_duration = 5000;
|
||||
|
@ -6843,6 +7070,10 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
|
|||
/* vendor commands/events support */
|
||||
wiphy->vendor_commands = brcmf_vendor_cmds;
|
||||
wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
|
||||
wiphy->vendor_events = brcmf_vendor_events;
|
||||
wiphy->n_vendor_events = BRCMF_VNDR_EVTS_LAST;
|
||||
brcmf_fweh_register(cfg->pub, BRCMF_E_PHY_TEMP,
|
||||
brcmf_wiphy_phy_temp_evt_handler);
|
||||
|
||||
brcmf_wiphy_wowl_params(wiphy, ifp);
|
||||
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
|
||||
|
@ -6916,7 +7147,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
|
|||
|
||||
brcmf_dongle_scantime(ifp);
|
||||
|
||||
power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
|
||||
power_mode = cfg->pwr_save ? ifp->drvr->settings->default_pm : PM_OFF;
|
||||
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
|
||||
if (err)
|
||||
goto default_conf_out;
|
||||
|
@ -6941,6 +7172,13 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
|
|||
|
||||
brcmf_configure_arp_nd_offload(ifp, true);
|
||||
|
||||
if (ifp->drvr->settings->frameburst) {
|
||||
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_FAKEFRAG, 1);
|
||||
if (err)
|
||||
brcmf_info("setting frameburst mode failed\n");
|
||||
brcmf_dbg(INFO, "frameburst mode enabled\n");
|
||||
}
|
||||
|
||||
cfg->dongle_up = true;
|
||||
default_conf_out:
|
||||
|
||||
|
@ -7222,6 +7460,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
|
|||
cfg->wiphy = wiphy;
|
||||
cfg->ops = ops;
|
||||
cfg->pub = drvr;
|
||||
cfg->pm_state = BRCMF_CFG80211_PM_STATE_RESUMED;
|
||||
init_vif_event(&cfg->vif_event);
|
||||
INIT_LIST_HEAD(&cfg->vif_list);
|
||||
|
||||
|
|
|
@ -103,6 +103,8 @@
|
|||
|
||||
#define BRCMF_VIF_EVENT_TIMEOUT msecs_to_jiffies(1500)
|
||||
|
||||
#define BRCMF_PM_WAIT_MAXRETRY 100
|
||||
|
||||
/* cfg80211 wowlan definitions */
|
||||
#define WL_WOWLAN_MAX_PATTERNS 8
|
||||
#define WL_WOWLAN_MIN_PATTERN_LEN 1
|
||||
|
@ -142,7 +144,8 @@ struct brcmf_cfg80211_security {
|
|||
enum brcmf_profile_fwsup {
|
||||
BRCMF_PROFILE_FWSUP_NONE,
|
||||
BRCMF_PROFILE_FWSUP_PSK,
|
||||
BRCMF_PROFILE_FWSUP_1X
|
||||
BRCMF_PROFILE_FWSUP_1X,
|
||||
BRCMF_PROFILE_FWSUP_SAE
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -157,6 +160,7 @@ struct brcmf_cfg80211_profile {
|
|||
struct brcmf_cfg80211_security sec;
|
||||
struct brcmf_wsec_key key[BRCMF_MAX_DEFAULT_KEYS];
|
||||
enum brcmf_profile_fwsup use_fwsup;
|
||||
bool is_ft;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -180,25 +184,36 @@ enum brcmf_vif_status {
|
|||
BRCMF_VIF_STATUS_ASSOC_SUCCESS,
|
||||
};
|
||||
|
||||
enum brcmf_cfg80211_pm_state {
|
||||
BRCMF_CFG80211_PM_STATE_RESUMED,
|
||||
BRCMF_CFG80211_PM_STATE_RESUMING,
|
||||
BRCMF_CFG80211_PM_STATE_SUSPENDED,
|
||||
BRCMF_CFG80211_PM_STATE_SUSPENDING,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vif_saved_ie - holds saved IEs for a virtual interface.
|
||||
*
|
||||
* @probe_req_ie: IE info for probe request.
|
||||
* @probe_res_ie: IE info for probe response.
|
||||
* @beacon_ie: IE info for beacon frame.
|
||||
* @assoc_res_ie: IE info for association response frame.
|
||||
* @probe_req_ie_len: IE info length for probe request.
|
||||
* @probe_res_ie_len: IE info length for probe response.
|
||||
* @beacon_ie_len: IE info length for beacon frame.
|
||||
* @assoc_res_ie_len: IE info length for association response frame.
|
||||
*/
|
||||
struct vif_saved_ie {
|
||||
u8 probe_req_ie[IE_MAX_LEN];
|
||||
u8 probe_res_ie[IE_MAX_LEN];
|
||||
u8 beacon_ie[IE_MAX_LEN];
|
||||
u8 assoc_req_ie[IE_MAX_LEN];
|
||||
u8 assoc_res_ie[IE_MAX_LEN];
|
||||
u32 probe_req_ie_len;
|
||||
u32 probe_res_ie_len;
|
||||
u32 beacon_ie_len;
|
||||
u32 assoc_req_ie_len;
|
||||
u32 assoc_res_ie_len;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -366,6 +381,7 @@ struct brcmf_cfg80211_info {
|
|||
struct brcmf_cfg80211_wowl wowl;
|
||||
struct brcmf_pno_info *pno;
|
||||
u8 ac_priority[MAX_8021D_PRIO];
|
||||
u8 pm_state;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -224,6 +224,24 @@ struct sbsocramregs {
|
|||
#define ARMCR4_BSZ_MASK 0x3f
|
||||
#define ARMCR4_BSZ_MULT 8192
|
||||
|
||||
/* Minimum PMU resource mask for 43012C0 */
|
||||
#define CY_43012_PMU_MIN_RES_MASK 0xF8BFE77
|
||||
|
||||
/* PMU STATUS mask for 43012C0 */
|
||||
#define CY_43012_PMU_STATUS_MASK 0x1AC
|
||||
|
||||
/* PMU CONTROL EXT mask for 43012C0 */
|
||||
#define CY_43012_PMU_CONTROL_EXT_MASK 0x11
|
||||
|
||||
/* PMU Watchdog Counter Tick value for 43012C0 */
|
||||
#define CY_43012_PMU_WATCHDOG_TICK_VAL 0x04
|
||||
|
||||
/* PMU Watchdog Counter Tick value for 4373 */
|
||||
#define CY_4373_PMU_WATCHDOG_TICK_VAL 0x04
|
||||
|
||||
/* Minimum PMU resource mask for 4373 */
|
||||
#define CY_4373_PMU_MIN_RES_MASK 0xFCAFF7F
|
||||
|
||||
struct brcmf_core_priv {
|
||||
struct brcmf_core pub;
|
||||
u32 wrapbase;
|
||||
|
@ -444,11 +462,25 @@ static void brcmf_chip_ai_resetcore(struct brcmf_core_priv *core, u32 prereset,
|
|||
{
|
||||
struct brcmf_chip_priv *ci;
|
||||
int count;
|
||||
struct brcmf_core *d11core2 = NULL;
|
||||
struct brcmf_core_priv *d11priv2 = NULL;
|
||||
|
||||
ci = core->chip;
|
||||
|
||||
/* special handle two D11 cores reset */
|
||||
if (core->pub.id == BCMA_CORE_80211) {
|
||||
d11core2 = brcmf_chip_get_d11core(&ci->pub, 1);
|
||||
if (d11core2) {
|
||||
brcmf_dbg(INFO, "found two d11 cores, reset both\n");
|
||||
d11priv2 = container_of(d11core2, struct brcmf_core_priv,
|
||||
pub);
|
||||
}
|
||||
}
|
||||
|
||||
/* must disable first to work for arbitrary current core state */
|
||||
brcmf_chip_ai_coredisable(core, prereset, reset);
|
||||
if (d11priv2)
|
||||
brcmf_chip_ai_coredisable(d11priv2, prereset, reset);
|
||||
|
||||
count = 0;
|
||||
while (ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL) &
|
||||
|
@ -460,9 +492,30 @@ static void brcmf_chip_ai_resetcore(struct brcmf_core_priv *core, u32 prereset,
|
|||
usleep_range(40, 60);
|
||||
}
|
||||
|
||||
if (d11priv2) {
|
||||
count = 0;
|
||||
while (ci->ops->read32(ci->ctx,
|
||||
d11priv2->wrapbase + BCMA_RESET_CTL) &
|
||||
BCMA_RESET_CTL_RESET) {
|
||||
ci->ops->write32(ci->ctx,
|
||||
d11priv2->wrapbase + BCMA_RESET_CTL,
|
||||
0);
|
||||
count++;
|
||||
if (count > 50)
|
||||
break;
|
||||
usleep_range(40, 60);
|
||||
}
|
||||
}
|
||||
|
||||
ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL,
|
||||
postreset | BCMA_IOCTL_CLK);
|
||||
ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL);
|
||||
|
||||
if (d11priv2) {
|
||||
ci->ops->write32(ci->ctx, d11priv2->wrapbase + BCMA_IOCTL,
|
||||
postreset | BCMA_IOCTL_CLK);
|
||||
ci->ops->read32(ci->ctx, d11priv2->wrapbase + BCMA_IOCTL);
|
||||
}
|
||||
}
|
||||
|
||||
static char *brcmf_chip_name(uint chipid, char *buf, uint len)
|
||||
|
@ -785,7 +838,7 @@ static int brcmf_chip_dmp_get_regaddr(struct brcmf_chip_priv *ci, u32 *eromaddr,
|
|||
u32 *regbase, u32 *wrapbase)
|
||||
{
|
||||
u8 desc;
|
||||
u32 val;
|
||||
u32 val, szdesc;
|
||||
u8 mpnum = 0;
|
||||
u8 stype, sztype, wraptype;
|
||||
|
||||
|
@ -831,14 +884,15 @@ static int brcmf_chip_dmp_get_regaddr(struct brcmf_chip_priv *ci, u32 *eromaddr,
|
|||
|
||||
/* next size descriptor can be skipped */
|
||||
if (sztype == DMP_SLAVE_SIZE_DESC) {
|
||||
val = brcmf_chip_dmp_get_desc(ci, eromaddr, NULL);
|
||||
szdesc = brcmf_chip_dmp_get_desc(ci, eromaddr, NULL);
|
||||
/* skip upper size descriptor if present */
|
||||
if (val & DMP_DESC_ADDRSIZE_GT32)
|
||||
if (szdesc & DMP_DESC_ADDRSIZE_GT32)
|
||||
brcmf_chip_dmp_get_desc(ci, eromaddr, NULL);
|
||||
}
|
||||
|
||||
/* only look for 4K register regions */
|
||||
if (sztype != DMP_SLAVE_SIZE_4K)
|
||||
/* look for 4K or 8K register regions */
|
||||
if (sztype != DMP_SLAVE_SIZE_4K &&
|
||||
sztype != DMP_SLAVE_SIZE_8K)
|
||||
continue;
|
||||
|
||||
stype = (val & DMP_SLAVE_TYPE) >> DMP_SLAVE_TYPE_S;
|
||||
|
@ -895,7 +949,8 @@ int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci)
|
|||
|
||||
/* need core with ports */
|
||||
if (nmw + nsw == 0 &&
|
||||
id != BCMA_CORE_PMU)
|
||||
id != BCMA_CORE_PMU &&
|
||||
id != BCMA_CORE_GCI)
|
||||
continue;
|
||||
|
||||
/* try to obtain register address info */
|
||||
|
@ -1119,6 +1174,21 @@ void brcmf_chip_detach(struct brcmf_chip *pub)
|
|||
kfree(chip);
|
||||
}
|
||||
|
||||
struct brcmf_core *brcmf_chip_get_d11core(struct brcmf_chip *pub, u8 unit)
|
||||
{
|
||||
struct brcmf_chip_priv *chip;
|
||||
struct brcmf_core_priv *core;
|
||||
|
||||
chip = container_of(pub, struct brcmf_chip_priv, pub);
|
||||
list_for_each_entry(core, &chip->cores, list) {
|
||||
if (core->pub.id == BCMA_CORE_80211) {
|
||||
if (unit-- == 0)
|
||||
return &core->pub;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *pub, u16 coreid)
|
||||
{
|
||||
struct brcmf_chip_priv *chip;
|
||||
|
@ -1161,6 +1231,14 @@ struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub)
|
|||
return cc;
|
||||
}
|
||||
|
||||
struct brcmf_core *brcmf_chip_get_gci(struct brcmf_chip *pub)
|
||||
{
|
||||
struct brcmf_core *gci;
|
||||
|
||||
gci = brcmf_chip_get_core(pub, BCMA_CORE_GCI);
|
||||
return gci;
|
||||
}
|
||||
|
||||
bool brcmf_chip_iscoreup(struct brcmf_core *pub)
|
||||
{
|
||||
struct brcmf_core_priv *core;
|
||||
|
@ -1368,6 +1446,7 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub)
|
|||
addr = CORE_CC_REG(base, sr_control0);
|
||||
reg = chip->ops->read32(chip->ctx, addr);
|
||||
return (reg & sr_eng_en) != 0;
|
||||
case BRCM_CC_4359_CHIP_ID:
|
||||
case CY_CC_43012_CHIP_ID:
|
||||
addr = CORE_CC_REG(pmu->base, retention_ctl);
|
||||
reg = chip->ops->read32(chip->ctx, addr);
|
||||
|
@ -1385,3 +1464,151 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub)
|
|||
PMU_RCTL_LOGIC_DISABLE_MASK)) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
void brcmf_chip_reset_pmu_regs(struct brcmf_chip *pub)
|
||||
{
|
||||
struct brcmf_chip_priv *chip;
|
||||
u32 addr;
|
||||
u32 base;
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
chip = container_of(pub, struct brcmf_chip_priv, pub);
|
||||
base = brcmf_chip_get_pmu(pub)->base;
|
||||
|
||||
switch (pub->chip) {
|
||||
case CY_CC_43012_CHIP_ID:
|
||||
/* SW scratch */
|
||||
addr = CORE_CC_REG(base, swscratch);
|
||||
chip->ops->write32(chip->ctx, addr, 0);
|
||||
|
||||
/* PMU status */
|
||||
addr = CORE_CC_REG(base, pmustatus);
|
||||
chip->ops->write32(chip->ctx, addr,
|
||||
CY_43012_PMU_STATUS_MASK);
|
||||
|
||||
/* PMU control ext */
|
||||
addr = CORE_CC_REG(base, pmucontrol_ext);
|
||||
chip->ops->write32(chip->ctx, addr,
|
||||
CY_43012_PMU_CONTROL_EXT_MASK);
|
||||
break;
|
||||
|
||||
default:
|
||||
brcmf_err("Unsupported chip id\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void brcmf_chip_set_default_min_res_mask(struct brcmf_chip *pub)
|
||||
{
|
||||
struct brcmf_chip_priv *chip;
|
||||
u32 addr;
|
||||
u32 base;
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
chip = container_of(pub, struct brcmf_chip_priv, pub);
|
||||
base = brcmf_chip_get_pmu(pub)->base;
|
||||
switch (pub->chip) {
|
||||
case CY_CC_43012_CHIP_ID:
|
||||
addr = CORE_CC_REG(base, min_res_mask);
|
||||
chip->ops->write32(chip->ctx, addr,
|
||||
CY_43012_PMU_MIN_RES_MASK);
|
||||
break;
|
||||
|
||||
default:
|
||||
brcmf_err("Unsupported chip id\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void brcmf_chip_ulp_reset_lhl_regs(struct brcmf_chip *pub)
|
||||
{
|
||||
struct brcmf_chip_priv *chip;
|
||||
u32 base;
|
||||
u32 addr;
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
chip = container_of(pub, struct brcmf_chip_priv, pub);
|
||||
base = brcmf_chip_get_gci(pub)->base;
|
||||
|
||||
/* LHL Top Level Power Sequence Control */
|
||||
addr = CORE_GCI_REG(base, lhl_top_pwrseq_ctl_adr);
|
||||
chip->ops->write32(chip->ctx, addr, 0);
|
||||
|
||||
/* GPIO Interrupt Enable0 */
|
||||
addr = CORE_GCI_REG(base, gpio_int_en_port_adr[0]);
|
||||
chip->ops->write32(chip->ctx, addr, 0);
|
||||
|
||||
/* GPIO Interrupt Status0 */
|
||||
addr = CORE_GCI_REG(base, gpio_int_st_port_adr[0]);
|
||||
chip->ops->write32(chip->ctx, addr, ~0);
|
||||
|
||||
/* WL ARM Timer0 Interrupt Mask */
|
||||
addr = CORE_GCI_REG(base, lhl_wl_armtim0_intrp_adr);
|
||||
chip->ops->write32(chip->ctx, addr, 0);
|
||||
|
||||
/* WL ARM Timer0 Interrupt Status */
|
||||
addr = CORE_GCI_REG(base, lhl_wl_armtim0_st_adr);
|
||||
chip->ops->write32(chip->ctx, addr, ~0);
|
||||
|
||||
/* WL ARM Timer */
|
||||
addr = CORE_GCI_REG(base, lhl_wl_armtim0_adr);
|
||||
chip->ops->write32(chip->ctx, addr, 0);
|
||||
|
||||
/* WL MAC Timer0 Interrupt Mask */
|
||||
addr = CORE_GCI_REG(base, lhl_wl_mactim0_intrp_adr);
|
||||
chip->ops->write32(chip->ctx, addr, 0);
|
||||
|
||||
/* WL MAC Timer0 Interrupt Status */
|
||||
addr = CORE_GCI_REG(base, lhl_wl_mactim0_st_adr);
|
||||
chip->ops->write32(chip->ctx, addr, ~0);
|
||||
|
||||
/* WL MAC TimerInt0 */
|
||||
addr = CORE_GCI_REG(base, lhl_wl_mactim_int0_adr);
|
||||
chip->ops->write32(chip->ctx, addr, 0x0);
|
||||
}
|
||||
|
||||
void brcmf_chip_reset_watchdog(struct brcmf_chip *pub)
|
||||
{
|
||||
struct brcmf_chip_priv *chip;
|
||||
u32 base;
|
||||
u32 addr;
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
chip = container_of(pub, struct brcmf_chip_priv, pub);
|
||||
base = brcmf_chip_get_pmu(pub)->base;
|
||||
|
||||
switch (pub->chip) {
|
||||
case CY_CC_43012_CHIP_ID:
|
||||
addr = CORE_CC_REG(base, min_res_mask);
|
||||
chip->ops->write32(chip->ctx, addr,
|
||||
CY_43012_PMU_MIN_RES_MASK);
|
||||
/* Watchdog res mask */
|
||||
addr = CORE_CC_REG(base, watchdog_res_mask);
|
||||
chip->ops->write32(chip->ctx, addr,
|
||||
CY_43012_PMU_MIN_RES_MASK);
|
||||
/* PMU watchdog */
|
||||
addr = CORE_CC_REG(base, pmuwatchdog);
|
||||
chip->ops->write32(chip->ctx, addr,
|
||||
CY_43012_PMU_WATCHDOG_TICK_VAL);
|
||||
break;
|
||||
case CY_CC_4373_CHIP_ID:
|
||||
addr = CORE_CC_REG(base, min_res_mask);
|
||||
chip->ops->write32(chip->ctx, addr,
|
||||
CY_4373_PMU_MIN_RES_MASK);
|
||||
addr = CORE_CC_REG(base, watchdog_res_mask);
|
||||
chip->ops->write32(chip->ctx, addr,
|
||||
CY_4373_PMU_MIN_RES_MASK);
|
||||
addr = CORE_CC_REG(base, pmuwatchdog);
|
||||
chip->ops->write32(chip->ctx, addr,
|
||||
CY_4373_PMU_WATCHDOG_TICK_VAL);
|
||||
mdelay(100);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#define CORE_CC_REG(base, field) \
|
||||
(base + offsetof(struct chipcregs, field))
|
||||
|
||||
#define CORE_GCI_REG(base, field) \
|
||||
(base + offsetof(struct chipgciregs, field))
|
||||
|
||||
/**
|
||||
* struct brcmf_chip - chip level information.
|
||||
*
|
||||
|
@ -93,5 +96,10 @@ void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset,
|
|||
void brcmf_chip_set_passive(struct brcmf_chip *ci);
|
||||
bool brcmf_chip_set_active(struct brcmf_chip *ci, u32 rstvec);
|
||||
bool brcmf_chip_sr_capable(struct brcmf_chip *pub);
|
||||
void brcmf_chip_reset_watchdog(struct brcmf_chip *pub);
|
||||
void brcmf_chip_ulp_reset_lhl_regs(struct brcmf_chip *pub);
|
||||
void brcmf_chip_reset_pmu_regs(struct brcmf_chip *pub);
|
||||
void brcmf_chip_set_default_min_res_mask(struct brcmf_chip *pub);
|
||||
struct brcmf_core *brcmf_chip_get_d11core(struct brcmf_chip *pub, u8 unit);
|
||||
|
||||
#endif /* BRCMF_AXIDMP_H */
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
#include "common.h"
|
||||
#include "of.h"
|
||||
#include "firmware.h"
|
||||
#include "fweh.h"
|
||||
#include <brcm_hw_ids.h>
|
||||
#include "defs.h"
|
||||
|
||||
MODULE_AUTHOR("Broadcom Corporation");
|
||||
MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
|
||||
|
@ -50,7 +53,8 @@ module_param_named(txglomsz, brcmf_sdiod_txglomsz, int, 0);
|
|||
MODULE_PARM_DESC(txglomsz, "Maximum tx packet chain size [SDIO]");
|
||||
|
||||
/* Debug level configuration. See debug.h for bits, sysfs modifiable */
|
||||
int brcmf_msg_level = 0x0fffffff;
|
||||
int brcmf_msg_level = BRCMF_DATA_VAL | BRCMF_CTL_VAL | BRCMF_HDRS_VAL | BRCMF_BYTES_VAL | BRCMF_GLOM_VAL | BRCMF_EVENT_VAL | BRCMF_FIL_VAL | BRCMF_FWCON_VAL | BRCMF_SCAN_VAL;
|
||||
|
||||
module_param_named(debug, brcmf_msg_level, int, S_IRUSR | S_IWUSR);
|
||||
MODULE_PARM_DESC(debug, "Level of debug output");
|
||||
|
||||
|
@ -83,6 +87,14 @@ static int brcmf_sdio_wq_highpri;
|
|||
module_param_named(sdio_wq_highpri, brcmf_sdio_wq_highpri, int, 0);
|
||||
MODULE_PARM_DESC(sdio_wq_highpri, "SDIO workqueue is set to high priority");
|
||||
|
||||
static int brcmf_frameburst;
|
||||
module_param_named(frameburst, brcmf_frameburst, int, 0);
|
||||
MODULE_PARM_DESC(frameburst, "Enable firmware frameburst feature");
|
||||
|
||||
static int brcmf_max_pm;
|
||||
module_param_named(max_pm, brcmf_max_pm, int, 0);
|
||||
MODULE_PARM_DESC(max_pm, "Use max power management mode by default");
|
||||
|
||||
#ifdef DEBUG
|
||||
/* always succeed brcmf_bus_started() */
|
||||
static int brcmf_ignore_probe_fail;
|
||||
|
@ -247,6 +259,9 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
|
|||
char *clmver;
|
||||
char *ptr;
|
||||
s32 err;
|
||||
struct eventmsgs_ext *eventmask_msg = NULL;
|
||||
u8 msglen;
|
||||
struct brcmf_bus *bus = ifp->drvr->bus_if;
|
||||
|
||||
/* retrieve mac addresses */
|
||||
err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
|
||||
|
@ -353,6 +368,41 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
|
|||
goto done;
|
||||
}
|
||||
|
||||
/* Enable event_msg_ext specific to 43012 chip */
|
||||
if (bus->chip == CY_CC_43012_CHIP_ID) {
|
||||
/* Program event_msg_ext to support event larger than 128 */
|
||||
msglen = (roundup(BRCMF_E_LAST, NBBY) / NBBY) +
|
||||
EVENTMSGS_EXT_STRUCT_SIZE;
|
||||
/* Allocate buffer for eventmask_msg */
|
||||
eventmask_msg = kzalloc(msglen, GFP_KERNEL);
|
||||
if (!eventmask_msg) {
|
||||
err = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Read the current programmed event_msgs_ext */
|
||||
eventmask_msg->ver = EVENTMSGS_VER;
|
||||
eventmask_msg->len = roundup(BRCMF_E_LAST, NBBY) / NBBY;
|
||||
err = brcmf_fil_iovar_data_get(ifp, "event_msgs_ext",
|
||||
eventmask_msg,
|
||||
msglen);
|
||||
|
||||
/* Enable ULP event */
|
||||
brcmf_dbg(EVENT, "enable event ULP\n");
|
||||
setbit(eventmask_msg->mask, BRCMF_E_ULP);
|
||||
|
||||
/* Write updated Event mask */
|
||||
eventmask_msg->ver = EVENTMSGS_VER;
|
||||
eventmask_msg->command = EVENTMSGS_SET_MASK;
|
||||
eventmask_msg->len = (roundup(BRCMF_E_LAST, NBBY) / NBBY);
|
||||
|
||||
err = brcmf_fil_iovar_data_set(ifp, "event_msgs_ext",
|
||||
eventmask_msg, msglen);
|
||||
if (err) {
|
||||
brcmf_err("Set event_msgs_ext error (%d)\n", err);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
/* Setup default scan channel time */
|
||||
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
|
||||
BRCMF_DEFAULT_SCAN_CHANNEL_TIME);
|
||||
|
@ -457,6 +507,8 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
|
|||
settings->roamoff = !!brcmf_roamoff;
|
||||
settings->eap_restrict = !!brcmf_eap_restrict;
|
||||
settings->sdio_wq_highpri = !!brcmf_sdio_wq_highpri;
|
||||
settings->frameburst = !!brcmf_frameburst;
|
||||
settings->default_pm = !!brcmf_max_pm ? PM_MAX : PM_FAST;
|
||||
#ifdef DEBUG
|
||||
settings->ignore_probe_fail = !!brcmf_ignore_probe_fail;
|
||||
#endif
|
||||
|
|
|
@ -51,6 +51,8 @@ extern struct brcmf_mp_global_t brcmf_mp_global;
|
|||
* @roamoff: Firmware roaming off?
|
||||
* @eap_restrict: Not allow data tx/rx until 802.1X auth succeeds
|
||||
* @sdio_wq_highpri: Tasks submitted to SDIO workqueue will run immediately.
|
||||
* @frameburst: Firmware frame burst mode.
|
||||
* @default_pm: default power management (PM) mode.
|
||||
* @ignore_probe_fail: Ignore probe failure.
|
||||
* @country_codes: If available, pointer to struct for translating country codes
|
||||
* @bus: Bus specific platform data. Only SDIO at the mmoment.
|
||||
|
@ -63,6 +65,8 @@ struct brcmf_mp_device {
|
|||
bool eap_restrict;
|
||||
int sdio_dpc_prio;
|
||||
bool sdio_wq_highpri;
|
||||
bool frameburst;
|
||||
int default_pm;
|
||||
bool ignore_probe_fail;
|
||||
struct brcmfmac_pd_cc *country_codes;
|
||||
union {
|
||||
|
|
|
@ -344,7 +344,8 @@ void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event)
|
|||
} else {
|
||||
/* Process special event packets */
|
||||
if (handle_event)
|
||||
brcmf_fweh_process_skb(ifp->drvr, skb);
|
||||
brcmf_fweh_process_skb(ifp->drvr, skb,
|
||||
BCMILCP_SUBTYPE_VENDOR_LONG);
|
||||
|
||||
brcmf_netif_rx(ifp, skb);
|
||||
}
|
||||
|
@ -361,7 +362,7 @@ void brcmf_rx_event(struct device *dev, struct sk_buff *skb)
|
|||
if (brcmf_rx_hdrpull(drvr, skb, &ifp))
|
||||
return;
|
||||
|
||||
brcmf_fweh_process_skb(ifp->drvr, skb);
|
||||
brcmf_fweh_process_skb(ifp->drvr, skb, 0);
|
||||
brcmu_pkt_buf_free_skb(skb);
|
||||
}
|
||||
|
||||
|
@ -370,6 +371,11 @@ void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
|
|||
struct ethhdr *eh;
|
||||
u16 type;
|
||||
|
||||
if (!ifp) {
|
||||
brcmu_pkt_buf_free_skb(txp);
|
||||
return;
|
||||
}
|
||||
|
||||
eh = (struct ethhdr *)(txp->data);
|
||||
type = ntohs(eh->h_proto);
|
||||
|
||||
|
@ -923,6 +929,14 @@ fail:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int brcmf_fwlog_attach(struct device *dev)
|
||||
{
|
||||
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
|
||||
struct brcmf_pub *drvr = bus_if->drvr;
|
||||
|
||||
return brcmf_debug_fwlog_init(drvr);
|
||||
}
|
||||
|
||||
static int brcmf_revinfo_read(struct seq_file *s, void *data)
|
||||
{
|
||||
struct brcmf_bus *bus_if = dev_get_drvdata(s->private);
|
||||
|
@ -1132,8 +1146,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) {
|
||||
brcmf_err("Timed out waiting for no pending 802.1x packets\n");
|
||||
atomic_set(&ifp->pend_8021x_cnt, 0);
|
||||
}
|
||||
|
||||
return !err;
|
||||
}
|
||||
|
@ -1338,6 +1354,7 @@ brcmf_pktfilter_add_remove(struct net_device *ndev, int filter_num, bool add)
|
|||
|
||||
drvr->pkt_filter[filter_num].id = 0;
|
||||
drvr->pkt_filter[filter_num].enable = 0;
|
||||
|
||||
}
|
||||
failed:
|
||||
if (ret)
|
||||
|
|
|
@ -27,6 +27,82 @@
|
|||
|
||||
static struct dentry *root_folder;
|
||||
|
||||
static int
|
||||
brcmf_debug_msgtrace_seqchk(u32 *prev, u32 cur)
|
||||
{
|
||||
if ((cur == 0 && *prev == 0xFFFFFFFF) || ((cur - *prev) == 1)) {
|
||||
goto done;
|
||||
} else if (cur == *prev) {
|
||||
brcmf_dbg(FWCON, "duplicate trace\n");
|
||||
return -1;
|
||||
} else if (cur > *prev) {
|
||||
brcmf_dbg(FWCON, "lost %d packets\n", cur - *prev);
|
||||
} else {
|
||||
brcmf_dbg(FWCON, "seq out of order, host %d, dongle %d\n",
|
||||
*prev, cur);
|
||||
}
|
||||
done:
|
||||
*prev = cur;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
brcmf_debug_msg_parser(void *event_data)
|
||||
{
|
||||
int err = 0;
|
||||
struct msgtrace_hdr *hdr;
|
||||
char *data, *s;
|
||||
static u32 seqnum_prev;
|
||||
|
||||
hdr = (struct msgtrace_hdr *)event_data;
|
||||
data = (char *)event_data + MSGTRACE_HDRLEN;
|
||||
|
||||
/* There are 2 bytes available at the end of data */
|
||||
data[ntohs(hdr->len)] = '\0';
|
||||
|
||||
if (ntohl(hdr->discarded_bytes) || ntohl(hdr->discarded_printf)) {
|
||||
brcmf_dbg(FWCON, "Discarded_bytes %d discarded_printf %d\n",
|
||||
ntohl(hdr->discarded_bytes),
|
||||
ntohl(hdr->discarded_printf));
|
||||
}
|
||||
|
||||
err = brcmf_debug_msgtrace_seqchk(&seqnum_prev, ntohl(hdr->seqnum));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
while (*data != '\0' && (s = strstr(data, "\n")) != NULL) {
|
||||
*s = '\0';
|
||||
brcmf_dbg(FWCON, "[FWLOG] %s\n", data);
|
||||
data = s + 1;
|
||||
}
|
||||
if (*data)
|
||||
brcmf_dbg(FWCON, "[FWLOG] %s", data);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
brcmf_debug_trace_parser(struct brcmf_if *ifp,
|
||||
const struct brcmf_event_msg *evtmsg,
|
||||
void *event_data)
|
||||
{
|
||||
int err = 0;
|
||||
struct msgtrace_hdr *hdr;
|
||||
|
||||
hdr = (struct msgtrace_hdr *)event_data;
|
||||
if (hdr->version != MSGTRACE_VERSION) {
|
||||
brcmf_dbg(FWCON, "trace version mismatch host %d dngl %d\n",
|
||||
MSGTRACE_VERSION, hdr->version);
|
||||
err = -EPROTO;
|
||||
return err;
|
||||
}
|
||||
|
||||
if (hdr->trace_type == MSGTRACE_HDR_TYPE_MSG)
|
||||
err = brcmf_debug_msg_parser(event_data);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data,
|
||||
size_t len)
|
||||
{
|
||||
|
@ -42,7 +118,8 @@ int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data,
|
|||
if (!dump)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(dump, data, len);
|
||||
if (data && len > 0)
|
||||
memcpy(dump, data, len);
|
||||
err = brcmf_bus_get_memdump(bus, dump + len, ramsize);
|
||||
if (err) {
|
||||
vfree(dump);
|
||||
|
@ -81,6 +158,12 @@ int brcmf_debug_attach(struct brcmf_pub *drvr)
|
|||
return PTR_ERR_OR_ZERO(drvr->dbgfs_dir);
|
||||
}
|
||||
|
||||
int brcmf_debug_fwlog_init(struct brcmf_pub *drvr)
|
||||
{
|
||||
return brcmf_fweh_register(drvr, BRCMF_E_TRACE,
|
||||
brcmf_debug_trace_parser);
|
||||
}
|
||||
|
||||
void brcmf_debug_detach(struct brcmf_pub *drvr)
|
||||
{
|
||||
brcmf_fweh_unregister(drvr, BRCMF_E_PSM_WATCHDOG);
|
||||
|
|
|
@ -17,13 +17,6 @@
|
|||
#ifndef BRCMFMAC_DEBUG_H
|
||||
#define BRCMFMAC_DEBUG_H
|
||||
|
||||
|
||||
/* SBA HACK !! */
|
||||
#define CONFIG_BRCMDBG
|
||||
#define DEBUG
|
||||
|
||||
|
||||
|
||||
#include <linux/net.h> /* net_ratelimit() */
|
||||
|
||||
/* message levels */
|
||||
|
@ -47,6 +40,7 @@
|
|||
#define BRCMF_MSGBUF_VAL 0x00040000
|
||||
#define BRCMF_PCIE_VAL 0x00080000
|
||||
#define BRCMF_FWCON_VAL 0x00100000
|
||||
#define BRCMF_ULP_VAL 0x00200000
|
||||
|
||||
/* set default print format */
|
||||
#undef pr_fmt
|
||||
|
@ -108,6 +102,10 @@ do { \
|
|||
|
||||
#endif /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */
|
||||
|
||||
#define MSGTRACE_VERSION 1
|
||||
#define MSGTRACE_HDR_TYPE_MSG 0
|
||||
#define MSGTRACE_HDR_TYPE_LOG 1
|
||||
|
||||
#define brcmf_dbg_hex_dump(test, data, len, fmt, ...) \
|
||||
do { \
|
||||
trace_brcmf_hexdump((void *)data, len); \
|
||||
|
@ -129,6 +127,7 @@ int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
|
|||
int (*read_fn)(struct seq_file *seq, void *data));
|
||||
int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data,
|
||||
size_t len);
|
||||
int brcmf_debug_fwlog_init(struct brcmf_pub *drvr);
|
||||
#else
|
||||
static inline void brcmf_debugfs_init(void)
|
||||
{
|
||||
|
@ -155,6 +154,25 @@ int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data,
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline
|
||||
int brcmf_debug_fwlog_init(struct brcmf_pub *drvr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Message trace header */
|
||||
struct msgtrace_hdr {
|
||||
u8 version;
|
||||
u8 trace_type;
|
||||
u16 len; /* Len of the trace */
|
||||
u32 seqnum; /* Sequence number of message */
|
||||
/* Number of discarded bytes because of trace overflow */
|
||||
u32 discarded_bytes;
|
||||
/* Number of discarded printf because of trace overflow */
|
||||
u32 discarded_printf;
|
||||
};
|
||||
|
||||
#define MSGTRACE_HDRLEN sizeof(struct msgtrace_hdr)
|
||||
#endif /* BRCMFMAC_DEBUG_H */
|
||||
|
|
|
@ -48,6 +48,7 @@ static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = {
|
|||
{ BRCMF_FEAT_MBSS, "mbss" },
|
||||
{ BRCMF_FEAT_MCHAN, "mchan" },
|
||||
{ BRCMF_FEAT_P2P, "p2p" },
|
||||
{ BRCMF_FEAT_SAE, "sae" },
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
* MFP: 802.11w Management Frame Protection.
|
||||
* GSCAN: enhanced scan offload feature.
|
||||
* FWSUP: Firmware supplicant.
|
||||
* SAE: simultaneous authentication of equals
|
||||
*/
|
||||
#define BRCMF_FEAT_LIST \
|
||||
BRCMF_FEAT_DEF(MBSS) \
|
||||
|
@ -48,7 +49,8 @@
|
|||
BRCMF_FEAT_DEF(WOWL_ARP_ND) \
|
||||
BRCMF_FEAT_DEF(MFP) \
|
||||
BRCMF_FEAT_DEF(GSCAN) \
|
||||
BRCMF_FEAT_DEF(FWSUP)
|
||||
BRCMF_FEAT_DEF(FWSUP) \
|
||||
BRCMF_FEAT_DEF(SAE)
|
||||
|
||||
/*
|
||||
* Quirks:
|
||||
|
|
|
@ -101,7 +101,9 @@ struct brcmf_cfg80211_info;
|
|||
BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \
|
||||
BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) \
|
||||
BRCMF_ENUM_DEF(TDLS_PEER_EVENT, 92) \
|
||||
BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127)
|
||||
BRCMF_ENUM_DEF(PHY_TEMP, 111) \
|
||||
BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) \
|
||||
BRCMF_ENUM_DEF(ULP, 146)
|
||||
|
||||
#define BRCMF_ENUM_DEF(id, val) \
|
||||
BRCMF_E_##id = (val),
|
||||
|
@ -113,7 +115,7 @@ enum brcmf_fweh_event_code {
|
|||
* minimum length check in device firmware so it is
|
||||
* hard-coded here.
|
||||
*/
|
||||
BRCMF_E_LAST = 139
|
||||
BRCMF_E_LAST = 147
|
||||
};
|
||||
#undef BRCMF_ENUM_DEF
|
||||
|
||||
|
@ -211,7 +213,7 @@ enum brcmf_fweh_event_code {
|
|||
*/
|
||||
#define BRCM_OUI "\x00\x10\x18"
|
||||
#define BCMILCP_BCM_SUBTYPE_EVENT 1
|
||||
|
||||
#define BCMILCP_SUBTYPE_VENDOR_LONG 32769
|
||||
|
||||
/**
|
||||
* struct brcm_ethhdr - broadcom specific ether header.
|
||||
|
@ -294,6 +296,28 @@ struct brcmf_if_event {
|
|||
u8 role;
|
||||
};
|
||||
|
||||
enum event_msgs_ext_command {
|
||||
EVENTMSGS_NONE = 0,
|
||||
EVENTMSGS_SET_BIT = 1,
|
||||
EVENTMSGS_RESET_BIT = 2,
|
||||
EVENTMSGS_SET_MASK = 3
|
||||
};
|
||||
|
||||
#define EVENTMSGS_VER 1
|
||||
#define EVENTMSGS_EXT_STRUCT_SIZE offsetof(struct eventmsgs_ext, mask[0])
|
||||
|
||||
/* len- for SET it would be mask size from the application to the firmware */
|
||||
/* for GET it would be actual firmware mask size */
|
||||
/* maxgetsize - is only used for GET. indicate max mask size that the */
|
||||
/* application can read from the firmware */
|
||||
struct eventmsgs_ext {
|
||||
u8 ver;
|
||||
u8 command;
|
||||
u8 len;
|
||||
u8 maxgetsize;
|
||||
u8 mask[1];
|
||||
};
|
||||
|
||||
typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp,
|
||||
const struct brcmf_event_msg *evtmsg,
|
||||
void *data);
|
||||
|
@ -334,10 +358,10 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
|
|||
void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing);
|
||||
|
||||
static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
|
||||
struct sk_buff *skb)
|
||||
struct sk_buff *skb, u16 stype)
|
||||
{
|
||||
struct brcmf_event *event_packet;
|
||||
u16 usr_stype;
|
||||
u16 subtype, usr_stype;
|
||||
|
||||
/* only process events when protocol matches */
|
||||
if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))
|
||||
|
@ -346,8 +370,16 @@ static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
|
|||
if ((skb->len + ETH_HLEN) < sizeof(*event_packet))
|
||||
return;
|
||||
|
||||
/* check for BRCM oui match */
|
||||
event_packet = (struct brcmf_event *)skb_mac_header(skb);
|
||||
|
||||
/* check subtype if needed */
|
||||
if (unlikely(stype)) {
|
||||
subtype = get_unaligned_be16(&event_packet->hdr.subtype);
|
||||
if (subtype != stype)
|
||||
return;
|
||||
}
|
||||
|
||||
/* check for BRCM oui match */
|
||||
if (memcmp(BRCM_OUI, &event_packet->hdr.oui[0],
|
||||
sizeof(event_packet->hdr.oui)))
|
||||
return;
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
#define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON 201
|
||||
#define BRCMF_C_SET_ASSOC_PREFER 205
|
||||
#define BRCMF_C_GET_VALID_CHANNELS 217
|
||||
#define BRCMF_C_SET_FAKEFRAG 219
|
||||
#define BRCMF_C_GET_KEY_PRIMARY 235
|
||||
#define BRCMF_C_SET_KEY_PRIMARY 236
|
||||
#define BRCMF_C_SET_SCAN_PASSIVE_TIME 258
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#define BRCMF_ARP_OL_PEER_AUTO_REPLY 0x00000008
|
||||
|
||||
#define BRCMF_BSS_INFO_VERSION 109 /* curr ver of brcmf_bss_info_le struct */
|
||||
#define BRCMF_BSS_RSSI_ON_CHANNEL 0x0002
|
||||
#define BRCMF_BSS_RSSI_ON_CHANNEL 0x0004
|
||||
|
||||
#define BRCMF_STA_WME 0x00000002 /* WMM association */
|
||||
#define BRCMF_STA_AUTHE 0x00000008 /* Authenticated */
|
||||
|
@ -53,6 +53,8 @@
|
|||
#define BRCMF_WSEC_MAX_PSK_LEN 32
|
||||
#define BRCMF_WSEC_PASSPHRASE BIT(0)
|
||||
|
||||
#define BRCMF_WSEC_MAX_SAE_PASSWORD_LEN 128
|
||||
|
||||
/* primary (ie tx) key */
|
||||
#define BRCMF_PRIMARY_KEY (1 << 1)
|
||||
#define DOT11_BSSTYPE_ANY 2
|
||||
|
@ -125,7 +127,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
|
||||
|
||||
enum {
|
||||
|
@ -519,6 +521,17 @@ struct brcmf_wsec_pmk_le {
|
|||
u8 key[2 * BRCMF_WSEC_MAX_PSK_LEN + 1];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct brcmf_wsec_sae_pwd_le - firmware SAE password material.
|
||||
*
|
||||
* @key_len: number of octets in key materials.
|
||||
* @key: SAE password material.
|
||||
*/
|
||||
struct brcmf_wsec_sae_pwd_le {
|
||||
__le16 key_len;
|
||||
u8 key[BRCMF_WSEC_MAX_SAE_PASSWORD_LEN];
|
||||
};
|
||||
|
||||
/* Used to get specific STA parameters */
|
||||
struct brcmf_scb_val_le {
|
||||
__le32 val;
|
||||
|
|
|
@ -322,28 +322,6 @@ struct brcmf_skbuff_cb {
|
|||
/* How long to defer borrowing in jiffies */
|
||||
#define BRCMF_FWS_BORROW_DEFER_PERIOD (HZ / 10)
|
||||
|
||||
/**
|
||||
* enum brcmf_fws_fifo - fifo indices used by dongle firmware.
|
||||
*
|
||||
* @BRCMF_FWS_FIFO_FIRST: first fifo, ie. background.
|
||||
* @BRCMF_FWS_FIFO_AC_BK: fifo for background traffic.
|
||||
* @BRCMF_FWS_FIFO_AC_BE: fifo for best-effort traffic.
|
||||
* @BRCMF_FWS_FIFO_AC_VI: fifo for video traffic.
|
||||
* @BRCMF_FWS_FIFO_AC_VO: fifo for voice traffic.
|
||||
* @BRCMF_FWS_FIFO_BCMC: fifo for broadcast/multicast (AP only).
|
||||
* @BRCMF_FWS_FIFO_ATIM: fifo for ATIM (AP only).
|
||||
* @BRCMF_FWS_FIFO_COUNT: number of fifos.
|
||||
*/
|
||||
enum brcmf_fws_fifo {
|
||||
BRCMF_FWS_FIFO_FIRST,
|
||||
BRCMF_FWS_FIFO_AC_BK = BRCMF_FWS_FIFO_FIRST,
|
||||
BRCMF_FWS_FIFO_AC_BE,
|
||||
BRCMF_FWS_FIFO_AC_VI,
|
||||
BRCMF_FWS_FIFO_AC_VO,
|
||||
BRCMF_FWS_FIFO_BCMC,
|
||||
BRCMF_FWS_FIFO_ATIM,
|
||||
BRCMF_FWS_FIFO_COUNT
|
||||
};
|
||||
|
||||
/**
|
||||
* enum brcmf_fws_txstatus - txstatus flag values.
|
||||
|
@ -416,6 +394,7 @@ struct brcmf_fws_mac_descriptor {
|
|||
};
|
||||
|
||||
#define BRCMF_FWS_HANGER_MAXITEMS 3072
|
||||
#define BRCMF_BORROW_RATIO 3
|
||||
|
||||
/**
|
||||
* enum brcmf_fws_hanger_item_state - state of hanger item.
|
||||
|
@ -512,7 +491,8 @@ struct brcmf_fws_info {
|
|||
u32 fifo_enqpkt[BRCMF_FWS_FIFO_COUNT];
|
||||
int fifo_credit[BRCMF_FWS_FIFO_COUNT];
|
||||
int init_fifo_credit[BRCMF_FWS_FIFO_COUNT];
|
||||
int credits_borrowed[BRCMF_FWS_FIFO_AC_VO + 1];
|
||||
int credits_borrowed[BRCMF_FWS_FIFO_AC_VO + 1]
|
||||
[BRCMF_FWS_FIFO_AC_VO + 1];
|
||||
int deq_node_pos[BRCMF_FWS_FIFO_COUNT];
|
||||
u32 fifo_credit_map;
|
||||
u32 fifo_delay_map;
|
||||
|
@ -521,6 +501,7 @@ struct brcmf_fws_info {
|
|||
bool creditmap_received;
|
||||
u8 mode;
|
||||
bool avoid_queueing;
|
||||
int fifo_init_credit[BRCMF_FWS_FIFO_COUNT];
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -583,15 +564,21 @@ static bool brcmf_fws_ifidx_match(struct sk_buff *skb, void *arg)
|
|||
static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q,
|
||||
int ifidx)
|
||||
{
|
||||
struct brcmf_fws_hanger_item *hi;
|
||||
bool (*matchfn)(struct sk_buff *, void *) = NULL;
|
||||
struct sk_buff *skb;
|
||||
int prec;
|
||||
u32 hslot;
|
||||
|
||||
if (ifidx != -1)
|
||||
matchfn = brcmf_fws_ifidx_match;
|
||||
for (prec = 0; prec < q->num_prec; prec++) {
|
||||
skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
|
||||
while (skb) {
|
||||
hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
|
||||
hi = &fws->hanger.items[hslot];
|
||||
WARN_ON(skb != hi->pkt);
|
||||
hi->state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
|
||||
brcmu_pkt_buf_free_skb(skb);
|
||||
skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
|
||||
}
|
||||
|
@ -1214,13 +1201,11 @@ static void brcmf_fws_return_credits(struct brcmf_fws_info *fws,
|
|||
if (!credits)
|
||||
return;
|
||||
|
||||
fws->fifo_credit_map |= 1 << fifo;
|
||||
|
||||
if ((fifo == BRCMF_FWS_FIFO_AC_BE) &&
|
||||
(fws->credits_borrowed[0])) {
|
||||
if (fifo > BRCMF_FWS_FIFO_AC_BK &&
|
||||
fifo <= BRCMF_FWS_FIFO_AC_VO) {
|
||||
for (lender_ac = BRCMF_FWS_FIFO_AC_VO; lender_ac >= 0;
|
||||
lender_ac--) {
|
||||
borrowed = &fws->credits_borrowed[lender_ac];
|
||||
borrowed = &fws->credits_borrowed[fifo][lender_ac];
|
||||
if (*borrowed) {
|
||||
fws->fifo_credit_map |= (1 << lender_ac);
|
||||
fifo_credit = &fws->fifo_credit[lender_ac];
|
||||
|
@ -1237,7 +1222,11 @@ static void brcmf_fws_return_credits(struct brcmf_fws_info *fws,
|
|||
}
|
||||
}
|
||||
|
||||
fws->fifo_credit[fifo] += credits;
|
||||
if (credits) {
|
||||
fws->fifo_credit[fifo] += credits;
|
||||
fws->fifo_credit_map |= 1 << fifo;
|
||||
}
|
||||
|
||||
if (fws->fifo_credit[fifo] > fws->init_fifo_credit[fifo])
|
||||
fws->fifo_credit[fifo] = fws->init_fifo_credit[fifo];
|
||||
|
||||
|
@ -1635,6 +1624,7 @@ static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp,
|
|||
if (fws->fifo_credit[i] < 0)
|
||||
brcmf_err("fifo_credit[%d] value is negative(%d)\n",
|
||||
i, fws->fifo_credit[i]);
|
||||
fws->fifo_init_credit[i] = fws->fifo_credit[i];
|
||||
}
|
||||
brcmf_fws_schedule_deq(fws);
|
||||
brcmf_fws_unlock(fws);
|
||||
|
@ -1868,6 +1858,9 @@ void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb)
|
|||
|
||||
WARN_ON(siglen > skb->len);
|
||||
|
||||
if (siglen > skb->len)
|
||||
siglen = skb->len;
|
||||
|
||||
if (!siglen)
|
||||
return;
|
||||
/* if flow control disabled, skip to packet data and leave */
|
||||
|
@ -2029,27 +2022,31 @@ static void brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,
|
|||
}
|
||||
}
|
||||
|
||||
static int brcmf_fws_borrow_credit(struct brcmf_fws_info *fws)
|
||||
static int brcmf_fws_borrow_credit(struct brcmf_fws_info *fws,
|
||||
int highest_lender_ac, int borrower_ac,
|
||||
bool borrow_all)
|
||||
{
|
||||
int lender_ac;
|
||||
int lender_ac, borrow_limit = 0;
|
||||
|
||||
if (time_after(fws->borrow_defer_timestamp, jiffies)) {
|
||||
fws->fifo_credit_map &= ~(1 << BRCMF_FWS_FIFO_AC_BE);
|
||||
return -ENAVAIL;
|
||||
}
|
||||
for (lender_ac = 0; lender_ac <= highest_lender_ac; lender_ac++) {
|
||||
|
||||
for (lender_ac = 0; lender_ac <= BRCMF_FWS_FIFO_AC_VO; lender_ac++) {
|
||||
if (fws->fifo_credit[lender_ac] > 0) {
|
||||
fws->credits_borrowed[lender_ac]++;
|
||||
if (!borrow_all)
|
||||
borrow_limit =
|
||||
fws->fifo_credit[lender_ac] / BRCMF_BORROW_RATIO;
|
||||
else
|
||||
borrow_limit = 0;
|
||||
|
||||
if (fws->fifo_credit[lender_ac] > borrow_limit) {
|
||||
fws->credits_borrowed[borrower_ac][lender_ac]++;
|
||||
fws->fifo_credit[lender_ac]--;
|
||||
if (fws->fifo_credit[lender_ac] == 0)
|
||||
fws->fifo_credit_map &= ~(1 << lender_ac);
|
||||
fws->fifo_credit_map |= (1 << BRCMF_FWS_FIFO_AC_BE);
|
||||
fws->fifo_credit_map |= (1 << borrower_ac);
|
||||
brcmf_dbg(DATA, "borrow credit from: %d\n", lender_ac);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
fws->fifo_credit_map &= ~(1 << BRCMF_FWS_FIFO_AC_BE);
|
||||
fws->fifo_credit_map &= ~(1 << borrower_ac);
|
||||
return -ENAVAIL;
|
||||
}
|
||||
|
||||
|
@ -2149,8 +2146,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
|
|||
brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_DELAYED, fifo, skb);
|
||||
brcmf_fws_schedule_deq(fws);
|
||||
} else {
|
||||
brcmf_err("drop skb: no hanger slot\n");
|
||||
brcmf_txfinalize(ifp, skb, false);
|
||||
brcmf_err("no hanger slot available\n");
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
brcmf_fws_unlock(fws);
|
||||
|
@ -2196,12 +2192,43 @@ void brcmf_fws_del_interface(struct brcmf_if *ifp)
|
|||
|
||||
brcmf_fws_lock(fws);
|
||||
ifp->fws_desc = NULL;
|
||||
brcmf_fws_macdesc_cleanup(fws, entry, ifp->ifidx);
|
||||
brcmf_dbg(TRACE, "deleting %s\n", entry->name);
|
||||
brcmf_fws_macdesc_deinit(entry);
|
||||
brcmf_fws_cleanup(fws, ifp->ifidx);
|
||||
brcmf_fws_unlock(fws);
|
||||
}
|
||||
|
||||
static bool brcmf_fws_ismultistream(struct brcmf_fws_info *fws)
|
||||
{
|
||||
bool ret = false;
|
||||
u8 credit_usage = 0;
|
||||
|
||||
/* Check only for BE, VI and VO traffic */
|
||||
u32 delay_map = fws->fifo_delay_map &
|
||||
((1 << BRCMF_FWS_FIFO_AC_BE) |
|
||||
(1 << BRCMF_FWS_FIFO_AC_VI) |
|
||||
(1 << BRCMF_FWS_FIFO_AC_VO));
|
||||
|
||||
if (hweight_long(delay_map) > 1) {
|
||||
ret = true;
|
||||
} else {
|
||||
if (fws->fifo_credit[BRCMF_FWS_FIFO_AC_BE] <
|
||||
fws->fifo_init_credit[BRCMF_FWS_FIFO_AC_BE])
|
||||
credit_usage++;
|
||||
if (fws->fifo_credit[BRCMF_FWS_FIFO_AC_VI] <
|
||||
fws->fifo_init_credit[BRCMF_FWS_FIFO_AC_VI])
|
||||
credit_usage++;
|
||||
if (fws->fifo_credit[BRCMF_FWS_FIFO_AC_VO] <
|
||||
fws->fifo_init_credit[BRCMF_FWS_FIFO_AC_VO])
|
||||
credit_usage++;
|
||||
|
||||
if (credit_usage > 1)
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void brcmf_fws_dequeue_worker(struct work_struct *worker)
|
||||
{
|
||||
struct brcmf_fws_info *fws;
|
||||
|
@ -2215,6 +2242,11 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
|
|||
fws = container_of(worker, struct brcmf_fws_info, fws_dequeue_work);
|
||||
drvr = fws->drvr;
|
||||
|
||||
if (brcmf_fws_ismultistream(fws))
|
||||
drvr->bus_if->allow_skborphan = false;
|
||||
else
|
||||
drvr->bus_if->allow_skborphan = true;
|
||||
|
||||
brcmf_fws_lock(fws);
|
||||
for (fifo = BRCMF_FWS_FIFO_BCMC; fifo >= 0 && !fws->bus_flow_blocked;
|
||||
fifo--) {
|
||||
|
@ -2239,9 +2271,10 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
|
|||
}
|
||||
continue;
|
||||
}
|
||||
while ((fws->fifo_credit[fifo] > 0) ||
|
||||
|
||||
while ((fws->fifo_credit[fifo]) ||
|
||||
((!fws->bcmc_credit_check) &&
|
||||
(fifo == BRCMF_FWS_FIFO_BCMC))) {
|
||||
(fifo == BRCMF_FWS_FIFO_BCMC))) {
|
||||
skb = brcmf_fws_deq(fws, fifo);
|
||||
if (!skb)
|
||||
break;
|
||||
|
@ -2251,10 +2284,14 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
|
|||
if (fws->bus_flow_blocked)
|
||||
break;
|
||||
}
|
||||
if ((fifo == BRCMF_FWS_FIFO_AC_BE) &&
|
||||
(fws->fifo_credit[fifo] <= 0) &&
|
||||
(!fws->bus_flow_blocked)) {
|
||||
while (brcmf_fws_borrow_credit(fws) == 0) {
|
||||
|
||||
if (fifo >= BRCMF_FWS_FIFO_AC_BE &&
|
||||
fifo <= BRCMF_FWS_FIFO_AC_VO &&
|
||||
fws->fifo_credit[fifo] == 0 &&
|
||||
!fws->bus_flow_blocked) {
|
||||
while (brcmf_fws_borrow_credit(fws,
|
||||
fifo - 1, fifo,
|
||||
false) == 0) {
|
||||
skb = brcmf_fws_deq(fws, fifo);
|
||||
if (!skb) {
|
||||
brcmf_fws_return_credits(fws, fifo, 1);
|
||||
|
@ -2345,7 +2382,7 @@ struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr)
|
|||
struct brcmf_if *ifp;
|
||||
u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS;
|
||||
int rc;
|
||||
u32 mode = 0;
|
||||
u32 mode;
|
||||
|
||||
fws = kzalloc(sizeof(*fws), GFP_KERNEL);
|
||||
if (!fws) {
|
||||
|
|
|
@ -18,6 +18,29 @@
|
|||
#ifndef FWSIGNAL_H_
|
||||
#define FWSIGNAL_H_
|
||||
|
||||
/**
|
||||
* enum brcmf_fws_fifo - fifo indices used by dongle firmware.
|
||||
*
|
||||
* @BRCMF_FWS_FIFO_FIRST: first fifo, ie. background.
|
||||
* @BRCMF_FWS_FIFO_AC_BK: fifo for background traffic.
|
||||
* @BRCMF_FWS_FIFO_AC_BE: fifo for best-effort traffic.
|
||||
* @BRCMF_FWS_FIFO_AC_VI: fifo for video traffic.
|
||||
* @BRCMF_FWS_FIFO_AC_VO: fifo for voice traffic.
|
||||
* @BRCMF_FWS_FIFO_BCMC: fifo for broadcast/multicast (AP only).
|
||||
* @BRCMF_FWS_FIFO_ATIM: fifo for ATIM (AP only).
|
||||
* @BRCMF_FWS_FIFO_COUNT: number of fifos.
|
||||
*/
|
||||
enum brcmf_fws_fifo {
|
||||
BRCMF_FWS_FIFO_FIRST,
|
||||
BRCMF_FWS_FIFO_AC_BK = BRCMF_FWS_FIFO_FIRST,
|
||||
BRCMF_FWS_FIFO_AC_BE,
|
||||
BRCMF_FWS_FIFO_AC_VI,
|
||||
BRCMF_FWS_FIFO_AC_VO,
|
||||
BRCMF_FWS_FIFO_BCMC,
|
||||
BRCMF_FWS_FIFO_ATIM,
|
||||
BRCMF_FWS_FIFO_COUNT
|
||||
};
|
||||
|
||||
struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr);
|
||||
void brcmf_fws_detach(struct brcmf_fws_info *fws);
|
||||
bool brcmf_fws_queue_skbs(struct brcmf_fws_info *fws);
|
||||
|
|
|
@ -78,6 +78,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;
|
||||
|
@ -330,7 +331,7 @@ brcmf_msgbuf_alloc_pktid(struct device *dev,
|
|||
do {
|
||||
(*idx)++;
|
||||
if (*idx == pktids->array_size)
|
||||
*idx = 0;
|
||||
*idx = 1;
|
||||
if (array[*idx].allocated.counter == 0)
|
||||
if (atomic_cmpxchg(&array[*idx].allocated, 0, 1) == 0)
|
||||
break;
|
||||
|
@ -793,8 +794,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);
|
||||
|
@ -1112,7 +1117,7 @@ static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf)
|
|||
|
||||
skb->protocol = eth_type_trans(skb, ifp->ndev);
|
||||
|
||||
brcmf_fweh_process_skb(ifp->drvr, skb);
|
||||
brcmf_fweh_process_skb(ifp->drvr, skb, 0);
|
||||
|
||||
exit:
|
||||
brcmu_pkt_buf_free_skb(skb);
|
||||
|
@ -1324,9 +1329,25 @@ 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;
|
||||
|
||||
void *ret_ptr;
|
||||
u8 ifidx;
|
||||
int err;
|
||||
int retry = BRCMF_MAX_TXSTATUS_WAIT_RETRIES;
|
||||
|
||||
/* wait for commonring txflow finished */
|
||||
commonring_del = msgbuf->flowrings[flowid];
|
||||
brcmf_commonring_lock(commonring_del);
|
||||
while (retry && atomic_read(&commonring_del->outstanding_tx)) {
|
||||
usleep_range(5000, 10000);
|
||||
retry--;
|
||||
}
|
||||
brcmf_commonring_unlock(commonring_del);
|
||||
if (!retry && atomic_read(&commonring_del->outstanding_tx)) {
|
||||
brcmf_err("timed out waiting for txstatus\n");
|
||||
atomic_set(&commonring_del->outstanding_tx, 0);
|
||||
}
|
||||
|
||||
commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];
|
||||
brcmf_commonring_lock(commonring);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "fwil_types.h"
|
||||
#include "p2p.h"
|
||||
#include "cfg80211.h"
|
||||
#include "feature.h"
|
||||
|
||||
/* parameters used for p2p escan */
|
||||
#define P2PAPI_SCAN_NPROBES 1
|
||||
|
@ -70,12 +71,13 @@
|
|||
#define P2P_AF_MIN_DWELL_TIME 100
|
||||
#define P2P_AF_MED_DWELL_TIME 400
|
||||
#define P2P_AF_LONG_DWELL_TIME 1000
|
||||
#define P2P_AF_TX_MAX_RETRY 1
|
||||
#define P2P_AF_TX_MAX_RETRY 5
|
||||
#define P2P_AF_MAX_WAIT_TIME msecs_to_jiffies(2000)
|
||||
#define P2P_INVALID_CHANNEL -1
|
||||
#define P2P_CHANNEL_SYNC_RETRY 5
|
||||
#define P2P_AF_FRM_SCAN_MAX_WAIT msecs_to_jiffies(450)
|
||||
#define P2P_DEFAULT_SLEEP_TIME_VSDB 200
|
||||
#define P2P_AF_RETRY_DELAY_TIME 40
|
||||
|
||||
/* WiFi P2P Public Action Frame OUI Subtypes */
|
||||
#define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */
|
||||
|
@ -103,6 +105,9 @@
|
|||
#define P2PSD_ACTION_ID_GAS_CRESP 0x0d /* GAS Comback Response AF */
|
||||
|
||||
#define BRCMF_P2P_DISABLE_TIMEOUT msecs_to_jiffies(500)
|
||||
|
||||
/* Mask for retry counter of custom dwell time */
|
||||
#define CUSTOM_RETRY_MASK 0xff000000
|
||||
/**
|
||||
* struct brcmf_p2p_disc_st_le - set discovery state in firmware.
|
||||
*
|
||||
|
@ -498,9 +503,13 @@ static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr)
|
|||
* BSSCFGs need to simultaneously co-exist, then this address must be
|
||||
* different from the P2P Device Address, but also locally administered.
|
||||
*/
|
||||
memcpy(p2p->int_addr, p2p->dev_addr, ETH_ALEN);
|
||||
p2p->int_addr[0] |= 0x02;
|
||||
p2p->int_addr[4] ^= 0x80;
|
||||
memcpy(p2p->conn_int_addr, p2p->dev_addr, ETH_ALEN);
|
||||
p2p->conn_int_addr[0] |= 0x02;
|
||||
p2p->conn_int_addr[4] ^= 0x80;
|
||||
|
||||
memcpy(p2p->conn2_int_addr, p2p->dev_addr, ETH_ALEN);
|
||||
p2p->conn2_int_addr[0] |= 0x02;
|
||||
p2p->conn2_int_addr[4] ^= 0x90;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1667,6 +1676,17 @@ static s32 brcmf_p2p_pub_af_tx(struct brcmf_cfg80211_info *cfg,
|
|||
return err;
|
||||
}
|
||||
|
||||
static bool brcmf_p2p_check_dwell_overflow(s32 requested_dwell,
|
||||
unsigned long dwell_jiffies)
|
||||
{
|
||||
if ((requested_dwell & CUSTOM_RETRY_MASK) &&
|
||||
(jiffies_to_msecs(jiffies - dwell_jiffies) >
|
||||
(requested_dwell & ~CUSTOM_RETRY_MASK))) {
|
||||
brcmf_err("Action frame TX retry time over dwell time!\n");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* brcmf_p2p_send_action_frame() - send action frame .
|
||||
*
|
||||
|
@ -1690,6 +1710,10 @@ bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg,
|
|||
s32 tx_retry;
|
||||
s32 extra_listen_time;
|
||||
uint delta_ms;
|
||||
unsigned long dwell_jiffies = 0;
|
||||
bool dwell_overflow = false;
|
||||
|
||||
s32 requested_dwell = af_params->dwell_time;
|
||||
|
||||
action_frame = &af_params->action_frame;
|
||||
action_frame_len = le16_to_cpu(action_frame->len);
|
||||
|
@ -1801,12 +1825,21 @@ bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg,
|
|||
/* update channel */
|
||||
af_params->channel = cpu_to_le32(afx_hdl->peer_chan);
|
||||
}
|
||||
dwell_jiffies = jiffies;
|
||||
dwell_overflow = brcmf_p2p_check_dwell_overflow(requested_dwell,
|
||||
dwell_jiffies);
|
||||
|
||||
tx_retry = 0;
|
||||
while (!p2p->block_gon_req_tx &&
|
||||
(ack == false) && (tx_retry < P2P_AF_TX_MAX_RETRY)) {
|
||||
(!ack) && (tx_retry < P2P_AF_TX_MAX_RETRY) &&
|
||||
!dwell_overflow) {
|
||||
if (af_params->channel)
|
||||
msleep(P2P_AF_RETRY_DELAY_TIME);
|
||||
|
||||
ack = !brcmf_p2p_tx_action_frame(p2p, af_params);
|
||||
tx_retry++;
|
||||
dwell_overflow = brcmf_p2p_check_dwell_overflow(requested_dwell,
|
||||
dwell_jiffies);
|
||||
}
|
||||
if (ack == false) {
|
||||
brcmf_err("Failed to send Action Frame(retry %d)\n", tx_retry);
|
||||
|
@ -2019,7 +2052,7 @@ int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
|
|||
|
||||
if_request.type = cpu_to_le16((u16)if_type);
|
||||
if_request.chspec = cpu_to_le16(chanspec);
|
||||
memcpy(if_request.addr, p2p->int_addr, sizeof(if_request.addr));
|
||||
memcpy(if_request.addr, p2p->conn_int_addr, sizeof(if_request.addr));
|
||||
|
||||
brcmf_cfg80211_arm_vif_event(cfg, vif);
|
||||
err = brcmf_fil_iovar_data_set(vif->ifp, "p2p_ifupd", &if_request,
|
||||
|
@ -2165,6 +2198,27 @@ fail:
|
|||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
int brcmf_p2p_get_conn_idx(struct brcmf_cfg80211_info *cfg)
|
||||
{
|
||||
int i;
|
||||
struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
|
||||
|
||||
if (!ifp)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = P2PAPI_BSSCFG_CONNECTION; i < P2PAPI_BSSCFG_MAX; i++) {
|
||||
if (!cfg->p2p.bss_idx[i].vif) {
|
||||
if (i == P2PAPI_BSSCFG_CONNECTION2 &&
|
||||
!(brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
|
||||
brcmf_err("Multi p2p not supported");
|
||||
return -EIO;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/**
|
||||
* brcmf_p2p_add_vif() - create a new P2P virtual interface.
|
||||
*
|
||||
|
@ -2183,7 +2237,9 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
|
|||
struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
|
||||
struct brcmf_cfg80211_vif *vif;
|
||||
enum brcmf_fil_p2p_if_types iftype;
|
||||
int err;
|
||||
int err = 0;
|
||||
int connidx;
|
||||
u8 *p2p_intf_addr;
|
||||
|
||||
if (brcmf_cfg80211_vif_event_armed(cfg))
|
||||
return ERR_PTR(-EBUSY);
|
||||
|
@ -2209,9 +2265,21 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
|
|||
return (struct wireless_dev *)vif;
|
||||
brcmf_cfg80211_arm_vif_event(cfg, vif);
|
||||
|
||||
err = brcmf_p2p_request_p2p_if(&cfg->p2p, ifp, cfg->p2p.int_addr,
|
||||
iftype);
|
||||
connidx = brcmf_p2p_get_conn_idx(cfg);
|
||||
|
||||
if (connidx == P2PAPI_BSSCFG_CONNECTION)
|
||||
p2p_intf_addr = cfg->p2p.conn_int_addr;
|
||||
else if (connidx == P2PAPI_BSSCFG_CONNECTION2)
|
||||
p2p_intf_addr = cfg->p2p.conn2_int_addr;
|
||||
else
|
||||
err = -EINVAL;
|
||||
|
||||
if (!err)
|
||||
err = brcmf_p2p_request_p2p_if(&cfg->p2p, ifp,
|
||||
p2p_intf_addr, iftype);
|
||||
|
||||
if (err) {
|
||||
brcmf_err("request p2p interface failed\n");
|
||||
brcmf_cfg80211_arm_vif_event(cfg, NULL);
|
||||
goto fail;
|
||||
}
|
||||
|
@ -2243,7 +2311,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
cfg->p2p.bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = vif;
|
||||
cfg->p2p.bss_idx[connidx].vif = vif;
|
||||
/* Disable firmware roaming for P2P interface */
|
||||
brcmf_fil_iovar_int_set(ifp, "roam_off", 1);
|
||||
if (iftype == BRCMF_FIL_P2P_IF_GO) {
|
||||
|
|
|
@ -25,13 +25,15 @@ struct brcmf_cfg80211_info;
|
|||
*
|
||||
* @P2PAPI_BSSCFG_PRIMARY: maps to driver's primary bsscfg.
|
||||
* @P2PAPI_BSSCFG_DEVICE: maps to driver's P2P device discovery bsscfg.
|
||||
* @P2PAPI_BSSCFG_CONNECTION: maps to driver's P2P connection bsscfg.
|
||||
* @P2PAPI_BSSCFG_CONNECTION: maps to driver's 1st P2P connection bsscfg.
|
||||
* @P2PAPI_BSSCFG_CONNECTION2: maps to driver's 2nd P2P connection bsscfg.
|
||||
* @P2PAPI_BSSCFG_MAX: used for range checking.
|
||||
*/
|
||||
enum p2p_bss_type {
|
||||
P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */
|
||||
P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */
|
||||
P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */
|
||||
P2PAPI_BSSCFG_CONNECTION, /* driver's 1st P2P connection bsscfg */
|
||||
P2PAPI_BSSCFG_CONNECTION2, /* driver's 2nd P2P connection bsscfg */
|
||||
P2PAPI_BSSCFG_MAX
|
||||
};
|
||||
|
||||
|
@ -130,7 +132,8 @@ struct brcmf_p2p_info {
|
|||
struct brcmf_cfg80211_info *cfg;
|
||||
unsigned long status;
|
||||
u8 dev_addr[ETH_ALEN];
|
||||
u8 int_addr[ETH_ALEN];
|
||||
u8 conn_int_addr[ETH_ALEN];
|
||||
u8 conn2_int_addr[ETH_ALEN];
|
||||
struct p2p_bss bss_idx[P2PAPI_BSSCFG_MAX];
|
||||
struct timer_list listen_timer;
|
||||
u8 listen_channel;
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "chip.h"
|
||||
#include "core.h"
|
||||
#include "common.h"
|
||||
#include "cfg80211.h"
|
||||
|
||||
|
||||
enum brcmf_pcie_state {
|
||||
|
@ -78,7 +79,7 @@ static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
|
|||
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371),
|
||||
};
|
||||
|
||||
#define BRCMF_PCIE_FW_UP_TIMEOUT 2000 /* msec */
|
||||
#define BRCMF_PCIE_FW_UP_TIMEOUT 5000 /* msec */
|
||||
|
||||
#define BRCMF_PCIE_REG_MAP_SIZE (32 * 1024)
|
||||
|
||||
|
@ -671,7 +672,6 @@ brcmf_pcie_send_mb_data(struct brcmf_pciedev_info *devinfo, u32 htod_mb_data)
|
|||
|
||||
brcmf_pcie_write_tcm32(devinfo, addr, htod_mb_data);
|
||||
pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_SBMBX, 1);
|
||||
pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_SBMBX, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1888,11 +1888,22 @@ static int brcmf_pcie_pm_enter_D3(struct device *dev)
|
|||
{
|
||||
struct brcmf_pciedev_info *devinfo;
|
||||
struct brcmf_bus *bus;
|
||||
struct brcmf_cfg80211_info *config;
|
||||
int retry = BRCMF_PM_WAIT_MAXRETRY;
|
||||
|
||||
brcmf_dbg(PCIE, "Enter\n");
|
||||
|
||||
bus = dev_get_drvdata(dev);
|
||||
devinfo = bus->bus_priv.pcie->devinfo;
|
||||
config = bus->drvr->config;
|
||||
|
||||
while (retry &&
|
||||
config->pm_state == BRCMF_CFG80211_PM_STATE_SUSPENDING) {
|
||||
usleep_range(10000, 20000);
|
||||
retry--;
|
||||
}
|
||||
if (!retry && config->pm_state == BRCMF_CFG80211_PM_STATE_SUSPENDING)
|
||||
brcmf_err("timed out wait for cfg80211 suspended\n");
|
||||
|
||||
brcmf_bus_change_state(bus, BRCMF_BUS_DOWN);
|
||||
|
||||
|
@ -1972,6 +1983,7 @@ static const struct dev_pm_ops brcmf_pciedrvr_pm = {
|
|||
|
||||
static const struct pci_device_id brcmf_pcie_devid_table[] = {
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID),
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_4354_RAW_DEVICE_ID),
|
||||
BRCMF_PCIE_DEVICE_SUB(BRCM_PCIE_4355_DEVICE_ID,BRCM_PCIE_VENDOR_ID_BROADCOM,BRCM_PCIE_4355_DEVICE_ID),
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID),
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID),
|
||||
|
|
|
@ -53,10 +53,17 @@
|
|||
|
||||
#define DEFAULT_F2_WATERMARK 0x8
|
||||
#define CY_4373_F2_WATERMARK 0x40
|
||||
#define CY_4373_F1_MESBUSYCTRL (CY_4373_F2_WATERMARK | SBSDIO_MESBUSYCTRL_ENAB)
|
||||
#define CY_43012_F2_WATERMARK 0x60
|
||||
#define CY_4339_F2_WATERMARK 48
|
||||
#define CY_43455_F2_WATERMARK 0x60
|
||||
#define CY_43455_MES_WATERMARK 0x50
|
||||
#define CY_43455_MESBUSYCTRL (CY_43455_MES_WATERMARK | \
|
||||
SBSDIO_MESBUSYCTRL_ENAB)
|
||||
#define CY_4339_F2_WATERMARK 48
|
||||
#define CY_4339_MES_WATERMARK 80
|
||||
#define CY_4339_MESBUSYCTRL (CY_4339_MES_WATERMARK | SBSDIO_MESBUSYCTRL_ENAB)
|
||||
#define CY_4359_F2_WATERMARK 0x40
|
||||
#define CY_4359_F1_MESBUSYCTRL (CY_4359_F2_WATERMARK | SBSDIO_MESBUSYCTRL_ENAB)
|
||||
#ifdef DEBUG
|
||||
|
||||
#define BRCMF_TRAP_INFO_SIZE 80
|
||||
|
@ -270,10 +277,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
|
||||
|
@ -329,6 +337,10 @@ struct rte_console {
|
|||
static void brcmf_sdio_firmware_callback(struct device *dev, int err,
|
||||
const struct firmware *code,
|
||||
void *nvram, u32 nvram_len);
|
||||
static int brcmf_sdio_f2_ready(struct brcmf_sdio *bus);
|
||||
static int brcmf_ulp_event_notify(struct brcmf_if *ifp,
|
||||
const struct brcmf_event_msg *evtmsg,
|
||||
void *data);
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Device console log buffer state */
|
||||
|
@ -623,6 +635,7 @@ BRCMF_FW_NVRAM_DEF(43430A1, "brcmfmac43430-sdio.bin", "brcmfmac43430-sdio.txt");
|
|||
BRCMF_FW_NVRAM_DEF(43455, "brcmfmac43455-sdio.bin", "brcmfmac43455-sdio.txt");
|
||||
BRCMF_FW_NVRAM_DEF(4354, "brcmfmac4354-sdio.bin", "brcmfmac4354-sdio.txt");
|
||||
BRCMF_FW_NVRAM_DEF(4356, "brcmfmac4356-sdio.bin", "brcmfmac4356-sdio.txt");
|
||||
BRCMF_FW_NVRAM_DEF(4359, "brcmfmac4359-sdio.bin", "brcmfmac4359-sdio.txt");
|
||||
BRCMF_FW_NVRAM_DEF(4373, "brcmfmac4373-sdio.bin", "brcmfmac4373-sdio.txt");
|
||||
BRCMF_FW_NVRAM_DEF(43012, "brcmfmac43012-sdio.bin", "brcmfmac43012-sdio.txt");
|
||||
|
||||
|
@ -644,6 +657,7 @@ static struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
|
|||
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFFC0, 43455),
|
||||
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354),
|
||||
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356),
|
||||
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359),
|
||||
BRCMF_FW_NVRAM_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373),
|
||||
BRCMF_FW_NVRAM_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012)
|
||||
};
|
||||
|
@ -787,6 +801,7 @@ static int brcmf_sdio_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
|
|||
clkreq =
|
||||
bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
|
||||
|
||||
printk("[---- SBA ----] Sending SBSDIO_FUNC1_CHIPCLKCSR/SBSDIO_HT_AVAIL_REQ ..\n");
|
||||
brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
|
||||
clkreq, &err);
|
||||
if (err) {
|
||||
|
@ -1092,7 +1107,7 @@ static void brcmf_sdio_get_console_addr(struct brcmf_sdio *bus)
|
|||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus)
|
||||
static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus, u32 *hmbd)
|
||||
{
|
||||
u32 intstatus = 0;
|
||||
u32 hmb_data;
|
||||
|
@ -1110,6 +1125,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",
|
||||
|
@ -1167,9 +1186,13 @@ 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);
|
||||
/* Populate hmb_data if argument is passed for DS1 check later */
|
||||
if (hmbd)
|
||||
*hmbd = hmb_data;
|
||||
|
||||
return intstatus;
|
||||
}
|
||||
|
@ -2560,23 +2583,21 @@ brcmf_sdio_ulp_preinit(struct device *dev)
|
|||
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
|
||||
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
|
||||
struct brcmf_if *ifp = bus_if->drvr->iflist[0];
|
||||
s32 err = 0;
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
brcmf_dbg(ULP, "Enter\n");
|
||||
|
||||
/* Query ulp_sdioctrl iovar to get the ULP related SHM offsets */
|
||||
err = brcmf_fil_iovar_data_get(ifp, "ulp_sdioctrl", &sdiodev->shm_ulp,
|
||||
sizeof(sdiodev->shm_ulp));
|
||||
if (err)
|
||||
brcmf_err("ulp_sdioctrl iovar returned err = %d\n", err);
|
||||
brcmf_fil_iovar_data_get(ifp, "ulp_sdioctrl",
|
||||
&sdiodev->fmac_ulp.ulp_shm_offset,
|
||||
sizeof(sdiodev->fmac_ulp.ulp_shm_offset));
|
||||
|
||||
sdiodev->ulp = false;
|
||||
|
||||
brcmf_dbg(TRACE, "m_ulp_ctrl_sdio[%x] m_ulp_wakeevt_ind [%x]\n",
|
||||
M_DS1_CTRL_SDIO(sdiodev->shm_ulp),
|
||||
M_WAKEEVENT_IND(sdiodev->shm_ulp));
|
||||
brcmf_dbg(TRACE, "m_ulp_wakeind [%x]\n",
|
||||
M_ULP_WAKE_IND(sdiodev->shm_ulp));
|
||||
brcmf_dbg(ULP, "m_ulp_ctrl_sdio[%x] m_ulp_wakeevt_ind [%x]\n",
|
||||
M_DS1_CTRL_SDIO(sdiodev->fmac_ulp),
|
||||
M_WAKEEVENT_IND(sdiodev->fmac_ulp));
|
||||
brcmf_dbg(ULP, "m_ulp_wakeind [%x]\n",
|
||||
M_ULP_WAKE_IND(sdiodev->fmac_ulp));
|
||||
}
|
||||
|
||||
/* Reinitialize ARM because In DS1 mode ARM got off */
|
||||
|
@ -2604,41 +2625,68 @@ brcmf_sdio_ulp_reinit_fw(struct brcmf_sdio *bus)
|
|||
|
||||
/* Check if device is in DS1 mode and handshake with ULP UCODE */
|
||||
static bool
|
||||
brcmf_sdio_ulp_pre_redownload_check(struct brcmf_sdio *bus)
|
||||
brcmf_sdio_ulp_pre_redownload_check(struct brcmf_sdio *bus, u32 hmb_data)
|
||||
{
|
||||
int err = 0;
|
||||
u32 value = 0;
|
||||
u32 val32, ulp_wake_ind, wowl_wake_ind;
|
||||
int reg_addr;
|
||||
unsigned long timeout;
|
||||
struct brcmf_ulp *fmac_ulp = &bus->sdiodev->fmac_ulp;
|
||||
int i = 0;
|
||||
|
||||
/* If any host mail box data is present, ignore DS1 exit sequence */
|
||||
if (hmb_data)
|
||||
return false;
|
||||
/* Skip if DS1 Exit is already in progress
|
||||
* This can happen if firmware download is taking more time
|
||||
*/
|
||||
if (fmac_ulp->ulp_state == FMAC_ULP_TRIGGERED)
|
||||
return false;
|
||||
|
||||
value = brcmf_sdiod_regrb(bus->sdiodev, SDIO_CCCR_IOEx, &err);
|
||||
|
||||
if (value == SDIO_FUNC_ENABLE_1) {
|
||||
brcmf_dbg(SDIO, "GOT THE INTERRUPT FROM UCODE\n");
|
||||
brcmf_dbg(ULP, "GOT THE INTERRUPT FROM UCODE\n");
|
||||
bus->sdiodev->ulp = true;
|
||||
ulp_wake_ind = D11SHM_RD(bus->sdiodev, M_ULP_WAKE_IND(
|
||||
bus->sdiodev->shm_ulp), &err) >> 16;
|
||||
wowl_wake_ind = D11SHM_RD(bus->sdiodev, M_WAKEEVENT_IND(
|
||||
bus->sdiodev->shm_ulp), &err) >> 16;
|
||||
fmac_ulp->ulp_state = FMAC_ULP_TRIGGERED;
|
||||
ulp_wake_ind = D11SHM_RDW(bus->sdiodev, M_ULP_WAKE_IND(
|
||||
bus->sdiodev->fmac_ulp), &err);
|
||||
wowl_wake_ind = D11SHM_RDW(bus->sdiodev, M_WAKEEVENT_IND(
|
||||
bus->sdiodev->fmac_ulp), &err);
|
||||
|
||||
brcmf_dbg(SDIO, "wowl_wake_ind: 0x%08x, ulp_wake_ind: 0x%08x\n",
|
||||
wowl_wake_ind, ulp_wake_ind);
|
||||
brcmf_dbg(ULP, "wowl_wake_ind: 0x%08x, ulp_wake_ind: 0x%08x state %s\n",
|
||||
wowl_wake_ind, ulp_wake_ind, (fmac_ulp->ulp_state) ?
|
||||
"DS1 Exit Triggered" : "IDLE State");
|
||||
|
||||
if (wowl_wake_ind || ulp_wake_ind) {
|
||||
/* TX wake Don't do anything.
|
||||
/* RX wake Don't do anything.
|
||||
* Just bail out and re-download firmware.
|
||||
*/
|
||||
/* Print out PHY TX error block when bit 9 set */
|
||||
if ((ulp_wake_ind & C_DS1_PHY_TXERR) &&
|
||||
M_DS1_PHYTX_ERR_BLK(bus->sdiodev->fmac_ulp)) {
|
||||
brcmf_err("Dump PHY TX Error SHM Locations\n");
|
||||
for (i = 0; i < PHYTX_ERR_BLK_SIZE; i++) {
|
||||
pr_err("0x%x", D11SHM_RDW(bus->sdiodev,
|
||||
(M_DS1_PHYTX_ERR_BLK
|
||||
(bus->sdiodev->fmac_ulp) +
|
||||
(i * 2)), &err));
|
||||
}
|
||||
brcmf_err("\n");
|
||||
}
|
||||
} else {
|
||||
/* RX wake negotiate with MAC */
|
||||
brcmf_dbg(SDIO, "M_DS1_CTRL_SDIO: 0x%08x\n",
|
||||
(u32)D11SHM_RD(bus->sdiodev,
|
||||
M_DS1_CTRL_SDIO(bus->sdiodev->shm_ulp),
|
||||
/* TX wake negotiate with MAC */
|
||||
brcmf_dbg(ULP, "M_DS1_CTRL_SDIO: 0x%08x\n",
|
||||
(u32)D11SHM_RDW(bus->sdiodev,
|
||||
M_DS1_CTRL_SDIO(bus->sdiodev->fmac_ulp),
|
||||
&err));
|
||||
val32 = D11SHM_RD(bus->sdiodev, M_DS1_CTRL_SDIO(
|
||||
bus->sdiodev->fmac_ulp), &err);
|
||||
D11SHM_WR(bus->sdiodev, M_DS1_CTRL_SDIO(
|
||||
bus->sdiodev->shm_ulp),
|
||||
C_DS1_CTRL_SDIO_DS1_EXIT |
|
||||
C_DS1_CTRL_REQ_VALID,
|
||||
bus->sdiodev->fmac_ulp), val32,
|
||||
(C_DS1_CTRL_SDIO_DS1_EXIT |
|
||||
C_DS1_CTRL_REQ_VALID),
|
||||
&err);
|
||||
val32 = D11REG_RD(bus->sdiodev,
|
||||
D11_MACCONTROL_REG, &err);
|
||||
|
@ -2647,37 +2695,38 @@ brcmf_sdio_ulp_pre_redownload_check(struct brcmf_sdio *bus)
|
|||
D11_MACCONTROL_REG, val32, &err);
|
||||
|
||||
/* Poll for PROC_DONE to be set by ucode */
|
||||
value = D11SHM_RD(bus->sdiodev,
|
||||
M_DS1_CTRL_SDIO(
|
||||
bus->sdiodev->shm_ulp), &err);
|
||||
value = D11SHM_RDW(bus->sdiodev,
|
||||
M_DS1_CTRL_SDIO(
|
||||
bus->sdiodev->fmac_ulp), &err);
|
||||
/* Wait here (polling) for C_DS1_CTRL_PROC_DONE */
|
||||
timeout = jiffies + ULP_HUDI_PROC_DONE_TIME;
|
||||
while (!(value & C_DS1_CTRL_PROC_DONE)) {
|
||||
value = D11SHM_RD(bus->sdiodev,
|
||||
M_DS1_CTRL_SDIO(
|
||||
bus->sdiodev->shm_ulp), &err);
|
||||
value = D11SHM_RDW(bus->sdiodev,
|
||||
M_DS1_CTRL_SDIO
|
||||
(bus->sdiodev->fmac_ulp),
|
||||
&err);
|
||||
if (time_after(jiffies, timeout))
|
||||
break;
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
brcmf_dbg(SDIO, "M_DS1_CTRL_SDIO: 0x%08x\n",
|
||||
(u32)D11SHM_RD(bus->sdiodev,
|
||||
brcmf_dbg(ULP, "M_DS1_CTRL_SDIO: 0x%08x\n",
|
||||
(u32)D11SHM_RDW(bus->sdiodev,
|
||||
M_DS1_CTRL_SDIO(
|
||||
bus->sdiodev->shm_ulp), &err));
|
||||
value = D11SHM_RD(bus->sdiodev,
|
||||
M_DS1_CTRL_SDIO(
|
||||
bus->sdiodev->shm_ulp), &err);
|
||||
bus->sdiodev->fmac_ulp), &err));
|
||||
value = D11SHM_RDW(bus->sdiodev,
|
||||
M_DS1_CTRL_SDIO(
|
||||
bus->sdiodev->fmac_ulp), &err);
|
||||
if (!(value & C_DS1_CTRL_PROC_DONE)) {
|
||||
brcmf_err("%s: timeout Failed to enter DS1 Exit state!\n",
|
||||
__func__);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ulp_wake_ind = D11SHM_RD(bus->sdiodev, M_ULP_WAKE_IND(
|
||||
bus->sdiodev->shm_ulp), &err) >> 16;
|
||||
wowl_wake_ind = D11SHM_RD(bus->sdiodev, M_WAKEEVENT_IND(
|
||||
bus->sdiodev->shm_ulp), &err) >> 16;
|
||||
brcmf_dbg(SDIO, "wowl_wake_ind: 0x%08x, ulp_wake_ind: 0x%08x\n",
|
||||
ulp_wake_ind = D11SHM_RDW(bus->sdiodev, M_ULP_WAKE_IND(
|
||||
bus->sdiodev->fmac_ulp), &err);
|
||||
wowl_wake_ind = D11SHM_RDW(bus->sdiodev, M_WAKEEVENT_IND(
|
||||
bus->sdiodev->fmac_ulp), &err);
|
||||
brcmf_dbg(ULP, "wowl_wake_ind: 0x%08x, ulp_wake_ind: 0x%08x\n",
|
||||
wowl_wake_ind, ulp_wake_ind);
|
||||
reg_addr = CORE_CC_REG(
|
||||
brcmf_chip_get_pmu(bus->ci)->base, min_res_mask);
|
||||
|
@ -2762,9 +2811,10 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
|
|||
|
||||
/* Handle host mailbox indication */
|
||||
if (intstatus & I_HMB_HOST_INT) {
|
||||
u32 hmb_data = 0;
|
||||
intstatus &= ~I_HMB_HOST_INT;
|
||||
intstatus |= brcmf_sdio_hostmail(bus);
|
||||
if (brcmf_sdio_ulp_pre_redownload_check(bus))
|
||||
intstatus |= brcmf_sdio_hostmail(bus, &hmb_data);
|
||||
if (brcmf_sdio_ulp_pre_redownload_check(bus, hmb_data))
|
||||
brcmf_sdio_ulp_reinit_fw(bus);
|
||||
}
|
||||
|
||||
|
@ -2810,13 +2860,14 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
|
|||
brcmf_sdio_clrintr(bus);
|
||||
|
||||
if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) &&
|
||||
data_ok(bus)) {
|
||||
data_ok(bus) && brcmf_sdio_f2_ready(bus)) {
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
if (bus->ctrl_frame_stat) {
|
||||
err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf,
|
||||
err = brcmf_sdio_tx_ctrlframe(bus,
|
||||
bus->ctrl_frame_buf,
|
||||
bus->ctrl_frame_len);
|
||||
bus->ctrl_frame_err = err;
|
||||
wmb();
|
||||
wmb(); /* drain writebuffer */
|
||||
bus->ctrl_frame_stat = false;
|
||||
}
|
||||
sdio_release_host(bus->sdiodev->func[1]);
|
||||
|
@ -3532,8 +3583,10 @@ static void brcmf_sdio_sr_init(struct brcmf_sdio *bus)
|
|||
}
|
||||
|
||||
if (bus->ci->chip == CY_CC_43012_CHIP_ID ||
|
||||
bus->ci->chip == CY_CC_4373_CHIP_ID ||
|
||||
bus->ci->chip == BRCM_CC_4339_CHIP_ID ||
|
||||
bus->ci->chip == BRCM_CC_4354_CHIP_ID ||
|
||||
bus->ci->chip == BRCM_CC_4356_CHIP_ID ||
|
||||
bus->ci->chip == BRCM_CC_4345_CHIP_ID) {
|
||||
cardcap = SDIO_CCCR_BRCM_CARDCAP_CMD_NODEC;
|
||||
} else {
|
||||
|
@ -3807,7 +3860,11 @@ static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
|
|||
if (bus->idlecount > bus->idletime) {
|
||||
brcmf_dbg(SDIO, "idle\n");
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
brcmf_sdio_wd_timer(bus, false);
|
||||
#ifdef DEBUG
|
||||
if (!BRCMF_FWCON_ON() ||
|
||||
bus->console_interval == 0)
|
||||
#endif
|
||||
brcmf_sdio_wd_timer(bus, false);
|
||||
bus->idlecount = 0;
|
||||
brcmf_sdio_bus_sleep(bus, true, false);
|
||||
sdio_release_host(bus->sdiodev->func[1]);
|
||||
|
@ -4219,7 +4276,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
|
|||
u8 saveclk;
|
||||
u8 devctl;
|
||||
|
||||
brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err);
|
||||
brcmf_dbg(ULP, "Enter: dev=%s, err=%d\n", dev_name(dev), err);
|
||||
bus_if = dev_get_drvdata(dev);
|
||||
sdiodev = bus_if->bus_priv.sdio;
|
||||
if (err)
|
||||
|
@ -4287,6 +4344,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
|
|||
devctl = brcmf_sdiod_regrb(sdiodev, SBSDIO_DEVICE_CTL, &err);
|
||||
devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
|
||||
brcmf_sdiod_regwb(sdiodev, SBSDIO_DEVICE_CTL, devctl, &err);
|
||||
brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_MESBUSYCTRL, CY_4373_F1_MESBUSYCTRL, &err);
|
||||
break;
|
||||
case SDIO_DEVICE_ID_CYPRESS_43012:
|
||||
brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes for 43012\n",
|
||||
|
@ -4299,6 +4357,22 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
|
|||
devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
|
||||
brcmf_sdiod_regwb(sdiodev,
|
||||
SBSDIO_DEVICE_CTL, devctl, &err);
|
||||
/* Register for ULP events */
|
||||
brcmf_fweh_register(bus_if->drvr, BRCMF_E_ULP,
|
||||
brcmf_ulp_event_notify);
|
||||
break;
|
||||
case SDIO_DEVICE_ID_BROADCOM_43455:
|
||||
brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes for 43455\n",
|
||||
CY_43455_F2_WATERMARK);
|
||||
brcmf_sdiod_regwb(sdiodev, SBSDIO_WATERMARK,
|
||||
CY_43455_F2_WATERMARK, &err);
|
||||
devctl = brcmf_sdiod_regrb(sdiodev, SBSDIO_DEVICE_CTL,
|
||||
&err);
|
||||
devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
|
||||
brcmf_sdiod_regwb(sdiodev, SBSDIO_DEVICE_CTL, devctl,
|
||||
&err);
|
||||
brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_MESBUSYCTRL,
|
||||
CY_43455_MESBUSYCTRL, &err);
|
||||
break;
|
||||
case SDIO_DEVICE_ID_BROADCOM_4339:
|
||||
brcmf_sdiod_regwb(sdiodev,
|
||||
|
@ -4312,6 +4386,19 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
|
|||
brcmf_sdiod_regwb(sdiodev,
|
||||
SBSDIO_FUNC1_MESBUSYCTRL, CY_4339_MESBUSYCTRL, &err);
|
||||
break;
|
||||
case SDIO_DEVICE_ID_BROADCOM_4359:
|
||||
brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes\n",
|
||||
CY_4359_F2_WATERMARK);
|
||||
brcmf_sdiod_regwb(sdiodev, SBSDIO_WATERMARK,
|
||||
CY_4359_F2_WATERMARK, &err);
|
||||
devctl = brcmf_sdiod_regrb(sdiodev, SBSDIO_DEVICE_CTL,
|
||||
&err);
|
||||
devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
|
||||
brcmf_sdiod_regwb(sdiodev, SBSDIO_DEVICE_CTL, devctl,
|
||||
&err);
|
||||
brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_MESBUSYCTRL,
|
||||
CY_4359_F1_MESBUSYCTRL, &err);
|
||||
break;
|
||||
default:
|
||||
brcmf_sdiod_regwb(sdiodev, SBSDIO_WATERMARK, DEFAULT_F2_WATERMARK, &err);
|
||||
break;
|
||||
|
@ -4355,6 +4442,12 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
|
|||
brcmf_err("dongle is not responding\n");
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
/* For ULP, after firmware redownload complete
|
||||
* set ULP state to IDLE
|
||||
*/
|
||||
if (bus->sdiodev->fmac_ulp.ulp_state == FMAC_ULP_TRIGGERED)
|
||||
bus->sdiodev->fmac_ulp.ulp_state = FMAC_ULP_IDLE;
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -4373,9 +4466,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
|
|||
struct brcmf_sdio *bus;
|
||||
struct workqueue_struct *wq;
|
||||
|
||||
printk("[--- SBA ---] brcmf_sdio_probe ENTER !!\n");
|
||||
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
/* Allocate private bus interface state */
|
||||
|
@ -4547,7 +4637,17 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
|
|||
* necessary cores.
|
||||
*/
|
||||
msleep(20);
|
||||
brcmf_chip_set_passive(bus->ci);
|
||||
if (bus->sdiodev->fmac_ulp.ulp_state ==
|
||||
FMAC_ULP_ENTRY_RECV) {
|
||||
brcmf_chip_ulp_reset_lhl_regs(bus->ci);
|
||||
brcmf_chip_reset_pmu_regs(bus->ci);
|
||||
} else {
|
||||
brcmf_chip_set_passive(bus->ci);
|
||||
}
|
||||
/* Reset the PMU, backplane and all the
|
||||
* cores by using the PMUWatchdogCounter.
|
||||
*/
|
||||
brcmf_chip_reset_watchdog(bus->ci);
|
||||
brcmf_sdio_clkctl(bus, CLK_NONE, false);
|
||||
sdio_release_host(bus->sdiodev->func[1]);
|
||||
}
|
||||
|
@ -4603,3 +4703,41 @@ int brcmf_sdio_sleep(struct brcmf_sdio *bus, bool sleep)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Check F2 Ready bit before sending data to Firmware */
|
||||
static int
|
||||
brcmf_sdio_f2_ready(struct brcmf_sdio *bus)
|
||||
{
|
||||
int ret = -1;
|
||||
int iordy_status = 0;
|
||||
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
/* Read the status of IOR2 */
|
||||
iordy_status = brcmf_sdiod_regrb(bus->sdiodev,
|
||||
SDIO_CCCR_IORx,
|
||||
NULL);
|
||||
|
||||
sdio_release_host(bus->sdiodev->func[1]);
|
||||
ret = iordy_status & SDIO_FUNC_ENABLE_2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int brcmf_ulp_event_notify(struct brcmf_if *ifp,
|
||||
const struct brcmf_event_msg *evtmsg,
|
||||
void *data)
|
||||
{
|
||||
int err = 0;
|
||||
struct brcmf_bus *bus_if = ifp->drvr->bus_if;
|
||||
struct brcmf_sdio_dev *sdiodev;
|
||||
struct brcmf_sdio *bus;
|
||||
struct brcmf_ulp_event *ulp_event = (struct brcmf_ulp_event *)data;
|
||||
|
||||
sdiodev = bus_if->bus_priv.sdio;
|
||||
bus = sdiodev->bus;
|
||||
|
||||
brcmf_dbg(ULP, "Chip went to DS1 state : action %d\n",
|
||||
ulp_event->ulp_dongle_action);
|
||||
if (ulp_event->ulp_dongle_action == FMAC_ULP_ENTRY)
|
||||
bus->sdiodev->fmac_ulp.ulp_state = FMAC_ULP_ENTRY_RECV;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -109,6 +109,7 @@
|
|||
#define SBSDIO_FUNC1_MESBUSYCTRL 0x1001D
|
||||
/* Enable busy capability for MES access */
|
||||
#define SBSDIO_MESBUSYCTRL_ENAB 0x80
|
||||
|
||||
/* Sdio Core Rev 12 */
|
||||
#define SBSDIO_FUNC1_WAKEUPCTRL 0x1001E
|
||||
#define SBSDIO_FUNC1_WCTRL_ALPWAIT_MASK 0x1
|
||||
|
@ -184,12 +185,30 @@ struct ulp_shm_info {
|
|||
u32 m_ulp_ctrl_sdio;
|
||||
u32 m_ulp_wakeevt_ind;
|
||||
u32 m_ulp_wakeind;
|
||||
u32 m_ulp_phytxblk;
|
||||
};
|
||||
|
||||
struct fmac_ulp {
|
||||
/* FMAC ULP state machine */
|
||||
#define FMAC_ULP_IDLE (0)
|
||||
#define FMAC_ULP_ENTRY_RECV (1)
|
||||
#define FMAC_ULP_TRIGGERED (2)
|
||||
|
||||
/* BRCMF_E_ULP event data */
|
||||
#define FMAC_ULP_EVENT_VERSION 1
|
||||
#define FMAC_ULP_DISABLE_CONSOLE 1 /* Disable console */
|
||||
#define FMAC_ULP_UCODE_DOWNLOAD 2 /* Download ULP ucode file */
|
||||
#define FMAC_ULP_ENTRY 3 /* Inform ulp entry to Host */
|
||||
|
||||
struct brcmf_ulp {
|
||||
uint ulp_state;
|
||||
struct ulp_shm_info ulp_shm_offset;
|
||||
};
|
||||
|
||||
struct brcmf_ulp_event {
|
||||
u16 version;
|
||||
u16 ulp_dongle_action;
|
||||
};
|
||||
|
||||
struct brcmf_sdio_dev {
|
||||
struct sdio_func *func[SDIO_MAX_FUNCS];
|
||||
u8 num_funcs; /* Supported funcs on client */
|
||||
|
@ -214,7 +233,7 @@ struct brcmf_sdio_dev {
|
|||
bool wowl_enabled;
|
||||
enum brcmf_sdiod_state state;
|
||||
struct brcmf_sdiod_freezer *freezer;
|
||||
struct fmac_ulp shm_ulp;
|
||||
struct brcmf_ulp fmac_ulp;
|
||||
bool ulp;
|
||||
};
|
||||
|
||||
|
@ -395,6 +414,7 @@ void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus);
|
|||
#define M_DS1_CTRL_SDIO(ptr) ((ptr).ulp_shm_offset.m_ulp_ctrl_sdio)
|
||||
#define M_WAKEEVENT_IND(ptr) ((ptr).ulp_shm_offset.m_ulp_wakeevt_ind)
|
||||
#define M_ULP_WAKE_IND(ptr) ((ptr).ulp_shm_offset.m_ulp_wakeind)
|
||||
#define M_DS1_PHYTX_ERR_BLK(ptr) ((ptr).ulp_shm_offset.m_ulp_phytxblk)
|
||||
|
||||
#define D11_BASE_ADDR 0x18001000
|
||||
#define D11_AXI_BASE_ADDR 0xE8000000
|
||||
|
@ -408,30 +428,61 @@ void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus);
|
|||
#define D11_MACCONTROL_REG D11REG_ADDR(0x120)
|
||||
#define D11_MACCONTROL_REG_WAKE 0x4000000
|
||||
|
||||
/* Following are the offsets in M_DRVR_UCODE_IF_PTR block. Start address of
|
||||
* M_DRVR_UCODE_IF_PTR block is present in M_DRVR_UCODE_IF_PTR.
|
||||
*/
|
||||
/* HUDI Sequence SHM bits */
|
||||
#define C_DS1_CTRL_SDIO_DS1_SLEEP 0x1
|
||||
#define C_DS1_CTRL_SDIO_MAC_ON 0x2
|
||||
#define C_DS1_CTRL_SDIO_RADIO_PHY_ON 0x4
|
||||
#define C_DS1_CTRL_SDIO_DS1_EXIT 0x8
|
||||
#define C_DS1_CTRL_PROC_DONE 0x100
|
||||
#define C_DS1_CTRL_REQ_VALID 0x200
|
||||
|
||||
/* M_ULP_WAKE_IND bits */
|
||||
#define ULP_WAKE_IND_WATCHDOG_EXP 0x1
|
||||
#define ULP_WAKE_IND_FCBS_ERROR 0x2
|
||||
#define ULP_WAKE_IND_RE_TRANSMIT_ERR 0x4
|
||||
#define ULP_WAKE_IND_HOST_WKUP 0x8
|
||||
#define ULP_WAKE_IND_INVALID_FCBS_BLK 0x10
|
||||
/* M_ULP_WAKEIND bits */
|
||||
#define C_WATCHDOG_EXPIRY BIT(0)
|
||||
#define C_FCBS_ERROR BIT(1)
|
||||
#define C_RETX_FAILURE BIT(2)
|
||||
#define C_HOST_WAKEUP BIT(3)
|
||||
#define C_INVALID_FCBS_BLOCK BIT(4)
|
||||
#define C_HUDI_DS1_EXIT BIT(5)
|
||||
#define C_LOB_SLEEP BIT(6)
|
||||
#define C_DS1_PHY_TXERR BIT(9)
|
||||
#define C_DS1_WAKE_TIMER BIT(10)
|
||||
|
||||
#define C_DS1_CTRL_SDIO_DS1_SLEEP 0x1
|
||||
#define C_DS1_CTRL_SDIO_MAC_ON 0x2
|
||||
#define C_DS1_CTRL_SDIO_RADIO_PHY_ON 0x4
|
||||
#define C_DS1_CTRL_SDIO_DS1_EXIT 0x8
|
||||
#define C_DS1_CTRL_PROC_DONE 0x100
|
||||
#define C_DS1_CTRL_REQ_VALID 0x200
|
||||
|
||||
#define D11SHM_WR(sdh, offset, val, ret) \
|
||||
brcmf_sdiod_regwl(sdh, D11SHM_ADDR(offset), val, ret)
|
||||
#define PHYTX_ERR_BLK_SIZE 18
|
||||
#define D11SHM_FIRST2BYTE_MASK 0xFFFF0000
|
||||
#define D11SHM_SECOND2BYTE_MASK 0x0000FFFF
|
||||
#define D11SHM_2BYTE_SHIFT 16
|
||||
|
||||
#define D11SHM_RD(sdh, offset, ret) \
|
||||
brcmf_sdiod_regrl(sdh, D11SHM_ADDR(offset), ret)
|
||||
|
||||
/* SHM Read is motified based on SHM 4 byte alignment as SHM size is 2 bytes and
|
||||
* 2 byte is currently not working on FMAC
|
||||
* If SHM address is not 4 byte aligned, then right shift by 16
|
||||
* otherwise, mask the first two MSB bytes
|
||||
* Suppose data in address 7260 is 0x440002 and it is 4 byte aligned
|
||||
* Correct SHM value is 0x2 for this SHM offset and next SHM value is 0x44
|
||||
*/
|
||||
#define D11SHM_RDW(sdh, offset, ret) \
|
||||
((offset % 4) ? \
|
||||
(brcmf_sdiod_regrl(sdh, D11SHM_ADDR(offset), ret) \
|
||||
>> D11SHM_2BYTE_SHIFT) : \
|
||||
(brcmf_sdiod_regrl(sdh, D11SHM_ADDR(offset), ret) \
|
||||
& D11SHM_SECOND2BYTE_MASK))
|
||||
|
||||
/* SHM is of size 2 bytes, 4 bytes write will overwrite other SHM's
|
||||
* First read 4 bytes and then clear the required two bytes based on
|
||||
* 4 byte alignment, then update the required value and write the
|
||||
* 4 byte value now
|
||||
*/
|
||||
#define D11SHM_WR(sdh, offset, val, mask, ret) \
|
||||
do { \
|
||||
if ((offset) % 4) \
|
||||
val = (val & D11SHM_SECOND2BYTE_MASK) | \
|
||||
((mask) << D11SHM_2BYTE_SHIFT); \
|
||||
else \
|
||||
val = (mask) | (val & D11SHM_FIRST2BYTE_MASK); \
|
||||
brcmf_sdiod_regwl(sdh, D11SHM_ADDR(offset), val, ret); \
|
||||
} while (0)
|
||||
#define D11REG_WR(sdh, addr, val, ret) \
|
||||
brcmf_sdiod_regwl(sdh, addr, val, ret)
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "core.h"
|
||||
#include "common.h"
|
||||
#include "bcdc.h"
|
||||
#include "cfg80211.h"
|
||||
|
||||
|
||||
#define IOCTL_RESP_TIMEOUT msecs_to_jiffies(2000)
|
||||
|
@ -103,7 +104,6 @@ static struct brcmf_firmware_mapping brcmf_usb_fwnames[] = {
|
|||
*/
|
||||
#define DL_IMAGE_TOOBIG 7 /* firmware image too big */
|
||||
|
||||
|
||||
struct trx_header_le {
|
||||
__le32 magic; /* "HDR0" */
|
||||
__le32 len; /* Length of file including header */
|
||||
|
@ -160,7 +160,7 @@ struct brcmf_usbdev_info {
|
|||
|
||||
struct usb_device *usbdev;
|
||||
struct device *dev;
|
||||
struct mutex dev_init_lock;
|
||||
struct completion fw_downloaded;
|
||||
|
||||
int ctl_in_pipe, ctl_out_pipe;
|
||||
struct urb *ctl_urb; /* URB for control endpoint */
|
||||
|
@ -175,7 +175,6 @@ struct brcmf_usbdev_info {
|
|||
|
||||
struct urb *bulk_urb; /* used for FW download */
|
||||
|
||||
bool wowl_enabled;
|
||||
struct brcmf_mp_device *settings;
|
||||
};
|
||||
|
||||
|
@ -323,27 +322,44 @@ static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len)
|
|||
int err = 0;
|
||||
int timeout = 0;
|
||||
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
|
||||
brcmf_dbg(USB, "Enter\n");
|
||||
if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP)
|
||||
return -EIO;
|
||||
|
||||
if (test_and_set_bit(0, &devinfo->ctl_op))
|
||||
return -EIO;
|
||||
err = usb_autopm_get_interface(intf);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) {
|
||||
err = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (test_and_set_bit(0, &devinfo->ctl_op)) {
|
||||
err = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
devinfo->ctl_completed = false;
|
||||
err = brcmf_usb_send_ctl(devinfo, buf, len);
|
||||
if (err) {
|
||||
brcmf_err("fail %d bytes: %d\n", err, len);
|
||||
clear_bit(0, &devinfo->ctl_op);
|
||||
return err;
|
||||
goto fail;
|
||||
}
|
||||
timeout = brcmf_usb_ioctl_resp_wait(devinfo);
|
||||
clear_bit(0, &devinfo->ctl_op);
|
||||
if (!timeout) {
|
||||
brcmf_err("Txctl wait timed out\n");
|
||||
usb_kill_urb(devinfo->ctl_urb);
|
||||
clear_bit(0, &devinfo->ctl_op);
|
||||
err = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
clear_bit(0, &devinfo->ctl_op);
|
||||
|
||||
fail:
|
||||
usb_autopm_put_interface(intf);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -352,32 +368,48 @@ static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len)
|
|||
int err = 0;
|
||||
int timeout = 0;
|
||||
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
|
||||
brcmf_dbg(USB, "Enter\n");
|
||||
if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP)
|
||||
return -EIO;
|
||||
|
||||
if (test_and_set_bit(0, &devinfo->ctl_op))
|
||||
return -EIO;
|
||||
err = usb_autopm_get_interface(intf);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) {
|
||||
err = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (test_and_set_bit(0, &devinfo->ctl_op)) {
|
||||
err = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
devinfo->ctl_completed = false;
|
||||
err = brcmf_usb_recv_ctl(devinfo, buf, len);
|
||||
if (err) {
|
||||
brcmf_err("fail %d bytes: %d\n", err, len);
|
||||
clear_bit(0, &devinfo->ctl_op);
|
||||
return err;
|
||||
goto fail;
|
||||
}
|
||||
timeout = brcmf_usb_ioctl_resp_wait(devinfo);
|
||||
err = devinfo->ctl_urb_status;
|
||||
clear_bit(0, &devinfo->ctl_op);
|
||||
if (!timeout) {
|
||||
brcmf_err("rxctl wait timed out\n");
|
||||
usb_kill_urb(devinfo->ctl_urb);
|
||||
clear_bit(0, &devinfo->ctl_op);
|
||||
err = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
clear_bit(0, &devinfo->ctl_op);
|
||||
|
||||
fail:
|
||||
usb_autopm_put_interface(intf);
|
||||
if (!err)
|
||||
return devinfo->ctl_urb_actual_length;
|
||||
else
|
||||
return err;
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct brcmf_usbreq *brcmf_usb_deq(struct brcmf_usbdev_info *devinfo,
|
||||
|
@ -515,10 +547,12 @@ static void brcmf_usb_rx_complete(struct urb *urb)
|
|||
return;
|
||||
}
|
||||
|
||||
if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
|
||||
if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP ||
|
||||
devinfo->bus_pub.state == BRCMFMAC_USB_STATE_SLEEP) {
|
||||
skb_put(skb, urb->actual_length);
|
||||
brcmf_rx_frame(devinfo->dev, skb, true);
|
||||
brcmf_usb_rx_refill(devinfo, req);
|
||||
usb_mark_last_busy(urb->dev);
|
||||
} else {
|
||||
brcmu_pkt_buf_free_skb(skb);
|
||||
brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL);
|
||||
|
@ -604,6 +638,11 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
|
|||
struct brcmf_usbreq *req;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
|
||||
ret = usb_autopm_get_interface(intf);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
brcmf_dbg(USB, "Enter, skb=%p\n", skb);
|
||||
if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) {
|
||||
|
@ -619,6 +658,8 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (devinfo->bus_pub.bus->allow_skborphan)
|
||||
skb_orphan(skb);
|
||||
req->skb = skb;
|
||||
req->devinfo = devinfo;
|
||||
usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->tx_pipe,
|
||||
|
@ -642,9 +683,10 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
|
|||
devinfo->tx_flowblock = true;
|
||||
}
|
||||
spin_unlock_irqrestore(&devinfo->tx_flowblock_lock, flags);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
usb_autopm_put_interface(intf);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1002,20 +1044,32 @@ static int
|
|||
brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo)
|
||||
{
|
||||
int err;
|
||||
struct usb_interface *intf;
|
||||
|
||||
brcmf_dbg(USB, "Enter\n");
|
||||
if (devinfo == NULL)
|
||||
return -ENODEV;
|
||||
if (!devinfo) {
|
||||
err = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!devinfo->image) {
|
||||
brcmf_err("No firmware!\n");
|
||||
return -ENOENT;
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
intf = to_usb_interface(devinfo->dev);
|
||||
err = usb_autopm_get_interface(intf);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = brcmf_usb_dlstart(devinfo,
|
||||
(u8 *)devinfo->image, devinfo->image_len);
|
||||
if (err == 0)
|
||||
err = brcmf_usb_dlrun(devinfo);
|
||||
|
||||
usb_autopm_put_interface(intf);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1116,18 +1170,6 @@ error:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void brcmf_usb_wowl_config(struct device *dev, bool enabled)
|
||||
{
|
||||
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
|
||||
|
||||
brcmf_dbg(USB, "Configuring WOWL, enabled=%d\n", enabled);
|
||||
devinfo->wowl_enabled = enabled;
|
||||
if (enabled)
|
||||
device_set_wakeup_enable(devinfo->dev, true);
|
||||
else
|
||||
device_set_wakeup_enable(devinfo->dev, false);
|
||||
}
|
||||
|
||||
static int brcmf_usb_get_fwname(struct device *dev, u32 chip, u32 chiprev,
|
||||
u8 *fw_name)
|
||||
{
|
||||
|
@ -1150,7 +1192,6 @@ static const struct brcmf_bus_ops brcmf_usb_bus_ops = {
|
|||
.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,
|
||||
};
|
||||
|
||||
|
@ -1165,6 +1206,12 @@ static int brcmf_usb_bus_setup(struct brcmf_usbdev_info *devinfo)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (BRCMF_FWCON_ON()) {
|
||||
ret = brcmf_fwlog_attach(devinfo->dev);
|
||||
if (ret)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = brcmf_usb_up(devinfo->dev);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
@ -1210,11 +1257,11 @@ static void brcmf_usb_probe_phase2(struct device *dev, int ret,
|
|||
if (ret)
|
||||
goto error;
|
||||
|
||||
mutex_unlock(&devinfo->dev_init_lock);
|
||||
complete(&devinfo->fw_downloaded);
|
||||
return;
|
||||
error:
|
||||
brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), ret);
|
||||
mutex_unlock(&devinfo->dev_init_lock);
|
||||
complete(&devinfo->fw_downloaded);
|
||||
device_release_driver(dev);
|
||||
}
|
||||
|
||||
|
@ -1243,6 +1290,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
|
|||
bus->ops = &brcmf_usb_bus_ops;
|
||||
bus->proto_type = BRCMF_PROTO_BCDC;
|
||||
bus->always_use_fws_queue = true;
|
||||
bus->allow_skborphan = true;
|
||||
#ifdef CONFIG_PM
|
||||
bus->wowl_supported = true;
|
||||
#endif
|
||||
|
@ -1260,7 +1308,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
|
|||
if (ret)
|
||||
goto fail;
|
||||
/* we are done */
|
||||
mutex_unlock(&devinfo->dev_init_lock);
|
||||
complete(&devinfo->fw_downloaded);
|
||||
return 0;
|
||||
}
|
||||
bus->chip = bus_pub->devid;
|
||||
|
@ -1321,14 +1369,14 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
|||
|
||||
devinfo->usbdev = usb;
|
||||
devinfo->dev = &usb->dev;
|
||||
/* Take an init lock, to protect for disconnect while still loading.
|
||||
* Necessary because of the asynchronous firmware load construction
|
||||
*/
|
||||
mutex_init(&devinfo->dev_init_lock);
|
||||
mutex_lock(&devinfo->dev_init_lock);
|
||||
|
||||
/* Initialize fw downloaded completion and mark it as not complete */
|
||||
init_completion(&devinfo->fw_downloaded);
|
||||
|
||||
usb_set_intfdata(intf, devinfo);
|
||||
|
||||
intf->needs_remote_wakeup = 1;
|
||||
|
||||
/* Check that the device supports only one configuration */
|
||||
if (usb->descriptor.bNumConfigurations != 1) {
|
||||
brcmf_err("Number of configurations: %d not supported\n",
|
||||
|
@ -1403,7 +1451,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
mutex_unlock(&devinfo->dev_init_lock);
|
||||
complete(&devinfo->fw_downloaded);
|
||||
kfree(devinfo);
|
||||
usb_set_intfdata(intf, NULL);
|
||||
return ret;
|
||||
|
@ -1418,7 +1466,7 @@ brcmf_usb_disconnect(struct usb_interface *intf)
|
|||
devinfo = (struct brcmf_usbdev_info *)usb_get_intfdata(intf);
|
||||
|
||||
if (devinfo) {
|
||||
mutex_lock(&devinfo->dev_init_lock);
|
||||
wait_for_completion(&devinfo->fw_downloaded);
|
||||
/* Make sure that devinfo still exists. Firmware probe routines
|
||||
* may have released the device and cleared the intfdata.
|
||||
*/
|
||||
|
@ -1439,13 +1487,25 @@ static int brcmf_usb_suspend(struct usb_interface *intf, pm_message_t state)
|
|||
{
|
||||
struct usb_device *usb = interface_to_usbdev(intf);
|
||||
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
|
||||
struct brcmf_bus *bus;
|
||||
struct brcmf_cfg80211_info *config;
|
||||
int retry = BRCMF_PM_WAIT_MAXRETRY;
|
||||
|
||||
brcmf_dbg(USB, "Enter\n");
|
||||
|
||||
bus = devinfo->bus_pub.bus;
|
||||
config = bus->drvr->config;
|
||||
while (retry &&
|
||||
config->pm_state == BRCMF_CFG80211_PM_STATE_SUSPENDING) {
|
||||
usleep_range(10000, 20000);
|
||||
retry--;
|
||||
}
|
||||
if (!retry && config->pm_state == BRCMF_CFG80211_PM_STATE_SUSPENDING)
|
||||
brcmf_err("timed out wait for cfg80211 suspended\n");
|
||||
|
||||
devinfo->bus_pub.state = BRCMFMAC_USB_STATE_SLEEP;
|
||||
if (devinfo->wowl_enabled)
|
||||
brcmf_cancel_all_urbs(devinfo);
|
||||
else
|
||||
brcmf_detach(&usb->dev);
|
||||
brcmf_cancel_all_urbs(devinfo);
|
||||
device_set_wakeup_enable(devinfo->dev, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1458,11 +1518,9 @@ static int brcmf_usb_resume(struct usb_interface *intf)
|
|||
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
|
||||
|
||||
brcmf_dbg(USB, "Enter\n");
|
||||
if (!devinfo->wowl_enabled)
|
||||
return brcmf_usb_bus_setup(devinfo);
|
||||
|
||||
devinfo->bus_pub.state = BRCMFMAC_USB_STATE_UP;
|
||||
brcmf_usb_rx_fill_all(devinfo);
|
||||
device_set_wakeup_enable(devinfo->dev, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1510,6 +1568,7 @@ static struct usb_driver brcmf_usbdrvr = {
|
|||
.suspend = brcmf_usb_suspend,
|
||||
.resume = brcmf_usb_resume,
|
||||
.reset_resume = brcmf_usb_reset_resume,
|
||||
.supports_autosuspend = true,
|
||||
.disable_hub_initiated_lpm = 1,
|
||||
};
|
||||
|
||||
|
|
|
@ -118,6 +118,56 @@ exit:
|
|||
return ret;
|
||||
}
|
||||
|
||||
s32
|
||||
brcmf_wiphy_phy_temp_evt_handler(struct brcmf_if *ifp,
|
||||
const struct brcmf_event_msg *e, void *data)
|
||||
|
||||
{
|
||||
struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
|
||||
struct wiphy *wiphy = cfg_to_wiphy(cfg);
|
||||
struct sk_buff *skb;
|
||||
struct nlattr *phy_temp_data;
|
||||
u32 version, temp, tempdelta;
|
||||
struct brcmf_phy_temp_evt *phy_temp_evt;
|
||||
|
||||
phy_temp_evt = (struct brcmf_phy_temp_evt *)data;
|
||||
|
||||
version = le32_to_cpu(phy_temp_evt->version);
|
||||
temp = le32_to_cpu(phy_temp_evt->temp);
|
||||
tempdelta = le32_to_cpu(phy_temp_evt->tempdelta);
|
||||
|
||||
skb = cfg80211_vendor_event_alloc(wiphy, NULL,
|
||||
sizeof(*phy_temp_evt),
|
||||
BRCMF_VNDR_EVTS_PHY_TEMP,
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!skb) {
|
||||
brcmf_dbg(EVENT, "NO MEM: can't allocate skb for vendor PHY_TEMP_EVENT\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
phy_temp_data = nla_nest_start(skb, NL80211_ATTR_VENDOR_EVENTS);
|
||||
if (!phy_temp_data) {
|
||||
nla_nest_cancel(skb, phy_temp_data);
|
||||
kfree_skb(skb);
|
||||
brcmf_dbg(EVENT, "skb could not nest vendor attributes\n");
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
if (nla_put_u32(skb, BRCMF_NLATTR_VERS, version) ||
|
||||
nla_put_u32(skb, BRCMF_NLATTR_PHY_TEMP, temp) ||
|
||||
nla_put_u32(skb, BRCMF_NLATTR_PHY_TEMPDELTA, tempdelta)) {
|
||||
kfree_skb(skb);
|
||||
brcmf_dbg(EVENT, "NO ROOM in skb for vendor PHY_TEMP_EVENT\n");
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
nla_nest_end(skb, phy_temp_data);
|
||||
|
||||
cfg80211_vendor_event(skb, GFP_KERNEL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct wiphy_vendor_command brcmf_vendor_cmds[] = {
|
||||
{
|
||||
{
|
||||
|
@ -129,3 +179,10 @@ const struct wiphy_vendor_command brcmf_vendor_cmds[] = {
|
|||
.doit = brcmf_cfg80211_vndr_cmds_dcmd_handler
|
||||
},
|
||||
};
|
||||
|
||||
const struct nl80211_vendor_cmd_info brcmf_vendor_events[] = {
|
||||
{
|
||||
.vendor_id = BROADCOM_OUI,
|
||||
.subcmd = BRCMF_VNDR_EVTS_PHY_TEMP,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -25,6 +25,11 @@ enum brcmf_vndr_cmds {
|
|||
BRCMF_VNDR_CMDS_LAST
|
||||
};
|
||||
|
||||
enum brcmf_vndr_evts {
|
||||
BRCMF_VNDR_EVTS_PHY_TEMP,
|
||||
BRCMF_VNDR_EVTS_LAST
|
||||
};
|
||||
|
||||
/**
|
||||
* enum brcmf_nlattrs - nl80211 message attributes
|
||||
*
|
||||
|
@ -36,11 +41,21 @@ enum brcmf_nlattrs {
|
|||
|
||||
BRCMF_NLATTR_LEN,
|
||||
BRCMF_NLATTR_DATA,
|
||||
BRCMF_NLATTR_VERS,
|
||||
BRCMF_NLATTR_PHY_TEMP,
|
||||
BRCMF_NLATTR_PHY_TEMPDELTA,
|
||||
|
||||
__BRCMF_NLATTR_AFTER_LAST,
|
||||
BRCMF_NLATTR_MAX = __BRCMF_NLATTR_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
/* structure of event sent up by firmware: is this the right place for it? */
|
||||
struct brcmf_phy_temp_evt {
|
||||
__le32 version;
|
||||
__le32 temp;
|
||||
__le32 tempdelta;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct brcmf_vndr_dcmd_hdr - message header for cfg80211 vendor command dcmd
|
||||
* support
|
||||
|
@ -60,5 +75,9 @@ struct brcmf_vndr_dcmd_hdr {
|
|||
};
|
||||
|
||||
extern const struct wiphy_vendor_command brcmf_vendor_cmds[];
|
||||
extern const struct nl80211_vendor_cmd_info brcmf_vendor_events[];
|
||||
s32 brcmf_wiphy_phy_temp_evt_handler(struct brcmf_if *ifp,
|
||||
const struct brcmf_event_msg *e,
|
||||
void *data);
|
||||
|
||||
#endif /* _vendor_h_ */
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
/* PCIE Device IDs */
|
||||
#define BRCM_PCIE_4350_DEVICE_ID 0x43a3
|
||||
#define BRCM_PCIE_4354_DEVICE_ID 0x43df
|
||||
#define BRCM_PCIE_4354_RAW_DEVICE_ID 0x4354
|
||||
#define BRCM_PCIE_4355_DEVICE_ID 0x4355
|
||||
#define BRCM_PCIE_4356_DEVICE_ID 0x43ec
|
||||
#define BRCM_PCIE_43567_DEVICE_ID 0x43d3
|
||||
|
|
|
@ -240,6 +240,8 @@ static inline bool ac_bitmap_tst(u8 bitmap, int prec)
|
|||
#define WPA2_AUTH_FT 0x4000 /* Fast BSS Transition */
|
||||
#define WPA2_AUTH_PSK_SHA256 0x8000 /* PSK with SHA256 key derivation */
|
||||
|
||||
#define WPA3_AUTH_SAE_PSK 0x40000 /* SAE with 4-way handshake */
|
||||
|
||||
#define DOT11_DEFAULT_RTS_LEN 2347
|
||||
#define DOT11_DEFAULT_FRAG_LEN 2346
|
||||
|
||||
|
|
|
@ -225,8 +225,197 @@ struct chipcregs {
|
|||
u32 PAD[3];
|
||||
u32 retention_grpidx; /* 0x680 */
|
||||
u32 retention_grpctl; /* 0x684 */
|
||||
u32 PAD[94];
|
||||
u16 sromotp[768];
|
||||
u32 mac_res_req_timer; /* 0x688 */
|
||||
u32 mac_res_req_mask; /* 0x68c */
|
||||
u32 PAD[18];
|
||||
u32 pmucontrol_ext; /* 0x6d8 */
|
||||
u32 slowclkperiod; /* 0x6dc */
|
||||
u32 PAD[8];
|
||||
u32 pmuintmask0; /* 0x700 */
|
||||
u32 pmuintmask1; /* 0x704 */
|
||||
u32 PAD[14];
|
||||
u32 pmuintstatus; /* 0x740 */
|
||||
u32 extwakeupstatus; /* 0x744 */
|
||||
u32 watchdog_res_mask; /* 0x748 */
|
||||
u32 swscratch; /* 0x750 */
|
||||
u32 PAD[3];
|
||||
u32 extwakemask[2]; /* 0x760-0x764 */
|
||||
u32 PAD[2];
|
||||
u32 extwakereqmask[2]; /* 0x770-0x774 */
|
||||
u32 PAD[2];
|
||||
u32 pmuintctrl0; /* 0x780 */
|
||||
u32 pmuintctrl1; /* 0x784 */
|
||||
u32 PAD[2];
|
||||
u32 extwakectrl[2]; /* 0x790 */
|
||||
};
|
||||
|
||||
#define CHIPGCIREGOFFS(field) offsetof(struct chipgciregs, field)
|
||||
|
||||
struct chipgciregs {
|
||||
u32 gci_corecaps0; /* 0x000 */
|
||||
u32 gci_corecaps1; /* 0x004 */
|
||||
u32 gci_corecaps2; /* 0x008 */
|
||||
u32 gci_corectrl; /* 0x00c */
|
||||
u32 gci_corestat; /* 0x010 */
|
||||
u32 gci_intstat; /* 0x014 */
|
||||
u32 gci_intmask; /* 0x018 */
|
||||
u32 gci_wakemask; /* 0x01c */
|
||||
u32 gci_levelintstat; /* 0x020 */
|
||||
u32 gci_eventintstat; /* 0x024 */
|
||||
u32 gci_wakelevelintstat; /* 0x028 */
|
||||
u32 gci_wakeeventintstat; /* 0x02c */
|
||||
u32 semaphoreintstatus; /* 0x030 */
|
||||
u32 semaphoreintmask; /* 0x034 */
|
||||
u32 semaphorerequest; /* 0x038 */
|
||||
u32 semaphorereserve; /* 0x03c */
|
||||
u32 gci_indirect_addr; /* 0x040 */
|
||||
u32 gci_gpioctl; /* 0x044 */
|
||||
u32 gci_gpiostatus; /* 0x048 */
|
||||
u32 gci_gpiomask; /* 0x04c */
|
||||
u32 eventsummary; /* 0x050 */
|
||||
u32 gci_miscctl; /* 0x054 */
|
||||
u32 gci_gpiointmask; /* 0x058 */
|
||||
u32 gci_gpiowakemask; /* 0x05c */
|
||||
u32 gci_input[32]; /* 0x060 */
|
||||
u32 gci_event[32]; /* 0x0e0 */
|
||||
u32 gci_output[4]; /* 0x160 */
|
||||
u32 gci_control_0; /* 0x170 */
|
||||
u32 gci_control_1; /* 0x174 */
|
||||
u32 gci_intpolreg; /* 0x178 */
|
||||
u32 gci_levelintmask; /* 0x17c */
|
||||
u32 gci_eventintmask; /* 0x180 */
|
||||
u32 wakelevelintmask; /* 0x184 */
|
||||
u32 wakeeventintmask; /* 0x188 */
|
||||
u32 hwmask; /* 0x18c */
|
||||
u32 PAD;
|
||||
u32 gci_inbandeventintmask; /* 0x194 */
|
||||
u32 PAD;
|
||||
u32 gci_inbandeventstatus; /* 0x19c */
|
||||
u32 gci_seciauxtx; /* 0x1a0 */
|
||||
u32 gci_seciauxrx; /* 0x1a4 */
|
||||
u32 gci_secitx_datatag; /* 0x1a8 */
|
||||
u32 gci_secirx_datatag; /* 0x1ac */
|
||||
u32 gci_secitx_datamask; /* 0x1b0 */
|
||||
u32 gci_seciusef0tx_reg; /* 0x1b4 */
|
||||
u32 gci_secif0tx_offset; /* 0x1b8 */
|
||||
u32 gci_secif0rx_offset; /* 0x1bc */
|
||||
u32 gci_secif1tx_offset; /* 0x1c0 */
|
||||
u32 gci_rxfifo_common_ctrl; /* 0x1c4 */
|
||||
u32 gci_rxfifoctrl; /* 0x1c8 */
|
||||
u32 gci_hw_sema_status; /* 0x1cc */
|
||||
u32 gci_seciuartescval; /* 0x1d0 */
|
||||
u32 gic_seciuartautobaudctr; /* 0x1d4 */
|
||||
u32 gci_secififolevel; /* 0x1d8 */
|
||||
u32 gci_seciuartdata; /* 0x1dc */
|
||||
u32 gci_secibauddiv; /* 0x1e0 */
|
||||
u32 gci_secifcr; /* 0x1e4 */
|
||||
u32 gci_secilcr; /* 0x1e8 */
|
||||
u32 gci_secimcr; /* 0x1ec */
|
||||
u32 gci_secilsr; /* 0x1f0 */
|
||||
u32 gci_secimsr; /* 0x1f4 */
|
||||
u32 gci_baudadj; /* 0x1f8 */
|
||||
u32 gci_inbandintmask; /* 0x1fc */
|
||||
u32 gci_chipctrl; /* 0x200 */
|
||||
u32 gci_chipsts; /* 0x204 */
|
||||
u32 gci_gpioout; /* 0x208 */
|
||||
u32 gci_gpioout_read; /* 0x20C */
|
||||
u32 gci_mpwaketx; /* 0x210 */
|
||||
u32 gci_mpwakedetect; /* 0x214 */
|
||||
u32 gci_seciin_ctrl; /* 0x218 */
|
||||
u32 gci_seciout_ctrl; /* 0x21C */
|
||||
u32 gci_seciin_auxfifo_en; /* 0x220 */
|
||||
u32 gci_seciout_txen_txbr; /* 0x224 */
|
||||
u32 gci_seciin_rxbrstatus; /* 0x228 */
|
||||
u32 gci_seciin_rxerrstatus; /* 0x22C */
|
||||
u32 gci_seciin_fcstatus; /* 0x230 */
|
||||
u32 gci_seciout_txstatus; /* 0x234 */
|
||||
u32 gci_seciout_txbrstatus; /* 0x238 */
|
||||
u32 wlan_mem_info; /* 0x23C */
|
||||
u32 wlan_bankxinfo; /* 0x240 */
|
||||
u32 bt_smem_select; /* 0x244 */
|
||||
u32 bt_smem_stby; /* 0x248 */
|
||||
u32 bt_smem_status; /* 0x24C */
|
||||
u32 wlan_bankxactivepda; /* 0x250 */
|
||||
u32 wlan_bankxsleeppda; /* 0x254 */
|
||||
u32 wlan_bankxkill; /* 0x258 */
|
||||
u32 PAD[41];
|
||||
u32 gci_chipid; /* 0x300 */
|
||||
u32 PAD[3];
|
||||
u32 otpstatus; /* 0x310 */
|
||||
u32 otpcontrol; /* 0x314 */
|
||||
u32 otpprog; /* 0x318 */
|
||||
u32 otplayout; /* 0x31c */
|
||||
u32 otplayoutextension; /* 0x320 */
|
||||
u32 otpcontrol1; /* 0x324 */
|
||||
u32 otpprogdata; /* 0x328 */
|
||||
u32 PAD[52];
|
||||
u32 otpECCstatus; /* 0x3FC */
|
||||
u32 PAD[512];
|
||||
u32 lhl_core_capab_adr; /* 0xC00 */
|
||||
u32 lhl_main_ctl_adr; /* 0xC04 */
|
||||
u32 lhl_pmu_ctl_adr; /* 0xC08 */
|
||||
u32 lhl_extlpo_ctl_adr; /* 0xC0C */
|
||||
u32 lpo_ctl_adr; /* 0xC10 */
|
||||
u32 lhl_lpo2_ctl_adr; /* 0xC14 */
|
||||
u32 lhl_osc32k_ctl_adr; /* 0xC18 */
|
||||
u32 lhl_clk_status_adr; /* 0xC1C */
|
||||
u32 lhl_clk_det_ctl_adr; /* 0xC20 */
|
||||
u32 lhl_clk_sel_adr; /* 0xC24 */
|
||||
u32 hidoff_cnt_adr[2]; /* 0xC28-0xC2C */
|
||||
u32 lhl_autoclk_ctl_adr; /* 0xC30 */
|
||||
u32 PAD;
|
||||
u32 lhl_hibtim_adr; /* 0xC38 */
|
||||
u32 lhl_wl_ilp_val_adr; /* 0xC3C */
|
||||
u32 lhl_wl_armtim0_intrp_adr; /* 0xC40 */
|
||||
u32 lhl_wl_armtim0_st_adr; /* 0xC44 */
|
||||
u32 lhl_wl_armtim0_adr; /* 0xC48 */
|
||||
u32 PAD[9];
|
||||
u32 lhl_wl_mactim0_intrp_adr; /* 0xC70 */
|
||||
u32 lhl_wl_mactim0_st_adr; /* 0xC74 */
|
||||
u32 lhl_wl_mactim_int0_adr; /* 0xC78 */
|
||||
u32 lhl_wl_mactim_frac0_adr; /* 0xC7C */
|
||||
u32 lhl_wl_mactim1_intrp_adr; /* 0xC80 */
|
||||
u32 lhl_wl_mactim1_st_adr; /* 0xC84 */
|
||||
u32 lhl_wl_mactim_int1_adr; /* 0xC88 */
|
||||
u32 lhl_wl_mactim_frac1_adr; /* 0xC8C */
|
||||
u32 PAD[8];
|
||||
u32 gpio_int_en_port_adr[4]; /* 0xCB0-0xCBC */
|
||||
u32 gpio_int_st_port_adr[4]; /* 0xCC0-0xCCC */
|
||||
u32 gpio_ctrl_iocfg_p_adr[64]; /* 0xCD0-0xDCC */
|
||||
u32 gpio_gctrl_iocfg_p0_p39_adr; /* 0xDD0 */
|
||||
u32 gpio_gdsctrl_iocfg_p0_p25_p30_p39_adr; /* 0xDD4 */
|
||||
u32 gpio_gdsctrl_iocfg_p26_p29_adr; /* 0xDD8 */
|
||||
u32 PAD[8];
|
||||
u32 lhl_gpio_din0_adr; /* 0xDFC */
|
||||
u32 lhl_gpio_din1_adr; /* 0xE00 */
|
||||
u32 lhl_wkup_status_adr; /* 0xE04 */
|
||||
u32 lhl_ctl_adr; /* 0xE08 */
|
||||
u32 lhl_adc_ctl_adr; /* 0xE0C */
|
||||
u32 lhl_qdxyz_in_dly_adr; /* 0xE10 */
|
||||
u32 lhl_optctl_adr; /* 0xE14 */
|
||||
u32 lhl_optct2_adr; /* 0xE18 */
|
||||
u32 lhl_scanp_cntr_init_val_adr; /* 0xE1C */
|
||||
u32 lhl_opt_togg_val_adr[6]; /* 0xE20-0xE34 */
|
||||
u32 lhl_optx_smp_val_adr; /* 0xE38 */
|
||||
u32 lhl_opty_smp_val_adr; /* 0xE3C */
|
||||
u32 lhl_optz_smp_val_adr; /* 0xE40 */
|
||||
u32 lhl_hidoff_keepstate_adr[3]; /* 0xE44-0xE4C */
|
||||
u32 lhl_bt_slmboot_ctl0_adr[4]; /* 0xE50-0xE5C */
|
||||
u32 lhl_wl_fw_ctl; /* 0xE60 */
|
||||
u32 lhl_wl_hw_ctl_adr[2]; /* 0xE64-0xE68 */
|
||||
u32 lhl_bt_hw_ctl_adr; /* 0xE6C */
|
||||
u32 lhl_top_pwrseq_en_adr; /* 0xE70 */
|
||||
u32 lhl_top_pwrdn_ctl_adr; /* 0xE74 */
|
||||
u32 lhl_top_pwrup_ctl_adr; /* 0xE78 */
|
||||
u32 lhl_top_pwrseq_ctl_adr; /* 0xE7C */
|
||||
u32 lhl_top_pwrdn2_ctl_adr; /* 0xE80 */
|
||||
u32 lhl_top_pwrup2_ctl_adr; /* 0xE84 */
|
||||
u32 wpt_regon_intrp_cfg_adr; /* 0xE88 */
|
||||
u32 bt_regon_intrp_cfg_adr; /* 0xE8C */
|
||||
u32 wl_regon_intrp_cfg_adr; /* 0xE90 */
|
||||
u32 regon_intrp_st_adr; /* 0xE94 */
|
||||
u32 regon_intrp_en_adr; /* 0xE98 */
|
||||
|
||||
};
|
||||
|
||||
/* chipid */
|
||||
|
|
|
@ -2112,6 +2112,7 @@ enum ieee80211_key_len {
|
|||
#define FILS_ERP_MAX_RRK_LEN 64
|
||||
|
||||
#define PMK_MAX_LEN 48
|
||||
#define SAE_PASSWORD_MAX_LEN 128
|
||||
|
||||
/* Public action codes (IEEE Std 802.11-2016, 9.6.8.1, Table 9-307) */
|
||||
enum ieee80211_pub_actioncode {
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#define SDIO_DEVICE_ID_BROADCOM_43455 0xa9bf
|
||||
#define SDIO_DEVICE_ID_BROADCOM_4354 0x4354
|
||||
#define SDIO_DEVICE_ID_BROADCOM_4356 0x4356
|
||||
#define SDIO_DEVICE_ID_BROADCOM_4359 0x4355
|
||||
#define SDIO_DEVICE_ID_CYPRESS_4373 0x4373
|
||||
#define SDIO_DEVICE_ID_CYPRESS_43012 43012
|
||||
|
||||
|
|
|
@ -650,6 +650,9 @@ struct survey_info {
|
|||
* CFG80211_MAX_WEP_KEYS WEP keys
|
||||
* @wep_tx_key: key index (0..3) of the default TX static WEP key
|
||||
* @psk: PSK (for devices supporting 4-way-handshake offload)
|
||||
* @sae_pwd: password for SAE authentication (for devices supporting SAE
|
||||
* offload)
|
||||
* @sae_pwd_len: length of SAE password (for devices supporting SAE offload)
|
||||
*/
|
||||
struct cfg80211_crypto_settings {
|
||||
u32 wpa_versions;
|
||||
|
@ -664,6 +667,8 @@ struct cfg80211_crypto_settings {
|
|||
struct key_params *wep_keys;
|
||||
int wep_tx_key;
|
||||
const u8 *psk;
|
||||
const u8 *sae_pwd;
|
||||
u16 sae_pwd_len;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -5309,6 +5314,8 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
|
|||
* not known. This value is used only if @status < 0 to indicate that the
|
||||
* failure is due to a timeout and not due to explicit rejection by the AP.
|
||||
* This value is ignored in other cases (@status >= 0).
|
||||
* @authorized: Indicates whether the connection is ready to transport
|
||||
* data packets.
|
||||
*/
|
||||
struct cfg80211_connect_resp_params {
|
||||
int status;
|
||||
|
@ -5326,6 +5333,7 @@ struct cfg80211_connect_resp_params {
|
|||
size_t pmk_len;
|
||||
const u8 *pmkid;
|
||||
enum nl80211_timeout_reason timeout_reason;
|
||||
bool authorized;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -5506,6 +5514,23 @@ struct cfg80211_roam_info {
|
|||
void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info,
|
||||
gfp_t gfp);
|
||||
|
||||
/**
|
||||
* cfg80211_port_authorized - notify cfg80211 of successful security association
|
||||
*
|
||||
* @dev: network device
|
||||
* @bssid: the BSSID of the AP
|
||||
* @gfp: allocation flags
|
||||
*
|
||||
* This function should be called by a driver that supports 4 way handshake
|
||||
* offload after a security association was successfully established (i.e.,
|
||||
* the 4 way handshake was completed successfully). The call to this function
|
||||
* should be preceded with a call to cfg80211_connect_result(),
|
||||
* cfg80211_connect_done(), cfg80211_connect_bss() or cfg80211_roamed() to
|
||||
* indicate the 802.11 association.
|
||||
*/
|
||||
void cfg80211_port_authorized(struct net_device *dev, const u8 *bssid,
|
||||
gfp_t gfp);
|
||||
|
||||
/**
|
||||
* cfg80211_disconnected - notify cfg80211 that connection was dropped
|
||||
*
|
||||
|
|
|
@ -231,6 +231,15 @@
|
|||
* use in a FILS shared key connection with PMKSA caching.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOC: SAE authentication offload
|
||||
*
|
||||
* By setting @NL80211_EXT_FEATURE_SAE_OFFLOAD flag drivers can indicate they
|
||||
* support offloading SAE authentication for WPA3-Personal networks. In
|
||||
* %NL80211_CMD_CONNECT the password for SAE should be specified using
|
||||
* %NL80211_ATTR_SAE_PASSWORD.
|
||||
*/
|
||||
|
||||
/**
|
||||
* enum nl80211_commands - supported nl80211 commands
|
||||
*
|
||||
|
@ -569,13 +578,14 @@
|
|||
* authentication/association or not receiving a response from the AP.
|
||||
* Non-zero %NL80211_ATTR_STATUS_CODE value is indicated in that case as
|
||||
* well to remain backwards compatible.
|
||||
* @NL80211_CMD_ROAM: notifcation indicating the card/driver roamed by itself.
|
||||
* When the driver roamed in a network that requires 802.1X authentication,
|
||||
* %NL80211_ATTR_PORT_AUTHORIZED should be set if the 802.1X authentication
|
||||
* was done by the driver or if roaming was done using Fast Transition
|
||||
* protocol (in which case 802.1X authentication is not needed). If
|
||||
* %NL80211_ATTR_PORT_AUTHORIZED is not set, user space is responsible for
|
||||
* the 802.1X authentication.
|
||||
* When establishing a security association, drivers that support 4 way
|
||||
* handshake offload should send %NL80211_CMD_PORT_AUTHORIZED event when
|
||||
* the 4 way handshake is completed successfully.
|
||||
* @NL80211_CMD_ROAM: Notification indicating the card/driver roamed by itself.
|
||||
* When a security association was established with the new AP (e.g. if
|
||||
* the FT protocol was used for roaming or the driver completed the 4 way
|
||||
* handshake), this event should be followed by an
|
||||
* %NL80211_CMD_PORT_AUTHORIZED event.
|
||||
* @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
|
||||
* userspace that a connection was dropped by the AP or due to other
|
||||
* reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
|
||||
|
@ -982,6 +992,12 @@
|
|||
* @NL80211_CMD_DEL_PMK: For offloaded 4-Way handshake, delete the previously
|
||||
* configured PMK for the authenticator address identified by
|
||||
* &NL80211_ATTR_MAC.
|
||||
* @NL80211_CMD_PORT_AUTHORIZED: An event that indicates that the 4 way
|
||||
* handshake was completed successfully by the driver. The BSSID is
|
||||
* specified with &NL80211_ATTR_MAC. Drivers that support 4 way handshake
|
||||
* offload should send this event after indicating 802.11 association with
|
||||
* &NL80211_CMD_CONNECT or &NL80211_CMD_ROAM. If the 4 way handshake failed
|
||||
* &NL80211_CMD_DISCONNECT should be indicated instead.
|
||||
*
|
||||
* @NL80211_CMD_MAX: highest used command number
|
||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||
|
@ -1185,6 +1201,8 @@ enum nl80211_commands {
|
|||
NL80211_CMD_SET_PMK,
|
||||
NL80211_CMD_DEL_PMK,
|
||||
|
||||
NL80211_CMD_PORT_AUTHORIZED,
|
||||
|
||||
/* add new commands above here */
|
||||
|
||||
/* used to define NL80211_CMD_MAX below */
|
||||
|
@ -2139,6 +2157,36 @@ enum nl80211_commands {
|
|||
* the driver or is not needed (because roaming used the Fast Transition
|
||||
* protocol).
|
||||
*
|
||||
* @NL80211_ATTR_EXTERNAL_AUTH_ACTION: Identify the requested external
|
||||
* authentication operation (u32 attribute with an
|
||||
* &enum nl80211_external_auth_action value). This is used with the
|
||||
* %NL80211_CMD_EXTERNAL_AUTH request event.
|
||||
* @NL80211_ATTR_EXTERNAL_AUTH_SUPPORT: Flag attribute indicating that the user
|
||||
* space supports external authentication. This attribute shall be used
|
||||
* only with %NL80211_CMD_CONNECT request. The driver may offload
|
||||
* authentication processing to user space if this capability is indicated
|
||||
* in NL80211_CMD_CONNECT requests from the user space.
|
||||
*
|
||||
* @NL80211_ATTR_NSS: Station's New/updated RX_NSS value notified using this
|
||||
* u8 attribute. This is used with %NL80211_CMD_STA_OPMODE_CHANGED.
|
||||
*
|
||||
* @NL80211_ATTR_TXQ_STATS: TXQ statistics (nested attribute, see &enum
|
||||
* nl80211_txq_stats)
|
||||
* @NL80211_ATTR_TXQ_LIMIT: Total packet limit for the TXQ queues for this phy.
|
||||
* The smaller of this and the memory limit is enforced.
|
||||
* @NL80211_ATTR_TXQ_MEMORY_LIMIT: Total memory memory limit (in bytes) for the
|
||||
* TXQ queues for this phy. The smaller of this and the packet limit is
|
||||
* enforced.
|
||||
* @NL80211_ATTR_TXQ_QUANTUM: TXQ scheduler quantum (bytes). Number of bytes
|
||||
* a flow is assigned on each round of the DRR scheduler.
|
||||
* @NL80211_ATTR_HE_CAPABILITY: HE Capability information element (from
|
||||
* association request when used with NL80211_CMD_NEW_STATION). Can be set
|
||||
* only if %NL80211_STA_FLAG_WME is set.
|
||||
*
|
||||
* @NL80211_ATTR_SAE_PASSWORD: attribute for passing SAE password material. It
|
||||
* is used with %NL80211_CMD_CONNECT to provide password for offloading
|
||||
* SAE authentication for WPA3-Personal networks.
|
||||
*
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
|
@ -2565,6 +2613,23 @@ enum nl80211_attrs {
|
|||
NL80211_ATTR_PMKR0_NAME,
|
||||
NL80211_ATTR_PORT_AUTHORIZED,
|
||||
|
||||
NL80211_ATTR_EXTERNAL_AUTH_ACTION,
|
||||
NL80211_ATTR_EXTERNAL_AUTH_SUPPORT,
|
||||
|
||||
NL80211_ATTR_NSS,
|
||||
NL80211_ATTR_ACK_SIGNAL,
|
||||
|
||||
NL80211_ATTR_CONTROL_PORT_OVER_NL80211,
|
||||
|
||||
NL80211_ATTR_TXQ_STATS,
|
||||
NL80211_ATTR_TXQ_LIMIT,
|
||||
NL80211_ATTR_TXQ_MEMORY_LIMIT,
|
||||
NL80211_ATTR_TXQ_QUANTUM,
|
||||
|
||||
NL80211_ATTR_HE_CAPABILITY,
|
||||
|
||||
NL80211_ATTR_SAE_PASSWORD,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
|
@ -3958,6 +4023,7 @@ enum nl80211_mfp {
|
|||
enum nl80211_wpa_versions {
|
||||
NL80211_WPA_VERSION_1 = 1 << 0,
|
||||
NL80211_WPA_VERSION_2 = 1 << 1,
|
||||
NL80211_WPA_VERSION_3 = 1 << 2,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -4916,6 +4982,40 @@ enum nl80211_feature_flags {
|
|||
* handshake with 802.1X in station mode (will pass EAP frames to the host
|
||||
* and accept the set_pmk/del_pmk commands), doing it in the host might not
|
||||
* be supported.
|
||||
* @NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME: Driver is capable of overriding
|
||||
* the max channel attribute in the FILS request params IE with the
|
||||
* actual dwell time.
|
||||
* @NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP: Driver accepts broadcast probe
|
||||
* response
|
||||
* @NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE: Driver supports sending
|
||||
* the first probe request in each channel at rate of at least 5.5Mbps.
|
||||
* @NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION: Driver supports
|
||||
* probe request tx deferral and suppression
|
||||
* @NL80211_EXT_FEATURE_MFP_OPTIONAL: Driver supports the %NL80211_MFP_OPTIONAL
|
||||
* value in %NL80211_ATTR_USE_MFP.
|
||||
* @NL80211_EXT_FEATURE_LOW_SPAN_SCAN: Driver supports low span scan.
|
||||
* @NL80211_EXT_FEATURE_LOW_POWER_SCAN: Driver supports low power scan.
|
||||
* @NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN: Driver supports high accuracy scan.
|
||||
* @NL80211_EXT_FEATURE_DFS_OFFLOAD: HW/driver will offload DFS actions.
|
||||
* Device or driver will do all DFS-related actions by itself,
|
||||
* informing user-space about CAC progress, radar detection event,
|
||||
* channel change triggered by radar detection event.
|
||||
* No need to start CAC from user-space, no need to react to
|
||||
* "radar detected" event.
|
||||
* @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211: Driver supports sending and
|
||||
* receiving control port frames over nl80211 instead of the netdevice.
|
||||
* @NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT: This Driver support data ack
|
||||
* rssi if firmware support, this flag is to intimate about ack rssi
|
||||
* support to nl80211.
|
||||
* @NL80211_EXT_FEATURE_TXQS: Driver supports FQ-CoDel-enabled intermediate
|
||||
* TXQs.
|
||||
* @NL80211_EXT_FEATURE_SCAN_RANDOM_SN: Driver/device supports randomizing the
|
||||
* SN in probe request frames if requested by %NL80211_SCAN_FLAG_RANDOM_SN.
|
||||
* @NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT: Driver/device can omit all data
|
||||
* except for supported rates from the probe request content if requested
|
||||
* by the %NL80211_SCAN_FLAG_MIN_PREQ_CONTENT flag.
|
||||
* @NL80211_EXT_FEATURE_SAE_OFFLOAD: Device wants to do SAE authentication in
|
||||
* station mode (SAE password is passed as part of the connect command).
|
||||
*
|
||||
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
||||
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
||||
|
@ -4938,6 +5038,21 @@ enum nl80211_ext_feature_index {
|
|||
NL80211_EXT_FEATURE_FILS_SK_OFFLOAD,
|
||||
NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK,
|
||||
NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X,
|
||||
NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME,
|
||||
NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP,
|
||||
NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE,
|
||||
NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION,
|
||||
NL80211_EXT_FEATURE_MFP_OPTIONAL,
|
||||
NL80211_EXT_FEATURE_LOW_SPAN_SCAN,
|
||||
NL80211_EXT_FEATURE_LOW_POWER_SCAN,
|
||||
NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN,
|
||||
NL80211_EXT_FEATURE_DFS_OFFLOAD,
|
||||
NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211,
|
||||
NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT,
|
||||
NL80211_EXT_FEATURE_TXQS,
|
||||
NL80211_EXT_FEATURE_SCAN_RANDOM_SN,
|
||||
NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT,
|
||||
NL80211_EXT_FEATURE_SAE_OFFLOAD,
|
||||
|
||||
/* add new features before the definition below */
|
||||
NUM_NL80211_EXT_FEATURES,
|
||||
|
|
|
@ -217,6 +217,7 @@ enum cfg80211_event_type {
|
|||
EVENT_DISCONNECTED,
|
||||
EVENT_IBSS_JOINED,
|
||||
EVENT_STOPPED,
|
||||
EVENT_PORT_AUTHORIZED,
|
||||
};
|
||||
|
||||
struct cfg80211_event {
|
||||
|
@ -236,6 +237,9 @@ struct cfg80211_event {
|
|||
u8 bssid[ETH_ALEN];
|
||||
struct ieee80211_channel *channel;
|
||||
} ij;
|
||||
struct {
|
||||
u8 bssid[ETH_ALEN];
|
||||
} pa;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -386,6 +390,7 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
|
|||
bool wextev);
|
||||
void __cfg80211_roamed(struct wireless_dev *wdev,
|
||||
struct cfg80211_roam_info *info);
|
||||
void __cfg80211_port_authorized(struct wireless_dev *wdev, const u8 *bssid);
|
||||
int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev);
|
||||
void cfg80211_autodisconnect_wk(struct work_struct *work);
|
||||
|
|
|
@ -421,6 +421,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
|||
[NL80211_ATTR_FILS_CACHE_ID] = { .len = 2 },
|
||||
[NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
|
||||
[NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG },
|
||||
[NL80211_ATTR_SAE_PASSWORD] = { .type = NLA_BINARY,
|
||||
.len = SAE_PASSWORD_MAX_LEN },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
|
@ -3866,6 +3868,13 @@ static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
|
|||
/* SAE not supported yet */
|
||||
if (auth_type == NL80211_AUTHTYPE_SAE)
|
||||
return false;
|
||||
|
||||
if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
|
||||
!wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_SAE_OFFLOAD) &&
|
||||
auth_type == NL80211_AUTHTYPE_SAE)
|
||||
return false;
|
||||
|
||||
/* FILS with SK PFS or PK not supported yet */
|
||||
if (auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
|
||||
auth_type == NL80211_AUTHTYPE_FILS_PK)
|
||||
|
@ -7966,7 +7975,8 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
static bool nl80211_valid_wpa_versions(u32 wpa_versions)
|
||||
{
|
||||
return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
|
||||
NL80211_WPA_VERSION_2));
|
||||
NL80211_WPA_VERSION_2 |
|
||||
NL80211_WPA_VERSION_3));
|
||||
}
|
||||
|
||||
static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
|
||||
|
@ -8180,6 +8190,16 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
|
|||
settings->psk = nla_data(info->attrs[NL80211_ATTR_PMK]);
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_SAE_PASSWORD]) {
|
||||
if (!wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_SAE_OFFLOAD))
|
||||
return -EINVAL;
|
||||
settings->sae_pwd =
|
||||
nla_data(info->attrs[NL80211_ATTR_SAE_PASSWORD]);
|
||||
settings->sae_pwd_len =
|
||||
nla_len(info->attrs[NL80211_ATTR_SAE_PASSWORD]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -13756,6 +13776,8 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
|
|||
(nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON,
|
||||
cr->timeout_reason))) ||
|
||||
(cr->authorized &&
|
||||
nla_put_flag(msg, NL80211_ATTR_PORT_AUTHORIZED)) ||
|
||||
(cr->req_ie &&
|
||||
nla_put(msg, NL80211_ATTR_REQ_IE, cr->req_ie_len, cr->req_ie)) ||
|
||||
(cr->resp_ie &&
|
||||
|
@ -13827,6 +13849,37 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
|
|||
nlmsg_free(msg);
|
||||
}
|
||||
|
||||
void nl80211_send_port_authorized(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *bssid)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PORT_AUTHORIZED);
|
||||
if (!hdr) {
|
||||
nlmsg_free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
|
||||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
|
||||
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
|
||||
NL80211_MCGRP_MLME, GFP_KERNEL);
|
||||
return;
|
||||
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
nlmsg_free(msg);
|
||||
}
|
||||
|
||||
void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, u16 reason,
|
||||
const u8 *ie, size_t ie_len, bool from_ap)
|
||||
|
|
|
@ -59,6 +59,8 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
|
|||
void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev,
|
||||
struct cfg80211_roam_info *info, gfp_t gfp);
|
||||
void nl80211_send_port_authorized(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *bssid);
|
||||
void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, u16 reason,
|
||||
const u8 *ie, size_t ie_len, bool from_ap);
|
||||
|
|
|
@ -857,6 +857,7 @@ void cfg80211_connect_done(struct net_device *dev,
|
|||
ev->cr.bss = params->bss;
|
||||
ev->cr.status = params->status;
|
||||
ev->cr.timeout_reason = params->timeout_reason;
|
||||
ev->cr.authorized = params->authorized;
|
||||
|
||||
spin_lock_irqsave(&wdev->event_lock, flags);
|
||||
list_add_tail(&ev->list, &wdev->event_list);
|
||||
|
@ -965,6 +966,50 @@ void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info,
|
|||
}
|
||||
EXPORT_SYMBOL(cfg80211_roamed);
|
||||
|
||||
void __cfg80211_port_authorized(struct wireless_dev *wdev, const u8 *bssid)
|
||||
{
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
|
||||
return;
|
||||
|
||||
if (WARN_ON(!wdev->current_bss) ||
|
||||
WARN_ON(!ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
|
||||
return;
|
||||
|
||||
nl80211_send_port_authorized(wiphy_to_rdev(wdev->wiphy), wdev->netdev,
|
||||
bssid);
|
||||
}
|
||||
|
||||
void cfg80211_port_authorized(struct net_device *dev, const u8 *bssid,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
struct cfg80211_event *ev;
|
||||
unsigned long flags;
|
||||
|
||||
if (WARN_ON(!bssid))
|
||||
return;
|
||||
|
||||
ev = kzalloc(sizeof(*ev), gfp);
|
||||
if (!ev)
|
||||
return;
|
||||
|
||||
ev->type = EVENT_PORT_AUTHORIZED;
|
||||
memcpy(ev->pa.bssid, bssid, ETH_ALEN);
|
||||
|
||||
/*
|
||||
* Use the wdev event list so that if there are pending
|
||||
* connected/roamed events, they will be reported first.
|
||||
*/
|
||||
spin_lock_irqsave(&wdev->event_lock, flags);
|
||||
list_add_tail(&ev->list, &wdev->event_list);
|
||||
spin_unlock_irqrestore(&wdev->event_lock, flags);
|
||||
queue_work(cfg80211_wq, &rdev->event_work);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_port_authorized);
|
||||
|
||||
void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
|
||||
size_t ie_len, u16 reason, bool from_ap)
|
||||
{
|
||||
|
|
|
@ -964,6 +964,9 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
|
|||
case EVENT_STOPPED:
|
||||
__cfg80211_leave(wiphy_to_rdev(wdev->wiphy), wdev);
|
||||
break;
|
||||
case EVENT_PORT_AUTHORIZED:
|
||||
__cfg80211_port_authorized(wdev, ev->pa.bssid);
|
||||
break;
|
||||
}
|
||||
wdev_unlock(wdev);
|
||||
|
||||
|
|
Loading…
Reference in New Issue