diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-03-26 05:35:50 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-03-26 05:35:50 -0400 |
commit | b510446b643572903535c3b1d3e63e9cfa4e94d9 (patch) | |
tree | 9948562b6e050f5722663d2436835787e3e22504 /drivers | |
parent | 8c6e83d6d3e522bba314225863ff323991d514f7 (diff) | |
parent | 64513ef449e3beaacb801d41467f47642683e35a (diff) |
Merge remote-tracking branch 'wireless-next/master' into iwlwifi-next
Diffstat (limited to 'drivers')
47 files changed, 672 insertions, 242 deletions
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index 4adf9ef9a113..8934298a638d 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c | |||
@@ -217,6 +217,7 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) | |||
217 | } | 217 | } |
218 | 218 | ||
219 | SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0); | 219 | SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0); |
220 | SPEX(board_type, SSB_SPROM1_SPID, ~0, 0); | ||
220 | 221 | ||
221 | SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0, | 222 | SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0, |
222 | SSB_SPROM4_TXPID2G0_SHIFT); | 223 | SSB_SPROM4_TXPID2G0_SHIFT); |
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 9959d4cb23dc..1cb51839912d 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c | |||
@@ -83,8 +83,8 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = { | |||
83 | }; | 83 | }; |
84 | 84 | ||
85 | static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { | 85 | static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { |
86 | .helper = "sd8688_helper.bin", | 86 | .helper = "mrvl/sd8688_helper.bin", |
87 | .firmware = "sd8688.bin", | 87 | .firmware = "mrvl/sd8688.bin", |
88 | .reg = &btmrvl_reg_8688, | 88 | .reg = &btmrvl_reg_8688, |
89 | .sd_blksz_fw_dl = 64, | 89 | .sd_blksz_fw_dl = 64, |
90 | }; | 90 | }; |
@@ -1185,7 +1185,7 @@ MODULE_AUTHOR("Marvell International Ltd."); | |||
1185 | MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION); | 1185 | MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION); |
1186 | MODULE_VERSION(VERSION); | 1186 | MODULE_VERSION(VERSION); |
1187 | MODULE_LICENSE("GPL v2"); | 1187 | MODULE_LICENSE("GPL v2"); |
1188 | MODULE_FIRMWARE("sd8688_helper.bin"); | 1188 | MODULE_FIRMWARE("mrvl/sd8688_helper.bin"); |
1189 | MODULE_FIRMWARE("sd8688.bin"); | 1189 | MODULE_FIRMWARE("mrvl/sd8688.bin"); |
1190 | MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); | 1190 | MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); |
1191 | MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin"); | 1191 | MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin"); |
diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 7157f7d311c5..afd1e36d308f 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c | |||
@@ -1091,7 +1091,7 @@ static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | |||
1091 | return ret; | 1091 | return ret; |
1092 | } | 1092 | } |
1093 | 1093 | ||
1094 | static void ar5523_flush(struct ieee80211_hw *hw, bool drop) | 1094 | static void ar5523_flush(struct ieee80211_hw *hw, u32 queues, bool drop) |
1095 | { | 1095 | { |
1096 | struct ar5523 *ar = hw->priv; | 1096 | struct ar5523 *ar = hw->priv; |
1097 | 1097 | ||
diff --git a/drivers/net/wireless/ath/ath6kl/trace.h b/drivers/net/wireless/ath/ath6kl/trace.h index 6af6fa038312..1a1ea7881b4d 100644 --- a/drivers/net/wireless/ath/ath6kl/trace.h +++ b/drivers/net/wireless/ath/ath6kl/trace.h | |||
@@ -53,7 +53,7 @@ TRACE_EVENT(ath6kl_wmi_cmd, | |||
53 | ), | 53 | ), |
54 | 54 | ||
55 | TP_printk( | 55 | TP_printk( |
56 | "id %d len %d", | 56 | "id %d len %zd", |
57 | __entry->id, __entry->buf_len | 57 | __entry->id, __entry->buf_len |
58 | ) | 58 | ) |
59 | ); | 59 | ); |
@@ -76,7 +76,7 @@ TRACE_EVENT(ath6kl_wmi_event, | |||
76 | ), | 76 | ), |
77 | 77 | ||
78 | TP_printk( | 78 | TP_printk( |
79 | "id %d len %d", | 79 | "id %d len %zd", |
80 | __entry->id, __entry->buf_len | 80 | __entry->id, __entry->buf_len |
81 | ) | 81 | ) |
82 | ); | 82 | ); |
@@ -108,7 +108,7 @@ TRACE_EVENT(ath6kl_sdio, | |||
108 | ), | 108 | ), |
109 | 109 | ||
110 | TP_printk( | 110 | TP_printk( |
111 | "%s addr 0x%x flags 0x%x len %d\n", | 111 | "%s addr 0x%x flags 0x%x len %zd\n", |
112 | __entry->tx ? "tx" : "rx", | 112 | __entry->tx ? "tx" : "rx", |
113 | __entry->addr, | 113 | __entry->addr, |
114 | __entry->flags, | 114 | __entry->flags, |
@@ -161,7 +161,7 @@ TRACE_EVENT(ath6kl_sdio_scat, | |||
161 | ), | 161 | ), |
162 | 162 | ||
163 | TP_printk( | 163 | TP_printk( |
164 | "%s addr 0x%x flags 0x%x entries %d total_len %d\n", | 164 | "%s addr 0x%x flags 0x%x entries %d total_len %zd\n", |
165 | __entry->tx ? "tx" : "rx", | 165 | __entry->tx ? "tx" : "rx", |
166 | __entry->addr, | 166 | __entry->addr, |
167 | __entry->flags, | 167 | __entry->flags, |
@@ -186,7 +186,7 @@ TRACE_EVENT(ath6kl_sdio_irq, | |||
186 | ), | 186 | ), |
187 | 187 | ||
188 | TP_printk( | 188 | TP_printk( |
189 | "irq len %d\n", __entry->buf_len | 189 | "irq len %zd\n", __entry->buf_len |
190 | ) | 190 | ) |
191 | ); | 191 | ); |
192 | 192 | ||
@@ -211,7 +211,7 @@ TRACE_EVENT(ath6kl_htc_rx, | |||
211 | ), | 211 | ), |
212 | 212 | ||
213 | TP_printk( | 213 | TP_printk( |
214 | "status %d endpoint %d len %d\n", | 214 | "status %d endpoint %d len %zd\n", |
215 | __entry->status, | 215 | __entry->status, |
216 | __entry->endpoint, | 216 | __entry->endpoint, |
217 | __entry->buf_len | 217 | __entry->buf_len |
@@ -239,7 +239,7 @@ TRACE_EVENT(ath6kl_htc_tx, | |||
239 | ), | 239 | ), |
240 | 240 | ||
241 | TP_printk( | 241 | TP_printk( |
242 | "status %d endpoint %d len %d\n", | 242 | "status %d endpoint %d len %zd\n", |
243 | __entry->status, | 243 | __entry->status, |
244 | __entry->endpoint, | 244 | __entry->endpoint, |
245 | __entry->buf_len | 245 | __entry->buf_len |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 6e66f9c6782b..24650fd41694 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -1745,7 +1745,7 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) | |||
1745 | mutex_unlock(&sc->mutex); | 1745 | mutex_unlock(&sc->mutex); |
1746 | } | 1746 | } |
1747 | 1747 | ||
1748 | static void ath9k_flush(struct ieee80211_hw *hw, bool drop) | 1748 | static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) |
1749 | { | 1749 | { |
1750 | struct ath_softc *sc = hw->priv; | 1750 | struct ath_softc *sc = hw->priv; |
1751 | struct ath_hw *ah = sc->sc_ah; | 1751 | struct ath_hw *ah = sc->sc_ah; |
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index f293b3ff4756..08b193199946 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c | |||
@@ -1703,7 +1703,7 @@ found: | |||
1703 | return 0; | 1703 | return 0; |
1704 | } | 1704 | } |
1705 | 1705 | ||
1706 | static void carl9170_op_flush(struct ieee80211_hw *hw, bool drop) | 1706 | static void carl9170_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop) |
1707 | { | 1707 | { |
1708 | struct ar9170 *ar = hw->priv; | 1708 | struct ar9170 *ar = hw->priv; |
1709 | unsigned int vid; | 1709 | unsigned int vid; |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index c4d0cc582555..ae4eeb3bfa54 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -2780,9 +2780,7 @@ static int b43_gpio_init(struct b43_wldev *dev) | |||
2780 | switch (dev->dev->bus_type) { | 2780 | switch (dev->dev->bus_type) { |
2781 | #ifdef CONFIG_B43_BCMA | 2781 | #ifdef CONFIG_B43_BCMA |
2782 | case B43_BUS_BCMA: | 2782 | case B43_BUS_BCMA: |
2783 | bcma_cc_write32(&dev->dev->bdev->bus->drv_cc, BCMA_CC_GPIOCTL, | 2783 | bcma_chipco_gpio_control(&dev->dev->bdev->bus->drv_cc, mask, set); |
2784 | (bcma_cc_read32(&dev->dev->bdev->bus->drv_cc, | ||
2785 | BCMA_CC_GPIOCTL) & ~mask) | set); | ||
2786 | break; | 2784 | break; |
2787 | #endif | 2785 | #endif |
2788 | #ifdef CONFIG_B43_SSB | 2786 | #ifdef CONFIG_B43_SSB |
@@ -2807,8 +2805,7 @@ static void b43_gpio_cleanup(struct b43_wldev *dev) | |||
2807 | switch (dev->dev->bus_type) { | 2805 | switch (dev->dev->bus_type) { |
2808 | #ifdef CONFIG_B43_BCMA | 2806 | #ifdef CONFIG_B43_BCMA |
2809 | case B43_BUS_BCMA: | 2807 | case B43_BUS_BCMA: |
2810 | bcma_cc_write32(&dev->dev->bdev->bus->drv_cc, BCMA_CC_GPIOCTL, | 2808 | bcma_chipco_gpio_control(&dev->dev->bdev->bus->drv_cc, ~0, 0); |
2811 | 0); | ||
2812 | break; | 2809 | break; |
2813 | #endif | 2810 | #endif |
2814 | #ifdef CONFIG_B43_SSB | 2811 | #ifdef CONFIG_B43_SSB |
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 3ae28561f7a4..5ed352ddae9e 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c | |||
@@ -104,14 +104,8 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev) | |||
104 | maxpwr = sprom->maxpwr_bg; | 104 | maxpwr = sprom->maxpwr_bg; |
105 | lpphy->max_tx_pwr_med_band = maxpwr; | 105 | lpphy->max_tx_pwr_med_band = maxpwr; |
106 | cckpo = sprom->cck2gpo; | 106 | cckpo = sprom->cck2gpo; |
107 | /* | ||
108 | * We don't read SPROM's opo as specs say. On rev8 SPROMs | ||
109 | * opo == ofdm2gpo and we don't know any SSB with LP-PHY | ||
110 | * and SPROM rev below 8. | ||
111 | */ | ||
112 | B43_WARN_ON(sprom->revision < 8); | ||
113 | ofdmpo = sprom->ofdm2gpo; | ||
114 | if (cckpo) { | 107 | if (cckpo) { |
108 | ofdmpo = sprom->ofdm2gpo; | ||
115 | for (i = 0; i < 4; i++) { | 109 | for (i = 0; i < 4; i++) { |
116 | lpphy->tx_max_rate[i] = | 110 | lpphy->tx_max_rate[i] = |
117 | maxpwr - (ofdmpo & 0xF) * 2; | 111 | maxpwr - (ofdmpo & 0xF) * 2; |
@@ -124,11 +118,11 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev) | |||
124 | ofdmpo >>= 4; | 118 | ofdmpo >>= 4; |
125 | } | 119 | } |
126 | } else { | 120 | } else { |
127 | ofdmpo &= 0xFF; | 121 | u8 opo = sprom->opo; |
128 | for (i = 0; i < 4; i++) | 122 | for (i = 0; i < 4; i++) |
129 | lpphy->tx_max_rate[i] = maxpwr; | 123 | lpphy->tx_max_rate[i] = maxpwr; |
130 | for (i = 4; i < 15; i++) | 124 | for (i = 4; i < 15; i++) |
131 | lpphy->tx_max_rate[i] = maxpwr - ofdmpo; | 125 | lpphy->tx_max_rate[i] = maxpwr - opo; |
132 | } | 126 | } |
133 | } else { /* 5GHz */ | 127 | } else { /* 5GHz */ |
134 | lpphy->tx_isolation_low_band = sprom->tri5gl; | 128 | lpphy->tx_isolation_low_band = sprom->tri5gl; |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index c70cf7b654cd..7cc30f8fed7d 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | |||
@@ -724,7 +724,7 @@ static bool brcms_tx_flush_completed(struct brcms_info *wl) | |||
724 | return result; | 724 | return result; |
725 | } | 725 | } |
726 | 726 | ||
727 | static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop) | 727 | static void brcms_ops_flush(struct ieee80211_hw *hw, u32 queues, bool drop) |
728 | { | 728 | { |
729 | struct brcms_info *wl = hw->priv; | 729 | struct brcms_info *wl = hw->priv; |
730 | int ret; | 730 | int ret; |
diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index bc465da40476..1a518feb4b26 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c | |||
@@ -4704,8 +4704,7 @@ out: | |||
4704 | } | 4704 | } |
4705 | EXPORT_SYMBOL(il_mac_change_interface); | 4705 | EXPORT_SYMBOL(il_mac_change_interface); |
4706 | 4706 | ||
4707 | void | 4707 | void il_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop) |
4708 | il_mac_flush(struct ieee80211_hw *hw, bool drop) | ||
4709 | { | 4708 | { |
4710 | struct il_priv *il = hw->priv; | 4709 | struct il_priv *il = hw->priv; |
4711 | unsigned long timeout = jiffies + msecs_to_jiffies(500); | 4710 | unsigned long timeout = jiffies + msecs_to_jiffies(500); |
diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h index 73bd3ef316c8..728aa1306ab8 100644 --- a/drivers/net/wireless/iwlegacy/common.h +++ b/drivers/net/wireless/iwlegacy/common.h | |||
@@ -1720,7 +1720,7 @@ void il_mac_remove_interface(struct ieee80211_hw *hw, | |||
1720 | struct ieee80211_vif *vif); | 1720 | struct ieee80211_vif *vif); |
1721 | int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 1721 | int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
1722 | enum nl80211_iftype newtype, bool newp2p); | 1722 | enum nl80211_iftype newtype, bool newp2p); |
1723 | void il_mac_flush(struct ieee80211_hw *hw, bool drop); | 1723 | void il_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop); |
1724 | int il_alloc_txq_mem(struct il_priv *il); | 1724 | int il_alloc_txq_mem(struct il_priv *il); |
1725 | void il_free_txq_mem(struct il_priv *il); | 1725 | void il_free_txq_mem(struct il_priv *il); |
1726 | 1726 | ||
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index c7cd2dffa5cd..a7294fa4d7e5 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c | |||
@@ -1100,7 +1100,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw, | |||
1100 | FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; | 1100 | FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; |
1101 | } | 1101 | } |
1102 | 1102 | ||
1103 | static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) | 1103 | static void iwlagn_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop) |
1104 | { | 1104 | { |
1105 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); | 1105 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); |
1106 | 1106 | ||
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 7490c4fc7177..0064d38276bf 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -964,6 +964,12 @@ static int mac80211_hwsim_change_interface(struct ieee80211_hw *hw, | |||
964 | newtype, vif->addr); | 964 | newtype, vif->addr); |
965 | hwsim_check_magic(vif); | 965 | hwsim_check_magic(vif); |
966 | 966 | ||
967 | /* | ||
968 | * interface may change from non-AP to AP in | ||
969 | * which case this needs to be set up again | ||
970 | */ | ||
971 | vif->cab_queue = 0; | ||
972 | |||
967 | return 0; | 973 | return 0; |
968 | } | 974 | } |
969 | 975 | ||
@@ -1389,7 +1395,7 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, | |||
1389 | return 0; | 1395 | return 0; |
1390 | } | 1396 | } |
1391 | 1397 | ||
1392 | static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop) | 1398 | static void mac80211_hwsim_flush(struct ieee80211_hw *hw, u32 queues, bool drop) |
1393 | { | 1399 | { |
1394 | /* Not implemented, queues only on kernel side */ | 1400 | /* Not implemented, queues only on kernel side */ |
1395 | } | 1401 | } |
diff --git a/drivers/net/wireless/mwifiex/11ac.c b/drivers/net/wireless/mwifiex/11ac.c index cf43b3c29250..de0a63469cb1 100644 --- a/drivers/net/wireless/mwifiex/11ac.c +++ b/drivers/net/wireless/mwifiex/11ac.c | |||
@@ -259,3 +259,22 @@ int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv, | |||
259 | 259 | ||
260 | return ret_len; | 260 | return ret_len; |
261 | } | 261 | } |
262 | |||
263 | int mwifiex_cmd_11ac_cfg(struct mwifiex_private *priv, | ||
264 | struct host_cmd_ds_command *cmd, u16 cmd_action, | ||
265 | struct mwifiex_11ac_vht_cfg *cfg) | ||
266 | { | ||
267 | struct host_cmd_11ac_vht_cfg *vhtcfg = &cmd->params.vht_cfg; | ||
268 | |||
269 | cmd->command = cpu_to_le16(HostCmd_CMD_11AC_CFG); | ||
270 | cmd->size = cpu_to_le16(sizeof(struct host_cmd_11ac_vht_cfg) + | ||
271 | S_DS_GEN); | ||
272 | vhtcfg->action = cpu_to_le16(cmd_action); | ||
273 | vhtcfg->band_config = cfg->band_config; | ||
274 | vhtcfg->misc_config = cfg->misc_config; | ||
275 | vhtcfg->cap_info = cpu_to_le32(cfg->cap_info); | ||
276 | vhtcfg->mcs_tx_set = cpu_to_le32(cfg->mcs_tx_set); | ||
277 | vhtcfg->mcs_rx_set = cpu_to_le32(cfg->mcs_rx_set); | ||
278 | |||
279 | return 0; | ||
280 | } | ||
diff --git a/drivers/net/wireless/mwifiex/11ac.h b/drivers/net/wireless/mwifiex/11ac.h index 80fd1ba46200..7c2c69b5b3eb 100644 --- a/drivers/net/wireless/mwifiex/11ac.h +++ b/drivers/net/wireless/mwifiex/11ac.h | |||
@@ -20,7 +20,24 @@ | |||
20 | #ifndef _MWIFIEX_11AC_H_ | 20 | #ifndef _MWIFIEX_11AC_H_ |
21 | #define _MWIFIEX_11AC_H_ | 21 | #define _MWIFIEX_11AC_H_ |
22 | 22 | ||
23 | #define VHT_CFG_2GHZ BIT(0) | ||
24 | #define VHT_CFG_5GHZ BIT(1) | ||
25 | |||
26 | enum vht_cfg_misc_config { | ||
27 | VHT_CAP_TX_OPERATION = 1, | ||
28 | VHT_CAP_ASSOCIATION, | ||
29 | VHT_CAP_UAP_ONLY | ||
30 | }; | ||
31 | |||
32 | #define DEFAULT_VHT_MCS_SET 0xfffa | ||
33 | #define DISABLE_VHT_MCS_SET 0xffff | ||
34 | |||
35 | #define VHT_BW_80_160_80P80 BIT(2) | ||
36 | |||
23 | int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv, | 37 | int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv, |
24 | struct mwifiex_bssdescriptor *bss_desc, | 38 | struct mwifiex_bssdescriptor *bss_desc, |
25 | u8 **buffer); | 39 | u8 **buffer); |
40 | int mwifiex_cmd_11ac_cfg(struct mwifiex_private *priv, | ||
41 | struct host_cmd_ds_command *cmd, u16 cmd_action, | ||
42 | struct mwifiex_11ac_vht_cfg *cfg); | ||
26 | #endif /* _MWIFIEX_11AC_H_ */ | 43 | #endif /* _MWIFIEX_11AC_H_ */ |
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index dbf5b1289516..95f3306e2836 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c | |||
@@ -1374,6 +1374,13 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, | |||
1374 | } | 1374 | } |
1375 | 1375 | ||
1376 | mwifiex_set_ht_params(priv, bss_cfg, params); | 1376 | mwifiex_set_ht_params(priv, bss_cfg, params); |
1377 | |||
1378 | if (priv->adapter->is_hw_11ac_capable) { | ||
1379 | mwifiex_set_vht_params(priv, bss_cfg, params); | ||
1380 | mwifiex_set_vht_width(priv, params->chandef.width, | ||
1381 | priv->ap_11ac_enabled); | ||
1382 | } | ||
1383 | |||
1377 | mwifiex_set_wmm_params(priv, bss_cfg, params); | 1384 | mwifiex_set_wmm_params(priv, bss_cfg, params); |
1378 | 1385 | ||
1379 | if (params->inactivity_timeout > 0) { | 1386 | if (params->inactivity_timeout > 0) { |
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 57c5defe1f9d..1f7578d553ec 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h | |||
@@ -295,6 +295,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { | |||
295 | #define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa | 295 | #define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa |
296 | #define HostCmd_CMD_MGMT_FRAME_REG 0x010c | 296 | #define HostCmd_CMD_MGMT_FRAME_REG 0x010c |
297 | #define HostCmd_CMD_REMAIN_ON_CHAN 0x010d | 297 | #define HostCmd_CMD_REMAIN_ON_CHAN 0x010d |
298 | #define HostCmd_CMD_11AC_CFG 0x0112 | ||
298 | 299 | ||
299 | #define PROTOCOL_NO_SECURITY 0x01 | 300 | #define PROTOCOL_NO_SECURITY 0x01 |
300 | #define PROTOCOL_STATIC_WEP 0x02 | 301 | #define PROTOCOL_STATIC_WEP 0x02 |
@@ -1363,6 +1364,15 @@ struct host_cmd_ds_sys_config { | |||
1363 | u8 tlv[0]; | 1364 | u8 tlv[0]; |
1364 | }; | 1365 | }; |
1365 | 1366 | ||
1367 | struct host_cmd_11ac_vht_cfg { | ||
1368 | __le16 action; | ||
1369 | u8 band_config; | ||
1370 | u8 misc_config; | ||
1371 | __le32 cap_info; | ||
1372 | __le32 mcs_tx_set; | ||
1373 | __le32 mcs_rx_set; | ||
1374 | } __packed; | ||
1375 | |||
1366 | struct host_cmd_tlv_akmp { | 1376 | struct host_cmd_tlv_akmp { |
1367 | struct host_cmd_tlv tlv; | 1377 | struct host_cmd_tlv tlv; |
1368 | __le16 key_mgmt; | 1378 | __le16 key_mgmt; |
@@ -1620,6 +1630,7 @@ struct host_cmd_ds_command { | |||
1620 | struct host_cmd_ds_802_11_eeprom_access eeprom; | 1630 | struct host_cmd_ds_802_11_eeprom_access eeprom; |
1621 | struct host_cmd_ds_802_11_subsc_evt subsc_evt; | 1631 | struct host_cmd_ds_802_11_subsc_evt subsc_evt; |
1622 | struct host_cmd_ds_sys_config uap_sys_config; | 1632 | struct host_cmd_ds_sys_config uap_sys_config; |
1633 | struct host_cmd_11ac_vht_cfg vht_cfg; | ||
1623 | } params; | 1634 | } params; |
1624 | } __packed; | 1635 | } __packed; |
1625 | 1636 | ||
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 91d522c746ed..7f27e45680b5 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h | |||
@@ -272,6 +272,14 @@ struct mwifiex_ds_pm_cfg { | |||
272 | } param; | 272 | } param; |
273 | }; | 273 | }; |
274 | 274 | ||
275 | struct mwifiex_11ac_vht_cfg { | ||
276 | u8 band_config; | ||
277 | u8 misc_config; | ||
278 | u32 cap_info; | ||
279 | u32 mcs_tx_set; | ||
280 | u32 mcs_rx_set; | ||
281 | }; | ||
282 | |||
275 | struct mwifiex_ds_11n_tx_cfg { | 283 | struct mwifiex_ds_11n_tx_cfg { |
276 | u16 tx_htcap; | 284 | u16 tx_htcap; |
277 | u16 tx_htinfo; | 285 | u16 tx_htinfo; |
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 920657587fff..975bc186a643 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h | |||
@@ -913,8 +913,14 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv, | |||
913 | void mwifiex_set_ht_params(struct mwifiex_private *priv, | 913 | void mwifiex_set_ht_params(struct mwifiex_private *priv, |
914 | struct mwifiex_uap_bss_param *bss_cfg, | 914 | struct mwifiex_uap_bss_param *bss_cfg, |
915 | struct cfg80211_ap_settings *params); | 915 | struct cfg80211_ap_settings *params); |
916 | void mwifiex_set_vht_params(struct mwifiex_private *priv, | ||
917 | struct mwifiex_uap_bss_param *bss_cfg, | ||
918 | struct cfg80211_ap_settings *params); | ||
916 | void mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg, | 919 | void mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg, |
917 | struct cfg80211_ap_settings *params); | 920 | struct cfg80211_ap_settings *params); |
921 | void mwifiex_set_vht_width(struct mwifiex_private *priv, | ||
922 | enum nl80211_chan_width width, | ||
923 | bool ap_11ac_disable); | ||
918 | void | 924 | void |
919 | mwifiex_set_wmm_params(struct mwifiex_private *priv, | 925 | mwifiex_set_wmm_params(struct mwifiex_private *priv, |
920 | struct mwifiex_uap_bss_param *bss_cfg, | 926 | struct mwifiex_uap_bss_param *bss_cfg, |
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index a2ae690a0a67..b193e25977d2 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "main.h" | 24 | #include "main.h" |
25 | #include "wmm.h" | 25 | #include "wmm.h" |
26 | #include "11n.h" | 26 | #include "11n.h" |
27 | #include "11ac.h" | ||
27 | 28 | ||
28 | /* | 29 | /* |
29 | * This function prepares command to set/get RSSI information. | 30 | * This function prepares command to set/get RSSI information. |
@@ -1258,6 +1259,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, | |||
1258 | cpu_to_le16(sizeof(struct host_cmd_ds_remain_on_chan) + | 1259 | cpu_to_le16(sizeof(struct host_cmd_ds_remain_on_chan) + |
1259 | S_DS_GEN); | 1260 | S_DS_GEN); |
1260 | break; | 1261 | break; |
1262 | case HostCmd_CMD_11AC_CFG: | ||
1263 | ret = mwifiex_cmd_11ac_cfg(priv, cmd_ptr, cmd_action, data_buf); | ||
1264 | break; | ||
1261 | case HostCmd_CMD_P2P_MODE_CFG: | 1265 | case HostCmd_CMD_P2P_MODE_CFG: |
1262 | cmd_ptr->command = cpu_to_le16(cmd_no); | 1266 | cmd_ptr->command = cpu_to_le16(cmd_no); |
1263 | cmd_ptr->params.mode_cfg.action = cpu_to_le16(cmd_action); | 1267 | cmd_ptr->params.mode_cfg.action = cpu_to_le16(cmd_action); |
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 80b9f2238001..c7dc450f0bf3 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c | |||
@@ -907,6 +907,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, | |||
907 | case HostCmd_CMD_REMAIN_ON_CHAN: | 907 | case HostCmd_CMD_REMAIN_ON_CHAN: |
908 | ret = mwifiex_ret_remain_on_chan(priv, resp, data_buf); | 908 | ret = mwifiex_ret_remain_on_chan(priv, resp, data_buf); |
909 | break; | 909 | break; |
910 | case HostCmd_CMD_11AC_CFG: | ||
911 | break; | ||
910 | case HostCmd_CMD_P2P_MODE_CFG: | 912 | case HostCmd_CMD_P2P_MODE_CFG: |
911 | ret = mwifiex_ret_p2p_mode_cfg(priv, resp, data_buf); | 913 | ret = mwifiex_ret_p2p_mode_cfg(priv, resp, data_buf); |
912 | break; | 914 | break; |
diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index 6e76a15a8950..b04b1db29100 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c | |||
@@ -18,6 +18,7 @@ | |||
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include "main.h" | 20 | #include "main.h" |
21 | #include "11ac.h" | ||
21 | 22 | ||
22 | /* This function parses security related parameters from cfg80211_ap_settings | 23 | /* This function parses security related parameters from cfg80211_ap_settings |
23 | * and sets into FW understandable bss_config structure. | 24 | * and sets into FW understandable bss_config structure. |
@@ -177,6 +178,60 @@ mwifiex_set_ht_params(struct mwifiex_private *priv, | |||
177 | return; | 178 | return; |
178 | } | 179 | } |
179 | 180 | ||
181 | /* This function updates 11ac related parameters from IE | ||
182 | * and sets them into bss_config structure. | ||
183 | */ | ||
184 | void mwifiex_set_vht_params(struct mwifiex_private *priv, | ||
185 | struct mwifiex_uap_bss_param *bss_cfg, | ||
186 | struct cfg80211_ap_settings *params) | ||
187 | { | ||
188 | const u8 *vht_ie; | ||
189 | |||
190 | vht_ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, params->beacon.tail, | ||
191 | params->beacon.tail_len); | ||
192 | if (vht_ie) { | ||
193 | memcpy(&bss_cfg->vht_cap, vht_ie + 2, | ||
194 | sizeof(struct ieee80211_vht_cap)); | ||
195 | priv->ap_11ac_enabled = 1; | ||
196 | } else { | ||
197 | priv->ap_11ac_enabled = 0; | ||
198 | } | ||
199 | |||
200 | return; | ||
201 | } | ||
202 | |||
203 | /* Enable VHT only when cfg80211_ap_settings has VHT IE. | ||
204 | * Otherwise disable VHT. | ||
205 | */ | ||
206 | void mwifiex_set_vht_width(struct mwifiex_private *priv, | ||
207 | enum nl80211_chan_width width, | ||
208 | bool ap_11ac_enable) | ||
209 | { | ||
210 | struct mwifiex_adapter *adapter = priv->adapter; | ||
211 | struct mwifiex_11ac_vht_cfg vht_cfg; | ||
212 | |||
213 | vht_cfg.band_config = VHT_CFG_5GHZ; | ||
214 | vht_cfg.cap_info = adapter->hw_dot_11ac_dev_cap; | ||
215 | |||
216 | if (!ap_11ac_enable) { | ||
217 | vht_cfg.mcs_tx_set = DISABLE_VHT_MCS_SET; | ||
218 | vht_cfg.mcs_rx_set = DISABLE_VHT_MCS_SET; | ||
219 | } else { | ||
220 | vht_cfg.mcs_tx_set = DEFAULT_VHT_MCS_SET; | ||
221 | vht_cfg.mcs_rx_set = DEFAULT_VHT_MCS_SET; | ||
222 | } | ||
223 | |||
224 | vht_cfg.misc_config = VHT_CAP_UAP_ONLY; | ||
225 | |||
226 | if (ap_11ac_enable && width >= NL80211_CHAN_WIDTH_80) | ||
227 | vht_cfg.misc_config |= VHT_BW_80_160_80P80; | ||
228 | |||
229 | mwifiex_send_cmd_sync(priv, HostCmd_CMD_11AC_CFG, | ||
230 | HostCmd_ACT_GEN_SET, 0, &vht_cfg); | ||
231 | |||
232 | return; | ||
233 | } | ||
234 | |||
180 | /* This function finds supported rates IE from beacon parameter and sets | 235 | /* This function finds supported rates IE from beacon parameter and sets |
181 | * these rates into bss_config structure. | 236 | * these rates into bss_config structure. |
182 | */ | 237 | */ |
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index aadda99989c0..ee654a691f38 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c | |||
@@ -670,7 +670,7 @@ static unsigned int p54_flush_count(struct p54_common *priv) | |||
670 | return total; | 670 | return total; |
671 | } | 671 | } |
672 | 672 | ||
673 | static void p54_flush(struct ieee80211_hw *dev, bool drop) | 673 | static void p54_flush(struct ieee80211_hw *dev, u32 queues, bool drop) |
674 | { | 674 | { |
675 | struct p54_common *priv = dev->priv; | 675 | struct p54_common *priv = dev->priv; |
676 | unsigned int total, i; | 676 | unsigned int total, i; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 51922cc179de..cdf26ede7270 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -1366,7 +1366,7 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, | |||
1366 | struct ieee80211_vif *vif, u16 queue, | 1366 | struct ieee80211_vif *vif, u16 queue, |
1367 | const struct ieee80211_tx_queue_params *params); | 1367 | const struct ieee80211_tx_queue_params *params); |
1368 | void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw); | 1368 | void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw); |
1369 | void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop); | 1369 | void rt2x00mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop); |
1370 | int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); | 1370 | int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); |
1371 | int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); | 1371 | int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); |
1372 | void rt2x00mac_get_ringparam(struct ieee80211_hw *hw, | 1372 | void rt2x00mac_get_ringparam(struct ieee80211_hw *hw, |
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 20c6eccce5aa..9161c02d8ff9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c | |||
@@ -748,7 +748,7 @@ void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw) | |||
748 | } | 748 | } |
749 | EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll); | 749 | EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll); |
750 | 750 | ||
751 | void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop) | 751 | void rt2x00mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop) |
752 | { | 752 | { |
753 | struct rt2x00_dev *rt2x00dev = hw->priv; | 753 | struct rt2x00_dev *rt2x00dev = hw->priv; |
754 | struct data_queue *queue; | 754 | struct data_queue *queue; |
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index d3ce9fbef00e..b5a7a260bf63 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c | |||
@@ -1166,7 +1166,7 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw) | |||
1166 | * before switch channle or power save, or tx buffer packet | 1166 | * before switch channle or power save, or tx buffer packet |
1167 | * maybe send after offchannel or rf sleep, this may cause | 1167 | * maybe send after offchannel or rf sleep, this may cause |
1168 | * dis-association by AP */ | 1168 | * dis-association by AP */ |
1169 | static void rtl_op_flush(struct ieee80211_hw *hw, bool drop) | 1169 | static void rtl_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop) |
1170 | { | 1170 | { |
1171 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 1171 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
1172 | 1172 | ||
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index b6222eedb835..710f7904ecdf 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c | |||
@@ -434,7 +434,7 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
434 | (u32)hdr->addr1[2], (u32)hdr->addr1[3], | 434 | (u32)hdr->addr1[2], (u32)hdr->addr1[3], |
435 | (u32)hdr->addr1[4], (u32)hdr->addr1[5]); | 435 | (u32)hdr->addr1[4], (u32)hdr->addr1[5]); |
436 | memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); | 436 | memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); |
437 | ieee80211_rx_irqsafe(hw, skb); | 437 | ieee80211_rx(hw, skb); |
438 | } | 438 | } |
439 | 439 | ||
440 | void rtl8192cu_rx_hdl(struct ieee80211_hw *hw, struct sk_buff * skb) | 440 | void rtl8192cu_rx_hdl(struct ieee80211_hw *hw, struct sk_buff * skb) |
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index b5c80b5d57ef..72c2614213c4 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c | |||
@@ -308,6 +308,8 @@ static int _rtl_usb_init_tx(struct ieee80211_hw *hw) | |||
308 | return 0; | 308 | return 0; |
309 | } | 309 | } |
310 | 310 | ||
311 | static void _rtl_rx_work(unsigned long param); | ||
312 | |||
311 | static int _rtl_usb_init_rx(struct ieee80211_hw *hw) | 313 | static int _rtl_usb_init_rx(struct ieee80211_hw *hw) |
312 | { | 314 | { |
313 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 315 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
@@ -324,6 +326,12 @@ static int _rtl_usb_init_rx(struct ieee80211_hw *hw) | |||
324 | pr_info("rx_max_size %d, rx_urb_num %d, in_ep %d\n", | 326 | pr_info("rx_max_size %d, rx_urb_num %d, in_ep %d\n", |
325 | rtlusb->rx_max_size, rtlusb->rx_urb_num, rtlusb->in_ep); | 327 | rtlusb->rx_max_size, rtlusb->rx_urb_num, rtlusb->in_ep); |
326 | init_usb_anchor(&rtlusb->rx_submitted); | 328 | init_usb_anchor(&rtlusb->rx_submitted); |
329 | init_usb_anchor(&rtlusb->rx_cleanup_urbs); | ||
330 | |||
331 | skb_queue_head_init(&rtlusb->rx_queue); | ||
332 | rtlusb->rx_work_tasklet.func = _rtl_rx_work; | ||
333 | rtlusb->rx_work_tasklet.data = (unsigned long)rtlusb; | ||
334 | |||
327 | return 0; | 335 | return 0; |
328 | } | 336 | } |
329 | 337 | ||
@@ -405,40 +413,30 @@ static void rtl_usb_init_sw(struct ieee80211_hw *hw) | |||
405 | rtlusb->disableHWSM = true; | 413 | rtlusb->disableHWSM = true; |
406 | } | 414 | } |
407 | 415 | ||
408 | #define __RADIO_TAP_SIZE_RSV 32 | ||
409 | |||
410 | static void _rtl_rx_completed(struct urb *urb); | 416 | static void _rtl_rx_completed(struct urb *urb); |
411 | 417 | ||
412 | static struct sk_buff *_rtl_prep_rx_urb(struct ieee80211_hw *hw, | 418 | static int _rtl_prep_rx_urb(struct ieee80211_hw *hw, struct rtl_usb *rtlusb, |
413 | struct rtl_usb *rtlusb, | 419 | struct urb *urb, gfp_t gfp_mask) |
414 | struct urb *urb, | ||
415 | gfp_t gfp_mask) | ||
416 | { | 420 | { |
417 | struct sk_buff *skb; | ||
418 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 421 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
422 | void *buf; | ||
419 | 423 | ||
420 | skb = __dev_alloc_skb((rtlusb->rx_max_size + __RADIO_TAP_SIZE_RSV), | 424 | buf = usb_alloc_coherent(rtlusb->udev, rtlusb->rx_max_size, gfp_mask, |
421 | gfp_mask); | 425 | &urb->transfer_dma); |
422 | if (!skb) { | 426 | if (!buf) { |
423 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, | 427 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, |
424 | "Failed to __dev_alloc_skb!!\n"); | 428 | "Failed to usb_alloc_coherent!!\n"); |
425 | return ERR_PTR(-ENOMEM); | 429 | return -ENOMEM; |
426 | } | 430 | } |
427 | 431 | ||
428 | /* reserve some space for mac80211's radiotap */ | ||
429 | skb_reserve(skb, __RADIO_TAP_SIZE_RSV); | ||
430 | usb_fill_bulk_urb(urb, rtlusb->udev, | 432 | usb_fill_bulk_urb(urb, rtlusb->udev, |
431 | usb_rcvbulkpipe(rtlusb->udev, rtlusb->in_ep), | 433 | usb_rcvbulkpipe(rtlusb->udev, rtlusb->in_ep), |
432 | skb->data, min(skb_tailroom(skb), | 434 | buf, rtlusb->rx_max_size, _rtl_rx_completed, rtlusb); |
433 | (int)rtlusb->rx_max_size), | 435 | urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
434 | _rtl_rx_completed, skb); | ||
435 | 436 | ||
436 | _rtl_install_trx_info(rtlusb, skb, rtlusb->in_ep); | 437 | return 0; |
437 | return skb; | ||
438 | } | 438 | } |
439 | 439 | ||
440 | #undef __RADIO_TAP_SIZE_RSV | ||
441 | |||
442 | static void _rtl_usb_rx_process_agg(struct ieee80211_hw *hw, | 440 | static void _rtl_usb_rx_process_agg(struct ieee80211_hw *hw, |
443 | struct sk_buff *skb) | 441 | struct sk_buff *skb) |
444 | { | 442 | { |
@@ -522,22 +520,11 @@ static void _rtl_usb_rx_process_noagg(struct ieee80211_hw *hw, | |||
522 | if (unicast) | 520 | if (unicast) |
523 | rtlpriv->link_info.num_rx_inperiod++; | 521 | rtlpriv->link_info.num_rx_inperiod++; |
524 | } | 522 | } |
525 | if (likely(rtl_action_proc(hw, skb, false))) { | 523 | |
526 | struct sk_buff *uskb = NULL; | 524 | if (likely(rtl_action_proc(hw, skb, false))) |
527 | u8 *pdata; | 525 | ieee80211_rx(hw, skb); |
528 | 526 | else | |
529 | uskb = dev_alloc_skb(skb->len + 128); | ||
530 | if (uskb) { /* drop packet on allocation failure */ | ||
531 | memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status, | ||
532 | sizeof(rx_status)); | ||
533 | pdata = (u8 *)skb_put(uskb, skb->len); | ||
534 | memcpy(pdata, skb->data, skb->len); | ||
535 | ieee80211_rx_irqsafe(hw, uskb); | ||
536 | } | ||
537 | dev_kfree_skb_any(skb); | ||
538 | } else { | ||
539 | dev_kfree_skb_any(skb); | 527 | dev_kfree_skb_any(skb); |
540 | } | ||
541 | } | 528 | } |
542 | } | 529 | } |
543 | 530 | ||
@@ -554,15 +541,70 @@ static void _rtl_rx_pre_process(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
554 | while (!skb_queue_empty(&rx_queue)) { | 541 | while (!skb_queue_empty(&rx_queue)) { |
555 | _skb = skb_dequeue(&rx_queue); | 542 | _skb = skb_dequeue(&rx_queue); |
556 | _rtl_usb_rx_process_agg(hw, _skb); | 543 | _rtl_usb_rx_process_agg(hw, _skb); |
557 | ieee80211_rx_irqsafe(hw, _skb); | 544 | ieee80211_rx(hw, _skb); |
558 | } | 545 | } |
559 | } | 546 | } |
560 | 547 | ||
548 | #define __RX_SKB_MAX_QUEUED 32 | ||
549 | |||
550 | static void _rtl_rx_work(unsigned long param) | ||
551 | { | ||
552 | struct rtl_usb *rtlusb = (struct rtl_usb *)param; | ||
553 | struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf); | ||
554 | struct sk_buff *skb; | ||
555 | |||
556 | while ((skb = skb_dequeue(&rtlusb->rx_queue))) { | ||
557 | if (unlikely(IS_USB_STOP(rtlusb))) { | ||
558 | dev_kfree_skb_any(skb); | ||
559 | continue; | ||
560 | } | ||
561 | |||
562 | if (likely(!rtlusb->usb_rx_segregate_hdl)) { | ||
563 | _rtl_usb_rx_process_noagg(hw, skb); | ||
564 | } else { | ||
565 | /* TO DO */ | ||
566 | _rtl_rx_pre_process(hw, skb); | ||
567 | pr_err("rx agg not supported\n"); | ||
568 | } | ||
569 | } | ||
570 | } | ||
571 | |||
572 | static unsigned int _rtl_rx_get_padding(struct ieee80211_hdr *hdr, | ||
573 | unsigned int len) | ||
574 | { | ||
575 | unsigned int padding = 0; | ||
576 | |||
577 | /* make function no-op when possible */ | ||
578 | if (NET_IP_ALIGN == 0 || len < sizeof(*hdr)) | ||
579 | return 0; | ||
580 | |||
581 | /* alignment calculation as in lbtf_rx() / carl9170_rx_copy_data() */ | ||
582 | /* TODO: deduplicate common code, define helper function instead? */ | ||
583 | |||
584 | if (ieee80211_is_data_qos(hdr->frame_control)) { | ||
585 | u8 *qc = ieee80211_get_qos_ctl(hdr); | ||
586 | |||
587 | padding ^= NET_IP_ALIGN; | ||
588 | |||
589 | /* Input might be invalid, avoid accessing memory outside | ||
590 | * the buffer. | ||
591 | */ | ||
592 | if ((unsigned long)qc - (unsigned long)hdr < len && | ||
593 | *qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT) | ||
594 | padding ^= NET_IP_ALIGN; | ||
595 | } | ||
596 | |||
597 | if (ieee80211_has_a4(hdr->frame_control)) | ||
598 | padding ^= NET_IP_ALIGN; | ||
599 | |||
600 | return padding; | ||
601 | } | ||
602 | |||
603 | #define __RADIO_TAP_SIZE_RSV 32 | ||
604 | |||
561 | static void _rtl_rx_completed(struct urb *_urb) | 605 | static void _rtl_rx_completed(struct urb *_urb) |
562 | { | 606 | { |
563 | struct sk_buff *skb = (struct sk_buff *)_urb->context; | 607 | struct rtl_usb *rtlusb = (struct rtl_usb *)_urb->context; |
564 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
565 | struct rtl_usb *rtlusb = (struct rtl_usb *)info->rate_driver_data[0]; | ||
566 | struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf); | 608 | struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf); |
567 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 609 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
568 | int err = 0; | 610 | int err = 0; |
@@ -571,28 +613,50 @@ static void _rtl_rx_completed(struct urb *_urb) | |||
571 | goto free; | 613 | goto free; |
572 | 614 | ||
573 | if (likely(0 == _urb->status)) { | 615 | if (likely(0 == _urb->status)) { |
574 | /* If this code were moved to work queue, would CPU | 616 | unsigned int padding; |
575 | * utilization be improved? NOTE: We shall allocate another skb | 617 | struct sk_buff *skb; |
576 | * and reuse the original one. | 618 | unsigned int qlen; |
577 | */ | 619 | unsigned int size = _urb->actual_length; |
578 | skb_put(skb, _urb->actual_length); | 620 | struct ieee80211_hdr *hdr; |
579 | 621 | ||
580 | if (likely(!rtlusb->usb_rx_segregate_hdl)) { | 622 | if (size < RTL_RX_DESC_SIZE + sizeof(struct ieee80211_hdr)) { |
581 | struct sk_buff *_skb; | 623 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, |
582 | _rtl_usb_rx_process_noagg(hw, skb); | 624 | "Too short packet from bulk IN! (len: %d)\n", |
583 | _skb = _rtl_prep_rx_urb(hw, rtlusb, _urb, GFP_ATOMIC); | 625 | size); |
584 | if (IS_ERR(_skb)) { | 626 | goto resubmit; |
585 | err = PTR_ERR(_skb); | 627 | } |
586 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, | 628 | |
587 | "Can't allocate skb for bulk IN!\n"); | 629 | qlen = skb_queue_len(&rtlusb->rx_queue); |
588 | return; | 630 | if (qlen >= __RX_SKB_MAX_QUEUED) { |
589 | } | 631 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, |
590 | skb = _skb; | 632 | "Pending RX skbuff queue full! (qlen: %d)\n", |
591 | } else{ | 633 | qlen); |
592 | /* TO DO */ | 634 | goto resubmit; |
593 | _rtl_rx_pre_process(hw, skb); | ||
594 | pr_err("rx agg not supported\n"); | ||
595 | } | 635 | } |
636 | |||
637 | hdr = (void *)(_urb->transfer_buffer + RTL_RX_DESC_SIZE); | ||
638 | padding = _rtl_rx_get_padding(hdr, size - RTL_RX_DESC_SIZE); | ||
639 | |||
640 | skb = dev_alloc_skb(size + __RADIO_TAP_SIZE_RSV + padding); | ||
641 | if (!skb) { | ||
642 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, | ||
643 | "Can't allocate skb for bulk IN!\n"); | ||
644 | goto resubmit; | ||
645 | } | ||
646 | |||
647 | _rtl_install_trx_info(rtlusb, skb, rtlusb->in_ep); | ||
648 | |||
649 | /* Make sure the payload data is 4 byte aligned. */ | ||
650 | skb_reserve(skb, padding); | ||
651 | |||
652 | /* reserve some space for mac80211's radiotap */ | ||
653 | skb_reserve(skb, __RADIO_TAP_SIZE_RSV); | ||
654 | |||
655 | memcpy(skb_put(skb, size), _urb->transfer_buffer, size); | ||
656 | |||
657 | skb_queue_tail(&rtlusb->rx_queue, skb); | ||
658 | tasklet_schedule(&rtlusb->rx_work_tasklet); | ||
659 | |||
596 | goto resubmit; | 660 | goto resubmit; |
597 | } | 661 | } |
598 | 662 | ||
@@ -608,9 +672,6 @@ static void _rtl_rx_completed(struct urb *_urb) | |||
608 | } | 672 | } |
609 | 673 | ||
610 | resubmit: | 674 | resubmit: |
611 | skb_reset_tail_pointer(skb); | ||
612 | skb_trim(skb, 0); | ||
613 | |||
614 | usb_anchor_urb(_urb, &rtlusb->rx_submitted); | 675 | usb_anchor_urb(_urb, &rtlusb->rx_submitted); |
615 | err = usb_submit_urb(_urb, GFP_ATOMIC); | 676 | err = usb_submit_urb(_urb, GFP_ATOMIC); |
616 | if (unlikely(err)) { | 677 | if (unlikely(err)) { |
@@ -620,13 +681,34 @@ resubmit: | |||
620 | return; | 681 | return; |
621 | 682 | ||
622 | free: | 683 | free: |
623 | dev_kfree_skb_irq(skb); | 684 | /* On some architectures, usb_free_coherent must not be called from |
685 | * hardirq context. Queue urb to cleanup list. | ||
686 | */ | ||
687 | usb_anchor_urb(_urb, &rtlusb->rx_cleanup_urbs); | ||
688 | } | ||
689 | |||
690 | #undef __RADIO_TAP_SIZE_RSV | ||
691 | |||
692 | static void _rtl_usb_cleanup_rx(struct ieee80211_hw *hw) | ||
693 | { | ||
694 | struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); | ||
695 | struct urb *urb; | ||
696 | |||
697 | usb_kill_anchored_urbs(&rtlusb->rx_submitted); | ||
698 | |||
699 | tasklet_kill(&rtlusb->rx_work_tasklet); | ||
700 | skb_queue_purge(&rtlusb->rx_queue); | ||
701 | |||
702 | while ((urb = usb_get_from_anchor(&rtlusb->rx_cleanup_urbs))) { | ||
703 | usb_free_coherent(urb->dev, urb->transfer_buffer_length, | ||
704 | urb->transfer_buffer, urb->transfer_dma); | ||
705 | usb_free_urb(urb); | ||
706 | } | ||
624 | } | 707 | } |
625 | 708 | ||
626 | static int _rtl_usb_receive(struct ieee80211_hw *hw) | 709 | static int _rtl_usb_receive(struct ieee80211_hw *hw) |
627 | { | 710 | { |
628 | struct urb *urb; | 711 | struct urb *urb; |
629 | struct sk_buff *skb; | ||
630 | int err; | 712 | int err; |
631 | int i; | 713 | int i; |
632 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 714 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
@@ -645,11 +727,10 @@ static int _rtl_usb_receive(struct ieee80211_hw *hw) | |||
645 | goto err_out; | 727 | goto err_out; |
646 | } | 728 | } |
647 | 729 | ||
648 | skb = _rtl_prep_rx_urb(hw, rtlusb, urb, GFP_KERNEL); | 730 | err = _rtl_prep_rx_urb(hw, rtlusb, urb, GFP_KERNEL); |
649 | if (IS_ERR(skb)) { | 731 | if (err < 0) { |
650 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, | 732 | RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, |
651 | "Failed to prep_rx_urb!!\n"); | 733 | "Failed to prep_rx_urb!!\n"); |
652 | err = PTR_ERR(skb); | ||
653 | usb_free_urb(urb); | 734 | usb_free_urb(urb); |
654 | goto err_out; | 735 | goto err_out; |
655 | } | 736 | } |
@@ -664,6 +745,7 @@ static int _rtl_usb_receive(struct ieee80211_hw *hw) | |||
664 | 745 | ||
665 | err_out: | 746 | err_out: |
666 | usb_kill_anchored_urbs(&rtlusb->rx_submitted); | 747 | usb_kill_anchored_urbs(&rtlusb->rx_submitted); |
748 | _rtl_usb_cleanup_rx(hw); | ||
667 | return err; | 749 | return err; |
668 | } | 750 | } |
669 | 751 | ||
@@ -705,7 +787,7 @@ static void rtl_usb_cleanup(struct ieee80211_hw *hw) | |||
705 | SET_USB_STOP(rtlusb); | 787 | SET_USB_STOP(rtlusb); |
706 | 788 | ||
707 | /* clean up rx stuff. */ | 789 | /* clean up rx stuff. */ |
708 | usb_kill_anchored_urbs(&rtlusb->rx_submitted); | 790 | _rtl_usb_cleanup_rx(hw); |
709 | 791 | ||
710 | /* clean up tx stuff */ | 792 | /* clean up tx stuff */ |
711 | for (i = 0; i < RTL_USB_MAX_EP_NUM; i++) { | 793 | for (i = 0; i < RTL_USB_MAX_EP_NUM; i++) { |
diff --git a/drivers/net/wireless/rtlwifi/usb.h b/drivers/net/wireless/rtlwifi/usb.h index fb986f98d1df..685273ca9561 100644 --- a/drivers/net/wireless/rtlwifi/usb.h +++ b/drivers/net/wireless/rtlwifi/usb.h | |||
@@ -136,11 +136,14 @@ struct rtl_usb { | |||
136 | void (*usb_tx_cleanup)(struct ieee80211_hw *, struct sk_buff *); | 136 | void (*usb_tx_cleanup)(struct ieee80211_hw *, struct sk_buff *); |
137 | 137 | ||
138 | /* Rx */ | 138 | /* Rx */ |
139 | u8 in_ep_nums ; | 139 | u8 in_ep_nums; |
140 | u32 in_ep; /* Bulk IN endpoint number */ | 140 | u32 in_ep; /* Bulk IN endpoint number */ |
141 | u32 rx_max_size; /* Bulk IN max buffer size */ | 141 | u32 rx_max_size; /* Bulk IN max buffer size */ |
142 | u32 rx_urb_num; /* How many Bulk INs are submitted to host. */ | 142 | u32 rx_urb_num; /* How many Bulk INs are submitted to host. */ |
143 | struct usb_anchor rx_submitted; | 143 | struct usb_anchor rx_submitted; |
144 | struct usb_anchor rx_cleanup_urbs; | ||
145 | struct tasklet_struct rx_work_tasklet; | ||
146 | struct sk_buff_head rx_queue; | ||
144 | void (*usb_rx_segregate_hdl)(struct ieee80211_hw *, struct sk_buff *, | 147 | void (*usb_rx_segregate_hdl)(struct ieee80211_hw *, struct sk_buff *, |
145 | struct sk_buff_head *); | 148 | struct sk_buff_head *); |
146 | void (*usb_rx_hdl)(struct ieee80211_hw *, struct sk_buff *); | 149 | void (*usb_rx_hdl)(struct ieee80211_hw *, struct sk_buff *); |
diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c index e57ee48edff6..e2b3d9c541e8 100644 --- a/drivers/net/wireless/ti/wl1251/sdio.c +++ b/drivers/net/wireless/ti/wl1251/sdio.c | |||
@@ -186,8 +186,10 @@ static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable) | |||
186 | wl->set_power(true); | 186 | wl->set_power(true); |
187 | 187 | ||
188 | ret = pm_runtime_get_sync(&func->dev); | 188 | ret = pm_runtime_get_sync(&func->dev); |
189 | if (ret < 0) | 189 | if (ret < 0) { |
190 | pm_runtime_put_sync(&func->dev); | ||
190 | goto out; | 191 | goto out; |
192 | } | ||
191 | 193 | ||
192 | sdio_claim_host(func); | 194 | sdio_claim_host(func); |
193 | sdio_enable_func(func); | 195 | sdio_enable_func(func); |
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index 09694e39bb14..1c627da85083 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c | |||
@@ -723,6 +723,7 @@ static int wl12xx_identify_chip(struct wl1271 *wl) | |||
723 | wl->sched_scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4; | 723 | wl->sched_scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4; |
724 | wl->sched_scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5; | 724 | wl->sched_scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5; |
725 | wl->max_channels_5 = WL12XX_MAX_CHANNELS_5GHZ; | 725 | wl->max_channels_5 = WL12XX_MAX_CHANNELS_5GHZ; |
726 | wl->ba_rx_session_count_max = WL12XX_RX_BA_MAX_SESSIONS; | ||
726 | out: | 727 | out: |
727 | return ret; | 728 | return ret; |
728 | } | 729 | } |
diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx.h b/drivers/net/wireless/ti/wl12xx/wl12xx.h index d4552857480c..222d03540200 100644 --- a/drivers/net/wireless/ti/wl12xx/wl12xx.h +++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h | |||
@@ -63,6 +63,8 @@ | |||
63 | 63 | ||
64 | #define WL12XX_NUM_MAC_ADDRESSES 2 | 64 | #define WL12XX_NUM_MAC_ADDRESSES 2 |
65 | 65 | ||
66 | #define WL12XX_RX_BA_MAX_SESSIONS 3 | ||
67 | |||
66 | struct wl127x_rx_mem_pool_addr { | 68 | struct wl127x_rx_mem_pool_addr { |
67 | u32 addr; | 69 | u32 addr; |
68 | u32 addr_extra; | 70 | u32 addr_extra; |
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index da3ef1b10a9c..9fa692d11025 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c | |||
@@ -678,6 +678,7 @@ static int wl18xx_identify_chip(struct wl1271 *wl) | |||
678 | wl->sched_scan_templ_id_2_4 = CMD_TEMPL_PROBE_REQ_2_4_PERIODIC; | 678 | wl->sched_scan_templ_id_2_4 = CMD_TEMPL_PROBE_REQ_2_4_PERIODIC; |
679 | wl->sched_scan_templ_id_5 = CMD_TEMPL_PROBE_REQ_5_PERIODIC; | 679 | wl->sched_scan_templ_id_5 = CMD_TEMPL_PROBE_REQ_5_PERIODIC; |
680 | wl->max_channels_5 = WL18XX_MAX_CHANNELS_5GHZ; | 680 | wl->max_channels_5 = WL18XX_MAX_CHANNELS_5GHZ; |
681 | wl->ba_rx_session_count_max = WL18XX_RX_BA_MAX_SESSIONS; | ||
681 | out: | 682 | out: |
682 | return ret; | 683 | return ret; |
683 | } | 684 | } |
@@ -1144,6 +1145,7 @@ static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl, | |||
1144 | static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver) | 1145 | static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver) |
1145 | { | 1146 | { |
1146 | u32 fuse; | 1147 | u32 fuse; |
1148 | s8 rom = 0, metal = 0, pg_ver = 0, rdl_ver = 0; | ||
1147 | int ret; | 1149 | int ret; |
1148 | 1150 | ||
1149 | ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); | 1151 | ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); |
@@ -1154,8 +1156,29 @@ static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver) | |||
1154 | if (ret < 0) | 1156 | if (ret < 0) |
1155 | goto out; | 1157 | goto out; |
1156 | 1158 | ||
1159 | pg_ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET; | ||
1160 | rom = (fuse & WL18XX_ROM_VER_MASK) >> WL18XX_ROM_VER_OFFSET; | ||
1161 | |||
1162 | if (rom <= 0xE) | ||
1163 | metal = (fuse & WL18XX_METAL_VER_MASK) >> | ||
1164 | WL18XX_METAL_VER_OFFSET; | ||
1165 | else | ||
1166 | metal = (fuse & WL18XX_NEW_METAL_VER_MASK) >> | ||
1167 | WL18XX_NEW_METAL_VER_OFFSET; | ||
1168 | |||
1169 | ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_2_3, &fuse); | ||
1170 | if (ret < 0) | ||
1171 | goto out; | ||
1172 | |||
1173 | rdl_ver = (fuse & WL18XX_RDL_VER_MASK) >> WL18XX_RDL_VER_OFFSET; | ||
1174 | if (rdl_ver > RDL_MAX) | ||
1175 | rdl_ver = RDL_NONE; | ||
1176 | |||
1177 | wl1271_info("wl18xx HW: RDL %d, %s, PG %x.%x (ROM %x)", | ||
1178 | rdl_ver, rdl_names[rdl_ver], pg_ver, metal, rom); | ||
1179 | |||
1157 | if (ver) | 1180 | if (ver) |
1158 | *ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET; | 1181 | *ver = pg_ver; |
1159 | 1182 | ||
1160 | ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); | 1183 | ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); |
1161 | 1184 | ||
diff --git a/drivers/net/wireless/ti/wl18xx/reg.h b/drivers/net/wireless/ti/wl18xx/reg.h index 937b71d8783f..6306e04cd258 100644 --- a/drivers/net/wireless/ti/wl18xx/reg.h +++ b/drivers/net/wireless/ti/wl18xx/reg.h | |||
@@ -131,6 +131,16 @@ | |||
131 | #define WL18XX_REG_FUSE_DATA_1_3 0xA0260C | 131 | #define WL18XX_REG_FUSE_DATA_1_3 0xA0260C |
132 | #define WL18XX_PG_VER_MASK 0x70 | 132 | #define WL18XX_PG_VER_MASK 0x70 |
133 | #define WL18XX_PG_VER_OFFSET 4 | 133 | #define WL18XX_PG_VER_OFFSET 4 |
134 | #define WL18XX_ROM_VER_MASK 0x3 | ||
135 | #define WL18XX_ROM_VER_OFFSET 0 | ||
136 | #define WL18XX_METAL_VER_MASK 0xC | ||
137 | #define WL18XX_METAL_VER_OFFSET 2 | ||
138 | #define WL18XX_NEW_METAL_VER_MASK 0x180 | ||
139 | #define WL18XX_NEW_METAL_VER_OFFSET 7 | ||
140 | |||
141 | #define WL18XX_REG_FUSE_DATA_2_3 0xA02614 | ||
142 | #define WL18XX_RDL_VER_MASK 0x1f00 | ||
143 | #define WL18XX_RDL_VER_OFFSET 8 | ||
134 | 144 | ||
135 | #define WL18XX_REG_FUSE_BD_ADDR_1 0xA02602 | 145 | #define WL18XX_REG_FUSE_BD_ADDR_1 0xA02602 |
136 | #define WL18XX_REG_FUSE_BD_ADDR_2 0xA02606 | 146 | #define WL18XX_REG_FUSE_BD_ADDR_2 0xA02606 |
@@ -188,4 +198,23 @@ enum { | |||
188 | NUM_BOARD_TYPES, | 198 | NUM_BOARD_TYPES, |
189 | }; | 199 | }; |
190 | 200 | ||
201 | enum { | ||
202 | RDL_NONE = 0, | ||
203 | RDL_1_HP = 1, | ||
204 | RDL_2_SP = 2, | ||
205 | RDL_3_HP = 3, | ||
206 | RDL_4_SP = 4, | ||
207 | |||
208 | _RDL_LAST, | ||
209 | RDL_MAX = _RDL_LAST - 1, | ||
210 | }; | ||
211 | |||
212 | static const char * const rdl_names[] = { | ||
213 | [RDL_NONE] = "", | ||
214 | [RDL_1_HP] = "1853 SISO", | ||
215 | [RDL_2_SP] = "1857 MIMO", | ||
216 | [RDL_3_HP] = "1893 SISO", | ||
217 | [RDL_4_SP] = "1897 MIMO", | ||
218 | }; | ||
219 | |||
191 | #endif /* __REG_H__ */ | 220 | #endif /* __REG_H__ */ |
diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h index b6739e79efcf..9204e07ee432 100644 --- a/drivers/net/wireless/ti/wl18xx/wl18xx.h +++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h | |||
@@ -29,7 +29,7 @@ | |||
29 | #define WL18XX_IFTYPE_VER 5 | 29 | #define WL18XX_IFTYPE_VER 5 |
30 | #define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE | 30 | #define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE |
31 | #define WL18XX_SUBTYPE_VER WLCORE_FW_VER_IGNORE | 31 | #define WL18XX_SUBTYPE_VER WLCORE_FW_VER_IGNORE |
32 | #define WL18XX_MINOR_VER 28 | 32 | #define WL18XX_MINOR_VER 39 |
33 | 33 | ||
34 | #define WL18XX_CMD_MAX_SIZE 740 | 34 | #define WL18XX_CMD_MAX_SIZE 740 |
35 | 35 | ||
@@ -40,6 +40,8 @@ | |||
40 | 40 | ||
41 | #define WL18XX_NUM_MAC_ADDRESSES 3 | 41 | #define WL18XX_NUM_MAC_ADDRESSES 3 |
42 | 42 | ||
43 | #define WL18XX_RX_BA_MAX_SESSIONS 5 | ||
44 | |||
43 | struct wl18xx_priv { | 45 | struct wl18xx_priv { |
44 | /* buffer for sending commands to FW */ | 46 | /* buffer for sending commands to FW */ |
45 | u8 cmd_buf[WL18XX_CMD_MAX_SIZE]; | 47 | u8 cmd_buf[WL18XX_CMD_MAX_SIZE]; |
diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c index c79654323396..7a970cd9c555 100644 --- a/drivers/net/wireless/ti/wlcore/acx.c +++ b/drivers/net/wireless/ti/wlcore/acx.c | |||
@@ -1736,6 +1736,35 @@ out: | |||
1736 | 1736 | ||
1737 | } | 1737 | } |
1738 | 1738 | ||
1739 | int wlcore_acx_average_rssi(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1740 | s8 *avg_rssi) | ||
1741 | { | ||
1742 | struct acx_roaming_stats *acx; | ||
1743 | int ret = 0; | ||
1744 | |||
1745 | wl1271_debug(DEBUG_ACX, "acx roaming statistics"); | ||
1746 | |||
1747 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1748 | if (!acx) { | ||
1749 | ret = -ENOMEM; | ||
1750 | goto out; | ||
1751 | } | ||
1752 | |||
1753 | acx->role_id = wlvif->role_id; | ||
1754 | ret = wl1271_cmd_interrogate(wl, ACX_ROAMING_STATISTICS_TBL, | ||
1755 | acx, sizeof(*acx)); | ||
1756 | if (ret < 0) { | ||
1757 | wl1271_warning("acx roaming statistics failed: %d", ret); | ||
1758 | ret = -ENOMEM; | ||
1759 | goto out; | ||
1760 | } | ||
1761 | |||
1762 | *avg_rssi = acx->rssi_beacon; | ||
1763 | out: | ||
1764 | kfree(acx); | ||
1765 | return ret; | ||
1766 | } | ||
1767 | |||
1739 | #ifdef CONFIG_PM | 1768 | #ifdef CONFIG_PM |
1740 | /* Set the global behaviour of RX filters - On/Off + default action */ | 1769 | /* Set the global behaviour of RX filters - On/Off + default action */ |
1741 | int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable, | 1770 | int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable, |
diff --git a/drivers/net/wireless/ti/wlcore/acx.h b/drivers/net/wireless/ti/wlcore/acx.h index 126536c6a393..6dcfad9b0472 100644 --- a/drivers/net/wireless/ti/wlcore/acx.h +++ b/drivers/net/wireless/ti/wlcore/acx.h | |||
@@ -728,8 +728,6 @@ struct wl1271_acx_ht_information { | |||
728 | u8 padding[2]; | 728 | u8 padding[2]; |
729 | } __packed; | 729 | } __packed; |
730 | 730 | ||
731 | #define RX_BA_MAX_SESSIONS 3 | ||
732 | |||
733 | struct wl1271_acx_ba_initiator_policy { | 731 | struct wl1271_acx_ba_initiator_policy { |
734 | struct acx_header header; | 732 | struct acx_header header; |
735 | 733 | ||
@@ -955,6 +953,18 @@ struct acx_rx_filter_cfg { | |||
955 | u8 fields[0]; | 953 | u8 fields[0]; |
956 | } __packed; | 954 | } __packed; |
957 | 955 | ||
956 | struct acx_roaming_stats { | ||
957 | struct acx_header header; | ||
958 | |||
959 | u8 role_id; | ||
960 | u8 pad[3]; | ||
961 | u32 missed_beacons; | ||
962 | u8 snr_data; | ||
963 | u8 snr_bacon; | ||
964 | s8 rssi_data; | ||
965 | s8 rssi_beacon; | ||
966 | } __packed; | ||
967 | |||
958 | enum { | 968 | enum { |
959 | ACX_WAKE_UP_CONDITIONS = 0x0000, | 969 | ACX_WAKE_UP_CONDITIONS = 0x0000, |
960 | ACX_MEM_CFG = 0x0001, | 970 | ACX_MEM_CFG = 0x0001, |
@@ -1112,6 +1122,8 @@ int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); | |||
1112 | int wl1271_acx_fm_coex(struct wl1271 *wl); | 1122 | int wl1271_acx_fm_coex(struct wl1271 *wl); |
1113 | int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl); | 1123 | int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl); |
1114 | int wl12xx_acx_config_hangover(struct wl1271 *wl); | 1124 | int wl12xx_acx_config_hangover(struct wl1271 *wl); |
1125 | int wlcore_acx_average_rssi(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1126 | s8 *avg_rssi); | ||
1115 | 1127 | ||
1116 | #ifdef CONFIG_PM | 1128 | #ifdef CONFIG_PM |
1117 | int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable, | 1129 | int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable, |
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 6331f9e1cb39..c9e060795d13 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c | |||
@@ -327,6 +327,14 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) | |||
327 | wl->links[link].prev_freed_pkts = | 327 | wl->links[link].prev_freed_pkts = |
328 | wl->fw_status_2->counters.tx_lnk_free_pkts[link]; | 328 | wl->fw_status_2->counters.tx_lnk_free_pkts[link]; |
329 | wl->links[link].wlvif = wlvif; | 329 | wl->links[link].wlvif = wlvif; |
330 | |||
331 | /* | ||
332 | * Take saved value for total freed packets from wlvif, in case this is | ||
333 | * recovery/resume | ||
334 | */ | ||
335 | if (wlvif->bss_type != BSS_TYPE_AP_BSS) | ||
336 | wl->links[link].total_freed_pkts = wlvif->total_freed_pkts; | ||
337 | |||
330 | *hlid = link; | 338 | *hlid = link; |
331 | 339 | ||
332 | wl->active_link_count++; | 340 | wl->active_link_count++; |
@@ -358,6 +366,26 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) | |||
358 | wl1271_tx_reset_link_queues(wl, *hlid); | 366 | wl1271_tx_reset_link_queues(wl, *hlid); |
359 | wl->links[*hlid].wlvif = NULL; | 367 | wl->links[*hlid].wlvif = NULL; |
360 | 368 | ||
369 | if (wlvif->bss_type == BSS_TYPE_STA_BSS || | ||
370 | (wlvif->bss_type == BSS_TYPE_AP_BSS && | ||
371 | *hlid == wlvif->ap.bcast_hlid)) { | ||
372 | /* | ||
373 | * save the total freed packets in the wlvif, in case this is | ||
374 | * recovery or suspend | ||
375 | */ | ||
376 | wlvif->total_freed_pkts = wl->links[*hlid].total_freed_pkts; | ||
377 | |||
378 | /* | ||
379 | * increment the initial seq number on recovery to account for | ||
380 | * transmitted packets that we haven't yet got in the FW status | ||
381 | */ | ||
382 | if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) | ||
383 | wlvif->total_freed_pkts += | ||
384 | WL1271_TX_SQN_POST_RECOVERY_PADDING; | ||
385 | } | ||
386 | |||
387 | wl->links[*hlid].total_freed_pkts = 0; | ||
388 | |||
361 | *hlid = WL12XX_INVALID_LINK_ID; | 389 | *hlid = WL12XX_INVALID_LINK_ID; |
362 | wl->active_link_count--; | 390 | wl->active_link_count--; |
363 | WARN_ON_ONCE(wl->active_link_count < 0); | 391 | WARN_ON_ONCE(wl->active_link_count < 0); |
@@ -609,6 +637,10 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
609 | if (ret < 0) | 637 | if (ret < 0) |
610 | goto out_free_global; | 638 | goto out_free_global; |
611 | 639 | ||
640 | /* use the previous security seq, if this is a recovery/resume */ | ||
641 | wl->links[wlvif->ap.bcast_hlid].total_freed_pkts = | ||
642 | wlvif->total_freed_pkts; | ||
643 | |||
612 | cmd->role_id = wlvif->role_id; | 644 | cmd->role_id = wlvif->role_id; |
613 | cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); | 645 | cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); |
614 | cmd->ap.bss_index = WL1271_AP_BSS_INDEX; | 646 | cmd->ap.bss_index = WL1271_AP_BSS_INDEX; |
diff --git a/drivers/net/wireless/ti/wlcore/debug.h b/drivers/net/wireless/ti/wlcore/debug.h index db4bf5a68ce2..0420bd45e4ee 100644 --- a/drivers/net/wireless/ti/wlcore/debug.h +++ b/drivers/net/wireless/ti/wlcore/debug.h | |||
@@ -89,25 +89,24 @@ extern u32 wl12xx_debug_level; | |||
89 | } while (0) | 89 | } while (0) |
90 | #endif | 90 | #endif |
91 | 91 | ||
92 | /* TODO: use pr_debug_hex_dump when it becomes available */ | 92 | #define wl1271_dump(level, prefix, buf, len) \ |
93 | #define wl1271_dump(level, prefix, buf, len) \ | 93 | do { \ |
94 | do { \ | 94 | if (level & wl12xx_debug_level) \ |
95 | if (level & wl12xx_debug_level) \ | 95 | print_hex_dump_debug(DRIVER_PREFIX prefix, \ |
96 | print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ | 96 | DUMP_PREFIX_OFFSET, 16, 1, \ |
97 | DUMP_PREFIX_OFFSET, 16, 1, \ | 97 | buf, \ |
98 | buf, \ | 98 | min_t(size_t, len, DEBUG_DUMP_LIMIT), \ |
99 | min_t(size_t, len, DEBUG_DUMP_LIMIT), \ | 99 | 0); \ |
100 | 0); \ | ||
101 | } while (0) | 100 | } while (0) |
102 | 101 | ||
103 | #define wl1271_dump_ascii(level, prefix, buf, len) \ | 102 | #define wl1271_dump_ascii(level, prefix, buf, len) \ |
104 | do { \ | 103 | do { \ |
105 | if (level & wl12xx_debug_level) \ | 104 | if (level & wl12xx_debug_level) \ |
106 | print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ | 105 | print_hex_dump_debug(DRIVER_PREFIX prefix, \ |
107 | DUMP_PREFIX_OFFSET, 16, 1, \ | 106 | DUMP_PREFIX_OFFSET, 16, 1, \ |
108 | buf, \ | 107 | buf, \ |
109 | min_t(size_t, len, DEBUG_DUMP_LIMIT), \ | 108 | min_t(size_t, len, DEBUG_DUMP_LIMIT), \ |
110 | true); \ | 109 | true); \ |
111 | } while (0) | 110 | } while (0) |
112 | 111 | ||
113 | #endif /* __DEBUG_H__ */ | 112 | #endif /* __DEBUG_H__ */ |
diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c index e70a7c864865..c3e1f79c7856 100644 --- a/drivers/net/wireless/ti/wlcore/debugfs.c +++ b/drivers/net/wireless/ti/wlcore/debugfs.c | |||
@@ -598,8 +598,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf, | |||
598 | VIF_STATE_PRINT_INT(last_rssi_event); | 598 | VIF_STATE_PRINT_INT(last_rssi_event); |
599 | VIF_STATE_PRINT_INT(ba_support); | 599 | VIF_STATE_PRINT_INT(ba_support); |
600 | VIF_STATE_PRINT_INT(ba_allowed); | 600 | VIF_STATE_PRINT_INT(ba_allowed); |
601 | VIF_STATE_PRINT_LLHEX(tx_security_seq); | 601 | VIF_STATE_PRINT_LLHEX(total_freed_pkts); |
602 | VIF_STATE_PRINT_INT(tx_security_last_seq_lsb); | ||
603 | } | 602 | } |
604 | 603 | ||
605 | #undef VIF_STATE_PRINT_INT | 604 | #undef VIF_STATE_PRINT_INT |
diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c index 70f289aa1bc6..67f61689b49e 100644 --- a/drivers/net/wireless/ti/wlcore/event.c +++ b/drivers/net/wireless/ti/wlcore/event.c | |||
@@ -237,6 +237,14 @@ void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap) | |||
237 | !test_bit(wlvif->role_id , &roles_bitmap)) | 237 | !test_bit(wlvif->role_id , &roles_bitmap)) |
238 | continue; | 238 | continue; |
239 | 239 | ||
240 | vif = wl12xx_wlvif_to_vif(wlvif); | ||
241 | |||
242 | /* don't attempt roaming in case of p2p */ | ||
243 | if (wlvif->p2p) { | ||
244 | ieee80211_connection_loss(vif); | ||
245 | continue; | ||
246 | } | ||
247 | |||
240 | /* | 248 | /* |
241 | * if the work is already queued, it should take place. | 249 | * if the work is already queued, it should take place. |
242 | * We don't want to delay the connection loss | 250 | * We don't want to delay the connection loss |
@@ -246,7 +254,6 @@ void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap) | |||
246 | &wlvif->connection_loss_work, | 254 | &wlvif->connection_loss_work, |
247 | msecs_to_jiffies(delay)); | 255 | msecs_to_jiffies(delay)); |
248 | 256 | ||
249 | vif = wl12xx_wlvif_to_vif(wlvif); | ||
250 | ieee80211_cqm_rssi_notify( | 257 | ieee80211_cqm_rssi_notify( |
251 | vif, | 258 | vif, |
252 | NL80211_CQM_RSSI_BEACON_LOSS_EVENT, | 259 | NL80211_CQM_RSSI_BEACON_LOSS_EVENT, |
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index d7e306333f6c..d10954c0c181 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c | |||
@@ -108,8 +108,7 @@ static void wl1271_reg_notify(struct wiphy *wiphy, | |||
108 | 108 | ||
109 | } | 109 | } |
110 | 110 | ||
111 | if (likely(wl->state == WLCORE_STATE_ON)) | 111 | wlcore_regdomain_config(wl); |
112 | wlcore_regdomain_config(wl); | ||
113 | } | 112 | } |
114 | 113 | ||
115 | static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 114 | static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
@@ -332,10 +331,9 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, | |||
332 | struct wl12xx_vif *wlvif, | 331 | struct wl12xx_vif *wlvif, |
333 | u8 hlid, u8 tx_pkts) | 332 | u8 hlid, u8 tx_pkts) |
334 | { | 333 | { |
335 | bool fw_ps, single_link; | 334 | bool fw_ps; |
336 | 335 | ||
337 | fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); | 336 | fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); |
338 | single_link = (wl->active_link_count == 1); | ||
339 | 337 | ||
340 | /* | 338 | /* |
341 | * Wake up from high level PS if the STA is asleep with too little | 339 | * Wake up from high level PS if the STA is asleep with too little |
@@ -348,8 +346,13 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, | |||
348 | * Start high-level PS if the STA is asleep with enough blocks in FW. | 346 | * Start high-level PS if the STA is asleep with enough blocks in FW. |
349 | * Make an exception if this is the only connected link. In this | 347 | * Make an exception if this is the only connected link. In this |
350 | * case FW-memory congestion is less of a problem. | 348 | * case FW-memory congestion is less of a problem. |
349 | * Note that a single connected STA means 3 active links, since we must | ||
350 | * account for the global and broadcast AP links. The "fw_ps" check | ||
351 | * assures us the third link is a STA connected to the AP. Otherwise | ||
352 | * the FW would not set the PSM bit. | ||
351 | */ | 353 | */ |
352 | else if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) | 354 | else if (wl->active_link_count > 3 && fw_ps && |
355 | tx_pkts >= WL1271_PS_STA_MAX_PACKETS) | ||
353 | wl12xx_ps_link_start(wl, wlvif, hlid, true); | 356 | wl12xx_ps_link_start(wl, wlvif, hlid, true); |
354 | } | 357 | } |
355 | 358 | ||
@@ -414,13 +417,21 @@ static int wlcore_fw_status(struct wl1271 *wl, | |||
414 | 417 | ||
415 | 418 | ||
416 | for_each_set_bit(i, wl->links_map, WL12XX_MAX_LINKS) { | 419 | for_each_set_bit(i, wl->links_map, WL12XX_MAX_LINKS) { |
420 | u8 diff; | ||
417 | lnk = &wl->links[i]; | 421 | lnk = &wl->links[i]; |
422 | |||
418 | /* prevent wrap-around in freed-packets counter */ | 423 | /* prevent wrap-around in freed-packets counter */ |
419 | lnk->allocated_pkts -= | 424 | diff = (status_2->counters.tx_lnk_free_pkts[i] - |
420 | (status_2->counters.tx_lnk_free_pkts[i] - | 425 | lnk->prev_freed_pkts) & 0xff; |
421 | lnk->prev_freed_pkts) & 0xff; | 426 | |
427 | if (diff == 0) | ||
428 | continue; | ||
422 | 429 | ||
430 | lnk->allocated_pkts -= diff; | ||
423 | lnk->prev_freed_pkts = status_2->counters.tx_lnk_free_pkts[i]; | 431 | lnk->prev_freed_pkts = status_2->counters.tx_lnk_free_pkts[i]; |
432 | |||
433 | /* accumulate the prev_freed_pkts counter */ | ||
434 | lnk->total_freed_pkts += diff; | ||
424 | } | 435 | } |
425 | 436 | ||
426 | /* prevent wrap-around in total blocks counter */ | 437 | /* prevent wrap-around in total blocks counter */ |
@@ -640,6 +651,25 @@ static irqreturn_t wlcore_irq(int irq, void *cookie) | |||
640 | unsigned long flags; | 651 | unsigned long flags; |
641 | struct wl1271 *wl = cookie; | 652 | struct wl1271 *wl = cookie; |
642 | 653 | ||
654 | /* complete the ELP completion */ | ||
655 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
656 | set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); | ||
657 | if (wl->elp_compl) { | ||
658 | complete(wl->elp_compl); | ||
659 | wl->elp_compl = NULL; | ||
660 | } | ||
661 | |||
662 | if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) { | ||
663 | /* don't enqueue a work right now. mark it as pending */ | ||
664 | set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags); | ||
665 | wl1271_debug(DEBUG_IRQ, "should not enqueue work"); | ||
666 | disable_irq_nosync(wl->irq); | ||
667 | pm_wakeup_event(wl->dev, 0); | ||
668 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
669 | return IRQ_HANDLED; | ||
670 | } | ||
671 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
672 | |||
643 | /* TX might be handled here, avoid redundant work */ | 673 | /* TX might be handled here, avoid redundant work */ |
644 | set_bit(WL1271_FLAG_TX_PENDING, &wl->flags); | 674 | set_bit(WL1271_FLAG_TX_PENDING, &wl->flags); |
645 | cancel_work_sync(&wl->tx_work); | 675 | cancel_work_sync(&wl->tx_work); |
@@ -919,18 +949,6 @@ static void wl1271_recovery_work(struct work_struct *work) | |||
919 | goto out_unlock; | 949 | goto out_unlock; |
920 | } | 950 | } |
921 | 951 | ||
922 | /* | ||
923 | * Advance security sequence number to overcome potential progress | ||
924 | * in the firmware during recovery. This doens't hurt if the network is | ||
925 | * not encrypted. | ||
926 | */ | ||
927 | wl12xx_for_each_wlvif(wl, wlvif) { | ||
928 | if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || | ||
929 | test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) | ||
930 | wlvif->tx_security_seq += | ||
931 | WL1271_TX_SQN_POST_RECOVERY_PADDING; | ||
932 | } | ||
933 | |||
934 | /* Prevent spurious TX during FW restart */ | 952 | /* Prevent spurious TX during FW restart */ |
935 | wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART); | 953 | wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART); |
936 | 954 | ||
@@ -2523,6 +2541,8 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, | |||
2523 | wl1271_ps_elp_sleep(wl); | 2541 | wl1271_ps_elp_sleep(wl); |
2524 | } | 2542 | } |
2525 | deinit: | 2543 | deinit: |
2544 | wl12xx_tx_reset_wlvif(wl, wlvif); | ||
2545 | |||
2526 | /* clear all hlids (except system_hlid) */ | 2546 | /* clear all hlids (except system_hlid) */ |
2527 | wlvif->dev_hlid = WL12XX_INVALID_LINK_ID; | 2547 | wlvif->dev_hlid = WL12XX_INVALID_LINK_ID; |
2528 | 2548 | ||
@@ -2546,7 +2566,6 @@ deinit: | |||
2546 | 2566 | ||
2547 | dev_kfree_skb(wlvif->probereq); | 2567 | dev_kfree_skb(wlvif->probereq); |
2548 | wlvif->probereq = NULL; | 2568 | wlvif->probereq = NULL; |
2549 | wl12xx_tx_reset_wlvif(wl, wlvif); | ||
2550 | if (wl->last_wlvif == wlvif) | 2569 | if (wl->last_wlvif == wlvif) |
2551 | wl->last_wlvif = NULL; | 2570 | wl->last_wlvif = NULL; |
2552 | list_del(&wlvif->list); | 2571 | list_del(&wlvif->list); |
@@ -2860,10 +2879,6 @@ static int wlcore_unset_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
2860 | wlvif->sta.klv_template_id, | 2879 | wlvif->sta.klv_template_id, |
2861 | ACX_KEEP_ALIVE_TPL_INVALID); | 2880 | ACX_KEEP_ALIVE_TPL_INVALID); |
2862 | 2881 | ||
2863 | /* reset TX security counters on a clean disconnect */ | ||
2864 | wlvif->tx_security_last_seq_lsb = 0; | ||
2865 | wlvif->tx_security_seq = 0; | ||
2866 | |||
2867 | return 0; | 2882 | return 0; |
2868 | } | 2883 | } |
2869 | 2884 | ||
@@ -3262,6 +3277,7 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, | |||
3262 | u32 tx_seq_32 = 0; | 3277 | u32 tx_seq_32 = 0; |
3263 | u16 tx_seq_16 = 0; | 3278 | u16 tx_seq_16 = 0; |
3264 | u8 key_type; | 3279 | u8 key_type; |
3280 | u8 hlid; | ||
3265 | 3281 | ||
3266 | wl1271_debug(DEBUG_MAC80211, "mac80211 set key"); | 3282 | wl1271_debug(DEBUG_MAC80211, "mac80211 set key"); |
3267 | 3283 | ||
@@ -3271,6 +3287,22 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, | |||
3271 | key_conf->keylen, key_conf->flags); | 3287 | key_conf->keylen, key_conf->flags); |
3272 | wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); | 3288 | wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); |
3273 | 3289 | ||
3290 | if (wlvif->bss_type == BSS_TYPE_AP_BSS) | ||
3291 | if (sta) { | ||
3292 | struct wl1271_station *wl_sta = (void *)sta->drv_priv; | ||
3293 | hlid = wl_sta->hlid; | ||
3294 | } else { | ||
3295 | hlid = wlvif->ap.bcast_hlid; | ||
3296 | } | ||
3297 | else | ||
3298 | hlid = wlvif->sta.hlid; | ||
3299 | |||
3300 | if (hlid != WL12XX_INVALID_LINK_ID) { | ||
3301 | u64 tx_seq = wl->links[hlid].total_freed_pkts; | ||
3302 | tx_seq_32 = WL1271_TX_SECURITY_HI32(tx_seq); | ||
3303 | tx_seq_16 = WL1271_TX_SECURITY_LO16(tx_seq); | ||
3304 | } | ||
3305 | |||
3274 | switch (key_conf->cipher) { | 3306 | switch (key_conf->cipher) { |
3275 | case WLAN_CIPHER_SUITE_WEP40: | 3307 | case WLAN_CIPHER_SUITE_WEP40: |
3276 | case WLAN_CIPHER_SUITE_WEP104: | 3308 | case WLAN_CIPHER_SUITE_WEP104: |
@@ -3280,22 +3312,14 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, | |||
3280 | break; | 3312 | break; |
3281 | case WLAN_CIPHER_SUITE_TKIP: | 3313 | case WLAN_CIPHER_SUITE_TKIP: |
3282 | key_type = KEY_TKIP; | 3314 | key_type = KEY_TKIP; |
3283 | |||
3284 | key_conf->hw_key_idx = key_conf->keyidx; | 3315 | key_conf->hw_key_idx = key_conf->keyidx; |
3285 | tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq); | ||
3286 | tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq); | ||
3287 | break; | 3316 | break; |
3288 | case WLAN_CIPHER_SUITE_CCMP: | 3317 | case WLAN_CIPHER_SUITE_CCMP: |
3289 | key_type = KEY_AES; | 3318 | key_type = KEY_AES; |
3290 | |||
3291 | key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; | 3319 | key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; |
3292 | tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq); | ||
3293 | tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq); | ||
3294 | break; | 3320 | break; |
3295 | case WL1271_CIPHER_SUITE_GEM: | 3321 | case WL1271_CIPHER_SUITE_GEM: |
3296 | key_type = KEY_GEM; | 3322 | key_type = KEY_GEM; |
3297 | tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq); | ||
3298 | tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq); | ||
3299 | break; | 3323 | break; |
3300 | default: | 3324 | default: |
3301 | wl1271_error("Unknown key algo 0x%x", key_conf->cipher); | 3325 | wl1271_error("Unknown key algo 0x%x", key_conf->cipher); |
@@ -3358,6 +3382,10 @@ void wlcore_regdomain_config(struct wl1271 *wl) | |||
3358 | return; | 3382 | return; |
3359 | 3383 | ||
3360 | mutex_lock(&wl->mutex); | 3384 | mutex_lock(&wl->mutex); |
3385 | |||
3386 | if (unlikely(wl->state != WLCORE_STATE_ON)) | ||
3387 | goto out; | ||
3388 | |||
3361 | ret = wl1271_ps_elp_wakeup(wl); | 3389 | ret = wl1271_ps_elp_wakeup(wl); |
3362 | if (ret < 0) | 3390 | if (ret < 0) |
3363 | goto out; | 3391 | goto out; |
@@ -4499,6 +4527,9 @@ static int wl1271_allocate_sta(struct wl1271 *wl, | |||
4499 | return -EBUSY; | 4527 | return -EBUSY; |
4500 | } | 4528 | } |
4501 | 4529 | ||
4530 | /* use the previous security seq, if this is a recovery/resume */ | ||
4531 | wl->links[wl_sta->hlid].total_freed_pkts = wl_sta->total_freed_pkts; | ||
4532 | |||
4502 | set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map); | 4533 | set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map); |
4503 | memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN); | 4534 | memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN); |
4504 | wl->active_sta_count++; | 4535 | wl->active_sta_count++; |
@@ -4507,12 +4538,37 @@ static int wl1271_allocate_sta(struct wl1271 *wl, | |||
4507 | 4538 | ||
4508 | void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid) | 4539 | void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid) |
4509 | { | 4540 | { |
4541 | struct wl1271_station *wl_sta; | ||
4542 | struct ieee80211_sta *sta; | ||
4543 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
4544 | |||
4510 | if (!test_bit(hlid, wlvif->ap.sta_hlid_map)) | 4545 | if (!test_bit(hlid, wlvif->ap.sta_hlid_map)) |
4511 | return; | 4546 | return; |
4512 | 4547 | ||
4513 | clear_bit(hlid, wlvif->ap.sta_hlid_map); | 4548 | clear_bit(hlid, wlvif->ap.sta_hlid_map); |
4514 | __clear_bit(hlid, &wl->ap_ps_map); | 4549 | __clear_bit(hlid, &wl->ap_ps_map); |
4515 | __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); | 4550 | __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); |
4551 | |||
4552 | /* | ||
4553 | * save the last used PN in the private part of iee80211_sta, | ||
4554 | * in case of recovery/suspend | ||
4555 | */ | ||
4556 | rcu_read_lock(); | ||
4557 | sta = ieee80211_find_sta(vif, wl->links[hlid].addr); | ||
4558 | if (sta) { | ||
4559 | wl_sta = (void *)sta->drv_priv; | ||
4560 | wl_sta->total_freed_pkts = wl->links[hlid].total_freed_pkts; | ||
4561 | |||
4562 | /* | ||
4563 | * increment the initial seq number on recovery to account for | ||
4564 | * transmitted packets that we haven't yet got in the FW status | ||
4565 | */ | ||
4566 | if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) | ||
4567 | wl_sta->total_freed_pkts += | ||
4568 | WL1271_TX_SQN_POST_RECOVERY_PADDING; | ||
4569 | } | ||
4570 | rcu_read_unlock(); | ||
4571 | |||
4516 | wl12xx_free_link(wl, wlvif, &hlid); | 4572 | wl12xx_free_link(wl, wlvif, &hlid); |
4517 | wl->active_sta_count--; | 4573 | wl->active_sta_count--; |
4518 | 4574 | ||
@@ -4616,13 +4672,11 @@ static int wl12xx_update_sta_state(struct wl1271 *wl, | |||
4616 | enum ieee80211_sta_state new_state) | 4672 | enum ieee80211_sta_state new_state) |
4617 | { | 4673 | { |
4618 | struct wl1271_station *wl_sta; | 4674 | struct wl1271_station *wl_sta; |
4619 | u8 hlid; | ||
4620 | bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS; | 4675 | bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS; |
4621 | bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS; | 4676 | bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS; |
4622 | int ret; | 4677 | int ret; |
4623 | 4678 | ||
4624 | wl_sta = (struct wl1271_station *)sta->drv_priv; | 4679 | wl_sta = (struct wl1271_station *)sta->drv_priv; |
4625 | hlid = wl_sta->hlid; | ||
4626 | 4680 | ||
4627 | /* Add station (AP mode) */ | 4681 | /* Add station (AP mode) */ |
4628 | if (is_ap && | 4682 | if (is_ap && |
@@ -4648,12 +4702,12 @@ static int wl12xx_update_sta_state(struct wl1271 *wl, | |||
4648 | /* Authorize station (AP mode) */ | 4702 | /* Authorize station (AP mode) */ |
4649 | if (is_ap && | 4703 | if (is_ap && |
4650 | new_state == IEEE80211_STA_AUTHORIZED) { | 4704 | new_state == IEEE80211_STA_AUTHORIZED) { |
4651 | ret = wl12xx_cmd_set_peer_state(wl, wlvif, hlid); | 4705 | ret = wl12xx_cmd_set_peer_state(wl, wlvif, wl_sta->hlid); |
4652 | if (ret < 0) | 4706 | if (ret < 0) |
4653 | return ret; | 4707 | return ret; |
4654 | 4708 | ||
4655 | ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, | 4709 | ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, |
4656 | hlid); | 4710 | wl_sta->hlid); |
4657 | if (ret) | 4711 | if (ret) |
4658 | return ret; | 4712 | return ret; |
4659 | 4713 | ||
@@ -4784,7 +4838,7 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, | |||
4784 | break; | 4838 | break; |
4785 | } | 4839 | } |
4786 | 4840 | ||
4787 | if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) { | 4841 | if (wl->ba_rx_session_count >= wl->ba_rx_session_count_max) { |
4788 | ret = -EBUSY; | 4842 | ret = -EBUSY; |
4789 | wl1271_error("exceeded max RX BA sessions"); | 4843 | wl1271_error("exceeded max RX BA sessions"); |
4790 | break; | 4844 | break; |
@@ -4946,7 +5000,7 @@ out: | |||
4946 | mutex_unlock(&wl->mutex); | 5000 | mutex_unlock(&wl->mutex); |
4947 | } | 5001 | } |
4948 | 5002 | ||
4949 | static void wlcore_op_flush(struct ieee80211_hw *hw, bool drop) | 5003 | static void wlcore_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop) |
4950 | { | 5004 | { |
4951 | struct wl1271 *wl = hw->priv; | 5005 | struct wl1271 *wl = hw->priv; |
4952 | 5006 | ||
@@ -5092,6 +5146,39 @@ static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw, | |||
5092 | wlcore_hw_sta_rc_update(wl, wlvif, sta, changed); | 5146 | wlcore_hw_sta_rc_update(wl, wlvif, sta, changed); |
5093 | } | 5147 | } |
5094 | 5148 | ||
5149 | static int wlcore_op_get_rssi(struct ieee80211_hw *hw, | ||
5150 | struct ieee80211_vif *vif, | ||
5151 | struct ieee80211_sta *sta, | ||
5152 | s8 *rssi_dbm) | ||
5153 | { | ||
5154 | struct wl1271 *wl = hw->priv; | ||
5155 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
5156 | int ret = 0; | ||
5157 | |||
5158 | wl1271_debug(DEBUG_MAC80211, "mac80211 get_rssi"); | ||
5159 | |||
5160 | mutex_lock(&wl->mutex); | ||
5161 | |||
5162 | if (unlikely(wl->state != WLCORE_STATE_ON)) | ||
5163 | goto out; | ||
5164 | |||
5165 | ret = wl1271_ps_elp_wakeup(wl); | ||
5166 | if (ret < 0) | ||
5167 | goto out_sleep; | ||
5168 | |||
5169 | ret = wlcore_acx_average_rssi(wl, wlvif, rssi_dbm); | ||
5170 | if (ret < 0) | ||
5171 | goto out_sleep; | ||
5172 | |||
5173 | out_sleep: | ||
5174 | wl1271_ps_elp_sleep(wl); | ||
5175 | |||
5176 | out: | ||
5177 | mutex_unlock(&wl->mutex); | ||
5178 | |||
5179 | return ret; | ||
5180 | } | ||
5181 | |||
5095 | static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) | 5182 | static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) |
5096 | { | 5183 | { |
5097 | struct wl1271 *wl = hw->priv; | 5184 | struct wl1271 *wl = hw->priv; |
@@ -5291,6 +5378,7 @@ static const struct ieee80211_ops wl1271_ops = { | |||
5291 | .assign_vif_chanctx = wlcore_op_assign_vif_chanctx, | 5378 | .assign_vif_chanctx = wlcore_op_assign_vif_chanctx, |
5292 | .unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx, | 5379 | .unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx, |
5293 | .sta_rc_update = wlcore_op_sta_rc_update, | 5380 | .sta_rc_update = wlcore_op_sta_rc_update, |
5381 | .get_rssi = wlcore_op_get_rssi, | ||
5294 | CFG80211_TESTMODE_CMD(wl1271_tm_cmd) | 5382 | CFG80211_TESTMODE_CMD(wl1271_tm_cmd) |
5295 | }; | 5383 | }; |
5296 | 5384 | ||
@@ -5930,35 +6018,6 @@ int wlcore_free_hw(struct wl1271 *wl) | |||
5930 | } | 6018 | } |
5931 | EXPORT_SYMBOL_GPL(wlcore_free_hw); | 6019 | EXPORT_SYMBOL_GPL(wlcore_free_hw); |
5932 | 6020 | ||
5933 | static irqreturn_t wl12xx_hardirq(int irq, void *cookie) | ||
5934 | { | ||
5935 | struct wl1271 *wl = cookie; | ||
5936 | unsigned long flags; | ||
5937 | |||
5938 | wl1271_debug(DEBUG_IRQ, "IRQ"); | ||
5939 | |||
5940 | /* complete the ELP completion */ | ||
5941 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
5942 | set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); | ||
5943 | if (wl->elp_compl) { | ||
5944 | complete(wl->elp_compl); | ||
5945 | wl->elp_compl = NULL; | ||
5946 | } | ||
5947 | |||
5948 | if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) { | ||
5949 | /* don't enqueue a work right now. mark it as pending */ | ||
5950 | set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags); | ||
5951 | wl1271_debug(DEBUG_IRQ, "should not enqueue work"); | ||
5952 | disable_irq_nosync(wl->irq); | ||
5953 | pm_wakeup_event(wl->dev, 0); | ||
5954 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
5955 | return IRQ_HANDLED; | ||
5956 | } | ||
5957 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
5958 | |||
5959 | return IRQ_WAKE_THREAD; | ||
5960 | } | ||
5961 | |||
5962 | static void wlcore_nvs_cb(const struct firmware *fw, void *context) | 6021 | static void wlcore_nvs_cb(const struct firmware *fw, void *context) |
5963 | { | 6022 | { |
5964 | struct wl1271 *wl = context; | 6023 | struct wl1271 *wl = context; |
@@ -6000,9 +6059,8 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context) | |||
6000 | else | 6059 | else |
6001 | irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; | 6060 | irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; |
6002 | 6061 | ||
6003 | ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wlcore_irq, | 6062 | ret = request_threaded_irq(wl->irq, NULL, wlcore_irq, |
6004 | irqflags, | 6063 | irqflags, pdev->name, wl); |
6005 | pdev->name, wl); | ||
6006 | if (ret < 0) { | 6064 | if (ret < 0) { |
6007 | wl1271_error("request_irq() failed: %d", ret); | 6065 | wl1271_error("request_irq() failed: %d", ret); |
6008 | goto out_free_nvs; | 6066 | goto out_free_nvs; |
diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c index 9b7b6e2e4fbc..9654577efd01 100644 --- a/drivers/net/wireless/ti/wlcore/ps.c +++ b/drivers/net/wireless/ti/wlcore/ps.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #define WL1271_WAKEUP_TIMEOUT 500 | 29 | #define WL1271_WAKEUP_TIMEOUT 500 |
30 | 30 | ||
31 | #define ELP_ENTRY_DELAY 30 | 31 | #define ELP_ENTRY_DELAY 30 |
32 | #define ELP_ENTRY_DELAY_FORCE_PS 5 | ||
32 | 33 | ||
33 | void wl1271_elp_work(struct work_struct *work) | 34 | void wl1271_elp_work(struct work_struct *work) |
34 | { | 35 | { |
@@ -98,7 +99,8 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) | |||
98 | return; | 99 | return; |
99 | } | 100 | } |
100 | 101 | ||
101 | timeout = ELP_ENTRY_DELAY; | 102 | timeout = wl->conf.conn.forced_ps ? |
103 | ELP_ENTRY_DELAY_FORCE_PS : ELP_ENTRY_DELAY; | ||
102 | ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, | 104 | ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, |
103 | msecs_to_jiffies(timeout)); | 105 | msecs_to_jiffies(timeout)); |
104 | } | 106 | } |
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c index ece392c54d9c..004d02e71f01 100644 --- a/drivers/net/wireless/ti/wlcore/tx.c +++ b/drivers/net/wireless/ti/wlcore/tx.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/etherdevice.h> | 26 | #include <linux/etherdevice.h> |
27 | #include <linux/spinlock.h> | ||
27 | 28 | ||
28 | #include "wlcore.h" | 29 | #include "wlcore.h" |
29 | #include "debug.h" | 30 | #include "debug.h" |
@@ -104,7 +105,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, | |||
104 | struct wl12xx_vif *wlvif, | 105 | struct wl12xx_vif *wlvif, |
105 | u8 hlid) | 106 | u8 hlid) |
106 | { | 107 | { |
107 | bool fw_ps, single_link; | 108 | bool fw_ps; |
108 | u8 tx_pkts; | 109 | u8 tx_pkts; |
109 | 110 | ||
110 | if (WARN_ON(!test_bit(hlid, wlvif->links_map))) | 111 | if (WARN_ON(!test_bit(hlid, wlvif->links_map))) |
@@ -112,15 +113,19 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, | |||
112 | 113 | ||
113 | fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); | 114 | fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); |
114 | tx_pkts = wl->links[hlid].allocated_pkts; | 115 | tx_pkts = wl->links[hlid].allocated_pkts; |
115 | single_link = (wl->active_link_count == 1); | ||
116 | 116 | ||
117 | /* | 117 | /* |
118 | * if in FW PS and there is enough data in FW we can put the link | 118 | * if in FW PS and there is enough data in FW we can put the link |
119 | * into high-level PS and clean out its TX queues. | 119 | * into high-level PS and clean out its TX queues. |
120 | * Make an exception if this is the only connected link. In this | 120 | * Make an exception if this is the only connected link. In this |
121 | * case FW-memory congestion is less of a problem. | 121 | * case FW-memory congestion is less of a problem. |
122 | * Note that a single connected STA means 3 active links, since we must | ||
123 | * account for the global and broadcast AP links. The "fw_ps" check | ||
124 | * assures us the third link is a STA connected to the AP. Otherwise | ||
125 | * the FW would not set the PSM bit. | ||
122 | */ | 126 | */ |
123 | if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) | 127 | if (wl->active_link_count > 3 && fw_ps && |
128 | tx_pkts >= WL1271_PS_STA_MAX_PACKETS) | ||
124 | wl12xx_ps_link_start(wl, wlvif, hlid, true); | 129 | wl12xx_ps_link_start(wl, wlvif, hlid, true); |
125 | } | 130 | } |
126 | 131 | ||
@@ -639,6 +644,7 @@ next: | |||
639 | 644 | ||
640 | } | 645 | } |
641 | 646 | ||
647 | out: | ||
642 | if (!skb && | 648 | if (!skb && |
643 | test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { | 649 | test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { |
644 | int q; | 650 | int q; |
@@ -652,7 +658,6 @@ next: | |||
652 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 658 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
653 | } | 659 | } |
654 | 660 | ||
655 | out: | ||
656 | return skb; | 661 | return skb; |
657 | } | 662 | } |
658 | 663 | ||
@@ -928,25 +933,6 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, | |||
928 | 933 | ||
929 | wl->stats.retry_count += result->ack_failures; | 934 | wl->stats.retry_count += result->ack_failures; |
930 | 935 | ||
931 | /* | ||
932 | * update sequence number only when relevant, i.e. only in | ||
933 | * sessions of TKIP, AES and GEM (not in open or WEP sessions) | ||
934 | */ | ||
935 | if (info->control.hw_key && | ||
936 | (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP || | ||
937 | info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP || | ||
938 | info->control.hw_key->cipher == WL1271_CIPHER_SUITE_GEM)) { | ||
939 | u8 fw_lsb = result->tx_security_sequence_number_lsb; | ||
940 | u8 cur_lsb = wlvif->tx_security_last_seq_lsb; | ||
941 | |||
942 | /* | ||
943 | * update security sequence number, taking care of potential | ||
944 | * wrap-around | ||
945 | */ | ||
946 | wlvif->tx_security_seq += (fw_lsb - cur_lsb) & 0xff; | ||
947 | wlvif->tx_security_last_seq_lsb = fw_lsb; | ||
948 | } | ||
949 | |||
950 | /* remove private header from packet */ | 936 | /* remove private header from packet */ |
951 | skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); | 937 | skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); |
952 | 938 | ||
@@ -1061,7 +1047,8 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
1061 | 1047 | ||
1062 | /* TX failure */ | 1048 | /* TX failure */ |
1063 | for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) { | 1049 | for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) { |
1064 | if (wlvif->bss_type == BSS_TYPE_AP_BSS) { | 1050 | if (wlvif->bss_type == BSS_TYPE_AP_BSS && |
1051 | i != wlvif->ap.bcast_hlid && i != wlvif->ap.global_hlid) { | ||
1065 | /* this calls wl12xx_free_link */ | 1052 | /* this calls wl12xx_free_link */ |
1066 | wl1271_free_sta(wl, wlvif, i); | 1053 | wl1271_free_sta(wl, wlvif, i); |
1067 | } else { | 1054 | } else { |
@@ -1304,7 +1291,7 @@ bool wlcore_is_queue_stopped_by_reason_locked(struct wl1271 *wl, | |||
1304 | { | 1291 | { |
1305 | int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue); | 1292 | int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue); |
1306 | 1293 | ||
1307 | WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock)); | 1294 | assert_spin_locked(&wl->wl_lock); |
1308 | return test_bit(reason, &wl->queue_stop_reasons[hwq]); | 1295 | return test_bit(reason, &wl->queue_stop_reasons[hwq]); |
1309 | } | 1296 | } |
1310 | 1297 | ||
@@ -1313,6 +1300,6 @@ bool wlcore_is_queue_stopped_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
1313 | { | 1300 | { |
1314 | int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue); | 1301 | int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue); |
1315 | 1302 | ||
1316 | WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock)); | 1303 | assert_spin_locked(&wl->wl_lock); |
1317 | return !!wl->queue_stop_reasons[hwq]; | 1304 | return !!wl->queue_stop_reasons[hwq]; |
1318 | } | 1305 | } |
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index af9fecaefc30..0034979e97cb 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h | |||
@@ -390,6 +390,9 @@ struct wl1271 { | |||
390 | /* number of currently active RX BA sessions */ | 390 | /* number of currently active RX BA sessions */ |
391 | int ba_rx_session_count; | 391 | int ba_rx_session_count; |
392 | 392 | ||
393 | /* Maximum number of supported RX BA sessions */ | ||
394 | int ba_rx_session_count_max; | ||
395 | |||
393 | /* AP-mode - number of currently connected stations */ | 396 | /* AP-mode - number of currently connected stations */ |
394 | int active_sta_count; | 397 | int active_sta_count; |
395 | 398 | ||
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index 508f5b0f8a70..e5e146435fe7 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h | |||
@@ -274,6 +274,13 @@ struct wl1271_link { | |||
274 | 274 | ||
275 | /* The wlvif this link belongs to. Might be null for global links */ | 275 | /* The wlvif this link belongs to. Might be null for global links */ |
276 | struct wl12xx_vif *wlvif; | 276 | struct wl12xx_vif *wlvif; |
277 | |||
278 | /* | ||
279 | * total freed FW packets on the link - used for tracking the | ||
280 | * AES/TKIP PN across recoveries. Re-initialized each time | ||
281 | * from the wl1271_station structure. | ||
282 | */ | ||
283 | u64 total_freed_pkts; | ||
277 | }; | 284 | }; |
278 | 285 | ||
279 | #define WL1271_MAX_RX_FILTERS 5 | 286 | #define WL1271_MAX_RX_FILTERS 5 |
@@ -318,6 +325,13 @@ struct wl12xx_rx_filter { | |||
318 | struct wl1271_station { | 325 | struct wl1271_station { |
319 | u8 hlid; | 326 | u8 hlid; |
320 | bool in_connection; | 327 | bool in_connection; |
328 | |||
329 | /* | ||
330 | * total freed FW packets on the link to the STA - used for tracking the | ||
331 | * AES/TKIP PN across recoveries. Re-initialized each time from the | ||
332 | * wl1271_station structure. | ||
333 | */ | ||
334 | u64 total_freed_pkts; | ||
321 | }; | 335 | }; |
322 | 336 | ||
323 | struct wl12xx_vif { | 337 | struct wl12xx_vif { |
@@ -449,16 +463,15 @@ struct wl12xx_vif { | |||
449 | */ | 463 | */ |
450 | struct { | 464 | struct { |
451 | u8 persistent[0]; | 465 | u8 persistent[0]; |
466 | |||
452 | /* | 467 | /* |
453 | * Security sequence number | 468 | * total freed FW packets on the link - used for |
454 | * bits 0-15: lower 16 bits part of sequence number | 469 | * storing the AES/TKIP PN during recovery, as this |
455 | * bits 16-47: higher 32 bits part of sequence number | 470 | * structure is not zeroed out. |
456 | * bits 48-63: not in use | 471 | * For STA this holds the PN of the link to the AP. |
472 | * For AP this holds the PN of the broadcast link. | ||
457 | */ | 473 | */ |
458 | u64 tx_security_seq; | 474 | u64 total_freed_pkts; |
459 | |||
460 | /* 8 bits of the last sequence number in use */ | ||
461 | u8 tx_security_last_seq_lsb; | ||
462 | }; | 475 | }; |
463 | }; | 476 | }; |
464 | 477 | ||
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 63ff69f9d3eb..a8dc95ebf2d6 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c | |||
@@ -347,6 +347,21 @@ static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in, | |||
347 | return (s8)gain; | 347 | return (s8)gain; |
348 | } | 348 | } |
349 | 349 | ||
350 | static void sprom_extract_r23(struct ssb_sprom *out, const u16 *in) | ||
351 | { | ||
352 | SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0); | ||
353 | SPEX(opo, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0); | ||
354 | SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0); | ||
355 | SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0); | ||
356 | SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0); | ||
357 | SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0); | ||
358 | SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0); | ||
359 | SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0); | ||
360 | SPEX(maxpwr_ah, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0); | ||
361 | SPEX(maxpwr_al, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO, | ||
362 | SSB_SPROM2_MAXP_A_LO_SHIFT); | ||
363 | } | ||
364 | |||
350 | static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) | 365 | static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) |
351 | { | 366 | { |
352 | u16 loc[3]; | 367 | u16 loc[3]; |
@@ -369,6 +384,7 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) | |||
369 | SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14); | 384 | SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14); |
370 | SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15); | 385 | SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15); |
371 | SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0); | 386 | SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0); |
387 | SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0); | ||
372 | if (out->revision == 1) | 388 | if (out->revision == 1) |
373 | SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, | 389 | SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, |
374 | SSB_SPROM1_BINF_CCODE_SHIFT); | 390 | SSB_SPROM1_BINF_CCODE_SHIFT); |
@@ -395,8 +411,7 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) | |||
395 | SSB_SPROM1_ITSSI_A_SHIFT); | 411 | SSB_SPROM1_ITSSI_A_SHIFT); |
396 | SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0); | 412 | SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0); |
397 | SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0); | 413 | SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0); |
398 | if (out->revision >= 2) | 414 | |
399 | SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0); | ||
400 | SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8); | 415 | SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8); |
401 | SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0); | 416 | SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0); |
402 | 417 | ||
@@ -407,6 +422,8 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) | |||
407 | out->antenna_gain.a1 = r123_extract_antgain(out->revision, in, | 422 | out->antenna_gain.a1 = r123_extract_antgain(out->revision, in, |
408 | SSB_SPROM1_AGAIN_A, | 423 | SSB_SPROM1_AGAIN_A, |
409 | SSB_SPROM1_AGAIN_A_SHIFT); | 424 | SSB_SPROM1_AGAIN_A_SHIFT); |
425 | if (out->revision >= 2) | ||
426 | sprom_extract_r23(out, in); | ||
410 | } | 427 | } |
411 | 428 | ||
412 | /* Revs 4 5 and 8 have partially shared layout */ | 429 | /* Revs 4 5 and 8 have partially shared layout */ |
@@ -464,6 +481,7 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) | |||
464 | SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A, | 481 | SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A, |
465 | SSB_SPROM4_ETHPHY_ET1A_SHIFT); | 482 | SSB_SPROM4_ETHPHY_ET1A_SHIFT); |
466 | SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0); | 483 | SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0); |
484 | SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0); | ||
467 | if (out->revision == 4) { | 485 | if (out->revision == 4) { |
468 | SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8); | 486 | SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8); |
469 | SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0); | 487 | SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0); |
@@ -535,6 +553,7 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) | |||
535 | sprom_get_mac(out->il0mac, &in[SPOFF(SSB_SPROM8_IL0MAC)]); | 553 | sprom_get_mac(out->il0mac, &in[SPOFF(SSB_SPROM8_IL0MAC)]); |
536 | 554 | ||
537 | SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0); | 555 | SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0); |
556 | SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0); | ||
538 | SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); | 557 | SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); |
539 | SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0); | 558 | SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0); |
540 | SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0); | 559 | SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0); |