summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS1
-rw-r--r--drivers/net/wireless/ath/ath5k/ahb.c20
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h4
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c10
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c82
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c10
-rw-r--r--drivers/net/wireless/brcm80211/Kconfig17
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/Makefile6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c14
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h17
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c59
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c32
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.c1623
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.h84
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h75
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c13
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/ampdu.c6
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c4
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/main.c1
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c28
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/srom.c14
-rw-r--r--drivers/net/wireless/iwlegacy/3945-debug.c6
-rw-r--r--drivers/net/wireless/iwlegacy/3945-mac.c108
-rw-r--r--drivers/net/wireless/iwlegacy/3945.c133
-rw-r--r--drivers/net/wireless/iwlegacy/3945.h8
-rw-r--r--drivers/net/wireless/iwlegacy/4965-calib.c4
-rw-r--r--drivers/net/wireless/iwlegacy/4965-debug.c6
-rw-r--r--drivers/net/wireless/iwlegacy/4965-mac.c589
-rw-r--r--drivers/net/wireless/iwlegacy/4965.c402
-rw-r--r--drivers/net/wireless/iwlegacy/4965.h20
-rw-r--r--drivers/net/wireless/iwlegacy/common.c548
-rw-r--r--drivers/net/wireless/iwlegacy/common.h224
-rw-r--r--drivers/net/wireless/iwlegacy/debug.c260
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c4
-rw-r--r--drivers/net/wireless/rtlwifi/base.c6
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c156
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/phy.c187
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/fw.h3
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/phy.c40
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/sw.c3
-rw-r--r--drivers/net/wireless/wl1251/Makefile2
-rw-r--r--drivers/net/wireless/wl1251/boot.c2
-rw-r--r--drivers/net/wireless/wl1251/io.h9
-rw-r--r--drivers/net/wireless/wl1251/wl1251.h2
-rw-r--r--drivers/net/wireless/wl12xx/Makefile2
-rw-r--r--drivers/net/wireless/wl12xx/acx.c17
-rw-r--r--drivers/net/wireless/wl12xx/acx.h149
-rw-r--r--drivers/net/wireless/wl12xx/boot.c105
-rw-r--r--drivers/net/wireless/wl12xx/boot.h10
-rw-r--r--drivers/net/wireless/wl12xx/cmd.c143
-rw-r--r--drivers/net/wireless/wl12xx/cmd.h148
-rw-r--r--drivers/net/wireless/wl12xx/conf.h51
-rw-r--r--drivers/net/wireless/wl12xx/debug.h1
-rw-r--r--drivers/net/wireless/wl12xx/debugfs.c241
-rw-r--r--drivers/net/wireless/wl12xx/event.c154
-rw-r--r--drivers/net/wireless/wl12xx/event.h20
-rw-r--r--drivers/net/wireless/wl12xx/init.c55
-rw-r--r--drivers/net/wireless/wl12xx/io.c59
-rw-r--r--drivers/net/wireless/wl12xx/io.h2
-rw-r--r--drivers/net/wireless/wl12xx/main.c674
-rw-r--r--drivers/net/wireless/wl12xx/ps.c34
-rw-r--r--drivers/net/wireless/wl12xx/ps.h2
-rw-r--r--drivers/net/wireless/wl12xx/reg.h27
-rw-r--r--drivers/net/wireless/wl12xx/rx.c2
-rw-r--r--drivers/net/wireless/wl12xx/scan.c56
-rw-r--r--drivers/net/wireless/wl12xx/scan.h2
-rw-r--r--drivers/net/wireless/wl12xx/sdio.c29
-rw-r--r--drivers/net/wireless/wl12xx/spi.c8
-rw-r--r--drivers/net/wireless/wl12xx/testmode.c50
-rw-r--r--drivers/net/wireless/wl12xx/tx.c75
-rw-r--r--drivers/net/wireless/wl12xx/tx.h5
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h46
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx_80211.h2
-rw-r--r--include/linux/nl80211.h34
-rw-r--r--include/net/cfg80211.h70
-rw-r--r--net/mac80211/cfg.c146
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/tx.c13
-rw-r--r--net/wireless/nl80211.c255
80 files changed, 4695 insertions, 2838 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 48418c8475f..0b92435d9f5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1575,7 +1575,6 @@ F: drivers/net/ethernet/broadcom/tg3.*
BROADCOM BRCM80211 IEEE802.11n WIRELESS DRIVER
M: Brett Rudley <brudley@broadcom.com>
-M: Henry Ptasinski <henryp@broadcom.com>
M: Roland Vossen <rvossen@broadcom.com>
M: Arend van Spriel <arend@broadcom.com>
M: Franky (Zhenhui) Lin <frankyl@broadcom.com>
diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c
index ee7ea572b06..8faa129da5a 100644
--- a/drivers/net/wireless/ath/ath5k/ahb.c
+++ b/drivers/net/wireless/ath/ath5k/ahb.c
@@ -140,23 +140,23 @@ static int ath_ahb_probe(struct platform_device *pdev)
if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
/* Enable WMAC AHB arbitration */
- reg = __raw_readl((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+ reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
reg |= AR5K_AR2315_AHB_ARB_CTL_WLAN;
- __raw_writel(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+ iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
/* Enable global WMAC swapping */
- reg = __raw_readl((void __iomem *) AR5K_AR2315_BYTESWAP);
+ reg = ioread32((void __iomem *) AR5K_AR2315_BYTESWAP);
reg |= AR5K_AR2315_BYTESWAP_WMAC;
- __raw_writel(reg, (void __iomem *) AR5K_AR2315_BYTESWAP);
+ iowrite32(reg, (void __iomem *) AR5K_AR2315_BYTESWAP);
} else {
/* Enable WMAC DMA access (assuming 5312 or 231x*/
/* TODO: check other platforms */
- reg = __raw_readl((void __iomem *) AR5K_AR5312_ENABLE);
+ reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE);
if (to_platform_device(ah->dev)->id == 0)
reg |= AR5K_AR5312_ENABLE_WLAN0;
else
reg |= AR5K_AR5312_ENABLE_WLAN1;
- __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE);
+ iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE);
/*
* On a dual-band AR5312, the multiband radio is only
@@ -203,17 +203,17 @@ static int ath_ahb_remove(struct platform_device *pdev)
if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
/* Disable WMAC AHB arbitration */
- reg = __raw_readl((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+ reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
reg &= ~AR5K_AR2315_AHB_ARB_CTL_WLAN;
- __raw_writel(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+ iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
} else {
/*Stop DMA access */
- reg = __raw_readl((void __iomem *) AR5K_AR5312_ENABLE);
+ reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE);
if (to_platform_device(ah->dev)->id == 0)
reg &= ~AR5K_AR5312_ENABLE_WLAN0;
else
reg &= ~AR5K_AR5312_ENABLE_WLAN1;
- __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE);
+ iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE);
}
ath5k_deinit_ah(ah);
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index c2b2518c2ec..6640326f700 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -1656,12 +1656,12 @@ static inline void __iomem *ath5k_ahb_reg(struct ath5k_hw *ah, u16 reg)
static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
{
- return __raw_readl(ath5k_ahb_reg(ah, reg));
+ return ioread32(ath5k_ahb_reg(ah, reg));
}
static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
{
- __raw_writel(val, ath5k_ahb_reg(ah, reg));
+ iowrite32(val, ath5k_ahb_reg(ah, reg));
}
#else
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 250db40b751..200f165c0c6 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -473,14 +473,14 @@ ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags)
}
/* Put BB/MAC into reset */
- regval = __raw_readl(reg);
- __raw_writel(regval | val, reg);
- regval = __raw_readl(reg);
+ regval = ioread32(reg);
+ iowrite32(regval | val, reg);
+ regval = ioread32(reg);
usleep_range(100, 150);
/* Bring BB/MAC out of reset */
- __raw_writel(regval & ~val, reg);
- regval = __raw_readl(reg);
+ iowrite32(regval & ~val, reg);
+ regval = ioread32(reg);
/*
* Reset configuration register (for hw byte-swap). Note that this
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index d1922d8eb3b..5370333883e 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -2269,25 +2269,11 @@ static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif,
return ret;
}
-static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
- struct beacon_parameters *info, bool add)
+static int ath6kl_set_ies(struct ath6kl_vif *vif,
+ struct cfg80211_beacon_data *info)
{
- struct ath6kl *ar = ath6kl_priv(dev);
- struct ath6kl_vif *vif = netdev_priv(dev);
- struct ieee80211_mgmt *mgmt;
- u8 *ies;
- int ies_len;
- struct wmi_connect_cmd p;
+ struct ath6kl *ar = vif->ar;
int res;
- int i, ret;
-
- ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
-
- if (!ath6kl_cfg80211_ready(vif))
- return -EIO;
-
- if (vif->next_mode != AP_NETWORK)
- return -EOPNOTSUPP;
if (info->beacon_ies) {
res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
@@ -2297,12 +2283,14 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
if (res)
return res;
}
+
if (info->proberesp_ies) {
res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
info->proberesp_ies_len);
if (res)
return res;
}
+
if (info->assocresp_ies) {
res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
WMI_FRAME_ASSOC_RESP,
@@ -2312,8 +2300,30 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
return res;
}
- if (!add)
- return 0;
+ return 0;
+}
+
+static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ap_settings *info)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+ struct ath6kl_vif *vif = netdev_priv(dev);
+ struct ieee80211_mgmt *mgmt;
+ u8 *ies;
+ int ies_len;
+ struct wmi_connect_cmd p;
+ int res;
+ int i, ret;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__);
+
+ if (!ath6kl_cfg80211_ready(vif))
+ return -EIO;
+
+ if (vif->next_mode != AP_NETWORK)
+ return -EOPNOTSUPP;
+
+ res = ath6kl_set_ies(vif, &info->beacon);
ar->ap_mode_bkey.valid = false;
@@ -2322,13 +2332,13 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
* info->dtim_period
*/
- if (info->head == NULL)
+ if (info->beacon.head == NULL)
return -EINVAL;
- mgmt = (struct ieee80211_mgmt *) info->head;
+ mgmt = (struct ieee80211_mgmt *) info->beacon.head;
ies = mgmt->u.beacon.variable;
- if (ies > info->head + info->head_len)
+ if (ies > info->beacon.head + info->beacon.head_len)
return -EINVAL;
- ies_len = info->head + info->head_len - ies;
+ ies_len = info->beacon.head + info->beacon.head_len - ies;
if (info->ssid == NULL)
return -EINVAL;
@@ -2436,19 +2446,21 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
-static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
- struct beacon_parameters *info)
+static int ath6kl_change_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_beacon_data *beacon)
{
- return ath6kl_ap_beacon(wiphy, dev, info, true);
-}
+ struct ath6kl_vif *vif = netdev_priv(dev);
-static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
- struct beacon_parameters *info)
-{
- return ath6kl_ap_beacon(wiphy, dev, info, false);
+ if (!ath6kl_cfg80211_ready(vif))
+ return -EIO;
+
+ if (vif->next_mode != AP_NETWORK)
+ return -EOPNOTSUPP;
+
+ return ath6kl_set_ies(vif, beacon);
}
-static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
+static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
{
struct ath6kl *ar = ath6kl_priv(dev);
struct ath6kl_vif *vif = netdev_priv(dev);
@@ -2783,9 +2795,9 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
.resume = __ath6kl_cfg80211_resume,
#endif
.set_channel = ath6kl_set_channel,
- .add_beacon = ath6kl_add_beacon,
- .set_beacon = ath6kl_set_beacon,
- .del_beacon = ath6kl_del_beacon,
+ .start_ap = ath6kl_start_ap,
+ .change_beacon = ath6kl_change_beacon,
+ .stop_ap = ath6kl_stop_ap,
.del_station = ath6kl_del_station,
.change_station = ath6kl_change_station,
.remain_on_channel = ath6kl_remain_on_channel,
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index ec82e926bad..c81304d3ef1 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -371,12 +371,8 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
if (sc->sc_flags & SC_OP_INVALID)
return -EIO;
- ath9k_ps_wakeup(sc);
-
r = ath_reset_internal(sc, hchan, false);
- ath9k_ps_restore(sc);
-
return r;
}
@@ -1587,12 +1583,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
ath9k_ps_wakeup(sc);
mutex_lock(&sc->mutex);
- /*
- * Leave this as the first check because we need to turn on the
- * radio if it was disabled before prior to processing the rest
- * of the changes. Likewise we must only disable the radio towards
- * the end.
- */
if (changed & IEEE80211_CONF_CHANGE_IDLE) {
sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
if (sc->ps_idle)
diff --git a/drivers/net/wireless/brcm80211/Kconfig b/drivers/net/wireless/brcm80211/Kconfig
index cd6375de2a6..c5104533e24 100644
--- a/drivers/net/wireless/brcm80211/Kconfig
+++ b/drivers/net/wireless/brcm80211/Kconfig
@@ -26,16 +26,25 @@ config BRCMFMAC
it'll be called brcmfmac.ko.
config BRCMFMAC_SDIO
- bool "SDIO bus interface support for FullMAC"
+ bool "SDIO bus interface support for FullMAC driver"
depends on MMC
depends on BRCMFMAC
select FW_LOADER
default y
---help---
This option enables the SDIO bus interface support for Broadcom
- FullMAC WLAN driver.
- Say Y if you want to use brcmfmac for a compatible SDIO interface
- wireless card.
+ IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to
+ use the driver for a SDIO wireless card.
+
+config BRCMFMAC_USB
+ bool "USB bus interface support for FullMAC driver"
+ depends on USB
+ depends on BRCMFMAC
+ select FW_LOADER
+ ---help---
+ This option enables the USB bus interface support for Broadcom
+ IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to
+ use the driver for an USB wireless card.
config BRCMDBG
bool "Broadcom driver debug functions"
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
index 9ca9ea1135e..abb48032753 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
@@ -19,6 +19,8 @@ ccflags-y += \
-Idrivers/net/wireless/brcm80211/brcmfmac \
-Idrivers/net/wireless/brcm80211/include
+ccflags-y += -D__CHECK_ENDIAN__
+
obj-$(CONFIG_BRCMFMAC) += brcmfmac.o
brcmfmac-objs += \
wl_cfg80211.o \
@@ -30,5 +32,5 @@ brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
bcmsdh.o \
bcmsdh_sdmmc.o \
sdio_chip.o
-
-ccflags-y += -D__CHECK_ENDIAN__
+brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
+ usb.o
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
index ac71adeece5..83ca3cc2ccc 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
@@ -294,13 +294,14 @@ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
struct sk_buff *pkt)
{
int status;
- uint pkt_len = pkt->len;
+ uint pkt_len;
bool fifo = (fix_inc == SDIOH_DATA_FIX);
brcmf_dbg(TRACE, "Enter\n");
if (pkt == NULL)
return -EINVAL;
+ pkt_len = pkt->len;
brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
if (brcmf_pm_resume_error(sdiodev))
@@ -488,7 +489,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
sdiodev->func[0] = func->card->sdio_func[0];
sdiodev->func[1] = func;
sdiodev->bus_if = bus_if;
- bus_if->bus_priv = sdiodev;
+ bus_if->bus_priv.sdio = sdiodev;
bus_if->type = SDIO_BUS;
bus_if->align = BRCMF_SDALIGN;
dev_set_drvdata(&func->card->dev, sdiodev);
@@ -529,7 +530,7 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
if (func->num == 2) {
bus_if = dev_get_drvdata(&func->dev);
- sdiodev = bus_if->bus_priv;
+ sdiodev = bus_if->bus_priv.sdio;
brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_remove...\n");
brcmf_sdio_remove(sdiodev);
dev_set_drvdata(&func->card->dev, NULL);
@@ -596,14 +597,14 @@ static struct sdio_driver brcmf_sdmmc_driver = {
#endif /* CONFIG_PM_SLEEP */
};
-static void __exit brcmf_sdio_exit(void)
+void brcmf_sdio_exit(void)
{
brcmf_dbg(TRACE, "Enter\n");
sdio_unregister_driver(&brcmf_sdmmc_driver);
}
-static int __init brcmf_sdio_init(void)
+int brcmf_sdio_init(void)
{
int ret;
@@ -616,6 +617,3 @@ static int __init brcmf_sdio_init(void)
return ret;
}
-
-module_init(brcmf_sdio_init);
-module_exit(brcmf_sdio_exit);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
index ad9be2410b5..b7671b30692 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
@@ -39,8 +39,11 @@ struct dngl_stats {
/* interface structure between common and bus layer */
struct brcmf_bus {
u8 type; /* bus type */
- void *bus_priv; /* pointer to bus private structure */
- void *drvr; /* pointer to driver pub structure brcmf_pub */
+ union {
+ struct brcmf_sdio_dev *sdio;
+ struct brcmf_usbdev *usb;
+ } bus_priv;
+ struct brcmf_pub *drvr; /* pointer to driver pub structure brcmf_pub */
enum brcmf_bus_state state;
uint maxctl; /* Max size rxctl request from proto to bus */
bool drvr_up; /* Status flag of driver up/down */
@@ -102,4 +105,14 @@ extern int brcmf_bus_start(struct device *dev);
extern int brcmf_add_if(struct device *dev, int ifidx,
char *name, u8 *mac_addr);
+
+#ifdef CONFIG_BRCMFMAC_SDIO
+extern void brcmf_sdio_exit(void);
+extern int brcmf_sdio_init(void);
+#endif
+#ifdef CONFIG_BRCMFMAC_USB
+extern void brcmf_usb_exit(void);
+extern int brcmf_usb_init(void);
+#endif
+
#endif /* _BRCMF_BUS_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index db2df1f1e6b..c4da0581744 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -796,18 +796,19 @@ static int brcmf_netdev_open(struct net_device *ndev)
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
+ struct brcmf_bus *bus_if = drvr->bus_if;
u32 toe_ol;
s32 ret = 0;
brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx);
if (ifp->idx == 0) { /* do it only for primary eth0 */
- /* try to bring up bus */
- ret = brcmf_bus_start(drvr->dev);
- if (ret != 0) {
- brcmf_dbg(ERROR, "failed with code %d\n", ret);
- return -1;
+ /* If bus is not ready, can't continue */
+ if (bus_if->state != BRCMF_BUS_DATA) {
+ brcmf_dbg(ERROR, "failed bus is not ready\n");
+ return -EAGAIN;
}
+
atomic_set(&drvr->pend_8021x_cnt, 0);
memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN);
@@ -979,12 +980,6 @@ int brcmf_bus_start(struct device *dev)
return ret;
}
- /* If bus is not ready, can't come up */
- if (bus_if->state != BRCMF_BUS_DATA) {
- brcmf_dbg(ERROR, "failed bus is not ready\n");
- return -ENODEV;
- }
-
brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN,
iovbuf, sizeof(iovbuf));
brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, iovbuf,
@@ -1021,6 +1016,8 @@ int brcmf_bus_start(struct device *dev)
if (ret < 0)
return ret;
+ /* signal bus ready */
+ bus_if->state = BRCMF_BUS_DATA;
return 0;
}
@@ -1109,13 +1106,13 @@ void brcmf_detach(struct device *dev)
if (drvr->iflist[i])
brcmf_del_if(drvr, i);
- cancel_work_sync(&drvr->setmacaddr_work);
- cancel_work_sync(&drvr->multicast_work);
-
brcmf_bus_detach(drvr);
- if (drvr->prot)
+ if (drvr->prot) {
+ cancel_work_sync(&drvr->setmacaddr_work);
+ cancel_work_sync(&drvr->multicast_work);
brcmf_proto_detach(drvr);
+ }
bus_if->drvr = NULL;
kfree(drvr);
@@ -1183,3 +1180,35 @@ exit:
return ret;
}
#endif /* DEBUG */
+
+static int __init brcmfmac_init(void)
+{
+ int ret = 0;
+
+#ifdef CONFIG_BRCMFMAC_SDIO
+ ret = brcmf_sdio_init();
+ if (ret)
+ goto fail;
+#endif
+#ifdef CONFIG_BRCMFMAC_USB
+ ret = brcmf_usb_init();
+ if (ret)
+ goto fail;
+#endif
+
+fail:
+ return ret;
+}
+
+static void __exit brcmfmac_exit(void)
+{
+#ifdef CONFIG_BRCMFMAC_SDIO
+ brcmf_sdio_exit();
+#endif
+#ifdef CONFIG_BRCMFMAC_USB
+ brcmf_usb_exit();
+#endif
+}
+
+module_init(brcmfmac_init);
+module_exit(brcmfmac_exit);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index 6e4b5e85a09..0b467b08604 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -309,10 +309,10 @@ struct rte_console {
/* Flags for SDH calls */
#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
-#define BRCMFMAC_FW_NAME "brcm/brcmfmac.bin"
-#define BRCMFMAC_NV_NAME "brcm/brcmfmac.txt"
-MODULE_FIRMWARE(BRCMFMAC_FW_NAME);
-MODULE_FIRMWARE(BRCMFMAC_NV_NAME);
+#define BRCMF_SDIO_FW_NAME "brcm/brcmfmac-sdio.bin"
+#define BRCMF_SDIO_NV_NAME "brcm/brcmfmac-sdio.txt"
+MODULE_FIRMWARE(BRCMF_SDIO_FW_NAME);
+MODULE_FIRMWARE(BRCMF_SDIO_NV_NAME);
#define BRCMF_IDLE_IMMEDIATE (-1) /* Enter idle immediately */
#define BRCMF_IDLE_ACTIVE 0 /* Do not request any SD clock change
@@ -2277,7 +2277,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
uint retries;
int err;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiodev->bus;
brcmf_dbg(TRACE, "Enter\n");
@@ -2627,7 +2627,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
int ret = -EBADE;
uint datalen, prec;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiodev->bus;
brcmf_dbg(TRACE, "Enter\n");
@@ -2869,7 +2869,7 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
u8 doff = 0;
int ret = -1;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiodev->bus;
brcmf_dbg(TRACE, "Enter\n");
@@ -2978,7 +2978,7 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
uint rxlen = 0;
bool pending;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiodev->bus;
brcmf_dbg(TRACE, "Enter\n");
@@ -3202,7 +3202,7 @@ static int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus)
brcmf_dbg(INFO, "Enter\n");
- ret = request_firmware(&bus->firmware, BRCMFMAC_FW_NAME,
+ ret = request_firmware(&bus->firmware, BRCMF_SDIO_FW_NAME,
&bus->sdiodev->func[2]->dev);
if (ret) {
brcmf_dbg(ERROR, "Fail to request firmware %d\n", ret);
@@ -3299,7 +3299,7 @@ static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus)
char *bufp;
int ret;
- ret = request_firmware(&bus->firmware, BRCMFMAC_NV_NAME,
+ ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME,
&bus->sdiodev->func[2]->dev);
if (ret) {
brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret);
@@ -3389,7 +3389,7 @@ brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
static int brcmf_sdbrcm_bus_init(struct device *dev)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiodev->bus;
unsigned long timeout;
uint retries = 0;
@@ -3464,16 +3464,12 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_WATERMARK, 8, &err);
-
- /* Set bus state according to enable result */
- bus_if->state = BRCMF_BUS_DATA;
- }
-
- else {
+ } else {
/* Disable F2 again */
enable = SDIO_FUNC_ENABLE_1;
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0,
SDIO_CCCR_IOEx, enable, NULL);
+ ret = -ENODEV;
}
/* Restore previous clock setting */
@@ -3481,7 +3477,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
/* If we didn't come up, turn off backplane clock */
- if (bus_if->state != BRCMF_BUS_DATA)
+ if (!ret)
brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
exit:
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
new file mode 100644
index 00000000000..934ed782620
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -0,0 +1,1623 @@
+/*
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/firmware.h>
+#include <linux/usb.h>
+#include <net/cfg80211.h>
+
+#include <defs.h>
+#include <brcmu_utils.h>
+#include <brcmu_wifi.h>
+#include <dhd_bus.h>
+#include <dhd_dbg.h>
+
+#include "usb_rdl.h"
+#include "usb.h"
+
+#define IOCTL_RESP_TIMEOUT 2000
+
+#define BRCMF_USB_SYNC_TIMEOUT 300 /* ms */
+#define BRCMF_USB_DLIMAGE_SPINWAIT 100 /* in unit of ms */
+#define BRCMF_USB_DLIMAGE_LIMIT 500 /* spinwait limit (ms) */
+
+#define BRCMF_POSTBOOT_ID 0xA123 /* ID to detect if dongle
+ has boot up */
+#define BRCMF_USB_RESETCFG_SPINWAIT 1 /* wait after resetcfg (ms) */
+
+#define BRCMF_USB_NRXQ 50
+#define BRCMF_USB_NTXQ 50
+
+#define CONFIGDESC(usb) (&((usb)->actconfig)->desc)
+#define IFPTR(usb, idx) ((usb)->actconfig->interface[(idx)])
+#define IFALTS(usb, idx) (IFPTR((usb), (idx))->altsetting[0])
+#define IFDESC(usb, idx) IFALTS((usb), (idx)).desc
+#define IFEPDESC(usb, idx, ep) (IFALTS((usb), (idx)).endpoint[(ep)]).desc
+
+#define CONTROL_IF 0
+#define BULK_IF 0
+
+#define BRCMF_USB_CBCTL_WRITE 0
+#define BRCMF_USB_CBCTL_READ 1
+#define BRCMF_USB_MAX_PKT_SIZE 1600
+
+#define BRCMF_USB_FW_NAME "brcm/brcmfmac-usb.bin"
+
+enum usbdev_suspend_state {
+ USBOS_SUSPEND_STATE_DEVICE_ACTIVE = 0, /* Device is busy, won't allow
+ suspend */
+ USBOS_SUSPEND_STATE_SUSPEND_PENDING, /* Device is idle, can be
+ * suspended. Wating PM to
+ * suspend the device
+ */
+ USBOS_SUSPEND_STATE_SUSPENDED /* Device suspended */
+};
+
+struct brcmf_usb_probe_info {
+ void *usbdev_info;
+ struct usb_device *usb; /* USB device pointer from OS */
+ uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2;
+ int intr_size; /* Size of interrupt message */
+ int interval; /* Interrupt polling interval */
+ int vid;
+ int pid;
+ enum usb_device_speed device_speed;
+ enum usbdev_suspend_state suspend_state;
+ struct usb_interface *intf;
+};
+static struct brcmf_usb_probe_info usbdev_probe_info;
+
+struct brcmf_usb_image {
+ void *data;
+ u32 len;
+};
+static struct brcmf_usb_image g_image = { NULL, 0 };
+
+struct intr_transfer_buf {
+ u32 notification;
+ u32 reserved;
+};
+
+struct brcmf_usbdev_info {
+ struct brcmf_usbdev bus_pub; /* MUST BE FIRST */
+ spinlock_t qlock;
+ struct list_head rx_freeq;
+ struct list_head rx_postq;
+ struct list_head tx_freeq;
+ struct list_head tx_postq;
+ enum usbdev_suspend_state suspend_state;
+ uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2;
+
+ bool activity;
+ int rx_low_watermark;
+ int tx_low_watermark;
+ int tx_high_watermark;
+ bool txoff;
+ bool rxoff;
+ bool txoverride;
+
+ struct brcmf_usbreq *tx_reqs;
+ struct brcmf_usbreq *rx_reqs;
+
+ u8 *image; /* buffer for combine fw and nvram */
+ int image_len;
+
+ wait_queue_head_t wait;
+ bool waitdone;
+ int sync_urb_status;
+
+ struct usb_device *usbdev;
+ struct device *dev;
+ enum usb_device_speed device_speed;
+
+ int ctl_in_pipe, ctl_out_pipe;
+ struct urb *ctl_urb; /* URB for control endpoint */
+ struct usb_ctrlrequest ctl_write;
+ struct usb_ctrlrequest ctl_read;
+ u32 ctl_urb_actual_length;
+ int ctl_urb_status;
+ int ctl_completed;
+ wait_queue_head_t ioctl_resp_wait;
+ wait_queue_head_t ctrl_wait;
+ ulong ctl_op;
+
+ bool rxctl_deferrespok;
+
+ struct urb *bulk_urb; /* used for FW download */
+ struct urb *intr_urb; /* URB for interrupt endpoint */
+ int intr_size; /* Size of interrupt message */
+ int interval; /* Interrupt polling interval */
+ struct intr_transfer_buf intr; /* Data buffer for interrupt endpoint */
+
+ struct brcmf_usb_probe_info probe_info;
+
+};
+
+static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
+ struct brcmf_usbreq *req);
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac usb driver.");
+MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac usb cards");
+MODULE_LICENSE("Dual BSD/GPL");
+
+static struct brcmf_usbdev *brcmf_usb_get_buspub(struct device *dev)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ return bus_if->bus_priv.usb;
+}
+
+static struct brcmf_usbdev_info *brcmf_usb_get_businfo(struct device *dev)
+{
+ return brcmf_usb_get_buspub(dev)->devinfo;
+}
+
+#if 0
+static void
+brcmf_usb_txflowcontrol(struct brcmf_usbdev_info *devinfo, bool onoff)
+{
+ dhd_txflowcontrol(devinfo->bus_pub.netdev, 0, onoff);
+}
+#endif
+
+static int brcmf_usb_ioctl_resp_wait(struct brcmf_usbdev_info *devinfo,
+ uint *condition, bool *pending)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int timeout = IOCTL_RESP_TIMEOUT;
+
+ /* Convert timeout in millsecond to jiffies */
+ timeout = msecs_to_jiffies(timeout);
+ /* Wait until control frame is available */
+ add_wait_queue(&devinfo->ioctl_resp_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ smp_mb();
+ while (!(*condition) && (!signal_pending(current) && timeout)) {
+ timeout = schedule_timeout(timeout);
+ /* Wait until control frame is available */
+ smp_mb();
+ }
+
+ if (signal_pending(current))
+ *pending = true;
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&devinfo->ioctl_resp_wait, &wait);
+
+ return timeout;
+}
+
+static int brcmf_usb_ioctl_resp_wake(struct brcmf_usbdev_info *devinfo)
+{
+ if (waitqueue_active(&devinfo->ioctl_resp_wait))
+ wake_up_interruptible(&devinfo->ioctl_resp_wait);
+
+ return 0;
+}
+
+static void
+brcmf_usb_ctl_complete(struct brcmf_usbdev_info *devinfo, int type, int status)
+{
+
+ if (unlikely(devinfo == NULL))
+ return;
+
+ if (type == BRCMF_USB_CBCTL_READ) {
+ if (status == 0)
+ devinfo->bus_pub.stats.rx_ctlpkts++;
+ else
+ devinfo->bus_pub.stats.rx_ctlerrs++;
+ } else if (type == BRCMF_USB_CBCTL_WRITE) {
+ if (status == 0)
+ devinfo->bus_pub.stats.tx_ctlpkts++;
+ else
+ devinfo->bus_pub.stats.tx_ctlerrs++;
+ }
+
+ devinfo->ctl_urb_status = status;
+ devinfo->ctl_completed = true;
+ brcmf_usb_ioctl_resp_wake(devinfo);
+}
+
+static void
+brcmf_usb_ctlread_complete(struct urb *urb)
+{
+ struct brcmf_usbdev_info *devinfo =
+ (struct brcmf_usbdev_info *)urb->context;
+
+ devinfo->ctl_urb_actual_length = urb->actual_length;
+ brcmf_usb_ctl_complete(devinfo, BRCMF_USB_CBCTL_READ,
+ urb->status);
+}
+
+static void
+brcmf_usb_ctlwrite_complete(struct urb *urb)
+{
+ struct brcmf_usbdev_info *devinfo =
+ (struct brcmf_usbdev_info *)urb->context;
+
+ brcmf_usb_ctl_complete(devinfo, BRCMF_USB_CBCTL_WRITE,
+ urb->status);
+}
+
+static int brcmf_usb_pnp(struct brcmf_usbdev_info *devinfo, uint state)
+{
+ return 0;
+}
+
+static int
+brcmf_usb_send_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len)
+{
+ int ret;
+ u16 size;
+
+ if (devinfo == NULL || buf == NULL ||
+ len == 0 || devinfo->ctl_urb == NULL)
+ return -EINVAL;
+
+ /* If the USB/HSIC bus in sleep state, wake it up */
+ if (devinfo->suspend_state == USBOS_SUSPEND_STATE_SUSPENDED)
+ if (brcmf_usb_pnp(devinfo, BCMFMAC_USB_PNP_RESUME) != 0) {
+ brcmf_dbg(ERROR, "Could not Resume the bus!\n");
+ return -EIO;
+ }
+
+ devinfo->activity = true;
+ size = len;
+ devinfo->ctl_write.wLength = cpu_to_le16p(&size);
+ devinfo->ctl_urb->transfer_buffer_length = size;
+ devinfo->ctl_urb_status = 0;
+ devinfo->ctl_urb_actual_length = 0;
+
+ usb_fill_control_urb(devinfo->ctl_urb,
+ devinfo->usbdev,
+ devinfo->ctl_out_pipe,
+ (unsigned char *) &devinfo->ctl_write,
+ buf, size,
+ (usb_complete_t)brcmf_usb_ctlwrite_complete,
+ devinfo);
+
+ ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC);
+ if (ret < 0)
+ brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret);
+
+ return ret;
+}
+
+static int
+brcmf_usb_recv_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len)
+{
+ int ret;
+ u16 size;
+
+ if ((devinfo == NULL) || (buf == NULL) || (len == 0)
+ || (devinfo->ctl_urb == NULL))
+ return -EINVAL;
+
+ size = len;
+ devinfo->ctl_read.wLength = cpu_to_le16p(&size);
+ devinfo->ctl_urb->transfer_buffer_length = size;
+
+ if (devinfo->rxctl_deferrespok) {
+ /* BMAC model */
+ devinfo->ctl_read.bRequestType = USB_DIR_IN
+ | USB_TYPE_VENDOR | USB_RECIP_INTERFACE;
+ devinfo->ctl_read.bRequest = DL_DEFER_RESP_OK;
+ } else {
+ /* full dongle model */
+ devinfo->ctl_read.bRequestType = USB_DIR_IN
+ | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ devinfo->ctl_read.bRequest = 1;
+ }
+
+ usb_fill_control_urb(devinfo->ctl_urb,
+ devinfo->usbdev,
+ devinfo->ctl_in_pipe,
+ (unsigned char *) &devinfo->ctl_read,
+ buf, size,
+ (usb_complete_t)brcmf_usb_ctlread_complete,
+ devinfo);
+
+ ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC);
+ if (ret < 0)
+ brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret);
+
+ return ret;
+}
+
+static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len)
+{
+ int err = 0;
+ int timeout = 0;
+ bool pending;
+ struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+
+ if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
+ /* TODO: handle suspend/resume */
+ return -EIO;
+ }
+
+ if (test_and_set_bit(0, &devinfo->ctl_op))
+ return -EIO;
+
+ err = brcmf_usb_send_ctl(devinfo, buf, len);
+ if (err) {
+ brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len);
+ return err;
+ }
+
+ devinfo->ctl_completed = false;
+ timeout = brcmf_usb_ioctl_resp_wait(devinfo, &devinfo->ctl_completed,
+ &pending);
+ clear_bit(0, &devinfo->ctl_op);
+ if (!timeout) {
+ brcmf_dbg(ERROR, "Txctl wait timed out\n");
+ err = -EIO;
+ }
+ return err;
+}
+
+static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len)
+{
+ int err = 0;
+ int timeout = 0;
+ bool pending;
+ struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+
+ if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
+ /* TODO: handle suspend/resume */
+ return -EIO;
+ }
+ if (test_and_set_bit(0, &devinfo->ctl_op))
+ return -EIO;
+
+ err = brcmf_usb_recv_ctl(devinfo, buf, len);
+ if (err) {
+ brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len);
+ return err;
+ }
+ devinfo->ctl_completed = false;
+ timeout = brcmf_usb_ioctl_resp_wait(devinfo, &devinfo->ctl_completed,
+ &pending);
+ err = devinfo->ctl_urb_status;
+ clear_bit(0, &devinfo->ctl_op);
+ if (!timeout) {
+ brcmf_dbg(ERROR, "rxctl wait timed out\n");
+ err = -EIO;
+ }
+ if (!err)
+ return devinfo->ctl_urb_actual_length;
+ else
+ return err;
+}
+
+static struct brcmf_usbreq *brcmf_usb_deq(struct brcmf_usbdev_info *devinfo,
+ struct list_head *q)
+{
+ unsigned long flags;
+ struct brcmf_usbreq *req;
+ spin_lock_irqsave(&devinfo->qlock, flags);
+ if (list_empty(q)) {
+ spin_unlock_irqrestore(&devinfo->qlock, flags);
+ return NULL;
+ }
+ req = list_entry(q->next, struct brcmf_usbreq, list);
+ list_del_init(q->next);
+ spin_unlock_irqrestore(&devinfo->qlock, flags);
+ return req;
+
+}
+
+static void brcmf_usb_enq(struct brcmf_usbdev_info *devinfo,
+ struct list_head *q, struct brcmf_usbreq *req)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&devinfo->qlock, flags);
+ list_add_tail(&req->list, q);
+ spin_unlock_irqrestore(&devinfo->qlock, flags);
+}
+
+static struct brcmf_usbreq *
+brcmf_usbdev_qinit(struct list_head *q, int qsize)
+{
+ int i;
+ struct brcmf_usbreq *req, *reqs;
+
+ reqs = kzalloc(sizeof(struct brcmf_usbreq) * qsize, GFP_ATOMIC);
+ if (reqs == NULL) {
+ brcmf_dbg(ERROR, "fail to allocate memory!\n");
+ return NULL;
+ }
+ req = reqs;
+
+ for (i = 0; i < qsize; i++) {
+ req->urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!req->urb)
+ goto fail;
+
+ INIT_LIST_HEAD(&req->list);
+ list_add_tail(&req->list, q);
+ req++;
+ }
+ return reqs;
+fail:
+ brcmf_dbg(ERROR, "fail!\n");
+ while (!list_empty(q)) {
+ req = list_entry(q->next, struct brcmf_usbreq, list);
+ if (req && req->urb)
+ usb_free_urb(req->urb);
+ list_del(q->next);
+ }
+ return NULL;
+
+}
+
+static void brcmf_usb_free_q(struct list_head *q, bool pending)
+{
+ struct brcmf_usbreq *req, *next;
+ int i = 0;
+ list_for_each_entry_safe(req, next, q, list) {
+ if (!req || !req->urb) {
+ brcmf_dbg(ERROR, "bad req\n");
+ break;
+ }
+ i++;
+ if (pending) {
+ usb_kill_urb(req->urb);
+ } else {
+ usb_free_urb(req->urb);
+ list_del_init(&req->list);
+ }
+ }
+}
+
+static void brcmf_usb_del_fromq(struct brcmf_usbdev_info *devinfo,
+ struct brcmf_usbreq *req)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&devinfo->qlock, flags);
+ list_del_init(&req->list);
+ spin_unlock_irqrestore(&devinfo->qlock, flags);
+}
+
+
+static void brcmf_usb_tx_complete(struct urb *urb)
+{
+ struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context;
+ struct brcmf_usbdev_info *devinfo = req->devinfo;
+
+ brcmf_usb_del_fromq(devinfo, req);
+ if (urb->status == 0)
+ devinfo->bus_pub.stats.tx_packets++;
+ else
+ devinfo->bus_pub.stats.tx_errors++;
+
+ dev_kfree_skb(req->skb);
+ req->skb = NULL;
+ brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req);
+
+}
+
+static void brcmf_usb_rx_complete(struct urb *urb)
+{
+ struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context;
+ struct brcmf_usbdev_info *devinfo = req->devinfo;
+ struct sk_buff *skb;
+ int ifidx = 0;
+
+ brcmf_usb_del_fromq(devinfo, req);
+ skb = req->skb;
+ req->skb = NULL;
+
+ if (urb->status == 0) {
+ devinfo->bus_pub.stats.rx_packets++;
+ } else {
+ devinfo->bus_pub.stats.rx_errors++;
+ dev_kfree_skb(skb);
+ brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
+ return;
+ }
+
+ if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP) {
+ skb_put(skb, urb->actual_length);
+ if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) {
+ brcmf_dbg(ERROR, "rx protocol error\n");
+ brcmu_pkt_buf_free_skb(skb);
+ devinfo->bus_pub.bus->dstats.rx_errors++;
+ } else {
+ brcmf_rx_packet(devinfo->dev, ifidx, skb);
+ brcmf_usb_rx_refill(devinfo, req);
+ }
+ } else {
+ dev_kfree_skb(skb);
+ }
+ return;
+
+}
+
+static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
+ struct brcmf_usbreq *req)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ if (!req || !devinfo)
+ return;
+
+ skb = dev_alloc_skb(devinfo->bus_pub.bus_mtu);
+ if (!skb) {
+ brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
+ return;
+ }
+ req->skb = skb;
+
+ usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->rx_pipe,
+ skb->data, skb_tailroom(skb), brcmf_usb_rx_complete,
+ req);
+ req->urb->transfer_flags |= URB_ZERO_PACKET;
+ req->devinfo = devinfo;
+
+ ret = usb_submit_urb(req->urb, GFP_ATOMIC);
+ if (ret == 0) {
+ brcmf_usb_enq(devinfo, &devinfo->rx_postq, req);
+ } else {
+ dev_kfree_skb(req->skb);
+ req->skb = NULL;
+ brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
+ }
+ return;
+}
+
+static void brcmf_usb_rx_fill_all(struct brcmf_usbdev_info *devinfo)
+{
+ struct brcmf_usbreq *req;
+
+ if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
+ brcmf_dbg(ERROR, "bus is not up\n");
+ return;
+ }
+ while ((req = brcmf_usb_deq(devinfo, &devinfo->rx_freeq)) != NULL)
+ brcmf_usb_rx_refill(devinfo, req);
+}
+
+static void
+brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state)
+{
+ struct brcmf_bus *bcmf_bus = devinfo->bus_pub.bus;
+ int old_state;
+
+
+ if (devinfo->bus_pub.state == state)
+ return;
+
+ old_state = devinfo->bus_pub.state;
+ brcmf_dbg(TRACE, "dbus state change from %d to to %d\n",
+ old_state, state);
+
+ /* Don't update state if it's PnP firmware re-download */
+ if (state != BCMFMAC_USB_STATE_PNP_FWDL) /* TODO */
+ devinfo->bus_pub.state = state;
+
+ if ((old_state == BCMFMAC_USB_STATE_SLEEP)
+ && (state == BCMFMAC_USB_STATE_UP)) {
+ brcmf_usb_rx_fill_all(devinfo);
+ }
+
+ /* update state of upper layer */
+ if (state == BCMFMAC_USB_STATE_DOWN) {
+ brcmf_dbg(INFO, "DBUS is down\n");
+ bcmf_bus->state = BRCMF_BUS_DOWN;
+ } else {
+ brcmf_dbg(INFO, "DBUS current state=%d\n", state);
+ }
+}
+
+static void
+brcmf_usb_intr_complete(struct urb *urb)
+{
+ struct brcmf_usbdev_info *devinfo =
+ (struct brcmf_usbdev_info *)urb->context;
+ bool killed;
+
+ if (devinfo == NULL)
+ return;
+
+ if (unlikely(urb->status)) {
+ if (devinfo->suspend_state ==
+ USBOS_SUSPEND_STATE_SUSPEND_PENDING)
+ killed = true;
+
+ if ((urb->status == -ENOENT && (!killed))
+ || urb->status == -ESHUTDOWN ||
+ urb->status == -ENODEV) {
+ brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_DOWN);
+ }
+ }
+
+ if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_DOWN) {
+ brcmf_dbg(ERROR, "intr cb when DBUS down, ignoring\n");
+ return;
+ }
+
+ if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP)
+ usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC);
+}
+
+static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
+{
+ struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+ struct brcmf_usbreq *req;
+ int ret;
+
+ if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
+ /* TODO: handle suspend/resume */
+ return -EIO;
+ }
+
+ req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq);
+ if (!req) {
+ brcmf_dbg(ERROR, "no req to send\n");
+ return -ENOMEM;
+ }
+ if (!req->urb) {
+ brcmf_dbg(ERROR, "no urb for req %p\n", req);
+ return -ENOBUFS;
+ }
+
+ req->skb = skb;
+ req->devinfo = devinfo;
+ usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->tx_pipe,
+ skb->data, skb->len, brcmf_usb_tx_complete, req);
+ req->urb->transfer_flags |= URB_ZERO_PACKET;
+ ret = usb_submit_urb(req->urb, GFP_ATOMIC);
+ if (!ret) {
+ brcmf_usb_enq(devinfo, &devinfo->tx_postq, req);
+ } else {
+ req->skb = NULL;
+ brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req);
+ }
+
+ return ret;
+}
+
+
+static int brcmf_usb_up(struct device *dev)
+{
+ struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+ u16 ifnum;
+
+ if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP)
+ return 0;
+
+ if (devinfo == NULL)
+ return -EINVAL;
+
+ /* If the USB/HSIC bus in sleep state, wake it up */
+ if (devinfo->suspend_state == USBOS_SUSPEND_STATE_SUSPENDED) {
+ if (brcmf_usb_pnp(devinfo, BCMFMAC_USB_PNP_RESUME) != 0) {
+ brcmf_dbg(ERROR, "Could not Resume the bus!\n");
+ return -EIO;
+ }
+ }
+ devinfo->activity = true;
+
+ /* Success, indicate devinfo is fully up */
+ brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_UP);
+
+ if (devinfo->intr_urb) {
+ int ret;
+
+ usb_fill_int_urb(devinfo->intr_urb, devinfo->usbdev,
+ devinfo->intr_pipe,
+ &devinfo->intr,
+ devinfo->intr_size,
+ (usb_complete_t)brcmf_usb_intr_complete,
+ devinfo,
+ devinfo->interval);
+
+ ret = usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC);
+ if (ret) {
+ brcmf_dbg(ERROR, "USB_SUBMIT_URB failed with status %d\n",
+ ret);
+ return -EINVAL;
+ }
+ }
+
+ if (devinfo->ctl_urb) {
+ devinfo->ctl_in_pipe = usb_rcvctrlpipe(devinfo->usbdev, 0);
+ devinfo->ctl_out_pipe = usb_sndctrlpipe(devinfo->usbdev, 0);
+
+ ifnum = IFDESC(devinfo->usbdev, CONTROL_IF).bInterfaceNumber;
+
+ /* CTL Write */
+ devinfo->ctl_write.bRequestType =
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ devinfo->ctl_write.bRequest = 0;
+ devinfo->ctl_write.wValue = cpu_to_le16(0);
+ devinfo->ctl_write.wIndex = cpu_to_le16p(&ifnum);
+
+ /* CTL Read */
+ devinfo->ctl_read.bRequestType =
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ devinfo->ctl_read.bRequest = 1;
+ devinfo->ctl_read.wValue = cpu_to_le16(0);
+ devinfo->ctl_read.wIndex = cpu_to_le16p(&ifnum);
+ }
+ brcmf_usb_rx_fill_all(devinfo);
+ return 0;
+}
+
+static void brcmf_usb_down(struct device *dev)
+{
+ struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+
+ if (devinfo == NULL)
+ return;
+
+ brcmf_dbg(TRACE, "enter\n");
+ if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_DOWN)
+ return;
+
+ brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_DOWN);
+ if (devinfo->intr_urb)
+ usb_kill_urb(devinfo->intr_urb);
+
+ 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 int
+brcmf_usb_sync_wait(struct brcmf_usbdev_info *devinfo, u16 time)
+{
+ int ret;
+ int err = 0;
+ int ms = time;
+
+ ret = wait_event_interruptible_timeout(devinfo->wait,
+ devinfo->waitdone == true, (ms * HZ / 1000));
+
+ if ((devinfo->waitdone == false) || (devinfo->sync_urb_status)) {
+ brcmf_dbg(ERROR, "timeout(%d) or urb err=%d\n",
+ ret, devinfo->sync_urb_status);
+ err = -EINVAL;
+ }
+ devinfo->waitdone = false;
+ return err;
+}
+
+static void
+brcmf_usb_sync_complete(struct urb *urb)
+{
+ struct brcmf_usbdev_info *devinfo =
+ (struct brcmf_usbdev_info *)urb->context;
+
+ devinfo->waitdone = true;
+ wake_up_interruptible(&devinfo->wait);
+ devinfo->sync_urb_status = urb->status;
+}
+
+static bool brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd,
+ void *buffer, int buflen)
+{
+ int ret = 0;
+ char *tmpbuf;
+ u16 size;
+
+ if ((!devinfo) || (devinfo->ctl_urb == NULL))
+ return false;
+
+ tmpbuf = kmalloc(buflen, GFP_ATOMIC);
+ if (!tmpbuf)
+ return false;
+
+ size = buflen;
+ devinfo->ctl_urb->transfer_buffer_length = size;
+
+ devinfo->ctl_read.wLength = cpu_to_le16p(&size);
+ devinfo->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_VENDOR |
+ USB_RECIP_INTERFACE;
+ devinfo->ctl_read.bRequest = cmd;
+
+ usb_fill_control_urb(devinfo->ctl_urb,
+ devinfo->usbdev,
+ usb_rcvctrlpipe(devinfo->usbdev, 0),
+ (unsigned char *) &devinfo->ctl_read,
+ (void *) tmpbuf, size,
+ (usb_complete_t)brcmf_usb_sync_complete, devinfo);
+
+ ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC);
+ if (ret < 0) {
+ brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret);
+ kfree(tmpbuf);
+ return false;
+ }
+
+ ret = brcmf_usb_sync_wait(devinfo, BRCMF_USB_SYNC_TIMEOUT);
+ memcpy(buffer, tmpbuf, buflen);
+ kfree(tmpbuf);
+
+ return (ret == 0);
+}
+
+static bool
+brcmf_usb_dlneeded(struct brcmf_usbdev_info *devinfo)
+{
+ struct bootrom_id_le id;
+ u32 chipid, chiprev;
+
+ brcmf_dbg(TRACE, "enter\n");
+
+ if (devinfo == NULL)
+ return false;
+
+ /* Check if firmware downloaded already by querying runtime ID */
+ id.chip = cpu_to_le32(0xDEAD);
+ brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id,
+ sizeof(struct bootrom_id_le));
+
+ chipid = le32_to_cpu(id.chip);
+ chiprev = le32_to_cpu(id.chiprev);
+
+ if ((chipid & 0x4300) == 0x4300)
+ brcmf_dbg(INFO, "chip %x rev 0x%x\n", chipid, chiprev);
+ else
+ brcmf_dbg(INFO, "chip %d rev 0x%x\n", chipid, chiprev);
+ if (chipid == BRCMF_POSTBOOT_ID) {
+ brcmf_dbg(INFO, "firmware already downloaded\n");
+ brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id,
+ sizeof(struct bootrom_id_le));
+ return false;
+ } else {
+ devinfo->bus_pub.attrib.devid = chipid;
+ devinfo->bus_pub.attrib.chiprev = chiprev;
+ }
+ return true;
+}
+
+static int
+brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo)
+{
+ struct bootrom_id_le id;
+ u16 wait = 0, wait_time;
+
+ brcmf_dbg(TRACE, "enter\n");
+
+ if (devinfo == NULL)
+ return -EINVAL;
+
+ /* Give dongle chance to boot */
+ wait_time = BRCMF_USB_DLIMAGE_SPINWAIT;
+ while (wait < BRCMF_USB_DLIMAGE_LIMIT) {
+ mdelay(wait_time);
+ wait += wait_time;
+ id.chip = cpu_to_le32(0xDEAD); /* Get the ID */
+ brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id,
+ sizeof(struct bootrom_id_le));
+ if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID))
+ break;
+ }
+
+ if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID)) {
+ brcmf_dbg(INFO, "download done %d ms postboot chip 0x%x/rev 0x%x\n",
+ wait, le32_to_cpu(id.chip), le32_to_cpu(id.chiprev));
+
+ brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id,
+ sizeof(struct bootrom_id_le));
+
+ /* XXX this wait may not be necessary */
+ mdelay(BRCMF_USB_RESETCFG_SPINWAIT);
+ return 0;
+ } else {
+ brcmf_dbg(ERROR, "Cannot talk to Dongle. Firmware is not UP, %d ms\n",
+ wait);
+ return -EINVAL;
+ }
+}
+
+
+static int
+brcmf_usb_dl_send_bulk(struct brcmf_usbdev_info *devinfo, void *buffer, int len)
+{
+ int ret;
+
+ if ((devinfo == NULL) || (devinfo->bulk_urb == NULL))
+ return -EINVAL;
+
+ /* Prepare the URB */
+ usb_fill_bulk_urb(devinfo->bulk_urb, devinfo->usbdev,
+ devinfo->tx_pipe, buffer, len,
+ (usb_complete_t)brcmf_usb_sync_complete, devinfo);
+
+ devinfo->bulk_urb->transfer_flags |= URB_ZERO_PACKET;
+
+ ret = usb_submit_urb(devinfo->bulk_urb, GFP_ATOMIC);
+ if (ret) {
+ brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret);
+ return ret;
+ }
+ ret = brcmf_usb_sync_wait(devinfo, BRCMF_USB_SYNC_TIMEOUT);
+ return ret;
+}
+
+static int
+brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)
+{
+ unsigned int sendlen, sent, dllen;
+ char *bulkchunk = NULL, *dlpos;
+ struct rdl_state_le state;
+ u32 rdlstate, rdlbytes;
+ int err = 0;
+ brcmf_dbg(TRACE, "fw %p, len %d\n", fw, fwlen);
+
+ bulkchunk = kmalloc(RDL_CHUNK, GFP_ATOMIC);
+ if (bulkchunk == NULL) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ /* 1) Prepare USB boot loader for runtime image */
+ brcmf_usb_dl_cmd(devinfo, DL_START, &state,
+ sizeof(struct rdl_state_le));
+
+ rdlstate = le32_to_cpu(state.state);
+ rdlbytes = le32_to_cpu(state.bytes);
+
+ /* 2) Check we are in the Waiting state */
+ if (rdlstate != DL_WAITING) {
+ brcmf_dbg(ERROR, "Failed to DL_START\n");
+ err = -EINVAL;
+ goto fail;
+ }
+ sent = 0;
+ dlpos = fw;
+ dllen = fwlen;
+
+ /* Get chip id and rev */
+ while (rdlbytes != dllen) {
+ /* Wait until the usb device reports it received all
+ * the bytes we sent */
+ if ((rdlbytes == sent) && (rdlbytes != dllen)) {
+ if ((dllen-sent) < RDL_CHUNK)
+ sendlen = dllen-sent;
+ else
+ sendlen = RDL_CHUNK;
+
+ /* simply avoid having to send a ZLP by ensuring we
+ * never have an even
+ * multiple of 64
+ */
+ if (!(sendlen % 64))
+ sendlen -= 4;
+
+ /* send data */
+ memcpy(bulkchunk, dlpos, sendlen);
+ if (brcmf_usb_dl_send_bulk(devinfo, bulkchunk,
+ sendlen)) {
+ brcmf_dbg(ERROR, "send_bulk failed\n");
+ err = -EINVAL;
+ goto fail;
+ }
+
+ dlpos += sendlen;
+ sent += sendlen;
+ }
+ if (!brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state,
+ sizeof(struct rdl_state_le))) {
+ brcmf_dbg(ERROR, "DL_GETSTATE Failed xxxx\n");
+ err = -EINVAL;
+ goto fail;
+ }
+
+ rdlstate = le32_to_cpu(state.state);
+ rdlbytes = le32_to_cpu(state.bytes);
+
+ /* restart if an error is reported */
+ if (rdlstate == DL_BAD_HDR || rdlstate == DL_BAD_CRC) {
+ brcmf_dbg(ERROR, "Bad Hdr or Bad CRC state %d\n",
+ rdlstate);
+ err = -EINVAL;
+ goto fail;
+ }
+ }
+
+fail:
+ kfree(bulkchunk);
+ brcmf_dbg(TRACE, "err=%d\n", err);
+ return err;
+}
+
+static int brcmf_usb_dlstart(struct brcmf_usbdev_info *devinfo, u8 *fw, int len)
+{
+ int err;
+
+ brcmf_dbg(TRACE, "enter\n");
+
+ if (devinfo == NULL)
+ return -EINVAL;
+
+ if (devinfo->bus_pub.attrib.devid == 0xDEAD)
+ return -EINVAL;
+
+ err = brcmf_usb_dl_writeimage(devinfo, fw, len);
+ if (err == 0)
+ devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_DONE;
+ else
+ devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_PENDING;
+ brcmf_dbg(TRACE, "exit: err=%d\n", err);
+
+ return err;
+}
+
+static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo)
+{
+ struct rdl_state_le state;
+
+ brcmf_dbg(TRACE, "enter\n");
+ if (!devinfo)
+ return -EINVAL;
+
+ if (devinfo->bus_pub.attrib.devid == 0xDEAD)
+ return -EINVAL;
+
+ /* Check we are runnable */
+ brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state,
+ sizeof(struct rdl_state_le));
+
+ /* Start the image */
+ if (state.state == cpu_to_le32(DL_RUNNABLE)) {
+ if (!brcmf_usb_dl_cmd(devinfo, DL_GO, &state,
+ sizeof(struct rdl_state_le)))
+ return -ENODEV;
+ if (brcmf_usb_resetcfg(devinfo))
+ return -ENODEV;
+ /* The Dongle may go for re-enumeration. */
+ } else {
+ brcmf_dbg(ERROR, "Dongle not runnable\n");
+ return -EINVAL;
+ }
+ brcmf_dbg(TRACE, "exit\n");
+ return 0;
+}
+
+static bool brcmf_usb_chip_support(int chipid, int chiprev)
+{
+ switch(chipid) {
+ case 43235:
+ case 43236:
+ case 43238:
+ return (chiprev == 3);
+ default:
+ break;
+ }
+ return false;
+}
+
+static int
+brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo)
+{
+ struct brcmf_usb_attrib *attr;
+ int err;
+
+ brcmf_dbg(TRACE, "enter\n");
+ if (devinfo == NULL)
+ return -ENODEV;
+
+ attr = &devinfo->bus_pub.attrib;
+
+ if (!brcmf_usb_chip_support(attr->devid, attr->chiprev)) {
+ brcmf_dbg(ERROR, "unsupported chip %d rev %d\n",
+ attr->devid, attr->chiprev);
+ return -EINVAL;
+ }
+
+ if (!devinfo->image) {
+ brcmf_dbg(ERROR, "No firmware!\n");
+ return -ENOENT;
+ }
+
+ err = brcmf_usb_dlstart(devinfo,
+ devinfo->image, devinfo->image_len);
+ if (err == 0)
+ err = brcmf_usb_dlrun(devinfo);
+ return err;
+}
+
+
+static void brcmf_usb_detach(const struct brcmf_usbdev *bus_pub)
+{
+ struct brcmf_usbdev_info *devinfo =
+ (struct brcmf_usbdev_info *)bus_pub;
+
+ brcmf_dbg(TRACE, "devinfo %p\n", devinfo);
+
+ /* store the image globally */
+ g_image.data = devinfo->image;
+ g_image.len = devinfo->image_len;
+
+ /* free the URBS */
+ brcmf_usb_free_q(&devinfo->rx_freeq, false);
+ brcmf_usb_free_q(&devinfo->tx_freeq, false);
+
+ usb_free_urb(devinfo->intr_urb);
+ usb_free_urb(devinfo->ctl_urb);
+ usb_free_urb(devinfo->bulk_urb);
+
+ kfree(devinfo->tx_reqs);
+ kfree(devinfo->rx_reqs);
+ kfree(devinfo);
+}
+
+#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)
+{
+ struct trx_header_le *trx;
+ int actual_len = -1;
+
+ /* Extract trx header */
+ trx = (struct trx_header_le *) headers;
+ if (trx->magic != cpu_to_le32(TRX_MAGIC))
+ return -1;
+
+ headers += sizeof(struct trx_header_le);
+
+ if (le32_to_cpu(trx->flag_version) & TRX_UNCOMP_IMAGE) {
+ actual_len = le32_to_cpu(trx->offsets[TRX_OFFSETS_DLFWLEN_IDX]);
+ return actual_len + sizeof(struct trx_header_le);
+ }
+ return -1;
+}
+
+static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)
+{
+ s8 *fwname;
+ const struct firmware *fw;
+ int err;
+
+ devinfo->image = g_image.data;
+ devinfo->image_len = g_image.len;
+
+ /*
+ * if we have an image we can leave here.
+ */
+ if (devinfo->image)
+ return 0;
+
+ fwname = BRCMF_USB_FW_NAME;
+
+ err = request_firmware(&fw, fwname, devinfo->dev);
+ if (!fw) {
+ brcmf_dbg(ERROR, "fail to request firmware %s\n", fwname);
+ return err;
+ }
+ if (check_file(fw->data) < 0) {
+ brcmf_dbg(ERROR, "invalid firmware %s\n", fwname);
+ return -EINVAL;
+ }
+
+ devinfo->image = kmalloc(fw->size, GFP_ATOMIC); /* plus nvram */
+ if (!devinfo->image)
+ return -ENOMEM;
+
+ memcpy(devinfo->image, fw->data, fw->size);
+ devinfo->image_len = fw->size;
+
+ release_firmware(fw);
+ return 0;
+}
+
+
+static
+struct brcmf_usbdev *brcmf_usb_attach(int nrxq, int ntxq, struct device *dev)
+{
+ struct brcmf_usbdev_info *devinfo;
+
+ devinfo = kzalloc(sizeof(struct brcmf_usbdev_info), GFP_ATOMIC);
+ if (devinfo == NULL)
+ return NULL;
+
+ devinfo->bus_pub.nrxq = nrxq;
+ devinfo->rx_low_watermark = nrxq / 2;
+ devinfo->bus_pub.devinfo = devinfo;
+ devinfo->bus_pub.ntxq = ntxq;
+
+ /* flow control when too many tx urbs posted */
+ devinfo->tx_low_watermark = ntxq / 4;
+ devinfo->tx_high_watermark = devinfo->tx_low_watermark * 3;
+ devinfo->dev = dev;
+ devinfo->usbdev = usbdev_probe_info.usb;
+ devinfo->tx_pipe = usbdev_probe_info.tx_pipe;
+ devinfo->rx_pipe = usbdev_probe_info.rx_pipe;
+ devinfo->rx_pipe2 = usbdev_probe_info.rx_pipe2;
+ devinfo->intr_pipe = usbdev_probe_info.intr_pipe;
+
+ devinfo->interval = usbdev_probe_info.interval;
+ devinfo->intr_size = usbdev_probe_info.intr_size;
+
+ memcpy(&devinfo->probe_info, &usbdev_probe_info,
+ sizeof(struct brcmf_usb_probe_info));
+ devinfo->bus_pub.bus_mtu = BRCMF_USB_MAX_PKT_SIZE;
+
+ /* Initialize other structure content */
+ init_waitqueue_head(&devinfo->ioctl_resp_wait);
+
+ /* Initialize the spinlocks */
+ spin_lock_init(&devinfo->qlock);
+
+ INIT_LIST_HEAD(&devinfo->rx_freeq);
+ INIT_LIST_HEAD(&devinfo->rx_postq);
+
+ INIT_LIST_HEAD(&devinfo->tx_freeq);
+ INIT_LIST_HEAD(&devinfo->tx_postq);
+
+ devinfo->rx_reqs = brcmf_usbdev_qinit(&devinfo->rx_freeq, nrxq);
+ if (!devinfo->rx_reqs)
+ goto error;
+
+ devinfo->tx_reqs = brcmf_usbdev_qinit(&devinfo->tx_freeq, ntxq);
+ if (!devinfo->tx_reqs)
+ goto error;
+
+ devinfo->intr_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!devinfo->intr_urb) {
+ brcmf_dbg(ERROR, "usb_alloc_urb (intr) failed\n");
+ goto error;
+ }
+ devinfo->ctl_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!devinfo->ctl_urb) {
+ brcmf_dbg(ERROR, "usb_alloc_urb (ctl) failed\n");
+ goto error;
+ }
+ devinfo->rxctl_deferrespok = 0;
+
+ devinfo->bulk_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!devinfo->bulk_urb) {
+ brcmf_dbg(ERROR, "usb_alloc_urb (bulk) failed\n");
+ goto error;
+ }
+
+ init_waitqueue_head(&devinfo->wait);
+ if (!brcmf_usb_dlneeded(devinfo))
+ return &devinfo->bus_pub;
+
+ brcmf_dbg(TRACE, "start fw downloading\n");
+ if (brcmf_usb_get_fw(devinfo))
+ goto error;
+
+ if (brcmf_usb_fw_download(devinfo))
+ goto error;
+
+ return &devinfo->bus_pub;
+
+error:
+ brcmf_dbg(ERROR, "failed!\n");
+ brcmf_usb_detach(&devinfo->bus_pub);
+ return NULL;
+}
+
+static int brcmf_usb_probe_cb(struct device *dev, const char *desc,
+ u32 bustype, u32 hdrlen)
+{
+ struct brcmf_bus *bus = NULL;
+ struct brcmf_usbdev *bus_pub = NULL;
+ int ret;
+
+
+ bus_pub = brcmf_usb_attach(BRCMF_USB_NRXQ, BRCMF_USB_NTXQ, dev);
+ if (!bus_pub) {
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC);
+ if (!bus) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ bus_pub->bus = bus;
+ bus->brcmf_bus_txdata = brcmf_usb_tx;
+ bus->brcmf_bus_init = brcmf_usb_up;
+ bus->brcmf_bus_stop = brcmf_usb_down;
+ bus->brcmf_bus_txctl = brcmf_usb_tx_ctlpkt;
+ bus->brcmf_bus_rxctl = brcmf_usb_rx_ctlpkt;
+ bus->type = bustype;
+ bus->bus_priv.usb = bus_pub;
+ dev_set_drvdata(dev, bus);
+
+ /* Attach to the common driver interface */
+ ret = brcmf_attach(hdrlen, dev);
+ if (ret) {
+ brcmf_dbg(ERROR, "dhd_attach failed\n");
+ goto fail;
+ }
+
+ ret = brcmf_bus_start(dev);
+ if (ret == -ENOLINK) {
+ brcmf_dbg(ERROR, "dongle is not responding\n");
+ brcmf_detach(dev);
+ goto fail;
+ }
+
+ /* add interface and open for business */
+ ret = brcmf_add_if(dev, 0, "wlan%d", NULL);
+ if (ret) {
+ brcmf_dbg(ERROR, "Add primary net device interface failed!!\n");
+ brcmf_detach(dev);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ /* Release resources in reverse order */
+ if (bus_pub)
+ brcmf_usb_detach(bus_pub);
+ kfree(bus);
+ return ret;
+}
+
+static void
+brcmf_usb_disconnect_cb(struct brcmf_usbdev *bus_pub)
+{
+ if (!bus_pub)
+ return;
+ brcmf_dbg(TRACE, "enter: bus_pub %p\n", bus_pub);
+
+ brcmf_detach(bus_pub->devinfo->dev);
+ kfree(bus_pub->bus);
+ brcmf_usb_detach(bus_pub);
+
+}
+
+static int
+brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ int ep;
+ struct usb_endpoint_descriptor *endpoint;
+ int ret = 0;
+ struct usb_device *usb = interface_to_usbdev(intf);
+ int num_of_eps;
+ u8 endpoint_num;
+
+ brcmf_dbg(TRACE, "enter\n");
+
+ usbdev_probe_info.usb = usb;
+ usbdev_probe_info.intf = intf;
+
+ if (id != NULL) {
+ usbdev_probe_info.vid = id->idVendor;
+ usbdev_probe_info.pid = id->idProduct;
+ }
+
+ usb_set_intfdata(intf, &usbdev_probe_info);
+
+ /* Check that the device supports only one configuration */
+ if (usb->descriptor.bNumConfigurations != 1) {
+ ret = -1;
+ goto fail;
+ }
+
+ if (usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) {
+ ret = -1;
+ goto fail;
+ }
+
+ /*
+ * Only the BDC interface configuration is supported:
+ * Device class: USB_CLASS_VENDOR_SPEC
+ * if0 class: USB_CLASS_VENDOR_SPEC
+ * if0/ep0: control
+ * if0/ep1: bulk in
+ * if0/ep2: bulk out (ok if swapped with bulk in)
+ */
+ if (CONFIGDESC(usb)->bNumInterfaces != 1) {
+ ret = -1;
+ goto fail;
+ }
+
+ /* Check interface */
+ if (IFDESC(usb, CONTROL_IF).bInterfaceClass != USB_CLASS_VENDOR_SPEC ||
+ IFDESC(usb, CONTROL_IF).bInterfaceSubClass != 2 ||
+ IFDESC(usb, CONTROL_IF).bInterfaceProtocol != 0xff) {
+ brcmf_dbg(ERROR, "invalid control interface: class %d, subclass %d, proto %d\n",
+ IFDESC(usb, CONTROL_IF).bInterfaceClass,
+ IFDESC(usb, CONTROL_IF).bInterfaceSubClass,
+ IFDESC(usb, CONTROL_IF).bInterfaceProtocol);
+ ret = -1;
+ goto fail;
+ }
+
+ /* Check control endpoint */
+ endpoint = &IFEPDESC(usb, CONTROL_IF, 0);
+ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ != USB_ENDPOINT_XFER_INT) {
+ brcmf_dbg(ERROR, "invalid control endpoint %d\n",
+ endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+ ret = -1;
+ goto fail;
+ }
+
+ endpoint_num = endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ usbdev_probe_info.intr_pipe = usb_rcvintpipe(usb, endpoint_num);
+
+ usbdev_probe_info.rx_pipe = 0;
+ usbdev_probe_info.rx_pipe2 = 0;
+ usbdev_probe_info.tx_pipe = 0;
+ num_of_eps = IFDESC(usb, BULK_IF).bNumEndpoints - 1;
+
+ /* Check data endpoints and get pipes */
+ for (ep = 1; ep <= num_of_eps; ep++) {
+ endpoint = &IFEPDESC(usb, BULK_IF, ep);
+ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+ USB_ENDPOINT_XFER_BULK) {
+ brcmf_dbg(ERROR, "invalid data endpoint %d\n", ep);
+ ret = -1;
+ goto fail;
+ }
+
+ endpoint_num = endpoint->bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ == USB_DIR_IN) {
+ if (!usbdev_probe_info.rx_pipe) {
+ usbdev_probe_info.rx_pipe =
+ usb_rcvbulkpipe(usb, endpoint_num);
+ } else {
+ usbdev_probe_info.rx_pipe2 =
+ usb_rcvbulkpipe(usb, endpoint_num);
+ }
+ } else {
+ usbdev_probe_info.tx_pipe =
+ usb_sndbulkpipe(usb, endpoint_num);
+ }
+ }
+
+ /* Allocate interrupt URB and data buffer */
+ /* RNDIS says 8-byte intr, our old drivers used 4-byte */
+ if (IFEPDESC(usb, CONTROL_IF, 0).wMaxPacketSize == cpu_to_le16(16))
+ usbdev_probe_info.intr_size = 8;
+ else
+ usbdev_probe_info.intr_size = 4;
+
+ usbdev_probe_info.interval = IFEPDESC(usb, CONTROL_IF, 0).bInterval;
+
+ usbdev_probe_info.device_speed = usb->speed;
+ if (usb->speed == USB_SPEED_HIGH)
+ brcmf_dbg(INFO, "Broadcom high speed USB wireless device detected\n");
+ else
+ brcmf_dbg(INFO, "Broadcom full speed USB wireless device detected\n");
+
+ ret = brcmf_usb_probe_cb(&usb->dev, "", USB_BUS, 0);
+ if (ret)
+ goto fail;
+
+ /* Success */
+ return 0;
+
+fail:
+ brcmf_dbg(ERROR, "failed with errno %d\n", ret);
+ usb_set_intfdata(intf, NULL);
+ return ret;
+
+}
+
+static void
+brcmf_usb_disconnect(struct usb_interface *intf)
+{
+ struct usb_device *usb = interface_to_usbdev(intf);
+
+ brcmf_dbg(TRACE, "enter\n");
+ brcmf_usb_disconnect_cb(brcmf_usb_get_buspub(&usb->dev));
+ usb_set_intfdata(intf, NULL);
+}
+
+/*
+ * only need to signal the bus being down and update the suspend state.
+ */
+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);
+
+ brcmf_dbg(TRACE, "enter\n");
+ devinfo->bus_pub.state = BCMFMAC_USB_STATE_DOWN;
+ devinfo->suspend_state = USBOS_SUSPEND_STATE_SUSPENDED;
+ return 0;
+}
+
+/*
+ * mark suspend state active and crank up the bus.
+ */
+static int brcmf_usb_resume(struct usb_interface *intf)
+{
+ struct usb_device *usb = interface_to_usbdev(intf);
+ struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
+
+ brcmf_dbg(TRACE, "enter\n");
+ devinfo->suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE;
+ brcmf_bus_start(&usb->dev);
+ return 0;
+}
+
+#define BRCMF_USB_VENDOR_ID_BROADCOM 0x0a5c
+#define BRCMF_USB_DEVICE_ID_43236 0xbd17
+#define BRCMF_USB_DEVICE_ID_BCMFW 0x0bdc
+
+static struct usb_device_id brcmf_usb_devid_table[] = {
+ { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43236) },
+ /* special entry for device with firmware loaded and running */
+ { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_BCMFW) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, brcmf_usb_devid_table);
+MODULE_FIRMWARE(BRCMF_USB_FW_NAME);
+
+/* TODO: suspend and resume entries */
+static struct usb_driver brcmf_usbdrvr = {
+ .name = KBUILD_MODNAME,
+ .probe = brcmf_usb_probe,
+ .disconnect = brcmf_usb_disconnect,
+ .id_table = brcmf_usb_devid_table,
+ .suspend = brcmf_usb_suspend,
+ .resume = brcmf_usb_resume,
+ .supports_autosuspend = 1
+};
+
+void brcmf_usb_exit(void)
+{
+ usb_deregister(&brcmf_usbdrvr);
+ kfree(g_image.data);
+ g_image.data = NULL;
+ g_image.len = 0;
+}
+
+int brcmf_usb_init(void)
+{
+ return usb_register(&brcmf_usbdrvr);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.h b/drivers/net/wireless/brcm80211/brcmfmac/usb.h
new file mode 100644
index 00000000000..b31da7b83ff
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.h
@@ -0,0 +1,84 @@
+/*
+ * 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 BRCMFMAC_USB_H
+#define BRCMFMAC_USB_H
+
+enum brcmf_usb_state {
+ BCMFMAC_USB_STATE_DL_PENDING,
+ BCMFMAC_USB_STATE_DL_DONE,
+ BCMFMAC_USB_STATE_UP,
+ BCMFMAC_USB_STATE_DOWN,
+ BCMFMAC_USB_STATE_PNP_FWDL,
+ BCMFMAC_USB_STATE_DISCONNECT,
+ BCMFMAC_USB_STATE_SLEEP
+};
+
+enum brcmf_usb_pnp_state {
+ BCMFMAC_USB_PNP_DISCONNECT,
+ BCMFMAC_USB_PNP_SLEEP,
+ BCMFMAC_USB_PNP_RESUME,
+};
+
+struct brcmf_stats {
+ u32 tx_errors;
+ u32 tx_packets;
+ u32 tx_multicast;
+ u32 tx_ctlpkts;
+ u32 tx_ctlerrs;
+ u32 tx_dropped;
+ u32 tx_flushed;
+ u32 rx_errors;
+ u32 rx_packets;
+ u32 rx_multicast;
+ u32 rx_ctlpkts;
+ u32 rx_ctlerrs;
+ u32 rx_dropped;
+ u32 rx_flushed;
+
+};
+
+struct brcmf_usb_attrib {
+ int bustype;
+ int vid;
+ int pid;
+ int devid;
+ int chiprev; /* chip revsion number */
+ int mtu;
+ int nchan; /* Data Channels */
+ int has_2nd_bulk_in_ep;
+};
+
+struct brcmf_usbdev_info;
+
+struct brcmf_usbdev {
+ struct brcmf_bus *bus;
+ struct brcmf_usbdev_info *devinfo;
+ enum brcmf_usb_state state;
+ struct brcmf_stats stats;
+ int ntxq, nrxq, rxsize;
+ u32 bus_mtu;
+ struct brcmf_usb_attrib attrib;
+};
+
+/* IO Request Block (IRB) */
+struct brcmf_usbreq {
+ struct list_head list;
+ struct brcmf_usbdev_info *devinfo;
+ struct urb *urb;
+ struct sk_buff *skb;
+};
+
+#endif /* BRCMFMAC_USB_H */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h b/drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h
new file mode 100644
index 00000000000..0a35c51c3da
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h
@@ -0,0 +1,75 @@
+/*
+ * 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/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index 74c95a59795..15d7f00513b 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -1376,7 +1376,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
memset(&join_params, 0, sizeof(join_params));
join_params_size = sizeof(join_params.ssid_le);
- ssid.SSID_len = min_t(u32, sizeof(ssid.SSID), sme->ssid_len);
+ ssid.SSID_len = min_t(u32, sizeof(ssid.SSID), (u32)sme->ssid_len);
memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid.SSID_len);
memcpy(&ssid.SSID, sme->ssid, ssid.SSID_len);
join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len);
@@ -3297,7 +3297,9 @@ static struct brcmf_cfg80211_event_q *brcmf_deq_event(
}
/*
-** push event to tail of the queue
+* push event to tail of the queue
+*
+* remark: this function may not sleep as it is called in atomic context.
*/
static s32
@@ -3306,17 +3308,18 @@ brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 event,
{
struct brcmf_cfg80211_event_q *e;
s32 err = 0;
+ ulong flags;
- e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_KERNEL);
+ e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_ATOMIC);
if (!e)
return -ENOMEM;
e->etype = event;
memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg));
- spin_lock_irq(&cfg_priv->evt_q_lock);
+ spin_lock_irqsave(&cfg_priv->evt_q_lock, flags);
list_add_tail(&e->evt_q_list, &cfg_priv->evt_q_list);
- spin_unlock_irq(&cfg_priv->evt_q_lock);
+ spin_unlock_irqrestore(&cfg_priv->evt_q_lock, flags);
return err;
}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
index d89dcb14cb6..c1ce831b9bf 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
@@ -1051,17 +1051,13 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
}
/* either retransmit or send bar if ack not recd */
if (!ack_recd) {
- struct ieee80211_tx_rate *txrate =
- tx_info->status.rates;
- if (retry && (txrate[0].count < (int)retry_limit)) {
+ if (retry && (ini->txretry[index] < (int)retry_limit)) {
ini->txretry[index]++;
ini->tx_in_transit--;
/*
* Use high prededence for retransmit to
* give some punch
*/
- /* brcms_c_txq_enq(wlc, scb, p,
- * BRCMS_PRIO_TO_PREC(tid)); */
brcms_c_txq_enq(wlc, scb, p,
BRCMS_PRIO_TO_HI_PREC(tid));
} else {
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index c8427978d09..fec0f10773e 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -1136,8 +1136,8 @@ static int brcms_suspend(struct bcma_device *pdev)
hw = bcma_get_drvdata(pdev);
wl = hw->priv;
if (!wl) {
- wiphy_err(wl->wiphy,
- "brcms_suspend: bcma_get_drvdata failed\n");
+ pr_err("%s: %s: no driver private struct!\n", KBUILD_MODNAME,
+ __func__);
return -ENODEV;
}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index fb712cac915..86186fa8294 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -2901,7 +2901,6 @@ brcms_b_read_objmem(struct brcms_hardware *wlc_hw, uint offset, u32 sel)
objoff += 2;
return bcma_read16(core, objoff);
-;
}
static void
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
index ec7450d2fbd..9595ecd38c1 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
@@ -17824,8 +17824,6 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi)
if (pi->sh->sromrev < 4) {
idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g;
idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g;
- target_pwr_qtrdbm[0] = 13 * 4;
- target_pwr_qtrdbm[1] = 13 * 4;
a1[0] = -424;
a1[1] = -424;
b0[0] = 5612;
@@ -17839,10 +17837,6 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi)
case WL_CHAN_FREQ_RANGE_2G:
idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g;
idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g;
- target_pwr_qtrdbm[0] =
- pi->nphy_pwrctrl_info[0].max_pwr_2g;
- target_pwr_qtrdbm[1] =
- pi->nphy_pwrctrl_info[1].max_pwr_2g;
a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_a1;
a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_2g_a1;
b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_b0;
@@ -17853,10 +17847,6 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi)
case WL_CHAN_FREQ_RANGE_5GL:
idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g;
idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g;
- target_pwr_qtrdbm[0] =
- pi->nphy_pwrctrl_info[0].max_pwr_5gl;
- target_pwr_qtrdbm[1] =
- pi->nphy_pwrctrl_info[1].max_pwr_5gl;
a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_a1;
a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gl_a1;
b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_b0;
@@ -17867,10 +17857,6 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi)
case WL_CHAN_FREQ_RANGE_5GM:
idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g;
idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g;
- target_pwr_qtrdbm[0] =
- pi->nphy_pwrctrl_info[0].max_pwr_5gm;
- target_pwr_qtrdbm[1] =
- pi->nphy_pwrctrl_info[1].max_pwr_5gm;
a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_a1;
a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gm_a1;
b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_b0;
@@ -17881,10 +17867,6 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi)
case WL_CHAN_FREQ_RANGE_5GH:
idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g;
idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g;
- target_pwr_qtrdbm[0] =
- pi->nphy_pwrctrl_info[0].max_pwr_5gh;
- target_pwr_qtrdbm[1] =
- pi->nphy_pwrctrl_info[1].max_pwr_5gh;
a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_a1;
a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gh_a1;
b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_b0;
@@ -17895,8 +17877,6 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi)
default:
idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g;
idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g;
- target_pwr_qtrdbm[0] = 13 * 4;
- target_pwr_qtrdbm[1] = 13 * 4;
a1[0] = -424;
a1[1] = -424;
b0[0] = 5612;
@@ -17907,6 +17887,7 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi)
}
}
+ /* use the provided transmit power */
target_pwr_qtrdbm[0] = (s8) pi->tx_power_max;
target_pwr_qtrdbm[1] = (s8) pi->tx_power_max;
@@ -19989,12 +19970,11 @@ static void wlc_phy_radio_init_2057(struct brcms_phy *pi)
switch (pi->pubpi.radiorev) {
case 5:
- if (pi->pubpi.radiover == 0x0)
+ if (NREV_IS(pi->pubpi.phy_rev, 8))
regs_2057_ptr = regs_2057_rev5;
- else if (pi->pubpi.radiover == 0x1)
+ else if (NREV_IS(pi->pubpi.phy_rev, 9))
regs_2057_ptr = regs_2057_rev5v1;
- else
- break;
+ break;
case 7:
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/srom.c b/drivers/net/wireless/brcm80211/brcmsmac/srom.c
index 56374364303..b96f4b9d74b 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/srom.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/srom.c
@@ -621,7 +621,7 @@ static inline void cpu_to_le16_buf(u16 *buf, uint nwords)
/*
* convert binary srom data into linked list of srom variable items.
*/
-static void
+static int
_initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
{
struct brcms_srom_list_head *entry;
@@ -638,6 +638,9 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
/* first store the srom revision */
entry = kzalloc(sizeof(struct brcms_srom_list_head), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
entry->varid = BRCMS_SROM_REV;
entry->var_type = BRCMS_SROM_UNUMBER;
entry->uval = sromrev;
@@ -715,6 +718,8 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
entry = kzalloc(sizeof(struct brcms_srom_list_head) +
extra_space, GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
entry->varid = id;
entry->var_type = type;
if (flags & SRFL_ETHADDR) {
@@ -754,6 +759,8 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
entry =
kzalloc(sizeof(struct brcms_srom_list_head),
GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
entry->varid = srv->varid+p;
entry->var_type = BRCMS_SROM_UNUMBER;
entry->uval = val;
@@ -761,6 +768,7 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
}
pb += psz;
}
+ return 0;
}
/*
@@ -906,7 +914,9 @@ int srom_var_init(struct si_pub *sih)
INIT_LIST_HEAD(&sii->var_list);
/* parse SROM into name=value pairs. */
- _initvars_srom_pci(sromrev, srom, &sii->var_list);
+ err = _initvars_srom_pci(sromrev, srom, &sii->var_list);
+ if (err)
+ srom_free_vars(sih);
}
errout:
diff --git a/drivers/net/wireless/iwlegacy/3945-debug.c b/drivers/net/wireless/iwlegacy/3945-debug.c
index 5e1a19fd354..f767dd106b0 100644
--- a/drivers/net/wireless/iwlegacy/3945-debug.c
+++ b/drivers/net/wireless/iwlegacy/3945-debug.c
@@ -503,3 +503,9 @@ il3945_ucode_general_stats_read(struct file *file, char __user *user_buf,
kfree(buf);
return ret;
}
+
+const struct il_debugfs_ops il3945_debugfs_ops = {
+ .rx_stats_read = il3945_ucode_rx_stats_read,
+ .tx_stats_read = il3945_ucode_tx_stats_read,
+ .general_stats_read = il3945_ucode_general_stats_read,
+};
diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c
index aa8f5c0bd64..0ccc934a35b 100644
--- a/drivers/net/wireless/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/iwlegacy/3945-mac.c
@@ -573,7 +573,6 @@ il3945_tx_skb(struct il_priv *il, struct sk_buff *skb)
len = (u16) skb->len;
tx_cmd->len = cpu_to_le16(len);
- il_dbg_log_tx_data_frame(il, len, hdr);
il_update_stats(il, true, fc, len);
tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
@@ -616,7 +615,7 @@ il3945_tx_skb(struct il_priv *il, struct sk_buff *skb)
/* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */
- il->ops->lib->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0);
+ il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0);
/* Set up TFD's 2nd entry to point directly to remainder of skb,
* if any (802.11 null frames have no payload). */
@@ -625,8 +624,8 @@ il3945_tx_skb(struct il_priv *il, struct sk_buff *skb)
phys_addr =
pci_map_single(il->pci_dev, skb->data + hdr_len, len,
PCI_DMA_TODEVICE);
- il->ops->lib->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0,
- U32_PAD(len));
+ il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0,
+ U32_PAD(len));
}
/* Tell device the write idx *just past* this latest filled TFD */
@@ -810,16 +809,16 @@ il3945_hdl_card_state(struct il_priv *il, struct il_rx_buf *rxb)
_il_wr(il, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
if (flags & HW_CARD_DISABLED)
- set_bit(S_RF_KILL_HW, &il->status);
+ set_bit(S_RFKILL, &il->status);
else
- clear_bit(S_RF_KILL_HW, &il->status);
+ clear_bit(S_RFKILL, &il->status);
il_scan_cancel(il);
- if ((test_bit(S_RF_KILL_HW, &status) !=
- test_bit(S_RF_KILL_HW, &il->status)))
+ if ((test_bit(S_RFKILL, &status) !=
+ test_bit(S_RFKILL, &il->status)))
wiphy_rfkill_set_hw_state(il->hw->wiphy,
- test_bit(S_RF_KILL_HW, &il->status));
+ test_bit(S_RFKILL, &il->status));
else
wake_up(&il->wait_command_queue);
}
@@ -2167,7 +2166,7 @@ il3945_alive_start(struct il_priv *il)
D_INFO("RFKILL status: 0x%x\n", rfkill);
if (rfkill & 0x1) {
- clear_bit(S_RF_KILL_HW, &il->status);
+ clear_bit(S_RFKILL, &il->status);
/* if RFKILL is not on, then wait for thermal
* sensor in adapter to kick in */
while (il3945_hw_get_temperature(il) == 0) {
@@ -2179,7 +2178,7 @@ il3945_alive_start(struct il_priv *il)
D_INFO("Thermal calibration took %dus\n",
thermal_spin * 10);
} else
- set_bit(S_RF_KILL_HW, &il->status);
+ set_bit(S_RFKILL, &il->status);
/* After the ALIVE response, we can send commands to 3945 uCode */
set_bit(S_ALIVE, &il->status);
@@ -2273,12 +2272,8 @@ __il3945_down(struct il_priv *il)
* clear all bits but the RF Kill bits and return */
if (!il_is_init(il)) {
il->status =
- test_bit(S_RF_KILL_HW,
- &il->
- status) << S_RF_KILL_HW |
- test_bit(S_GEO_CONFIGURED,
- &il->
- status) << S_GEO_CONFIGURED |
+ test_bit(S_RFKILL, &il->status) << S_RFKILL |
+ test_bit(S_GEO_CONFIGURED, &il->status) << S_GEO_CONFIGURED |
test_bit(S_EXIT_PENDING, &il->status) << S_EXIT_PENDING;
goto exit;
}
@@ -2286,25 +2281,30 @@ __il3945_down(struct il_priv *il)
/* ...otherwise clear out all the status bits but the RF Kill
* bit and continue taking the NIC down. */
il->status &=
- test_bit(S_RF_KILL_HW,
- &il->status) << S_RF_KILL_HW | test_bit(S_GEO_CONFIGURED,
- &il->
- status) <<
- S_GEO_CONFIGURED | test_bit(S_FW_ERROR,
- &il->
- status) << S_FW_ERROR |
+ test_bit(S_RFKILL, &il->status) << S_RFKILL |
+ test_bit(S_GEO_CONFIGURED, &il->status) << S_GEO_CONFIGURED |
+ test_bit(S_FW_ERROR, &il->status) << S_FW_ERROR |
test_bit(S_EXIT_PENDING, &il->status) << S_EXIT_PENDING;
+ /*
+ * We disabled and synchronized interrupt, and priv->mutex is taken, so
+ * here is the only thread which will program device registers, but
+ * still have lockdep assertions, so we are taking reg_lock.
+ */
+ spin_lock_irq(&il->reg_lock);
+ /* FIXME: il_grab_nic_access if rfkill is off ? */
+
il3945_hw_txq_ctx_stop(il);
il3945_hw_rxq_stop(il);
-
/* Power-down device's busmaster DMA clocks */
- il_wr_prph(il, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
+ _il_wr_prph(il, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
udelay(5);
-
/* Stop the device, and put it in low power state */
- il_apm_stop(il);
+ _il_apm_stop(il);
+
+ spin_unlock_irq(&il->reg_lock);
+ il3945_hw_txq_ctx_free(il);
exit:
memset(&il->card_alive, 0, sizeof(struct il_alive_resp));
@@ -2371,9 +2371,9 @@ __il3945_up(struct il_priv *il)
/* If platform's RF_KILL switch is NOT set to KILL */
if (_il_rd(il, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
- clear_bit(S_RF_KILL_HW, &il->status);
+ clear_bit(S_RFKILL, &il->status);
else {
- set_bit(S_RF_KILL_HW, &il->status);
+ set_bit(S_RFKILL, &il->status);
IL_WARN("Radio disabled by HW RF Kill switch\n");
return -ENODEV;
}
@@ -2405,7 +2405,7 @@ __il3945_up(struct il_priv *il)
il->ucode_data.len);
/* We return success when we resume from suspend and rf_kill is on. */
- if (test_bit(S_RF_KILL_HW, &il->status))
+ if (test_bit(S_RFKILL, &il->status))
return 0;
for (i = 0; i < MAX_HW_RESTARTS; i++) {
@@ -2413,7 +2413,7 @@ __il3945_up(struct il_priv *il)
/* load bootstrap state machine,
* load bootstrap program into processor's memory,
* prepare to load the "initialize" uCode */
- rc = il->ops->lib->load_ucode(il);
+ rc = il->ops->load_ucode(il);
if (rc) {
IL_ERR("Unable to set up bootstrap uCode: %d\n", rc);
@@ -2485,15 +2485,15 @@ il3945_rfkill_poll(struct work_struct *data)
{
struct il_priv *il =
container_of(data, struct il_priv, _3945.rfkill_poll.work);
- bool old_rfkill = test_bit(S_RF_KILL_HW, &il->status);
+ bool old_rfkill = test_bit(S_RFKILL, &il->status);
bool new_rfkill =
!(_il_rd(il, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
if (new_rfkill != old_rfkill) {
if (new_rfkill)
- set_bit(S_RF_KILL_HW, &il->status);
+ set_bit(S_RFKILL, &il->status);
else
- clear_bit(S_RF_KILL_HW, &il->status);
+ clear_bit(S_RFKILL, &il->status);
wiphy_rfkill_set_hw_state(il->hw->wiphy, new_rfkill);
@@ -2782,10 +2782,9 @@ il3945_mac_start(struct ieee80211_hw *hw)
struct il_priv *il = hw->priv;
int ret;
- D_MAC80211("enter\n");
-
/* we should be verifying the device is ready to be opened */
mutex_lock(&il->mutex);
+ D_MAC80211("enter\n");
/* fetch ucode file from disk, alloc and copy to bus-master buffers ...
* ucode filename and max sizes are card-specific. */
@@ -2941,15 +2940,19 @@ il3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
* hardware will then not attempt to decrypt the frames.
*/
if (vif->type == NL80211_IFTYPE_ADHOC &&
- !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+ !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+ D_MAC80211("leave - IBSS RSN\n");
return -EOPNOTSUPP;
+ }
static_key = !il_is_associated(il);
if (!static_key) {
sta_id = il_sta_id_or_broadcast(il, sta);
- if (sta_id == IL_INVALID_STATION)
+ if (sta_id == IL_INVALID_STATION) {
+ D_MAC80211("leave - station not found\n");
return -EINVAL;
+ }
}
mutex_lock(&il->mutex);
@@ -2974,8 +2977,8 @@ il3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ret = -EINVAL;
}
+ D_MAC80211("leave ret %d\n", ret);
mutex_unlock(&il->mutex);
- D_MAC80211("leave\n");
return ret;
}
@@ -2990,9 +2993,8 @@ il3945_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
bool is_ap = vif->type == NL80211_IFTYPE_STATION;
u8 sta_id;
- D_INFO("received request to add station %pM\n", sta->addr);
mutex_lock(&il->mutex);
- D_INFO("proceeding to add station %pM\n", sta->addr);
+ D_INFO("station %pM\n", sta->addr);
sta_priv->common.sta_id = IL_INVALID_STATION;
ret = il_add_station_common(il, sta->addr, is_ap, sta, &sta_id);
@@ -3098,11 +3100,9 @@ il3945_store_debug_level(struct device *d, struct device_attribute *attr,
ret = strict_strtoul(buf, 0, &val);
if (ret)
IL_INFO("%s is not in hex or decimal form.\n", buf);
- else {
+ else
il->debug_level = val;
- if (il_alloc_traffic_mem(il))
- IL_ERR("Not enough memory to generate traffic log\n");
- }
+
return strnlen(buf, count);
}
@@ -3619,12 +3619,12 @@ il3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
D_INFO("*** LOAD DRIVER ***\n");
il->cfg = cfg;
il->ops = &il3945_ops;
+#ifdef CONFIG_IWLEGACY_DEBUGFS
+ il->debugfs_ops = &il3945_debugfs_ops;
+#endif
il->pci_dev = pdev;
il->inta_mask = CSR_INI_SET_MASK;
- if (il_alloc_traffic_mem(il))
- IL_ERR("Not enough memory to generate traffic log\n");
-
/***************************
* 2. Initializing PCI bus
* *************************/
@@ -3655,7 +3655,7 @@ il3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/***********************
* 3. Read REV Register
* ********************/
- il->hw_base = pci_iomap(pdev, 0, 0);
+ il->hw_base = pci_ioremap_bar(pdev, 0);
if (!il->hw_base) {
err = -ENODEV;
goto out_pci_release_regions;
@@ -3669,7 +3669,7 @@ il3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
* PCI Tx retries from interfering with C3 CPU state */
pci_write_config_byte(pdev, 0x41, 0x00);
- /* these spin locks will be used in apm_ops.init and EEPROM access
+ /* these spin locks will be used in apm_init and EEPROM access
* we should init now
*/
spin_lock_init(&il->reg_lock);
@@ -3780,14 +3780,13 @@ out_unset_hw_params:
out_eeprom_free:
il_eeprom_free(il);
out_iounmap:
- pci_iounmap(pdev, il->hw_base);
+ iounmap(il->hw_base);
out_pci_release_regions:
pci_release_regions(pdev);
out_pci_disable_device:
pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
out_ieee80211_free_hw:
- il_free_traffic_mem(il);
ieee80211_free_hw(il->hw);
out:
return err;
@@ -3855,12 +3854,11 @@ il3945_pci_remove(struct pci_dev *pdev)
* until now... */
destroy_workqueue(il->workqueue);
il->workqueue = NULL;
- il_free_traffic_mem(il);
free_irq(pdev->irq, il);
pci_disable_msi(pdev);
- pci_iounmap(pdev, il->hw_base);
+ iounmap(il->hw_base);
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
diff --git a/drivers/net/wireless/iwlegacy/3945.c b/drivers/net/wireless/iwlegacy/3945.c
index 6c1ae5fab89..456f32da6b2 100644
--- a/drivers/net/wireless/iwlegacy/3945.c
+++ b/drivers/net/wireless/iwlegacy/3945.c
@@ -57,10 +57,6 @@ il3945_send_led_cmd(struct il_priv *il, struct il_led_cmd *led_cmd)
return il_send_cmd(il, &cmd);
}
-const struct il_led_ops il3945_led_ops = {
- .cmd = il3945_send_led_cmd,
-};
-
#define IL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np) \
[RATE_##r##M_IDX] = { RATE_##r##M_PLCP, \
RATE_##r##M_IEEE, \
@@ -303,7 +299,7 @@ il3945_tx_queue_reclaim(struct il_priv *il, int txq_id, int idx)
skb = txq->skbs[txq->q.read_ptr];
ieee80211_tx_status_irqsafe(il->hw, skb);
txq->skbs[txq->q.read_ptr] = NULL;
- il->ops->lib->txq_free_tfd(il, txq);
+ il->ops->txq_free_tfd(il, txq);
}
if (il_queue_space(q) > q->low_mark && txq_id >= 0 &&
@@ -577,8 +573,6 @@ il3945_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb)
network_packet ? '*' : ' ', le16_to_cpu(rx_hdr->channel),
rx_status.signal, rx_status.signal, rx_status.rate_idx);
- il_dbg_log_rx_data_frame(il, le16_to_cpu(rx_hdr->len), header);
-
if (network_packet) {
il->_3945.last_beacon_time =
le32_to_cpu(rx_end->beacon_timestamp);
@@ -796,7 +790,6 @@ il3945_rx_init(struct il_priv *il, struct il_rx_queue *rxq)
static int
il3945_tx_reset(struct il_priv *il)
{
-
/* bypass mode */
il_wr_prph(il, ALM_SCD_MODE_REG, 0x2);
@@ -833,8 +826,7 @@ il3945_tx_reset(struct il_priv *il)
static int
il3945_txq_ctx_reset(struct il_priv *il)
{
- int rc;
- int txq_id, slots_num;
+ int rc, txq_id;
il3945_hw_txq_ctx_free(il);
@@ -850,10 +842,7 @@ il3945_txq_ctx_reset(struct il_priv *il)
/* Tx queue(s) */
for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++) {
- slots_num =
- (txq_id ==
- IL39_CMD_QUEUE_NUM) ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
- rc = il_tx_queue_init(il, &il->txq[txq_id], slots_num, txq_id);
+ rc = il_tx_queue_init(il, txq_id);
if (rc) {
IL_ERR("Tx %d queue init failed\n", txq_id);
goto error;
@@ -958,12 +947,11 @@ il3945_hw_nic_init(struct il_priv *il)
struct il_rx_queue *rxq = &il->rxq;
spin_lock_irqsave(&il->lock, flags);
- il->ops->lib->apm_ops.init(il);
+ il3945_apm_init(il);
spin_unlock_irqrestore(&il->lock, flags);
il3945_set_pwr_vmain(il);
-
- il->ops->lib->apm_ops.config(il);
+ il3945_nic_config(il);
/* Allocate the RX queue, or reset if it is already allocated */
if (!rxq->bd) {
@@ -1014,7 +1002,7 @@ il3945_hw_txq_ctx_free(struct il_priv *il)
il_tx_queue_free(il, txq_id);
/* free tx queue structure */
- il_txq_mem(il);
+ il_free_txq_mem(il);
}
void
@@ -1023,18 +1011,17 @@ il3945_hw_txq_ctx_stop(struct il_priv *il)
int txq_id;
/* stop SCD */
- il_wr_prph(il, ALM_SCD_MODE_REG, 0);
- il_wr_prph(il, ALM_SCD_TXFACT_REG, 0);
+ _il_wr_prph(il, ALM_SCD_MODE_REG, 0);
+ _il_wr_prph(il, ALM_SCD_TXFACT_REG, 0);
/* reset TFD queues */
for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++) {
- il_wr(il, FH39_TCSR_CONFIG(txq_id), 0x0);
- il_poll_bit(il, FH39_TSSR_TX_STATUS,
- FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id),
- 1000);
+ _il_wr(il, FH39_TCSR_CONFIG(txq_id), 0x0);
+ _il_poll_bit(il, FH39_TSSR_TX_STATUS,
+ FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id),
+ FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id),
+ 1000);
}
-
- il3945_hw_txq_ctx_free(il);
}
/**
@@ -1613,7 +1600,7 @@ il3945_hw_reg_comp_txpower_temp(struct il_priv *il)
}
/* send Txpower command for current channel to ucode */
- return il->ops->lib->send_tx_power(il);
+ return il->ops->send_tx_power(il);
}
int
@@ -2183,12 +2170,14 @@ il3945_txpower_set_from_eeprom(struct il_priv *il)
int
il3945_hw_rxq_stop(struct il_priv *il)
{
- int rc;
+ int ret;
- il_wr(il, FH39_RCSR_CONFIG(0), 0);
- rc = il_poll_bit(il, FH39_RSSR_STATUS,
- FH39_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
- if (rc < 0)
+ _il_wr(il, FH39_RCSR_CONFIG(0), 0);
+ ret = _il_poll_bit(il, FH39_RSSR_STATUS,
+ FH39_RSSR_CHNL0_RX_STATUS_CHNL_IDLE,
+ FH39_RSSR_CHNL0_RX_STATUS_CHNL_IDLE,
+ 1000);
+ if (ret < 0)
IL_ERR("Can't stop Rx DMA.\n");
return 0;
@@ -2630,65 +2619,31 @@ il3945_load_bsm(struct il_priv *il)
return 0;
}
-static struct il_hcmd_ops il3945_hcmd = {
- .rxon_assoc = il3945_send_rxon_assoc,
- .commit_rxon = il3945_commit_rxon,
-};
-
-static struct il_lib_ops il3945_lib = {
+const struct il_ops il3945_ops = {
.txq_attach_buf_to_tfd = il3945_hw_txq_attach_buf_to_tfd,
.txq_free_tfd = il3945_hw_txq_free_tfd,
.txq_init = il3945_hw_tx_queue_init,
.load_ucode = il3945_load_bsm,
.dump_nic_error_log = il3945_dump_nic_error_log,
- .apm_ops = {
- .init = il3945_apm_init,
- .config = il3945_nic_config,
- },
- .eeprom_ops = {
- .regulatory_bands = {
- EEPROM_REGULATORY_BAND_1_CHANNELS,
- EEPROM_REGULATORY_BAND_2_CHANNELS,
- EEPROM_REGULATORY_BAND_3_CHANNELS,
- EEPROM_REGULATORY_BAND_4_CHANNELS,
- EEPROM_REGULATORY_BAND_5_CHANNELS,
- EEPROM_REGULATORY_BAND_NO_HT40,
- EEPROM_REGULATORY_BAND_NO_HT40,
- },
- .acquire_semaphore = il3945_eeprom_acquire_semaphore,
- .release_semaphore = il3945_eeprom_release_semaphore,
- },
+ .apm_init = il3945_apm_init,
.send_tx_power = il3945_send_tx_power,
.is_valid_rtc_data_addr = il3945_hw_valid_rtc_data_addr,
+ .eeprom_acquire_semaphore = il3945_eeprom_acquire_semaphore,
+ .eeprom_release_semaphore = il3945_eeprom_release_semaphore,
-#ifdef CONFIG_IWLEGACY_DEBUGFS
- .debugfs_ops = {
- .rx_stats_read = il3945_ucode_rx_stats_read,
- .tx_stats_read = il3945_ucode_tx_stats_read,
- .general_stats_read = il3945_ucode_general_stats_read,
- },
-#endif
-};
-
-static const struct il_legacy_ops il3945_legacy_ops = {
- .post_associate = il3945_post_associate,
- .config_ap = il3945_config_ap,
- .manage_ibss_station = il3945_manage_ibss_station,
-};
+ .rxon_assoc = il3945_send_rxon_assoc,
+ .commit_rxon = il3945_commit_rxon,
-static struct il_hcmd_utils_ops il3945_hcmd_utils = {
.get_hcmd_size = il3945_get_hcmd_size,
.build_addsta_hcmd = il3945_build_addsta_hcmd,
.request_scan = il3945_request_scan,
.post_scan = il3945_post_scan,
-};
-const struct il_ops il3945_ops = {
- .lib = &il3945_lib,
- .hcmd = &il3945_hcmd,
- .utils = &il3945_hcmd_utils,
- .led = &il3945_led_ops,
- .legacy = &il3945_legacy_ops,
+ .post_associate = il3945_post_associate,
+ .config_ap = il3945_config_ap,
+ .manage_ibss_station = il3945_manage_ibss_station,
+
+ .send_led_cmd = il3945_send_led_cmd,
};
static struct il_cfg il3945_bg_cfg = {
@@ -2707,7 +2662,17 @@ static struct il_cfg il3945_bg_cfg = {
.set_l0s = false,
.use_bsm = true,
.led_compensation = 64,
- .wd_timeout = IL_DEF_WD_TIMEOUT
+ .wd_timeout = IL_DEF_WD_TIMEOUT,
+
+ .regulatory_bands = {
+ EEPROM_REGULATORY_BAND_1_CHANNELS,
+ EEPROM_REGULATORY_BAND_2_CHANNELS,
+ EEPROM_REGULATORY_BAND_3_CHANNELS,
+ EEPROM_REGULATORY_BAND_4_CHANNELS,
+ EEPROM_REGULATORY_BAND_5_CHANNELS,
+ EEPROM_REGULATORY_BAND_NO_HT40,
+ EEPROM_REGULATORY_BAND_NO_HT40,
+ },
};
static struct il_cfg il3945_abg_cfg = {
@@ -2726,7 +2691,17 @@ static struct il_cfg il3945_abg_cfg = {
.set_l0s = false,
.use_bsm = true,
.led_compensation = 64,
- .wd_timeout = IL_DEF_WD_TIMEOUT
+ .wd_timeout = IL_DEF_WD_TIMEOUT,
+
+ .regulatory_bands = {
+ EEPROM_REGULATORY_BAND_1_CHANNELS,
+ EEPROM_REGULATORY_BAND_2_CHANNELS,
+ EEPROM_REGULATORY_BAND_3_CHANNELS,
+ EEPROM_REGULATORY_BAND_4_CHANNELS,
+ EEPROM_REGULATORY_BAND_5_CHANNELS,
+ EEPROM_REGULATORY_BAND_NO_HT40,
+ EEPROM_REGULATORY_BAND_NO_HT40,
+ },
};
DEFINE_PCI_DEVICE_TABLE(il3945_hw_card_ids) = {
diff --git a/drivers/net/wireless/iwlegacy/3945.h b/drivers/net/wireless/iwlegacy/3945.h
index c00a8d30b6f..1d45075e0d5 100644
--- a/drivers/net/wireless/iwlegacy/3945.h
+++ b/drivers/net/wireless/iwlegacy/3945.h
@@ -595,13 +595,7 @@ struct il3945_tfd {
} __packed;
#ifdef CONFIG_IWLEGACY_DEBUGFS
-ssize_t il3945_ucode_rx_stats_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos);
-ssize_t il3945_ucode_tx_stats_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos);
-ssize_t il3945_ucode_general_stats_read(struct file *file,
- char __user *user_buf, size_t count,
- loff_t *ppos);
+extern const struct il_debugfs_ops il3945_debugfs_ops;
#endif
#endif
diff --git a/drivers/net/wireless/iwlegacy/4965-calib.c b/drivers/net/wireless/iwlegacy/4965-calib.c
index fe9171506a9..47c20e3d560 100644
--- a/drivers/net/wireless/iwlegacy/4965-calib.c
+++ b/drivers/net/wireless/iwlegacy/4965-calib.c
@@ -923,8 +923,8 @@ il4965_chain_noise_calibration(struct il_priv *il, void *stat_resp)
/* Some power changes may have been made during the calibration.
* Update and commit the RXON
*/
- if (il->ops->lib->update_chain_flags)
- il->ops->lib->update_chain_flags(il);
+ if (il->ops->update_chain_flags)
+ il->ops->update_chain_flags(il);
data->state = IL_CHAIN_NOISE_DONE;
il_power_update_mode(il, false);
diff --git a/drivers/net/wireless/iwlegacy/4965-debug.c b/drivers/net/wireless/iwlegacy/4965-debug.c
index 98ec39f56ba..c8153fc64f7 100644
--- a/drivers/net/wireless/iwlegacy/4965-debug.c
+++ b/drivers/net/wireless/iwlegacy/4965-debug.c
@@ -744,3 +744,9 @@ il4965_ucode_general_stats_read(struct file *file, char __user *user_buf,
kfree(buf);
return ret;
}
+
+const struct il_debugfs_ops il4965_debugfs_ops = {
+ .rx_stats_read = il4965_ucode_rx_stats_read,
+ .tx_stats_read = il4965_ucode_tx_stats_read,
+ .general_stats_read = il4965_ucode_general_stats_read,
+};
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index 235812ac6a0..2d01db0f08e 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -199,18 +199,14 @@ il4965_hw_nic_init(struct il_priv *il)
struct il_rx_queue *rxq = &il->rxq;
int ret;
- /* nic_init */
spin_lock_irqsave(&il->lock, flags);
- il->ops->lib->apm_ops.init(il);
-
+ il_apm_init(il);
/* Set interrupt coalescing calibration timer to default (512 usecs) */
il_write8(il, CSR_INT_COALESCING, IL_HOST_INT_CALIB_TIMEOUT_DEF);
-
spin_unlock_irqrestore(&il->lock, flags);
il4965_set_pwr_vmain(il);
-
- il->ops->lib->apm_ops.config(il);
+ il4965_nic_config(il);
/* Allocate the RX queue, or reset if it is already allocated */
if (!rxq->bd) {
@@ -445,11 +441,15 @@ il4965_rx_queue_free(struct il_priv *il, struct il_rx_queue *rxq)
int
il4965_rxq_stop(struct il_priv *il)
{
+ int ret;
- /* stop Rx DMA */
- il_wr(il, FH49_MEM_RCSR_CHNL0_CONFIG_REG, 0);
- il_poll_bit(il, FH49_MEM_RSSR_RX_STATUS_REG,
- FH49_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
+ _il_wr(il, FH49_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+ ret = _il_poll_bit(il, FH49_MEM_RSSR_RX_STATUS_REG,
+ FH49_RSSR_CHNL0_RX_STATUS_CHNL_IDLE,
+ FH49_RSSR_CHNL0_RX_STATUS_CHNL_IDLE,
+ 1000);
+ if (ret < 0)
+ IL_ERR("Can't stop Rx DMA.\n");
return 0;
}
@@ -692,7 +692,6 @@ il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb)
/* Find max signal strength (dBm) among 3 antenna/receiver chains */
rx_status.signal = il4965_calc_rssi(il, phy_res);
- il_dbg_log_rx_data_frame(il, len, header);
D_STATS("Rssi %d, TSF %llu\n", rx_status.signal,
(unsigned long long)rx_status.mactime);
@@ -1343,12 +1342,11 @@ il4965_accumulative_stats(struct il_priv *il, __le32 * stats)
}
#endif
-#define REG_RECALIB_PERIOD (60)
-
void
il4965_hdl_stats(struct il_priv *il, struct il_rx_buf *rxb)
{
- int change;
+ const int recalib_seconds = 60;
+ bool change;
struct il_rx_pkt *pkt = rxb_addr(rxb);
D_RX("Statistics notification received (%d vs %d).\n",
@@ -1369,20 +1367,21 @@ il4965_hdl_stats(struct il_priv *il, struct il_rx_buf *rxb)
set_bit(S_STATS, &il->status);
- /* Reschedule the stats timer to occur in
- * REG_RECALIB_PERIOD seconds to ensure we get a
- * thermal update even if the uCode doesn't give
- * us one */
+ /*
+ * Reschedule the stats timer to occur in recalib_seconds to ensure
+ * we get a thermal update even if the uCode doesn't give us one
+ */
mod_timer(&il->stats_periodic,
- jiffies + msecs_to_jiffies(REG_RECALIB_PERIOD * 1000));
+ jiffies + msecs_to_jiffies(recalib_seconds * 1000));
if (unlikely(!test_bit(S_SCANNING, &il->status)) &&
(pkt->hdr.cmd == N_STATS)) {
il4965_rx_calc_noise(il);
queue_work(il->workqueue, &il->run_time_calib_work);
}
- if (il->ops->lib->temp_ops.temperature && change)
- il->ops->lib->temp_ops.temperature(il);
+
+ if (change)
+ il4965_temperature_calib(il);
}
void
@@ -1785,7 +1784,6 @@ il4965_tx_skb(struct il_priv *il, struct sk_buff *skb)
/* TODO need this for burst mode later on */
il4965_tx_cmd_build_basic(il, skb, tx_cmd, info, hdr, sta_id);
- il_dbg_log_tx_data_frame(il, len, hdr);
il4965_tx_cmd_build_rate(il, tx_cmd, info, fc);
@@ -1815,7 +1813,7 @@ il4965_tx_skb(struct il_priv *il, struct sk_buff *skb)
dma_unmap_len_set(out_meta, len, firstlen);
/* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */
- il->ops->lib->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0);
+ il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0);
if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1;
@@ -1831,8 +1829,8 @@ il4965_tx_skb(struct il_priv *il, struct sk_buff *skb)
phys_addr =
pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen,
PCI_DMA_TODEVICE);
- il->ops->lib->txq_attach_buf_to_tfd(il, txq, phys_addr,
- secondlen, 0, 0);
+ il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, secondlen,
+ 0, 0);
}
scratch_phys =
@@ -1852,8 +1850,7 @@ il4965_tx_skb(struct il_priv *il, struct sk_buff *skb)
/* Set up entry for this TFD in Tx byte-count array */
if (info->flags & IEEE80211_TX_CTL_AMPDU)
- il->ops->lib->txq_update_byte_cnt_tbl(il, txq,
- le16_to_cpu(tx_cmd->len));
+ il->ops->txq_update_byte_cnt_tbl(il, txq, le16_to_cpu(tx_cmd->len));
pci_dma_sync_single_for_device(il->pci_dev, txcmd_phys, firstlen,
PCI_DMA_BIDIRECTIONAL);
@@ -1942,7 +1939,7 @@ il4965_hw_txq_ctx_free(struct il_priv *il)
il4965_free_dma_ptr(il, &il->scd_bc_tbls);
/* free tx queue structure */
- il_txq_mem(il);
+ il_free_txq_mem(il);
}
/**
@@ -1955,8 +1952,7 @@ il4965_hw_txq_ctx_free(struct il_priv *il)
int
il4965_txq_ctx_alloc(struct il_priv *il)
{
- int ret;
- int txq_id, slots_num;
+ int ret, txq_id;
unsigned long flags;
/* Free all tx/cmd queues and keep-warm buffer */
@@ -1993,10 +1989,7 @@ il4965_txq_ctx_alloc(struct il_priv *il)
/* Alloc and init all Tx queues, including the command queue (#4/#9) */
for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++) {
- slots_num =
- (txq_id ==
- il->cmd_queue) ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
- ret = il_tx_queue_init(il, &il->txq[txq_id], slots_num, txq_id);
+ ret = il_tx_queue_init(il, txq_id);
if (ret) {
IL_ERR("Tx %d queue init failed\n", txq_id);
goto error;
@@ -2017,52 +2010,27 @@ error_bc_tbls:
void
il4965_txq_ctx_reset(struct il_priv *il)
{
- int txq_id, slots_num;
+ int txq_id;
unsigned long flags;
spin_lock_irqsave(&il->lock, flags);
/* Turn off all Tx DMA fifos */
il4965_txq_set_sched(il, 0);
-
/* Tell NIC where to find the "keep warm" buffer */
il_wr(il, FH49_KW_MEM_ADDR_REG, il->kw.dma >> 4);
spin_unlock_irqrestore(&il->lock, flags);
/* Alloc and init all Tx queues, including the command queue (#4) */
- for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++) {
- slots_num =
- txq_id == il->cmd_queue ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
- il_tx_queue_reset(il, &il->txq[txq_id], slots_num, txq_id);
- }
+ for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++)
+ il_tx_queue_reset(il, txq_id);
}
-/**
- * il4965_txq_ctx_stop - Stop all Tx DMA channels
- */
void
-il4965_txq_ctx_stop(struct il_priv *il)
+il4965_txq_ctx_unmap(struct il_priv *il)
{
- int ch, txq_id;
- unsigned long flags;
-
- /* Turn off all Tx DMA fifos */
- spin_lock_irqsave(&il->lock, flags);
-
- il4965_txq_set_sched(il, 0);
-
- /* Stop each Tx DMA channel, and wait for it to be idle */
- for (ch = 0; ch < il->hw_params.dma_chnl_num; ch++) {
- il_wr(il, FH49_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
- if (il_poll_bit
- (il, FH49_TSSR_TX_STATUS_REG,
- FH49_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000))
- IL_ERR("Failing on timeout while stopping"
- " DMA channel %d [0x%08x]", ch,
- il_rd(il, FH49_TSSR_TX_STATUS_REG));
- }
- spin_unlock_irqrestore(&il->lock, flags);
+ int txq_id;
if (!il->txq)
return;
@@ -2075,6 +2043,30 @@ il4965_txq_ctx_stop(struct il_priv *il)
il_tx_queue_unmap(il, txq_id);
}
+/**
+ * il4965_txq_ctx_stop - Stop all Tx DMA channels
+ */
+void
+il4965_txq_ctx_stop(struct il_priv *il)
+{
+ int ch, ret;
+
+ _il_wr_prph(il, IL49_SCD_TXFACT, 0);
+
+ /* Stop each Tx DMA channel, and wait for it to be idle */
+ for (ch = 0; ch < il->hw_params.dma_chnl_num; ch++) {
+ _il_wr(il, FH49_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
+ ret =
+ _il_poll_bit(il, FH49_TSSR_TX_STATUS_REG,
+ FH49_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
+ FH49_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
+ 1000);
+ if (ret < 0)
+ IL_ERR("Timeout stopping DMA channel %d [0x%08x]",
+ ch, _il_rd(il, FH49_TSSR_TX_STATUS_REG));
+ }
+}
+
/*
* Find first available (lowest unused) Tx Queue, mark it "active".
* Called only when finding queue for aggregation.
@@ -2474,7 +2466,7 @@ il4965_tx_queue_reclaim(struct il_priv *il, int txq_id, int idx)
il4965_tx_status(il, skb, txq_id >= IL4965_FIRST_AMPDU_QUEUE);
txq->skbs[txq->q.read_ptr] = NULL;
- il->ops->lib->txq_free_tfd(il, txq);
+ il->ops->txq_free_tfd(il, txq);
}
return nfreed;
}
@@ -2548,6 +2540,308 @@ il4965_tx_status_reply_compressed_ba(struct il_priv *il, struct il_ht_agg *agg,
return 0;
}
+static inline bool
+il4965_is_tx_success(u32 status)
+{
+ status &= TX_STATUS_MSK;
+ return (status == TX_STATUS_SUCCESS || status == TX_STATUS_DIRECT_DONE);
+}
+
+static u8
+il4965_find_station(struct il_priv *il, const u8 *addr)
+{
+ int i;
+ int start = 0;
+ int ret = IL_INVALID_STATION;
+ unsigned long flags;
+
+ if (il->iw_mode == NL80211_IFTYPE_ADHOC)
+ start = IL_STA_ID;
+
+ if (is_broadcast_ether_addr(addr))
+ return il->hw_params.bcast_id;
+
+ spin_lock_irqsave(&il->sta_lock, flags);
+ for (i = start; i < il->hw_params.max_stations; i++)
+ if (il->stations[i].used &&
+ (!compare_ether_addr(il->stations[i].sta.sta.addr, addr))) {
+ ret = i;
+ goto out;
+ }
+
+ D_ASSOC("can not find STA %pM total %d\n", addr, il->num_stations);
+
+out:
+ /*
+ * It may be possible that more commands interacting with stations
+ * arrive before we completed processing the adding of
+ * station
+ */
+ if (ret != IL_INVALID_STATION &&
+ (!(il->stations[ret].used & IL_STA_UCODE_ACTIVE) ||
+ ((il->stations[ret].used & IL_STA_UCODE_ACTIVE) &&
+ (il->stations[ret].used & IL_STA_UCODE_INPROGRESS)))) {
+ IL_ERR("Requested station info for sta %d before ready.\n",
+ ret);
+ ret = IL_INVALID_STATION;
+ }
+ spin_unlock_irqrestore(&il->sta_lock, flags);
+ return ret;
+}
+
+static int
+il4965_get_ra_sta_id(struct il_priv *il, struct ieee80211_hdr *hdr)
+{
+ if (il->iw_mode == NL80211_IFTYPE_STATION)
+ return IL_AP_ID;
+ else {
+ u8 *da = ieee80211_get_DA(hdr);
+
+ return il4965_find_station(il, da);
+ }
+}
+
+static inline u32
+il4965_get_scd_ssn(struct il4965_tx_resp *tx_resp)
+{
+ return le32_to_cpup(&tx_resp->u.status + tx_resp->frame_count) & MAX_SN;
+}
+
+static inline u32
+il4965_tx_status_to_mac80211(u32 status)
+{
+ status &= TX_STATUS_MSK;
+
+ switch (status) {
+ case TX_STATUS_SUCCESS:
+ case TX_STATUS_DIRECT_DONE:
+ return IEEE80211_TX_STAT_ACK;
+ case TX_STATUS_FAIL_DEST_PS:
+ return IEEE80211_TX_STAT_TX_FILTERED;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * il4965_tx_status_reply_tx - Handle Tx response for frames in aggregation queue
+ */
+static int
+il4965_tx_status_reply_tx(struct il_priv *il, struct il_ht_agg *agg,
+ struct il4965_tx_resp *tx_resp, int txq_id,
+ u16 start_idx)
+{
+ u16 status;
+ struct agg_tx_status *frame_status = tx_resp->u.agg_status;
+ struct ieee80211_tx_info *info = NULL;
+ struct ieee80211_hdr *hdr = NULL;
+ u32 rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+ int i, sh, idx;
+ u16 seq;
+ if (agg->wait_for_ba)
+ D_TX_REPLY("got tx response w/o block-ack\n");
+
+ agg->frame_count = tx_resp->frame_count;
+ agg->start_idx = start_idx;
+ agg->rate_n_flags = rate_n_flags;
+ agg->bitmap = 0;
+
+ /* num frames attempted by Tx command */
+ if (agg->frame_count == 1) {
+ /* Only one frame was attempted; no block-ack will arrive */
+ status = le16_to_cpu(frame_status[0].status);
+ idx = start_idx;
+
+ D_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n",
+ agg->frame_count, agg->start_idx, idx);
+
+ info = IEEE80211_SKB_CB(il->txq[txq_id].skbs[idx]);
+ info->status.rates[0].count = tx_resp->failure_frame + 1;
+ info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+ info->flags |= il4965_tx_status_to_mac80211(status);
+ il4965_hwrate_to_tx_control(il, rate_n_flags, info);
+
+ D_TX_REPLY("1 Frame 0x%x failure :%d\n", status & 0xff,
+ tx_resp->failure_frame);
+ D_TX_REPLY("Rate Info rate_n_flags=%x\n", rate_n_flags);
+
+ agg->wait_for_ba = 0;
+ } else {
+ /* Two or more frames were attempted; expect block-ack */
+ u64 bitmap = 0;
+ int start = agg->start_idx;
+ struct sk_buff *skb;
+
+ /* Construct bit-map of pending frames within Tx win */
+ for (i = 0; i < agg->frame_count; i++) {
+ u16 sc;
+ status = le16_to_cpu(frame_status[i].status);
+ seq = le16_to_cpu(frame_status[i].sequence);
+ idx = SEQ_TO_IDX(seq);
+ txq_id = SEQ_TO_QUEUE(seq);
+
+ if (status &
+ (AGG_TX_STATE_FEW_BYTES_MSK |
+ AGG_TX_STATE_ABORT_MSK))
+ continue;
+
+ D_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
+ agg->frame_count, txq_id, idx);
+
+ skb = il->txq[txq_id].skbs[idx];
+ if (WARN_ON_ONCE(skb == NULL))
+ return -1;
+ hdr = (struct ieee80211_hdr *) skb->data;
+
+ sc = le16_to_cpu(hdr->seq_ctrl);
+ if (idx != (SEQ_TO_SN(sc) & 0xff)) {
+ IL_ERR("BUG_ON idx doesn't match seq control"
+ " idx=%d, seq_idx=%d, seq=%d\n", idx,
+ SEQ_TO_SN(sc), hdr->seq_ctrl);
+ return -1;
+ }
+
+ D_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", i, idx,
+ SEQ_TO_SN(sc));
+
+ sh = idx - start;
+ if (sh > 64) {
+ sh = (start - idx) + 0xff;
+ bitmap = bitmap << sh;
+ sh = 0;
+ start = idx;
+ } else if (sh < -64)
+ sh = 0xff - (start - idx);
+ else if (sh < 0) {
+ sh = start - idx;
+ start = idx;
+ bitmap = bitmap << sh;
+ sh = 0;
+ }
+ bitmap |= 1ULL << sh;
+ D_TX_REPLY("start=%d bitmap=0x%llx\n", start,
+ (unsigned long long)bitmap);
+ }
+
+ agg->bitmap = bitmap;
+ agg->start_idx = start;
+ D_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n",
+ agg->frame_count, agg->start_idx,
+ (unsigned long long)agg->bitmap);
+
+ if (bitmap)
+ agg->wait_for_ba = 1;
+ }
+ return 0;
+}
+
+/**
+ * il4965_hdl_tx - Handle standard (non-aggregation) Tx response
+ */
+static void
+il4965_hdl_tx(struct il_priv *il, struct il_rx_buf *rxb)
+{
+ struct il_rx_pkt *pkt = rxb_addr(rxb);
+ u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+ int txq_id = SEQ_TO_QUEUE(sequence);
+ int idx = SEQ_TO_IDX(sequence);
+ struct il_tx_queue *txq = &il->txq[txq_id];
+ struct sk_buff *skb;
+ struct ieee80211_hdr *hdr;
+ struct ieee80211_tx_info *info;
+ struct il4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+ u32 status = le32_to_cpu(tx_resp->u.status);
+ int uninitialized_var(tid);
+ int sta_id;
+ int freed;
+ u8 *qc = NULL;
+ unsigned long flags;
+
+ if (idx >= txq->q.n_bd || il_queue_used(&txq->q, idx) == 0) {
+ IL_ERR("Read idx for DMA queue txq_id (%d) idx %d "
+ "is out of range [0-%d] %d %d\n", txq_id, idx,
+ txq->q.n_bd, txq->q.write_ptr, txq->q.read_ptr);
+ return;
+ }
+
+ txq->time_stamp = jiffies;
+
+ skb = txq->skbs[txq->q.read_ptr];
+ info = IEEE80211_SKB_CB(skb);
+ memset(&info->status, 0, sizeof(info->status));
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ if (ieee80211_is_data_qos(hdr->frame_control)) {
+ qc = ieee80211_get_qos_ctl(hdr);
+ tid = qc[0] & 0xf;
+ }
+
+ sta_id = il4965_get_ra_sta_id(il, hdr);
+ if (txq->sched_retry && unlikely(sta_id == IL_INVALID_STATION)) {
+ IL_ERR("Station not known\n");
+ return;
+ }
+
+ spin_lock_irqsave(&il->sta_lock, flags);
+ if (txq->sched_retry) {
+ const u32 scd_ssn = il4965_get_scd_ssn(tx_resp);
+ struct il_ht_agg *agg = NULL;
+ WARN_ON(!qc);
+
+ agg = &il->stations[sta_id].tid[tid].agg;
+
+ il4965_tx_status_reply_tx(il, agg, tx_resp, txq_id, idx);
+
+ /* check if BAR is needed */
+ if (tx_resp->frame_count == 1 &&
+ !il4965_is_tx_success(status))
+ info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+
+ if (txq->q.read_ptr != (scd_ssn & 0xff)) {
+ idx = il_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
+ D_TX_REPLY("Retry scheduler reclaim scd_ssn "
+ "%d idx %d\n", scd_ssn, idx);
+ freed = il4965_tx_queue_reclaim(il, txq_id, idx);
+ if (qc)
+ il4965_free_tfds_in_queue(il, sta_id, tid,
+ freed);
+
+ if (il->mac80211_registered &&
+ il_queue_space(&txq->q) > txq->q.low_mark &&
+ agg->state != IL_EMPTYING_HW_QUEUE_DELBA)
+ il_wake_queue(il, txq);
+ }
+ } else {
+ info->status.rates[0].count = tx_resp->failure_frame + 1;
+ info->flags |= il4965_tx_status_to_mac80211(status);
+ il4965_hwrate_to_tx_control(il,
+ le32_to_cpu(tx_resp->rate_n_flags),
+ info);
+
+ D_TX_REPLY("TXQ %d status %s (0x%08x) "
+ "rate_n_flags 0x%x retries %d\n", txq_id,
+ il4965_get_tx_fail_reason(status), status,
+ le32_to_cpu(tx_resp->rate_n_flags),
+ tx_resp->failure_frame);
+
+ freed = il4965_tx_queue_reclaim(il, txq_id, idx);
+ if (qc && likely(sta_id != IL_INVALID_STATION))
+ il4965_free_tfds_in_queue(il, sta_id, tid, freed);
+ else if (sta_id == IL_INVALID_STATION)
+ D_TX_REPLY("Station not known\n");
+
+ if (il->mac80211_registered &&
+ il_queue_space(&txq->q) > txq->q.low_mark)
+ il_wake_queue(il, txq);
+ }
+ if (qc && likely(sta_id != IL_INVALID_STATION))
+ il4965_txq_check_empty(il, sta_id, tid, txq_id);
+
+ il4965_check_abort_status(il, tx_resp->frame_count, status);
+
+ spin_unlock_irqrestore(&il->sta_lock, flags);
+}
+
/**
* translate ucode response to mac80211 tx status control values
*/
@@ -3352,8 +3646,8 @@ il4965_sta_modify_sleep_tx_count(struct il_priv *il, int sta_id, int cnt)
void
il4965_update_chain_flags(struct il_priv *il)
{
- if (il->ops->hcmd->set_rxon_chain) {
- il->ops->hcmd->set_rxon_chain(il);
+ if (il->ops->set_rxon_chain) {
+ il->ops->set_rxon_chain(il);
if (il->active.rx_chain != il->staging.rx_chain)
il_commit_rxon(il);
}
@@ -3726,9 +4020,9 @@ il4965_hdl_alive(struct il_priv *il, struct il_rx_buf *rxb)
* This callback is provided in order to send a stats request.
*
* This timer function is continually reset to execute within
- * REG_RECALIB_PERIOD seconds since the last N_STATS
- * was received. We need to ensure we receive the stats in order
- * to update the temperature used for calibrating the TXPOWER.
+ * 60 seconds since the last N_STATS was received. We need to
+ * ensure we receive the stats in order to update the temperature
+ * used for calibrating the TXPOWER.
*/
static void
il4965_bg_stats_periodic(unsigned long data)
@@ -3778,7 +4072,7 @@ il4965_perform_ct_kill_task(struct il_priv *il)
_il_rd(il, CSR_UCODE_DRV_GP1);
spin_lock_irqsave(&il->reg_lock, flags);
- if (!_il_grab_nic_access(il))
+ if (likely(_il_grab_nic_access(il)))
_il_release_nic_access(il);
spin_unlock_irqrestore(&il->reg_lock, flags);
}
@@ -3816,17 +4110,17 @@ il4965_hdl_card_state(struct il_priv *il, struct il_rx_buf *rxb)
il4965_perform_ct_kill_task(il);
if (flags & HW_CARD_DISABLED)
- set_bit(S_RF_KILL_HW, &il->status);
+ set_bit(S_RFKILL, &il->status);
else
- clear_bit(S_RF_KILL_HW, &il->status);
+ clear_bit(S_RFKILL, &il->status);
if (!(flags & RXON_CARD_DISABLED))
il_scan_cancel(il);
- if ((test_bit(S_RF_KILL_HW, &status) !=
- test_bit(S_RF_KILL_HW, &il->status)))
+ if ((test_bit(S_RFKILL, &status) !=
+ test_bit(S_RFKILL, &il->status)))
wiphy_rfkill_set_hw_state(il->hw->wiphy,
- test_bit(S_RF_KILL_HW, &il->status));
+ test_bit(S_RFKILL, &il->status));
else
wake_up(&il->wait_command_queue);
}
@@ -3868,10 +4162,11 @@ il4965_setup_handlers(struct il_priv *il)
/* Rx handlers */
il->handlers[N_RX_PHY] = il4965_hdl_rx_phy;
il->handlers[N_RX_MPDU] = il4965_hdl_rx;
+ il->handlers[N_RX] = il4965_hdl_rx;
/* block ack */
il->handlers[N_COMPRESSED_BA] = il4965_hdl_compressed_ba;
- /* Set up hardware specific Rx handlers */
- il->ops->lib->handler_setup(il);
+ /* Tx response */
+ il->handlers[C_TX] = il4965_hdl_tx;
}
/**
@@ -4101,9 +4396,8 @@ il4965_irq_tasklet(struct il_priv *il)
/* HW RF KILL switch toggled */
if (inta & CSR_INT_BIT_RF_KILL) {
int hw_rf_kill = 0;
- if (!
- (_il_rd(il, CSR_GP_CNTRL) &
- CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+
+ if (!(_il_rd(il, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
hw_rf_kill = 1;
IL_WARN("RF_KILL bit toggled to %s.\n",
@@ -4118,9 +4412,9 @@ il4965_irq_tasklet(struct il_priv *il)
*/
if (!test_bit(S_ALIVE, &il->status)) {
if (hw_rf_kill)
- set_bit(S_RF_KILL_HW, &il->status);
+ set_bit(S_RFKILL, &il->status);
else
- clear_bit(S_RF_KILL_HW, &il->status);
+ clear_bit(S_RFKILL, &il->status);
wiphy_rfkill_set_hw_state(il->hw->wiphy, hw_rf_kill);
}
@@ -4244,11 +4538,9 @@ il4965_store_debug_level(struct device *d, struct device_attribute *attr,
ret = strict_strtoul(buf, 0, &val);
if (ret)
IL_ERR("%s is not in hex or decimal form.\n", buf);
- else {
+ else
il->debug_level = val;
- if (il_alloc_traffic_mem(il))
- IL_ERR("Not enough memory to generate traffic log\n");
- }
+
return strnlen(buf, count);
}
@@ -4773,7 +5065,7 @@ il4965_dump_nic_error_log(struct il_priv *il)
else
base = le32_to_cpu(il->card_alive.error_event_table_ptr);
- if (!il->ops->lib->is_valid_rtc_data_addr(base)) {
+ if (!il->ops->is_valid_rtc_data_addr(base)) {
IL_ERR("Not valid error log pointer 0x%08X for %s uCode\n",
base, (il->ucode_type == UCODE_INIT) ? "Init" : "RT");
return;
@@ -5002,8 +5294,8 @@ il4965_alive_start(struct il_priv *il)
/* Initialize our rx_config data */
il_connection_init_rx_config(il);
- if (il->ops->hcmd->set_rxon_chain)
- il->ops->hcmd->set_rxon_chain(il);
+ if (il->ops->set_rxon_chain)
+ il->ops->set_rxon_chain(il);
}
/* Configure bluetooth coexistence if enabled */
@@ -5091,12 +5383,8 @@ __il4965_down(struct il_priv *il)
* clear all bits but the RF Kill bit and return */
if (!il_is_init(il)) {
il->status =
- test_bit(S_RF_KILL_HW,
- &il->
- status) << S_RF_KILL_HW |
- test_bit(S_GEO_CONFIGURED,
- &il->
- status) << S_GEO_CONFIGURED |
+ test_bit(S_RFKILL, &il->status) << S_RFKILL |
+ test_bit(S_GEO_CONFIGURED, &il->status) << S_GEO_CONFIGURED |
test_bit(S_EXIT_PENDING, &il->status) << S_EXIT_PENDING;
goto exit;
}
@@ -5104,28 +5392,32 @@ __il4965_down(struct il_priv *il)
/* ...otherwise clear out all the status bits but the RF Kill
* bit and continue taking the NIC down. */
il->status &=
- test_bit(S_RF_KILL_HW,
- &il->status) << S_RF_KILL_HW | test_bit(S_GEO_CONFIGURED,
- &il->
- status) <<
- S_GEO_CONFIGURED | test_bit(S_FW_ERROR,
- &il->
- status) << S_FW_ERROR |
+ test_bit(S_RFKILL, &il->status) << S_RFKILL |
+ test_bit(S_GEO_CONFIGURED, &il->status) << S_GEO_CONFIGURED |
+ test_bit(S_FW_ERROR, &il->status) << S_FW_ERROR |
test_bit(S_EXIT_PENDING, &il->status) << S_EXIT_PENDING;
+ /*
+ * We disabled and synchronized interrupt, and priv->mutex is taken, so
+ * here is the only thread which will program device registers, but
+ * still have lockdep assertions, so we are taking reg_lock.
+ */
+ spin_lock_irq(&il->reg_lock);
+ /* FIXME: il_grab_nic_access if rfkill is off ? */
+
il4965_txq_ctx_stop(il);
il4965_rxq_stop(il);
-
/* Power-down device's busmaster DMA clocks */
- il_wr_prph(il, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
+ _il_wr_prph(il, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
udelay(5);
-
/* Make sure (redundant) we've released our request to stay awake */
- il_clear_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
+ _il_clear_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
/* Stop the device, and put it in low power state */
- il_apm_stop(il);
+ _il_apm_stop(il);
+
+ spin_unlock_irq(&il->reg_lock);
+ il4965_txq_ctx_unmap(il);
exit:
memset(&il->card_alive, 0, sizeof(struct il_alive_resp));
@@ -5146,40 +5438,36 @@ il4965_down(struct il_priv *il)
il4965_cancel_deferred_work(il);
}
-#define HW_READY_TIMEOUT (50)
-static int
+static void
il4965_set_hw_ready(struct il_priv *il)
{
- int ret = 0;
+ int ret;
il_set_bit(il, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
/* See if we got it */
- ret =
- _il_poll_bit(il, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
- CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, HW_READY_TIMEOUT);
- if (ret != -ETIMEDOUT)
+ ret = _il_poll_bit(il, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
+ CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
+ 100);
+ if (ret >= 0)
il->hw_ready = true;
- else
- il->hw_ready = false;
- D_INFO("hardware %s\n", (il->hw_ready == 1) ? "ready" : "not ready");
- return ret;
+ D_INFO("hardware %s ready\n", (il->hw_ready) ? "" : "not");
}
-static int
+static void
il4965_prepare_card_hw(struct il_priv *il)
{
- int ret = 0;
+ int ret;
- D_INFO("il4965_prepare_card_hw enter\n");
+ il->hw_ready = false;
- ret = il4965_set_hw_ready(il);
+ il4965_set_hw_ready(il);
if (il->hw_ready)
- return ret;
+ return;
/* If HW is not ready, prepare the conditions to check again */
il_set_bit(il, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_PREPARE);
@@ -5192,8 +5480,6 @@ il4965_prepare_card_hw(struct il_priv *il)
/* HW should be ready by now, check again. */
if (ret != -ETIMEDOUT)
il4965_set_hw_ready(il);
-
- return ret;
}
#define MAX_HW_RESTARTS 5
@@ -5221,22 +5507,19 @@ __il4965_up(struct il_priv *il)
}
il4965_prepare_card_hw(il);
-
if (!il->hw_ready) {
- IL_WARN("Exit HW not ready\n");
+ IL_ERR("HW not ready\n");
return -EIO;
}
/* If platform's RF_KILL switch is NOT set to KILL */
if (_il_rd(il, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
- clear_bit(S_RF_KILL_HW, &il->status);
- else
- set_bit(S_RF_KILL_HW, &il->status);
-
- if (il_is_rfkill(il)) {
+ clear_bit(S_RFKILL, &il->status);
+ else {
+ set_bit(S_RFKILL, &il->status);
wiphy_rfkill_set_hw_state(il->hw->wiphy, true);
- il_enable_interrupts(il);
+ il_enable_rfkill_int(il);
IL_WARN("Radio disabled by HW RF Kill switch\n");
return 0;
}
@@ -5275,7 +5558,7 @@ __il4965_up(struct il_priv *il)
/* load bootstrap state machine,
* load bootstrap program into processor's memory,
* prepare to load the "initialize" uCode */
- ret = il->ops->lib->load_ucode(il);
+ ret = il->ops->load_ucode(il);
if (ret) {
IL_ERR("Unable to set up bootstrap uCode: %d\n", ret);
@@ -5316,7 +5599,7 @@ il4965_bg_init_alive_start(struct work_struct *data)
if (test_bit(S_EXIT_PENDING, &il->status))
goto out;
- il->ops->lib->init_alive_start(il);
+ il->ops->init_alive_start(il);
out:
mutex_unlock(&il->mutex);
}
@@ -5748,7 +6031,7 @@ il4965_mac_channel_switch(struct ieee80211_hw *hw,
if (!il_is_associated(il))
goto out;
- if (!il->ops->lib->set_channel_switch)
+ if (!il->ops->set_channel_switch)
goto out;
ch = channel->hw_value;
@@ -5800,7 +6083,7 @@ il4965_mac_channel_switch(struct ieee80211_hw *hw,
*/
set_bit(S_CHANNEL_SWITCH_PENDING, &il->status);
il->switch_channel = cpu_to_le16(ch);
- if (il->ops->lib->set_channel_switch(il, ch_switch)) {
+ if (il->ops->set_channel_switch(il, ch_switch)) {
clear_bit(S_CHANNEL_SWITCH_PENDING, &il->status);
il->switch_channel = 0;
ieee80211_chswitch_done(il->vif, false);
@@ -5883,7 +6166,7 @@ il4965_bg_txpower_work(struct work_struct *work)
/* Regardless of if we are associated, we must reconfigure the
* TX power since frames can be sent on non-radar channels while
* not associated */
- il->ops->lib->send_tx_power(il);
+ il->ops->send_tx_power(il);
/* Update last_temperature to keep is_calib_needed from running
* when it isn't needed... */
@@ -6035,8 +6318,8 @@ il4965_init_drv(struct il_priv *il)
il->force_reset.reset_duration = IL_DELAY_NEXT_FORCE_FW_RELOAD;
/* Choose which receivers/antennas to use */
- if (il->ops->hcmd->set_rxon_chain)
- il->ops->hcmd->set_rxon_chain(il);
+ if (il->ops->set_rxon_chain)
+ il->ops->set_rxon_chain(il);
il_init_scan_params(il);
@@ -6180,12 +6463,12 @@ il4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
D_INFO("*** LOAD DRIVER ***\n");
il->cfg = cfg;
il->ops = &il4965_ops;
+#ifdef CONFIG_IWLEGACY_DEBUGFS
+ il->debugfs_ops = &il4965_debugfs_ops;
+#endif
il->pci_dev = pdev;
il->inta_mask = CSR_INI_SET_MASK;
- if (il_alloc_traffic_mem(il))
- IL_ERR("Not enough memory to generate traffic log\n");
-
/**************************
* 2. Initializing PCI bus
**************************/
@@ -6224,7 +6507,7 @@ il4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/***********************
* 3. Read REV register
***********************/
- il->hw_base = pci_iomap(pdev, 0, 0);
+ il->hw_base = pci_ioremap_bar(pdev, 0);
if (!il->hw_base) {
err = -ENODEV;
goto out_pci_release_regions;
@@ -6329,12 +6612,12 @@ il4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* If platform's RF_KILL switch is NOT set to KILL */
if (_il_rd(il, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
- clear_bit(S_RF_KILL_HW, &il->status);
+ clear_bit(S_RFKILL, &il->status);
else
- set_bit(S_RF_KILL_HW, &il->status);
+ set_bit(S_RFKILL, &il->status);
wiphy_rfkill_set_hw_state(il->hw->wiphy,
- test_bit(S_RF_KILL_HW, &il->status));
+ test_bit(S_RFKILL, &il->status));
il_power_initialize(il);
@@ -6356,14 +6639,13 @@ out_disable_msi:
out_free_eeprom:
il_eeprom_free(il);
out_iounmap:
- pci_iounmap(pdev, il->hw_base);
+ iounmap(il->hw_base);
out_pci_release_regions:
pci_set_drvdata(pdev, NULL);
pci_release_regions(pdev);
out_pci_disable_device:
pci_disable_device(pdev);
out_ieee80211_free_hw:
- il_free_traffic_mem(il);
ieee80211_free_hw(il->hw);
out:
return err;
@@ -6434,11 +6716,10 @@ il4965_pci_remove(struct pci_dev *pdev)
* until now... */
destroy_workqueue(il->workqueue);
il->workqueue = NULL;
- il_free_traffic_mem(il);
free_irq(il->pci_dev->irq, il);
pci_disable_msi(il->pci_dev);
- pci_iounmap(pdev, il->hw_base);
+ iounmap(il->hw_base);
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
diff --git a/drivers/net/wireless/iwlegacy/4965.c b/drivers/net/wireless/iwlegacy/4965.c
index 79e4e797133..5db11714e04 100644
--- a/drivers/net/wireless/iwlegacy/4965.c
+++ b/drivers/net/wireless/iwlegacy/4965.c
@@ -264,10 +264,6 @@ il4965_led_enable(struct il_priv *il)
_il_wr(il, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
}
-const struct il_led_ops il4965_led_ops = {
- .cmd = il4965_send_led_cmd,
-};
-
static int il4965_send_tx_power(struct il_priv *il);
static int il4965_hw_get_temperature(struct il_priv *il);
@@ -508,7 +504,7 @@ iw4965_is_ht40_channel(__le32 rxon_flags)
chan_mod == CHANNEL_MODE_MIXED);
}
-static void
+void
il4965_nic_config(struct il_priv *il)
{
unsigned long flags;
@@ -1678,7 +1674,7 @@ il4965_is_temp_calib_needed(struct il_priv *il)
return 1;
}
-static void
+void
il4965_temperature_calib(struct il_priv *il)
{
s32 temp;
@@ -1737,323 +1733,6 @@ il4965_build_addsta_hcmd(const struct il_addsta_cmd *cmd, u8 * data)
return (u16) sizeof(struct il4965_addsta_cmd);
}
-static inline u32
-il4965_get_scd_ssn(struct il4965_tx_resp *tx_resp)
-{
- return le32_to_cpup(&tx_resp->u.status + tx_resp->frame_count) & MAX_SN;
-}
-
-static inline u32
-il4965_tx_status_to_mac80211(u32 status)
-{
- status &= TX_STATUS_MSK;
-
- switch (status) {
- case TX_STATUS_SUCCESS:
- case TX_STATUS_DIRECT_DONE:
- return IEEE80211_TX_STAT_ACK;
- case TX_STATUS_FAIL_DEST_PS:
- return IEEE80211_TX_STAT_TX_FILTERED;
- default:
- return 0;
- }
-}
-
-static inline bool
-il4965_is_tx_success(u32 status)
-{
- status &= TX_STATUS_MSK;
- return (status == TX_STATUS_SUCCESS || status == TX_STATUS_DIRECT_DONE);
-}
-
-/**
- * il4965_tx_status_reply_tx - Handle Tx response for frames in aggregation queue
- */
-static int
-il4965_tx_status_reply_tx(struct il_priv *il, struct il_ht_agg *agg,
- struct il4965_tx_resp *tx_resp, int txq_id,
- u16 start_idx)
-{
- u16 status;
- struct agg_tx_status *frame_status = tx_resp->u.agg_status;
- struct ieee80211_tx_info *info = NULL;
- struct ieee80211_hdr *hdr = NULL;
- u32 rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
- int i, sh, idx;
- u16 seq;
- if (agg->wait_for_ba)
- D_TX_REPLY("got tx response w/o block-ack\n");
-
- agg->frame_count = tx_resp->frame_count;
- agg->start_idx = start_idx;
- agg->rate_n_flags = rate_n_flags;
- agg->bitmap = 0;
-
- /* num frames attempted by Tx command */
- if (agg->frame_count == 1) {
- /* Only one frame was attempted; no block-ack will arrive */
- status = le16_to_cpu(frame_status[0].status);
- idx = start_idx;
-
- D_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n",
- agg->frame_count, agg->start_idx, idx);
-
- info = IEEE80211_SKB_CB(il->txq[txq_id].skbs[idx]);
- info->status.rates[0].count = tx_resp->failure_frame + 1;
- info->flags &= ~IEEE80211_TX_CTL_AMPDU;
- info->flags |= il4965_tx_status_to_mac80211(status);
- il4965_hwrate_to_tx_control(il, rate_n_flags, info);
-
- D_TX_REPLY("1 Frame 0x%x failure :%d\n", status & 0xff,
- tx_resp->failure_frame);
- D_TX_REPLY("Rate Info rate_n_flags=%x\n", rate_n_flags);
-
- agg->wait_for_ba = 0;
- } else {
- /* Two or more frames were attempted; expect block-ack */
- u64 bitmap = 0;
- int start = agg->start_idx;
- struct sk_buff *skb;
-
- /* Construct bit-map of pending frames within Tx win */
- for (i = 0; i < agg->frame_count; i++) {
- u16 sc;
- status = le16_to_cpu(frame_status[i].status);
- seq = le16_to_cpu(frame_status[i].sequence);
- idx = SEQ_TO_IDX(seq);
- txq_id = SEQ_TO_QUEUE(seq);
-
- if (status &
- (AGG_TX_STATE_FEW_BYTES_MSK |
- AGG_TX_STATE_ABORT_MSK))
- continue;
-
- D_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
- agg->frame_count, txq_id, idx);
-
- skb = il->txq[txq_id].skbs[idx];
- if (WARN_ON_ONCE(skb == NULL))
- return -1;
- hdr = (struct ieee80211_hdr *) skb->data;
-
- sc = le16_to_cpu(hdr->seq_ctrl);
- if (idx != (SEQ_TO_SN(sc) & 0xff)) {
- IL_ERR("BUG_ON idx doesn't match seq control"
- " idx=%d, seq_idx=%d, seq=%d\n", idx,
- SEQ_TO_SN(sc), hdr->seq_ctrl);
- return -1;
- }
-
- D_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", i, idx,
- SEQ_TO_SN(sc));
-
- sh = idx - start;
- if (sh > 64) {
- sh = (start - idx) + 0xff;
- bitmap = bitmap << sh;
- sh = 0;
- start = idx;
- } else if (sh < -64)
- sh = 0xff - (start - idx);
- else if (sh < 0) {
- sh = start - idx;
- start = idx;
- bitmap = bitmap << sh;
- sh = 0;
- }
- bitmap |= 1ULL << sh;
- D_TX_REPLY("start=%d bitmap=0x%llx\n", start,
- (unsigned long long)bitmap);
- }
-
- agg->bitmap = bitmap;
- agg->start_idx = start;
- D_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n",
- agg->frame_count, agg->start_idx,
- (unsigned long long)agg->bitmap);
-
- if (bitmap)
- agg->wait_for_ba = 1;
- }
- return 0;
-}
-
-static u8
-il4965_find_station(struct il_priv *il, const u8 * addr)
-{
- int i;
- int start = 0;
- int ret = IL_INVALID_STATION;
- unsigned long flags;
-
- if ((il->iw_mode == NL80211_IFTYPE_ADHOC))
- start = IL_STA_ID;
-
- if (is_broadcast_ether_addr(addr))
- return il->hw_params.bcast_id;
-
- spin_lock_irqsave(&il->sta_lock, flags);
- for (i = start; i < il->hw_params.max_stations; i++)
- if (il->stations[i].used &&
- (!compare_ether_addr(il->stations[i].sta.sta.addr, addr))) {
- ret = i;
- goto out;
- }
-
- D_ASSOC("can not find STA %pM total %d\n", addr, il->num_stations);
-
-out:
- /*
- * It may be possible that more commands interacting with stations
- * arrive before we completed processing the adding of
- * station
- */
- if (ret != IL_INVALID_STATION &&
- (!(il->stations[ret].used & IL_STA_UCODE_ACTIVE) ||
- ((il->stations[ret].used & IL_STA_UCODE_ACTIVE) &&
- (il->stations[ret].used & IL_STA_UCODE_INPROGRESS)))) {
- IL_ERR("Requested station info for sta %d before ready.\n",
- ret);
- ret = IL_INVALID_STATION;
- }
- spin_unlock_irqrestore(&il->sta_lock, flags);
- return ret;
-}
-
-static int
-il4965_get_ra_sta_id(struct il_priv *il, struct ieee80211_hdr *hdr)
-{
- if (il->iw_mode == NL80211_IFTYPE_STATION) {
- return IL_AP_ID;
- } else {
- u8 *da = ieee80211_get_DA(hdr);
- return il4965_find_station(il, da);
- }
-}
-
-/**
- * il4965_hdl_tx - Handle standard (non-aggregation) Tx response
- */
-static void
-il4965_hdl_tx(struct il_priv *il, struct il_rx_buf *rxb)
-{
- struct il_rx_pkt *pkt = rxb_addr(rxb);
- u16 sequence = le16_to_cpu(pkt->hdr.sequence);
- int txq_id = SEQ_TO_QUEUE(sequence);
- int idx = SEQ_TO_IDX(sequence);
- struct il_tx_queue *txq = &il->txq[txq_id];
- struct sk_buff *skb;
- struct ieee80211_hdr *hdr;
- struct ieee80211_tx_info *info;
- struct il4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
- u32 status = le32_to_cpu(tx_resp->u.status);
- int uninitialized_var(tid);
- int sta_id;
- int freed;
- u8 *qc = NULL;
- unsigned long flags;
-
- if (idx >= txq->q.n_bd || il_queue_used(&txq->q, idx) == 0) {
- IL_ERR("Read idx for DMA queue txq_id (%d) idx %d "
- "is out of range [0-%d] %d %d\n", txq_id, idx,
- txq->q.n_bd, txq->q.write_ptr, txq->q.read_ptr);
- return;
- }
-
- txq->time_stamp = jiffies;
-
- skb = txq->skbs[txq->q.read_ptr];
- info = IEEE80211_SKB_CB(skb);
- memset(&info->status, 0, sizeof(info->status));
-
- hdr = (struct ieee80211_hdr *) skb->data;
- if (ieee80211_is_data_qos(hdr->frame_control)) {
- qc = ieee80211_get_qos_ctl(hdr);
- tid = qc[0] & 0xf;
- }
-
- sta_id = il4965_get_ra_sta_id(il, hdr);
- if (txq->sched_retry && unlikely(sta_id == IL_INVALID_STATION)) {
- IL_ERR("Station not known\n");
- return;
- }
-
- spin_lock_irqsave(&il->sta_lock, flags);
- if (txq->sched_retry) {
- const u32 scd_ssn = il4965_get_scd_ssn(tx_resp);
- struct il_ht_agg *agg = NULL;
- WARN_ON(!qc);
-
- agg = &il->stations[sta_id].tid[tid].agg;
-
- il4965_tx_status_reply_tx(il, agg, tx_resp, txq_id, idx);
-
- /* check if BAR is needed */
- if ((tx_resp->frame_count == 1) &&
- !il4965_is_tx_success(status))
- info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
-
- if (txq->q.read_ptr != (scd_ssn & 0xff)) {
- idx = il_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
- D_TX_REPLY("Retry scheduler reclaim scd_ssn "
- "%d idx %d\n", scd_ssn, idx);
- freed = il4965_tx_queue_reclaim(il, txq_id, idx);
- if (qc)
- il4965_free_tfds_in_queue(il, sta_id, tid,
- freed);
-
- if (il->mac80211_registered &&
- il_queue_space(&txq->q) > txq->q.low_mark &&
- agg->state != IL_EMPTYING_HW_QUEUE_DELBA)
- il_wake_queue(il, txq);
- }
- } else {
- info->status.rates[0].count = tx_resp->failure_frame + 1;
- info->flags |= il4965_tx_status_to_mac80211(status);
- il4965_hwrate_to_tx_control(il,
- le32_to_cpu(tx_resp->rate_n_flags),
- info);
-
- D_TX_REPLY("TXQ %d status %s (0x%08x) "
- "rate_n_flags 0x%x retries %d\n", txq_id,
- il4965_get_tx_fail_reason(status), status,
- le32_to_cpu(tx_resp->rate_n_flags),
- tx_resp->failure_frame);
-
- freed = il4965_tx_queue_reclaim(il, txq_id, idx);
- if (qc && likely(sta_id != IL_INVALID_STATION))
- il4965_free_tfds_in_queue(il, sta_id, tid, freed);
- else if (sta_id == IL_INVALID_STATION)
- D_TX_REPLY("Station not known\n");
-
- if (il->mac80211_registered &&
- il_queue_space(&txq->q) > txq->q.low_mark)
- il_wake_queue(il, txq);
- }
- if (qc && likely(sta_id != IL_INVALID_STATION))
- il4965_txq_check_empty(il, sta_id, tid, txq_id);
-
- il4965_check_abort_status(il, tx_resp->frame_count, status);
-
- spin_unlock_irqrestore(&il->sta_lock, flags);
-}
-
-/* Set up 4965-specific Rx frame reply handlers */
-static void
-il4965_handler_setup(struct il_priv *il)
-{
- /* Legacy Rx frames */
- il->handlers[N_RX] = il4965_hdl_rx;
- /* Tx response */
- il->handlers[C_TX] = il4965_hdl_tx;
-}
-
-static struct il_hcmd_ops il4965_hcmd = {
- .rxon_assoc = il4965_send_rxon_assoc,
- .commit_rxon = il4965_commit_rxon,
- .set_rxon_chain = il4965_set_rxon_chain,
-};
-
static void
il4965_post_scan(struct il_priv *il)
{
@@ -2093,8 +1772,8 @@ il4965_post_associate(struct il_priv *il)
il_set_rxon_ht(il, &il->current_ht_config);
- if (il->ops->hcmd->set_rxon_chain)
- il->ops->hcmd->set_rxon_chain(il);
+ if (il->ops->set_rxon_chain)
+ il->ops->set_rxon_chain(il);
il->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
@@ -2168,8 +1847,8 @@ il4965_config_ap(struct il_priv *il)
/* AP has all antennas */
il->chain_noise_data.active_chains = il->hw_params.valid_rx_ant;
il_set_rxon_ht(il, &il->current_ht_config);
- if (il->ops->hcmd->set_rxon_chain)
- il->ops->hcmd->set_rxon_chain(il);
+ if (il->ops->set_rxon_chain)
+ il->ops->set_rxon_chain(il);
il->staging.assoc_id = 0;
@@ -2193,68 +1872,38 @@ il4965_config_ap(struct il_priv *il)
il4965_send_beacon_cmd(il);
}
-static struct il_hcmd_utils_ops il4965_hcmd_utils = {
- .get_hcmd_size = il4965_get_hcmd_size,
- .build_addsta_hcmd = il4965_build_addsta_hcmd,
- .request_scan = il4965_request_scan,
- .post_scan = il4965_post_scan,
-};
-
-static struct il_lib_ops il4965_lib = {
+const struct il_ops il4965_ops = {
.txq_update_byte_cnt_tbl = il4965_txq_update_byte_cnt_tbl,
.txq_attach_buf_to_tfd = il4965_hw_txq_attach_buf_to_tfd,
.txq_free_tfd = il4965_hw_txq_free_tfd,
.txq_init = il4965_hw_tx_queue_init,
- .handler_setup = il4965_handler_setup,
.is_valid_rtc_data_addr = il4965_hw_valid_rtc_data_addr,
.init_alive_start = il4965_init_alive_start,
.load_ucode = il4965_load_bsm,
.dump_nic_error_log = il4965_dump_nic_error_log,
.dump_fh = il4965_dump_fh,
.set_channel_switch = il4965_hw_channel_switch,
- .apm_ops = {
- .init = il_apm_init,
- .config = il4965_nic_config,
- },
- .eeprom_ops = {
- .regulatory_bands = {
- EEPROM_REGULATORY_BAND_1_CHANNELS,
- EEPROM_REGULATORY_BAND_2_CHANNELS,
- EEPROM_REGULATORY_BAND_3_CHANNELS,
- EEPROM_REGULATORY_BAND_4_CHANNELS,
- EEPROM_REGULATORY_BAND_5_CHANNELS,
- EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS,
- EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS},
- .acquire_semaphore = il4965_eeprom_acquire_semaphore,
- .release_semaphore = il4965_eeprom_release_semaphore,
- },
+ .apm_init = il_apm_init,
.send_tx_power = il4965_send_tx_power,
.update_chain_flags = il4965_update_chain_flags,
- .temp_ops = {
- .temperature = il4965_temperature_calib,
- },
-#ifdef CONFIG_IWLEGACY_DEBUGFS
- .debugfs_ops = {
- .rx_stats_read = il4965_ucode_rx_stats_read,
- .tx_stats_read = il4965_ucode_tx_stats_read,
- .general_stats_read = il4965_ucode_general_stats_read,
- },
-#endif
-};
+ .eeprom_acquire_semaphore = il4965_eeprom_acquire_semaphore,
+ .eeprom_release_semaphore = il4965_eeprom_release_semaphore,
+
+ .rxon_assoc = il4965_send_rxon_assoc,
+ .commit_rxon = il4965_commit_rxon,
+ .set_rxon_chain = il4965_set_rxon_chain,
+
+ .get_hcmd_size = il4965_get_hcmd_size,
+ .build_addsta_hcmd = il4965_build_addsta_hcmd,
+ .request_scan = il4965_request_scan,
+ .post_scan = il4965_post_scan,
-static const struct il_legacy_ops il4965_legacy_ops = {
.post_associate = il4965_post_associate,
.config_ap = il4965_config_ap,
.manage_ibss_station = il4965_manage_ibss_station,
.update_bcast_stations = il4965_update_bcast_stations,
-};
-const struct il_ops il4965_ops = {
- .lib = &il4965_lib,
- .hcmd = &il4965_hcmd,
- .utils = &il4965_hcmd_utils,
- .led = &il4965_led_ops,
- .legacy = &il4965_legacy_ops,
+ .send_led_cmd = il4965_send_led_cmd,
};
struct il_cfg il4965_cfg = {
@@ -2288,6 +1937,17 @@ struct il_cfg il4965_cfg = {
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
+
+ .regulatory_bands = {
+ EEPROM_REGULATORY_BAND_1_CHANNELS,
+ EEPROM_REGULATORY_BAND_2_CHANNELS,
+ EEPROM_REGULATORY_BAND_3_CHANNELS,
+ EEPROM_REGULATORY_BAND_4_CHANNELS,
+ EEPROM_REGULATORY_BAND_5_CHANNELS,
+ EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS,
+ EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS
+ },
+
};
/* Module firmware */
diff --git a/drivers/net/wireless/iwlegacy/4965.h b/drivers/net/wireless/iwlegacy/4965.h
index 83ab6049638..208a4564d06 100644
--- a/drivers/net/wireless/iwlegacy/4965.h
+++ b/drivers/net/wireless/iwlegacy/4965.h
@@ -60,6 +60,8 @@ int il4965_rx_init(struct il_priv *il, struct il_rx_queue *rxq);
int il4965_hw_nic_init(struct il_priv *il);
int il4965_dump_fh(struct il_priv *il, char **buf, bool display);
+void il4965_nic_config(struct il_priv *il);
+
/* rx */
void il4965_rx_queue_restock(struct il_priv *il);
void il4965_rx_replenish(struct il_priv *il);
@@ -67,8 +69,6 @@ void il4965_rx_replenish_now(struct il_priv *il);
void il4965_rx_queue_free(struct il_priv *il, struct il_rx_queue *rxq);
int il4965_rxq_stop(struct il_priv *il);
int il4965_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
-void il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb);
-void il4965_hdl_rx_phy(struct il_priv *il, struct il_rx_buf *rxb);
void il4965_rx_handle(struct il_priv *il);
/* tx */
@@ -84,7 +84,6 @@ int il4965_tx_agg_start(struct il_priv *il, struct ieee80211_vif *vif,
int il4965_tx_agg_stop(struct il_priv *il, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid);
int il4965_txq_check_empty(struct il_priv *il, int sta_id, u8 tid, int txq_id);
-void il4965_hdl_compressed_ba(struct il_priv *il, struct il_rx_buf *rxb);
int il4965_tx_queue_reclaim(struct il_priv *il, int txq_id, int idx);
void il4965_hw_txq_ctx_free(struct il_priv *il);
int il4965_txq_ctx_alloc(struct il_priv *il);
@@ -106,12 +105,6 @@ void il4965_set_wr_ptrs(struct il_priv *il, int txq_id, u32 idx);
void il4965_tx_queue_set_status(struct il_priv *il, struct il_tx_queue *txq,
int tx_fifo_id, int scd_retry);
-/* rx */
-void il4965_hdl_missed_beacon(struct il_priv *il, struct il_rx_buf *rxb);
-bool il4965_good_plcp_health(struct il_priv *il, struct il_rx_pkt *pkt);
-void il4965_hdl_stats(struct il_priv *il, struct il_rx_buf *rxb);
-void il4965_hdl_c_stats(struct il_priv *il, struct il_rx_buf *rxb);
-
/* scan */
int il4965_request_scan(struct il_priv *il, struct ieee80211_vif *vif);
@@ -275,6 +268,7 @@ il4965_hw_valid_rtc_data_addr(u32 addr)
((t) < IL_TX_POWER_TEMPERATURE_MIN || \
(t) > IL_TX_POWER_TEMPERATURE_MAX)
+extern void il4965_temperature_calib(struct il_priv *il);
/********************* END TEMPERATURE ***************************************/
/********************* START TXPOWER *****************************************/
@@ -937,13 +931,7 @@ void il4965_calib_free_results(struct il_priv *il);
/* Debug */
#ifdef CONFIG_IWLEGACY_DEBUGFS
-ssize_t il4965_ucode_rx_stats_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos);
-ssize_t il4965_ucode_tx_stats_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos);
-ssize_t il4965_ucode_general_stats_read(struct file *file,
- char __user *user_buf, size_t count,
- loff_t *ppos);
+extern const struct il_debugfs_ops il4965_debugfs_ops;
#endif
/****************************/
diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c
index 04ec38e5eaa..b42052b47d8 100644
--- a/drivers/net/wireless/iwlegacy/common.c
+++ b/drivers/net/wireless/iwlegacy/common.c
@@ -81,7 +81,7 @@ il_clear_bit(struct il_priv *p, u32 r, u32 m)
}
EXPORT_SYMBOL(il_clear_bit);
-int
+bool
_il_grab_nic_access(struct il_priv *il)
{
int ret;
@@ -111,14 +111,15 @@ _il_grab_nic_access(struct il_priv *il)
_il_poll_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
(CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
- if (ret < 0) {
+ if (unlikely(ret < 0)) {
val = _il_rd(il, CSR_GP_CNTRL);
- IL_ERR("MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val);
+ WARN_ONCE(1, "Timeout waiting for ucode processor access "
+ "(CSR_GP_CNTRL 0x%08x)\n", val);
_il_wr(il, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
- return -EIO;
+ return false;
}
- return 0;
+ return true;
}
EXPORT_SYMBOL_GPL(_il_grab_nic_access);
@@ -160,7 +161,7 @@ il_wr_prph(struct il_priv *il, u32 addr, u32 val)
unsigned long reg_flags;
spin_lock_irqsave(&il->reg_lock, reg_flags);
- if (!_il_grab_nic_access(il)) {
+ if (likely(_il_grab_nic_access(il))) {
_il_wr_prph(il, addr, val);
_il_release_nic_access(il);
}
@@ -178,7 +179,6 @@ il_read_targ_mem(struct il_priv *il, u32 addr)
_il_grab_nic_access(il);
_il_wr(il, HBUS_TARG_MEM_RADDR, addr);
- rmb();
value = _il_rd(il, HBUS_TARG_MEM_RDAT);
_il_release_nic_access(il);
@@ -193,9 +193,8 @@ il_write_targ_mem(struct il_priv *il, u32 addr, u32 val)
unsigned long reg_flags;
spin_lock_irqsave(&il->reg_lock, reg_flags);
- if (!_il_grab_nic_access(il)) {
+ if (likely(_il_grab_nic_access(il))) {
_il_wr(il, HBUS_TARG_MEM_WADDR, addr);
- wmb();
_il_wr(il, HBUS_TARG_MEM_WDAT, val);
_il_release_nic_access(il);
}
@@ -351,7 +350,7 @@ il_send_cmd_sync(struct il_priv *il, struct il_host_cmd *cmd)
}
}
- if (test_bit(S_RF_KILL_HW, &il->status)) {
+ if (test_bit(S_RFKILL, &il->status)) {
IL_ERR("Command %s aborted: RF KILL Switch\n",
il_get_cmd_string(cmd->id));
ret = -ECANCELED;
@@ -520,7 +519,7 @@ il_led_cmd(struct il_priv *il, unsigned long on, unsigned long off)
il_blink_compensation(il, off,
il->cfg->led_compensation);
- ret = il->ops->led->cmd(il, &led_cmd);
+ ret = il->ops->send_led_cmd(il, &led_cmd);
if (!ret) {
il->blink_on = on;
il->blink_off = off;
@@ -731,7 +730,7 @@ il_eeprom_init(struct il_priv *il)
}
e = (__le16 *) il->eeprom;
- il->ops->lib->apm_ops.init(il);
+ il->ops->apm_init(il);
ret = il_eeprom_verify_signature(il);
if (ret < 0) {
@@ -741,7 +740,7 @@ il_eeprom_init(struct il_priv *il)
}
/* Make sure driver (instead of uCode) is allowed to read EEPROM */
- ret = il->ops->lib->eeprom_ops.acquire_semaphore(il);
+ ret = il->ops->eeprom_acquire_semaphore(il);
if (ret < 0) {
IL_ERR("Failed to acquire EEPROM semaphore.\n");
ret = -ENOENT;
@@ -773,7 +772,7 @@ il_eeprom_init(struct il_priv *il)
ret = 0;
done:
- il->ops->lib->eeprom_ops.release_semaphore(il);
+ il->ops->eeprom_release_semaphore(il);
err:
if (ret)
@@ -799,8 +798,8 @@ il_init_band_reference(const struct il_priv *il, int eep_band,
const struct il_eeprom_channel **eeprom_ch_info,
const u8 **eeprom_ch_idx)
{
- u32 offset =
- il->ops->lib->eeprom_ops.regulatory_bands[eep_band - 1];
+ u32 offset = il->cfg->regulatory_bands[eep_band - 1];
+
switch (eep_band) {
case 1: /* 2.4GHz band */
*eeprom_ch_count = ARRAY_SIZE(il_eeprom_band_1);
@@ -1001,10 +1000,8 @@ il_init_channel_map(struct il_priv *il)
}
/* Check if we do have HT40 channels */
- if (il->ops->lib->eeprom_ops.regulatory_bands[5] ==
- EEPROM_REGULATORY_BAND_NO_HT40 &&
- il->ops->lib->eeprom_ops.regulatory_bands[6] ==
- EEPROM_REGULATORY_BAND_NO_HT40)
+ if (il->cfg->regulatory_bands[5] == EEPROM_REGULATORY_BAND_NO_HT40 &&
+ il->cfg->regulatory_bands[6] == EEPROM_REGULATORY_BAND_NO_HT40)
return 0;
/* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */
@@ -1158,9 +1155,9 @@ il_power_set_mode(struct il_priv *il, struct il_powertable_cmd *cmd, bool force)
if (!(cmd->flags & IL_POWER_DRIVER_ALLOW_SLEEP_MSK))
clear_bit(S_POWER_PMI, &il->status);
- if (il->ops->lib->update_chain_flags && update_chains)
- il->ops->lib->update_chain_flags(il);
- else if (il->ops->lib->update_chain_flags)
+ if (il->ops->update_chain_flags && update_chains)
+ il->ops->update_chain_flags(il);
+ else if (il->ops->update_chain_flags)
D_POWER("Cannot update the power, chain noise "
"calibration running: %d\n",
il->chain_noise_data.state);
@@ -1485,9 +1482,6 @@ il_scan_initiate(struct il_priv *il, struct ieee80211_vif *vif)
lockdep_assert_held(&il->mutex);
- if (WARN_ON(!il->ops->utils->request_scan))
- return -EOPNOTSUPP;
-
cancel_delayed_work(&il->scan_check);
if (!il_is_ready_rf(il)) {
@@ -1510,7 +1504,7 @@ il_scan_initiate(struct il_priv *il, struct ieee80211_vif *vif)
set_bit(S_SCANNING, &il->status);
il->scan_start = jiffies;
- ret = il->ops->utils->request_scan(il, vif);
+ ret = il->ops->request_scan(il, vif);
if (ret) {
clear_bit(S_SCANNING, &il->status);
return ret;
@@ -1529,12 +1523,13 @@ il_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct il_priv *il = hw->priv;
int ret;
- D_MAC80211("enter\n");
-
- if (req->n_channels == 0)
+ if (req->n_channels == 0) {
+ IL_ERR("Can not scan on no channels.\n");
return -EINVAL;
+ }
mutex_lock(&il->mutex);
+ D_MAC80211("enter\n");
if (test_bit(S_SCANNING, &il->status)) {
D_SCAN("Scan already in progress.\n");
@@ -1549,9 +1544,8 @@ il_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
ret = il_scan_initiate(il, vif);
- D_MAC80211("leave\n");
-
out_unlock:
+ D_MAC80211("leave ret %d\n", ret);
mutex_unlock(&il->mutex);
return ret;
@@ -1672,7 +1666,7 @@ out_settings:
il_power_set_mode(il, &il->power_data.sleep_cmd_next, false);
il_set_tx_power(il, il->tx_power_next, false);
- il->ops->utils->post_scan(il);
+ il->ops->post_scan(il);
out:
mutex_unlock(&il->mutex);
@@ -1814,7 +1808,7 @@ il_send_add_sta(struct il_priv *il, struct il_addsta_cmd *sta, u8 flags)
might_sleep();
}
- cmd.len = il->ops->utils->build_addsta_hcmd(sta, data);
+ cmd.len = il->ops->build_addsta_hcmd(sta, data);
ret = il_send_cmd(il, &cmd);
if (ret || (flags & CMD_ASYNC))
@@ -2419,13 +2413,16 @@ il_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct il_station_priv_common *sta_common = (void *)sta->drv_priv;
int ret;
- D_INFO("received request to remove station %pM\n", sta->addr);
mutex_lock(&il->mutex);
- D_INFO("proceeding to remove station %pM\n", sta->addr);
+ D_MAC80211("enter station %pM\n", sta->addr);
+
ret = il_remove_station(il, sta_common->sta_id, sta->addr);
if (ret)
IL_ERR("Error removing station %pM\n", sta->addr);
+
+ D_MAC80211("leave ret %d\n", ret);
mutex_unlock(&il->mutex);
+
return ret;
}
EXPORT_SYMBOL(il_mac_sta_remove);
@@ -2722,7 +2719,7 @@ il_tx_queue_unmap(struct il_priv *il, int txq_id)
return;
while (q->write_ptr != q->read_ptr) {
- il->ops->lib->txq_free_tfd(il, txq);
+ il->ops->txq_free_tfd(il, txq);
q->read_ptr = il_queue_inc_wrap(q->read_ptr, q->n_bd);
}
}
@@ -2890,20 +2887,22 @@ EXPORT_SYMBOL(il_queue_space);
* il_queue_init - Initialize queue's high/low-water and read/write idxes
*/
static int
-il_queue_init(struct il_priv *il, struct il_queue *q, int count, int slots_num,
- u32 id)
+il_queue_init(struct il_priv *il, struct il_queue *q, int slots, u32 id)
{
- q->n_bd = count;
- q->n_win = slots_num;
- q->id = id;
+ /*
+ * TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+ * il_queue_inc_wrap and il_queue_dec_wrap are broken.
+ */
+ BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+ /* FIXME: remove q->n_bd */
+ q->n_bd = TFD_QUEUE_SIZE_MAX;
- /* count must be power-of-two size, otherwise il_queue_inc_wrap
- * and il_queue_dec_wrap are broken. */
- BUG_ON(!is_power_of_2(count));
+ q->n_win = slots;
+ q->id = id;
- /* slots_num must be power-of-two size, otherwise
+ /* slots_must be power-of-two size, otherwise
* il_get_cmd_idx is broken. */
- BUG_ON(!is_power_of_2(slots_num));
+ BUG_ON(!is_power_of_2(slots));
q->low_mark = q->n_win / 4;
if (q->low_mark < 4)
@@ -2962,12 +2961,11 @@ error:
* il_tx_queue_init - Allocate and initialize one tx/cmd queue
*/
int
-il_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq, int slots_num,
- u32 txq_id)
+il_tx_queue_init(struct il_priv *il, u32 txq_id)
{
- int i, len;
- int ret;
- int actual_slots = slots_num;
+ int i, len, ret;
+ int slots, actual_slots;
+ struct il_tx_queue *txq = &il->txq[txq_id];
/*
* Alloc buffer array for commands (Tx or other types of commands).
@@ -2977,8 +2975,13 @@ il_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq, int slots_num,
* For normal Tx queues (all other queues), no super-size command
* space is needed.
*/
- if (txq_id == il->cmd_queue)
- actual_slots++;
+ if (txq_id == il->cmd_queue) {
+ slots = TFD_CMD_SLOTS;
+ actual_slots = slots + 1;
+ } else {
+ slots = TFD_TX_CMD_SLOTS;
+ actual_slots = slots;
+ }
txq->meta =
kzalloc(sizeof(struct il_cmd_meta) * actual_slots, GFP_KERNEL);
@@ -2991,7 +2994,7 @@ il_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq, int slots_num,
len = sizeof(struct il_device_cmd);
for (i = 0; i < actual_slots; i++) {
/* only happens for cmd queue */
- if (i == slots_num)
+ if (i == slots)
len = IL_MAX_CMD_SIZE;
txq->cmd[i] = kmalloc(len, GFP_KERNEL);
@@ -3014,15 +3017,11 @@ il_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq, int slots_num,
if (txq_id < 4)
il_set_swq_id(txq, txq_id, txq_id);
- /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
- * il_queue_inc_wrap and il_queue_dec_wrap are broken. */
- BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
-
/* Initialize queue's high/low-water marks, and head/tail idxes */
- il_queue_init(il, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+ il_queue_init(il, &txq->q, slots, txq_id);
/* Tell device where to find queue */
- il->ops->lib->txq_init(il, txq);
+ il->ops->txq_init(il, txq);
return 0;
err:
@@ -3037,23 +3036,27 @@ out_free_arrays:
EXPORT_SYMBOL(il_tx_queue_init);
void
-il_tx_queue_reset(struct il_priv *il, struct il_tx_queue *txq, int slots_num,
- u32 txq_id)
+il_tx_queue_reset(struct il_priv *il, u32 txq_id)
{
- int actual_slots = slots_num;
+ int slots, actual_slots;
+ struct il_tx_queue *txq = &il->txq[txq_id];
- if (txq_id == il->cmd_queue)
- actual_slots++;
+ if (txq_id == il->cmd_queue) {
+ slots = TFD_CMD_SLOTS;
+ actual_slots = TFD_CMD_SLOTS + 1;
+ } else {
+ slots = TFD_TX_CMD_SLOTS;
+ actual_slots = TFD_TX_CMD_SLOTS;
+ }
memset(txq->meta, 0, sizeof(struct il_cmd_meta) * actual_slots);
-
txq->need_update = 0;
/* Initialize queue's high/low-water marks, and head/tail idxes */
- il_queue_init(il, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+ il_queue_init(il, &txq->q, slots, txq_id);
/* Tell device where to find queue */
- il->ops->lib->txq_init(il, txq);
+ il->ops->txq_init(il, txq);
}
EXPORT_SYMBOL(il_tx_queue_reset);
@@ -3081,7 +3084,7 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd)
u32 idx;
u16 fix_size;
- cmd->len = il->ops->utils->get_hcmd_size(cmd->id, cmd->len);
+ cmd->len = il->ops->get_hcmd_size(cmd->id, cmd->len);
fix_size = (u16) (cmd->len + sizeof(out_cmd->hdr));
/* If any of the command structures end up being larger than
@@ -3160,9 +3163,9 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd)
#endif
txq->need_update = 1;
- if (il->ops->lib->txq_update_byte_cnt_tbl)
+ if (il->ops->txq_update_byte_cnt_tbl)
/* Set up entry in queue's byte count circular buffer */
- il->ops->lib->txq_update_byte_cnt_tbl(il, txq, 0);
+ il->ops->txq_update_byte_cnt_tbl(il, txq, 0);
phys_addr =
pci_map_single(il->pci_dev, &out_cmd->hdr, fix_size,
@@ -3170,7 +3173,7 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd)
dma_unmap_addr_set(out_meta, mapping, phys_addr);
dma_unmap_len_set(out_meta, len, fix_size);
- il->ops->lib->txq_attach_buf_to_tfd(il, txq, phys_addr, fix_size, 1,
+ il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, fix_size, 1,
U32_PAD(cmd->len));
/* Increment and update queue's write idx */
@@ -3845,8 +3848,8 @@ _il_set_rxon_ht(struct il_priv *il, struct il_ht_config *ht_conf)
rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY;
}
- if (il->ops->hcmd->set_rxon_chain)
- il->ops->hcmd->set_rxon_chain(il);
+ if (il->ops->set_rxon_chain)
+ il->ops->set_rxon_chain(il);
D_ASSOC("rxon flags 0x%X operation mode :0x%X "
"extension channel offset 0x%x\n", le32_to_cpu(rxon->flags),
@@ -4104,9 +4107,9 @@ il_irq_handle_error(struct il_priv *il)
IL_ERR("Loaded firmware version: %s\n", il->hw->wiphy->fw_version);
- il->ops->lib->dump_nic_error_log(il);
- if (il->ops->lib->dump_fh)
- il->ops->lib->dump_fh(il, NULL, false);
+ il->ops->dump_nic_error_log(il);
+ if (il->ops->dump_fh)
+ il->ops->dump_fh(il, NULL, false);
#ifdef CONFIG_IWLEGACY_DEBUG
if (il_get_debug_level(il) & IL_DL_FW_ERRORS)
il_print_rx_config_cmd(il);
@@ -4129,17 +4132,17 @@ il_irq_handle_error(struct il_priv *il)
EXPORT_SYMBOL(il_irq_handle_error);
static int
-il_apm_stop_master(struct il_priv *il)
+_il_apm_stop_master(struct il_priv *il)
{
int ret = 0;
/* stop device's busmaster DMA activity */
- il_set_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+ _il_set_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
ret =
_il_poll_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED,
CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
- if (ret)
+ if (ret < 0)
IL_WARN("Master Disable Timed Out, 100 usec\n");
D_INFO("stop master\n");
@@ -4148,15 +4151,17 @@ il_apm_stop_master(struct il_priv *il)
}
void
-il_apm_stop(struct il_priv *il)
+_il_apm_stop(struct il_priv *il)
{
+ lockdep_assert_held(&il->reg_lock);
+
D_INFO("Stop card, put in low power state\n");
/* Stop device's DMA activity */
- il_apm_stop_master(il);
+ _il_apm_stop_master(il);
/* Reset the entire device */
- il_set_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+ _il_set_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
udelay(10);
@@ -4164,7 +4169,18 @@ il_apm_stop(struct il_priv *il)
* Clear "initialization complete" bit to move adapter from
* D0A* (powered-up Active) --> D0U* (Uninitialized) state.
*/
- il_clear_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ _il_clear_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+}
+EXPORT_SYMBOL(_il_apm_stop);
+
+void
+il_apm_stop(struct il_priv *il)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&il->reg_lock, flags);
+ _il_apm_stop(il);
+ spin_unlock_irqrestore(&il->reg_lock, flags);
}
EXPORT_SYMBOL(il_apm_stop);
@@ -4293,7 +4309,7 @@ il_set_tx_power(struct il_priv *il, s8 tx_power, bool force)
if (il->tx_power_user_lmt == tx_power && !force)
return 0;
- if (!il->ops->lib->send_tx_power)
+ if (!il->ops->send_tx_power)
return -EOPNOTSUPP;
/* 0 dBm mean 1 milliwatt */
@@ -4326,7 +4342,7 @@ il_set_tx_power(struct il_priv *il, s8 tx_power, bool force)
prev_tx_power = il->tx_power_user_lmt;
il->tx_power_user_lmt = tx_power;
- ret = il->ops->lib->send_tx_power(il);
+ ret = il->ops->send_tx_power(il);
/* if fail to set tx_power, restore the orig. tx power */
if (ret) {
@@ -4465,8 +4481,14 @@ int
il_mac_tx_last_beacon(struct ieee80211_hw *hw)
{
struct il_priv *il = hw->priv;
+ int ret;
- return il->ibss_manager == IL_IBSS_MANAGER;
+ D_MAC80211("enter\n");
+
+ ret = (il->ibss_manager == IL_IBSS_MANAGER);
+
+ D_MAC80211("leave ret %d\n", ret);
+ return ret;
}
EXPORT_SYMBOL_GPL(il_mac_tx_last_beacon);
@@ -4475,8 +4497,8 @@ il_set_mode(struct il_priv *il)
{
il_connection_init_rx_config(il);
- if (il->ops->hcmd->set_rxon_chain)
- il->ops->hcmd->set_rxon_chain(il);
+ if (il->ops->set_rxon_chain)
+ il->ops->set_rxon_chain(il);
return il_commit_rxon(il);
}
@@ -4487,9 +4509,8 @@ il_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
struct il_priv *il = hw->priv;
int err;
- D_MAC80211("enter: type %d, addr %pM\n", vif->type, vif->addr);
-
mutex_lock(&il->mutex);
+ D_MAC80211("enter: type %d, addr %pM\n", vif->type, vif->addr);
if (!il_is_ready_rf(il)) {
IL_WARN("Try to add interface when device not ready\n");
@@ -4512,9 +4533,9 @@ il_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
}
out:
+ D_MAC80211("leave err %d\n", err);
mutex_unlock(&il->mutex);
- D_MAC80211("leave\n");
return err;
}
EXPORT_SYMBOL(il_mac_add_interface);
@@ -4540,20 +4561,17 @@ il_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct il_priv *il = hw->priv;
- D_MAC80211("enter\n");
-
mutex_lock(&il->mutex);
+ D_MAC80211("enter: type %d, addr %pM\n", vif->type, vif->addr);
WARN_ON(il->vif != vif);
il->vif = NULL;
il_teardown_interface(il, vif, false);
-
memset(il->bssid, 0, ETH_ALEN);
- mutex_unlock(&il->mutex);
D_MAC80211("leave\n");
-
+ mutex_unlock(&il->mutex);
}
EXPORT_SYMBOL(il_mac_remove_interface);
@@ -4573,259 +4591,12 @@ il_alloc_txq_mem(struct il_priv *il)
EXPORT_SYMBOL(il_alloc_txq_mem);
void
-il_txq_mem(struct il_priv *il)
+il_free_txq_mem(struct il_priv *il)
{
kfree(il->txq);
il->txq = NULL;
}
-EXPORT_SYMBOL(il_txq_mem);
-
-#ifdef CONFIG_IWLEGACY_DEBUGFS
-
-#define IL_TRAFFIC_DUMP_SIZE (IL_TRAFFIC_ENTRY_SIZE * IL_TRAFFIC_ENTRIES)
-
-void
-il_reset_traffic_log(struct il_priv *il)
-{
- il->tx_traffic_idx = 0;
- il->rx_traffic_idx = 0;
- if (il->tx_traffic)
- memset(il->tx_traffic, 0, IL_TRAFFIC_DUMP_SIZE);
- if (il->rx_traffic)
- memset(il->rx_traffic, 0, IL_TRAFFIC_DUMP_SIZE);
-}
-
-int
-il_alloc_traffic_mem(struct il_priv *il)
-{
- u32 traffic_size = IL_TRAFFIC_DUMP_SIZE;
-
- if (il_debug_level & IL_DL_TX) {
- if (!il->tx_traffic) {
- il->tx_traffic = kzalloc(traffic_size, GFP_KERNEL);
- if (!il->tx_traffic)
- return -ENOMEM;
- }
- }
- if (il_debug_level & IL_DL_RX) {
- if (!il->rx_traffic) {
- il->rx_traffic = kzalloc(traffic_size, GFP_KERNEL);
- if (!il->rx_traffic)
- return -ENOMEM;
- }
- }
- il_reset_traffic_log(il);
- return 0;
-}
-EXPORT_SYMBOL(il_alloc_traffic_mem);
-
-void
-il_free_traffic_mem(struct il_priv *il)
-{
- kfree(il->tx_traffic);
- il->tx_traffic = NULL;
-
- kfree(il->rx_traffic);
- il->rx_traffic = NULL;
-}
-EXPORT_SYMBOL(il_free_traffic_mem);
-
-void
-il_dbg_log_tx_data_frame(struct il_priv *il, u16 length,
- struct ieee80211_hdr *header)
-{
- __le16 fc;
- u16 len;
-
- if (likely(!(il_debug_level & IL_DL_TX)))
- return;
-
- if (!il->tx_traffic)
- return;
-
- fc = header->frame_control;
- if (ieee80211_is_data(fc)) {
- len =
- (length >
- IL_TRAFFIC_ENTRY_SIZE) ? IL_TRAFFIC_ENTRY_SIZE : length;
- memcpy((il->tx_traffic +
- (il->tx_traffic_idx * IL_TRAFFIC_ENTRY_SIZE)), header,
- len);
- il->tx_traffic_idx =
- (il->tx_traffic_idx + 1) % IL_TRAFFIC_ENTRIES;
- }
-}
-EXPORT_SYMBOL(il_dbg_log_tx_data_frame);
-
-void
-il_dbg_log_rx_data_frame(struct il_priv *il, u16 length,
- struct ieee80211_hdr *header)
-{
- __le16 fc;
- u16 len;
-
- if (likely(!(il_debug_level & IL_DL_RX)))
- return;
-
- if (!il->rx_traffic)
- return;
-
- fc = header->frame_control;
- if (ieee80211_is_data(fc)) {
- len =
- (length >
- IL_TRAFFIC_ENTRY_SIZE) ? IL_TRAFFIC_ENTRY_SIZE : length;
- memcpy((il->rx_traffic +
- (il->rx_traffic_idx * IL_TRAFFIC_ENTRY_SIZE)), header,
- len);
- il->rx_traffic_idx =
- (il->rx_traffic_idx + 1) % IL_TRAFFIC_ENTRIES;
- }
-}
-EXPORT_SYMBOL(il_dbg_log_rx_data_frame);
-
-const char *
-il_get_mgmt_string(int cmd)
-{
- switch (cmd) {
- IL_CMD(MANAGEMENT_ASSOC_REQ);
- IL_CMD(MANAGEMENT_ASSOC_RESP);
- IL_CMD(MANAGEMENT_REASSOC_REQ);
- IL_CMD(MANAGEMENT_REASSOC_RESP);
- IL_CMD(MANAGEMENT_PROBE_REQ);
- IL_CMD(MANAGEMENT_PROBE_RESP);
- IL_CMD(MANAGEMENT_BEACON);
- IL_CMD(MANAGEMENT_ATIM);
- IL_CMD(MANAGEMENT_DISASSOC);
- IL_CMD(MANAGEMENT_AUTH);
- IL_CMD(MANAGEMENT_DEAUTH);
- IL_CMD(MANAGEMENT_ACTION);
- default:
- return "UNKNOWN";
-
- }
-}
-
-const char *
-il_get_ctrl_string(int cmd)
-{
- switch (cmd) {
- IL_CMD(CONTROL_BACK_REQ);
- IL_CMD(CONTROL_BACK);
- IL_CMD(CONTROL_PSPOLL);
- IL_CMD(CONTROL_RTS);
- IL_CMD(CONTROL_CTS);
- IL_CMD(CONTROL_ACK);
- IL_CMD(CONTROL_CFEND);
- IL_CMD(CONTROL_CFENDACK);
- default:
- return "UNKNOWN";
-
- }
-}
-
-void
-il_clear_traffic_stats(struct il_priv *il)
-{
- memset(&il->tx_stats, 0, sizeof(struct traffic_stats));
- memset(&il->rx_stats, 0, sizeof(struct traffic_stats));
-}
-
-/*
- * if CONFIG_IWLEGACY_DEBUGFS defined,
- * il_update_stats function will
- * record all the MGMT, CTRL and DATA pkt for both TX and Rx pass
- * Use debugFs to display the rx/rx_stats
- * if CONFIG_IWLEGACY_DEBUGFS not being defined, then no MGMT and CTRL
- * information will be recorded, but DATA pkt still will be recorded
- * for the reason of il_led.c need to control the led blinking based on
- * number of tx and rx data.
- *
- */
-void
-il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len)
-{
- struct traffic_stats *stats;
-
- if (is_tx)
- stats = &il->tx_stats;
- else
- stats = &il->rx_stats;
-
- if (ieee80211_is_mgmt(fc)) {
- switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
- case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
- stats->mgmt[MANAGEMENT_ASSOC_REQ]++;
- break;
- case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
- stats->mgmt[MANAGEMENT_ASSOC_RESP]++;
- break;
- case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
- stats->mgmt[MANAGEMENT_REASSOC_REQ]++;
- break;
- case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
- stats->mgmt[MANAGEMENT_REASSOC_RESP]++;
- break;
- case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
- stats->mgmt[MANAGEMENT_PROBE_REQ]++;
- break;
- case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
- stats->mgmt[MANAGEMENT_PROBE_RESP]++;
- break;
- case cpu_to_le16(IEEE80211_STYPE_BEACON):
- stats->mgmt[MANAGEMENT_BEACON]++;
- break;
- case cpu_to_le16(IEEE80211_STYPE_ATIM):
- stats->mgmt[MANAGEMENT_ATIM]++;
- break;
- case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
- stats->mgmt[MANAGEMENT_DISASSOC]++;
- break;
- case cpu_to_le16(IEEE80211_STYPE_AUTH):
- stats->mgmt[MANAGEMENT_AUTH]++;
- break;
- case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
- stats->mgmt[MANAGEMENT_DEAUTH]++;
- break;
- case cpu_to_le16(IEEE80211_STYPE_ACTION):
- stats->mgmt[MANAGEMENT_ACTION]++;
- break;
- }
- } else if (ieee80211_is_ctl(fc)) {
- switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
- case cpu_to_le16(IEEE80211_STYPE_BACK_REQ):
- stats->ctrl[CONTROL_BACK_REQ]++;
- break;
- case cpu_to_le16(IEEE80211_STYPE_BACK):
- stats->ctrl[CONTROL_BACK]++;
- break;
- case cpu_to_le16(IEEE80211_STYPE_PSPOLL):
- stats->ctrl[CONTROL_PSPOLL]++;
- break;
- case cpu_to_le16(IEEE80211_STYPE_RTS):
- stats->ctrl[CONTROL_RTS]++;
- break;
- case cpu_to_le16(IEEE80211_STYPE_CTS):
- stats->ctrl[CONTROL_CTS]++;
- break;
- case cpu_to_le16(IEEE80211_STYPE_ACK):
- stats->ctrl[CONTROL_ACK]++;
- break;
- case cpu_to_le16(IEEE80211_STYPE_CFEND):
- stats->ctrl[CONTROL_CFEND]++;
- break;
- case cpu_to_le16(IEEE80211_STYPE_CFENDACK):
- stats->ctrl[CONTROL_CFENDACK]++;
- break;
- }
- } else {
- /* data */
- stats->data_cnt++;
- stats->data_bytes += len;
- }
-}
-EXPORT_SYMBOL(il_update_stats);
-#endif
+EXPORT_SYMBOL(il_free_txq_mem);
int
il_force_reset(struct il_priv *il, bool external)
@@ -4886,10 +4657,14 @@ il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct il_priv *il = hw->priv;
int err;
- if (newp2p)
- return -EOPNOTSUPP;
-
mutex_lock(&il->mutex);
+ D_MAC80211("enter: type %d, addr %pM newtype %d newp2p %d\n",
+ vif->type, vif->addr, newtype, newp2p);
+
+ if (newp2p) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
if (!il->vif || !il_is_ready_rf(il)) {
/*
@@ -4916,7 +4691,9 @@ il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
err = 0;
out:
+ D_MAC80211("leave err %d\n", err);
mutex_unlock(&il->mutex);
+
return err;
}
EXPORT_SYMBOL(il_mac_change_interface);
@@ -5113,9 +4890,9 @@ il_pci_resume(struct device *device)
hw_rfkill = true;
if (hw_rfkill)
- set_bit(S_RF_KILL_HW, &il->status);
+ set_bit(S_RFKILL, &il->status);
else
- clear_bit(S_RF_KILL_HW, &il->status);
+ clear_bit(S_RFKILL, &il->status);
wiphy_rfkill_set_hw_state(il->hw->wiphy, hw_rfkill);
@@ -5174,12 +4951,8 @@ il_mac_config(struct ieee80211_hw *hw, u32 changed)
int scan_active = 0;
bool ht_changed = false;
- if (WARN_ON(!il->ops->legacy))
- return -EOPNOTSUPP;
-
mutex_lock(&il->mutex);
-
- D_MAC80211("enter to channel %d changed 0x%X\n", channel->hw_value,
+ D_MAC80211("enter: channel %d changed 0x%X\n", channel->hw_value,
changed);
if (unlikely(test_bit(S_SCANNING, &il->status))) {
@@ -5199,8 +4972,8 @@ il_mac_config(struct ieee80211_hw *hw, u32 changed)
* set up the SM PS mode to OFF if an HT channel is
* configured.
*/
- if (il->ops->hcmd->set_rxon_chain)
- il->ops->hcmd->set_rxon_chain(il);
+ if (il->ops->set_rxon_chain)
+ il->ops->set_rxon_chain(il);
}
/* during scanning mac80211 will delay channel setting until
@@ -5269,8 +5042,8 @@ il_mac_config(struct ieee80211_hw *hw, u32 changed)
spin_unlock_irqrestore(&il->lock, flags);
- if (il->ops->legacy->update_bcast_stations)
- ret = il->ops->legacy->update_bcast_stations(il);
+ if (il->ops->update_bcast_stations)
+ ret = il->ops->update_bcast_stations(il);
set_ch_out:
/* The list of supported rates and rate mask can be different
@@ -5308,8 +5081,9 @@ set_ch_out:
il_update_qos(il);
out:
- D_MAC80211("leave\n");
+ D_MAC80211("leave ret %d\n", ret);
mutex_unlock(&il->mutex);
+
return ret;
}
EXPORT_SYMBOL(il_mac_config);
@@ -5320,24 +5094,17 @@ il_mac_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
struct il_priv *il = hw->priv;
unsigned long flags;
- if (WARN_ON(!il->ops->legacy))
- return;
-
mutex_lock(&il->mutex);
- D_MAC80211("enter\n");
+ D_MAC80211("enter: type %d, addr %pM\n", vif->type, vif->addr);
spin_lock_irqsave(&il->lock, flags);
- memset(&il->current_ht_config, 0, sizeof(struct il_ht_config));
- spin_unlock_irqrestore(&il->lock, flags);
- spin_lock_irqsave(&il->lock, flags);
+ memset(&il->current_ht_config, 0, sizeof(struct il_ht_config));
/* new association get rid of ibss beacon skb */
if (il->beacon_skb)
dev_kfree_skb(il->beacon_skb);
-
il->beacon_skb = NULL;
-
il->timestamp = 0;
spin_unlock_irqrestore(&il->lock, flags);
@@ -5349,17 +5116,14 @@ il_mac_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
return;
}
- /* we are restarting association process
- * clear RXON_FILTER_ASSOC_MSK bit
- */
+ /* we are restarting association process */
il->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
il_commit_rxon(il);
il_set_rate(il);
- mutex_unlock(&il->mutex);
-
D_MAC80211("leave\n");
+ mutex_unlock(&il->mutex);
}
EXPORT_SYMBOL(il_mac_reset_tsf);
@@ -5475,7 +5239,7 @@ il_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
return;
}
- il->ops->legacy->post_associate(il);
+ il->ops->post_associate(il);
}
void
@@ -5485,14 +5249,11 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct il_priv *il = hw->priv;
int ret;
- if (WARN_ON(!il->ops->legacy))
- return;
-
- D_MAC80211("changes = 0x%X\n", changes);
-
mutex_lock(&il->mutex);
+ D_MAC80211("enter: changes 0x%x\n", changes);
if (!il_is_alive(il)) {
+ D_MAC80211("leave - not alive\n");
mutex_unlock(&il->mutex);
return;
}
@@ -5523,8 +5284,7 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
* below/in post_associate will fail.
*/
if (il_scan_cancel_timeout(il, 100)) {
- IL_WARN("Aborted scan still in progress after 100ms\n");
- D_MAC80211("leaving - scan abort failed.\n");
+ D_MAC80211("leave - scan abort failed\n");
mutex_unlock(&il->mutex);
return;
}
@@ -5536,10 +5296,8 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
/* currently needed in a few places */
memcpy(il->bssid, bss_conf->bssid, ETH_ALEN);
- } else {
+ } else
il->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- }
-
}
/*
@@ -5590,8 +5348,8 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (changes & BSS_CHANGED_HT) {
il_ht_conf(il, vif);
- if (il->ops->hcmd->set_rxon_chain)
- il->ops->hcmd->set_rxon_chain(il);
+ if (il->ops->set_rxon_chain)
+ il->ops->set_rxon_chain(il);
}
if (changes & BSS_CHANGED_ASSOC) {
@@ -5600,7 +5358,7 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
il->timestamp = bss_conf->timestamp;
if (!il_is_rfkill(il))
- il->ops->legacy->post_associate(il);
+ il->ops->post_associate(il);
} else
il_set_no_assoc(il, vif);
}
@@ -5620,24 +5378,22 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
memcpy(il->staging.bssid_addr, bss_conf->bssid,
ETH_ALEN);
memcpy(il->bssid, bss_conf->bssid, ETH_ALEN);
- il->ops->legacy->config_ap(il);
+ il->ops->config_ap(il);
} else
il_set_no_assoc(il, vif);
}
if (changes & BSS_CHANGED_IBSS) {
- ret =
- il->ops->legacy->manage_ibss_station(il, vif,
- bss_conf->ibss_joined);
+ ret = il->ops->manage_ibss_station(il, vif,
+ bss_conf->ibss_joined);
if (ret)
IL_ERR("failed to %s IBSS station %pM\n",
bss_conf->ibss_joined ? "add" : "remove",
bss_conf->bssid);
}
- mutex_unlock(&il->mutex);
-
D_MAC80211("leave\n");
+ mutex_unlock(&il->mutex);
}
EXPORT_SYMBOL(il_mac_bss_info_changed);
diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h
index 708095644f1..6ed9871f1c4 100644
--- a/drivers/net/wireless/iwlegacy/common.h
+++ b/drivers/net/wireless/iwlegacy/common.h
@@ -425,12 +425,6 @@ struct il_eeprom_calib_info {
#define EEPROM_REGULATORY_BAND_NO_HT40 (0)
-struct il_eeprom_ops {
- const u32 regulatory_bands[7];
- int (*acquire_semaphore) (struct il_priv *il);
- void (*release_semaphore) (struct il_priv *il);
-};
-
int il_eeprom_init(struct il_priv *il);
void il_eeprom_free(struct il_priv *il);
const u8 *il_eeprom_query_addr(const struct il_priv *il, size_t offset);
@@ -1156,13 +1150,15 @@ struct il_power_mgr {
};
struct il_priv {
-
- /* ieee device used by generic ieee processing code */
struct ieee80211_hw *hw;
struct ieee80211_channel *ieee_channels;
struct ieee80211_rate *ieee_rates;
+
struct il_cfg *cfg;
const struct il_ops *ops;
+#ifdef CONFIG_IWLEGACY_DEBUGFS
+ const struct il_debugfs_ops *debugfs_ops;
+#endif
/* temporary frame storage list */
struct list_head free_frames;
@@ -1557,24 +1553,6 @@ il_free_pages(struct il_priv *il, unsigned long page)
#define IL_RX_BUF_SIZE_4K (4 * 1024)
#define IL_RX_BUF_SIZE_8K (8 * 1024)
-struct il_hcmd_ops {
- int (*rxon_assoc) (struct il_priv *il);
- int (*commit_rxon) (struct il_priv *il);
- void (*set_rxon_chain) (struct il_priv *il);
-};
-
-struct il_hcmd_utils_ops {
- u16(*get_hcmd_size) (u8 cmd_id, u16 len);
- u16(*build_addsta_hcmd) (const struct il_addsta_cmd *cmd, u8 *data);
- int (*request_scan) (struct il_priv *il, struct ieee80211_vif *vif);
- void (*post_scan) (struct il_priv *il);
-};
-
-struct il_apm_ops {
- int (*init) (struct il_priv *il);
- void (*config) (struct il_priv *il);
-};
-
#ifdef CONFIG_IWLEGACY_DEBUGFS
struct il_debugfs_ops {
ssize_t(*rx_stats_read) (struct file *file, char __user *user_buf,
@@ -1587,11 +1565,7 @@ struct il_debugfs_ops {
};
#endif
-struct il_temp_ops {
- void (*temperature) (struct il_priv *il);
-};
-
-struct il_lib_ops {
+struct il_ops {
/* Handling TX */
void (*txq_update_byte_cnt_tbl) (struct il_priv *il,
struct il_tx_queue *txq,
@@ -1601,8 +1575,6 @@ struct il_lib_ops {
u16 len, u8 reset, u8 pad);
void (*txq_free_tfd) (struct il_priv *il, struct il_tx_queue *txq);
int (*txq_init) (struct il_priv *il, struct il_tx_queue *txq);
- /* setup Rx handler */
- void (*handler_setup) (struct il_priv *il);
/* alive notification after init uCode load */
void (*init_alive_start) (struct il_priv *il);
/* check validity of rtc data address */
@@ -1615,44 +1587,33 @@ struct il_lib_ops {
int (*set_channel_switch) (struct il_priv *il,
struct ieee80211_channel_switch *ch_switch);
/* power management */
- struct il_apm_ops apm_ops;
+ int (*apm_init) (struct il_priv *il);
- /* power */
+ /* tx power */
int (*send_tx_power) (struct il_priv *il);
void (*update_chain_flags) (struct il_priv *il);
/* eeprom operations */
- struct il_eeprom_ops eeprom_ops;
+ int (*eeprom_acquire_semaphore) (struct il_priv *il);
+ void (*eeprom_release_semaphore) (struct il_priv *il);
- /* temperature */
- struct il_temp_ops temp_ops;
-
-#ifdef CONFIG_IWLEGACY_DEBUGFS
- struct il_debugfs_ops debugfs_ops;
-#endif
-
-};
+ int (*rxon_assoc) (struct il_priv *il);
+ int (*commit_rxon) (struct il_priv *il);
+ void (*set_rxon_chain) (struct il_priv *il);
-struct il_led_ops {
- int (*cmd) (struct il_priv *il, struct il_led_cmd *led_cmd);
-};
+ u16(*get_hcmd_size) (u8 cmd_id, u16 len);
+ u16(*build_addsta_hcmd) (const struct il_addsta_cmd *cmd, u8 *data);
-struct il_legacy_ops {
+ int (*request_scan) (struct il_priv *il, struct ieee80211_vif *vif);
+ void (*post_scan) (struct il_priv *il);
void (*post_associate) (struct il_priv *il);
void (*config_ap) (struct il_priv *il);
/* station management */
int (*update_bcast_stations) (struct il_priv *il);
int (*manage_ibss_station) (struct il_priv *il,
struct ieee80211_vif *vif, bool add);
-};
-struct il_ops {
- const struct il_lib_ops *lib;
- const struct il_hcmd_ops *hcmd;
- const struct il_hcmd_utils_ops *utils;
- const struct il_led_ops *led;
- const struct il_nic_ops *nic;
- const struct il_legacy_ops *legacy;
+ int (*send_led_cmd) (struct il_priv *il, struct il_led_cmd *led_cmd);
};
struct il_mod_params {
@@ -1665,22 +1626,6 @@ struct il_mod_params {
int restart_fw; /* def: 1 = restart firmware */
};
-/*
- * @led_compensation: compensate on the led on/off time per HW according
- * to the deviation to achieve the desired led frequency.
- * The detail algorithm is described in common.c
- * @chain_noise_num_beacons: number of beacons used to compute chain noise
- * @wd_timeout: TX queues watchdog timeout
- * @temperature_kelvin: temperature report by uCode in kelvin
- * @ucode_tracing: support ucode continuous tracing
- * @sensitivity_calib_by_driver: driver has the capability to perform
- * sensitivity calibration operation
- * @chain_noise_calib_by_driver: driver has the capability to perform
- * chain noise calibration operation
- */
-struct il_base_params {
-};
-
#define IL_LED_SOLID 11
#define IL_DEF_LED_INTRVL cpu_to_le32(1000)
@@ -1769,6 +1714,8 @@ struct il_cfg {
const bool ucode_tracing;
const bool sensitivity_calib_by_driver;
const bool chain_noise_calib_by_driver;
+
+ const u32 regulatory_bands[7];
};
/***************************
@@ -1800,60 +1747,24 @@ void il_mac_remove_interface(struct ieee80211_hw *hw,
int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum nl80211_iftype newtype, bool newp2p);
int il_alloc_txq_mem(struct il_priv *il);
-void il_txq_mem(struct il_priv *il);
+void il_free_txq_mem(struct il_priv *il);
#ifdef CONFIG_IWLEGACY_DEBUGFS
-int il_alloc_traffic_mem(struct il_priv *il);
-void il_free_traffic_mem(struct il_priv *il);
-void il_reset_traffic_log(struct il_priv *il);
-void il_dbg_log_tx_data_frame(struct il_priv *il, u16 length,
- struct ieee80211_hdr *header);
-void il_dbg_log_rx_data_frame(struct il_priv *il, u16 length,
- struct ieee80211_hdr *header);
-const char *il_get_mgmt_string(int cmd);
-const char *il_get_ctrl_string(int cmd);
-void il_clear_traffic_stats(struct il_priv *il);
-void il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len);
+extern void il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len);
#else
-static inline int
-il_alloc_traffic_mem(struct il_priv *il)
-{
- return 0;
-}
-
-static inline void
-il_free_traffic_mem(struct il_priv *il)
-{
-}
-
-static inline void
-il_reset_traffic_log(struct il_priv *il)
-{
-}
-
-static inline void
-il_dbg_log_tx_data_frame(struct il_priv *il, u16 length,
- struct ieee80211_hdr *header)
-{
-}
-
-static inline void
-il_dbg_log_rx_data_frame(struct il_priv *il, u16 length,
- struct ieee80211_hdr *header)
-{
-}
-
static inline void
il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len)
{
}
#endif
+
/*****************************************************
- * RX handlers.
- * **************************************************/
+ * Handlers
+ ***************************************************/
void il_hdl_pm_sleep(struct il_priv *il, struct il_rx_buf *rxb);
void il_hdl_pm_debug_stats(struct il_priv *il, struct il_rx_buf *rxb);
void il_hdl_error(struct il_priv *il, struct il_rx_buf *rxb);
+void il_hdl_csa(struct il_priv *il, struct il_rx_buf *rxb);
/*****************************************************
* RX
@@ -1864,25 +1775,20 @@ int il_rx_queue_alloc(struct il_priv *il);
void il_rx_queue_update_write_ptr(struct il_priv *il, struct il_rx_queue *q);
int il_rx_queue_space(const struct il_rx_queue *q);
void il_tx_cmd_complete(struct il_priv *il, struct il_rx_buf *rxb);
-/* Handlers */
+
void il_hdl_spectrum_measurement(struct il_priv *il, struct il_rx_buf *rxb);
void il_recover_from_stats(struct il_priv *il, struct il_rx_pkt *pkt);
void il_chswitch_done(struct il_priv *il, bool is_success);
-void il_hdl_csa(struct il_priv *il, struct il_rx_buf *rxb);
-
-/* TX helpers */
/*****************************************************
* TX
******************************************************/
-void il_txq_update_write_ptr(struct il_priv *il, struct il_tx_queue *txq);
-int il_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq, int slots_num,
- u32 txq_id);
-void il_tx_queue_reset(struct il_priv *il, struct il_tx_queue *txq,
- int slots_num, u32 txq_id);
-void il_tx_queue_unmap(struct il_priv *il, int txq_id);
-void il_tx_queue_free(struct il_priv *il, int txq_id);
-void il_setup_watchdog(struct il_priv *il);
+extern void il_txq_update_write_ptr(struct il_priv *il, struct il_tx_queue *txq);
+extern int il_tx_queue_init(struct il_priv *il, u32 txq_id);
+extern void il_tx_queue_reset(struct il_priv *il, u32 txq_id);
+extern void il_tx_queue_unmap(struct il_priv *il, int txq_id);
+extern void il_tx_queue_free(struct il_priv *il, int txq_id);
+extern void il_setup_watchdog(struct il_priv *il);
/*****************************************************
* TX power
****************************************************/
@@ -2000,7 +1906,7 @@ void il_free_geos(struct il_priv *il);
#define S_HCMD_ACTIVE 0 /* host command in progress */
/* 1 is unused (used to be S_HCMD_SYNC_ACTIVE) */
#define S_INT_ENABLED 2
-#define S_RF_KILL_HW 3
+#define S_RFKILL 3
#define S_CT_KILL 4
#define S_INIT 5
#define S_ALIVE 6
@@ -2039,15 +1945,9 @@ il_is_init(struct il_priv *il)
}
static inline int
-il_is_rfkill_hw(struct il_priv *il)
-{
- return test_bit(S_RF_KILL_HW, &il->status);
-}
-
-static inline int
il_is_rfkill(struct il_priv *il)
{
- return il_is_rfkill_hw(il);
+ return test_bit(S_RFKILL, &il->status);
}
static inline int
@@ -2068,7 +1968,9 @@ il_is_ready_rf(struct il_priv *il)
extern void il_send_bt_config(struct il_priv *il);
extern int il_send_stats_request(struct il_priv *il, u8 flags, bool clear);
-void il_apm_stop(struct il_priv *il);
+extern void il_apm_stop(struct il_priv *il);
+extern void _il_apm_stop(struct il_priv *il);
+
int il_apm_init(struct il_priv *il);
int il_send_rxon_timing(struct il_priv *il);
@@ -2076,13 +1978,13 @@ int il_send_rxon_timing(struct il_priv *il);
static inline int
il_send_rxon_assoc(struct il_priv *il)
{
- return il->ops->hcmd->rxon_assoc(il);
+ return il->ops->rxon_assoc(il);
}
static inline int
il_commit_rxon(struct il_priv *il)
{
- return il->ops->hcmd->commit_rxon(il);
+ return il->ops->commit_rxon(il);
}
static inline const struct ieee80211_supported_band *
@@ -2103,7 +2005,7 @@ irqreturn_t il_isr(int irq, void *data);
extern void il_set_bit(struct il_priv *p, u32 r, u32 m);
extern void il_clear_bit(struct il_priv *p, u32 r, u32 m);
-extern int _il_grab_nic_access(struct il_priv *il);
+extern bool _il_grab_nic_access(struct il_priv *il);
extern int _il_poll_bit(struct il_priv *il, u32 addr, u32 bits, u32 mask, int timeout);
extern int il_poll_bit(struct il_priv *il, u32 addr, u32 mask, int timeout);
extern u32 il_rd_prph(struct il_priv *il, u32 reg);
@@ -2114,20 +2016,20 @@ extern void il_write_targ_mem(struct il_priv *il, u32 addr, u32 val);
static inline void
_il_write8(struct il_priv *il, u32 ofs, u8 val)
{
- iowrite8(val, il->hw_base + ofs);
+ writeb(val, il->hw_base + ofs);
}
#define il_write8(il, ofs, val) _il_write8(il, ofs, val)
static inline void
_il_wr(struct il_priv *il, u32 ofs, u32 val)
{
- iowrite32(val, il->hw_base + ofs);
+ writel(val, il->hw_base + ofs);
}
static inline u32
_il_rd(struct il_priv *il, u32 ofs)
{
- return ioread32(il->hw_base + ofs);
+ return readl(il->hw_base + ofs);
}
static inline void
@@ -2146,6 +2048,13 @@ static inline void
_il_release_nic_access(struct il_priv *il)
{
_il_clear_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ /*
+ * In above we are reading CSR_GP_CNTRL register, what will flush any
+ * previous writes, but still want write, which clear MAC_ACCESS_REQ
+ * bit, be performed on PCI bus before any other writes scheduled on
+ * different CPUs (after we drop reg_lock).
+ */
+ mmiowb();
}
static inline u32
@@ -2168,7 +2077,7 @@ il_wr(struct il_priv *il, u32 reg, u32 value)
unsigned long reg_flags;
spin_lock_irqsave(&il->reg_lock, reg_flags);
- if (!_il_grab_nic_access(il)) {
+ if (likely(_il_grab_nic_access(il))) {
_il_wr(il, reg, value);
_il_release_nic_access(il);
}
@@ -2179,7 +2088,6 @@ static inline u32
_il_rd_prph(struct il_priv *il, u32 reg)
{
_il_wr(il, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
- rmb();
return _il_rd(il, HBUS_TARG_PRPH_RDAT);
}
@@ -2187,7 +2095,6 @@ static inline void
_il_wr_prph(struct il_priv *il, u32 addr, u32 val)
{
_il_wr(il, HBUS_TARG_PRPH_WADDR, ((addr & 0x0000FFFF) | (3 << 24)));
- wmb();
_il_wr(il, HBUS_TARG_PRPH_WDAT, val);
}
@@ -2197,9 +2104,10 @@ il_set_bits_prph(struct il_priv *il, u32 reg, u32 mask)
unsigned long reg_flags;
spin_lock_irqsave(&il->reg_lock, reg_flags);
- _il_grab_nic_access(il);
- _il_wr_prph(il, reg, (_il_rd_prph(il, reg) | mask));
- _il_release_nic_access(il);
+ if (likely(_il_grab_nic_access(il))) {
+ _il_wr_prph(il, reg, (_il_rd_prph(il, reg) | mask));
+ _il_release_nic_access(il);
+ }
spin_unlock_irqrestore(&il->reg_lock, reg_flags);
}
@@ -2209,9 +2117,10 @@ il_set_bits_mask_prph(struct il_priv *il, u32 reg, u32 bits, u32 mask)
unsigned long reg_flags;
spin_lock_irqsave(&il->reg_lock, reg_flags);
- _il_grab_nic_access(il);
- _il_wr_prph(il, reg, ((_il_rd_prph(il, reg) & mask) | bits));
- _il_release_nic_access(il);
+ if (likely(_il_grab_nic_access(il))) {
+ _il_wr_prph(il, reg, ((_il_rd_prph(il, reg) & mask) | bits));
+ _il_release_nic_access(il);
+ }
spin_unlock_irqrestore(&il->reg_lock, reg_flags);
}
@@ -2222,10 +2131,11 @@ il_clear_bits_prph(struct il_priv *il, u32 reg, u32 mask)
u32 val;
spin_lock_irqsave(&il->reg_lock, reg_flags);
- _il_grab_nic_access(il);
- val = _il_rd_prph(il, reg);
- _il_wr_prph(il, reg, (val & ~mask));
- _il_release_nic_access(il);
+ if (likely(_il_grab_nic_access(il))) {
+ val = _il_rd_prph(il, reg);
+ _il_wr_prph(il, reg, (val & ~mask));
+ _il_release_nic_access(il);
+ }
spin_unlock_irqrestore(&il->reg_lock, reg_flags);
}
@@ -2487,10 +2397,10 @@ struct il_rb_status {
__le32 __unused; /* 3945 only */
} __packed;
-#define TFD_QUEUE_SIZE_MAX (256)
-#define TFD_QUEUE_SIZE_BC_DUP (64)
+#define TFD_QUEUE_SIZE_MAX 256
+#define TFD_QUEUE_SIZE_BC_DUP 64
#define TFD_QUEUE_BC_SIZE (TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP)
-#define IL_TX_DMA_MASK DMA_BIT_MASK(36)
+#define IL_TX_DMA_MASK DMA_BIT_MASK(36)
#define IL_NUM_OF_TBS 20
static inline u8
diff --git a/drivers/net/wireless/iwlegacy/debug.c b/drivers/net/wireless/iwlegacy/debug.c
index bb7c95607a6..229849150aa 100644
--- a/drivers/net/wireless/iwlegacy/debug.c
+++ b/drivers/net/wireless/iwlegacy/debug.c
@@ -31,6 +31,101 @@
#include "common.h"
+void
+il_clear_traffic_stats(struct il_priv *il)
+{
+ memset(&il->tx_stats, 0, sizeof(struct traffic_stats));
+ memset(&il->rx_stats, 0, sizeof(struct traffic_stats));
+}
+
+/*
+ * il_update_stats function record all the MGMT, CTRL and DATA pkt for
+ * both TX and Rx . Use debugfs to display the rx/rx_stats
+ */
+void
+il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len)
+{
+ struct traffic_stats *stats;
+
+ if (is_tx)
+ stats = &il->tx_stats;
+ else
+ stats = &il->rx_stats;
+
+ if (ieee80211_is_mgmt(fc)) {
+ switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
+ case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
+ stats->mgmt[MANAGEMENT_ASSOC_REQ]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
+ stats->mgmt[MANAGEMENT_ASSOC_RESP]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
+ stats->mgmt[MANAGEMENT_REASSOC_REQ]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
+ stats->mgmt[MANAGEMENT_REASSOC_RESP]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
+ stats->mgmt[MANAGEMENT_PROBE_REQ]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
+ stats->mgmt[MANAGEMENT_PROBE_RESP]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_BEACON):
+ stats->mgmt[MANAGEMENT_BEACON]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_ATIM):
+ stats->mgmt[MANAGEMENT_ATIM]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
+ stats->mgmt[MANAGEMENT_DISASSOC]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_AUTH):
+ stats->mgmt[MANAGEMENT_AUTH]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
+ stats->mgmt[MANAGEMENT_DEAUTH]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_ACTION):
+ stats->mgmt[MANAGEMENT_ACTION]++;
+ break;
+ }
+ } else if (ieee80211_is_ctl(fc)) {
+ switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
+ case cpu_to_le16(IEEE80211_STYPE_BACK_REQ):
+ stats->ctrl[CONTROL_BACK_REQ]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_BACK):
+ stats->ctrl[CONTROL_BACK]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_PSPOLL):
+ stats->ctrl[CONTROL_PSPOLL]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_RTS):
+ stats->ctrl[CONTROL_RTS]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_CTS):
+ stats->ctrl[CONTROL_CTS]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_ACK):
+ stats->ctrl[CONTROL_ACK]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_CFEND):
+ stats->ctrl[CONTROL_CFEND]++;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_CFENDACK):
+ stats->ctrl[CONTROL_CFENDACK]++;
+ break;
+ }
+ } else {
+ /* data */
+ stats->data_cnt++;
+ stats->data_bytes += len;
+ }
+}
+EXPORT_SYMBOL(il_update_stats);
+
/* create and remove of files */
#define DEBUGFS_ADD_FILE(name, parent, mode) do { \
if (!debugfs_create_file(#name, mode, parent, il, \
@@ -98,6 +193,46 @@ static const struct file_operations il_dbgfs_##name##_ops = { \
.llseek = generic_file_llseek, \
};
+static const char *
+il_get_mgmt_string(int cmd)
+{
+ switch (cmd) {
+ IL_CMD(MANAGEMENT_ASSOC_REQ);
+ IL_CMD(MANAGEMENT_ASSOC_RESP);
+ IL_CMD(MANAGEMENT_REASSOC_REQ);
+ IL_CMD(MANAGEMENT_REASSOC_RESP);
+ IL_CMD(MANAGEMENT_PROBE_REQ);
+ IL_CMD(MANAGEMENT_PROBE_RESP);
+ IL_CMD(MANAGEMENT_BEACON);
+ IL_CMD(MANAGEMENT_ATIM);
+ IL_CMD(MANAGEMENT_DISASSOC);
+ IL_CMD(MANAGEMENT_AUTH);
+ IL_CMD(MANAGEMENT_DEAUTH);
+ IL_CMD(MANAGEMENT_ACTION);
+ default:
+ return "UNKNOWN";
+
+ }
+}
+
+static const char *
+il_get_ctrl_string(int cmd)
+{
+ switch (cmd) {
+ IL_CMD(CONTROL_BACK_REQ);
+ IL_CMD(CONTROL_BACK);
+ IL_CMD(CONTROL_PSPOLL);
+ IL_CMD(CONTROL_RTS);
+ IL_CMD(CONTROL_CTS);
+ IL_CMD(CONTROL_ACK);
+ IL_CMD(CONTROL_CFEND);
+ IL_CMD(CONTROL_CFENDACK);
+ default:
+ return "UNKNOWN";
+
+ }
+}
+
static ssize_t
il_dbgfs_tx_stats_read(struct file *file, char __user *user_buf, size_t count,
loff_t *ppos)
@@ -495,8 +630,8 @@ il_dbgfs_status_read(struct file *file, char __user *user_buf, size_t count,
scnprintf(buf + pos, bufsz - pos, "S_INT_ENABLED:\t %d\n",
test_bit(S_INT_ENABLED, &il->status));
pos +=
- scnprintf(buf + pos, bufsz - pos, "S_RF_KILL_HW:\t %d\n",
- test_bit(S_RF_KILL_HW, &il->status));
+ scnprintf(buf + pos, bufsz - pos, "S_RFKILL:\t %d\n",
+ test_bit(S_RFKILL, &il->status));
pos +=
scnprintf(buf + pos, bufsz - pos, "S_CT_KILL:\t\t %d\n",
test_bit(S_CT_KILL, &il->status));
@@ -715,112 +850,6 @@ DEBUGFS_READ_FILE_OPS(qos);
DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
static ssize_t
-il_dbgfs_traffic_log_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct il_priv *il = file->private_data;
- int pos = 0, ofs = 0;
- int cnt = 0, entry;
- struct il_tx_queue *txq;
- struct il_queue *q;
- struct il_rx_queue *rxq = &il->rxq;
- char *buf;
- int bufsz =
- ((IL_TRAFFIC_ENTRIES * IL_TRAFFIC_ENTRY_SIZE * 64) * 2) +
- (il->cfg->num_of_queues * 32 * 8) + 400;
- const u8 *ptr;
- ssize_t ret;
-
- if (!il->txq) {
- IL_ERR("txq not ready\n");
- return -EAGAIN;
- }
- buf = kzalloc(bufsz, GFP_KERNEL);
- if (!buf) {
- IL_ERR("Can not allocate buffer\n");
- return -ENOMEM;
- }
- pos += scnprintf(buf + pos, bufsz - pos, "Tx Queue\n");
- for (cnt = 0; cnt < il->hw_params.max_txq_num; cnt++) {
- txq = &il->txq[cnt];
- q = &txq->q;
- pos +=
- scnprintf(buf + pos, bufsz - pos,
- "q[%d]: read_ptr: %u, write_ptr: %u\n", cnt,
- q->read_ptr, q->write_ptr);
- }
- if (il->tx_traffic && (il_debug_level & IL_DL_TX)) {
- ptr = il->tx_traffic;
- pos +=
- scnprintf(buf + pos, bufsz - pos, "Tx Traffic idx: %u\n",
- il->tx_traffic_idx);
- for (cnt = 0, ofs = 0; cnt < IL_TRAFFIC_ENTRIES; cnt++) {
- for (entry = 0; entry < IL_TRAFFIC_ENTRY_SIZE / 16;
- entry++, ofs += 16) {
- pos +=
- scnprintf(buf + pos, bufsz - pos, "0x%.4x ",
- ofs);
- hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
- buf + pos, bufsz - pos, 0);
- pos += strlen(buf + pos);
- if (bufsz - pos > 0)
- buf[pos++] = '\n';
- }
- }
- }
-
- pos += scnprintf(buf + pos, bufsz - pos, "Rx Queue\n");
- pos +=
- scnprintf(buf + pos, bufsz - pos, "read: %u, write: %u\n",
- rxq->read, rxq->write);
-
- if (il->rx_traffic && (il_debug_level & IL_DL_RX)) {
- ptr = il->rx_traffic;
- pos +=
- scnprintf(buf + pos, bufsz - pos, "Rx Traffic idx: %u\n",
- il->rx_traffic_idx);
- for (cnt = 0, ofs = 0; cnt < IL_TRAFFIC_ENTRIES; cnt++) {
- for (entry = 0; entry < IL_TRAFFIC_ENTRY_SIZE / 16;
- entry++, ofs += 16) {
- pos +=
- scnprintf(buf + pos, bufsz - pos, "0x%.4x ",
- ofs);
- hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
- buf + pos, bufsz - pos, 0);
- pos += strlen(buf + pos);
- if (bufsz - pos > 0)
- buf[pos++] = '\n';
- }
- }
- }
-
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
- kfree(buf);
- return ret;
-}
-
-static ssize_t
-il_dbgfs_traffic_log_write(struct file *file, const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct il_priv *il = file->private_data;
- char buf[8];
- int buf_size;
- int traffic_log;
-
- memset(buf, 0, sizeof(buf));
- buf_size = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- if (sscanf(buf, "%d", &traffic_log) != 1)
- return -EFAULT;
- if (traffic_log == 0)
- il_reset_traffic_log(il);
-
- return count;
-}
-
-static ssize_t
il_dbgfs_tx_queue_read(struct file *file, char __user *user_buf, size_t count,
loff_t *ppos)
{
@@ -901,7 +930,8 @@ il_dbgfs_ucode_rx_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct il_priv *il = file->private_data;
- return il->ops->lib->debugfs_ops.rx_stats_read(file, user_buf, count, ppos);
+
+ return il->debugfs_ops->rx_stats_read(file, user_buf, count, ppos);
}
static ssize_t
@@ -909,7 +939,8 @@ il_dbgfs_ucode_tx_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct il_priv *il = file->private_data;
- return il->ops->lib->debugfs_ops.tx_stats_read(file, user_buf, count, ppos);
+
+ return il->debugfs_ops->tx_stats_read(file, user_buf, count, ppos);
}
static ssize_t
@@ -917,7 +948,8 @@ il_dbgfs_ucode_general_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct il_priv *il = file->private_data;
- return il->ops->lib->debugfs_ops.general_stats_read(file, user_buf, count, ppos);
+
+ return il->debugfs_ops->general_stats_read(file, user_buf, count, ppos);
}
static ssize_t
@@ -1175,8 +1207,8 @@ il_dbgfs_fh_reg_read(struct file *file, char __user *user_buf, size_t count,
int pos = 0;
ssize_t ret = -EFAULT;
- if (il->ops->lib->dump_fh) {
- ret = pos = il->ops->lib->dump_fh(il, &buf, true);
+ if (il->ops->dump_fh) {
+ ret = pos = il->ops->dump_fh(il, &buf, true);
if (buf) {
ret =
simple_read_from_buffer(user_buf, count, ppos, buf,
@@ -1300,7 +1332,6 @@ il_dbgfs_wd_timeout_write(struct file *file, const char __user *user_buf,
DEBUGFS_READ_FILE_OPS(rx_stats);
DEBUGFS_READ_FILE_OPS(tx_stats);
-DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
DEBUGFS_READ_FILE_OPS(rx_queue);
DEBUGFS_READ_FILE_OPS(tx_queue);
DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
@@ -1354,7 +1385,6 @@ il_dbgfs_register(struct il_priv *il, const char *name)
DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(rx_stats, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(tx_stats, dir_debug, S_IRUSR);
- DEBUGFS_ADD_FILE(traffic_log, dir_debug, S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index a0a7854facc..299c3879582 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -163,7 +163,7 @@ config RT2800USB_RT53XX
depends on EXPERIMENTAL
---help---
This adds support for rt53xx wireless chipset family to the
- rt2800pci driver.
+ rt2800usb driver.
Supported chips: RT5370
config RT2800USB_UNKNOWN
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 772d4aec303..f1df929e97a 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -4053,7 +4053,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
case RT5390:
break;
default:
- ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
+ ERROR(rt2x00dev, "Invalid RT chipset 0x%04x detected.\n", rt2x00dev->chip.rt);
return -ENODEV;
}
@@ -4072,7 +4072,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
case RF5390:
break;
default:
- ERROR(rt2x00dev, "Invalid RF chipset 0x%x detected.\n",
+ ERROR(rt2x00dev, "Invalid RF chipset 0x%04x detected.\n",
rt2x00dev->chip.rf);
return -ENODEV;
}
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index df5655cc55c..510023554e5 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -39,10 +39,10 @@
#include <linux/module.h>
/*
- *NOTICE!!!: This file will be very big, we hsould
- *keep it clear under follwing roles:
+ *NOTICE!!!: This file will be very big, we should
+ *keep it clear under following roles:
*
- *This file include follwing part, so, if you add new
+ *This file include following parts, so, if you add new
*functions into this file, please check which part it
*should includes. or check if you should add new part
*for this file:
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
index 22e998dd2f3..cdd71f5e77a 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
@@ -177,7 +177,7 @@ u32 _rtl92c_phy_calculate_bit_shift(u32 bitmask)
u32 i;
for (i = 0; i <= 31; i++) {
- if (((bitmask >> i) & 0x1) == 1)
+ if ((bitmask >> i) & 0x1)
break;
}
return i;
@@ -253,121 +253,51 @@ void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ int index;
+
+ if (regaddr == RTXAGC_A_RATE18_06)
+ index = 0;
+ else if (regaddr == RTXAGC_A_RATE54_24)
+ index = 1;
+ else if (regaddr == RTXAGC_A_CCK1_MCS32)
+ index = 6;
+ else if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00)
+ index = 7;
+ else if (regaddr == RTXAGC_A_MCS03_MCS00)
+ index = 2;
+ else if (regaddr == RTXAGC_A_MCS07_MCS04)
+ index = 3;
+ else if (regaddr == RTXAGC_A_MCS11_MCS08)
+ index = 4;
+ else if (regaddr == RTXAGC_A_MCS15_MCS12)
+ index = 5;
+ else if (regaddr == RTXAGC_B_RATE18_06)
+ index = 8;
+ else if (regaddr == RTXAGC_B_RATE54_24)
+ index = 9;
+ else if (regaddr == RTXAGC_B_CCK1_55_MCS32)
+ index = 14;
+ else if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff)
+ index = 15;
+ else if (regaddr == RTXAGC_B_MCS03_MCS00)
+ index = 10;
+ else if (regaddr == RTXAGC_B_MCS07_MCS04)
+ index = 11;
+ else if (regaddr == RTXAGC_B_MCS11_MCS08)
+ index = 12;
+ else if (regaddr == RTXAGC_B_MCS15_MCS12)
+ index = 13;
+ else
+ return;
- if (regaddr == RTXAGC_A_RATE18_06) {
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][0] = data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][0] = 0x%x\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][0]);
- }
- if (regaddr == RTXAGC_A_RATE54_24) {
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][1] = data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][1] = 0x%x\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][1]);
- }
- if (regaddr == RTXAGC_A_CCK1_MCS32) {
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][6] = data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][6] = 0x%x\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][6]);
- }
- if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00) {
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][7] = data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][7] = 0x%x\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][7]);
- }
- if (regaddr == RTXAGC_A_MCS03_MCS00) {
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][2] = data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][2] = 0x%x\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][2]);
- }
- if (regaddr == RTXAGC_A_MCS07_MCS04) {
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][3] = data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][3] = 0x%x\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][3]);
- }
- if (regaddr == RTXAGC_A_MCS11_MCS08) {
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][4] = data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][4] = 0x%x\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][4]);
- }
- if (regaddr == RTXAGC_A_MCS15_MCS12) {
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][5] = data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][5] = 0x%x\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][5]);
- }
- if (regaddr == RTXAGC_B_RATE18_06) {
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][8] = data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][8] = 0x%x\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][8]);
- }
- if (regaddr == RTXAGC_B_RATE54_24) {
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][9] = data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][9]);
- }
- if (regaddr == RTXAGC_B_CCK1_55_MCS32) {
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][14] = data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][14]);
- }
- if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) {
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][15] = data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][15]);
- }
- if (regaddr == RTXAGC_B_MCS03_MCS00) {
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][10] = data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][10]);
- }
- if (regaddr == RTXAGC_B_MCS07_MCS04) {
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][11] = data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][11]);
- }
- if (regaddr == RTXAGC_B_MCS11_MCS08) {
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][12] = data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][12]);
- }
- if (regaddr == RTXAGC_B_MCS15_MCS12) {
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][13] = data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][13]);
+ rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][index] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n",
+ rtlphy->pwrgroup_cnt, index,
+ rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][index]);
+ if (index == 13)
rtlphy->pwrgroup_cnt++;
- }
}
EXPORT_SYMBOL(_rtl92c_store_pwrIndex_diffrate_offset);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
index 9581a19c254..96dc71746ea 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
@@ -665,152 +665,51 @@ static void _rtl92d_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ int index;
+
+ if (regaddr == RTXAGC_A_RATE18_06)
+ index = 0;
+ else if (regaddr == RTXAGC_A_RATE54_24)
+ index = 1;
+ else if (regaddr == RTXAGC_A_CCK1_MCS32)
+ index = 6;
+ else if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00)
+ index = 7;
+ else if (regaddr == RTXAGC_A_MCS03_MCS00)
+ index = 2;
+ else if (regaddr == RTXAGC_A_MCS07_MCS04)
+ index = 3;
+ else if (regaddr == RTXAGC_A_MCS11_MCS08)
+ index = 4;
+ else if (regaddr == RTXAGC_A_MCS15_MCS12)
+ index = 5;
+ else if (regaddr == RTXAGC_B_RATE18_06)
+ index = 8;
+ else if (regaddr == RTXAGC_B_RATE54_24)
+ index = 9;
+ else if (regaddr == RTXAGC_B_CCK1_55_MCS32)
+ index = 14;
+ else if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff)
+ index = 15;
+ else if (regaddr == RTXAGC_B_MCS03_MCS00)
+ index = 10;
+ else if (regaddr == RTXAGC_B_MCS07_MCS04)
+ index = 11;
+ else if (regaddr == RTXAGC_B_MCS11_MCS08)
+ index = 12;
+ else if (regaddr == RTXAGC_B_MCS15_MCS12)
+ index = 13;
+ else
+ return;
- if (regaddr == RTXAGC_A_RATE18_06) {
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][0] =
- data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][0] = 0x%ulx\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->mcs_txpwrlevel_origoffset
- [rtlphy->pwrgroup_cnt][0]);
- }
- if (regaddr == RTXAGC_A_RATE54_24) {
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][1] =
- data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][1] = 0x%ulx\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->mcs_txpwrlevel_origoffset
- [rtlphy->pwrgroup_cnt][1]);
- }
- if (regaddr == RTXAGC_A_CCK1_MCS32) {
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][6] =
- data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][6] = 0x%ulx\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->mcs_txpwrlevel_origoffset
- [rtlphy->pwrgroup_cnt][6]);
- }
- if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00) {
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][7] =
- data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][7] = 0x%ulx\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->mcs_txpwrlevel_origoffset
- [rtlphy->pwrgroup_cnt][7]);
- }
- if (regaddr == RTXAGC_A_MCS03_MCS00) {
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][2] =
- data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][2] = 0x%ulx\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->mcs_txpwrlevel_origoffset
- [rtlphy->pwrgroup_cnt][2]);
- }
- if (regaddr == RTXAGC_A_MCS07_MCS04) {
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][3] =
- data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][3] = 0x%ulx\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->mcs_txpwrlevel_origoffset
- [rtlphy->pwrgroup_cnt][3]);
- }
- if (regaddr == RTXAGC_A_MCS11_MCS08) {
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][4] =
- data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][4] = 0x%ulx\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->mcs_txpwrlevel_origoffset
- [rtlphy->pwrgroup_cnt][4]);
- }
- if (regaddr == RTXAGC_A_MCS15_MCS12) {
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][5] =
- data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][5] = 0x%ulx\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->mcs_txpwrlevel_origoffset
- [rtlphy->pwrgroup_cnt][5]);
- }
- if (regaddr == RTXAGC_B_RATE18_06) {
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][8] =
- data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][8] = 0x%ulx\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->mcs_txpwrlevel_origoffset
- [rtlphy->pwrgroup_cnt][8]);
- }
- if (regaddr == RTXAGC_B_RATE54_24) {
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][9] =
- data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][9] = 0x%ulx\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->mcs_txpwrlevel_origoffset
- [rtlphy->pwrgroup_cnt][9]);
- }
- if (regaddr == RTXAGC_B_CCK1_55_MCS32) {
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][14] =
- data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][14] = 0x%ulx\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->mcs_txpwrlevel_origoffset
- [rtlphy->pwrgroup_cnt][14]);
- }
- if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) {
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][15] =
- data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][15] = 0x%ulx\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->mcs_txpwrlevel_origoffset
- [rtlphy->pwrgroup_cnt][15]);
- }
- if (regaddr == RTXAGC_B_MCS03_MCS00) {
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][10] =
- data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][10] = 0x%ulx\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->mcs_txpwrlevel_origoffset
- [rtlphy->pwrgroup_cnt][10]);
- }
- if (regaddr == RTXAGC_B_MCS07_MCS04) {
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][11] =
- data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][11] = 0x%ulx\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->mcs_txpwrlevel_origoffset
- [rtlphy->pwrgroup_cnt][11]);
- }
- if (regaddr == RTXAGC_B_MCS11_MCS08) {
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][12] =
- data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][12] = 0x%ulx\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->mcs_txpwrlevel_origoffset
- [rtlphy->pwrgroup_cnt][12]);
- }
- if (regaddr == RTXAGC_B_MCS15_MCS12) {
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][13] =
- data;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][13] = 0x%ulx\n",
- rtlphy->pwrgroup_cnt,
- rtlphy->mcs_txpwrlevel_origoffset
- [rtlphy->pwrgroup_cnt][13]);
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][index] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%ulx\n",
+ rtlphy->pwrgroup_cnt, index,
+ rtlphy->mcs_txpwrlevel_origoffset
+ [rtlphy->pwrgroup_cnt][index]);
+ if (index == 13)
rtlphy->pwrgroup_cnt++;
- }
}
static bool _rtl92d_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.h b/drivers/net/wireless/rtlwifi/rtl8192se/fw.h
index babe85d4b69..b4afff62643 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/fw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.h
@@ -30,6 +30,7 @@
#define __REALTEK_FIRMWARE92S_H__
#define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000
+#define RTL8190_MAX_RAW_FIRMWARE_CODE_SIZE 90000
#define RTL8190_CPU_START_OFFSET 0x80
/* Firmware Local buffer size. 64k */
#define MAX_FIRMWARE_CODE_SIZE 0xFF00
@@ -217,7 +218,7 @@ struct rt_firmware {
u8 fw_emem[RTL8190_MAX_FIRMWARE_CODE_SIZE];
u32 fw_imem_len;
u32 fw_emem_len;
- u8 sz_fw_tmpbuffer[164000];
+ u8 sz_fw_tmpbuffer[RTL8190_MAX_RAW_FIRMWARE_CODE_SIZE];
u32 sz_fw_tmpbufferlen;
u16 cmdpacket_fragthresold;
};
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
index 05b4e2790e9..6d5bbd0e4d3 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
@@ -678,30 +678,28 @@ static void _rtl92s_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ int index;
if (reg_addr == RTXAGC_RATE18_06)
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][0] =
- data;
- if (reg_addr == RTXAGC_RATE54_24)
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][1] =
- data;
- if (reg_addr == RTXAGC_CCK_MCS32)
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][6] =
- data;
- if (reg_addr == RTXAGC_MCS03_MCS00)
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][2] =
- data;
- if (reg_addr == RTXAGC_MCS07_MCS04)
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][3] =
- data;
- if (reg_addr == RTXAGC_MCS11_MCS08)
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][4] =
- data;
- if (reg_addr == RTXAGC_MCS15_MCS12) {
- rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][5] =
- data;
+ index = 0;
+ else if (reg_addr == RTXAGC_RATE54_24)
+ index = 1;
+ else if (reg_addr == RTXAGC_CCK_MCS32)
+ index = 6;
+ else if (reg_addr == RTXAGC_MCS03_MCS00)
+ index = 2;
+ else if (reg_addr == RTXAGC_MCS07_MCS04)
+ index = 3;
+ else if (reg_addr == RTXAGC_MCS11_MCS08)
+ index = 4;
+ else if (reg_addr == RTXAGC_MCS15_MCS12)
+ index = 5;
+ else
+ return;
+
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][index] = data;
+ if (index == 5)
rtlphy->pwrgroup_cnt++;
- }
}
static void _rtl92s_phy_init_register_definition(struct ieee80211_hw *hw)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
index ca38dd9f356..345d752137f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
@@ -108,6 +108,7 @@ static void rtl92se_fw_cb(const struct firmware *firmware, void *context)
if (firmware->size > rtlpriv->max_fw_size) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Firmware is too big!\n");
+ rtlpriv->max_fw_size = 0;
release_firmware(firmware);
return;
}
@@ -232,7 +233,7 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw)
return 1;
}
- rtlpriv->max_fw_size = sizeof(struct rt_firmware);
+ rtlpriv->max_fw_size = RTL8190_MAX_RAW_FIRMWARE_CODE_SIZE;
pr_info("Driver for Realtek RTL8192SE/RTL8191SE\n"
"Loading firmware %s\n", rtlpriv->cfg->fw_name);
diff --git a/drivers/net/wireless/wl1251/Makefile b/drivers/net/wireless/wl1251/Makefile
index 58b4f935a3f..a5c6328b5f7 100644
--- a/drivers/net/wireless/wl1251/Makefile
+++ b/drivers/net/wireless/wl1251/Makefile
@@ -6,3 +6,5 @@ wl1251_sdio-objs += sdio.o
obj-$(CONFIG_WL1251) += wl1251.o
obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o
obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/wl1251/boot.c b/drivers/net/wireless/wl1251/boot.c
index d729daf8e84..a2e5241382d 100644
--- a/drivers/net/wireless/wl1251/boot.c
+++ b/drivers/net/wireless/wl1251/boot.c
@@ -464,8 +464,6 @@ static int wl1251_boot_upload_nvs(struct wl1251 *wl)
val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
| (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
- val = cpu_to_le32(val);
-
wl1251_debug(DEBUG_BOOT,
"nvs write table 0x%x: 0x%x",
nvs_start, val);
diff --git a/drivers/net/wireless/wl1251/io.h b/drivers/net/wireless/wl1251/io.h
index c545e9d5f51..d382877c34c 100644
--- a/drivers/net/wireless/wl1251/io.h
+++ b/drivers/net/wireless/wl1251/io.h
@@ -36,16 +36,15 @@
static inline u32 wl1251_read32(struct wl1251 *wl, int addr)
{
- u32 response;
-
- wl->if_ops->read(wl, addr, &response, sizeof(u32));
+ wl->if_ops->read(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32));
- return response;
+ return le32_to_cpu(wl->buffer_32);
}
static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val)
{
- wl->if_ops->write(wl, addr, &val, sizeof(u32));
+ wl->buffer_32 = cpu_to_le32(val);
+ wl->if_ops->write(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32));
}
static inline u32 wl1251_read_elp(struct wl1251 *wl, int addr)
diff --git a/drivers/net/wireless/wl1251/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h
index a77f1bbbed0..9d8f5816c6f 100644
--- a/drivers/net/wireless/wl1251/wl1251.h
+++ b/drivers/net/wireless/wl1251/wl1251.h
@@ -380,7 +380,7 @@ struct wl1251 {
struct wl1251_stats stats;
struct wl1251_debugfs debugfs;
- u32 buffer_32;
+ __le32 buffer_32;
u32 buffer_cmd;
u8 buffer_busyword[WL1251_BUSY_WORD_LEN];
struct wl1251_rx_descriptor *rx_descriptor;
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index fe67262ba19..98f289c907a 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -11,3 +11,5 @@ obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o
# small builtin driver bit
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index 7537c401a44..bc96db0683a 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -34,12 +34,14 @@
#include "reg.h"
#include "ps.h"
-int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 wake_up_event, u8 listen_interval)
{
struct acx_wake_up_condition *wake_up;
int ret;
- wl1271_debug(DEBUG_ACX, "acx wake up conditions");
+ wl1271_debug(DEBUG_ACX, "acx wake up conditions (wake_up_event %d listen_interval %d)",
+ wake_up_event, listen_interval);
wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL);
if (!wake_up) {
@@ -48,8 +50,8 @@ int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif)
}
wake_up->role_id = wlvif->role_id;
- wake_up->wake_up_event = wl->conf.conn.wake_up_event;
- wake_up->listen_interval = wl->conf.conn.listen_interval;
+ wake_up->wake_up_event = wake_up_event;
+ wake_up->listen_interval = listen_interval;
ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS,
wake_up, sizeof(*wake_up));
@@ -1459,9 +1461,10 @@ out:
return ret;
}
-int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
+int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u64 *mactime)
{
- struct wl1271_acx_fw_tsf_information *tsf_info;
+ struct wl12xx_acx_fw_tsf_information *tsf_info;
int ret;
tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL);
@@ -1470,6 +1473,8 @@ int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
goto out;
}
+ tsf_info->role_id = wlvif->role_id;
+
ret = wl1271_cmd_interrogate(wl, ACX_TSF_INFO,
tsf_info, sizeof(*tsf_info));
if (ret < 0) {
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index 69892b40c2d..a28fc044034 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -995,15 +995,17 @@ struct wl1271_acx_ba_receiver_setup {
u8 padding[2];
} __packed;
-struct wl1271_acx_fw_tsf_information {
+struct wl12xx_acx_fw_tsf_information {
struct acx_header header;
+ u8 role_id;
+ u8 padding1[3];
__le32 current_tsf_high;
__le32 current_tsf_low;
__le32 last_bttt_high;
__le32 last_tbtt_low;
u8 last_dtim_count;
- u8 padding[3];
+ u8 padding2[3];
} __packed;
struct wl1271_acx_ps_rx_streaming {
@@ -1151,79 +1153,81 @@ struct wl12xx_acx_config_hangover {
} __packed;
enum {
- ACX_WAKE_UP_CONDITIONS = 0x0002,
- ACX_MEM_CFG = 0x0003,
- ACX_SLOT = 0x0004,
- ACX_AC_CFG = 0x0007,
- ACX_MEM_MAP = 0x0008,
- ACX_AID = 0x000A,
- ACX_MEDIUM_USAGE = 0x000F,
- ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */
- ACX_STATISTICS = 0x0013, /* Debug API */
- ACX_PWR_CONSUMPTION_STATISTICS = 0x0014,
- ACX_FEATURE_CFG = 0x0015,
- ACX_TID_CFG = 0x001A,
- ACX_PS_RX_STREAMING = 0x001B,
- ACX_BEACON_FILTER_OPT = 0x001F,
- ACX_NOISE_HIST = 0x0021,
- ACX_HDK_VERSION = 0x0022, /* ??? */
- ACX_PD_THRESHOLD = 0x0023,
- ACX_TX_CONFIG_OPT = 0x0024,
- ACX_CCA_THRESHOLD = 0x0025,
- ACX_EVENT_MBOX_MASK = 0x0026,
- ACX_CONN_MONIT_PARAMS = 0x002D,
- ACX_BCN_DTIM_OPTIONS = 0x0031,
- ACX_SG_ENABLE = 0x0032,
- ACX_SG_CFG = 0x0033,
- ACX_FM_COEX_CFG = 0x0034,
- ACX_BEACON_FILTER_TABLE = 0x0038,
- ACX_ARP_IP_FILTER = 0x0039,
- ACX_ROAMING_STATISTICS_TBL = 0x003B,
- ACX_RATE_POLICY = 0x003D,
- ACX_CTS_PROTECTION = 0x003E,
- ACX_SLEEP_AUTH = 0x003F,
- ACX_PREAMBLE_TYPE = 0x0040,
- ACX_ERROR_CNT = 0x0041,
- ACX_IBSS_FILTER = 0x0044,
- ACX_SERVICE_PERIOD_TIMEOUT = 0x0045,
- ACX_TSF_INFO = 0x0046,
- ACX_CONFIG_PS_WMM = 0x0049,
- ACX_ENABLE_RX_DATA_FILTER = 0x004A,
- ACX_SET_RX_DATA_FILTER = 0x004B,
- ACX_GET_DATA_FILTER_STATISTICS = 0x004C,
- ACX_RX_CONFIG_OPT = 0x004E,
- ACX_FRAG_CFG = 0x004F,
- ACX_BET_ENABLE = 0x0050,
- ACX_RSSI_SNR_TRIGGER = 0x0051,
- ACX_RSSI_SNR_WEIGHTS = 0x0052,
- ACX_KEEP_ALIVE_MODE = 0x0053,
- ACX_SET_KEEP_ALIVE_CONFIG = 0x0054,
- ACX_BA_SESSION_INIT_POLICY = 0x0055,
- ACX_BA_SESSION_RX_SETUP = 0x0056,
- ACX_PEER_HT_CAP = 0x0057,
- ACX_HT_BSS_OPERATION = 0x0058,
- ACX_COEX_ACTIVITY = 0x0059,
- ACX_BURST_MODE = 0x005C,
- ACX_SET_RATE_MGMT_PARAMS = 0x005D,
- ACX_SET_RATE_ADAPT_PARAMS = 0x0060,
- ACX_SET_DCO_ITRIM_PARAMS = 0x0061,
- ACX_GEN_FW_CMD = 0x0070,
- ACX_HOST_IF_CFG_BITMAP = 0x0071,
- ACX_MAX_TX_FAILURE = 0x0072,
- ACX_UPDATE_INCONNECTION_STA_LIST = 0x0073,
- DOT11_RX_MSDU_LIFE_TIME = 0x1004,
- DOT11_CUR_TX_PWR = 0x100D,
- DOT11_RX_DOT11_MODE = 0x1012,
- DOT11_RTS_THRESHOLD = 0x1013,
- DOT11_GROUP_ADDRESS_TBL = 0x1014,
- ACX_PM_CONFIG = 0x1016,
- ACX_CONFIG_PS = 0x1017,
- ACX_CONFIG_HANGOVER = 0x1018,
+ ACX_WAKE_UP_CONDITIONS = 0x0000,
+ ACX_MEM_CFG = 0x0001,
+ ACX_SLOT = 0x0002,
+ ACX_AC_CFG = 0x0003,
+ ACX_MEM_MAP = 0x0004,
+ ACX_AID = 0x0005,
+ ACX_MEDIUM_USAGE = 0x0006,
+ ACX_STATISTICS = 0x0007,
+ ACX_PWR_CONSUMPTION_STATISTICS = 0x0008,
+ ACX_TID_CFG = 0x0009,
+ ACX_PS_RX_STREAMING = 0x000A,
+ ACX_BEACON_FILTER_OPT = 0x000B,
+ ACX_NOISE_HIST = 0x000C,
+ ACX_HDK_VERSION = 0x000D,
+ ACX_PD_THRESHOLD = 0x000E,
+ ACX_TX_CONFIG_OPT = 0x000F,
+ ACX_CCA_THRESHOLD = 0x0010,
+ ACX_EVENT_MBOX_MASK = 0x0011,
+ ACX_CONN_MONIT_PARAMS = 0x0012,
+ ACX_DISABLE_BROADCASTS = 0x0013,
+ ACX_BCN_DTIM_OPTIONS = 0x0014,
+ ACX_SG_ENABLE = 0x0015,
+ ACX_SG_CFG = 0x0016,
+ ACX_FM_COEX_CFG = 0x0017,
+ ACX_BEACON_FILTER_TABLE = 0x0018,
+ ACX_ARP_IP_FILTER = 0x0019,
+ ACX_ROAMING_STATISTICS_TBL = 0x001A,
+ ACX_RATE_POLICY = 0x001B,
+ ACX_CTS_PROTECTION = 0x001C,
+ ACX_SLEEP_AUTH = 0x001D,
+ ACX_PREAMBLE_TYPE = 0x001E,
+ ACX_ERROR_CNT = 0x001F,
+ ACX_IBSS_FILTER = 0x0020,
+ ACX_SERVICE_PERIOD_TIMEOUT = 0x0021,
+ ACX_TSF_INFO = 0x0022,
+ ACX_CONFIG_PS_WMM = 0x0023,
+ ACX_ENABLE_RX_DATA_FILTER = 0x0024,
+ ACX_SET_RX_DATA_FILTER = 0x0025,
+ ACX_GET_DATA_FILTER_STATISTICS = 0x0026,
+ ACX_RX_CONFIG_OPT = 0x0027,
+ ACX_FRAG_CFG = 0x0028,
+ ACX_BET_ENABLE = 0x0029,
+ ACX_RSSI_SNR_TRIGGER = 0x002A,
+ ACX_RSSI_SNR_WEIGHTS = 0x002B,
+ ACX_KEEP_ALIVE_MODE = 0x002C,
+ ACX_SET_KEEP_ALIVE_CONFIG = 0x002D,
+ ACX_BA_SESSION_INIT_POLICY = 0x002E,
+ ACX_BA_SESSION_RX_SETUP = 0x002F,
+ ACX_PEER_HT_CAP = 0x0030,
+ ACX_HT_BSS_OPERATION = 0x0031,
+ ACX_COEX_ACTIVITY = 0x0032,
+ ACX_BURST_MODE = 0x0033,
+ ACX_SET_RATE_MGMT_PARAMS = 0x0034,
+ ACX_GET_RATE_MGMT_PARAMS = 0x0035,
+ ACX_SET_RATE_ADAPT_PARAMS = 0x0036,
+ ACX_SET_DCO_ITRIM_PARAMS = 0x0037,
+ ACX_GEN_FW_CMD = 0x0038,
+ ACX_HOST_IF_CFG_BITMAP = 0x0039,
+ ACX_MAX_TX_FAILURE = 0x003A,
+ ACX_UPDATE_INCONNECTION_STA_LIST = 0x003B,
+ DOT11_RX_MSDU_LIFE_TIME = 0x003C,
+ DOT11_CUR_TX_PWR = 0x003D,
+ DOT11_RTS_THRESHOLD = 0x003E,
+ DOT11_GROUP_ADDRESS_TBL = 0x003F,
+ ACX_PM_CONFIG = 0x0040,
+ ACX_CONFIG_PS = 0x0041,
+ ACX_CONFIG_HANGOVER = 0x0042,
+ ACX_FEATURE_CFG = 0x0043,
+ ACX_PROTECTION_CFG = 0x0044,
};
int wl1271_acx_wake_up_conditions(struct wl1271 *wl,
- struct wl12xx_vif *wlvif);
+ struct wl12xx_vif *wlvif,
+ u8 wake_up_event, u8 listen_interval);
int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth);
int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif,
int power);
@@ -1296,7 +1300,8 @@ int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl,
struct wl12xx_vif *wlvif);
int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
u16 ssn, bool enable, u8 peer_hlid);
-int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
+int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u64 *mactime);
int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
bool enable);
int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif);
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c
index 8f9cf5a816e..954101d03f0 100644
--- a/drivers/net/wireless/wl12xx/boot.c
+++ b/drivers/net/wireless/wl12xx/boot.c
@@ -33,65 +33,6 @@
#include "event.h"
#include "rx.h"
-static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
- [PART_DOWN] = {
- .mem = {
- .start = 0x00000000,
- .size = 0x000177c0
- },
- .reg = {
- .start = REGISTERS_BASE,
- .size = 0x00008800
- },
- .mem2 = {
- .start = 0x00000000,
- .size = 0x00000000
- },
- .mem3 = {
- .start = 0x00000000,
- .size = 0x00000000
- },
- },
-
- [PART_WORK] = {
- .mem = {
- .start = 0x00040000,
- .size = 0x00014fc0
- },
- .reg = {
- .start = REGISTERS_BASE,
- .size = 0x0000a000
- },
- .mem2 = {
- .start = 0x003004f8,
- .size = 0x00000004
- },
- .mem3 = {
- .start = 0x00040404,
- .size = 0x00000000
- },
- },
-
- [PART_DRPW] = {
- .mem = {
- .start = 0x00040000,
- .size = 0x00014fc0
- },
- .reg = {
- .start = DRPW_BASE,
- .size = 0x00006000
- },
- .mem2 = {
- .start = 0x00000000,
- .size = 0x00000000
- },
- .mem3 = {
- .start = 0x00000000,
- .size = 0x00000000
- }
- }
-};
-
static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
{
u32 cpu_ctrl;
@@ -181,13 +122,13 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
return -ENOMEM;
}
- memcpy(&partition, &part_table[PART_DOWN], sizeof(partition));
+ memcpy(&partition, &wl12xx_part_table[PART_DOWN], sizeof(partition));
partition.mem.start = dest;
wl1271_set_partition(wl, &partition);
/* 10.1 set partition limit and chunk num */
chunk_num = 0;
- partition_limit = part_table[PART_DOWN].mem.size;
+ partition_limit = wl12xx_part_table[PART_DOWN].mem.size;
while (chunk_num < fw_data_len / CHUNK_SIZE) {
/* 10.2 update partition, if needed */
@@ -195,7 +136,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
if (addr > partition_limit) {
addr = dest + chunk_num * CHUNK_SIZE;
partition_limit = chunk_num * CHUNK_SIZE +
- part_table[PART_DOWN].mem.size;
+ wl12xx_part_table[PART_DOWN].mem.size;
partition.mem.start = addr;
wl1271_set_partition(wl, &partition);
}
@@ -317,12 +258,12 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
}
/* update current MAC address to NVS */
- nvs_ptr[11] = wl->mac_addr[0];
- nvs_ptr[10] = wl->mac_addr[1];
- nvs_ptr[6] = wl->mac_addr[2];
- nvs_ptr[5] = wl->mac_addr[3];
- nvs_ptr[4] = wl->mac_addr[4];
- nvs_ptr[3] = wl->mac_addr[5];
+ nvs_ptr[11] = wl->addresses[0].addr[0];
+ nvs_ptr[10] = wl->addresses[0].addr[1];
+ nvs_ptr[6] = wl->addresses[0].addr[2];
+ nvs_ptr[5] = wl->addresses[0].addr[3];
+ nvs_ptr[4] = wl->addresses[0].addr[4];
+ nvs_ptr[3] = wl->addresses[0].addr[5];
/*
* Layout before the actual NVS tables:
@@ -383,7 +324,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
nvs_len -= nvs_ptr - (u8 *)wl->nvs;
/* Now we must set the partition correctly */
- wl1271_set_partition(wl, &part_table[PART_WORK]);
+ wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]);
/* Copy the NVS tables to a new block to ensure alignment */
nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
@@ -492,7 +433,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
/* set the working partition to its "running" mode offset */
- wl1271_set_partition(wl, &part_table[PART_WORK]);
+ wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]);
wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
wl->cmd_box_addr, wl->event_box_addr);
@@ -507,8 +448,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
/* unmask required mbox events */
wl->event_mask = BSS_LOSE_EVENT_ID |
SCAN_COMPLETE_EVENT_ID |
- PS_REPORT_EVENT_ID |
- DISCONNECT_EVENT_COMPLETE_ID |
+ ROLE_STOP_COMPLETE_EVENT_ID |
RSSI_SNR_TRIGGER_0_EVENT_ID |
PSPOLL_DELIVERY_FAILURE_EVENT_ID |
SOFT_GEMINI_SENSE_EVENT_ID |
@@ -547,19 +487,6 @@ static int wl1271_boot_write_irq_polarity(struct wl1271 *wl)
return 0;
}
-static void wl1271_boot_hw_version(struct wl1271 *wl)
-{
- u32 fuse;
-
- if (wl->chip.id == CHIP_ID_1283_PG20)
- fuse = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
- else
- fuse = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
- fuse = (fuse & PG_VER_MASK) >> PG_VER_OFFSET;
-
- wl->hw_pg_ver = (s8)fuse;
-}
-
static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl)
{
u16 spare_reg;
@@ -698,7 +625,7 @@ static int wl127x_boot_clk(struct wl1271 *wl)
u32 pause;
u32 clk;
- if (((wl->hw_pg_ver & PG_MAJOR_VER_MASK) >> PG_MAJOR_VER_OFFSET) < 3)
+ if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3)
wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
if (wl->ref_clock == CONF_REF_CLK_19_2_E ||
@@ -753,8 +680,6 @@ int wl1271_load_firmware(struct wl1271 *wl)
u32 tmp, clk;
int selected_clock = -1;
- wl1271_boot_hw_version(wl);
-
if (wl->chip.id == CHIP_ID_1283_PG20) {
ret = wl128x_boot_clk(wl, &selected_clock);
if (ret < 0)
@@ -769,7 +694,7 @@ int wl1271_load_firmware(struct wl1271 *wl)
wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
udelay(500);
- wl1271_set_partition(wl, &part_table[PART_DRPW]);
+ wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
/* Read-modify-write DRPW_SCRATCH_START register (see next state)
to be used by DRPw FW. The RTRIM value will be added by the FW
@@ -788,7 +713,7 @@ int wl1271_load_firmware(struct wl1271 *wl)
wl1271_write32(wl, DRPW_SCRATCH_START, clk);
- wl1271_set_partition(wl, &part_table[PART_WORK]);
+ wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]);
/* Disable interrupts */
wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h
index 06dad9380fa..c3adc09f403 100644
--- a/drivers/net/wireless/wl12xx/boot.h
+++ b/drivers/net/wireless/wl12xx/boot.h
@@ -55,16 +55,6 @@ struct wl1271_static_data {
#define OCP_REG_CLK_POLARITY 0x0cb2
#define OCP_REG_CLK_PULL 0x0cb4
-#define WL127X_REG_FUSE_DATA_2_1 0x050a
-#define WL128X_REG_FUSE_DATA_2_1 0x2152
-#define PG_VER_MASK 0x3c
-#define PG_VER_OFFSET 2
-
-#define PG_MAJOR_VER_MASK 0x3
-#define PG_MAJOR_VER_OFFSET 0x0
-#define PG_MINOR_VER_MASK 0xc
-#define PG_MINOR_VER_OFFSET 0x2
-
#define CMD_MBOX_ADDRESS 0x407B4
#define POLARITY_LOW BIT(1)
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 25990bd38be..b776d9d5efe 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -566,7 +566,7 @@ static int wl12xx_cmd_role_stop_dev(struct wl1271 *wl,
goto out_free;
}
- ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
+ ret = wl1271_cmd_wait_for_event(wl, ROLE_STOP_COMPLETE_EVENT_ID);
if (ret < 0) {
wl1271_error("cmd role stop dev event completion error");
goto out_free;
@@ -715,6 +715,8 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int);
cmd->ap.dtim_interval = bss_conf->dtim_period;
cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
+ /* FIXME: Change when adding DFS */
+ cmd->ap.reset_tsf = 1; /* By default reset AP TSF */
cmd->channel = wlvif->channel;
if (!bss_conf->hidden_ssid) {
@@ -994,7 +996,7 @@ out:
}
int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- u8 ps_mode)
+ u8 ps_mode, u16 auto_ps_timeout)
{
struct wl1271_cmd_ps_params *ps_params = NULL;
int ret = 0;
@@ -1009,6 +1011,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
ps_params->role_id = wlvif->role_id;
ps_params->ps_mode = ps_mode;
+ ps_params->auto_ps_timeout = auto_ps_timeout;
ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
sizeof(*ps_params), 0);
@@ -1022,13 +1025,15 @@ out:
return ret;
}
-int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
- void *buf, size_t buf_len, int index, u32 rates)
+int wl1271_cmd_template_set(struct wl1271 *wl, u8 role_id,
+ u16 template_id, void *buf, size_t buf_len,
+ int index, u32 rates)
{
struct wl1271_cmd_template_set *cmd;
int ret = 0;
- wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id);
+ wl1271_debug(DEBUG_CMD, "cmd template_set %d (role %d)",
+ template_id, role_id);
WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE);
buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE);
@@ -1039,6 +1044,8 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
goto out;
}
+ /* during initialization wlvif is NULL */
+ cmd->role_id = role_id;
cmd->len = cpu_to_le16(buf_len);
cmd->template_type = template_id;
cmd->enabled_rates = cpu_to_le32(rates);
@@ -1082,7 +1089,8 @@ int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif)
ptr = skb->data;
}
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0,
+ ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+ CMD_TEMPL_NULL_DATA, ptr, size, 0,
wlvif->basic_rate);
out:
@@ -1105,7 +1113,7 @@ int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl,
if (!skb)
goto out;
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV,
+ ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_KLV,
skb->data, skb->len,
CMD_TEMPL_KLV_IDX_NULL_DATA,
wlvif->basic_rate);
@@ -1130,7 +1138,8 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (!skb)
goto out;
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data,
+ ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+ CMD_TEMPL_PS_POLL, skb->data,
skb->len, 0, wlvif->basic_rate_set);
out:
@@ -1138,9 +1147,10 @@ out:
return ret;
}
-int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 role_id, u8 band,
const u8 *ssid, size_t ssid_len,
- const u8 *ie, size_t ie_len, u8 band)
+ const u8 *ie, size_t ie_len)
{
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
struct sk_buff *skb;
@@ -1158,10 +1168,12 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
if (band == IEEE80211_BAND_2GHZ)
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
+ ret = wl1271_cmd_template_set(wl, role_id,
+ CMD_TEMPL_CFG_PROBE_REQ_2_4,
skb->data, skb->len, 0, rate);
else
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
+ ret = wl1271_cmd_template_set(wl, role_id,
+ CMD_TEMPL_CFG_PROBE_REQ_5,
skb->data, skb->len, 0, rate);
out:
@@ -1186,10 +1198,12 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]);
if (wlvif->band == IEEE80211_BAND_2GHZ)
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
+ ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+ CMD_TEMPL_CFG_PROBE_REQ_2_4,
skb->data, skb->len, 0, rate);
else
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
+ ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+ CMD_TEMPL_CFG_PROBE_REQ_5,
skb->data, skb->len, 0, rate);
if (ret < 0)
@@ -1199,32 +1213,34 @@ out:
return skb;
}
-int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- __be32 ip_addr)
+int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
- int ret;
+ int ret, extra;
+ u16 fc;
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
- struct wl12xx_arp_rsp_template tmpl;
+ struct sk_buff *skb;
+ struct wl12xx_arp_rsp_template *tmpl;
struct ieee80211_hdr_3addr *hdr;
struct arphdr *arp_hdr;
- memset(&tmpl, 0, sizeof(tmpl));
+ skb = dev_alloc_skb(sizeof(*hdr) + sizeof(__le16) + sizeof(*tmpl) +
+ WL1271_EXTRA_SPACE_MAX);
+ if (!skb) {
+ wl1271_error("failed to allocate buffer for arp rsp template");
+ return -ENOMEM;
+ }
- /* mac80211 header */
- hdr = &tmpl.hdr;
- hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
- IEEE80211_STYPE_DATA |
- IEEE80211_FCTL_TODS);
- memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN);
- memcpy(hdr->addr2, vif->addr, ETH_ALEN);
- memset(hdr->addr3, 0xff, ETH_ALEN);
+ skb_reserve(skb, sizeof(*hdr) + WL1271_EXTRA_SPACE_MAX);
+
+ tmpl = (struct wl12xx_arp_rsp_template *)skb_put(skb, sizeof(*tmpl));
+ memset(tmpl, 0, sizeof(tmpl));
/* llc layer */
- memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header));
- tmpl.llc_type = cpu_to_be16(ETH_P_ARP);
+ memcpy(tmpl->llc_hdr, rfc1042_header, sizeof(rfc1042_header));
+ tmpl->llc_type = cpu_to_be16(ETH_P_ARP);
/* arp header */
- arp_hdr = &tmpl.arp_hdr;
+ arp_hdr = &tmpl->arp_hdr;
arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER);
arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP);
arp_hdr->ar_hln = ETH_ALEN;
@@ -1232,13 +1248,59 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif,
arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY);
/* arp payload */
- memcpy(tmpl.sender_hw, vif->addr, ETH_ALEN);
- tmpl.sender_ip = ip_addr;
+ memcpy(tmpl->sender_hw, vif->addr, ETH_ALEN);
+ tmpl->sender_ip = wlvif->ip_addr;
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP,
- &tmpl, sizeof(tmpl), 0,
- wlvif->basic_rate);
+ /* encryption space */
+ switch (wlvif->encryption_type) {
+ case KEY_TKIP:
+ extra = WL1271_EXTRA_SPACE_TKIP;
+ break;
+ case KEY_AES:
+ extra = WL1271_EXTRA_SPACE_AES;
+ break;
+ case KEY_NONE:
+ case KEY_WEP:
+ case KEY_GEM:
+ extra = 0;
+ break;
+ default:
+ wl1271_warning("Unknown encryption type: %d",
+ wlvif->encryption_type);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (extra) {
+ u8 *space = skb_push(skb, extra);
+ memset(space, 0, extra);
+ }
+
+ /* QoS header - BE */
+ if (wlvif->sta.qos)
+ memset(skb_push(skb, sizeof(__le16)), 0, sizeof(__le16));
+ /* mac80211 header */
+ hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, sizeof(*hdr));
+ memset(hdr, 0, sizeof(hdr));
+ fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS;
+ if (wlvif->sta.qos)
+ fc |= IEEE80211_STYPE_QOS_DATA;
+ else
+ fc |= IEEE80211_STYPE_DATA;
+ if (wlvif->encryption_type != KEY_NONE)
+ fc |= IEEE80211_FCTL_PROTECTED;
+
+ hdr->frame_control = cpu_to_le16(fc);
+ memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN);
+ memcpy(hdr->addr2, vif->addr, ETH_ALEN);
+ memset(hdr->addr3, 0xff, ETH_ALEN);
+
+ ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_ARP_RSP,
+ skb->data, skb->len, 0,
+ wlvif->basic_rate);
+out:
+ dev_kfree_skb(skb);
return ret;
}
@@ -1260,7 +1322,8 @@ int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif)
/* FIXME: not sure what priority to use here */
template.qos_ctrl = cpu_to_le16(0);
- return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template,
+ return wl1271_cmd_template_set(wl, wlvif->role_id,
+ CMD_TEMPL_QOS_NULL_DATA, &template,
sizeof(template), 0,
wlvif->basic_rate);
}
@@ -1744,6 +1807,7 @@ out:
}
int wl12xx_cmd_channel_switch(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
struct ieee80211_channel_switch *ch_switch)
{
struct wl12xx_cmd_channel_switch *cmd;
@@ -1757,10 +1821,13 @@ int wl12xx_cmd_channel_switch(struct wl1271 *wl,
goto out;
}
+ cmd->role_id = wlvif->role_id;
cmd->channel = ch_switch->channel->hw_value;
cmd->switch_time = ch_switch->count;
- cmd->tx_suspend = ch_switch->block_tx;
- cmd->flush = 0; /* this value is ignored by the FW */
+ cmd->stop_tx = ch_switch->block_tx;
+
+ /* FIXME: control from mac80211 in the future */
+ cmd->post_switch_tx_disable = 0; /* Enable TX on the target channel */
ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0);
if (ret < 0) {
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h
index 3f7d0b93c24..de217d92516 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/cmd.h
@@ -51,22 +51,23 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- u8 ps_mode);
+ u8 ps_mode, u16 auto_ps_timeout);
int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
size_t len);
-int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
- void *buf, size_t buf_len, int index, u32 rates);
+int wl1271_cmd_template_set(struct wl1271 *wl, u8 role_id,
+ u16 template_id, void *buf, size_t buf_len,
+ int index, u32 rates);
int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u16 aid);
-int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 role_id, u8 band,
const u8 *ssid, size_t ssid_len,
- const u8 *ie, size_t ie_len, u8 band);
+ const u8 *ie, size_t ie_len);
struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct sk_buff *skb);
-int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- __be32 ip_addr);
+int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif);
int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl,
struct wl12xx_vif *wlvif);
@@ -89,6 +90,7 @@ int wl12xx_cmd_config_fwlog(struct wl1271 *wl);
int wl12xx_cmd_start_fwlog(struct wl1271 *wl);
int wl12xx_cmd_stop_fwlog(struct wl1271 *wl);
int wl12xx_cmd_channel_switch(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
struct ieee80211_channel_switch *ch_switch);
int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl);
int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif,
@@ -96,62 +98,65 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif,
void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid);
enum wl1271_commands {
- CMD_INTERROGATE = 1, /*use this to read information elements*/
- CMD_CONFIGURE = 2, /*use this to write information elements*/
- CMD_ENABLE_RX = 3,
- CMD_ENABLE_TX = 4,
- CMD_DISABLE_RX = 5,
- CMD_DISABLE_TX = 6,
- CMD_SCAN = 8,
- CMD_STOP_SCAN = 9,
- CMD_SET_KEYS = 12,
- CMD_READ_MEMORY = 13,
- CMD_WRITE_MEMORY = 14,
- CMD_SET_TEMPLATE = 19,
- CMD_TEST = 23,
- CMD_NOISE_HIST = 28,
- CMD_QUIET_ELEMENT_SET_STATE = 29,
- CMD_SET_BCN_MODE = 33,
- CMD_MEASUREMENT = 34,
- CMD_STOP_MEASUREMENT = 35,
- CMD_SET_PS_MODE = 37,
- CMD_CHANNEL_SWITCH = 38,
- CMD_STOP_CHANNEL_SWICTH = 39,
- CMD_AP_DISCOVERY = 40,
- CMD_STOP_AP_DISCOVERY = 41,
- CMD_HEALTH_CHECK = 45,
- CMD_DEBUG = 46,
- CMD_TRIGGER_SCAN_TO = 47,
- CMD_CONNECTION_SCAN_CFG = 48,
- CMD_CONNECTION_SCAN_SSID_CFG = 49,
- CMD_START_PERIODIC_SCAN = 50,
- CMD_STOP_PERIODIC_SCAN = 51,
- CMD_SET_PEER_STATE = 52,
- CMD_REMAIN_ON_CHANNEL = 53,
- CMD_CANCEL_REMAIN_ON_CHANNEL = 54,
-
- CMD_CONFIG_FWLOGGER = 55,
- CMD_START_FWLOGGER = 56,
- CMD_STOP_FWLOGGER = 57,
-
- /* AP commands */
- CMD_ADD_PEER = 62,
- CMD_REMOVE_PEER = 63,
+ CMD_INTERROGATE = 1, /* use this to read information elements */
+ CMD_CONFIGURE = 2, /* use this to write information elements */
+ CMD_ENABLE_RX = 3,
+ CMD_ENABLE_TX = 4,
+ CMD_DISABLE_RX = 5,
+ CMD_DISABLE_TX = 6,
+ CMD_SCAN = 7,
+ CMD_STOP_SCAN = 8,
+ CMD_SET_KEYS = 9,
+ CMD_READ_MEMORY = 10,
+ CMD_WRITE_MEMORY = 11,
+ CMD_SET_TEMPLATE = 12,
+ CMD_TEST = 13,
+ CMD_NOISE_HIST = 14,
+ CMD_QUIET_ELEMENT_SET_STATE = 15,
+ CMD_SET_BCN_MODE = 16,
+
+ CMD_MEASUREMENT = 17,
+ CMD_STOP_MEASUREMENT = 18,
+ CMD_SET_PS_MODE = 19,
+ CMD_CHANNEL_SWITCH = 20,
+ CMD_STOP_CHANNEL_SWICTH = 21,
+ CMD_AP_DISCOVERY = 22,
+ CMD_STOP_AP_DISCOVERY = 23,
+ CMD_HEALTH_CHECK = 24,
+ CMD_DEBUG = 25,
+ CMD_TRIGGER_SCAN_TO = 26,
+ CMD_CONNECTION_SCAN_CFG = 27,
+ CMD_CONNECTION_SCAN_SSID_CFG = 28,
+ CMD_START_PERIODIC_SCAN = 29,
+ CMD_STOP_PERIODIC_SCAN = 30,
+ CMD_SET_PEER_STATE = 31,
+ CMD_REMAIN_ON_CHANNEL = 32,
+ CMD_CANCEL_REMAIN_ON_CHANNEL = 33,
+ CMD_CONFIG_FWLOGGER = 34,
+ CMD_START_FWLOGGER = 35,
+ CMD_STOP_FWLOGGER = 36,
+
+ /* Access point commands */
+ CMD_ADD_PEER = 37,
+ CMD_REMOVE_PEER = 38,
/* Role API */
- CMD_ROLE_ENABLE = 70,
- CMD_ROLE_DISABLE = 71,
- CMD_ROLE_START = 72,
- CMD_ROLE_STOP = 73,
+ CMD_ROLE_ENABLE = 39,
+ CMD_ROLE_DISABLE = 40,
+ CMD_ROLE_START = 41,
+ CMD_ROLE_STOP = 42,
- /* WIFI Direct */
- CMD_WFD_START_DISCOVERY = 80,
- CMD_WFD_STOP_DISCOVERY = 81,
- CMD_WFD_ATTRIBUTE_CONFIG = 82,
+ /* DFS */
+ CMD_START_RADAR_DETECTION = 43,
+ CMD_STOP_RADAR_DETECTION = 44,
- CMD_NOP = 100,
+ /* WIFI Direct */
+ CMD_WFD_START_DISCOVERY = 45,
+ CMD_WFD_STOP_DISCOVERY = 46,
+ CMD_WFD_ATTRIBUTE_CONFIG = 47,
+ CMD_NOP = 48,
+ CMD_LAST_COMMAND,
- NUM_COMMANDS,
MAX_COMMAND_ID = 0xFFFF,
};
@@ -191,7 +196,7 @@ enum cmd_templ {
/* unit ms */
#define WL1271_COMMAND_TIMEOUT 2000
#define WL1271_CMD_TEMPL_DFLT_SIZE 252
-#define WL1271_CMD_TEMPL_MAX_SIZE 548
+#define WL1271_CMD_TEMPL_MAX_SIZE 512
#define WL1271_EVENT_TIMEOUT 750
struct wl1271_cmd_header {
@@ -339,7 +344,9 @@ struct wl12xx_cmd_role_start {
u8 ssid_len;
u8 ssid[IEEE80211_MAX_SSID_LEN];
- u8 padding_1[5];
+ u8 reset_tsf;
+
+ u8 padding_1[4];
} __packed ap;
};
} __packed;
@@ -364,14 +371,18 @@ struct cmd_enabledisable_path {
struct wl1271_cmd_template_set {
struct wl1271_cmd_header header;
- __le16 len;
+ u8 role_id;
u8 template_type;
+ __le16 len;
u8 index; /* relevant only for KLV_TEMPLATE type */
+ u8 padding[3];
+
__le32 enabled_rates;
u8 short_retry_limit;
u8 long_retry_limit;
u8 aflags;
u8 reserved;
+
u8 template_data[WL1271_CMD_TEMPL_MAX_SIZE];
} __packed;
@@ -388,6 +399,7 @@ struct wl1271_tim {
} __packed;
enum wl1271_cmd_ps_mode {
+ STATION_AUTO_PS_MODE, /* Dynamic Power Save */
STATION_ACTIVE_MODE,
STATION_POWER_SAVE_MODE
};
@@ -397,7 +409,7 @@ struct wl1271_cmd_ps_params {
u8 role_id;
u8 ps_mode; /* STATION_* */
- u8 padding[2];
+ u16 auto_ps_timeout;
} __packed;
/* HW encryption keys */
@@ -695,14 +707,18 @@ struct wl12xx_cmd_stop_fwlog {
struct wl12xx_cmd_channel_switch {
struct wl1271_cmd_header header;
+ u8 role_id;
+
/* The new serving channel */
u8 channel;
/* Relative time of the serving channel switch in TBTT units */
u8 switch_time;
- /* 1: Suspend TX till switch time; 0: Do not suspend TX */
- u8 tx_suspend;
- /* 1: Flush TX at switch time; 0: Do not flush */
- u8 flush;
+ /* Stop the role TX, should expect it after radar detection */
+ u8 stop_tx;
+ /* The target channel tx status 1-stopped 0-open*/
+ u8 post_switch_tx_disable;
+
+ u8 padding[3];
} __packed;
struct wl12xx_cmd_stop_channel_switch {
diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index 1bcfb017058..cc50faaf03d 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -66,7 +66,8 @@ enum {
};
enum {
- CONF_HW_RXTX_RATE_MCS7 = 0,
+ CONF_HW_RXTX_RATE_MCS7_SGI = 0,
+ CONF_HW_RXTX_RATE_MCS7,
CONF_HW_RXTX_RATE_MCS6,
CONF_HW_RXTX_RATE_MCS5,
CONF_HW_RXTX_RATE_MCS4,
@@ -91,6 +92,10 @@ enum {
CONF_HW_RXTX_RATE_UNSUPPORTED = 0xff
};
+/* Rates between and including these are MCS rates */
+#define CONF_HW_RXTX_RATE_MCS_MIN CONF_HW_RXTX_RATE_MCS7_SGI
+#define CONF_HW_RXTX_RATE_MCS_MAX CONF_HW_RXTX_RATE_MCS0
+
enum {
CONF_SG_DISABLE = 0,
CONF_SG_PROTECTIVE,
@@ -312,6 +317,10 @@ enum {
CONF_AP_BT_ACL_VAL_BT_SERVE_TIME,
CONF_AP_BT_ACL_VAL_WL_SERVE_TIME,
+ /* CTS Diluting params */
+ CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH,
+ CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER,
+
CONF_SG_TEMP_PARAM_1,
CONF_SG_TEMP_PARAM_2,
CONF_SG_TEMP_PARAM_3,
@@ -810,6 +819,19 @@ struct conf_conn_settings {
u8 listen_interval;
/*
+ * Firmware wakeup conditions during suspend
+ * Range: CONF_WAKE_UP_EVENT_*
+ */
+ u8 suspend_wake_up_event;
+
+ /*
+ * Listen interval during suspend.
+ * Currently will be in DTIMs (1-10)
+ *
+ */
+ u8 suspend_listen_interval;
+
+ /*
* Enable or disable the beacon filtering.
*
* Range: CONF_BCN_FILT_MODE_*
@@ -868,13 +890,6 @@ struct conf_conn_settings {
u8 ps_poll_threshold;
/*
- * PS Poll failure recovery ACTIVE period length
- *
- * Range: u32 (ms)
- */
- u32 ps_poll_recovery_period;
-
- /*
* Configuration of signal average weights.
*/
struct conf_sig_weights sig_weights;
@@ -922,6 +937,18 @@ struct conf_conn_settings {
u8 psm_entry_nullfunc_retries;
/*
+ * Specifies the dynamic PS timeout in ms that will be used
+ * by the FW when in AUTO_PS mode
+ */
+ u16 dynamic_ps_timeout;
+
+ /*
+ * Specifies whether dynamic PS should be disabled and PSM forced.
+ * This is required for certain WiFi certification tests.
+ */
+ u8 forced_ps;
+
+ /*
*
* Specifies the interval of the connection keep-alive null-func
* frame in ms.
@@ -1055,6 +1082,14 @@ struct conf_scan_settings {
*/
u16 num_probe_reqs;
+ /*
+ * Scan trigger (split scan) timeout. The FW will split the scan
+ * operation into slices of the given time and allow the FW to schedule
+ * other tasks in between.
+ *
+ * Range: u32 Microsecs
+ */
+ u32 split_scan_timeout;
};
struct conf_sched_scan_settings {
diff --git a/drivers/net/wireless/wl12xx/debug.h b/drivers/net/wireless/wl12xx/debug.h
index b85fd8c41e8..ec0fdc25b28 100644
--- a/drivers/net/wireless/wl12xx/debug.h
+++ b/drivers/net/wireless/wl12xx/debug.h
@@ -51,6 +51,7 @@ enum {
DEBUG_FILTERS = BIT(15),
DEBUG_ADHOC = BIT(16),
DEBUG_AP = BIT(17),
+ DEBUG_PROBE = BIT(18),
DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP),
DEBUG_ALL = ~0,
};
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 15eb3a9c30c..e1cf7276596 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -113,7 +113,7 @@ static void wl1271_debugfs_update_stats(struct wl1271 *wl)
if (ret < 0)
goto out;
- if (wl->state == WL1271_STATE_ON &&
+ if (wl->state == WL1271_STATE_ON && !wl->plt &&
time_after(jiffies, wl->stats.fw_stats_update +
msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) {
wl1271_acx_statistics(wl, wl->stats.fw_stats);
@@ -312,6 +312,181 @@ static const struct file_operations start_recovery_ops = {
.llseek = default_llseek,
};
+static ssize_t dynamic_ps_timeout_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+
+ return wl1271_format_buffer(user_buf, count,
+ ppos, "%d\n",
+ wl->conf.conn.dynamic_ps_timeout);
+}
+
+static ssize_t dynamic_ps_timeout_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ struct wl12xx_vif *wlvif;
+ unsigned long value;
+ int ret;
+
+ ret = kstrtoul_from_user(user_buf, count, 10, &value);
+ if (ret < 0) {
+ wl1271_warning("illegal value in dynamic_ps");
+ return -EINVAL;
+ }
+
+ if (value < 1 || value > 65535) {
+ wl1271_warning("dyanmic_ps_timeout is not in valid range");
+ return -ERANGE;
+ }
+
+ mutex_lock(&wl->mutex);
+
+ wl->conf.conn.dynamic_ps_timeout = value;
+
+ if (wl->state == WL1271_STATE_OFF)
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ /* In case we're already in PSM, trigger it again to set new timeout
+ * immediately without waiting for re-association
+ */
+
+ wl12xx_for_each_wlvif_sta(wl, wlvif) {
+ if (test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags))
+ wl1271_ps_set_mode(wl, wlvif, STATION_AUTO_PS_MODE);
+ }
+
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+ return count;
+}
+
+static const struct file_operations dynamic_ps_timeout_ops = {
+ .read = dynamic_ps_timeout_read,
+ .write = dynamic_ps_timeout_write,
+ .open = wl1271_open_file_generic,
+ .llseek = default_llseek,
+};
+
+static ssize_t forced_ps_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+
+ return wl1271_format_buffer(user_buf, count,
+ ppos, "%d\n",
+ wl->conf.conn.forced_ps);
+}
+
+static ssize_t forced_ps_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ struct wl12xx_vif *wlvif;
+ unsigned long value;
+ int ret, ps_mode;
+
+ ret = kstrtoul_from_user(user_buf, count, 10, &value);
+ if (ret < 0) {
+ wl1271_warning("illegal value in forced_ps");
+ return -EINVAL;
+ }
+
+ if (value != 1 && value != 0) {
+ wl1271_warning("forced_ps should be either 0 or 1");
+ return -ERANGE;
+ }
+
+ mutex_lock(&wl->mutex);
+
+ if (wl->conf.conn.forced_ps == value)
+ goto out;
+
+ wl->conf.conn.forced_ps = value;
+
+ if (wl->state == WL1271_STATE_OFF)
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ /* In case we're already in PSM, trigger it again to switch mode
+ * immediately without waiting for re-association
+ */
+
+ ps_mode = value ? STATION_POWER_SAVE_MODE : STATION_AUTO_PS_MODE;
+
+ wl12xx_for_each_wlvif_sta(wl, wlvif) {
+ if (test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags))
+ wl1271_ps_set_mode(wl, wlvif, ps_mode);
+ }
+
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+ return count;
+}
+
+static const struct file_operations forced_ps_ops = {
+ .read = forced_ps_read,
+ .write = forced_ps_write,
+ .open = wl1271_open_file_generic,
+ .llseek = default_llseek,
+};
+
+static ssize_t split_scan_timeout_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+
+ return wl1271_format_buffer(user_buf, count,
+ ppos, "%d\n",
+ wl->conf.scan.split_scan_timeout / 1000);
+}
+
+static ssize_t split_scan_timeout_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ unsigned long value;
+ int ret;
+
+ ret = kstrtoul_from_user(user_buf, count, 10, &value);
+ if (ret < 0) {
+ wl1271_warning("illegal value in split_scan_timeout");
+ return -EINVAL;
+ }
+
+ if (value == 0)
+ wl1271_info("split scan will be disabled");
+
+ mutex_lock(&wl->mutex);
+
+ wl->conf.scan.split_scan_timeout = value * 1000;
+
+ mutex_unlock(&wl->mutex);
+ return count;
+}
+
+static const struct file_operations split_scan_timeout_ops = {
+ .read = split_scan_timeout_read,
+ .write = split_scan_timeout_write,
+ .open = wl1271_open_file_generic,
+ .llseek = default_llseek,
+};
+
static ssize_t driver_state_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -446,6 +621,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
VIF_STATE_PRINT_INT(sta.basic_rate_idx);
VIF_STATE_PRINT_INT(sta.ap_rate_idx);
VIF_STATE_PRINT_INT(sta.p2p_rate_idx);
+ VIF_STATE_PRINT_INT(sta.qos);
} else {
VIF_STATE_PRINT_INT(ap.global_hlid);
VIF_STATE_PRINT_INT(ap.bcast_hlid);
@@ -471,7 +647,6 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
VIF_STATE_PRINT_INT(default_key);
VIF_STATE_PRINT_INT(aid);
VIF_STATE_PRINT_INT(session_counter);
- VIF_STATE_PRINT_INT(ps_poll_failures);
VIF_STATE_PRINT_INT(psm_entry_retry);
VIF_STATE_PRINT_INT(power_level);
VIF_STATE_PRINT_INT(rssi_thold);
@@ -562,6 +737,64 @@ static const struct file_operations dtim_interval_ops = {
.llseek = default_llseek,
};
+
+
+static ssize_t suspend_dtim_interval_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ u8 value;
+
+ if (wl->conf.conn.suspend_wake_up_event == CONF_WAKE_UP_EVENT_DTIM ||
+ wl->conf.conn.suspend_wake_up_event == CONF_WAKE_UP_EVENT_N_DTIM)
+ value = wl->conf.conn.suspend_listen_interval;
+ else
+ value = 0;
+
+ return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value);
+}
+
+static ssize_t suspend_dtim_interval_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ unsigned long value;
+ int ret;
+
+ ret = kstrtoul_from_user(user_buf, count, 10, &value);
+ if (ret < 0) {
+ wl1271_warning("illegal value for suspend_dtim_interval");
+ return -EINVAL;
+ }
+
+ if (value < 1 || value > 10) {
+ wl1271_warning("suspend_dtim value is not in valid range");
+ return -ERANGE;
+ }
+
+ mutex_lock(&wl->mutex);
+
+ wl->conf.conn.suspend_listen_interval = value;
+ /* for some reason there are different event types for 1 and >1 */
+ if (value == 1)
+ wl->conf.conn.suspend_wake_up_event = CONF_WAKE_UP_EVENT_DTIM;
+ else
+ wl->conf.conn.suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM;
+
+ mutex_unlock(&wl->mutex);
+ return count;
+}
+
+
+static const struct file_operations suspend_dtim_interval_ops = {
+ .read = suspend_dtim_interval_read,
+ .write = suspend_dtim_interval_write,
+ .open = wl1271_open_file_generic,
+ .llseek = default_llseek,
+};
+
static ssize_t beacon_interval_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -886,8 +1119,12 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
DEBUGFS_ADD(driver_state, rootdir);
DEBUGFS_ADD(vifs_state, rootdir);
DEBUGFS_ADD(dtim_interval, rootdir);
+ DEBUGFS_ADD(suspend_dtim_interval, rootdir);
DEBUGFS_ADD(beacon_interval, rootdir);
DEBUGFS_ADD(beacon_filtering, rootdir);
+ DEBUGFS_ADD(dynamic_ps_timeout, rootdir);
+ DEBUGFS_ADD(forced_ps, rootdir);
+ DEBUGFS_ADD(split_scan_timeout, rootdir);
streaming = debugfs_create_dir("rx_streaming", rootdir);
if (!streaming || IS_ERR(streaming))
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c
index d3280df68f5..c953717f38e 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/event.c
@@ -30,133 +30,6 @@
#include "scan.h"
#include "wl12xx_80211.h"
-void wl1271_pspoll_work(struct work_struct *work)
-{
- struct ieee80211_vif *vif;
- struct wl12xx_vif *wlvif;
- struct delayed_work *dwork;
- struct wl1271 *wl;
- int ret;
-
- dwork = container_of(work, struct delayed_work, work);
- wlvif = container_of(dwork, struct wl12xx_vif, pspoll_work);
- vif = container_of((void *)wlvif, struct ieee80211_vif, drv_priv);
- wl = wlvif->wl;
-
- wl1271_debug(DEBUG_EVENT, "pspoll work");
-
- mutex_lock(&wl->mutex);
-
- if (unlikely(wl->state == WL1271_STATE_OFF))
- goto out;
-
- if (!test_and_clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags))
- goto out;
-
- if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
- goto out;
-
- /*
- * if we end up here, then we were in powersave when the pspoll
- * delivery failure occurred, and no-one changed state since, so
- * we should go back to powersave.
- */
- ret = wl1271_ps_elp_wakeup(wl);
- if (ret < 0)
- goto out;
-
- wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
- wlvif->basic_rate, true);
-
- wl1271_ps_elp_sleep(wl);
-out:
- mutex_unlock(&wl->mutex);
-};
-
-static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl,
- struct wl12xx_vif *wlvif)
-{
- int delay = wl->conf.conn.ps_poll_recovery_period;
- int ret;
-
- wlvif->ps_poll_failures++;
- if (wlvif->ps_poll_failures == 1)
- wl1271_info("AP with dysfunctional ps-poll, "
- "trying to work around it.");
-
- /* force active mode receive data from the AP */
- if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
- ret = wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
- wlvif->basic_rate, true);
- if (ret < 0)
- return;
- set_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
- ieee80211_queue_delayed_work(wl->hw, &wlvif->pspoll_work,
- msecs_to_jiffies(delay));
- }
-
- /*
- * If already in active mode, lets we should be getting data from
- * the AP right away. If we enter PSM too fast after this, and data
- * remains on the AP, we will get another event like this, and we'll
- * go into active once more.
- */
-}
-
-static int wl1271_event_ps_report(struct wl1271 *wl,
- struct wl12xx_vif *wlvif,
- struct event_mailbox *mbox,
- bool *beacon_loss)
-{
- int ret = 0;
- u32 total_retries = wl->conf.conn.psm_entry_retries;
-
- wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status);
-
- switch (mbox->ps_status) {
- case EVENT_ENTER_POWER_SAVE_FAIL:
- wl1271_debug(DEBUG_PSM, "PSM entry failed");
-
- if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
- /* remain in active mode */
- wlvif->psm_entry_retry = 0;
- break;
- }
-
- if (wlvif->psm_entry_retry < total_retries) {
- wlvif->psm_entry_retry++;
- ret = wl1271_ps_set_mode(wl, wlvif,
- STATION_POWER_SAVE_MODE,
- wlvif->basic_rate, true);
- } else {
- wl1271_info("No ack to nullfunc from AP.");
- wlvif->psm_entry_retry = 0;
- *beacon_loss = true;
- }
- break;
- case EVENT_ENTER_POWER_SAVE_SUCCESS:
- wlvif->psm_entry_retry = 0;
-
- /*
- * BET has only a minor effect in 5GHz and masks
- * channel switch IEs, so we only enable BET on 2.4GHz
- */
- if (wlvif->band == IEEE80211_BAND_2GHZ)
- /* enable beacon early termination */
- ret = wl1271_acx_bet_enable(wl, wlvif, true);
-
- if (wlvif->ps_compl) {
- complete(wlvif->ps_compl);
- wlvif->ps_compl = NULL;
- }
- break;
- default:
- break;
- }
-
- return ret;
-}
-
static void wl1271_event_rssi_trigger(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct event_mailbox *mbox)
@@ -205,21 +78,13 @@ static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)
static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
u8 enable)
{
- struct ieee80211_vif *vif;
struct wl12xx_vif *wlvif;
if (enable) {
- /* disable dynamic PS when requested by the firmware */
- wl12xx_for_each_wlvif_sta(wl, wlvif) {
- vif = wl12xx_wlvif_to_vif(wlvif);
- ieee80211_disable_dyn_ps(vif);
- }
set_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
} else {
clear_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
wl12xx_for_each_wlvif_sta(wl, wlvif) {
- vif = wl12xx_wlvif_to_vif(wlvif);
- ieee80211_enable_dyn_ps(vif);
wl1271_recalc_rx_streaming(wl, wlvif);
}
}
@@ -237,7 +102,6 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
{
struct ieee80211_vif *vif;
struct wl12xx_vif *wlvif;
- int ret;
u32 vector;
bool beacon_loss = false;
bool disconnect_sta = false;
@@ -293,21 +157,6 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
beacon_loss = true;
}
- if (vector & PS_REPORT_EVENT_ID) {
- wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
- wl12xx_for_each_wlvif_sta(wl, wlvif) {
- ret = wl1271_event_ps_report(wl, wlvif,
- mbox, &beacon_loss);
- if (ret < 0)
- return ret;
- }
- }
-
- if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID)
- wl12xx_for_each_wlvif_sta(wl, wlvif) {
- wl1271_event_pspoll_delivery_fail(wl, wlvif);
- }
-
if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
/* TODO: check actual multi-role support */
wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
@@ -344,7 +193,6 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
/* TODO: configure only the relevant vif */
wl12xx_for_each_wlvif_sta(wl, wlvif) {
- struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
bool success;
if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS,
@@ -352,6 +200,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
continue;
success = mbox->channel_switch_status ? false : true;
+ vif = wl12xx_wlvif_to_vif(wlvif);
+
ieee80211_chswitch_done(vif, success);
}
}
diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h
index 1d878ba47bf..057d193d352 100644
--- a/drivers/net/wireless/wl12xx/event.h
+++ b/drivers/net/wireless/wl12xx/event.h
@@ -51,10 +51,10 @@ enum {
SCAN_COMPLETE_EVENT_ID = BIT(10),
WFD_DISCOVERY_COMPLETE_EVENT_ID = BIT(11),
AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12),
- PS_REPORT_EVENT_ID = BIT(13),
+ RESERVED1 = BIT(13),
PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14),
- DISCONNECT_EVENT_COMPLETE_ID = BIT(15),
- /* BIT(16) is reserved */
+ ROLE_STOP_COMPLETE_EVENT_ID = BIT(15),
+ RADAR_DETECTED_EVENT_ID = BIT(16),
CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17),
BSS_LOSE_EVENT_ID = BIT(18),
REGAINED_BSS_EVENT_ID = BIT(19),
@@ -94,9 +94,9 @@ struct event_mailbox {
u8 soft_gemini_sense_info;
u8 soft_gemini_protective_info;
s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS];
- u8 channel_switch_status;
+ u8 change_auto_mode_timeout;
u8 scheduled_scan_status;
- u8 ps_status;
+ u8 reserved4;
/* tuned channel (roc) */
u8 roc_channel;
@@ -119,17 +119,21 @@ struct event_mailbox {
u8 rx_ba_allowed;
u8 reserved_6[2];
+ /* Channel switch results */
+
+ u8 channel_switch_role_id;
+ u8 channel_switch_status;
+ u8 reserved_7[2];
+
u8 ps_poll_delivery_failure_role_ids;
u8 stopped_role_ids;
u8 started_role_ids;
- u8 change_auto_mode_timeout;
- u8 reserved_7[12];
+ u8 reserved_8[9];
} __packed;
int wl1271_event_unmask(struct wl1271 *wl);
void wl1271_event_mbox_config(struct wl1271 *wl);
int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
-void wl1271_pspoll_work(struct work_struct *work);
#endif
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index ca7ee59e450..203fbebf09e 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -37,54 +37,64 @@
int wl1271_init_templates_config(struct wl1271 *wl)
{
int ret, i;
+ size_t max_size;
/* send empty templates for fw memory reservation */
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
- WL1271_CMD_TEMPL_DFLT_SIZE,
+ ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+ CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
+ WL1271_CMD_TEMPL_MAX_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
- NULL, WL1271_CMD_TEMPL_DFLT_SIZE, 0,
+ ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+ CMD_TEMPL_CFG_PROBE_REQ_5,
+ NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0,
WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL,
+ ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+ CMD_TEMPL_NULL_DATA, NULL,
sizeof(struct wl12xx_null_data_template),
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL,
+ ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+ CMD_TEMPL_PS_POLL, NULL,
sizeof(struct wl12xx_ps_poll_template),
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL,
+ ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+ CMD_TEMPL_QOS_NULL_DATA, NULL,
sizeof
(struct ieee80211_qos_hdr),
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL,
+ ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+ CMD_TEMPL_PROBE_RESPONSE, NULL,
WL1271_CMD_TEMPL_DFLT_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL,
+ ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+ CMD_TEMPL_BEACON, NULL,
WL1271_CMD_TEMPL_DFLT_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, NULL,
- sizeof
- (struct wl12xx_arp_rsp_template),
+ max_size = sizeof(struct wl12xx_arp_rsp_template) +
+ WL1271_EXTRA_SPACE_MAX;
+ ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+ CMD_TEMPL_ARP_RSP, NULL,
+ max_size,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
@@ -93,19 +103,22 @@ int wl1271_init_templates_config(struct wl1271 *wl)
* Put very large empty placeholders for all templates. These
* reserve memory for later.
*/
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, NULL,
+ ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+ CMD_TEMPL_AP_PROBE_RESPONSE, NULL,
WL1271_CMD_TEMPL_MAX_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_BEACON, NULL,
+ ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+ CMD_TEMPL_AP_BEACON, NULL,
WL1271_CMD_TEMPL_MAX_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, NULL,
+ ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+ CMD_TEMPL_DEAUTH_AP, NULL,
sizeof
(struct wl12xx_disconn_template),
0, WL1271_RATE_AUTOMATIC);
@@ -113,7 +126,8 @@ int wl1271_init_templates_config(struct wl1271 *wl)
return ret;
for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL,
+ ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
+ CMD_TEMPL_KLV, NULL,
sizeof(struct ieee80211_qos_hdr),
i, WL1271_RATE_AUTOMATIC);
if (ret < 0)
@@ -140,7 +154,8 @@ static int wl1271_ap_init_deauth_template(struct wl1271 *wl,
IEEE80211_STYPE_DEAUTH);
rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP,
+ ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+ CMD_TEMPL_DEAUTH_AP,
tmpl, sizeof(*tmpl), 0, rate);
out:
@@ -172,7 +187,8 @@ static int wl1271_ap_init_null_template(struct wl1271 *wl,
memcpy(nullfunc->addr3, vif->addr, ETH_ALEN);
rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc,
+ ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+ CMD_TEMPL_NULL_DATA, nullfunc,
sizeof(*nullfunc), 0, rate);
out:
@@ -204,7 +220,8 @@ static int wl1271_ap_init_qos_null_template(struct wl1271 *wl,
memcpy(qosnull->addr3, vif->addr, ETH_ALEN);
rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
- ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull,
+ ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+ CMD_TEMPL_QOS_NULL_DATA, qosnull,
sizeof(*qosnull), 0, rate);
out:
diff --git a/drivers/net/wireless/wl12xx/io.c b/drivers/net/wireless/wl12xx/io.c
index 079ad380e8f..c574a3b31e3 100644
--- a/drivers/net/wireless/wl12xx/io.c
+++ b/drivers/net/wireless/wl12xx/io.c
@@ -45,6 +45,65 @@
#define OCP_STATUS_REQ_FAILED 0x20000
#define OCP_STATUS_RESP_ERROR 0x30000
+struct wl1271_partition_set wl12xx_part_table[PART_TABLE_LEN] = {
+ [PART_DOWN] = {
+ .mem = {
+ .start = 0x00000000,
+ .size = 0x000177c0
+ },
+ .reg = {
+ .start = REGISTERS_BASE,
+ .size = 0x00008800
+ },
+ .mem2 = {
+ .start = 0x00000000,
+ .size = 0x00000000
+ },
+ .mem3 = {
+ .start = 0x00000000,
+ .size = 0x00000000
+ },
+ },
+
+ [PART_WORK] = {
+ .mem = {
+ .start = 0x00040000,
+ .size = 0x00014fc0
+ },
+ .reg = {
+ .start = REGISTERS_BASE,
+ .size = 0x0000a000
+ },
+ .mem2 = {
+ .start = 0x003004f8,
+ .size = 0x00000004
+ },
+ .mem3 = {
+ .start = 0x00040404,
+ .size = 0x00000000
+ },
+ },
+
+ [PART_DRPW] = {
+ .mem = {
+ .start = 0x00040000,
+ .size = 0x00014fc0
+ },
+ .reg = {
+ .start = DRPW_BASE,
+ .size = 0x00006000
+ },
+ .mem2 = {
+ .start = 0x00000000,
+ .size = 0x00000000
+ },
+ .mem3 = {
+ .start = 0x00000000,
+ .size = 0x00000000
+ }
+ }
+};
+
bool wl1271_set_block_size(struct wl1271 *wl)
{
if (wl->if_ops->set_block_size) {
diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h
index d398cbcea98..4fb3dab8c3b 100644
--- a/drivers/net/wireless/wl12xx/io.h
+++ b/drivers/net/wireless/wl12xx/io.h
@@ -43,6 +43,8 @@
#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000
+extern struct wl1271_partition_set wl12xx_part_table[PART_TABLE_LEN];
+
struct wl1271;
void wl1271_disable_interrupts(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index f8748cedbae..adf9bbcf88f 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1,3 +1,4 @@
+
/*
* This file is part of wl1271
*
@@ -115,6 +116,9 @@ static struct conf_drv_settings default_conf = {
[CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
[CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
[CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
+ /* CTS Diluting params */
+ [CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0,
+ [CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0,
},
.state = CONF_SG_PROTECTIVE,
},
@@ -217,6 +221,8 @@ static struct conf_drv_settings default_conf = {
.conn = {
.wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
.listen_interval = 1,
+ .suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM,
+ .suspend_listen_interval = 3,
.bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
.bcn_filt_ie_count = 2,
.bcn_filt_ie = {
@@ -235,12 +241,13 @@ static struct conf_drv_settings default_conf = {
.broadcast_timeout = 20000,
.rx_broadcast_in_ps = 1,
.ps_poll_threshold = 10,
- .ps_poll_recovery_period = 700,
.bet_enable = CONF_BET_MODE_ENABLE,
.bet_max_consecutive = 50,
.psm_entry_retries = 8,
.psm_exit_retries = 16,
.psm_entry_nullfunc_retries = 3,
+ .dynamic_ps_timeout = 100,
+ .forced_ps = false,
.keep_alive_interval = 55000,
.max_listen_interval = 20,
},
@@ -265,6 +272,7 @@ static struct conf_drv_settings default_conf = {
.min_dwell_time_passive = 100000,
.max_dwell_time_passive = 100000,
.num_probe_reqs = 2,
+ .split_scan_timeout = 50000,
},
.sched_scan = {
/* sched_scan requires dwell times in TU instead of TU/1000 */
@@ -672,8 +680,6 @@ static int wl1271_plt_init(struct wl1271 *wl)
if (ret < 0)
return ret;
}
- if (ret < 0)
- return ret;
/* Chip-specific initializations */
ret = wl1271_chip_specific_init(wl);
@@ -985,16 +991,70 @@ out:
return IRQ_HANDLED;
}
-static int wl1271_fetch_firmware(struct wl1271 *wl)
+struct vif_counter_data {
+ u8 counter;
+
+ struct ieee80211_vif *cur_vif;
+ bool cur_vif_running;
+};
+
+static void wl12xx_vif_count_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct vif_counter_data *counter = data;
+
+ counter->counter++;
+ if (counter->cur_vif == vif)
+ counter->cur_vif_running = true;
+}
+
+/* caller must not hold wl->mutex, as it might deadlock */
+static void wl12xx_get_vif_count(struct ieee80211_hw *hw,
+ struct ieee80211_vif *cur_vif,
+ struct vif_counter_data *data)
+{
+ memset(data, 0, sizeof(*data));
+ data->cur_vif = cur_vif;
+
+ ieee80211_iterate_active_interfaces(hw,
+ wl12xx_vif_count_iter, data);
+}
+
+static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
{
const struct firmware *fw;
const char *fw_name;
+ enum wl12xx_fw_type fw_type;
int ret;
- if (wl->chip.id == CHIP_ID_1283_PG20)
- fw_name = WL128X_FW_NAME;
- else
- fw_name = WL127X_FW_NAME;
+ if (plt) {
+ fw_type = WL12XX_FW_TYPE_PLT;
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ fw_name = WL128X_PLT_FW_NAME;
+ else
+ fw_name = WL127X_PLT_FW_NAME;
+ } else {
+ /*
+ * we can't call wl12xx_get_vif_count() here because
+ * wl->mutex is taken, so use the cached last_vif_count value
+ */
+ if (wl->last_vif_count > 1) {
+ fw_type = WL12XX_FW_TYPE_MULTI;
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ fw_name = WL128X_FW_NAME_MULTI;
+ else
+ fw_name = WL127X_FW_NAME_MULTI;
+ } else {
+ fw_type = WL12XX_FW_TYPE_NORMAL;
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ fw_name = WL128X_FW_NAME_SINGLE;
+ else
+ fw_name = WL127X_FW_NAME_SINGLE;
+ }
+ }
+
+ if (wl->fw_type == fw_type)
+ return 0;
wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
@@ -1013,6 +1073,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
}
vfree(wl->fw);
+ wl->fw_type = WL12XX_FW_TYPE_NONE;
wl->fw_len = fw->size;
wl->fw = vmalloc(wl->fw_len);
@@ -1024,7 +1085,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
memcpy(wl->fw, fw->data, wl->fw_len);
ret = 0;
-
+ wl->fw_type = fw_type;
out:
release_firmware(fw);
@@ -1152,7 +1213,7 @@ static void wl1271_recovery_work(struct work_struct *work)
mutex_lock(&wl->mutex);
- if (wl->state != WL1271_STATE_ON)
+ if (wl->state != WL1271_STATE_ON || wl->plt)
goto out_unlock;
/* Avoid a recursive recovery */
@@ -1232,10 +1293,9 @@ static int wl1271_setup(struct wl1271 *wl)
return 0;
}
-static int wl1271_chip_wakeup(struct wl1271 *wl)
+static int wl12xx_set_power_on(struct wl1271 *wl)
{
- struct wl1271_partition_set partition;
- int ret = 0;
+ int ret;
msleep(WL1271_PRE_POWER_ON_SLEEP);
ret = wl1271_power_on(wl);
@@ -1245,20 +1305,22 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
wl1271_io_reset(wl);
wl1271_io_init(wl);
- /* We don't need a real memory partition here, because we only want
- * to use the registers at this point. */
- memset(&partition, 0, sizeof(partition));
- partition.reg.start = REGISTERS_BASE;
- partition.reg.size = REGISTERS_DOWN_SIZE;
- wl1271_set_partition(wl, &partition);
+ wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
/* ELP module wake up */
wl1271_fw_wakeup(wl);
- /* whal_FwCtrl_BootSm() */
+out:
+ return ret;
+}
- /* 0. read chip id from CHIP_ID */
- wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
+static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
+{
+ int ret = 0;
+
+ ret = wl12xx_set_power_on(wl);
+ if (ret < 0)
+ goto out;
/*
* For wl127x based devices we could use the default block
@@ -1307,11 +1369,9 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
goto out;
}
- if (wl->fw == NULL) {
- ret = wl1271_fetch_firmware(wl);
- if (ret < 0)
- goto out;
- }
+ ret = wl12xx_fetch_firmware(wl, plt);
+ if (ret < 0)
+ goto out;
/* No NVS from netlink, try to get it from the filesystem */
if (wl->nvs == NULL) {
@@ -1343,7 +1403,7 @@ int wl1271_plt_start(struct wl1271 *wl)
while (retries) {
retries--;
- ret = wl1271_chip_wakeup(wl);
+ ret = wl12xx_chip_wakeup(wl, true);
if (ret < 0)
goto power_off;
@@ -1355,7 +1415,8 @@ int wl1271_plt_start(struct wl1271 *wl)
if (ret < 0)
goto irq_disable;
- wl->state = WL1271_STATE_PLT;
+ wl->plt = true;
+ wl->state = WL1271_STATE_ON;
wl1271_notice("firmware booted in PLT mode (%s)",
wl->chip.fw_ver_str);
@@ -1391,41 +1452,51 @@ out:
return ret;
}
-static int __wl1271_plt_stop(struct wl1271 *wl)
+int wl1271_plt_stop(struct wl1271 *wl)
{
int ret = 0;
wl1271_notice("power down");
- if (wl->state != WL1271_STATE_PLT) {
+ /*
+ * Interrupts must be disabled before setting the state to OFF.
+ * Otherwise, the interrupt handler might be called and exit without
+ * reading the interrupt status.
+ */
+ wl1271_disable_interrupts(wl);
+ mutex_lock(&wl->mutex);
+ if (!wl->plt) {
+ mutex_unlock(&wl->mutex);
+
+ /*
+ * This will not necessarily enable interrupts as interrupts
+ * may have been disabled when op_stop was called. It will,
+ * however, balance the above call to disable_interrupts().
+ */
+ wl1271_enable_interrupts(wl);
+
wl1271_error("cannot power down because not in PLT "
"state: %d", wl->state);
ret = -EBUSY;
goto out;
}
- wl1271_power_off(wl);
-
- wl->state = WL1271_STATE_OFF;
- wl->rx_counter = 0;
-
mutex_unlock(&wl->mutex);
- wl1271_disable_interrupts(wl);
+
wl1271_flush_deferred_work(wl);
cancel_work_sync(&wl->netstack_work);
cancel_work_sync(&wl->recovery_work);
- mutex_lock(&wl->mutex);
-out:
- return ret;
-}
-
-int wl1271_plt_stop(struct wl1271 *wl)
-{
- int ret;
+ cancel_delayed_work_sync(&wl->elp_work);
mutex_lock(&wl->mutex);
- ret = __wl1271_plt_stop(wl);
+ wl1271_power_off(wl);
+ wl->flags = 0;
+ wl->state = WL1271_STATE_OFF;
+ wl->plt = false;
+ wl->rx_counter = 0;
mutex_unlock(&wl->mutex);
+
+out:
return ret;
}
@@ -1574,38 +1645,16 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
if (ret < 0)
goto out_unlock;
- /* enter psm if needed*/
- if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
- DECLARE_COMPLETION_ONSTACK(compl);
+ ret = wl1271_acx_wake_up_conditions(wl, wlvif,
+ wl->conf.conn.suspend_wake_up_event,
+ wl->conf.conn.suspend_listen_interval);
- wlvif->ps_compl = &compl;
- ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
- wlvif->basic_rate, true);
- if (ret < 0)
- goto out_sleep;
-
- /* we must unlock here so we will be able to get events */
- wl1271_ps_elp_sleep(wl);
- mutex_unlock(&wl->mutex);
-
- ret = wait_for_completion_timeout(
- &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
+ if (ret < 0)
+ wl1271_error("suspend: set wake up conditions failed: %d", ret);
- mutex_lock(&wl->mutex);
- if (ret <= 0) {
- wl1271_warning("couldn't enter ps mode!");
- ret = -EBUSY;
- goto out_cleanup;
- }
- ret = wl1271_ps_elp_wakeup(wl);
- if (ret < 0)
- goto out_cleanup;
- }
-out_sleep:
wl1271_ps_elp_sleep(wl);
-out_cleanup:
- wlvif->ps_compl = NULL;
+
out_unlock:
mutex_unlock(&wl->mutex);
return ret;
@@ -1648,11 +1697,11 @@ static int wl1271_configure_suspend(struct wl1271 *wl,
static void wl1271_configure_resume(struct wl1271 *wl,
struct wl12xx_vif *wlvif)
{
- int ret;
- bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
+ int ret = 0;
bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
+ bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
- if (!is_sta && !is_ap)
+ if ((!is_ap) && (!is_sta))
return;
mutex_lock(&wl->mutex);
@@ -1661,12 +1710,16 @@ static void wl1271_configure_resume(struct wl1271 *wl,
goto out;
if (is_sta) {
- /* exit psm if it wasn't configured */
- if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
- wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
- wlvif->basic_rate, true);
+ ret = wl1271_acx_wake_up_conditions(wl, wlvif,
+ wl->conf.conn.wake_up_event,
+ wl->conf.conn.listen_interval);
+
+ if (ret < 0)
+ wl1271_error("resume: wake up conditions failed: %d",
+ ret);
+
} else if (is_ap) {
- wl1271_acx_beacon_filter_opt(wl, wlvif, false);
+ ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
}
wl1271_ps_elp_sleep(wl);
@@ -1709,9 +1762,6 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
wl1271_enable_interrupts(wl);
flush_work(&wl->tx_work);
- wl12xx_for_each_wlvif(wl, wlvif) {
- flush_delayed_work(&wlvif->pspoll_work);
- }
flush_delayed_work(&wl->elp_work);
return 0;
@@ -1778,11 +1828,25 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
+ /*
+ * Interrupts must be disabled before setting the state to OFF.
+ * Otherwise, the interrupt handler might be called and exit without
+ * reading the interrupt status.
+ */
+ wl1271_disable_interrupts(wl);
mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF) {
mutex_unlock(&wl->mutex);
+
+ /*
+ * This will not necessarily enable interrupts as interrupts
+ * may have been disabled when op_stop was called. It will,
+ * however, balance the above call to disable_interrupts().
+ */
+ wl1271_enable_interrupts(wl);
return;
}
+
/*
* this must be before the cancel_work calls below, so that the work
* functions don't perform further work.
@@ -1794,7 +1858,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
list_del(&wl->list);
mutex_unlock(&wl_list_mutex);
- wl1271_disable_interrupts(wl);
wl1271_flush_deferred_work(wl);
cancel_delayed_work_sync(&wl->scan_complete_work);
cancel_work_sync(&wl->netstack_work);
@@ -1969,7 +2032,6 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
wl1271_rx_streaming_enable_work);
INIT_WORK(&wlvif->rx_streaming_disable_work,
wl1271_rx_streaming_disable_work);
- INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
INIT_LIST_HEAD(&wlvif->list);
setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
@@ -1986,7 +2048,7 @@ static bool wl12xx_init_fw(struct wl1271 *wl)
while (retries) {
retries--;
- ret = wl1271_chip_wakeup(wl);
+ ret = wl12xx_chip_wakeup(wl, false);
if (ret < 0)
goto power_off;
@@ -2051,11 +2113,60 @@ static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
}
+/*
+ * Check whether a fw switch (i.e. moving from one loaded
+ * fw to another) is needed. This function is also responsible
+ * for updating wl->last_vif_count, so it must be called before
+ * loading a non-plt fw (so the correct fw (single-role/multi-role)
+ * will be used).
+ */
+static bool wl12xx_need_fw_change(struct wl1271 *wl,
+ struct vif_counter_data vif_counter_data,
+ bool add)
+{
+ enum wl12xx_fw_type current_fw = wl->fw_type;
+ u8 vif_count = vif_counter_data.counter;
+
+ if (test_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags))
+ return false;
+
+ /* increase the vif count if this is a new vif */
+ if (add && !vif_counter_data.cur_vif_running)
+ vif_count++;
+
+ wl->last_vif_count = vif_count;
+
+ /* no need for fw change if the device is OFF */
+ if (wl->state == WL1271_STATE_OFF)
+ return false;
+
+ if (vif_count > 1 && current_fw == WL12XX_FW_TYPE_NORMAL)
+ return true;
+ if (vif_count <= 1 && current_fw == WL12XX_FW_TYPE_MULTI)
+ return true;
+
+ return false;
+}
+
+/*
+ * Enter "forced psm". Make sure the sta is in psm against the ap,
+ * to make the fw switch a bit more disconnection-persistent.
+ */
+static void wl12xx_force_active_psm(struct wl1271 *wl)
+{
+ struct wl12xx_vif *wlvif;
+
+ wl12xx_for_each_wlvif_sta(wl, wlvif) {
+ wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE);
+ }
+}
+
static int wl1271_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+ struct vif_counter_data vif_count;
int ret = 0;
u8 role_type;
bool booted = false;
@@ -2066,18 +2177,13 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
ieee80211_vif_type_p2p(vif), vif->addr);
+ wl12xx_get_vif_count(hw, vif, &vif_count);
+
mutex_lock(&wl->mutex);
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out_unlock;
- if (wl->vif) {
- wl1271_debug(DEBUG_MAC80211,
- "multiple vifs are not supported yet");
- ret = -EBUSY;
- goto out;
- }
-
/*
* in some very corner case HW recovery scenarios its possible to
* get here before __wl1271_op_remove_interface is complete, so
@@ -2089,6 +2195,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
+
ret = wl12xx_init_vif_data(wl, vif);
if (ret < 0)
goto out;
@@ -2100,6 +2207,13 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
+ if (wl12xx_need_fw_change(wl, vif_count, true)) {
+ wl12xx_force_active_psm(wl);
+ mutex_unlock(&wl->mutex);
+ wl1271_recovery_work(&wl->recovery_work);
+ return 0;
+ }
+
/*
* TODO: after the nvs issue will be solved, move this block
* to start(), and make sure here the driver is ON.
@@ -2109,7 +2223,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
* we still need this in order to configure the fw
* while uploading the nvs
*/
- memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
+ memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
booted = wl12xx_init_fw(wl);
if (!booted) {
@@ -2142,7 +2256,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- wl->vif = vif;
list_add(&wlvif->list, &wl->wlvif_list);
set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
@@ -2175,18 +2288,12 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
return;
- wl->vif = NULL;
-
/* because of hardware recovery, we may get here twice */
if (wl->state != WL1271_STATE_ON)
return;
wl1271_info("down");
- /* enable dyn ps just in case (if left on due to fw crash etc) */
- if (wlvif->bss_type == BSS_TYPE_STA_BSS)
- ieee80211_enable_dyn_ps(vif);
-
if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
wl->scan_vif == vif) {
wl->scan.state = WL1271_SCAN_STATE_IDLE;
@@ -2253,10 +2360,10 @@ deinit:
wl->sta_count--;
mutex_unlock(&wl->mutex);
+
del_timer_sync(&wlvif->rx_streaming_timer);
cancel_work_sync(&wlvif->rx_streaming_enable_work);
cancel_work_sync(&wlvif->rx_streaming_disable_work);
- cancel_delayed_work_sync(&wlvif->pspoll_work);
mutex_lock(&wl->mutex);
}
@@ -2267,7 +2374,10 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
struct wl12xx_vif *iter;
+ struct vif_counter_data vif_count;
+ bool cancel_recovery = true;
+ wl12xx_get_vif_count(hw, vif, &vif_count);
mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF ||
@@ -2286,20 +2396,33 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
break;
}
WARN_ON(iter != wlvif);
+ if (wl12xx_need_fw_change(wl, vif_count, false)) {
+ wl12xx_force_active_psm(wl);
+ wl12xx_queue_recovery_work(wl);
+ cancel_recovery = false;
+ }
out:
mutex_unlock(&wl->mutex);
- cancel_work_sync(&wl->recovery_work);
+ if (cancel_recovery)
+ cancel_work_sync(&wl->recovery_work);
}
static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum nl80211_iftype new_type, bool p2p)
{
+ struct wl1271 *wl = hw->priv;
+ int ret;
+
+ set_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
wl1271_op_remove_interface(hw, vif);
vif->type = ieee80211_iftype_p2p(new_type, p2p);
vif->p2p = p2p;
- return wl1271_op_add_interface(hw, vif);
+ ret = wl1271_op_add_interface(hw, vif);
+
+ clear_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
+ return ret;
}
static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
@@ -2320,6 +2443,9 @@ static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
wl1271_info("JOIN while associated.");
+ /* clear encryption type */
+ wlvif->encryption_type = KEY_NONE;
+
if (set_assoc)
set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
@@ -2503,38 +2629,41 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
}
}
- /*
- * if mac80211 changes the PSM mode, make sure the mode is not
- * incorrectly changed after the pspoll failure active window.
- */
- if (changed & IEEE80211_CONF_CHANGE_PS)
- clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
+ if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) {
- if (conf->flags & IEEE80211_CONF_PS &&
- !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
- set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
+ if ((conf->flags & IEEE80211_CONF_PS) &&
+ test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
+ !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
- /*
- * We enter PSM only if we're already associated.
- * If we're not, we'll enter it when joining an SSID,
- * through the bss_info_changed() hook.
- */
- if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
- wl1271_debug(DEBUG_PSM, "psm enabled");
- ret = wl1271_ps_set_mode(wl, wlvif,
- STATION_POWER_SAVE_MODE,
- wlvif->basic_rate, true);
- }
- } else if (!(conf->flags & IEEE80211_CONF_PS) &&
- test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
- wl1271_debug(DEBUG_PSM, "psm disabled");
+ int ps_mode;
+ char *ps_mode_str;
- clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
+ if (wl->conf.conn.forced_ps) {
+ ps_mode = STATION_POWER_SAVE_MODE;
+ ps_mode_str = "forced";
+ } else {
+ ps_mode = STATION_AUTO_PS_MODE;
+ ps_mode_str = "auto";
+ }
+
+ wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
+
+ ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
+
+ if (ret < 0)
+ wl1271_warning("enter %s ps failed %d",
+ ps_mode_str, ret);
+
+ } else if (!(conf->flags & IEEE80211_CONF_PS) &&
+ test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
+
+ wl1271_debug(DEBUG_PSM, "auto ps disabled");
- if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
ret = wl1271_ps_set_mode(wl, wlvif,
- STATION_ACTIVE_MODE,
- wlvif->basic_rate, true);
+ STATION_ACTIVE_MODE);
+ if (ret < 0)
+ wl1271_warning("exit auto ps failed %d", ret);
+ }
}
if (conf->power_level != wlvif->power_level) {
@@ -2974,6 +3103,21 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
wl1271_error("Could not add or replace key");
goto out_sleep;
}
+
+ /*
+ * reconfiguring arp response if the unicast (or common)
+ * encryption key type was changed
+ */
+ if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
+ (sta || key_type == KEY_WEP) &&
+ wlvif->encryption_type != key_type) {
+ wlvif->encryption_type = key_type;
+ ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
+ if (ret < 0) {
+ wl1271_warning("build arp rsp failed: %d", ret);
+ goto out_sleep;
+ }
+ }
break;
case DISABLE_KEY:
@@ -3043,10 +3187,6 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
goto out_sleep;
}
- /* cancel ROC before scanning */
- if (wl12xx_dev_role_started(wlvif))
- wl12xx_stop_dev(wl, wlvif);
-
ret = wl1271_scan(hw->priv, vif, ssid, len, req);
out_sleep:
wl1271_ps_elp_sleep(wl);
@@ -3108,6 +3248,11 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
mutex_lock(&wl->mutex);
+ if (wl->state == WL1271_STATE_OFF) {
+ ret = -EAGAIN;
+ goto out;
+ }
+
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
@@ -3139,6 +3284,9 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
mutex_lock(&wl->mutex);
+ if (wl->state == WL1271_STATE_OFF)
+ goto out;
+
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
@@ -3266,6 +3414,7 @@ static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
struct ieee80211_vif *vif)
{
+ struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
struct sk_buff *skb;
int ret;
@@ -3273,7 +3422,7 @@ static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
if (!skb)
return -EOPNOTSUPP;
- ret = wl1271_cmd_template_set(wl,
+ ret = wl1271_cmd_template_set(wl, wlvif->role_id,
CMD_TEMPL_AP_PROBE_RESPONSE,
skb->data,
skb->len, 0,
@@ -3297,7 +3446,7 @@ static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
/* no need to change probe response if the SSID is set correctly */
if (wlvif->ssid_len > 0)
- return wl1271_cmd_template_set(wl,
+ return wl1271_cmd_template_set(wl, wlvif->role_id,
CMD_TEMPL_AP_PROBE_RESPONSE,
probe_rsp_data,
probe_rsp_len, 0,
@@ -3334,7 +3483,7 @@ static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
ptr, probe_rsp_len - (ptr - probe_rsp_data));
templ_len += probe_rsp_len - (ptr - probe_rsp_data);
- return wl1271_cmd_template_set(wl,
+ return wl1271_cmd_template_set(wl, wlvif->role_id,
CMD_TEMPL_AP_PROBE_RESPONSE,
probe_rsp_templ,
templ_len, 0,
@@ -3431,7 +3580,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
CMD_TEMPL_BEACON;
- ret = wl1271_cmd_template_set(wl, tmpl_id,
+ ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
beacon->data,
beacon->len, 0,
min_rate);
@@ -3470,7 +3619,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
beacon->len,
min_rate);
else
- ret = wl1271_cmd_template_set(wl,
+ ret = wl1271_cmd_template_set(wl, wlvif->role_id,
CMD_TEMPL_PROBE_RESPONSE,
beacon->data,
beacon->len, 0,
@@ -3634,7 +3783,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
}
- if (changed & BSS_CHANGED_BSSID)
+ if (changed & BSS_CHANGED_BSSID &&
+ (is_ibss || bss_conf->assoc))
if (!is_zero_ether_addr(bss_conf->bssid)) {
ret = wl12xx_cmd_build_null_data(wl, wlvif);
if (ret < 0)
@@ -3673,8 +3823,6 @@ sta_not_found:
wlvif->aid = bss_conf->aid;
set_assoc = true;
- wlvif->ps_poll_failures = 0;
-
/*
* use basic rates from AP, and determine lowest rate
* to use with control frames.
@@ -3734,9 +3882,6 @@ sta_not_found:
dev_kfree_skb(wlvif->probereq);
wlvif->probereq = NULL;
- /* re-enable dynamic ps - just in case */
- ieee80211_enable_dyn_ps(vif);
-
/* revert back to minimum rates for the current band */
wl1271_set_band_rate(wl, wlvif);
wlvif->basic_rate =
@@ -3810,34 +3955,6 @@ sta_not_found:
if (ret < 0)
goto out;
- if (changed & BSS_CHANGED_ARP_FILTER) {
- __be32 addr = bss_conf->arp_addr_list[0];
- WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
-
- if (bss_conf->arp_addr_cnt == 1 &&
- bss_conf->arp_filter_enabled) {
- /*
- * The template should have been configured only upon
- * association. however, it seems that the correct ip
- * isn't being set (when sending), so we have to
- * reconfigure the template upon every ip change.
- */
- ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
- if (ret < 0) {
- wl1271_warning("build arp rsp failed: %d", ret);
- goto out;
- }
-
- ret = wl1271_acx_arp_ip_filter(wl, wlvif,
- ACX_ARP_FILTER_ARP_FILTERING,
- addr);
- } else
- ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
-
- if (ret < 0)
- goto out;
- }
-
if (do_join) {
ret = wl1271_join(wl, wlvif, set_assoc);
if (ret < 0) {
@@ -3863,19 +3980,6 @@ sta_not_found:
if (ret < 0)
goto out;
}
-
- /* If we want to go in PSM but we're not there yet */
- if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
- !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
- enum wl1271_cmd_ps_mode mode;
-
- mode = STATION_POWER_SAVE_MODE;
- ret = wl1271_ps_set_mode(wl, wlvif, mode,
- wlvif->basic_rate,
- true);
- if (ret < 0)
- goto out;
- }
}
/* Handle new association with HT. Do this after join. */
@@ -3917,6 +4021,41 @@ sta_not_found:
}
}
+ /* Handle arp filtering. Done after join. */
+ if ((changed & BSS_CHANGED_ARP_FILTER) ||
+ (!is_ibss && (changed & BSS_CHANGED_QOS))) {
+ __be32 addr = bss_conf->arp_addr_list[0];
+ wlvif->sta.qos = bss_conf->qos;
+ WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
+
+ if (bss_conf->arp_addr_cnt == 1 &&
+ bss_conf->arp_filter_enabled) {
+ wlvif->ip_addr = addr;
+ /*
+ * The template should have been configured only upon
+ * association. however, it seems that the correct ip
+ * isn't being set (when sending), so we have to
+ * reconfigure the template upon every ip change.
+ */
+ ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
+ if (ret < 0) {
+ wl1271_warning("build arp rsp failed: %d", ret);
+ goto out;
+ }
+
+ ret = wl1271_acx_arp_ip_filter(wl, wlvif,
+ (ACX_ARP_FILTER_ARP_FILTERING |
+ ACX_ARP_FILTER_AUTO_ARP),
+ addr);
+ } else {
+ wlvif->ip_addr = 0;
+ ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
+ }
+
+ if (ret < 0)
+ goto out;
+ }
+
out:
return;
}
@@ -4012,6 +4151,7 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
{
struct wl1271 *wl = hw->priv;
+ struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
u64 mactime = ULLONG_MAX;
int ret;
@@ -4026,7 +4166,7 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- ret = wl1271_acx_tsf_info(wl, &mactime);
+ ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime);
if (ret < 0)
goto out_sleep;
@@ -4373,7 +4513,7 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
/* TODO: change mac80211 to pass vif as param */
wl12xx_for_each_wlvif_sta(wl, wlvif) {
- ret = wl12xx_cmd_channel_switch(wl, ch_switch);
+ ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch);
if (!ret)
set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
@@ -4467,6 +4607,7 @@ static struct ieee80211_channel wl1271_channels[] = {
/* mapping to indexes for wl1271_rates */
static const u8 wl1271_rate_to_idx_2ghz[] = {
/* MCS rates are used only with 11n */
+ 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
7, /* CONF_HW_RXTX_RATE_MCS7 */
6, /* CONF_HW_RXTX_RATE_MCS6 */
5, /* CONF_HW_RXTX_RATE_MCS5 */
@@ -4588,6 +4729,7 @@ static struct ieee80211_channel wl1271_channels_5ghz[] = {
/* mapping to indexes for wl1271_rates_5ghz */
static const u8 wl1271_rate_to_idx_5ghz[] = {
/* MCS rates are used only with 11n */
+ 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
7, /* CONF_HW_RXTX_RATE_MCS7 */
6, /* CONF_HW_RXTX_RATE_MCS6 */
5, /* CONF_HW_RXTX_RATE_MCS5 */
@@ -4828,13 +4970,120 @@ static struct bin_attribute fwlog_attr = {
.read = wl1271_sysfs_read_fwlog,
};
+static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
+{
+ bool supported = false;
+ u8 major, minor;
+
+ if (wl->chip.id == CHIP_ID_1283_PG20) {
+ major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
+ minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
+
+ /* in wl128x we have the MAC address if the PG is >= (2, 1) */
+ if (major > 2 || (major == 2 && minor >= 1))
+ supported = true;
+ } else {
+ major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver);
+ minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver);
+
+ /* in wl127x we have the MAC address if the PG is >= (3, 1) */
+ if (major == 3 && minor >= 1)
+ supported = true;
+ }
+
+ wl1271_debug(DEBUG_PROBE,
+ "PG Ver major = %d minor = %d, MAC %s present",
+ major, minor, supported ? "is" : "is not");
+
+ return supported;
+}
+
+static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
+ u32 oui, u32 nic, int n)
+{
+ int i;
+
+ wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d",
+ oui, nic, n);
+
+ if (nic + n - 1 > 0xffffff)
+ wl1271_warning("NIC part of the MAC address wraps around!");
+
+ for (i = 0; i < n; i++) {
+ wl->addresses[i].addr[0] = (u8)(oui >> 16);
+ wl->addresses[i].addr[1] = (u8)(oui >> 8);
+ wl->addresses[i].addr[2] = (u8) oui;
+ wl->addresses[i].addr[3] = (u8)(nic >> 16);
+ wl->addresses[i].addr[4] = (u8)(nic >> 8);
+ wl->addresses[i].addr[5] = (u8) nic;
+ nic++;
+ }
+
+ wl->hw->wiphy->n_addresses = n;
+ wl->hw->wiphy->addresses = wl->addresses;
+}
+
+static void wl12xx_get_fuse_mac(struct wl1271 *wl)
+{
+ u32 mac1, mac2;
+
+ wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
+
+ mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1);
+ mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
+
+ /* these are the two parts of the BD_ADDR */
+ wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
+ ((mac1 & 0xff000000) >> 24);
+ wl->fuse_nic_addr = mac1 & 0xffffff;
+
+ wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
+}
+
+static int wl12xx_get_hw_info(struct wl1271 *wl)
+{
+ int ret;
+ u32 die_info;
+
+ ret = wl12xx_set_power_on(wl);
+ if (ret < 0)
+ goto out;
+
+ wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
+
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
+ else
+ die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
+
+ wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
+
+ if (!wl12xx_mac_in_fuse(wl)) {
+ wl->fuse_oui_addr = 0;
+ wl->fuse_nic_addr = 0;
+ } else {
+ wl12xx_get_fuse_mac(wl);
+ }
+
+ wl1271_power_off(wl);
+out:
+ return ret;
+}
+
static int wl1271_register_hw(struct wl1271 *wl)
{
int ret;
+ u32 oui_addr = 0, nic_addr = 0;
if (wl->mac80211_registered)
return 0;
+ ret = wl12xx_get_hw_info(wl);
+ if (ret < 0) {
+ wl1271_error("couldn't get hw info");
+ goto out;
+ }
+
ret = wl1271_fetch_nvs(wl);
if (ret == 0) {
/* NOTE: The wl->nvs->nvs element must be first, in
@@ -4843,20 +5092,25 @@ static int wl1271_register_hw(struct wl1271 *wl)
*/
u8 *nvs_ptr = (u8 *)wl->nvs;
- wl->mac_addr[0] = nvs_ptr[11];
- wl->mac_addr[1] = nvs_ptr[10];
- wl->mac_addr[2] = nvs_ptr[6];
- wl->mac_addr[3] = nvs_ptr[5];
- wl->mac_addr[4] = nvs_ptr[4];
- wl->mac_addr[5] = nvs_ptr[3];
+ oui_addr =
+ (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
+ nic_addr =
+ (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
}
- SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
+ /* if the MAC address is zeroed in the NVS derive from fuse */
+ if (oui_addr == 0 && nic_addr == 0) {
+ oui_addr = wl->fuse_oui_addr;
+ /* fuse has the BD_ADDR, the WLAN addresses are the next two */
+ nic_addr = wl->fuse_nic_addr + 1;
+ }
+
+ wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);
ret = ieee80211_register_hw(wl->hw);
if (ret < 0) {
wl1271_error("unable to register mac80211 hw: %d", ret);
- return ret;
+ goto out;
}
wl->mac80211_registered = true;
@@ -4867,13 +5121,14 @@ static int wl1271_register_hw(struct wl1271 *wl)
wl1271_notice("loaded");
- return 0;
+out:
+ return ret;
}
static void wl1271_unregister_hw(struct wl1271 *wl)
{
- if (wl->state == WL1271_STATE_PLT)
- __wl1271_plt_stop(wl);
+ if (wl->plt)
+ wl1271_plt_stop(wl);
unregister_netdevice_notifier(&wl1271_dev_notifier);
ieee80211_unregister_hw(wl->hw);
@@ -4892,7 +5147,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
};
/* The tx descriptor buffer and the TKIP space. */
- wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
+ wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP +
sizeof(struct wl1271_tx_hw_descr);
/* unit us */
@@ -4902,6 +5157,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
IEEE80211_HW_SUPPORTS_UAPSD |
IEEE80211_HW_HAS_RATE_CONTROL |
IEEE80211_HW_CONNECTION_MONITOR |
@@ -4909,7 +5165,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
IEEE80211_HW_SPECTRUM_MGMT |
IEEE80211_HW_AP_LINK_PS |
IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
+ IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
+ IEEE80211_HW_SCAN_WHILE_IDLE;
wl->hw->wiphy->cipher_suites = cipher_suites;
wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
@@ -4925,10 +5182,10 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
* should be the maximum length possible for a template, without
* the IEEE80211 header of the template
*/
- wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
+ wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
sizeof(struct ieee80211_header);
- wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
+ wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
sizeof(struct ieee80211_header);
wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
@@ -5022,7 +5279,6 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
wl->rx_counter = 0;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
wl->band = IEEE80211_BAND_2GHZ;
- wl->vif = NULL;
wl->flags = 0;
wl->sg_enabled = true;
wl->hw_pg_ver = -1;
@@ -5047,6 +5303,7 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
spin_lock_init(&wl->wl_lock);
wl->state = WL1271_STATE_OFF;
+ wl->fw_type = WL12XX_FW_TYPE_NONE;
mutex_init(&wl->mutex);
/* Apply default driver configuration. */
@@ -5114,6 +5371,7 @@ static int wl1271_free_hw(struct wl1271 *wl)
vfree(wl->fw);
wl->fw = NULL;
+ wl->fw_type = WL12XX_FW_TYPE_NONE;
kfree(wl->nvs);
wl->nvs = NULL;
@@ -5300,7 +5558,7 @@ module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
module_param_named(fwlog, fwlog_param, charp, 0);
-MODULE_PARM_DESC(keymap,
+MODULE_PARM_DESC(fwlog,
"FW logger options: continuous, ondemand, dbgpins or disable");
module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c
index a2bdacdd7e1..23d67501c50 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/ps.c
@@ -56,7 +56,7 @@ void wl1271_elp_work(struct work_struct *work)
if (wlvif->bss_type == BSS_TYPE_AP_BSS)
goto out;
- if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) &&
+ if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
goto out;
}
@@ -84,7 +84,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
if (wlvif->bss_type == BSS_TYPE_AP_BSS)
return;
- if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) &&
+ if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
return;
}
@@ -160,28 +160,39 @@ out:
}
int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- enum wl1271_cmd_ps_mode mode, u32 rates, bool send)
+ enum wl1271_cmd_ps_mode mode)
{
int ret;
+ u16 timeout = wl->conf.conn.dynamic_ps_timeout;
switch (mode) {
+ case STATION_AUTO_PS_MODE:
case STATION_POWER_SAVE_MODE:
- wl1271_debug(DEBUG_PSM, "entering psm");
+ wl1271_debug(DEBUG_PSM, "entering psm (mode=%d,timeout=%u)",
+ mode, timeout);
- ret = wl1271_acx_wake_up_conditions(wl, wlvif);
+ ret = wl1271_acx_wake_up_conditions(wl, wlvif,
+ wl->conf.conn.wake_up_event,
+ wl->conf.conn.listen_interval);
if (ret < 0) {
wl1271_error("couldn't set wake up conditions");
return ret;
}
- ret = wl1271_cmd_ps_mode(wl, wlvif, STATION_POWER_SAVE_MODE);
+ ret = wl1271_cmd_ps_mode(wl, wlvif, mode, timeout);
if (ret < 0)
return ret;
- set_bit(WLVIF_FLAG_PSM, &wlvif->flags);
+ set_bit(WLVIF_FLAG_IN_PS, &wlvif->flags);
+
+ /* enable beacon early termination. Not relevant for 5GHz */
+ if (wlvif->band == IEEE80211_BAND_2GHZ) {
+ ret = wl1271_acx_bet_enable(wl, wlvif, true);
+ if (ret < 0)
+ return ret;
+ }
break;
case STATION_ACTIVE_MODE:
- default:
wl1271_debug(DEBUG_PSM, "leaving psm");
/* disable beacon early termination */
@@ -191,12 +202,15 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
return ret;
}
- ret = wl1271_cmd_ps_mode(wl, wlvif, STATION_ACTIVE_MODE);
+ ret = wl1271_cmd_ps_mode(wl, wlvif, mode, 0);
if (ret < 0)
return ret;
- clear_bit(WLVIF_FLAG_PSM, &wlvif->flags);
+ clear_bit(WLVIF_FLAG_IN_PS, &wlvif->flags);
break;
+ default:
+ wl1271_warning("trying to set ps to unsupported mode %d", mode);
+ ret = -EINVAL;
}
return ret;
diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h
index a12052f0202..5f19d4fbbf2 100644
--- a/drivers/net/wireless/wl12xx/ps.h
+++ b/drivers/net/wireless/wl12xx/ps.h
@@ -28,7 +28,7 @@
#include "acx.h"
int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- enum wl1271_cmd_ps_mode mode, u32 rates, bool send);
+ enum wl1271_cmd_ps_mode mode);
void wl1271_ps_elp_sleep(struct wl1271 *wl);
int wl1271_ps_elp_wakeup(struct wl1271 *wl);
void wl1271_elp_work(struct work_struct *work);
diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h
index df34d5977b9..340db324bc2 100644
--- a/drivers/net/wireless/wl12xx/reg.h
+++ b/drivers/net/wireless/wl12xx/reg.h
@@ -525,4 +525,31 @@ b12-b0 - Supported Rate indicator bits as defined below.
*/
#define INTR_TRIG_TX_PROC1 BIT(18)
+#define WL127X_REG_FUSE_DATA_2_1 0x050a
+#define WL128X_REG_FUSE_DATA_2_1 0x2152
+#define PG_VER_MASK 0x3c
+#define PG_VER_OFFSET 2
+
+#define WL127X_PG_MAJOR_VER_MASK 0x3
+#define WL127X_PG_MAJOR_VER_OFFSET 0x0
+#define WL127X_PG_MINOR_VER_MASK 0xc
+#define WL127X_PG_MINOR_VER_OFFSET 0x2
+
+#define WL128X_PG_MAJOR_VER_MASK 0xc
+#define WL128X_PG_MAJOR_VER_OFFSET 0x2
+#define WL128X_PG_MINOR_VER_MASK 0x3
+#define WL128X_PG_MINOR_VER_OFFSET 0x0
+
+#define WL127X_PG_GET_MAJOR(pg_ver) ((pg_ver & WL127X_PG_MAJOR_VER_MASK) >> \
+ WL127X_PG_MAJOR_VER_OFFSET)
+#define WL127X_PG_GET_MINOR(pg_ver) ((pg_ver & WL127X_PG_MINOR_VER_MASK) >> \
+ WL127X_PG_MINOR_VER_OFFSET)
+#define WL128X_PG_GET_MAJOR(pg_ver) ((pg_ver & WL128X_PG_MAJOR_VER_MASK) >> \
+ WL128X_PG_MAJOR_VER_OFFSET)
+#define WL128X_PG_GET_MINOR(pg_ver) ((pg_ver & WL128X_PG_MINOR_VER_MASK) >> \
+ WL128X_PG_MINOR_VER_OFFSET)
+
+#define WL12XX_REG_FUSE_BD_ADDR_1 0x00310eb4
+#define WL12XX_REG_FUSE_BD_ADDR_2 0x00310eb8
+
#endif
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c
index 4fbd2a722ff..cfa6071704c 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/rx.c
@@ -113,7 +113,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
* In PLT mode we seem to get frames and mac80211 warns about them,
* workaround this by not retrieving them at all.
*/
- if (unlikely(wl->state == WL1271_STATE_PLT))
+ if (unlikely(wl->plt))
return -EINVAL;
/* the data read starts with the descriptor */
diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c
index e24111ececc..e43a6b2c1d9 100644
--- a/drivers/net/wireless/wl12xx/scan.c
+++ b/drivers/net/wireless/wl12xx/scan.c
@@ -38,7 +38,6 @@ void wl1271_scan_complete_work(struct work_struct *work)
struct ieee80211_vif *vif;
struct wl12xx_vif *wlvif;
int ret;
- bool is_sta, is_ibss;
dwork = container_of(work, struct delayed_work, work);
wl = container_of(dwork, struct wl1271, scan_complete_work);
@@ -70,15 +69,6 @@ void wl1271_scan_complete_work(struct work_struct *work)
wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq);
}
- /* return to ROC if needed */
- is_sta = (wlvif->bss_type == BSS_TYPE_STA_BSS);
- is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
- if (((is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) ||
- (is_ibss && !test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags))) &&
- !test_bit(wlvif->dev_role_id, wl->roc_map)) {
- /* restore remain on channel */
- wl12xx_start_dev(wl, wlvif);
- }
wl1271_ps_elp_sleep(wl);
if (wl->scan.failed) {
@@ -182,14 +172,23 @@ static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif,
goto out;
}
+ if (wl->conf.scan.split_scan_timeout)
+ scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN;
+
if (passive)
scan_options |= WL1271_SCAN_OPT_PASSIVE;
- if (WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID)) {
+ if (wlvif->bss_type == BSS_TYPE_AP_BSS ||
+ test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
+ cmd->params.role_id = wlvif->role_id;
+ else
+ cmd->params.role_id = wlvif->dev_role_id;
+
+ if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) {
ret = -EINVAL;
goto out;
}
- cmd->params.role_id = wlvif->role_id;
+
cmd->params.scan_options = cpu_to_le16(scan_options);
cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
@@ -202,7 +201,7 @@ static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif,
cmd->params.tx_rate = cpu_to_le32(basic_rate);
cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs;
- cmd->params.tid_trigger = 0;
+ cmd->params.tid_trigger = CONF_TX_AC_ANY_TID;
cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
if (band == IEEE80211_BAND_2GHZ)
@@ -217,16 +216,17 @@ static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif,
memcpy(cmd->addr, vif->addr, ETH_ALEN);
- ret = wl1271_cmd_build_probe_req(wl, wlvif, wl->scan.ssid,
- wl->scan.ssid_len, wl->scan.req->ie,
- wl->scan.req->ie_len, band);
+ ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+ cmd->params.role_id, band,
+ wl->scan.ssid, wl->scan.ssid_len,
+ wl->scan.req->ie,
+ wl->scan.req->ie_len);
if (ret < 0) {
wl1271_error("PROBE request template failed");
goto out;
}
- /* disable the timeout */
- trigger->timeout = 0;
+ trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout);
ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
sizeof(*trigger), 0);
if (ret < 0) {
@@ -658,11 +658,13 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
}
if (!force_passive && cfg->active[0]) {
- ret = wl1271_cmd_build_probe_req(wl, wlvif, req->ssids[0].ssid,
+ u8 band = IEEE80211_BAND_2GHZ;
+ ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+ wlvif->dev_role_id, band,
+ req->ssids[0].ssid,
req->ssids[0].ssid_len,
- ies->ie[IEEE80211_BAND_2GHZ],
- ies->len[IEEE80211_BAND_2GHZ],
- IEEE80211_BAND_2GHZ);
+ ies->ie[band],
+ ies->len[band]);
if (ret < 0) {
wl1271_error("2.4GHz PROBE request template failed");
goto out;
@@ -670,11 +672,13 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
}
if (!force_passive && cfg->active[1]) {
- ret = wl1271_cmd_build_probe_req(wl, wlvif, req->ssids[0].ssid,
+ u8 band = IEEE80211_BAND_5GHZ;
+ ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+ wlvif->dev_role_id, band,
+ req->ssids[0].ssid,
req->ssids[0].ssid_len,
- ies->ie[IEEE80211_BAND_5GHZ],
- ies->len[IEEE80211_BAND_5GHZ],
- IEEE80211_BAND_5GHZ);
+ ies->ie[band],
+ ies->len[band]);
if (ret < 0) {
wl1271_error("5GHz PROBE request template failed");
goto out;
diff --git a/drivers/net/wireless/wl12xx/scan.h b/drivers/net/wireless/wl12xx/scan.h
index a7ed43dc08c..96ff457a3a0 100644
--- a/drivers/net/wireless/wl12xx/scan.h
+++ b/drivers/net/wireless/wl12xx/scan.h
@@ -48,7 +48,7 @@ void wl1271_scan_sched_scan_results(struct wl1271 *wl);
#define WL1271_SCAN_CURRENT_TX_PWR 0
#define WL1271_SCAN_OPT_ACTIVE 0
#define WL1271_SCAN_OPT_PASSIVE 1
-#define WL1271_SCAN_OPT_TRIGGERED_SCAN 2
+#define WL1271_SCAN_OPT_SPLIT_SCAN 2
#define WL1271_SCAN_OPT_PRIORITY_HIGH 4
/* scan even if we fail to enter psm */
#define WL1271_SCAN_OPT_FORCE 8
diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
index 468a50553fa..4b3c32774ba 100644
--- a/drivers/net/wireless/wl12xx/sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -74,6 +74,8 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf,
struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
struct sdio_func *func = dev_to_sdio_func(glue->dev);
+ sdio_claim_host(func);
+
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n",
@@ -88,6 +90,8 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf,
addr, len);
}
+ sdio_release_host(func);
+
if (ret)
dev_err(child->parent, "sdio read failed (%d)\n", ret);
}
@@ -99,6 +103,8 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf,
struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
struct sdio_func *func = dev_to_sdio_func(glue->dev);
+ sdio_claim_host(func);
+
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n",
@@ -113,6 +119,8 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf,
ret = sdio_memcpy_toio(func, addr, buf, len);
}
+ sdio_release_host(func);
+
if (ret)
dev_err(child->parent, "sdio write failed (%d)\n", ret);
}
@@ -136,6 +144,7 @@ static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue)
sdio_claim_host(func);
sdio_enable_func(func);
+ sdio_release_host(func);
out:
return ret;
@@ -146,6 +155,7 @@ static int wl12xx_sdio_power_off(struct wl12xx_sdio_glue *glue)
int ret;
struct sdio_func *func = dev_to_sdio_func(glue->dev);
+ sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
@@ -314,9 +324,6 @@ static int wl1271_suspend(struct device *dev)
dev_err(dev, "error while trying to keep power\n");
goto out;
}
-
- /* release host */
- sdio_release_host(func);
}
out:
return ret;
@@ -324,15 +331,7 @@ out:
static int wl1271_resume(struct device *dev)
{
- struct sdio_func *func = dev_to_sdio_func(dev);
- struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func);
- struct wl1271 *wl = platform_get_drvdata(glue->core);
-
dev_dbg(dev, "wl1271 resume\n");
- if (wl->wow_enabled) {
- /* claim back host */
- sdio_claim_host(func);
- }
return 0;
}
@@ -371,5 +370,9 @@ module_exit(wl1271_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
-MODULE_FIRMWARE(WL127X_FW_NAME);
-MODULE_FIRMWARE(WL128X_FW_NAME);
+MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
+MODULE_FIRMWARE(WL127X_FW_NAME_MULTI);
+MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
+MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE);
+MODULE_FIRMWARE(WL128X_FW_NAME_MULTI);
+MODULE_FIRMWARE(WL128X_PLT_FW_NAME);
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c
index 92caa7ce605..2fc18a8dcce 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/spi.c
@@ -433,6 +433,10 @@ module_exit(wl1271_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
-MODULE_FIRMWARE(WL127X_FW_NAME);
-MODULE_FIRMWARE(WL128X_FW_NAME);
+MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
+MODULE_FIRMWARE(WL127X_FW_NAME_MULTI);
+MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
+MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE);
+MODULE_FIRMWARE(WL128X_FW_NAME_MULTI);
+MODULE_FIRMWARE(WL128X_PLT_FW_NAME);
MODULE_ALIAS("spi:wl1271");
diff --git a/drivers/net/wireless/wl12xx/testmode.c b/drivers/net/wireless/wl12xx/testmode.c
index 25093c0cb0e..1e93bb9c024 100644
--- a/drivers/net/wireless/wl12xx/testmode.c
+++ b/drivers/net/wireless/wl12xx/testmode.c
@@ -30,6 +30,7 @@
#include "acx.h"
#include "reg.h"
#include "ps.h"
+#include "io.h"
#define WL1271_TM_MAX_DATA_LENGTH 1024
@@ -41,6 +42,7 @@ enum wl1271_tm_commands {
WL1271_TM_CMD_NVS_PUSH, /* Not in use. Keep to not break ABI */
WL1271_TM_CMD_SET_PLT_MODE,
WL1271_TM_CMD_RECOVER,
+ WL1271_TM_CMD_GET_MAC,
__WL1271_TM_CMD_AFTER_LAST
};
@@ -264,6 +266,52 @@ static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[])
return 0;
}
+static int wl12xx_tm_cmd_get_mac(struct wl1271 *wl, struct nlattr *tb[])
+{
+ struct sk_buff *skb;
+ u8 mac_addr[ETH_ALEN];
+ int ret = 0;
+
+ mutex_lock(&wl->mutex);
+
+ if (!wl->plt) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (wl->fuse_oui_addr == 0 && wl->fuse_nic_addr == 0) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ mac_addr[0] = (u8)(wl->fuse_oui_addr >> 16);
+ mac_addr[1] = (u8)(wl->fuse_oui_addr >> 8);
+ mac_addr[2] = (u8) wl->fuse_oui_addr;
+ mac_addr[3] = (u8)(wl->fuse_nic_addr >> 16);
+ mac_addr[4] = (u8)(wl->fuse_nic_addr >> 8);
+ mac_addr[5] = (u8) wl->fuse_nic_addr;
+
+ skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, ETH_ALEN);
+ if (!skb) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ NLA_PUT(skb, WL1271_TM_ATTR_DATA, ETH_ALEN, mac_addr);
+ ret = cfg80211_testmode_reply(skb);
+ if (ret < 0)
+ goto out;
+
+out:
+ mutex_unlock(&wl->mutex);
+ return ret;
+
+nla_put_failure:
+ kfree_skb(skb);
+ ret = -EMSGSIZE;
+ goto out;
+}
+
int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
{
struct wl1271 *wl = hw->priv;
@@ -288,6 +336,8 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
return wl1271_tm_cmd_set_plt_mode(wl, tb);
case WL1271_TM_CMD_RECOVER:
return wl1271_tm_cmd_recover(wl, tb);
+ case WL1271_TM_CMD_GET_MAC:
+ return wl12xx_tm_cmd_get_mac(wl, tb);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 4508ccd7832..6446e4d3e8f 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -77,35 +77,6 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id)
}
}
-static int wl1271_tx_update_filters(struct wl1271 *wl,
- struct wl12xx_vif *wlvif,
- struct sk_buff *skb)
-{
- struct ieee80211_hdr *hdr;
- int ret;
-
- hdr = (struct ieee80211_hdr *)skb->data;
-
- /*
- * stop bssid-based filtering before transmitting authentication
- * requests. this way the hw will never drop authentication
- * responses coming from BSSIDs it isn't familiar with (e.g. on
- * roaming)
- */
- if (!ieee80211_is_auth(hdr->frame_control))
- return 0;
-
- if (wlvif->dev_hlid != WL12XX_INVALID_LINK_ID)
- goto out;
-
- wl1271_debug(DEBUG_CMD, "starting device role for roaming");
- ret = wl12xx_start_dev(wl, wlvif);
- if (ret < 0)
- goto out;
-out:
- return 0;
-}
-
static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
struct sk_buff *skb)
{
@@ -187,8 +158,6 @@ u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (wlvif->bss_type == BSS_TYPE_AP_BSS)
return wl12xx_tx_get_hlid_ap(wl, wlvif, skb);
- wl1271_tx_update_filters(wl, wlvif, skb);
-
if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) &&
!ieee80211_is_auth(hdr->frame_control) &&
@@ -286,16 +255,20 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
int aligned_len, ac, rate_idx;
s64 hosttime;
u16 tx_attr = 0;
+ __le16 frame_control;
+ struct ieee80211_hdr *hdr;
+ u8 *frame_start;
bool is_dummy;
desc = (struct wl1271_tx_hw_descr *) skb->data;
+ frame_start = (u8 *)(desc + 1);
+ hdr = (struct ieee80211_hdr *)(frame_start + extra);
+ frame_control = hdr->frame_control;
/* relocate space for security header */
if (extra) {
- void *framestart = skb->data + sizeof(*desc);
- u16 fc = *(u16 *)(framestart + extra);
- int hdrlen = ieee80211_hdrlen(cpu_to_le16(fc));
- memmove(framestart, framestart + extra, hdrlen);
+ int hdrlen = ieee80211_hdrlen(frame_control);
+ memmove(frame_start, hdr, hdrlen);
}
/* configure packet life time */
@@ -384,6 +357,11 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
desc->wl127x_mem.total_mem_blocks);
}
+ /* for WEP shared auth - no fw encryption is needed */
+ if (ieee80211_is_auth(frame_control) &&
+ ieee80211_has_protected(frame_control))
+ tx_attr |= TX_HW_ATTR_HOST_ENCRYPT;
+
desc->tx_attr = cpu_to_le16(tx_attr);
}
@@ -408,7 +386,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (info->control.hw_key &&
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP)
- extra = WL1271_TKIP_IV_SPACE;
+ extra = WL1271_EXTRA_SPACE_TKIP;
if (info->control.hw_key) {
bool is_wep;
@@ -795,6 +773,18 @@ out:
mutex_unlock(&wl->mutex);
}
+static u8 wl1271_tx_get_rate_flags(u8 rate_class_index)
+{
+ u8 flags = 0;
+
+ if (rate_class_index >= CONF_HW_RXTX_RATE_MCS_MIN &&
+ rate_class_index <= CONF_HW_RXTX_RATE_MCS_MAX)
+ flags |= IEEE80211_TX_RC_MCS;
+ if (rate_class_index == CONF_HW_RXTX_RATE_MCS7_SGI)
+ flags |= IEEE80211_TX_RC_SHORT_GI;
+ return flags;
+}
+
static void wl1271_tx_complete_packet(struct wl1271 *wl,
struct wl1271_tx_hw_res_descr *result)
{
@@ -804,6 +794,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
struct sk_buff *skb;
int id = result->id;
int rate = -1;
+ u8 rate_flags = 0;
u8 retries = 0;
/* check for id legality */
@@ -830,6 +821,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
info->flags |= IEEE80211_TX_STAT_ACK;
rate = wl1271_rate_to_idx(result->rate_class_index,
wlvif->band);
+ rate_flags = wl1271_tx_get_rate_flags(result->rate_class_index);
retries = result->ack_failures;
} else if (result->status == TX_RETRY_EXCEEDED) {
wl->stats.excessive_retries++;
@@ -838,7 +830,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
info->status.rates[0].idx = rate;
info->status.rates[0].count = retries;
- info->status.rates[0].flags = 0;
+ info->status.rates[0].flags = rate_flags;
info->status.ack_signal = -1;
wl->stats.retry_count += result->ack_failures;
@@ -869,8 +861,9 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
if (info->control.hw_key &&
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, hdrlen);
- skb_pull(skb, WL1271_TKIP_IV_SPACE);
+ memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data,
+ hdrlen);
+ skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
}
wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
@@ -1012,9 +1005,9 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
info->control.hw_key->cipher ==
WLAN_CIPHER_SUITE_TKIP) {
int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- memmove(skb->data + WL1271_TKIP_IV_SPACE,
+ memmove(skb->data + WL1271_EXTRA_SPACE_TKIP,
skb->data, hdrlen);
- skb_pull(skb, WL1271_TKIP_IV_SPACE);
+ skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
}
info->status.rates[0].idx = -1;
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index 2dbb24e6d54..e3977b55a71 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -39,6 +39,7 @@
#define TX_HW_ATTR_LAST_WORD_PAD (BIT(10) | BIT(11))
#define TX_HW_ATTR_TX_CMPLT_REQ BIT(12)
#define TX_HW_ATTR_TX_DUMMY_REQ BIT(13)
+#define TX_HW_ATTR_HOST_ENCRYPT BIT(14)
#define TX_HW_ATTR_OFST_SAVE_RETRIES 0
#define TX_HW_ATTR_OFST_HEADER_PAD 1
@@ -51,7 +52,9 @@
#define TX_HW_RESULT_QUEUE_LEN_MASK 0xf
#define WL1271_TX_ALIGN_TO 4
-#define WL1271_TKIP_IV_SPACE 4
+#define WL1271_EXTRA_SPACE_TKIP 4
+#define WL1271_EXTRA_SPACE_AES 8
+#define WL1271_EXTRA_SPACE_MAX 8
/* Used for management frames and dummy packets */
#define WL1271_TID_MGMT 7
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index b2b09cd0202..90352415e2a 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -35,8 +35,14 @@
#include "conf.h"
#include "ini.h"
-#define WL127X_FW_NAME "ti-connectivity/wl127x-fw-3.bin"
-#define WL128X_FW_NAME "ti-connectivity/wl128x-fw-3.bin"
+#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin"
+#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin"
+
+#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin"
+#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin"
+
+#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin"
+#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin"
/*
* wl127x and wl128x are using the same NVS file name. However, the
@@ -90,7 +96,13 @@
enum wl1271_state {
WL1271_STATE_OFF,
WL1271_STATE_ON,
- WL1271_STATE_PLT,
+};
+
+enum wl12xx_fw_type {
+ WL12XX_FW_TYPE_NONE,
+ WL12XX_FW_TYPE_NORMAL,
+ WL12XX_FW_TYPE_MULTI,
+ WL12XX_FW_TYPE_PLT,
};
enum wl1271_partition_type {
@@ -247,6 +259,7 @@ enum wl12xx_flags {
WL1271_FLAG_PENDING_WORK,
WL1271_FLAG_SOFT_GEMINI,
WL1271_FLAG_RECOVERY_IN_PROGRESS,
+ WL1271_FLAG_VIF_CHANGE_IN_PROGRESS,
};
enum wl12xx_vif_flags {
@@ -254,8 +267,7 @@ enum wl12xx_vif_flags {
WLVIF_FLAG_STA_ASSOCIATED,
WLVIF_FLAG_IBSS_JOINED,
WLVIF_FLAG_AP_STARTED,
- WLVIF_FLAG_PSM,
- WLVIF_FLAG_PSM_REQUESTED,
+ WLVIF_FLAG_IN_PS,
WLVIF_FLAG_STA_STATE_SENT,
WLVIF_FLAG_RX_STREAMING_STARTED,
WLVIF_FLAG_PSPOLL_FAILURE,
@@ -295,6 +307,9 @@ struct wl1271 {
spinlock_t wl_lock;
enum wl1271_state state;
+ enum wl12xx_fw_type fw_type;
+ bool plt;
+ u8 last_vif_count;
struct mutex mutex;
unsigned long flags;
@@ -313,7 +328,12 @@ struct wl1271 {
s8 hw_pg_ver;
- u8 mac_addr[ETH_ALEN];
+ /* address read from the fuse ROM */
+ u32 fuse_oui_addr;
+ u32 fuse_nic_addr;
+
+ /* we have up to 2 MAC addresses */
+ struct mac_address addresses[2];
int channel;
u8 system_hlid;
@@ -425,8 +445,6 @@ struct wl1271 {
struct wl12xx_fw_status *fw_status;
struct wl1271_tx_hw_res_if *tx_res_if;
- struct ieee80211_vif *vif;
-
/* Current chipset configuration */
struct conf_drv_settings conf;
@@ -503,6 +521,8 @@ struct wl12xx_vif {
u8 basic_rate_idx;
u8 ap_rate_idx;
u8 p2p_rate_idx;
+
+ bool qos;
} sta;
struct {
u8 global_hlid;
@@ -560,12 +580,6 @@ struct wl12xx_vif {
/* Session counter for the chipset */
int session_counter;
- struct completion *ps_compl;
- struct delayed_work pspoll_work;
-
- /* counter for ps-poll delivery failures */
- int ps_poll_failures;
-
/* retry counter for PSM entries */
u8 psm_entry_retry;
@@ -575,6 +589,10 @@ struct wl12xx_vif {
int rssi_thold;
int last_rssi_event;
+ /* save the current encryption type for auto-arp config */
+ u8 encryption_type;
+ __be32 ip_addr;
+
/* RX BA constraint value */
bool ba_support;
bool ba_allowed;
diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h
index 8f0ffaf6230..22b0bc98d7b 100644
--- a/drivers/net/wireless/wl12xx/wl12xx_80211.h
+++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h
@@ -117,7 +117,7 @@ struct wl12xx_ps_poll_template {
} __packed;
struct wl12xx_arp_rsp_template {
- struct ieee80211_hdr_3addr hdr;
+ /* not including ieee80211 header */
u8 llc_hdr[sizeof(rfc1042_header)];
__be16 llc_type;
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index ad56e21a9f1..be35a68746a 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -156,21 +156,23 @@
* @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
* or %NL80211_ATTR_MAC.
*
- * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
- * %NL80222_CMD_NEW_BEACON message)
- * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
- * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
- * %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes.
- * Following attributes are provided for drivers that generate full Beacon
- * and Probe Response frames internally: %NL80211_ATTR_SSID,
+ * @NL80211_CMD_GET_BEACON: (not used)
+ * @NL80211_CMD_SET_BEACON: change the beacon on an access point interface
+ * using the %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL
+ * attributes. For drivers that generate the beacon and probe responses
+ * internally, the following attributes must be provided: %NL80211_ATTR_IE,
+ * %NL80211_ATTR_IE_PROBE_RESP and %NL80211_ATTR_IE_ASSOC_RESP.
+ * @NL80211_CMD_START_AP: Start AP operation on an AP interface, parameters
+ * are like for %NL80211_CMD_SET_BEACON, and additionally parameters that
+ * do not change are used, these include %NL80211_ATTR_BEACON_INTERVAL,
+ * %NL80211_ATTR_DTIM_PERIOD, %NL80211_ATTR_SSID,
* %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE,
* %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
- * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
- * %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_IE, %NL80211_ATTR_IE_PROBE_RESP,
- * %NL80211_ATTR_IE_ASSOC_RESP.
- * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
- * parameters are like for %NL80211_CMD_SET_BEACON.
- * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
+ * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY and
+ * %NL80211_ATTR_AUTH_TYPE.
+ * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
+ * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
+ * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
*
* @NL80211_CMD_GET_STATION: Get station attributes for station identified by
* %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
@@ -565,8 +567,10 @@ enum nl80211_commands {
NL80211_CMD_GET_BEACON,
NL80211_CMD_SET_BEACON,
- NL80211_CMD_NEW_BEACON,
- NL80211_CMD_DEL_BEACON,
+ NL80211_CMD_START_AP,
+ NL80211_CMD_NEW_BEACON = NL80211_CMD_START_AP,
+ NL80211_CMD_STOP_AP,
+ NL80211_CMD_DEL_BEACON = NL80211_CMD_STOP_AP,
NL80211_CMD_GET_STATION,
NL80211_CMD_SET_STATION,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index e0c9ff3a197..755a7707a7c 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -366,25 +366,13 @@ struct cfg80211_crypto_settings {
};
/**
- * struct beacon_parameters - beacon parameters
- *
- * Used to configure the beacon for an interface.
- *
+ * struct cfg80211_beacon_data - beacon data
* @head: head portion of beacon (before TIM IE)
* or %NULL if not changed
* @tail: tail portion of beacon (after TIM IE)
* or %NULL if not changed
- * @interval: beacon interval or zero if not changed
- * @dtim_period: DTIM period or zero if not changed
* @head_len: length of @head
* @tail_len: length of @tail
- * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided from
- * user space)
- * @ssid_len: length of @ssid
- * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response frames
- * @crypto: crypto settings
- * @privacy: the BSS uses privacy
- * @auth_type: Authentication type (algorithm)
* @beacon_ies: extra information element(s) to add into Beacon frames or %NULL
* @beacon_ies_len: length of beacon_ies in octets
* @proberesp_ies: extra information element(s) to add into Probe Response
@@ -396,24 +384,46 @@ struct cfg80211_crypto_settings {
* @probe_resp_len: length of probe response template (@probe_resp)
* @probe_resp: probe response template (AP mode only)
*/
-struct beacon_parameters {
- u8 *head, *tail;
- int interval, dtim_period;
- int head_len, tail_len;
+struct cfg80211_beacon_data {
+ const u8 *head, *tail;
+ const u8 *beacon_ies;
+ const u8 *proberesp_ies;
+ const u8 *assocresp_ies;
+ const u8 *probe_resp;
+
+ size_t head_len, tail_len;
+ size_t beacon_ies_len;
+ size_t proberesp_ies_len;
+ size_t assocresp_ies_len;
+ size_t probe_resp_len;
+};
+
+/**
+ * struct cfg80211_ap_settings - AP configuration
+ *
+ * Used to configure an AP interface.
+ *
+ * @beacon: beacon data
+ * @beacon_interval: beacon interval
+ * @dtim_period: DTIM period
+ * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided from
+ * user space)
+ * @ssid_len: length of @ssid
+ * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response frames
+ * @crypto: crypto settings
+ * @privacy: the BSS uses privacy
+ * @auth_type: Authentication type (algorithm)
+ */
+struct cfg80211_ap_settings {
+ struct cfg80211_beacon_data beacon;
+
+ int beacon_interval, dtim_period;
const u8 *ssid;
size_t ssid_len;
enum nl80211_hidden_ssid hidden_ssid;
struct cfg80211_crypto_settings crypto;
bool privacy;
enum nl80211_auth_type auth_type;
- const u8 *beacon_ies;
- size_t beacon_ies_len;
- const u8 *proberesp_ies;
- size_t proberesp_ies_len;
- const u8 *assocresp_ies;
- size_t assocresp_ies_len;
- int probe_resp_len;
- u8 *probe_resp;
};
/**
@@ -1518,11 +1528,11 @@ struct cfg80211_ops {
struct net_device *netdev,
u8 key_index);
- int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev,
- struct beacon_parameters *info);
- int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev,
- struct beacon_parameters *info);
- int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev);
+ int (*start_ap)(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ap_settings *settings);
+ int (*change_beacon)(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_beacon_data *info);
+ int (*stop_ap)(struct wiphy *wiphy, struct net_device *dev);
int (*add_station)(struct wiphy *wiphy, struct net_device *dev,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index c3de921c8cf..f7eb25aabf8 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -489,27 +489,13 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
return ret;
}
-static void ieee80211_config_ap_ssid(struct ieee80211_sub_if_data *sdata,
- struct beacon_parameters *params)
-{
- struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
-
- bss_conf->ssid_len = params->ssid_len;
-
- if (params->ssid_len)
- memcpy(bss_conf->ssid, params->ssid, params->ssid_len);
-
- bss_conf->hidden_ssid =
- (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE);
-}
-
static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
- u8 *resp, size_t resp_len)
+ const u8 *resp, size_t resp_len)
{
struct sk_buff *new, *old;
if (!resp || !resp_len)
- return -EINVAL;
+ return 1;
old = rtnl_dereference(sdata->u.ap.probe_resp);
@@ -520,50 +506,28 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
memcpy(skb_put(new, resp_len), resp, resp_len);
rcu_assign_pointer(sdata->u.ap.probe_resp, new);
- synchronize_rcu();
-
- if (old)
+ if (old) {
+ /* TODO: use call_rcu() */
+ synchronize_rcu();
dev_kfree_skb(old);
+ }
return 0;
}
-/*
- * This handles both adding a beacon and setting new beacon info
- */
-static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
- struct beacon_parameters *params)
+static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_beacon_data *params)
{
struct beacon_data *new, *old;
int new_head_len, new_tail_len;
- int size;
- int err = -EINVAL;
- u32 changed = 0;
+ int size, err;
+ u32 changed = BSS_CHANGED_BEACON;
old = rtnl_dereference(sdata->u.ap.beacon);
- /* head must not be zero-length */
- if (params->head && !params->head_len)
- return -EINVAL;
-
- /*
- * This is a kludge. beacon interval should really be part
- * of the beacon information.
- */
- if (params->interval &&
- (sdata->vif.bss_conf.beacon_int != params->interval)) {
- sdata->vif.bss_conf.beacon_int = params->interval;
- ieee80211_bss_info_change_notify(sdata,
- BSS_CHANGED_BEACON_INT);
- }
-
/* Need to have a beacon head if we don't have one yet */
if (!params->head && !old)
- return err;
-
- /* sorry, no way to start beaconing without dtim period */
- if (!params->dtim_period && !old)
- return err;
+ return -EINVAL;
/* new or old head? */
if (params->head)
@@ -586,12 +550,6 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
/* start filling the new info now */
- /* new or old dtim period? */
- if (params->dtim_period)
- new->dtim_period = params->dtim_period;
- else
- new->dtim_period = old->dtim_period;
-
/*
* pointers go into the block we allocated,
* memory is | beacon_data | head | tail |
@@ -614,46 +572,37 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
if (old)
memcpy(new->tail, old->tail, new_tail_len);
- sdata->vif.bss_conf.dtim_period = new->dtim_period;
-
- rcu_assign_pointer(sdata->u.ap.beacon, new);
-
- synchronize_rcu();
-
- kfree(old);
-
err = ieee80211_set_probe_resp(sdata, params->probe_resp,
params->probe_resp_len);
- if (!err)
+ if (err < 0)
+ return err;
+ if (err == 0)
changed |= BSS_CHANGED_AP_PROBE_RESP;
- ieee80211_config_ap_ssid(sdata, params);
- changed |= BSS_CHANGED_BEACON_ENABLED |
- BSS_CHANGED_BEACON |
- BSS_CHANGED_SSID;
+ rcu_assign_pointer(sdata->u.ap.beacon, new);
+
+ if (old)
+ kfree_rcu(old, rcu_head);
- ieee80211_bss_info_change_notify(sdata, changed);
- return 0;
+ return changed;
}
-static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
- struct beacon_parameters *params)
+static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ap_settings *params)
{
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct beacon_data *old;
struct ieee80211_sub_if_data *vlan;
- int ret;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ u32 changed = BSS_CHANGED_BEACON_INT |
+ BSS_CHANGED_BEACON_ENABLED |
+ BSS_CHANGED_BEACON |
+ BSS_CHANGED_SSID;
+ int err;
old = rtnl_dereference(sdata->u.ap.beacon);
if (old)
return -EALREADY;
- ret = ieee80211_config_beacon(sdata, params);
- if (ret)
- return ret;
-
/*
* Apply control port protocol, this allows us to
* not encrypt dynamic WEP control frames.
@@ -667,14 +616,32 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
params->crypto.control_port_no_encrypt;
}
+ sdata->vif.bss_conf.beacon_int = params->beacon_interval;
+ sdata->vif.bss_conf.dtim_period = params->dtim_period;
+
+ sdata->vif.bss_conf.ssid_len = params->ssid_len;
+ if (params->ssid_len)
+ memcpy(sdata->vif.bss_conf.ssid, params->ssid,
+ params->ssid_len);
+ sdata->vif.bss_conf.hidden_ssid =
+ (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE);
+
+ err = ieee80211_assign_beacon(sdata, &params->beacon);
+ if (err < 0)
+ return err;
+ changed |= err;
+
+ ieee80211_bss_info_change_notify(sdata, changed);
+
return 0;
}
-static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
- struct beacon_parameters *params)
+static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_beacon_data *params)
{
struct ieee80211_sub_if_data *sdata;
struct beacon_data *old;
+ int err;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -682,10 +649,14 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
if (!old)
return -ENOENT;
- return ieee80211_config_beacon(sdata, params);
+ err = ieee80211_assign_beacon(sdata, params);
+ if (err < 0)
+ return err;
+ ieee80211_bss_info_change_notify(sdata, err);
+ return 0;
}
-static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
+static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata;
struct beacon_data *old;
@@ -697,10 +668,11 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
return -ENOENT;
RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
- synchronize_rcu();
- kfree(old);
+
+ kfree_rcu(old, rcu_head);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
+
return 0;
}
@@ -2699,9 +2671,9 @@ struct cfg80211_ops mac80211_config_ops = {
.get_key = ieee80211_get_key,
.set_default_key = ieee80211_config_default_key,
.set_default_mgmt_key = ieee80211_config_default_mgmt_key,
- .add_beacon = ieee80211_add_beacon,
- .set_beacon = ieee80211_set_beacon,
- .del_beacon = ieee80211_del_beacon,
+ .start_ap = ieee80211_start_ap,
+ .change_beacon = ieee80211_change_beacon,
+ .stop_ap = ieee80211_stop_ap,
.add_station = ieee80211_add_station,
.del_station = ieee80211_del_station,
.change_station = ieee80211_change_station,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 74594f012cd..67aed1eff13 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -228,7 +228,7 @@ struct ieee80211_rx_data {
struct beacon_data {
u8 *head, *tail;
int head_len, tail_len;
- int dtim_period;
+ struct rcu_head rcu_head;
};
struct ieee80211_if_ap {
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 1be0ca2b593..c6eadac9ca4 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2206,7 +2206,8 @@ void ieee80211_tx_pending(unsigned long data)
/* functions for drivers to get certain frames */
-static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss,
+static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_if_ap *bss,
struct sk_buff *skb,
struct beacon_data *beacon)
{
@@ -2223,7 +2224,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss,
IEEE80211_MAX_AID+1);
if (bss->dtim_count == 0)
- bss->dtim_count = beacon->dtim_period - 1;
+ bss->dtim_count = sdata->vif.bss_conf.dtim_period - 1;
else
bss->dtim_count--;
@@ -2231,7 +2232,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss,
*pos++ = WLAN_EID_TIM;
*pos++ = 4;
*pos++ = bss->dtim_count;
- *pos++ = beacon->dtim_period;
+ *pos++ = sdata->vif.bss_conf.dtim_period;
if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
aid0 = 1;
@@ -2324,12 +2325,14 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
* of the tim bitmap in mac80211 and the driver.
*/
if (local->tim_in_locked_section) {
- ieee80211_beacon_add_tim(ap, skb, beacon);
+ ieee80211_beacon_add_tim(sdata, ap, skb,
+ beacon);
} else {
unsigned long flags;
spin_lock_irqsave(&local->tim_lock, flags);
- ieee80211_beacon_add_tim(ap, skb, beacon);
+ ieee80211_beacon_add_tim(sdata, ap, skb,
+ beacon);
spin_unlock_irqrestore(&local->tim_lock, flags);
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index fe274765356..1998c368277 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -871,7 +871,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
CMD(add_virtual_intf, NEW_INTERFACE);
CMD(change_virtual_intf, SET_INTERFACE);
CMD(add_key, NEW_KEY);
- CMD(add_beacon, NEW_BEACON);
+ CMD(start_ap, START_AP);
CMD(add_station, NEW_STATION);
CMD(add_mpath, NEW_MPATH);
CMD(update_mesh_config, SET_MESH_CONFIG);
@@ -2075,15 +2075,10 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
return err;
}
-static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_parse_beacon(struct genl_info *info,
+ struct cfg80211_beacon_data *bcn)
{
- int (*call)(struct wiphy *wiphy, struct net_device *dev,
- struct beacon_parameters *info);
- struct cfg80211_registered_device *rdev = info->user_ptr[0];
- struct net_device *dev = info->user_ptr[1];
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct beacon_parameters params;
- int haveinfo = 0, err;
+ bool haveinfo = false;
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) ||
!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) ||
@@ -2091,149 +2086,183 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]))
return -EINVAL;
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
- dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
- return -EOPNOTSUPP;
-
- memset(&params, 0, sizeof(params));
-
- switch (info->genlhdr->cmd) {
- case NL80211_CMD_NEW_BEACON:
- /* these are required for NEW_BEACON */
- if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
- !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
- !info->attrs[NL80211_ATTR_BEACON_HEAD])
- return -EINVAL;
-
- params.interval =
- nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
- params.dtim_period =
- nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
-
- err = cfg80211_validate_beacon_int(rdev, params.interval);
- if (err)
- return err;
-
- /*
- * In theory, some of these attributes could be required for
- * NEW_BEACON, but since they were not used when the command was
- * originally added, keep them optional for old user space
- * programs to work with drivers that do not need the additional
- * information.
- */
- if (info->attrs[NL80211_ATTR_SSID]) {
- params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
- params.ssid_len =
- nla_len(info->attrs[NL80211_ATTR_SSID]);
- if (params.ssid_len == 0 ||
- params.ssid_len > IEEE80211_MAX_SSID_LEN)
- return -EINVAL;
- }
-
- if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
- params.hidden_ssid = nla_get_u32(
- info->attrs[NL80211_ATTR_HIDDEN_SSID]);
- if (params.hidden_ssid !=
- NL80211_HIDDEN_SSID_NOT_IN_USE &&
- params.hidden_ssid !=
- NL80211_HIDDEN_SSID_ZERO_LEN &&
- params.hidden_ssid !=
- NL80211_HIDDEN_SSID_ZERO_CONTENTS)
- return -EINVAL;
- }
-
- params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
-
- if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
- params.auth_type = nla_get_u32(
- info->attrs[NL80211_ATTR_AUTH_TYPE]);
- if (!nl80211_valid_auth_type(params.auth_type))
- return -EINVAL;
- } else
- params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
-
- err = nl80211_crypto_settings(rdev, info, &params.crypto,
- NL80211_MAX_NR_CIPHER_SUITES);
- if (err)
- return err;
-
- call = rdev->ops->add_beacon;
- break;
- case NL80211_CMD_SET_BEACON:
- call = rdev->ops->set_beacon;
- break;
- default:
- WARN_ON(1);
- return -EOPNOTSUPP;
- }
-
- if (!call)
- return -EOPNOTSUPP;
+ memset(bcn, 0, sizeof(*bcn));
if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
- params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
- params.head_len =
- nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
- haveinfo = 1;
+ bcn->head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+ bcn->head_len = nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+ if (!bcn->head_len)
+ return -EINVAL;
+ haveinfo = true;
}
if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
- params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
- params.tail_len =
+ bcn->tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
+ bcn->tail_len =
nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
- haveinfo = 1;
+ haveinfo = true;
}
if (!haveinfo)
return -EINVAL;
if (info->attrs[NL80211_ATTR_IE]) {
- params.beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]);
- params.beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ bcn->beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]);
+ bcn->beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
}
if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) {
- params.proberesp_ies =
+ bcn->proberesp_ies =
nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
- params.proberesp_ies_len =
+ bcn->proberesp_ies_len =
nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
}
if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
- params.assocresp_ies =
+ bcn->assocresp_ies =
nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
- params.assocresp_ies_len =
+ bcn->assocresp_ies_len =
nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
}
if (info->attrs[NL80211_ATTR_PROBE_RESP]) {
- params.probe_resp =
+ bcn->probe_resp =
nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]);
- params.probe_resp_len =
+ bcn->probe_resp_len =
nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]);
}
- err = call(&rdev->wiphy, dev, &params);
- if (!err && params.interval)
- wdev->beacon_interval = params.interval;
+ return 0;
+}
+
+static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_ap_settings params;
+ int err;
+
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EOPNOTSUPP;
+
+ if (!rdev->ops->start_ap)
+ return -EOPNOTSUPP;
+
+ if (wdev->beacon_interval)
+ return -EALREADY;
+
+ memset(&params, 0, sizeof(params));
+
+ /* these are required for START_AP */
+ if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
+ !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
+ !info->attrs[NL80211_ATTR_BEACON_HEAD])
+ return -EINVAL;
+
+ err = nl80211_parse_beacon(info, &params.beacon);
+ if (err)
+ return err;
+
+ params.beacon_interval =
+ nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
+ params.dtim_period =
+ nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
+
+ err = cfg80211_validate_beacon_int(rdev, params.beacon_interval);
+ if (err)
+ return err;
+
+ /*
+ * In theory, some of these attributes should be required here
+ * but since they were not used when the command was originally
+ * added, keep them optional for old user space programs to let
+ * them continue to work with drivers that do not need the
+ * additional information -- drivers must check!
+ */
+ if (info->attrs[NL80211_ATTR_SSID]) {
+ params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+ params.ssid_len =
+ nla_len(info->attrs[NL80211_ATTR_SSID]);
+ if (params.ssid_len == 0 ||
+ params.ssid_len > IEEE80211_MAX_SSID_LEN)
+ return -EINVAL;
+ }
+
+ if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
+ params.hidden_ssid = nla_get_u32(
+ info->attrs[NL80211_ATTR_HIDDEN_SSID]);
+ if (params.hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE &&
+ params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_LEN &&
+ params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_CONTENTS)
+ return -EINVAL;
+ }
+
+ params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
+
+ if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
+ params.auth_type = nla_get_u32(
+ info->attrs[NL80211_ATTR_AUTH_TYPE]);
+ if (!nl80211_valid_auth_type(params.auth_type))
+ return -EINVAL;
+ } else
+ params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
+
+ err = nl80211_crypto_settings(rdev, info, &params.crypto,
+ NL80211_MAX_NR_CIPHER_SUITES);
+ if (err)
+ return err;
+
+ err = rdev->ops->start_ap(&rdev->wiphy, dev, &params);
+ if (!err)
+ wdev->beacon_interval = params.beacon_interval;
return err;
}
-static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_beacon_data params;
+ int err;
+
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EOPNOTSUPP;
+
+ if (!rdev->ops->change_beacon)
+ return -EOPNOTSUPP;
+
+ if (!wdev->beacon_interval)
+ return -EINVAL;
+
+ err = nl80211_parse_beacon(info, &params);
+ if (err)
+ return err;
+
+ return rdev->ops->change_beacon(&rdev->wiphy, dev, &params);
+}
+
+static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = dev->ieee80211_ptr;
int err;
- if (!rdev->ops->del_beacon)
+ if (!rdev->ops->stop_ap)
return -EOPNOTSUPP;
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
return -EOPNOTSUPP;
- err = rdev->ops->del_beacon(&rdev->wiphy, dev);
+ if (!wdev->beacon_interval)
+ return -ENOENT;
+
+ err = rdev->ops->stop_ap(&rdev->wiphy, dev);
if (!err)
wdev->beacon_interval = 0;
return err;
@@ -6357,23 +6386,23 @@ static struct genl_ops nl80211_ops[] = {
.cmd = NL80211_CMD_SET_BEACON,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
- .doit = nl80211_addset_beacon,
+ .doit = nl80211_set_beacon,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
{
- .cmd = NL80211_CMD_NEW_BEACON,
+ .cmd = NL80211_CMD_START_AP,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
- .doit = nl80211_addset_beacon,
+ .doit = nl80211_start_ap,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
{
- .cmd = NL80211_CMD_DEL_BEACON,
+ .cmd = NL80211_CMD_STOP_AP,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
- .doit = nl80211_del_beacon,
+ .doit = nl80211_stop_ap,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},