1
0
Fork 0

Merge branch 'wifi/next' into next

* wifi/next: (51 commits)
  MLK-22949 brcmfmac: add chip id check for clm_blob firmware load
  MLK-22948 brcmfmac: avoid to send mailbox interrupt twice for core version 0xb
  MLK-22946 brcmfmac: freeing wiphy after brcmf attach failed
  dt-bindings: add new property to enable board_type
  brcmfmac: let board_type is optional
  ...
5.4-rM2-2.2.x-imx-squashed
Dong Aisheng 2019-12-02 18:05:33 +08:00
commit 9c3a4bfcf6
28 changed files with 2430 additions and 62 deletions

View File

@ -11,6 +11,7 @@ Required properties:
Optional properties:
- brcm,drive-strength : drive strength used for SDIO pins on device in mA
(default = 6).
- brcm,use_board_type : suffix string for NVRAM
- interrupts : specifies attributes for the out-of-band interrupt (host-wake).
When not specified the device will use in-band SDIO interrupts.
- interrupt-names : name of the out-of-band interrupt, which must be set

View File

@ -22,6 +22,7 @@
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/acpi.h>
#include <linux/of.h>
#include <net/cfg80211.h>
#include <defs.h>
@ -36,6 +37,7 @@
#include "sdio.h"
#include "core.h"
#include "common.h"
#include "cfg80211.h"
#define SDIOH_API_ACCESS_RETRY_LIMIT 2
@ -43,6 +45,7 @@
#define SDIO_FUNC1_BLOCKSIZE 64
#define SDIO_FUNC2_BLOCKSIZE 512
#define SDIO_4373_FUNC2_BLOCKSIZE 256
/* Maximum milliseconds to wait for F2 to come up */
#define SDIO_WAIT_F2RDY 3000
@ -903,6 +906,7 @@ static void brcmf_sdiod_host_fixup(struct mmc_host *host)
static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
{
int ret = 0;
unsigned int f2_blksz = SDIO_FUNC2_BLOCKSIZE;
sdio_claim_host(sdiodev->func1);
@ -912,11 +916,18 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
sdio_release_host(sdiodev->func1);
goto out;
}
ret = sdio_set_block_size(sdiodev->func2, SDIO_FUNC2_BLOCKSIZE);
if (sdiodev->func1->device == SDIO_DEVICE_ID_CYPRESS_4373) {
f2_blksz = SDIO_4373_FUNC2_BLOCKSIZE;
}
ret = sdio_set_block_size(sdiodev->func2, f2_blksz);
if (ret) {
brcmf_err("Failed to set F2 blocksize\n");
sdio_release_host(sdiodev->func1);
goto out;
} else {
brcmf_dbg(SDIO, "set F2 blocksize to %d\n", f2_blksz);
}
/* increase F2 timeout */
@ -964,6 +975,7 @@ 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),
@ -995,6 +1007,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
struct brcmf_sdio_dev *sdiodev;
struct brcmf_bus *bus_if;
struct device *dev;
struct device *func_dev;
brcmf_dbg(SDIO, "Enter\n");
brcmf_dbg(SDIO, "Class=%x\n", func->class);
@ -1010,6 +1023,11 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
/* prohibit ACPI power management for this device */
brcmf_sdiod_acpi_set_power_manageable(dev, 0);
func_dev = &func->card->sdio_func[0]->dev;
if (!func_dev->of_node ||
!of_device_is_compatible(func_dev->of_node, "brcm,bcm4329-fmac"))
return -ENODEV;
/* Consume func num 1 but dont do anything with it. */
if (func->num == 1)
return 0;
@ -1039,6 +1057,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
dev_set_drvdata(&func->dev, bus_if);
dev_set_drvdata(&sdiodev->func1->dev, bus_if);
sdiodev->dev = &sdiodev->func1->dev;
dev_set_drvdata(&sdiodev->func2->dev, bus_if);
brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_DOWN);
@ -1055,6 +1074,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
fail:
dev_set_drvdata(&func->dev, NULL);
dev_set_drvdata(&sdiodev->func1->dev, NULL);
dev_set_drvdata(&sdiodev->func2->dev, NULL);
kfree(sdiodev);
kfree(bus_if);
return err;
@ -1093,6 +1113,14 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
brcmf_dbg(SDIO, "Exit\n");
}
static void brcmf_ops_sdio_shutdown(struct device *dev)
{
struct sdio_func *func = container_of(dev, struct sdio_func, dev);
brcmf_ops_sdio_remove(func);
return;
}
void brcmf_sdio_wowl_config(struct device *dev, bool enabled)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
@ -1109,14 +1137,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);
if (func->num != 1)
return 0;
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");
bus_if = dev_get_drvdata(dev);
sdiodev = bus_if->bus_priv.sdio;
brcmf_sdiod_freezer_on(sdiodev);
@ -1164,6 +1204,7 @@ static struct sdio_driver brcmf_sdmmc_driver = {
#ifdef CONFIG_PM_SLEEP
.pm = &brcmf_sdio_pm_ops,
#endif /* CONFIG_PM_SLEEP */
.shutdown = brcmf_ops_sdio_shutdown,
.coredump = brcmf_dev_coredump,
},
};

View File

@ -3575,7 +3575,7 @@ static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
sizeof(wake_ind_le));
if (err) {
bphy_err(drvr, "Get wowl_wakeind failed, err = %d\n", err);
brcmf_dbg(INFO, "cannet get wowl_wakeind, err = %d\n", err);
return;
}
@ -3643,10 +3643,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);
@ -3662,7 +3676,12 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
brcmf_notify_sched_scan_results);
cfg->wowl.nd_enabled = false;
}
/* disable packet filters */
brcmf_pktfilter_enable(ifp->ndev, false);
}
config->pm_state = BRCMF_CFG80211_PM_STATE_RESUMED;
return 0;
}
@ -3720,6 +3739,9 @@ static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
brcmf_bus_wowl_config(cfg->pub->bus_if, true);
cfg->wowl.active = true;
/* enable packet filters */
brcmf_pktfilter_enable(ifp->ndev, true);
}
static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
@ -3729,9 +3751,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.
*/
@ -3746,7 +3771,8 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
brcmf_abort_scanning(cfg);
if (wowl == NULL) {
if (!wowl || !test_bit(BRCMF_VIF_STATUS_CONNECTED,
&ifp->vif->sme_state)) {
brcmf_bus_wowl_config(cfg->pub->bus_if, false);
list_for_each_entry(vif, &cfg->vif_list, list) {
if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
@ -3766,14 +3792,19 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
brcmf_set_mpc(ifp, 1);
} else {
/* Configure WOWL paramaters */
brcmf_configure_wowl(cfg, ifp, wowl);
/* Configure WOWL parameters */
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
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;
}
@ -4584,9 +4615,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
}
}
if ((dev_role == NL80211_IFTYPE_AP) &&
((ifp->ifidx == 0) ||
!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
if ((dev_role == NL80211_IFTYPE_AP) && (ifp->ifidx == 0)) {
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
if (err < 0) {
bphy_err(drvr, "BRCMF_C_DOWN error %d\n",
@ -5006,7 +5035,7 @@ static int brcmf_cfg80211_get_channel(struct wiphy *wiphy,
err = brcmf_fil_iovar_int_get(netdev_priv(ndev), "chanspec", &chanspec);
if (err) {
bphy_err(drvr, "chanspec failed (%d)\n", err);
brcmf_dbg(TRACE, "chanspec failed (%d)\n", err);
return err;
}
@ -5235,6 +5264,26 @@ static int brcmf_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
return brcmf_set_pmk(ifp, NULL, 0);
}
static int
brcmf_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *dev,
struct bss_parameters *params)
{
struct brcmf_if *ifp;
int ret = 0;
u32 ap_isolate;
brcmf_dbg(TRACE, "Enter\n");
ifp = netdev_priv(dev);
if (params->ap_isolate >= 0) {
ap_isolate = (u32)params->ap_isolate;
ret = brcmf_fil_iovar_int_set(ifp, "ap_isolate", ap_isolate);
if (ret < 0)
brcmf_err("ap_isolate iovar failed: ret=%d\n", ret);
}
return ret;
}
static struct cfg80211_ops brcmf_cfg80211_ops = {
.add_virtual_intf = brcmf_cfg80211_add_iface,
.del_virtual_intf = brcmf_cfg80211_del_iface,
@ -5280,6 +5329,7 @@ static struct cfg80211_ops brcmf_cfg80211_ops = {
.update_connect_params = brcmf_cfg80211_update_conn_params,
.set_pmk = brcmf_cfg80211_set_pmk,
.del_pmk = brcmf_cfg80211_del_pmk,
.change_bss = brcmf_cfg80211_change_bss,
};
struct cfg80211_ops *brcmf_cfg80211_get_ops(struct brcmf_mp_device *settings)
@ -5427,12 +5477,125 @@ static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
conn_info->resp_ie_len = 0;
}
u8 brcmf_map_prio_to_prec(void *config, u8 prio)
{
struct brcmf_cfg80211_info *cfg = (struct brcmf_cfg80211_info *)config;
if (!cfg)
return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ?
(prio ^ 2) : prio;
/* For those AC(s) with ACM flag set to 1, convert its 4-level priority
* to an 8-level precedence which is the same as BE's */
if (prio > PRIO_8021D_EE &&
cfg->ac_priority[prio] == cfg->ac_priority[PRIO_8021D_BE])
return cfg->ac_priority[prio] * 2;
/* Conversion of 4-level priority to 8-level precedence */
if (prio == PRIO_8021D_BE || prio == PRIO_8021D_BK ||
prio == PRIO_8021D_CL || prio == PRIO_8021D_VO)
return cfg->ac_priority[prio] * 2;
else
return cfg->ac_priority[prio] * 2 + 1;
}
u8 brcmf_map_prio_to_aci(void *config, u8 prio)
{
/* Prio here refers to the 802.1d priority in range of 0 to 7.
* ACI here refers to the WLAN AC Index in range of 0 to 3.
* This function will return ACI corresponding to input prio.
*/
struct brcmf_cfg80211_info *cfg = (struct brcmf_cfg80211_info *)config;
if (cfg)
return cfg->ac_priority[prio];
return prio;
}
static void brcmf_wifi_prioritize_acparams(const
struct brcmf_cfg80211_edcf_acparam *acp, u8 *priority)
{
u8 aci;
u8 aifsn;
u8 ecwmin;
u8 ecwmax;
u8 acm;
u8 ranking_basis[EDCF_AC_COUNT];
u8 aci_prio[EDCF_AC_COUNT]; /* AC_BE, AC_BK, AC_VI, AC_VO */
u8 index;
for (aci = 0; aci < EDCF_AC_COUNT; aci++, acp++) {
aifsn = acp->ACI & EDCF_AIFSN_MASK;
acm = (acp->ACI & EDCF_ACM_MASK) ? 1 : 0;
ecwmin = acp->ECW & EDCF_ECWMIN_MASK;
ecwmax = (acp->ECW & EDCF_ECWMAX_MASK) >> EDCF_ECWMAX_SHIFT;
brcmf_dbg(CONN, "ACI %d aifsn %d acm %d ecwmin %d ecwmax %d\n",
aci, aifsn, acm, ecwmin, ecwmax);
/* Default AC_VO will be the lowest ranking value */
ranking_basis[aci] = aifsn + ecwmin + ecwmax;
/* Initialise priority starting at 0 (AC_BE) */
aci_prio[aci] = 0;
/* If ACM is set, STA can't use this AC as per 802.11.
* Change the ranking to BE
*/
if (aci != AC_BE && aci != AC_BK && acm == 1)
ranking_basis[aci] = ranking_basis[AC_BE];
}
/* Ranking method which works for AC priority
* swapping when values for cwmin, cwmax and aifsn are varied
* Compare each aci_prio against each other aci_prio
*/
for (aci = 0; aci < EDCF_AC_COUNT; aci++) {
for (index = 0; index < EDCF_AC_COUNT; index++) {
if (index != aci) {
/* Smaller ranking value has higher priority,
* so increment priority for each ACI which has
* a higher ranking value
*/
if (ranking_basis[aci] < ranking_basis[index])
aci_prio[aci]++;
}
}
}
/* By now, aci_prio[] will be in range of 0 to 3.
* Use ACI prio to get the new priority value for
* each 802.1d traffic type, in this range.
*/
/* 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 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];
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]);
brcmf_dbg(CONN, "Adj prio VI 4->%d, VI 5->%d, VO 6->%d, VO 7->%d\n",
priority[4], priority[5], priority[6], priority[7]);
}
static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
struct brcmf_if *ifp)
{
struct brcmf_pub *drvr = cfg->pub;
struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
struct brcmf_cfg80211_edcf_acparam edcf_acparam_info[EDCF_AC_COUNT];
u32 req_len;
u32 resp_len;
s32 err = 0;
@ -5481,6 +5644,17 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
GFP_KERNEL);
if (!conn_info->resp_ie)
conn_info->resp_ie_len = 0;
err = brcmf_fil_iovar_data_get(ifp, "wme_ac_sta",
edcf_acparam_info,
sizeof(edcf_acparam_info));
if (err) {
brcmf_err("could not get wme_ac_sta (%d)\n", err);
return err;
}
brcmf_wifi_prioritize_acparams(edcf_acparam_info,
cfg->ac_priority);
} else {
conn_info->resp_ie_len = 0;
conn_info->resp_ie = NULL;
@ -5798,6 +5972,25 @@ 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,
@ -5892,6 +6085,7 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
mutex_init(&cfg->usr_sync);
brcmf_init_escan(cfg);
brcmf_init_conf(cfg->conf);
brcmf_init_wmm_prio(cfg->ac_priority);
init_completion(&cfg->vif_disabled);
return err;
}
@ -6579,6 +6773,7 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_pub *drvr = cfg->pub;
struct wiphy_wowlan_support *wowl;
struct cfg80211_wowlan *brcmf_wowlan_config = NULL;
wowl = kmemdup(&brcmf_wowlan_support, sizeof(brcmf_wowlan_support),
GFP_KERNEL);
@ -6601,6 +6796,27 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
}
wiphy->wowlan = wowl;
/* wowlan_config structure report for kernels */
brcmf_wowlan_config = kzalloc(sizeof(*brcmf_wowlan_config),
GFP_KERNEL);
if (brcmf_wowlan_config) {
brcmf_wowlan_config->any = false;
brcmf_wowlan_config->disconnect = true;
brcmf_wowlan_config->eap_identity_req = true;
brcmf_wowlan_config->four_way_handshake = true;
brcmf_wowlan_config->rfkill_release = false;
brcmf_wowlan_config->patterns = NULL;
brcmf_wowlan_config->n_patterns = 0;
brcmf_wowlan_config->tcp = NULL;
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
brcmf_wowlan_config->gtk_rekey_failure = true;
else
brcmf_wowlan_config->gtk_rekey_failure = false;
} else {
brcmf_err("Can not allocate memory for brcm_wowlan_config\n");
}
wiphy->wowlan_config = brcmf_wowlan_config;
#endif
}
@ -6739,6 +6955,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
struct wireless_dev *wdev;
struct brcmf_if *ifp;
s32 power_mode;
s32 eap_restrict;
s32 err = 0;
if (cfg->dongle_up)
@ -6763,6 +6980,14 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
err = brcmf_dongle_roam(ifp);
if (err)
goto default_conf_out;
eap_restrict = ifp->drvr->settings->eap_restrict;
if (eap_restrict) {
err = brcmf_fil_iovar_int_set(ifp, "eap_restrict",
eap_restrict);
if (err)
brcmf_info("eap_restrict error (%d)\n", err);
}
err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
NULL);
if (err)
@ -7043,6 +7268,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
cfg->wiphy = wiphy;
cfg->pub = drvr;
cfg->pm_state = BRCMF_CFG80211_PM_STATE_RESUMED;
init_vif_event(&cfg->vif_event);
INIT_LIST_HEAD(&cfg->vif_list);

View File

@ -23,6 +23,23 @@
#define WL_ROAM_TRIGGER_LEVEL -75
#define WL_ROAM_DELTA 20
/* WME Access Category Indices (ACIs) */
#define AC_BE 0 /* Best Effort */
#define AC_BK 1 /* Background */
#define AC_VI 2 /* Video */
#define AC_VO 3 /* Voice */
#define EDCF_AC_COUNT 4
#define MAX_8021D_PRIO 8
#define EDCF_ACI_MASK 0x60
#define EDCF_ACI_SHIFT 5
#define EDCF_ACM_MASK 0x10
#define EDCF_ECWMIN_MASK 0x0f
#define EDCF_ECWMAX_SHIFT 4
#define EDCF_AIFSN_MASK 0x0f
#define EDCF_AIFSN_MAX 15
#define EDCF_ECWMAX_MASK 0xf0
/* Keep BRCMF_ESCAN_BUF_SIZE below 64K (65536). Allocing over 64K can be
* problematic on some systems and should be avoided.
*/
@ -75,6 +92,15 @@
#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
#define WL_WOWLAN_MAX_PATTERN_LEN 255
#define WL_WOWLAN_PKT_FILTER_ID_FIRST 201
#define WL_WOWLAN_PKT_FILTER_ID_LAST (WL_WOWLAN_PKT_FILTER_ID_FIRST + \
WL_WOWLAN_MAX_PATTERNS - 1)
/**
* enum brcmf_scan_status - scan engine status
*
@ -145,6 +171,13 @@ 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.
*
@ -203,6 +236,12 @@ struct brcmf_cfg80211_assoc_ielen_le {
__le32 resp_len;
};
struct brcmf_cfg80211_edcf_acparam {
u8 ACI;
u8 ECW;
u16 TXOP; /* stored in network order (ls octet first) */
};
/* dongle escan state */
enum wl_escan_state {
WL_ESCAN_STATE_IDLE,
@ -321,6 +360,8 @@ struct brcmf_cfg80211_info {
struct brcmf_assoclist_le assoclist;
struct brcmf_cfg80211_wowl wowl;
struct brcmf_pno_info *pno;
u8 ac_priority[MAX_8021D_PRIO];
u8 pm_state;
};
/**

View File

@ -433,11 +433,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) &
@ -449,9 +463,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);
}
}
char *brcmf_chip_name(u32 id, u32 rev, char *buf, uint len)
@ -463,6 +498,16 @@ char *brcmf_chip_name(u32 id, u32 rev, char *buf, uint len)
return buf;
}
bool brcmf_chip_has_clm_blob(u32 id)
{
bool ret = true;
if (id == BRCM_CC_4339_CHIP_ID)
return false;
return ret;
}
static struct brcmf_core *brcmf_chip_add_core(struct brcmf_chip_priv *ci,
u16 coreid, u32 base,
u32 wrapbase)
@ -1113,6 +1158,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;

View File

@ -76,6 +76,7 @@ void brcmf_chip_detach(struct brcmf_chip *chip);
struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid);
struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *chip);
struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub);
struct brcmf_core *brcmf_chip_get_d11core(struct brcmf_chip *pub, u8 unit);
bool brcmf_chip_iscoreup(struct brcmf_core *core);
void brcmf_chip_coredisable(struct brcmf_core *core, u32 prereset, u32 reset);
void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset,
@ -84,5 +85,6 @@ 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);
char *brcmf_chip_name(u32 chipid, u32 chiprev, char *buf, uint len);
bool brcmf_chip_has_clm_blob(u32 id);
#endif /* BRCMF_AXIDMP_H */

View File

@ -8,6 +8,7 @@
#include <linux/netdevice.h>
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/pinctrl/consumer.h>
#include <brcmu_wifi.h>
#include <brcmu_utils.h>
#include "core.h"
@ -67,6 +68,14 @@ static int brcmf_iapp_enable;
module_param_named(iapp, brcmf_iapp_enable, int, 0);
MODULE_PARM_DESC(iapp, "Enable partial support for the obsoleted Inter-Access Point Protocol");
static int brcmf_eap_restrict;
module_param_named(eap_restrict, brcmf_eap_restrict, int, 0400);
MODULE_PARM_DESC(eap_restrict, "Block non-802.1X frames until auth finished");
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");
#ifdef DEBUG
/* always succeed brcmf_bus_started() */
static int brcmf_ignore_probe_fail;
@ -202,7 +211,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
char *ptr;
s32 err;
/* retreive mac address */
/* retrieve mac addresses */
err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
sizeof(ifp->mac_addr));
if (err < 0) {
@ -250,10 +259,12 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
ri->chipname, sizeof(ri->chipname));
/* Do any CLM downloading */
err = brcmf_c_process_clm_blob(ifp);
if (err < 0) {
bphy_err(drvr, "download CLM blob file failed, %d\n", err);
goto done;
if (brcmf_chip_has_clm_blob(bus->chip)) {
err = brcmf_c_process_clm_blob(ifp);
if (err < 0) {
bphy_err(drvr, "download CLM blob file failed, %d\n", err);
goto done;
}
}
/* query for 'ver' to get version info from firmware */
@ -336,6 +347,13 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
/* Enable tx beamforming, errors can be ignored (not supported) */
(void)brcmf_fil_iovar_int_set(ifp, "txbf", 1);
/* add unicast packet filter */
err = brcmf_pktfilter_add_remove(ifp->ndev,
BRCMF_UNICAST_FILTER_NUM, true);
if (err)
brcmf_info("Add unicast filter error (%d)\n", err);
done:
return err;
}
@ -407,12 +425,14 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
if (!settings)
return NULL;
/* start by using the module paramaters */
/* start by using the module parameters */
settings->p2p_enable = !!brcmf_p2p_enable;
settings->feature_disable = brcmf_feature_disable;
settings->fcmode = brcmf_fcmode;
settings->roamoff = !!brcmf_roamoff;
settings->iapp = !!brcmf_iapp_enable;
settings->eap_restrict = !!brcmf_eap_restrict;
settings->sdio_wq_highpri = !!brcmf_sdio_wq_highpri;
#ifdef DEBUG
settings->ignore_probe_fail = !!brcmf_ignore_probe_fail;
#endif
@ -423,6 +443,7 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
/* See if there is any device specific platform data configured */
found = false;
if (brcmfmac_pdata) {
pinctrl_pm_select_default_state(brcmfmac_pdata->dev);
for (i = 0; i < brcmfmac_pdata->device_count; i++) {
device_pd = &brcmfmac_pdata->devices[i];
if ((device_pd->bus_type == bus_type) &&
@ -456,10 +477,30 @@ void brcmf_release_module_param(struct brcmf_mp_device *module_param)
static int __init brcmf_common_pd_probe(struct platform_device *pdev)
{
int err;
struct brcmfmac_platform_data pdata = {
.power_on = NULL,
.power_off = NULL,
.fw_alternative_path = NULL,
.device_count = 0,
};
brcmf_dbg(INFO, "Enter\n");
brcmfmac_pdata = dev_get_platdata(&pdev->dev);
if (!brcmfmac_pdata) {
err = platform_device_add_data(pdev, &pdata,
sizeof(pdata));
if (err)
brcmf_err("platform data allocation failed\n");
brcmfmac_pdata = dev_get_platdata(&pdev->dev);
pinctrl_pm_select_idle_state(&pdev->dev);
}
if (!brcmfmac_pdata)
return 0;
brcmfmac_pdata->dev = &pdev->dev;
if (brcmfmac_pdata->power_on)
brcmfmac_pdata->power_on();
@ -470,7 +511,7 @@ static int brcmf_common_pd_remove(struct platform_device *pdev)
{
brcmf_dbg(INFO, "Enter\n");
if (brcmfmac_pdata->power_off)
if (brcmfmac_pdata && brcmfmac_pdata->power_off)
brcmfmac_pdata->power_off();
return 0;
@ -492,7 +533,7 @@ static int __init brcmfmac_module_init(void)
if (err == -ENODEV)
brcmf_dbg(INFO, "No platform data available.\n");
/* Initialize global module paramaters */
/* Initialize global module parameters */
brcmf_mp_attach();
/* Continue the initialization by registering the different busses */

View File

@ -37,6 +37,8 @@ extern struct brcmf_mp_global_t brcmf_mp_global;
* @feature_disable: Feature_disable bitmask.
* @fcmode: FWS flow control.
* @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.
* @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.
@ -47,6 +49,9 @@ struct brcmf_mp_device {
int fcmode;
bool roamoff;
bool iapp;
bool eap_restrict;
int sdio_dpc_prio;
bool sdio_wq_highpri;
bool ignore_probe_fail;
struct brcmfmac_pd_cc *country_codes;
const char *board_type;
@ -71,5 +76,8 @@ void brcmf_dmi_probe(struct brcmf_mp_device *settings, u32 chip, u32 chiprev);
static inline void
brcmf_dmi_probe(struct brcmf_mp_device *settings, u32 chip, u32 chiprev) {}
#endif
u8 brcmf_map_prio_to_prec(void *cfg, u8 prio);
u8 brcmf_map_prio_to_aci(void *cfg, u8 prio);
#endif /* BRCMFMAC_COMMON_H */

View File

@ -536,6 +536,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);
@ -1470,3 +1475,177 @@ void __exit brcmf_core_exit(void)
#endif
}
int
brcmf_pktfilter_add_remove(struct net_device *ndev, int filter_num, bool add)
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
struct brcmf_pkt_filter_le *pkt_filter;
int filter_fixed_len = offsetof(struct brcmf_pkt_filter_le, u);
int pattern_fixed_len = offsetof(struct brcmf_pkt_filter_pattern_le,
mask_and_pattern);
u16 mask_and_pattern[MAX_PKTFILTER_PATTERN_SIZE];
int buflen = 0;
int ret = 0;
brcmf_dbg(INFO, "%s packet filter number %d\n",
(add ? "add" : "remove"), filter_num);
pkt_filter = kzalloc(sizeof(*pkt_filter) +
(MAX_PKTFILTER_PATTERN_SIZE * 2), GFP_ATOMIC);
if (!pkt_filter)
return -ENOMEM;
switch (filter_num) {
case BRCMF_UNICAST_FILTER_NUM:
pkt_filter->id = 100;
pkt_filter->type = 0;
pkt_filter->negate_match = 0;
pkt_filter->u.pattern.offset = 0;
pkt_filter->u.pattern.size_bytes = 1;
mask_and_pattern[0] = 0x0001;
break;
case BRCMF_BROADCAST_FILTER_NUM:
//filter_pattern = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF";
pkt_filter->id = 101;
pkt_filter->type = 0;
pkt_filter->negate_match = 0;
pkt_filter->u.pattern.offset = 0;
pkt_filter->u.pattern.size_bytes = 6;
mask_and_pattern[0] = 0xFFFF;
mask_and_pattern[1] = 0xFFFF;
mask_and_pattern[2] = 0xFFFF;
mask_and_pattern[3] = 0xFFFF;
mask_and_pattern[4] = 0xFFFF;
mask_and_pattern[5] = 0xFFFF;
break;
case BRCMF_MULTICAST4_FILTER_NUM:
//filter_pattern = "102 0 0 0 0xFFFFFF 0x01005E";
pkt_filter->id = 102;
pkt_filter->type = 0;
pkt_filter->negate_match = 0;
pkt_filter->u.pattern.offset = 0;
pkt_filter->u.pattern.size_bytes = 3;
mask_and_pattern[0] = 0xFFFF;
mask_and_pattern[1] = 0x01FF;
mask_and_pattern[2] = 0x5E00;
break;
case BRCMF_MULTICAST6_FILTER_NUM:
//filter_pattern = "103 0 0 0 0xFFFF 0x3333";
pkt_filter->id = 103;
pkt_filter->type = 0;
pkt_filter->negate_match = 0;
pkt_filter->u.pattern.offset = 0;
pkt_filter->u.pattern.size_bytes = 2;
mask_and_pattern[0] = 0xFFFF;
mask_and_pattern[1] = 0x3333;
break;
case BRCMF_MDNS_FILTER_NUM:
//filter_pattern = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB";
pkt_filter->id = 104;
pkt_filter->type = 0;
pkt_filter->negate_match = 0;
pkt_filter->u.pattern.offset = 0;
pkt_filter->u.pattern.size_bytes = 6;
mask_and_pattern[0] = 0xFFFF;
mask_and_pattern[1] = 0xFFFF;
mask_and_pattern[2] = 0xFFFF;
mask_and_pattern[3] = 0x0001;
mask_and_pattern[4] = 0x005E;
mask_and_pattern[5] = 0xFB00;
break;
case BRCMF_ARP_FILTER_NUM:
//filter_pattern = "105 0 0 12 0xFFFF 0x0806";
pkt_filter->id = 105;
pkt_filter->type = 0;
pkt_filter->negate_match = 0;
pkt_filter->u.pattern.offset = 12;
pkt_filter->u.pattern.size_bytes = 2;
mask_and_pattern[0] = 0xFFFF;
mask_and_pattern[1] = 0x0608;
break;
case BRCMF_BROADCAST_ARP_FILTER_NUM:
//filter_pattern = "106 0 0 0
//0xFFFFFFFFFFFF0000000000000806
//0xFFFFFFFFFFFF0000000000000806";
pkt_filter->id = 106;
pkt_filter->type = 0;
pkt_filter->negate_match = 0;
pkt_filter->u.pattern.offset = 0;
pkt_filter->u.pattern.size_bytes = 14;
mask_and_pattern[0] = 0xFFFF;
mask_and_pattern[1] = 0xFFFF;
mask_and_pattern[2] = 0xFFFF;
mask_and_pattern[3] = 0x0000;
mask_and_pattern[4] = 0x0000;
mask_and_pattern[5] = 0x0000;
mask_and_pattern[6] = 0x0608;
mask_and_pattern[7] = 0xFFFF;
mask_and_pattern[8] = 0xFFFF;
mask_and_pattern[9] = 0xFFFF;
mask_and_pattern[10] = 0x0000;
mask_and_pattern[11] = 0x0000;
mask_and_pattern[12] = 0x0000;
mask_and_pattern[13] = 0x0608;
break;
default:
ret = -EINVAL;
goto failed;
}
memcpy(pkt_filter->u.pattern.mask_and_pattern, mask_and_pattern,
pkt_filter->u.pattern.size_bytes * 2);
buflen = filter_fixed_len + pattern_fixed_len +
pkt_filter->u.pattern.size_bytes * 2;
if (add) {
/* Add filter */
ret = brcmf_fil_iovar_data_set(ifp, "pkt_filter_add",
pkt_filter, buflen);
if (ret)
goto failed;
drvr->pkt_filter[filter_num].id = pkt_filter->id;
drvr->pkt_filter[filter_num].enable = 0;
} else {
/* Delete filter */
ret = brcmf_fil_iovar_int_set(ifp, "pkt_filter_delete",
pkt_filter->id);
if (ret == -ENOENT)
ret = 0;
if (ret)
goto failed;
drvr->pkt_filter[filter_num].id = 0;
drvr->pkt_filter[filter_num].enable = 0;
}
failed:
if (ret)
brcmf_err("%s packet filter failed, ret=%d\n",
(add ? "add" : "remove"), ret);
kfree(pkt_filter);
return ret;
}
int brcmf_pktfilter_enable(struct net_device *ndev, bool enable)
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
int ret = 0;
int idx = 0;
for (idx = 0; idx < MAX_PKT_FILTER_COUNT; ++idx) {
if (drvr->pkt_filter[idx].id != 0) {
drvr->pkt_filter[idx].enable = enable;
ret = brcmf_fil_iovar_data_set(ifp, "pkt_filter_enable",
&drvr->pkt_filter[idx],
sizeof(struct brcmf_pkt_filter_enable_le));
if (ret) {
brcmf_err("%s packet filter id(%d) failed, ret=%d\n",
(enable ? "enable" : "disable"),
drvr->pkt_filter[idx].id, ret);
}
}
}
return ret;
}

View File

@ -12,6 +12,7 @@
#include <net/cfg80211.h>
#include "fweh.h"
#include "fwil_types.h"
#define TOE_TX_CSUM_OL 0x00000001
#define TOE_RX_CSUM_OL 0x00000002
@ -136,6 +137,8 @@ struct brcmf_pub {
struct work_struct bus_reset;
u8 clmver[BRCMF_DCMD_SMLEN];
struct brcmf_pkt_filter_enable_le pkt_filter[MAX_PKT_FILTER_COUNT];
};
/* forward declarations */
@ -213,5 +216,7 @@ void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb);
void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
int __init brcmf_core_init(void);
void __exit brcmf_core_exit(void);
int brcmf_pktfilter_add_remove(struct net_device *ndev, int filter_num,
bool add);
int brcmf_pktfilter_enable(struct net_device *ndev, bool enable);
#endif /* BRCMFMAC_CORE_H */

View File

@ -99,7 +99,7 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
s32 err, fwerr;
if (drvr->bus_if->state != BRCMF_BUS_UP) {
bphy_err(drvr, "bus is down. we have nothing to do.\n");
brcmf_dbg(FIL, "bus is down. we have nothing to do.\n");
return -EIO;
}

View File

@ -136,6 +136,19 @@
#define BRCMF_WOWL_MAXPATTERNS 8
#define BRCMF_WOWL_MAXPATTERNSIZE 128
enum {
BRCMF_UNICAST_FILTER_NUM = 0,
BRCMF_BROADCAST_FILTER_NUM,
BRCMF_MULTICAST4_FILTER_NUM,
BRCMF_MULTICAST6_FILTER_NUM,
BRCMF_MDNS_FILTER_NUM,
BRCMF_ARP_FILTER_NUM,
BRCMF_BROADCAST_ARP_FILTER_NUM,
MAX_PKT_FILTER_COUNT
};
#define MAX_PKTFILTER_PATTERN_SIZE 16
#define BRCMF_COUNTRY_BUF_SZ 4
#define BRCMF_ANT_MAX 4

View File

@ -404,7 +404,7 @@ struct brcmf_fws_mac_descriptor {
u8 traffic_lastreported_bmp;
};
#define BRCMF_FWS_HANGER_MAXITEMS 1024
#define BRCMF_FWS_HANGER_MAXITEMS 3072
/**
* enum brcmf_fws_hanger_item_state - state of hanger item.
@ -1865,6 +1865,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 */
@ -2130,8 +2133,10 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
skcb->if_flags = 0;
skcb->state = BRCMF_FWS_SKBSTATE_NEW;
brcmf_skb_if_flags_set_field(skb, INDEX, ifp->ifidx);
/* mapping from 802.1d priority to firmware fifo index */
if (!multicast)
fifo = brcmf_fws_prio2fifo[skb->priority];
fifo = brcmf_map_prio_to_aci(drvr->config, skb->priority);
brcmf_fws_lock(fws);
if (fifo != BRCMF_FWS_FIFO_AC_BE && fifo < BRCMF_FWS_FIFO_BCMC)
@ -2343,7 +2348,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;
u32 mode = 0;
fws = kzalloc(sizeof(*fws), GFP_KERNEL);
if (!fws) {

View File

@ -18,15 +18,17 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
struct brcmfmac_sdio_pd *sdio = &settings->bus.sdio;
struct device_node *root, *np = dev->of_node;
struct property *prop;
const char *cp = NULL;
int irq;
u32 irqf;
u32 val;
u32 val32;
u16 val16;
/* Set board-type to the first string of the machine compatible prop */
root = of_find_node_by_path("/");
if (root) {
prop = of_find_property(root, "compatible", NULL);
settings->board_type = of_prop_next_string(prop, NULL);
cp = of_prop_next_string(prop, NULL);
of_node_put(root);
}
@ -34,8 +36,18 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
!of_device_is_compatible(np, "brcm,bcm4329-fmac"))
return;
if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0)
sdio->drive_strength = val;
if (of_property_read_u32(np, "brcm,drive-strength", &val32) == 0)
sdio->drive_strength = val32;
if (of_property_read_bool(np, "brcm,use_board_type"))
settings->board_type = cp;
sdio->broken_sg_support = of_property_read_bool(np,
"brcm,broken_sg_support");
if (of_property_read_u16(np, "brcm,sd_head_align", &val16) == 0)
sdio->sd_head_align = val16;
if (of_property_read_u16(np, "brcm,sd_sgentry_align", &val16) == 0)
sdio->sd_sgentry_align = val16;
/* make sure there are interrupts defined in the node */
if (!of_find_property(np, "interrupts", NULL))

View File

@ -457,10 +457,21 @@ static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac)
*/
static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr)
{
struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
bool random_addr = false;
bool local_admin = false;
if (!dev_addr || is_zero_ether_addr(dev_addr))
random_addr = true;
if (!dev_addr || is_zero_ether_addr(dev_addr)) {
/* If the primary interface address is already locally
* administered, create a new random address.
*/
if (pri_ifp->mac_addr[0] & 0x02) {
random_addr = true;
} else {
dev_addr = pri_ifp->mac_addr;
local_admin = true;
}
}
/* Generate the P2P Device Address obtaining a random ethernet
* address with the locally administered bit set.
@ -470,6 +481,9 @@ static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr)
else
memcpy(p2p->dev_addr, dev_addr, ETH_ALEN);
if (local_admin)
p2p->dev_addr[0] |= 0x02;
/* Generate the P2P Interface Address. If the discovery and connection
* BSSCFGs need to simultaneously co-exist, then this address must be
* different from the P2P Device Address, but also locally administered.
@ -1491,6 +1505,7 @@ static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p,
{
struct brcmf_pub *drvr = p2p->cfg->pub;
struct brcmf_cfg80211_vif *vif;
struct brcmf_p2p_action_frame *p2p_act_frame;
s32 err = 0;
s32 timeout = 0;
@ -1500,7 +1515,13 @@ static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p,
clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status);
clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);
vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
/* check if it is a p2p_presence response */
p2p_act_frame = (struct brcmf_p2p_action_frame *) af_params->action_frame.data;
if (p2p_act_frame->subtype == P2P_AF_PRESENCE_RSP)
vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif;
else
vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe", af_params,
sizeof(*af_params));
if (err) {

View File

@ -38,6 +38,7 @@
#include "chip.h"
#include "core.h"
#include "common.h"
#include "cfg80211.h"
enum brcmf_pcie_state {
@ -78,7 +79,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
BRCMF_FW_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)
@ -188,7 +189,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
#define BRCMF_H2D_HOST_D0_INFORM_IN_USE 0x00000008
#define BRCMF_H2D_HOST_D0_INFORM 0x00000010
#define BRCMF_PCIE_MBDATA_TIMEOUT msecs_to_jiffies(2000)
#define BRCMF_PCIE_MBDATA_TIMEOUT msecs_to_jiffies(5000)
#define BRCMF_PCIE_CFGREG_STATUS_CMD 0x4
#define BRCMF_PCIE_CFGREG_PM_CSR 0x4C
@ -692,7 +693,7 @@ brcmf_pcie_send_mb_data(struct brcmf_pciedev_info *devinfo, u32 htod_mb_data)
/* Send mailbox interrupt twice as a hardware workaround */
core = brcmf_chip_get_core(devinfo->ci, BCMA_CORE_PCIE2);
if (core->rev <= 13)
if (core && (core->rev <= 0xd && core->rev != 0xb))
pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_SBMBX, 1);
return 0;
@ -1834,6 +1835,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
return;
fail:
brcmf_free(dev);
device_release_driver(dev);
}
@ -2001,6 +2003,11 @@ brcmf_pcie_remove(struct pci_dev *pdev)
dev_set_drvdata(&pdev->dev, NULL);
}
static void brcmf_pcie_shutdown(struct pci_dev *pdev)
{
brcmf_pcie_remove(pdev);
return;
}
#ifdef CONFIG_PM
@ -2009,11 +2016,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(bus, "timed out wait for cfg80211 suspended\n");
brcmf_bus_change_state(bus, BRCMF_BUS_DOWN);
@ -2023,9 +2041,21 @@ static int brcmf_pcie_pm_enter_D3(struct device *dev)
wait_event_timeout(devinfo->mbdata_resp_wait, devinfo->mbdata_completed,
BRCMF_PCIE_MBDATA_TIMEOUT);
if (!devinfo->mbdata_completed) {
brcmf_err(bus, "Timeout on response for entering D3 substate\n");
brcmf_bus_change_state(bus, BRCMF_BUS_UP);
return -EIO;
struct brcmf_pcie_shared_info *shared;
u32 addr;
u32 dtoh_mb_data;
shared = &devinfo->shared;
addr = shared->dtoh_mb_data_addr;
dtoh_mb_data = brcmf_pcie_read_tcm32(devinfo, addr);
if (dtoh_mb_data & BRCMF_D2H_DEV_D3_ACK) {
brcmf_dbg(PCIE, "D2H_MB_DATA: D3 ACK\n");
devinfo->mbdata_completed = true;
}
if (!devinfo->mbdata_completed)
brcmf_err(bus, "Timeout on response for entering D3 substate\n");
}
devinfo->state = BRCMFMAC_PCIE_STATE_DOWN;
@ -2033,7 +2063,6 @@ static int brcmf_pcie_pm_enter_D3(struct device *dev)
return 0;
}
static int brcmf_pcie_pm_leave_D3(struct device *dev)
{
struct brcmf_pciedev_info *devinfo;
@ -2053,6 +2082,7 @@ static int brcmf_pcie_pm_leave_D3(struct device *dev)
if (brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_D0_INFORM))
goto cleanup;
brcmf_dbg(PCIE, "Hot resume, continue....\n");
msleep(10);
devinfo->state = BRCMFMAC_PCIE_STATE_UP;
brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2);
brcmf_bus_change_state(bus, BRCMF_BUS_UP);
@ -2126,6 +2156,7 @@ static struct pci_driver brcmf_pciedrvr = {
.id_table = brcmf_pcie_devid_table,
.probe = brcmf_pcie_probe,
.remove = brcmf_pcie_remove,
.shutdown = brcmf_pcie_shutdown,
#ifdef CONFIG_PM
.driver.pm = &brcmf_pciedrvr_pm,
#endif

View File

@ -34,15 +34,23 @@
#include "core.h"
#include "common.h"
#include "bcdc.h"
#include "fwil.h"
#define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500)
#define CTL_DONE_TIMEOUT msecs_to_jiffies(2500)
#define ULP_HUDI_PROC_DONE_TIME msecs_to_jiffies(2500)
/* watermark expressed in number of words */
#define DEFAULT_F2_WATERMARK 0x8
#define CY_4373_F2_WATERMARK 0x40
#define CY_43012_F2_WATERMARK 0x60
#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)
#ifdef DEBUG
#define BRCMF_TRAP_INFO_SIZE 80
@ -313,14 +321,8 @@ struct rte_console {
#define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
#define BRCMF_SDIO_MAX_ACCESS_ERRORS 5
/*
* Conversion of 802.1D priority to precedence level
*/
static uint prio2prec(u32 prio)
{
return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ?
(prio^2) : prio;
}
static void brcmf_sdio_firmware_callback(struct device *dev, int err,
struct brcmf_fw_request *fwreq);
#ifdef DEBUG
/* Device console log buffer state */
@ -2317,6 +2319,7 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
&prec_out);
if (pkt == NULL)
break;
skb_orphan(pkt);
__skb_queue_tail(&pktq, pkt);
}
spin_unlock_bh(&bus->txq_lock);
@ -2540,6 +2543,166 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
return ret;
}
/* This Function is used to retrieve important
* details from dongle related to ULP mode Mostly
* values/SHM details that will be vary depending
* on the firmware branches
*/
static void
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");
/* 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_dbg(TRACE, "ulp_sdioctrl iovar returned err = %d\n", err);
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));
}
#define BRCMF_SDIO_FW_CODE 0
#define BRCMF_SDIO_FW_NVRAM 1
/* Reinitialize ARM because In DS1 mode ARM got off */
static int
brcmf_sdio_ulp_reinit_fw(struct brcmf_sdio *bus)
{
struct brcmf_sdio_dev *sdiodev = bus->sdiodev;
struct brcmf_fw_request *fwreq;
int err = 0;
/* After firmware redownload tx/rx seq are reset accordingly
* these values are reset on FMAC side tx_max is initially set to 4,
* which later is updated by FW.
*/
bus->tx_seq = 0;
bus->rx_seq = 0;
bus->tx_max = 4;
fwreq = kzalloc(sizeof(fwreq) + 2 * sizeof(struct brcmf_fw_item),
GFP_KERNEL);
if (!fwreq)
return -ENOMEM;
fwreq->items[BRCMF_SDIO_FW_CODE].path = sdiodev->fw_name;
fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
fwreq->items[BRCMF_SDIO_FW_NVRAM].path = sdiodev->nvram_name;
fwreq->items[BRCMF_SDIO_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
fwreq->n_items = 2;
err = brcmf_fw_get_firmwares(sdiodev->dev, fwreq,
brcmf_sdio_firmware_callback);
if (err != 0) {
brcmf_err("async firmware request failed: %d\n", err);
kfree(fwreq);
}
return err;
}
/* Check if device is in DS1 mode and handshake with ULP UCODE */
static bool
brcmf_sdio_ulp_pre_redownload_check(struct brcmf_sdio *bus)
{
int err = 0;
u32 value = 0;
u32 val32, ulp_wake_ind, wowl_wake_ind;
int reg_addr;
unsigned long timeout;
value = brcmf_sdiod_readb(bus->sdiodev, SDIO_CCCR_IOEx, &err);
if (value == SDIO_FUNC_ENABLE_1) {
brcmf_dbg(SDIO, "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;
brcmf_dbg(SDIO, "wowl_wake_ind: 0x%08x, ulp_wake_ind: 0x%08x\n",
wowl_wake_ind, ulp_wake_ind);
if (wowl_wake_ind || ulp_wake_ind) {
/* TX wake Don't do anything.
* Just bail out and re-download firmware.
*/
} 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),
&err));
D11SHM_WR(bus->sdiodev, M_DS1_CTRL_SDIO(
bus->sdiodev->shm_ulp),
C_DS1_CTRL_SDIO_DS1_EXIT |
C_DS1_CTRL_REQ_VALID,
&err);
val32 = D11REG_RD(bus->sdiodev,
D11_MACCONTROL_REG, &err);
val32 = val32 | D11_MACCONTROL_REG_WAKE;
D11REG_WR(bus->sdiodev,
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);
/* 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);
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,
M_DS1_CTRL_SDIO(
bus->sdiodev->shm_ulp), &err));
value = D11SHM_RD(bus->sdiodev,
M_DS1_CTRL_SDIO(
bus->sdiodev->shm_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",
wowl_wake_ind, ulp_wake_ind);
reg_addr = CORE_CC_REG(
brcmf_chip_get_pmu(bus->ci)->base, min_res_mask);
brcmf_sdiod_writel(bus->sdiodev, reg_addr,
DEFAULT_43012_MIN_RES_MASK, &err);
if (err)
brcmf_err("min_res_mask failed\n");
return true;
}
return false;
}
static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
{
struct brcmf_sdio_dev *sdiod = bus->sdiodev;
@ -2613,6 +2776,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
if (intstatus & I_HMB_HOST_INT) {
intstatus &= ~I_HMB_HOST_INT;
intstatus |= brcmf_sdio_hostmail(bus);
if ((sdiod->func1->device != SDIO_DEVICE_ID_BROADCOM_4339) &&
brcmf_sdio_ulp_pre_redownload_check(bus))
brcmf_sdio_ulp_reinit_fw(bus);
}
sdio_release_host(bus->sdiodev->func1);
@ -2767,7 +2933,13 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
skb_push(pkt, bus->tx_hdrlen);
/* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */
prec = prio2prec((pkt->priority & PRIOMASK));
/* In WLAN, priority is always set by the AP using WMM parameters
* and this need not always follow the standard 802.1d priority.
* Based on AP WMM config, map from 802.1d priority to corresponding
* precedence level.
*/
prec = brcmf_map_prio_to_prec(bus_if->drvr->config,
(pkt->priority & PRIOMASK));
/* Check for existing queue, current flow-control,
pending event, or pending clock */
@ -3515,6 +3687,11 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
if (err < 0)
goto done;
/* initialize SHM address from firmware for DS1 */
if ((sdiodev->func1->device != SDIO_DEVICE_ID_BROADCOM_4339) &&
!bus->sdiodev->ulp)
brcmf_sdio_ulp_preinit(dev);
bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;
if (sdiodev->sg_support) {
bus->txglom = false;
@ -4106,9 +4283,6 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
.debugfs_create = brcmf_sdio_debugfs_create
};
#define BRCMF_SDIO_FW_CODE 0
#define BRCMF_SDIO_FW_NVRAM 1
static void brcmf_sdio_firmware_callback(struct device *dev, int err,
struct brcmf_fw_request *fwreq)
{
@ -4205,6 +4379,31 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
brcmf_sdiod_writeb(sdiod, SBSDIO_DEVICE_CTL, devctl,
&err);
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_writeb(sdiod, SBSDIO_WATERMARK,
CY_43455_F2_WATERMARK, &err);
devctl = brcmf_sdiod_readb(sdiod, SBSDIO_DEVICE_CTL,
&err);
devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
brcmf_sdiod_writeb(sdiod, SBSDIO_DEVICE_CTL, devctl,
&err);
brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_MESBUSYCTRL,
CY_43455_MESBUSYCTRL, &err);
break;
case SDIO_DEVICE_ID_BROADCOM_4339:
brcmf_sdiod_writeb(sdiod,
SBSDIO_WATERMARK,
CY_4339_F2_WATERMARK, &err);
devctl = brcmf_sdiod_readb(sdiod,
SBSDIO_DEVICE_CTL, &err);
devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
brcmf_sdiod_writeb(sdiod,
SBSDIO_DEVICE_CTL, devctl, &err);
brcmf_sdiod_writeb(sdiod,
SBSDIO_FUNC1_MESBUSYCTRL, CY_4339_MESBUSYCTRL, &err);
break;
default:
brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK,
DEFAULT_F2_WATERMARK, &err);
@ -4322,9 +4521,21 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
bus->txminmax = BRCMF_TXMINMAX;
bus->tx_seq = SDPCM_SEQ_WRAP - 1;
/* attempt to attach to the dongle */
if (!(brcmf_sdio_probe_attach(bus))) {
brcmf_err("brcmf_sdio_probe_attach failed\n");
goto fail;
}
/* single-threaded workqueue */
wq = alloc_ordered_workqueue("brcmf_wq/%s", WQ_MEM_RECLAIM,
dev_name(&sdiodev->func1->dev));
if (sdiodev->settings->sdio_wq_highpri) {
wq = alloc_workqueue("brcmf_wq/%s",
WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND,
1, dev_name(&sdiodev->func1->dev));
} else {
wq = alloc_ordered_workqueue("brcmf_wq/%s", WQ_MEM_RECLAIM,
dev_name(&sdiodev->func1->dev));
}
if (!wq) {
brcmf_err("insufficient memory to create txworkqueue\n");
goto fail;
@ -4333,12 +4544,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
bus->brcmf_wq = wq;
/* attempt to attach to the dongle */
if (!(brcmf_sdio_probe_attach(bus))) {
brcmf_err("brcmf_sdio_probe_attach failed\n");
goto fail;
}
spin_lock_init(&bus->rxctl_lock);
spin_lock_init(&bus->txq_lock);
init_waitqueue_head(&bus->ctrl_wait);

View File

@ -165,6 +165,17 @@ struct brcmf_sdreg {
struct brcmf_sdio;
struct brcmf_sdiod_freezer;
/* ULP SHM Offsets info */
struct ulp_shm_info {
u32 m_ulp_ctrl_sdio;
u32 m_ulp_wakeevt_ind;
u32 m_ulp_wakeind;
};
struct fmac_ulp {
struct ulp_shm_info ulp_shm_offset;
};
struct brcmf_sdio_dev {
struct sdio_func *func1;
struct sdio_func *func2;
@ -190,6 +201,8 @@ struct brcmf_sdio_dev {
bool wowl_enabled;
enum brcmf_sdiod_state state;
struct brcmf_sdiod_freezer *freezer;
struct fmac_ulp shm_ulp;
bool ulp;
};
/* sdio core registers */
@ -377,4 +390,51 @@ void brcmf_sdio_wowl_config(struct device *dev, bool enabled);
int brcmf_sdio_sleep(struct brcmf_sdio *bus, bool sleep);
void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus);
/* SHM offsets */
#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 D11_BASE_ADDR 0x18001000
#define D11_AXI_BASE_ADDR 0xE8000000
#define D11_SHM_BASE_ADDR (D11_AXI_BASE_ADDR + 0x4000)
#define D11REG_ADDR(offset) (D11_BASE_ADDR + (offset))
#define D11IHR_ADDR(offset) (D11_AXI_BASE_ADDR + 0x400 + (2 * (offset)))
#define D11SHM_ADDR(offset) (D11_SHM_BASE_ADDR + (offset))
/* MacControl register */
#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.
*/
/* 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
#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_writel(sdh, D11SHM_ADDR(offset), val, ret)
#define D11SHM_RD(sdh, offset, ret) \
brcmf_sdiod_readl(sdh, D11SHM_ADDR(offset), ret)
#define D11REG_WR(sdh, addr, val, ret) \
brcmf_sdiod_writel(sdh, addr, val, ret)
#define D11REG_RD(sdh, addr, ret) \
brcmf_sdiod_readl(sdh, addr, ret)
#endif /* BRCMFMAC_SDIO_H */

View File

@ -19,6 +19,7 @@
#include "core.h"
#include "common.h"
#include "bcdc.h"
#include "cfg80211.h"
#define IOCTL_RESP_TIMEOUT msecs_to_jiffies(2000)
@ -1441,8 +1442,22 @@ 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);

View File

@ -70,8 +70,12 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy,
else
ret = brcmf_fil_cmd_data_get(ifp, cmdhdr->cmd, dcmd_buf,
ret_len);
if (ret != 0)
if (ret != 0) {
brcmf_dbg(INFO, "error(%d), return -EPERM\n", ret);
ret = -EPERM;
goto exit;
}
wr_pointer = dcmd_buf;
while (ret_len > 0) {

View File

@ -306,6 +306,8 @@ struct chipcregs {
* Maximum delay for the PMU state transition in us.
* This is an upper bound intended for spinwaits etc.
*/
#define PMU_MAX_TRANSITION_DLY 15000
#define PMU_MAX_TRANSITION_DLY 15000
#define DEFAULT_43012_MIN_RES_MASK 0x0f8bfe77
#endif /* _SBCHIPC_H */

View File

@ -36,6 +36,7 @@
#define SDIO_DEVICE_ID_BROADCOM_4339 0x4339
#define SDIO_DEVICE_ID_BROADCOM_43362 0xa962
#define SDIO_DEVICE_ID_BROADCOM_43364 0xa9a4
#define SDIO_DEVICE_ID_BROADCOM_43428 0xa9a4
#define SDIO_DEVICE_ID_BROADCOM_43430 0xa9a6
#define SDIO_DEVICE_ID_BROADCOM_4345 0x4345
#define SDIO_DEVICE_ID_BROADCOM_43455 0xa9bf

View File

@ -178,6 +178,7 @@ struct brcmfmac_platform_data {
void (*power_off)(void);
char *fw_alternative_path;
int device_count;
struct device *dev;
struct brcmfmac_pd_device devices[0];
};

View File

@ -4017,6 +4017,7 @@ enum wiphy_flags {
WIPHY_FLAG_SUPPORTS_5_10_MHZ = BIT(22),
WIPHY_FLAG_HAS_CHANNEL_SWITCH = BIT(23),
WIPHY_FLAG_HAS_STATIC_WEP = BIT(24),
WIPHY_FLAG_DFS_OFFLOAD = BIT(25)
};
/**
@ -5473,6 +5474,32 @@ void cfg80211_send_layer2_update(struct net_device *dev, const u8 *addr);
*/
int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
/**
* regulatory_hint_user - hint to the wireless core a regulatory domain
* which the driver has received from an application
* @alpha2: the ISO/IEC 3166 alpha2 the driver claims its regulatory domain
* should be in. If @rd is set this should be NULL. Note that if you
* set this to NULL you should still set rd->alpha2 to some accepted
* alpha2.
* @user_reg_hint_type: the type of user regulatory hint.
*
* Wireless drivers can use this function to hint to the wireless core
* the current regulatory domain as specified by trusted applications,
* it is the driver's responsibilty to estbalish which applications it
* trusts.
*
* The wiphy should be registered to cfg80211 prior to this call.
* For cfg80211 drivers this means you must first use wiphy_register(),
* for mac80211 drivers you must first use ieee80211_register_hw().
*
* Drivers should check the return value, its possible you can get
* an -ENOMEM or an -EINVAL.
*
* Return: 0 on success. -ENOMEM, -EINVAL.
*/
int regulatory_hint_user(const char *alpha2,
enum nl80211_user_reg_hint_type user_reg_hint_type);
/**
* regulatory_set_wiphy_regd - set regdom info for self managed drivers
* @wiphy: the wireless device we want to process the regulatory domain on
@ -7445,6 +7472,15 @@ void cfg80211_pmsr_complete(struct wireless_dev *wdev,
bool cfg80211_iftype_allowed(struct wiphy *wiphy, enum nl80211_iftype iftype,
bool is_4addr, u8 check_swif);
/**
* cfg80211_is_gratuitous_arp_unsolicited_na - packet is grat. ARP/unsol. NA
* @skb: the input packet, must be an ethernet frame already
*
* Return: %true if the packet is a gratuitous ARP or unsolicited NA packet.
* This is used to drop packets that shouldn't occur because the AP implements
* a proxy service.
*/
bool cfg80211_is_gratuitous_arp_unsolicited_na(struct sk_buff *skb);
/* Logging, debugging and troubleshooting/diagnostic helpers. */

View File

@ -815,7 +815,8 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
for (freq = start_freq; freq <= end_freq; freq += 20) {
c = ieee80211_get_channel(wiphy, freq);
if (!c || c->flags & prohibited_flags)
if (!c || ((c->flags & prohibited_flags) &&
!(wiphy->flags & WIPHY_FLAG_DFS_OFFLOAD)))
return false;
}

1305
net/wireless/db.txt 100644

File diff suppressed because it is too large Load Diff

View File

@ -2951,6 +2951,7 @@ int regulatory_hint_user(const char *alpha2,
return 0;
}
EXPORT_SYMBOL(regulatory_hint_user);
int regulatory_hint_indoor(bool is_indoor, u32 portid)
{

View File

@ -2150,3 +2150,54 @@ bool cfg80211_iftype_allowed(struct wiphy *wiphy, enum nl80211_iftype iftype,
return false;
}
EXPORT_SYMBOL(cfg80211_iftype_allowed);
bool cfg80211_is_gratuitous_arp_unsolicited_na(struct sk_buff *skb)
{
const struct ethhdr *eth = (void *)skb->data;
const struct {
struct arphdr hdr;
u8 ar_sha[ETH_ALEN];
u8 ar_sip[4];
u8 ar_tha[ETH_ALEN];
u8 ar_tip[4];
} __packed *arp;
const struct ipv6hdr *ipv6;
const struct icmp6hdr *icmpv6;
switch (eth->h_proto) {
case cpu_to_be16(ETH_P_ARP):
/* can't say - but will probably be dropped later anyway */
if (!pskb_may_pull(skb, sizeof(*eth) + sizeof(*arp)))
return false;
arp = (void *)(eth + 1);
if ((arp->hdr.ar_op == cpu_to_be16(ARPOP_REPLY) ||
arp->hdr.ar_op == cpu_to_be16(ARPOP_REQUEST)) &&
!memcmp(arp->ar_sip, arp->ar_tip, sizeof(arp->ar_sip)))
return true;
break;
case cpu_to_be16(ETH_P_IPV6):
/* can't say - but will probably be dropped later anyway */
if (!pskb_may_pull(skb, sizeof(*eth) + sizeof(*ipv6) +
sizeof(*icmpv6)))
return false;
ipv6 = (void *)(eth + 1);
icmpv6 = (void *)(ipv6 + 1);
if (icmpv6->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT &&
!memcmp(&ipv6->saddr, &ipv6->daddr, sizeof(ipv6->saddr)))
return true;
break;
default:
/*
* no need to support other protocols, proxy service isn't
* specified for any others
*/
break;
}
return false;
}
EXPORT_SYMBOL(cfg80211_is_gratuitous_arp_unsolicited_na);