diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-04-22 09:31:43 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-04-22 09:31:43 -0400 |
commit | a42c74ee608a424342ef7069ccddf196d873040c (patch) | |
tree | 75adfb9f5e06ebb7c7d5d5e5a5408fa0d6d504b9 /drivers/net/wireless/ti | |
parent | 97990a060e6757f48b931a3946b17c1c4362c3fb (diff) | |
parent | 9b383672452bb1097124c76fcb4903e0021f6baf (diff) |
Merge remote-tracking branch 'wireless-next/master' into mac80211-next
Diffstat (limited to 'drivers/net/wireless/ti')
-rw-r--r-- | drivers/net/wireless/ti/wl1251/sdio.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wl12xx/main.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wl12xx/wl12xx.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wl18xx/main.c | 25 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wl18xx/reg.h | 29 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wl18xx/wl18xx.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/acx.c | 29 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/acx.h | 16 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/cmd.c | 32 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/debug.h | 33 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/debugfs.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/event.c | 9 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/main.c | 198 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/ps.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/tx.c | 39 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/wlcore.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/wlcore_i.h | 29 |
17 files changed, 330 insertions, 130 deletions
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 c26cb095010c..953111a502ee 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; |
@@ -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 | ||