diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac')
34 files changed, 966 insertions, 730 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile index 90a977fe9a64..dc4c75083085 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile @@ -23,15 +23,15 @@ ccflags-y += -D__CHECK_ENDIAN__ obj-$(CONFIG_BRCMFMAC) += brcmfmac.o brcmfmac-objs += \ - wl_cfg80211.o \ + cfg80211.o \ chip.o \ fwil.o \ fweh.o \ fwsignal.o \ p2p.o \ proto.o \ - dhd_common.o \ - dhd_linux.o \ + common.o \ + core.o \ firmware.o \ feature.o \ btcoex.o \ @@ -43,14 +43,14 @@ brcmfmac-$(CONFIG_BRCMFMAC_PROTO_MSGBUF) += \ flowring.o \ msgbuf.o brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \ - dhd_sdio.o \ + sdio.o \ bcmsdh.o brcmfmac-$(CONFIG_BRCMFMAC_USB) += \ usb.o brcmfmac-$(CONFIG_BRCMFMAC_PCIE) += \ pcie.o brcmfmac-$(CONFIG_BRCMDBG) += \ - dhd_dbg.o + debug.o brcmfmac-$(CONFIG_BRCM_TRACING) += \ tracepoint.o brcmfmac-$(CONFIG_OF) += \ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c index a159ff3427de..8e0e91c4a0b1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c @@ -25,10 +25,10 @@ #include <brcmu_utils.h> #include <brcmu_wifi.h> -#include "dhd.h" -#include "dhd_bus.h" +#include "core.h" +#include "bus.h" #include "fwsignal.h" -#include "dhd_dbg.h" +#include "debug.h" #include "tracepoint.h" #include "proto.h" #include "bcdc.h" diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 8dbd5dbb78fd..f754ffcd0308 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -41,9 +41,9 @@ #include <chipcommon.h> #include <soc.h> #include "chip.h" -#include "dhd_bus.h" -#include "dhd_dbg.h" -#include "sdio_host.h" +#include "bus.h" +#include "debug.h" +#include "sdio.h" #include "of.h" #define SDIOH_API_ACCESS_RETRY_LIMIT 2 @@ -1064,6 +1064,16 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, if (!sdiodev->pdata) brcmf_of_probe(sdiodev); +#ifdef CONFIG_PM_SLEEP + /* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ + * is true or when platform data OOB irq is true). + */ + if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) && + ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) || + (sdiodev->pdata->oob_irq_supported))) + bus_if->wowl_supported = true; +#endif + atomic_set(&sdiodev->suspend, false); init_waitqueue_head(&sdiodev->request_word_wait); init_waitqueue_head(&sdiodev->request_buffer_wait); @@ -1116,34 +1126,39 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func) brcmf_dbg(SDIO, "Exit\n"); } +void brcmf_sdio_wowl_config(struct device *dev, bool enabled) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; + + brcmf_dbg(SDIO, "Configuring WOWL, enabled=%d\n", enabled); + sdiodev->wowl_enabled = enabled; +} + #ifdef CONFIG_PM_SLEEP static int brcmf_ops_sdio_suspend(struct device *dev) { - mmc_pm_flag_t sdio_flags; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; - int ret = 0; + mmc_pm_flag_t sdio_flags; brcmf_dbg(SDIO, "Enter\n"); - sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]); - if (!(sdio_flags & MMC_PM_KEEP_POWER)) { - brcmf_err("Host can't keep power while suspended\n"); - return -EINVAL; - } - atomic_set(&sdiodev->suspend, true); - ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER); - if (ret) { - brcmf_err("Failed to set pm_flags\n"); - atomic_set(&sdiodev->suspend, false); - return ret; + if (sdiodev->wowl_enabled) { + sdio_flags = MMC_PM_KEEP_POWER; + if (sdiodev->pdata->oob_irq_supported) + enable_irq_wake(sdiodev->pdata->oob_irq_nr); + else + sdio_flags = MMC_PM_WAKE_SDIO_IRQ; + if (sdio_set_host_pm_flags(sdiodev->func[1], sdio_flags)) + brcmf_err("Failed to set pm_flags %x\n", sdio_flags); } brcmf_sdio_wd_timer(sdiodev->bus, 0); - return ret; + return 0; } static int brcmf_ops_sdio_resume(struct device *dev) @@ -1152,6 +1167,8 @@ static int brcmf_ops_sdio_resume(struct device *dev) struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; brcmf_dbg(SDIO, "Enter\n"); + if (sdiodev->pdata->oob_irq_supported) + disable_irq_wake(sdiodev->pdata->oob_irq_nr); brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS); atomic_set(&sdiodev->suspend, false); return 0; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c b/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c index a29ac4977b3a..0445163991b7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c @@ -20,13 +20,13 @@ #include <brcmu_wifi.h> #include <brcmu_utils.h> #include <defs.h> -#include <dhd.h> -#include <dhd_dbg.h> +#include "core.h" +#include "debug.h" #include "fwil.h" #include "fwil_types.h" #include "btcoex.h" #include "p2p.h" -#include "wl_cfg80211.h" +#include "cfg80211.h" /* T1 start SCO/eSCO priority suppression */ #define BRCMF_BTCOEX_OPPR_WIN_TIME 2000 diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/bus.h index 80e73a1262be..ef344e47218a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/bus.h @@ -14,10 +14,10 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _BRCMF_BUS_H_ -#define _BRCMF_BUS_H_ +#ifndef BRCMFMAC_BUS_H +#define BRCMFMAC_BUS_H -#include "dhd_dbg.h" +#include "debug.h" /* IDs of the 6 default common rings of msgbuf protocol */ #define BRCMF_H2D_MSGRING_CONTROL_SUBMIT 0 @@ -227,8 +227,7 @@ void brcmf_txflowblock(struct device *dev, bool state); void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success); int brcmf_bus_start(struct device *dev); -s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, - u32 len); +s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len); void brcmf_bus_add_txhdrlen(struct device *dev, uint len); #ifdef CONFIG_BRCMFMAC_SDIO @@ -241,4 +240,4 @@ void brcmf_usb_exit(void); void brcmf_usb_register(void); #endif -#endif /* _BRCMF_BUS_H_ */ +#endif /* BRCMFMAC_BUS_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index 39b45c038a93..3aecc5f48719 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -26,18 +26,18 @@ #include <brcmu_utils.h> #include <defs.h> #include <brcmu_wifi.h> -#include "dhd.h" -#include "dhd_dbg.h" +#include "core.h" +#include "debug.h" #include "tracepoint.h" #include "fwil_types.h" #include "p2p.h" #include "btcoex.h" -#include "wl_cfg80211.h" +#include "cfg80211.h" #include "feature.h" #include "fwil.h" #include "proto.h" #include "vendor.h" -#include "dhd_bus.h" +#include "bus.h" #define BRCMF_SCAN_IE_LEN_MAX 2048 #define BRCMF_PNO_VERSION 2 @@ -520,6 +520,95 @@ brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev) ADDR_INDIRECT); } +static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp) +{ + struct brcmf_mbss_ssid_le mbss_ssid_le; + int bsscfgidx; + int err; + + memset(&mbss_ssid_le, 0, sizeof(mbss_ssid_le)); + bsscfgidx = brcmf_get_next_free_bsscfgidx(ifp->drvr); + if (bsscfgidx < 0) + return bsscfgidx; + + mbss_ssid_le.bsscfgidx = cpu_to_le32(bsscfgidx); + mbss_ssid_le.SSID_len = cpu_to_le32(5); + sprintf(mbss_ssid_le.SSID, "ssid%d" , bsscfgidx); + + err = brcmf_fil_bsscfg_data_set(ifp, "bsscfg:ssid", &mbss_ssid_le, + sizeof(mbss_ssid_le)); + if (err < 0) + brcmf_err("setting ssid failed %d\n", err); + + return err; +} + +/** + * brcmf_ap_add_vif() - create a new AP virtual interface for multiple BSS + * + * @wiphy: wiphy device of new interface. + * @name: name of the new interface. + * @flags: not used. + * @params: contains mac address for AP device. + */ +static +struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name, + u32 *flags, struct vif_params *params) +{ + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); + struct brcmf_cfg80211_vif *vif; + int err; + + if (brcmf_cfg80211_vif_event_armed(cfg)) + return ERR_PTR(-EBUSY); + + brcmf_dbg(INFO, "Adding vif \"%s\"\n", name); + + vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_AP, false); + if (IS_ERR(vif)) + return (struct wireless_dev *)vif; + + brcmf_cfg80211_arm_vif_event(cfg, vif); + + err = brcmf_cfg80211_request_ap_if(ifp); + if (err) { + brcmf_cfg80211_arm_vif_event(cfg, NULL); + goto fail; + } + + /* wait for firmware event */ + err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD, + msecs_to_jiffies(1500)); + brcmf_cfg80211_arm_vif_event(cfg, NULL); + if (!err) { + brcmf_err("timeout occurred\n"); + err = -EIO; + goto fail; + } + + /* interface created in firmware */ + ifp = vif->ifp; + if (!ifp) { + brcmf_err("no if pointer provided\n"); + err = -ENOENT; + goto fail; + } + + strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1); + err = brcmf_net_attach(ifp, true); + if (err) { + brcmf_err("Registering netdevice failed\n"); + goto fail; + } + + return &ifp->vif->wdev; + +fail: + brcmf_free_vif(vif); + return ERR_PTR(err); +} + static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif) { enum nl80211_iftype iftype; @@ -545,12 +634,16 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, switch (type) { case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_MESH_POINT: return ERR_PTR(-EOPNOTSUPP); + case NL80211_IFTYPE_AP: + wdev = brcmf_ap_add_vif(wiphy, name, flags, params); + if (!IS_ERR(wdev)) + brcmf_cfg80211_update_proto_addr_mode(wdev); + return wdev; case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_P2P_DEVICE: @@ -1815,6 +1908,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, return -EIO; clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state); + clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state); cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL); memcpy(&scbval.ea, &profile->bssid, ETH_ALEN); @@ -2785,6 +2879,44 @@ static __always_inline void brcmf_delay(u32 ms) } } +static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4], + u8 *pattern, u32 patternsize, u8 *mask, + u32 packet_offset) +{ + struct brcmf_fil_wowl_pattern_le *filter; + u32 masksize; + u32 patternoffset; + u8 *buf; + u32 bufsize; + s32 ret; + + masksize = (patternsize + 7) / 8; + patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize; + + bufsize = sizeof(*filter) + patternsize + masksize; + buf = kzalloc(bufsize, GFP_KERNEL); + if (!buf) + return -ENOMEM; + filter = (struct brcmf_fil_wowl_pattern_le *)buf; + + memcpy(filter->cmd, cmd, 4); + filter->masksize = cpu_to_le32(masksize); + filter->offset = cpu_to_le32(packet_offset); + filter->patternoffset = cpu_to_le32(patternoffset); + filter->patternsize = cpu_to_le32(patternsize); + filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP); + + if ((mask) && (masksize)) + memcpy(buf + sizeof(*filter), mask, masksize); + if ((pattern) && (patternsize)) + memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize); + + ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize); + + kfree(buf); + return ret; +} + static s32 brcmf_cfg80211_resume(struct wiphy *wiphy) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); @@ -2794,10 +2926,11 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy) brcmf_dbg(TRACE, "Enter\n"); if (cfg->wowl_enabled) { + brcmf_configure_arp_offload(ifp, true); brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, cfg->pre_wowl_pmmode); - brcmf_fil_iovar_data_set(ifp, "wowl_pattern", "clr", 4); brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0); + brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0); cfg->wowl_enabled = false; } return 0; @@ -2808,21 +2941,29 @@ static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg, struct cfg80211_wowlan *wowl) { u32 wowl_config; + u32 i; brcmf_dbg(TRACE, "Suspend, wowl config.\n"); + brcmf_configure_arp_offload(ifp, false); brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->pre_wowl_pmmode); brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX); wowl_config = 0; if (wowl->disconnect) - wowl_config |= WL_WOWL_DIS | WL_WOWL_BCN | WL_WOWL_RETR; - /* Note: if "wowl" target and not "wowlpf" then wowl_bcn_loss - * should be configured. This paramater is not supported by - * wowlpf. - */ + wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR; if (wowl->magic_pkt) - wowl_config |= WL_WOWL_MAGIC; + wowl_config |= BRCMF_WOWL_MAGIC; + if ((wowl->patterns) && (wowl->n_patterns)) { + wowl_config |= BRCMF_WOWL_NET; + for (i = 0; i < wowl->n_patterns; i++) { + brcmf_config_wowl_pattern(ifp, "add", + (u8 *)wowl->patterns[i].pattern, + wowl->patterns[i].pattern_len, + (u8 *)wowl->patterns[i].mask, + wowl->patterns[i].pkt_offset); + } + } brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config); brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1); brcmf_bus_wowl_config(cfg->pub->bus_if, true); @@ -2885,7 +3026,7 @@ brcmf_update_pmklist(struct net_device *ndev, struct brcmf_cfg80211_pmk_list *pmk_list, s32 err) { int i, j; - int pmkid_len; + u32 pmkid_len; pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid); @@ -2913,8 +3054,7 @@ brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, struct brcmf_if *ifp = netdev_priv(ndev); struct pmkid_list *pmkids = &cfg->pmk_list->pmkids; s32 err = 0; - int i; - int pmkid_len; + u32 pmkid_len, i; brcmf_dbg(TRACE, "Enter\n"); if (!check_vif_up(ifp->vif)) @@ -2953,7 +3093,7 @@ brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, struct brcmf_if *ifp = netdev_priv(ndev); struct pmkid_list pmkid; s32 err = 0; - int i, pmkid_len; + u32 pmkid_len, i; brcmf_dbg(TRACE, "Enter\n"); if (!check_vif_up(ifp->vif)) @@ -3314,11 +3454,10 @@ static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie) } static s32 -brcmf_configure_wpaie(struct net_device *ndev, +brcmf_configure_wpaie(struct brcmf_if *ifp, const struct brcmf_vs_tlv *wpa_ie, bool is_rsn_ie) { - struct brcmf_if *ifp = netdev_priv(ndev); u32 auth = 0; /* d11 open authentication */ u16 count; s32 err = 0; @@ -3793,6 +3932,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, enum nl80211_iftype dev_role; struct brcmf_fil_bss_enable_le bss_enable; u16 chanspec; + bool mbss; brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n", settings->chandef.chan->hw_value, @@ -3803,6 +3943,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, settings->inactivity_timeout); dev_role = ifp->vif->wdev.iftype; + mbss = ifp->vif->mbss; memset(&ssid_le, 0, sizeof(ssid_le)); if (settings->ssid == NULL || settings->ssid_len == 0) { @@ -3822,8 +3963,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len); } - brcmf_set_mpc(ifp, 0); - brcmf_configure_arp_offload(ifp, false); + if (!mbss) { + brcmf_set_mpc(ifp, 0); + brcmf_configure_arp_offload(ifp, false); + } /* find the RSN_IE */ rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, @@ -3837,13 +3980,16 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_dbg(TRACE, "WPA(2) IE is found\n"); if (wpa_ie != NULL) { /* WPA IE */ - err = brcmf_configure_wpaie(ndev, wpa_ie, false); + err = brcmf_configure_wpaie(ifp, wpa_ie, false); if (err < 0) goto exit; } else { + struct brcmf_vs_tlv *tmp_ie; + + tmp_ie = (struct brcmf_vs_tlv *)rsn_ie; + /* RSN IE */ - err = brcmf_configure_wpaie(ndev, - (struct brcmf_vs_tlv *)rsn_ie, true); + err = brcmf_configure_wpaie(ifp, tmp_ie, true); if (err < 0) goto exit; } @@ -3854,45 +4000,53 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon); - chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef); - err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec); - if (err < 0) { - brcmf_err("Set Channel failed: chspec=%d, %d\n", chanspec, err); - goto exit; - } - - if (settings->beacon_interval) { - err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, - settings->beacon_interval); + if (!mbss) { + chanspec = chandef_to_chanspec(&cfg->d11inf, + &settings->chandef); + err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec); if (err < 0) { - brcmf_err("Beacon Interval Set Error, %d\n", err); + brcmf_err("Set Channel failed: chspec=%d, %d\n", + chanspec, err); goto exit; } - } - if (settings->dtim_period) { - err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD, - settings->dtim_period); - if (err < 0) { - brcmf_err("DTIM Interval Set Error, %d\n", err); - goto exit; + + if (settings->beacon_interval) { + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, + settings->beacon_interval); + if (err < 0) { + brcmf_err("Beacon Interval Set Error, %d\n", + err); + goto exit; + } + } + if (settings->dtim_period) { + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD, + settings->dtim_period); + if (err < 0) { + brcmf_err("DTIM Interval Set Error, %d\n", err); + goto exit; + } } - } - if (dev_role == NL80211_IFTYPE_AP) { - err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); + if (dev_role == NL80211_IFTYPE_AP) { + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); + if (err < 0) { + brcmf_err("BRCMF_C_DOWN error %d\n", err); + goto exit; + } + brcmf_fil_iovar_int_set(ifp, "apsta", 0); + } + + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1); if (err < 0) { - brcmf_err("BRCMF_C_DOWN error %d\n", err); + brcmf_err("SET INFRA error %d\n", err); goto exit; } - brcmf_fil_iovar_int_set(ifp, "apsta", 0); - } - - err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1); - if (err < 0) { - brcmf_err("SET INFRA error %d\n", err); - goto exit; } if (dev_role == NL80211_IFTYPE_AP) { + if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss)) + brcmf_fil_iovar_int_set(ifp, "mbss", 1); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1); if (err < 0) { brcmf_err("setting AP mode failed %d\n", err); @@ -3937,7 +4091,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); exit: - if (err) { + if ((err) && (!mbss)) { brcmf_set_mpc(ifp, 1); brcmf_configure_arp_offload(ifp, true); } @@ -3958,20 +4112,31 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) /* first to make sure they get processed by fw. */ msleep(400); + if (ifp->vif->mbss) { + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); + return err; + } + memset(&join_params, 0, sizeof(join_params)); err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, &join_params, sizeof(join_params)); if (err < 0) brcmf_err("SET SSID error (%d)\n", err); - err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); if (err < 0) - brcmf_err("BRCMF_C_UP error %d\n", err); + brcmf_err("BRCMF_C_DOWN error %d\n", err); err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0); if (err < 0) brcmf_err("setting AP mode failed %d\n", err); err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0); if (err < 0) brcmf_err("setting INFRA mode failed %d\n", err); + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) + brcmf_fil_iovar_int_set(ifp, "mbss", 0); + /* Bring device back up so it can be used again */ + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1); + if (err < 0) + brcmf_err("BRCMF_C_UP error %d\n", err); } else { bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx); bss_enable.enable = cpu_to_le32(0); @@ -4004,24 +4169,24 @@ brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev, static int brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, - const u8 *mac) + struct station_del_parameters *params) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_scb_val_le scbval; struct brcmf_if *ifp = netdev_priv(ndev); s32 err; - if (!mac) + if (!params->mac) return -EFAULT; - brcmf_dbg(TRACE, "Enter %pM\n", mac); + brcmf_dbg(TRACE, "Enter %pM\n", params->mac); if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; if (!check_vif_up(ifp->vif)) return -EIO; - memcpy(&scbval.ea, mac, ETH_ALEN); + memcpy(&scbval.ea, params->mac, ETH_ALEN); scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING); err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, sizeof(scbval)); @@ -4323,7 +4488,9 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, enum nl80211_iftype type, bool pm_block) { + struct brcmf_cfg80211_vif *vif_walk; struct brcmf_cfg80211_vif *vif; + bool mbss; brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n", sizeof(*vif)); @@ -4339,6 +4506,17 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, brcmf_init_prof(&vif->profile); + if (type == NL80211_IFTYPE_AP) { + mbss = false; + list_for_each_entry(vif_walk, &cfg->vif_list, list) { + if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) { + mbss = true; + break; + } + } + vif->mbss = mbss; + } + list_add_tail(&vif->list, &cfg->vif_list); return vif; } @@ -4581,6 +4759,7 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, const struct brcmf_event_msg *e, void *data) { + struct brcmf_if *ifp = netdev_priv(ndev); static int generation; u32 event = e->event_code; u32 reason = e->reason; @@ -4591,6 +4770,8 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, ndev != cfg_to_ndev(cfg)) { brcmf_dbg(CONN, "AP mode link down\n"); complete(&cfg->vif_disabled); + if (ifp->vif->mbss) + brcmf_remove_interface(ifp->drvr, ifp->bssidx); return 0; } @@ -5382,7 +5563,28 @@ static int brcmf_setup_wiphybands(struct wiphy *wiphy) return 0; } -static const struct ieee80211_iface_limit brcmf_iface_limits[] = { +static const struct ieee80211_iface_limit brcmf_iface_limits_mbss[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) + }, + { + .max = 4, + .types = BIT(NL80211_IFTYPE_AP) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE) + } +}; + +static const struct ieee80211_iface_limit brcmf_iface_limits_sbss[] = { { .max = 2, .types = BIT(NL80211_IFTYPE_STATION) | @@ -5403,8 +5605,8 @@ static struct ieee80211_iface_combination brcmf_iface_combos[] = { { .max_interfaces = BRCMF_IFACE_MAX_CNT, .num_different_channels = 1, - .n_limits = ARRAY_SIZE(brcmf_iface_limits), - .limits = brcmf_iface_limits + .n_limits = ARRAY_SIZE(brcmf_iface_limits_sbss), + .limits = brcmf_iface_limits_sbss, } }; @@ -5446,10 +5648,13 @@ static void brcmf_wiphy_pno_params(struct wiphy *wiphy) wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; } - #ifdef CONFIG_PM static const struct wiphy_wowlan_support brcmf_wowlan_support = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, + .n_patterns = BRCMF_WOWL_MAXPATTERNS, + .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE, + .pattern_min_len = 1, + .max_pkt_offset = 1500, }; #endif @@ -5477,6 +5682,10 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) ifc_combo = brcmf_iface_combos[0]; if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) ifc_combo.num_different_channels = 2; + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) { + ifc_combo.n_limits = ARRAY_SIZE(brcmf_iface_limits_mbss), + ifc_combo.limits = brcmf_iface_limits_mbss; + } wiphy->iface_combinations = kmemdup(&ifc_combo, sizeof(ifc_combo), GFP_KERNEL); @@ -5613,7 +5822,8 @@ enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp) return wdev->iftype; } -bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, unsigned long state) +bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, + unsigned long state) { struct brcmf_cfg80211_vif *vif; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h index 6abf94e41d3d..9e98b8d52757 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h @@ -14,8 +14,8 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _wl_cfg80211_h_ -#define _wl_cfg80211_h_ +#ifndef BRCMFMAC_CFG80211_H +#define BRCMFMAC_CFG80211_H /* for brcmu_d11inf */ #include <brcmu_d11.h> @@ -183,6 +183,7 @@ struct vif_saved_ie { * @pm_block: power-management blocked. * @list: linked list. * @mgmt_rx_reg: registered rx mgmt frame types. + * @mbss: Multiple BSS type, set if not first AP (not relevant for P2P). */ struct brcmf_cfg80211_vif { struct brcmf_if *ifp; @@ -194,6 +195,7 @@ struct brcmf_cfg80211_vif { struct vif_saved_ie saved_ie; struct list_head list; u16 mgmt_rx_reg; + bool mbss; }; /* association inform */ @@ -480,7 +482,8 @@ const struct brcmf_tlv * brcmf_parse_tlvs(const void *buf, int buflen, uint key); u16 channel_to_chanspec(struct brcmu_d11inf *d11inf, struct ieee80211_channel *ch); -bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, unsigned long state); +bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, + unsigned long state); void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg, struct brcmf_cfg80211_vif *vif); bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg); @@ -493,4 +496,4 @@ void brcmf_set_mpc(struct brcmf_if *ndev, int mpc); void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg); void brcmf_cfg80211_free_netdev(struct net_device *ndev); -#endif /* _wl_cfg80211_h_ */ +#endif /* BRCMFMAC_CFG80211_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c index 95efde868db8..ddae0b5e56ec 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c @@ -25,7 +25,7 @@ #include <brcm_hw_ids.h> #include <brcmu_utils.h> #include <chipcommon.h> -#include "dhd_dbg.h" +#include "debug.h" #include "chip.h" /* SOC Interconnect types (aka chip types) */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/common.c b/drivers/net/wireless/brcm80211/brcmfmac/common.c new file mode 100644 index 000000000000..1861a13e8d03 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/common.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/netdevice.h> +#include <brcmu_wifi.h> +#include <brcmu_utils.h> +#include "core.h" +#include "bus.h" +#include "debug.h" +#include "fwil.h" +#include "fwil_types.h" +#include "tracepoint.h" + +#define BRCMF_DEFAULT_BCN_TIMEOUT 3 +#define BRCMF_DEFAULT_SCAN_CHANNEL_TIME 40 +#define BRCMF_DEFAULT_SCAN_UNASSOC_TIME 40 + +/* boost value for RSSI_DELTA in preferred join selection */ +#define BRCMF_JOIN_PREF_RSSI_BOOST 8 + +int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) +{ + s8 eventmask[BRCMF_EVENTING_MASK_LEN]; + u8 buf[BRCMF_DCMD_SMLEN]; + struct brcmf_join_pref_params join_pref_params[2]; + char *ptr; + s32 err; + + /* retreive mac address */ + err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr, + sizeof(ifp->mac_addr)); + if (err < 0) { + brcmf_err("Retreiving cur_etheraddr failed, %d\n", + err); + goto done; + } + memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac)); + + /* query for 'ver' to get version info from firmware */ + memset(buf, 0, sizeof(buf)); + strcpy(buf, "ver"); + err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf)); + if (err < 0) { + brcmf_err("Retreiving version information failed, %d\n", + err); + goto done; + } + ptr = (char *)buf; + strsep(&ptr, "\n"); + + /* Print fw version info */ + brcmf_err("Firmware version = %s\n", buf); + + /* locate firmware version number for ethtool */ + ptr = strrchr(buf, ' ') + 1; + strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver)); + + /* set mpc */ + err = brcmf_fil_iovar_int_set(ifp, "mpc", 1); + if (err) { + brcmf_err("failed setting mpc\n"); + goto done; + } + + /* + * Setup timeout if Beacons are lost and roam is off to report + * link down + */ + err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", + BRCMF_DEFAULT_BCN_TIMEOUT); + if (err) { + brcmf_err("bcn_timeout error (%d)\n", err); + goto done; + } + + /* Enable/Disable build-in roaming to allowed ext supplicant to take + * of romaing + */ + err = brcmf_fil_iovar_int_set(ifp, "roam_off", 1); + if (err) { + brcmf_err("roam_off error (%d)\n", err); + goto done; + } + + /* Setup join_pref to select target by RSSI(with boost on 5GHz) */ + join_pref_params[0].type = BRCMF_JOIN_PREF_RSSI_DELTA; + join_pref_params[0].len = 2; + join_pref_params[0].rssi_gain = BRCMF_JOIN_PREF_RSSI_BOOST; + join_pref_params[0].band = WLC_BAND_5G; + join_pref_params[1].type = BRCMF_JOIN_PREF_RSSI; + join_pref_params[1].len = 2; + join_pref_params[1].rssi_gain = 0; + join_pref_params[1].band = 0; + err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params, + sizeof(join_pref_params)); + if (err) + brcmf_err("Set join_pref error (%d)\n", err); + + /* Setup event_msgs, enable E_IF */ + err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask, + BRCMF_EVENTING_MASK_LEN); + if (err) { + brcmf_err("Get event_msgs error (%d)\n", err); + goto done; + } + setbit(eventmask, BRCMF_E_IF); + err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask, + BRCMF_EVENTING_MASK_LEN); + if (err) { + brcmf_err("Set event_msgs 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); + if (err) { + brcmf_err("BRCMF_C_SET_SCAN_CHANNEL_TIME error (%d)\n", + err); + goto done; + } + + /* Setup default scan unassoc time */ + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME, + BRCMF_DEFAULT_SCAN_UNASSOC_TIME); + if (err) { + brcmf_err("BRCMF_C_SET_SCAN_UNASSOC_TIME error (%d)\n", + err); + goto done; + } + + /* do bus specific preinit here */ + err = brcmf_bus_preinit(ifp->drvr->bus_if); +done: + return err; +} + +#if defined(CONFIG_BRCM_TRACING) || defined(CONFIG_BRCMDBG) +void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...) +{ + struct va_format vaf = { + .fmt = fmt, + }; + va_list args; + + va_start(args, fmt); + vaf.va = &args; + if (brcmf_msg_level & level) + pr_debug("%s %pV", func, &vaf); + trace_brcmf_dbg(level, func, &vaf); + va_end(args); +} +#endif diff --git a/drivers/net/wireless/brcm80211/brcmfmac/commonring.c b/drivers/net/wireless/brcm80211/brcmfmac/commonring.c index c6d65b8e1e15..77656c711bed 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/commonring.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.c @@ -19,7 +19,7 @@ #include <brcmu_utils.h> #include <brcmu_wifi.h> -#include "dhd.h" +#include "core.h" #include "commonring.h" diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c index fb1043908a23..effe6d7831d9 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c @@ -22,12 +22,12 @@ #include <brcmu_utils.h> #include <brcmu_wifi.h> -#include "dhd.h" -#include "dhd_bus.h" -#include "dhd_dbg.h" +#include "core.h" +#include "bus.h" +#include "debug.h" #include "fwil_types.h" #include "p2p.h" -#include "wl_cfg80211.h" +#include "cfg80211.h" #include "fwil.h" #include "fwsignal.h" #include "feature.h" @@ -836,7 +836,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, return ifp; } -void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx) +static void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx) { struct brcmf_if *ifp; @@ -869,6 +869,38 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx) } } +void brcmf_remove_interface(struct brcmf_pub *drvr, u32 bssidx) +{ + if (drvr->iflist[bssidx]) { + brcmf_fws_del_interface(drvr->iflist[bssidx]); + brcmf_del_if(drvr, bssidx); + } +} + +int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr) +{ + int ifidx; + int bsscfgidx; + bool available; + int highest; + + available = false; + bsscfgidx = 2; + highest = 2; + for (ifidx = 0; ifidx < BRCMF_MAX_IFS; ifidx++) { + if (drvr->iflist[ifidx]) { + if (drvr->iflist[ifidx]->bssidx == bsscfgidx) + bsscfgidx = highest + 1; + else if (drvr->iflist[ifidx]->bssidx > highest) + highest = drvr->iflist[ifidx]->bssidx; + } else { + available = true; + } + } + + return available ? bsscfgidx : -ENOMEM; +} + int brcmf_attach(struct device *dev) { struct brcmf_pub *drvr = NULL; @@ -1033,10 +1065,7 @@ void brcmf_detach(struct device *dev) /* make sure primary interface removed last */ for (i = BRCMF_MAX_IFS-1; i > -1; i--) - if (drvr->iflist[i]) { - brcmf_fws_del_interface(drvr->iflist[i]); - brcmf_del_if(drvr, i); - } + brcmf_remove_interface(drvr, i); brcmf_cfg80211_detach(drvr->config); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/core.h index 5e4317dbc2b0..23f74b139cc8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h @@ -18,8 +18,8 @@ * Common types * */ -#ifndef _BRCMF_H_ -#define _BRCMF_H_ +#ifndef BRCMFMAC_CORE_H +#define BRCMFMAC_CORE_H #include "fweh.h" @@ -83,7 +83,6 @@ struct brcmf_pub { /* Internal brcmf items */ uint hdrlen; /* Total BRCMF header length (proto + bus) */ uint rxsz; /* Rx buffer size bus module should use */ - u8 wme_dp; /* wme discard priority */ /* Dongle media info */ char fwver[BRCMF_DRIVER_FIRMWARE_VERSION_LEN]; @@ -176,7 +175,8 @@ char *brcmf_ifname(struct brcmf_pub *drvr, int idx); int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, char *name, u8 *mac_addr); -void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx); +void brcmf_remove_interface(struct brcmf_pub *drvr, u32 bssidx); +int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr); void brcmf_txflowblock_if(struct brcmf_if *ifp, enum brcmf_netif_stop_reason reason, bool state); void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx, @@ -186,4 +186,4 @@ void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb); /* Sets dongle media info (drv_version, mac address). */ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp); -#endif /* _BRCMF_H_ */ +#endif /* BRCMFMAC_CORE_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/debug.c index be9f4f829192..9b473d50b005 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.c @@ -19,9 +19,9 @@ #include <brcmu_wifi.h> #include <brcmu_utils.h> -#include "dhd.h" -#include "dhd_bus.h" -#include "dhd_dbg.h" +#include "core.h" +#include "bus.h" +#include "debug.h" static struct dentry *root_folder; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/debug.h index dec40d316c82..eb0b8c47479d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.h @@ -14,8 +14,8 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _BRCMF_DBG_H_ -#define _BRCMF_DBG_H_ +#ifndef BRCMFMAC_DEBUG_H +#define BRCMFMAC_DEBUG_H /* message levels */ #define BRCMF_TRACE_VAL 0x00000002 @@ -133,4 +133,4 @@ int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn, } #endif -#endif /* _BRCMF_DBG_H_ */ +#endif /* BRCMFMAC_DEBUG_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c deleted file mode 100644 index d991f8e3d9ec..000000000000 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/netdevice.h> -#include <brcmu_wifi.h> -#include <brcmu_utils.h> -#include "dhd.h" -#include "dhd_bus.h" -#include "dhd_dbg.h" -#include "fwil.h" -#include "fwil_types.h" -#include "tracepoint.h" - -#define PKTFILTER_BUF_SIZE 128 -#define BRCMF_DEFAULT_BCN_TIMEOUT 3 -#define BRCMF_DEFAULT_SCAN_CHANNEL_TIME 40 -#define BRCMF_DEFAULT_SCAN_UNASSOC_TIME 40 -#define BRCMF_DEFAULT_PACKET_FILTER "100 0 0 0 0x01 0x00" - -/* boost value for RSSI_DELTA in preferred join selection */ -#define BRCMF_JOIN_PREF_RSSI_BOOST 8 - - -bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, - struct sk_buff *pkt, int prec) -{ - struct sk_buff *p; - int eprec = -1; /* precedence to evict from */ - bool discard_oldest; - struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_pub *drvr = bus_if->drvr; - - /* Fast case, precedence queue is not full and we are also not - * exceeding total queue length - */ - if (!pktq_pfull(q, prec) && !pktq_full(q)) { - brcmu_pktq_penq(q, prec, pkt); - return true; - } - - /* Determine precedence from which to evict packet, if any */ - if (pktq_pfull(q, prec)) - eprec = prec; - else if (pktq_full(q)) { - p = brcmu_pktq_peek_tail(q, &eprec); - if (eprec > prec) - return false; - } - - /* Evict if needed */ - if (eprec >= 0) { - /* Detect queueing to unconfigured precedence */ - discard_oldest = ac_bitmap_tst(drvr->wme_dp, eprec); - if (eprec == prec && !discard_oldest) - return false; /* refuse newer (incoming) packet */ - /* Evict packet according to discard policy */ - p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) : - brcmu_pktq_pdeq_tail(q, eprec); - if (p == NULL) - brcmf_err("brcmu_pktq_penq() failed, oldest %d\n", - discard_oldest); - - brcmu_pkt_buf_free_skb(p); - } - - /* Enqueue */ - p = brcmu_pktq_penq(q, prec, pkt); - if (p == NULL) - brcmf_err("brcmu_pktq_penq() failed\n"); - - return p != NULL; -} - -/* Convert user's input in hex pattern to byte-size mask */ -static int brcmf_c_pattern_atoh(char *src, char *dst) -{ - int i; - if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) { - brcmf_err("Mask invalid format. Needs to start with 0x\n"); - return -EINVAL; - } - src = src + 2; /* Skip past 0x */ - if (strlen(src) % 2 != 0) { - brcmf_err("Mask invalid format. Length must be even.\n"); - return -EINVAL; - } - for (i = 0; *src != '\0'; i++) { - unsigned long res; - char num[3]; - strncpy(num, src, 2); - num[2] = '\0'; - if (kstrtoul(num, 16, &res)) - return -EINVAL; - dst[i] = (u8)res; - src += 2; - } - return i; -} - -static void -brcmf_c_pktfilter_offload_enable(struct brcmf_if *ifp, char *arg, int enable, - int master_mode) -{ - unsigned long res; - char *argv; - char *arg_save = NULL, *arg_org = NULL; - s32 err; - struct brcmf_pkt_filter_enable_le enable_parm; - - arg_save = kstrdup(arg, GFP_ATOMIC); - if (!arg_save) - goto fail; - - arg_org = arg_save; - - argv = strsep(&arg_save, " "); - - if (argv == NULL) { - brcmf_err("No args provided\n"); - goto fail; - } - - /* Parse packet filter id. */ - enable_parm.id = 0; - if (!kstrtoul(argv, 0, &res)) - enable_parm.id = cpu_to_le32((u32)res); - - /* Enable/disable the specified filter. */ - enable_parm.enable = cpu_to_le32(enable); - - err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_enable", &enable_parm, - sizeof(enable_parm)); - if (err) - brcmf_err("Set pkt_filter_enable error (%d)\n", err); - - /* Control the master mode */ - err = brcmf_fil_iovar_int_set(ifp, "pkt_filter_mode", master_mode); - if (err) - brcmf_err("Set pkt_filter_mode error (%d)\n", err); - -fail: - kfree(arg_org); -} - -static void brcmf_c_pktfilter_offload_set(struct brcmf_if *ifp, char *arg) -{ - struct brcmf_pkt_filter_le *pkt_filter; - unsigned long res; - int buf_len; - s32 err; - u32 mask_size; - u32 pattern_size; - char *argv[8], *buf = NULL; - int i = 0; - char *arg_save = NULL, *arg_org = NULL; - - arg_save = kstrdup(arg, GFP_ATOMIC); - if (!arg_save) - goto fail; - - arg_org = arg_save; - - buf = kmalloc(PKTFILTER_BUF_SIZE, GFP_ATOMIC); - if (!buf) - goto fail; - - argv[i] = strsep(&arg_save, " "); - while (argv[i]) { - i++; - if (i >= 8) { - brcmf_err("Too many parameters\n"); - goto fail; - } - argv[i] = strsep(&arg_save, " "); - } - - if (i != 6) { - brcmf_err("Not enough args provided %d\n", i); - goto fail; - } - - pkt_filter = (struct brcmf_pkt_filter_le *)buf; - - /* Parse packet filter id. */ - pkt_filter->id = 0; - if (!kstrtoul(argv[0], 0, &res)) - pkt_filter->id = cpu_to_le32((u32)res); - - /* Parse filter polarity. */ - pkt_filter->negate_match = 0; - if (!kstrtoul(argv[1], 0, &res)) - pkt_filter->negate_match = cpu_to_le32((u32)res); - - /* Parse filter type. */ - pkt_filter->type = 0; - if (!kstrtoul(argv[2], 0, &res)) - pkt_filter->type = cpu_to_le32((u32)res); - - /* Parse pattern filter offset. */ - pkt_filter->u.pattern.offset = 0; - if (!kstrtoul(argv[3], 0, &res)) - pkt_filter->u.pattern.offset = cpu_to_le32((u32)res); - - /* Parse pattern filter mask. */ - mask_size = brcmf_c_pattern_atoh(argv[4], - (char *)pkt_filter->u.pattern.mask_and_pattern); - - /* Parse pattern filter pattern. */ - pattern_size = brcmf_c_pattern_atoh(argv[5], - (char *)&pkt_filter->u.pattern.mask_and_pattern[mask_size]); - - if (mask_size != pattern_size) { - brcmf_err("Mask and pattern not the same size\n"); - goto fail; - } - - pkt_filter->u.pattern.size_bytes = cpu_to_le32(mask_size); - buf_len = offsetof(struct brcmf_pkt_filter_le, - u.pattern.mask_and_pattern); - buf_len += mask_size + pattern_size; - - err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_add", pkt_filter, - buf_len); - if (err) - brcmf_err("Set pkt_filter_add error (%d)\n", err); - -fail: - kfree(arg_org); - - kfree(buf); -} - -int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) -{ - s8 eventmask[BRCMF_EVENTING_MASK_LEN]; - u8 buf[BRCMF_DCMD_SMLEN]; - struct brcmf_join_pref_params join_pref_params[2]; - char *ptr; - s32 err; - - /* retreive mac address */ - err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr, - sizeof(ifp->mac_addr)); - if (err < 0) { - brcmf_err("Retreiving cur_etheraddr failed, %d\n", - err); - goto done; - } - memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac)); - - /* query for 'ver' to get version info from firmware */ - memset(buf, 0, sizeof(buf)); - strcpy(buf, "ver"); - err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf)); - if (err < 0) { - brcmf_err("Retreiving version information failed, %d\n", - err); - goto done; - } - ptr = (char *)buf; - strsep(&ptr, "\n"); - - /* Print fw version info */ - brcmf_err("Firmware version = %s\n", buf); - - /* locate firmware version number for ethtool */ - ptr = strrchr(buf, ' ') + 1; - strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver)); - - /* set mpc */ - err = brcmf_fil_iovar_int_set(ifp, "mpc", 1); - if (err) { - brcmf_err("failed setting mpc\n"); - goto done; - } - - /* - * Setup timeout if Beacons are lost and roam is off to report - * link down - */ - err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", - BRCMF_DEFAULT_BCN_TIMEOUT); - if (err) { - brcmf_err("bcn_timeout error (%d)\n", err); - goto done; - } - - /* Enable/Disable build-in roaming to allowed ext supplicant to take - * of romaing - */ - err = brcmf_fil_iovar_int_set(ifp, "roam_off", 1); - if (err) { - brcmf_err("roam_off error (%d)\n", err); - goto done; - } - - /* Setup join_pref to select target by RSSI(with boost on 5GHz) */ - join_pref_params[0].type = BRCMF_JOIN_PREF_RSSI_DELTA; - join_pref_params[0].len = 2; - join_pref_params[0].rssi_gain = BRCMF_JOIN_PREF_RSSI_BOOST; - join_pref_params[0].band = WLC_BAND_5G; - join_pref_params[1].type = BRCMF_JOIN_PREF_RSSI; - join_pref_params[1].len = 2; - join_pref_params[1].rssi_gain = 0; - join_pref_params[1].band = 0; - err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params, - sizeof(join_pref_params)); - if (err) - brcmf_err("Set join_pref error (%d)\n", err); - - /* Setup event_msgs, enable E_IF */ - err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask, - BRCMF_EVENTING_MASK_LEN); - if (err) { - brcmf_err("Get event_msgs error (%d)\n", err); - goto done; - } - setbit(eventmask, BRCMF_E_IF); - err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask, - BRCMF_EVENTING_MASK_LEN); - if (err) { - brcmf_err("Set event_msgs 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); - if (err) { - brcmf_err("BRCMF_C_SET_SCAN_CHANNEL_TIME error (%d)\n", - err); - goto done; - } - - /* Setup default scan unassoc time */ - err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME, - BRCMF_DEFAULT_SCAN_UNASSOC_TIME); - if (err) { - brcmf_err("BRCMF_C_SET_SCAN_UNASSOC_TIME error (%d)\n", - err); - goto done; - } - - /* Setup packet filter */ - brcmf_c_pktfilter_offload_set(ifp, BRCMF_DEFAULT_PACKET_FILTER); - brcmf_c_pktfilter_offload_enable(ifp, BRCMF_DEFAULT_PACKET_FILTER, - 0, true); - - /* do bus specific preinit here */ - err = brcmf_bus_preinit(ifp->drvr->bus_if); -done: - return err; -} - -#ifdef CONFIG_BRCM_TRACING -void __brcmf_err(const char *func, const char *fmt, ...) -{ - struct va_format vaf = { - .fmt = fmt, - }; - va_list args; - - va_start(args, fmt); - vaf.va = &args; - pr_err("%s: %pV", func, &vaf); - trace_brcmf_err(func, &vaf); - va_end(args); -} -#endif -#if defined(CONFIG_BRCM_TRACING) || defined(CONFIG_BRCMDBG) -void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...) -{ - struct va_format vaf = { - .fmt = fmt, - }; - va_list args; - - va_start(args, fmt); - vaf.va = &args; - if (brcmf_msg_level & level) - pr_debug("%s %pV", func, &vaf); - trace_brcmf_dbg(level, func, &vaf); - va_end(args); -} -#endif diff --git a/drivers/net/wireless/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/brcm80211/brcmfmac/feature.c index aed53acef456..defb7a44e0bc 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c @@ -17,18 +17,13 @@ #include <linux/netdevice.h> #include <brcm_hw_ids.h> -#include "dhd.h" -#include "dhd_bus.h" -#include "dhd_dbg.h" +#include "core.h" +#include "bus.h" +#include "debug.h" #include "fwil.h" #include "feature.h" /* - * firmware error code received if iovar is unsupported. - */ -#define EBRCMF_FEAT_UNSUPPORTED 23 - -/* * expand feature list to array of feature strings. */ #define BRCMF_FEAT_DEF(_f) \ @@ -102,6 +97,28 @@ static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp, } } +/** + * brcmf_feat_iovar_int_set() - determine feature through iovar set. + * + * @ifp: interface to query. + * @id: feature id. + * @name: iovar name. + */ +static void brcmf_feat_iovar_int_set(struct brcmf_if *ifp, + enum brcmf_feat_id id, char *name, u32 val) +{ + int err; + + err = brcmf_fil_iovar_int_set(ifp, name, val); + if (err == 0) { + brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]); + ifp->drvr->feat_flags |= BIT(id); + } else { + brcmf_dbg(TRACE, "%s feature check failed: %d\n", + brcmf_feat_names[id], err); + } +} + void brcmf_feat_attach(struct brcmf_pub *drvr) { struct brcmf_if *ifp = drvr->iflist[0]; @@ -109,6 +126,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan"); if (drvr->bus_if->wowl_supported) brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl"); + brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0); /* set chip related quirks */ switch (drvr->bus_if->chip) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/brcm80211/brcmfmac/feature.h index b9a796d0a44d..f5832e077bb7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/feature.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.h @@ -22,6 +22,7 @@ * MCHAN: multi-channel for concurrent P2P. */ #define BRCMF_FEAT_LIST \ + BRCMF_FEAT_DEF(MBSS) \ BRCMF_FEAT_DEF(MCHAN) \ BRCMF_FEAT_DEF(WOWL) /* diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c index 8ea9f283d2b8..1ff787d1a36b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c @@ -20,7 +20,7 @@ #include <linux/firmware.h> #include <linux/module.h> -#include "dhd_dbg.h" +#include "debug.h" #include "firmware.h" char brcmf_firmware_path[BRCMF_FW_PATH_LEN]; @@ -262,8 +262,7 @@ static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx) fail: brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev)); - if (fwctx->code) - release_firmware(fwctx->code); + release_firmware(fwctx->code); device_release_driver(fwctx->dev); kfree(fwctx); } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c index 1faa929f5fff..44f3a84d1999 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c @@ -19,9 +19,9 @@ #include <linux/etherdevice.h> #include <brcmu_utils.h> -#include "dhd.h" -#include "dhd_dbg.h" -#include "dhd_bus.h" +#include "core.h" +#include "debug.h" +#include "bus.h" #include "proto.h" #include "flowring.h" #include "msgbuf.h" diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c index 44fc85f68f7a..ec62492ffa69 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c @@ -18,8 +18,8 @@ #include "brcmu_wifi.h" #include "brcmu_utils.h" -#include "dhd.h" -#include "dhd_dbg.h" +#include "core.h" +#include "debug.h" #include "tracepoint.h" #include "fwsignal.h" #include "fweh.h" @@ -221,10 +221,8 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); - if (ifp && ifevent->action == BRCMF_E_IF_DEL) { - brcmf_fws_del_interface(ifp); - brcmf_del_if(drvr, ifevent->bssidx); - } + if (ifp && ifevent->action == BRCMF_E_IF_DEL) + brcmf_remove_interface(drvr, ifevent->bssidx); } /** diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c index ded328f80cd1..03f2c406a17b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c @@ -22,9 +22,9 @@ #include <linux/netdevice.h> #include <brcmu_utils.h> #include <brcmu_wifi.h> -#include "dhd.h" -#include "dhd_bus.h" -#include "dhd_dbg.h" +#include "core.h" +#include "bus.h" +#include "debug.h" #include "tracepoint.h" #include "fwil.h" #include "proto.h" @@ -32,6 +32,76 @@ #define MAX_HEX_DUMP_LEN 64 +#ifdef DEBUG +static const char * const brcmf_fil_errstr[] = { + "BCME_OK", + "BCME_ERROR", + "BCME_BADARG", + "BCME_BADOPTION", + "BCME_NOTUP", + "BCME_NOTDOWN", + "BCME_NOTAP", + "BCME_NOTSTA", + "BCME_BADKEYIDX", + "BCME_RADIOOFF", + "BCME_NOTBANDLOCKED", + "BCME_NOCLK", + "BCME_BADRATESET", + "BCME_BADBAND", + "BCME_BUFTOOSHORT", + "BCME_BUFTOOLONG", + "BCME_BUSY", + "BCME_NOTASSOCIATED", + "BCME_BADSSIDLEN", + "BCME_OUTOFRANGECHAN", + "BCME_BADCHAN", + "BCME_BADADDR", + "BCME_NORESOURCE", + "BCME_UNSUPPORTED", + "BCME_BADLEN", + "BCME_NOTREADY", + "BCME_EPERM", + "BCME_NOMEM", + "BCME_ASSOCIATED", + "BCME_RANGE", + "BCME_NOTFOUND", + "BCME_WME_NOT_ENABLED", + "BCME_TSPEC_NOTFOUND", + "BCME_ACM_NOTSUPPORTED", + "BCME_NOT_WME_ASSOCIATION", + "BCME_SDIO_ERROR", + "BCME_DONGLE_DOWN", + "BCME_VERSION", + "BCME_TXFAIL", + "BCME_RXFAIL", + "BCME_NODEVICE", + "BCME_NMODE_DISABLED", + "BCME_NONRESIDENT", + "BCME_SCANREJECT", + "BCME_USAGE_ERROR", + "BCME_IOCTL_ERROR", + "BCME_SERIAL_PORT_ERR", + "BCME_DISABLED", + "BCME_DECERR", + "BCME_ENCERR", + "BCME_MICERR", + "BCME_REPLAY", + "BCME_IE_NOTFOUND", +}; + +static const char *brcmf_fil_get_errstr(u32 err) +{ + if (err >= ARRAY_SIZE(brcmf_fil_errstr)) + return "(unknown)"; + + return brcmf_fil_errstr[err]; +} +#else +static const char *brcmf_fil_get_errstr(u32 err) +{ + return ""; +} +#endif /* DEBUG */ static s32 brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set) @@ -52,11 +122,11 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set) err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd, data, len); if (err >= 0) - err = 0; - else - brcmf_dbg(FIL, "Failed err=%d\n", err); + return 0; - return err; + brcmf_dbg(FIL, "Failed: %s (%d)\n", + brcmf_fil_get_errstr((u32)(-err)), err); + return -EBADE; } s32 @@ -66,7 +136,7 @@ brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) mutex_lock(&ifp->drvr->proto_block); - brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len); + brcmf_dbg(FIL, "ifidx=%d, cmd=%d, len=%d\n", ifp->ifidx, cmd, len); brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); @@ -84,7 +154,7 @@ brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) mutex_lock(&ifp->drvr->proto_block); err = brcmf_fil_cmd_data(ifp, cmd, data, len, false); - brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len); + brcmf_dbg(FIL, "ifidx=%d, cmd=%d, len=%d\n", ifp->ifidx, cmd, len); brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); @@ -101,7 +171,7 @@ brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data) __le32 data_le = cpu_to_le32(data); mutex_lock(&ifp->drvr->proto_block); - brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, data); + brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, data); err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true); mutex_unlock(&ifp->drvr->proto_block); @@ -118,7 +188,7 @@ brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data) err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false); mutex_unlock(&ifp->drvr->proto_block); *data = le32_to_cpu(data_le); - brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, *data); + brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, *data); return err; } @@ -154,7 +224,7 @@ brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, const void *data, mutex_lock(&drvr->proto_block); - brcmf_dbg(FIL, "name=%s, len=%d\n", name, len); + brcmf_dbg(FIL, "ifidx=%d, name=%s, len=%d\n", ifp->ifidx, name, len); brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); @@ -194,7 +264,7 @@ brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data, brcmf_err("Creating iovar failed\n"); } - brcmf_dbg(FIL, "name=%s, len=%d\n", name, len); + brcmf_dbg(FIL, "ifidx=%d, name=%s, len=%d\n", ifp->ifidx, name, len); brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); @@ -277,7 +347,8 @@ brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name, mutex_lock(&drvr->proto_block); - brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len); + brcmf_dbg(FIL, "ifidx=%d, bssidx=%d, name=%s, len=%d\n", ifp->ifidx, + ifp->bssidx, name, len); brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); @@ -316,7 +387,8 @@ brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name, err = -EPERM; brcmf_err("Creating bsscfg failed\n"); } - brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len); + brcmf_dbg(FIL, "ifidx=%d, bssidx=%d, name=%s, len=%d\n", ifp->ifidx, + ifp->bssidx, name, len); brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h index 5ff5cd0bb032..50891c02c4c1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h @@ -55,59 +55,63 @@ /* WOWL bits */ /* Wakeup on Magic packet: */ -#define WL_WOWL_MAGIC (1 << 0) +#define BRCMF_WOWL_MAGIC (1 << 0) /* Wakeup on Netpattern */ -#define WL_WOWL_NET (1 << 1) +#define BRCMF_WOWL_NET (1 << 1) /* Wakeup on loss-of-link due to Disassoc/Deauth: */ -#define WL_WOWL_DIS (1 << 2) +#define BRCMF_WOWL_DIS (1 << 2) /* Wakeup on retrograde TSF: */ -#define WL_WOWL_RETR (1 << 3) +#define BRCMF_WOWL_RETR (1 << 3) /* Wakeup on loss of beacon: */ -#define WL_WOWL_BCN (1 << 4) +#define BRCMF_WOWL_BCN (1 << 4) /* Wakeup after test: */ -#define WL_WOWL_TST (1 << 5) +#define BRCMF_WOWL_TST (1 << 5) /* Wakeup after PTK refresh: */ -#define WL_WOWL_M1 (1 << 6) +#define BRCMF_WOWL_M1 (1 << 6) /* Wakeup after receipt of EAP-Identity Req: */ -#define WL_WOWL_EAPID (1 << 7) +#define BRCMF_WOWL_EAPID (1 << 7) /* Wakeind via PME(0) or GPIO(1): */ -#define WL_WOWL_PME_GPIO (1 << 8) +#define BRCMF_WOWL_PME_GPIO (1 << 8) /* need tkip phase 1 key to be updated by the driver: */ -#define WL_WOWL_NEEDTKIP1 (1 << 9) +#define BRCMF_WOWL_NEEDTKIP1 (1 << 9) /* enable wakeup if GTK fails: */ -#define WL_WOWL_GTK_FAILURE (1 << 10) +#define BRCMF_WOWL_GTK_FAILURE (1 << 10) /* support extended magic packets: */ -#define WL_WOWL_EXTMAGPAT (1 << 11) +#define BRCMF_WOWL_EXTMAGPAT (1 << 11) /* support ARP/NS/keepalive offloading: */ -#define WL_WOWL_ARPOFFLOAD (1 << 12) +#define BRCMF_WOWL_ARPOFFLOAD (1 << 12) /* read protocol version for EAPOL frames: */ -#define WL_WOWL_WPA2 (1 << 13) +#define BRCMF_WOWL_WPA2 (1 << 13) /* If the bit is set, use key rotaton: */ -#define WL_WOWL_KEYROT (1 << 14) +#define BRCMF_WOWL_KEYROT (1 << 14) /* If the bit is set, frm received was bcast frame: */ -#define WL_WOWL_BCAST (1 << 15) +#define BRCMF_WOWL_BCAST (1 << 15) /* If the bit is set, scan offload is enabled: */ -#define WL_WOWL_SCANOL (1 << 16) +#define BRCMF_WOWL_SCANOL (1 << 16) /* Wakeup on tcpkeep alive timeout: */ -#define WL_WOWL_TCPKEEP_TIME (1 << 17) +#define BRCMF_WOWL_TCPKEEP_TIME (1 << 17) /* Wakeup on mDNS Conflict Resolution: */ -#define WL_WOWL_MDNS_CONFLICT (1 << 18) +#define BRCMF_WOWL_MDNS_CONFLICT (1 << 18) /* Wakeup on mDNS Service Connect: */ -#define WL_WOWL_MDNS_SERVICE (1 << 19) +#define BRCMF_WOWL_MDNS_SERVICE (1 << 19) /* tcp keepalive got data: */ -#define WL_WOWL_TCPKEEP_DATA (1 << 20) +#define BRCMF_WOWL_TCPKEEP_DATA (1 << 20) /* Firmware died in wowl mode: */ -#define WL_WOWL_FW_HALT (1 << 21) +#define BRCMF_WOWL_FW_HALT (1 << 21) /* Enable detection of radio button changes: */ -#define WL_WOWL_ENAB_HWRADIO (1 << 22) +#define BRCMF_WOWL_ENAB_HWRADIO (1 << 22) /* Offloads detected MIC failure(s): */ -#define WL_WOWL_MIC_FAIL (1 << 23) +#define BRCMF_WOWL_MIC_FAIL (1 << 23) /* Wakeup in Unassociated state (Net/Magic Pattern): */ -#define WL_WOWL_UNASSOC (1 << 24) +#define BRCMF_WOWL_UNASSOC (1 << 24) /* Wakeup if received matched secured pattern: */ -#define WL_WOWL_SECURE (1 << 25) +#define BRCMF_WOWL_SECURE (1 << 25) /* Link Down indication in WoWL mode: */ -#define WL_WOWL_LINKDOWN (1 << 31) +#define BRCMF_WOWL_LINKDOWN (1 << 31) + +#define BRCMF_WOWL_MAXPATTERNS 8 +#define BRCMF_WOWL_MAXPATTERNSIZE 128 + /* join preference types for join_pref iovar */ enum brcmf_join_pref_types { @@ -124,6 +128,12 @@ enum brcmf_fil_p2p_if_types { BRCMF_FIL_P2P_IF_DEV, }; +enum brcmf_wowl_pattern_type { + BRCMF_WOWL_PATTERN_TYPE_BITMAP = 0, + BRCMF_WOWL_PATTERN_TYPE_ARP, + BRCMF_WOWL_PATTERN_TYPE_NA +}; + struct brcmf_fil_p2p_if_le { u8 addr[ETH_ALEN]; __le16 type; @@ -484,4 +494,35 @@ struct brcmf_rx_mgmt_data { __be32 rate; }; +/** + * struct brcmf_fil_wowl_pattern_le - wowl pattern configuration struct. + * + * @cmd: "add", "del" or "clr". + * @masksize: Size of the mask in #of bytes + * @offset: Pattern byte offset in packet + * @patternoffset: Offset of start of pattern. Starting from field masksize. + * @patternsize: Size of the pattern itself in #of bytes + * @id: id + * @reasonsize: Size of the wakeup reason code + * @type: Type of pattern (enum brcmf_wowl_pattern_type) + */ +struct brcmf_fil_wowl_pattern_le { + u8 cmd[4]; + __le32 masksize; + __le32 offset; + __le32 patternoffset; + __le32 patternsize; + __le32 id; + __le32 reasonsize; + __le32 type; + /* u8 mask[] - Mask follows the structure above */ + /* u8 pattern[] - Pattern follows the mask is at 'patternoffset' */ +}; + +struct brcmf_mbss_ssid_le { + __le32 bsscfgidx; + __le32 SSID_len; + unsigned char SSID[32]; +}; + #endif /* FWIL_TYPES_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index 183f08d7fc8c..f0dda0ecd23b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c @@ -26,15 +26,15 @@ #include <brcmu_utils.h> #include <brcmu_wifi.h> -#include "dhd.h" -#include "dhd_dbg.h" -#include "dhd_bus.h" +#include "core.h" +#include "debug.h" +#include "bus.h" #include "fwil.h" #include "fwil_types.h" #include "fweh.h" #include "fwsignal.h" #include "p2p.h" -#include "wl_cfg80211.h" +#include "cfg80211.h" #include "proto.h" /** diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c index 11cc051f97cd..456944a6a2db 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c @@ -24,13 +24,13 @@ #include <brcmu_utils.h> #include <brcmu_wifi.h> -#include "dhd.h" -#include "dhd_dbg.h" +#include "core.h" +#include "debug.h" #include "proto.h" #include "msgbuf.h" #include "commonring.h" #include "flowring.h" -#include "dhd_bus.h" +#include "bus.h" #include "tracepoint.h" @@ -518,8 +518,7 @@ static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx, memcpy(buf, skb->data, (len < msgbuf->ioctl_resp_ret_len) ? len : msgbuf->ioctl_resp_ret_len); } - if (skb) - brcmu_pkt_buf_free_skb(skb); + brcmu_pkt_buf_free_skb(skb); return msgbuf->ioctl_resp_status; } @@ -1081,8 +1080,17 @@ brcmf_msgbuf_rx_skb(struct brcmf_msgbuf *msgbuf, struct sk_buff *skb, { struct brcmf_if *ifp; + /* The ifidx is the idx to map to matching netdev/ifp. When receiving + * events this is easy because it contains the bssidx which maps + * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. + * bssidx 1 is used for p2p0 and no data can be received or + * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 + */ + if (ifidx) + (ifidx)++; ifp = msgbuf->drvr->iflist[ifidx]; if (!ifp || !ifp->ndev) { + brcmf_err("Received pkt for invalid ifidx %d\n", ifidx); brcmu_pkt_buf_free_skb(skb); return; } @@ -1355,6 +1363,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) } INIT_WORK(&msgbuf->txflow_work, brcmf_msgbuf_txflow_worker); count = BITS_TO_LONGS(if_msgbuf->nrof_flowrings); + count = count * sizeof(unsigned long); msgbuf->flow_map = kzalloc(count, GFP_KERNEL); if (!msgbuf->flow_map) goto fail; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/of.c b/drivers/net/wireless/brcm80211/brcmfmac/of.c index 927bffd5be64..c824570ddea3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/of.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/of.c @@ -21,8 +21,8 @@ #include <linux/mmc/sdio_func.h> #include <defs.h> -#include "dhd_dbg.h" -#include "sdio_host.h" +#include "debug.h" +#include "sdio.h" void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index d54c58a32faa..effb48ebd864 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c @@ -21,12 +21,12 @@ #include <brcmu_wifi.h> #include <brcmu_utils.h> #include <defs.h> -#include <dhd.h> -#include <dhd_dbg.h> +#include "core.h" +#include "debug.h" #include "fwil.h" #include "fwil_types.h" #include "p2p.h" -#include "wl_cfg80211.h" +#include "cfg80211.h" /* parameters used for p2p escan */ #define P2PAPI_SCAN_NPROBES 1 diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c index 16fef3382019..905991fdb7b1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c @@ -30,8 +30,8 @@ #include <brcmu_wifi.h> #include <brcm_hw_ids.h> -#include "dhd_dbg.h" -#include "dhd_bus.h" +#include "debug.h" +#include "bus.h" #include "commonring.h" #include "msgbuf.h" #include "pcie.h" @@ -798,12 +798,14 @@ static int brcmf_pcie_request_irq(struct brcmf_pciedev_info *devinfo) brcmf_dbg(PCIE, "Enter\n"); /* is it a v1 or v2 implementation */ devinfo->irq_requested = false; + pci_enable_msi(pdev); if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) { if (request_threaded_irq(pdev->irq, brcmf_pcie_quick_check_isr_v1, brcmf_pcie_isr_thread_v1, IRQF_SHARED, "brcmf_pcie_intr", devinfo)) { + pci_disable_msi(pdev); brcmf_err("Failed to request IRQ %d\n", pdev->irq); return -EIO; } @@ -813,6 +815,7 @@ static int brcmf_pcie_request_irq(struct brcmf_pciedev_info *devinfo) brcmf_pcie_isr_thread_v2, IRQF_SHARED, "brcmf_pcie_intr", devinfo)) { + pci_disable_msi(pdev); brcmf_err("Failed to request IRQ %d\n", pdev->irq); return -EIO; } @@ -839,6 +842,7 @@ static void brcmf_pcie_release_irq(struct brcmf_pciedev_info *devinfo) return; devinfo->irq_requested = false; free_irq(pdev->irq, devinfo); + pci_disable_msi(pdev); msleep(50); count = 0; @@ -1857,6 +1861,8 @@ static struct pci_device_id brcmf_pcie_devid_table[] = { BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_2G_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_5G_DEVICE_ID), { /* end: all zeroes */ } }; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/proto.c b/drivers/net/wireless/brcm80211/brcmfmac/proto.c index 62b940723339..26b68c367f57 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/proto.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/proto.c @@ -20,9 +20,9 @@ #include <linux/netdevice.h> #include <brcmu_wifi.h> -#include "dhd.h" -#include "dhd_bus.h" -#include "dhd_dbg.h" +#include "core.h" +#include "bus.h" +#include "debug.h" #include "proto.h" #include "bcdc.h" #include "msgbuf.h" diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index d20d4e6f391a..0b0d51a61060 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -40,7 +40,7 @@ #include <brcmu_utils.h> #include <brcm_hw_ids.h> #include <soc.h> -#include "sdio_host.h" +#include "sdio.h" #include "chip.h" #include "firmware.h" @@ -96,8 +96,8 @@ struct rte_console { #endif /* DEBUG */ #include <chipcommon.h> -#include "dhd_bus.h" -#include "dhd_dbg.h" +#include "bus.h" +#include "debug.h" #include "tracepoint.h" #define TXQLEN 2048 /* bulk tx queue length */ @@ -2762,6 +2762,48 @@ static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev) return &bus->txq; } +static bool brcmf_sdio_prec_enq(struct pktq *q, struct sk_buff *pkt, int prec) +{ + struct sk_buff *p; + int eprec = -1; /* precedence to evict from */ + + /* Fast case, precedence queue is not full and we are also not + * exceeding total queue length + */ + if (!pktq_pfull(q, prec) && !pktq_full(q)) { + brcmu_pktq_penq(q, prec, pkt); + return true; + } + + /* Determine precedence from which to evict packet, if any */ + if (pktq_pfull(q, prec)) { + eprec = prec; + } else if (pktq_full(q)) { + p = brcmu_pktq_peek_tail(q, &eprec); + if (eprec > prec) + return false; + } + + /* Evict if needed */ + if (eprec >= 0) { + /* Detect queueing to unconfigured precedence */ + if (eprec == prec) + return false; /* refuse newer (incoming) packet */ + /* Evict packet according to discard policy */ + p = brcmu_pktq_pdeq_tail(q, eprec); + if (p == NULL) + brcmf_err("brcmu_pktq_pdeq_tail() failed\n"); + brcmu_pkt_buf_free_skb(p); + } + + /* Enqueue */ + p = brcmu_pktq_penq(q, prec, pkt); + if (p == NULL) + brcmf_err("brcmu_pktq_penq() failed\n"); + + return p != NULL; +} + static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) { int ret = -EBADE; @@ -2787,7 +2829,7 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) spin_lock_bh(&bus->txq_lock); /* reset bus_flags in packet cb */ *(u16 *)(pkt->cb) = 0; - if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) { + if (!brcmf_sdio_prec_enq(&bus->txq, pkt, prec)) { skb_pull(pkt, bus->tx_hdrlen); brcmf_err("out of bus->txq !!!\n"); ret = -ENOSR; @@ -2797,7 +2839,7 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) if (pktq_len(&bus->txq) >= TXHI) { bus->txoff = true; - brcmf_txflowblock(bus->sdiodev->dev, true); + brcmf_txflowblock(dev, true); } spin_unlock_bh(&bus->txq_lock); @@ -3948,6 +3990,7 @@ static struct brcmf_bus_ops brcmf_sdio_bus_ops = { .txctl = brcmf_sdio_bus_txctl, .rxctl = brcmf_sdio_bus_rxctl, .gettxq = brcmf_sdio_bus_gettxq, + .wowl_config = brcmf_sdio_wowl_config }; static void brcmf_sdio_firmware_callback(struct device *dev, @@ -4074,7 +4117,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) /* platform specific configuration: * alignments must be at least 4 bytes for ADMA - */ + */ bus->head_align = ALIGNMENT; bus->sgentry_align = ALIGNMENT; if (sdiodev->pdata) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio.h index f2d06cae366a..8eb42620129c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.h @@ -14,8 +14,8 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _BRCM_SDH_H_ -#define _BRCM_SDH_H_ +#ifndef BRCMFMAC_SDIO_H +#define BRCMFMAC_SDIO_H #include <linux/skbuff.h> #include <linux/firmware.h> @@ -186,6 +186,7 @@ struct brcmf_sdio_dev { struct sg_table sgtable; char fw_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN]; char nvram_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN]; + bool wowl_enabled; }; /* sdio core registers */ @@ -334,5 +335,6 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus); void brcmf_sdio_isr(struct brcmf_sdio *bus); void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick); +void brcmf_sdio_wowl_config(struct device *dev, bool enabled); -#endif /* _BRCM_SDH_H_ */ +#endif /* BRCMFMAC_SDIO_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.c b/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.c index b505db48c60d..a10f35c5eb3d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.c @@ -19,4 +19,19 @@ #ifndef __CHECKER__ #define CREATE_TRACE_POINTS #include "tracepoint.h" + +void __brcmf_err(const char *func, const char *fmt, ...) +{ + struct va_format vaf = { + .fmt = fmt, + }; + va_list args; + + va_start(args, fmt); + vaf.va = &args; + pr_err("%s: %pV", func, &vaf); + trace_brcmf_err(func, &vaf); + va_end(args); +} + #endif diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index 875d1142c8b0..4572defc280f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -23,13 +23,12 @@ #include <brcmu_utils.h> #include <brcm_hw_ids.h> #include <brcmu_wifi.h> -#include <dhd_bus.h> -#include <dhd_dbg.h> - +#include "bus.h" +#include "debug.h" #include "firmware.h" -#include "usb_rdl.h" #include "usb.h" + #define IOCTL_RESP_TIMEOUT 2000 #define BRCMF_USB_RESET_GETVER_SPINWAIT 100 /* in unit of ms */ @@ -49,6 +48,71 @@ #define BRCMF_USB_43242_FW_NAME "brcm/brcmfmac43242a.bin" #define BRCMF_USB_43569_FW_NAME "brcm/brcmfmac43569.bin" +#define TRX_MAGIC 0x30524448 /* "HDR0" */ +#define TRX_MAX_OFFSET 3 /* Max number of file offsets */ +#define TRX_UNCOMP_IMAGE 0x20 /* Trx holds uncompressed img */ +#define TRX_RDL_CHUNK 1500 /* size of each dl transfer */ +#define TRX_OFFSETS_DLFWLEN_IDX 0 + +/* Control messages: bRequest values */ +#define DL_GETSTATE 0 /* returns the rdl_state_t struct */ +#define DL_CHECK_CRC 1 /* currently unused */ +#define DL_GO 2 /* execute downloaded image */ +#define DL_START 3 /* initialize dl state */ +#define DL_REBOOT 4 /* reboot the device in 2 seconds */ +#define DL_GETVER 5 /* returns the bootrom_id_t struct */ +#define DL_GO_PROTECTED 6 /* execute the downloaded code and set reset + * event to occur in 2 seconds. It is the + * responsibility of the downloaded code to + * clear this event + */ +#define DL_EXEC 7 /* jump to a supplied address */ +#define DL_RESETCFG 8 /* To support single enum on dongle + * - Not used by bootloader + */ +#define DL_DEFER_RESP_OK 9 /* Potentially defer the response to setup + * if resp unavailable + */ + +/* states */ +#define DL_WAITING 0 /* waiting to rx first pkt */ +#define DL_READY 1 /* hdr was good, waiting for more of the + * compressed image + */ +#define DL_BAD_HDR 2 /* hdr was corrupted */ +#define DL_BAD_CRC 3 /* compressed image was corrupted */ +#define DL_RUNNABLE 4 /* download was successful,waiting for go cmd */ +#define DL_START_FAIL 5 /* failed to initialize correctly */ +#define DL_NVRAM_TOOBIG 6 /* host specified nvram data exceeds DL_NVRAM + * value + */ +#define DL_IMAGE_TOOBIG 7 /* firmware image too big */ + + +struct trx_header_le { + __le32 magic; /* "HDR0" */ + __le32 len; /* Length of file including header */ + __le32 crc32; /* CRC from flag_version to end of file */ + __le32 flag_version; /* 0:15 flags, 16:31 version */ + __le32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of + * header + */ +}; + +struct rdl_state_le { + __le32 state; + __le32 bytes; +}; + +struct bootrom_id_le { + __le32 chip; /* Chip id */ + __le32 chiprev; /* Chip rev */ + __le32 ramsize; /* Size of RAM */ + __le32 remapbase; /* Current remap base address */ + __le32 boardtype; /* Type of board */ + __le32 boardrev; /* Board revision */ +}; + struct brcmf_usb_image { struct list_head list; s8 *fwname; @@ -93,6 +157,8 @@ struct brcmf_usbdev_info { u8 ifnum; struct urb *bulk_urb; /* used for FW download */ + + bool wowl_enabled; }; static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo, @@ -600,6 +666,16 @@ static int brcmf_usb_up(struct device *dev) return 0; } +static void brcmf_cancel_all_urbs(struct brcmf_usbdev_info *devinfo) +{ + if (devinfo->ctl_urb) + usb_kill_urb(devinfo->ctl_urb); + if (devinfo->bulk_urb) + usb_kill_urb(devinfo->bulk_urb); + brcmf_usb_free_q(&devinfo->tx_postq, true); + brcmf_usb_free_q(&devinfo->rx_postq, true); +} + static void brcmf_usb_down(struct device *dev) { struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); @@ -613,14 +689,7 @@ static void brcmf_usb_down(struct device *dev) brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_DOWN); - if (devinfo->ctl_urb) - usb_kill_urb(devinfo->ctl_urb); - - if (devinfo->bulk_urb) - usb_kill_urb(devinfo->bulk_urb); - brcmf_usb_free_q(&devinfo->tx_postq, true); - - brcmf_usb_free_q(&devinfo->rx_postq, true); + brcmf_cancel_all_urbs(devinfo); } static void @@ -785,7 +854,7 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen) brcmf_dbg(USB, "Enter, fw %p, len %d\n", fw, fwlen); - bulkchunk = kmalloc(RDL_CHUNK, GFP_ATOMIC); + bulkchunk = kmalloc(TRX_RDL_CHUNK, GFP_ATOMIC); if (bulkchunk == NULL) { err = -ENOMEM; goto fail; @@ -812,10 +881,10 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen) /* Wait until the usb device reports it received all * the bytes we sent */ if ((rdlbytes == sent) && (rdlbytes != dllen)) { - if ((dllen-sent) < RDL_CHUNK) + if ((dllen-sent) < TRX_RDL_CHUNK) sendlen = dllen-sent; else - sendlen = RDL_CHUNK; + sendlen = TRX_RDL_CHUNK; /* simply avoid having to send a ZLP by ensuring we * never have an even @@ -980,21 +1049,6 @@ static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo) kfree(devinfo->rx_reqs); } -#define TRX_MAGIC 0x30524448 /* "HDR0" */ -#define TRX_VERSION 1 /* Version 1 */ -#define TRX_MAX_LEN 0x3B0000 /* Max length */ -#define TRX_NO_HEADER 1 /* Do not write TRX header */ -#define TRX_MAX_OFFSET 3 /* Max number of individual files */ -#define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed image */ - -struct trx_header_le { - __le32 magic; /* "HDR0" */ - __le32 len; /* Length of file including header */ - __le32 crc32; /* CRC from flag_version to end of file */ - __le32 flag_version; /* 0:15 flags, 16:31 version */ - __le32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of - * header */ -}; static int check_file(const u8 *headers) { @@ -1096,11 +1150,24 @@ 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 struct brcmf_bus_ops brcmf_usb_bus_ops = { .txdata = brcmf_usb_tx, .stop = brcmf_usb_down, .txctl = brcmf_usb_tx_ctlpkt, .rxctl = brcmf_usb_rx_ctlpkt, + .wowl_config = brcmf_usb_wowl_config, }; static int brcmf_usb_bus_setup(struct brcmf_usbdev_info *devinfo) @@ -1188,6 +1255,9 @@ 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; +#ifdef CONFIG_PM + bus->wowl_supported = true; +#endif if (!brcmf_usb_dlneeded(devinfo)) { ret = brcmf_usb_bus_setup(devinfo); @@ -1341,7 +1411,10 @@ static int brcmf_usb_suspend(struct usb_interface *intf, pm_message_t state) brcmf_dbg(USB, "Enter\n"); devinfo->bus_pub.state = BRCMFMAC_USB_STATE_SLEEP; - brcmf_detach(&usb->dev); + if (devinfo->wowl_enabled) + brcmf_cancel_all_urbs(devinfo); + else + brcmf_detach(&usb->dev); return 0; } @@ -1354,7 +1427,12 @@ 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"); - return brcmf_usb_bus_setup(devinfo); + if (!devinfo->wowl_enabled) + return brcmf_usb_bus_setup(devinfo); + + devinfo->bus_pub.state = BRCMFMAC_USB_STATE_UP; + brcmf_usb_rx_fill_all(devinfo); + return 0; } static int brcmf_usb_reset_resume(struct usb_interface *intf) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h b/drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h deleted file mode 100644 index 0a35c51c3da2..000000000000 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2011 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _USB_RDL_H -#define _USB_RDL_H - -/* Control messages: bRequest values */ -#define DL_GETSTATE 0 /* returns the rdl_state_t struct */ -#define DL_CHECK_CRC 1 /* currently unused */ -#define DL_GO 2 /* execute downloaded image */ -#define DL_START 3 /* initialize dl state */ -#define DL_REBOOT 4 /* reboot the device in 2 seconds */ -#define DL_GETVER 5 /* returns the bootrom_id_t struct */ -#define DL_GO_PROTECTED 6 /* execute the downloaded code and set reset - * event to occur in 2 seconds. It is the - * responsibility of the downloaded code to - * clear this event - */ -#define DL_EXEC 7 /* jump to a supplied address */ -#define DL_RESETCFG 8 /* To support single enum on dongle - * - Not used by bootloader - */ -#define DL_DEFER_RESP_OK 9 /* Potentially defer the response to setup - * if resp unavailable - */ - -/* states */ -#define DL_WAITING 0 /* waiting to rx first pkt */ -#define DL_READY 1 /* hdr was good, waiting for more of the - * compressed image */ -#define DL_BAD_HDR 2 /* hdr was corrupted */ -#define DL_BAD_CRC 3 /* compressed image was corrupted */ -#define DL_RUNNABLE 4 /* download was successful,waiting for go cmd */ -#define DL_START_FAIL 5 /* failed to initialize correctly */ -#define DL_NVRAM_TOOBIG 6 /* host specified nvram data exceeds DL_NVRAM - * value */ -#define DL_IMAGE_TOOBIG 7 /* download image too big (exceeds DATA_START - * for rdl) */ - -struct rdl_state_le { - __le32 state; - __le32 bytes; -}; - -struct bootrom_id_le { - __le32 chip; /* Chip id */ - __le32 chiprev; /* Chip rev */ - __le32 ramsize; /* Size of RAM */ - __le32 remapbase; /* Current remap base address */ - __le32 boardtype; /* Type of board */ - __le32 boardrev; /* Board revision */ -}; - -#define RDL_CHUNK 1500 /* size of each dl transfer */ - -#define TRX_OFFSETS_DLFWLEN_IDX 0 -#define TRX_OFFSETS_JUMPTO_IDX 1 -#define TRX_OFFSETS_NVM_LEN_IDX 2 - -#define TRX_OFFSETS_DLBASE_IDX 0 - -#endif /* _USB_RDL_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/vendor.c b/drivers/net/wireless/brcm80211/brcmfmac/vendor.c index 5960d827508c..50cdf7090198 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/vendor.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/vendor.c @@ -20,10 +20,10 @@ #include <brcmu_wifi.h> #include "fwil_types.h" -#include "dhd.h" +#include "core.h" #include "p2p.h" -#include "dhd_dbg.h" -#include "wl_cfg80211.h" +#include "debug.h" +#include "cfg80211.h" #include "vendor.h" #include "fwil.h" @@ -31,8 +31,8 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - struct net_device *ndev = cfg_to_ndev(cfg); + struct brcmf_cfg80211_vif *vif; + struct brcmf_if *ifp; const struct brcmf_vndr_dcmd_hdr *cmdhdr = data; struct sk_buff *reply; int ret, payload, ret_len; @@ -42,6 +42,9 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy, brcmf_dbg(TRACE, "cmd %x set %d len %d\n", cmdhdr->cmd, cmdhdr->set, cmdhdr->len); + vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev); + ifp = vif->ifp; + len -= sizeof(struct brcmf_vndr_dcmd_hdr); ret_len = cmdhdr->len; if (ret_len > 0 || len > 0) { @@ -63,11 +66,11 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy, } if (cmdhdr->set) - ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), cmdhdr->cmd, - dcmd_buf, ret_len); + ret = brcmf_fil_cmd_data_set(ifp, cmdhdr->cmd, dcmd_buf, + ret_len); else - ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), cmdhdr->cmd, - dcmd_buf, ret_len); + ret = brcmf_fil_cmd_data_get(ifp, cmdhdr->cmd, dcmd_buf, + ret_len); if (ret != 0) goto exit; |