aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2011-04-26 16:21:51 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-04-28 14:50:45 -0400
commit47684808fd89d6809c0886e06f8ac324252499d8 (patch)
treef5edf3dae33bc46a39d8526484bae71f33a19bab /drivers/net/wireless
parenta039a993496d79d09ae9709c82b545b9800954c9 (diff)
wl12xx: support FW TX inactivity triggers
In AP mode we register for the MAX_TX_RETRY and INACTIVE_STA events. Both are reported to the upper layers as a TX failure in the offending stations. In STA mode we register only for the MAX_TX_RETRY event. A TX failure is interpreted as a loss of connection. Support for IEEE80211_HW_REPORTS_TX_ACK_STATUS has been removed to avoid the inherent race condition of a mac80211 TX failure counter in addition to the FW counter. This patch depends on "mac80211: allow low level driver to report packet loss" Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/wl12xx/acx.c34
-rw-r--r--drivers/net/wireless/wl12xx/acx.h12
-rw-r--r--drivers/net/wireless/wl12xx/boot.c6
-rw-r--r--drivers/net/wireless/wl12xx/cmd.c2
-rw-r--r--drivers/net/wireless/wl12xx/conf.h12
-rw-r--r--drivers/net/wireless/wl12xx/event.c47
-rw-r--r--drivers/net/wireless/wl12xx/event.h12
-rw-r--r--drivers/net/wireless/wl12xx/init.c6
-rw-r--r--drivers/net/wireless/wl12xx/main.c10
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h1
10 files changed, 125 insertions, 17 deletions
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index b277947400b5..a5c9c0aff83f 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -1524,22 +1524,46 @@ out:
1524 return ret; 1524 return ret;
1525} 1525}
1526 1526
1527int wl1271_acx_max_tx_retry(struct wl1271 *wl) 1527int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl)
1528{ 1528{
1529 struct wl1271_acx_max_tx_retry *acx = NULL; 1529 struct wl1271_acx_ap_max_tx_retry *acx = NULL;
1530 int ret; 1530 int ret;
1531 1531
1532 wl1271_debug(DEBUG_ACX, "acx max tx retry"); 1532 wl1271_debug(DEBUG_ACX, "acx ap max tx retry");
1533 1533
1534 acx = kzalloc(sizeof(*acx), GFP_KERNEL); 1534 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1535 if (!acx) 1535 if (!acx)
1536 return -ENOMEM; 1536 return -ENOMEM;
1537 1537
1538 acx->max_tx_retry = cpu_to_le16(wl->conf.tx.ap_max_tx_retries); 1538 acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries);
1539 1539
1540 ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx)); 1540 ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx));
1541 if (ret < 0) { 1541 if (ret < 0) {
1542 wl1271_warning("acx max tx retry failed: %d", ret); 1542 wl1271_warning("acx ap max tx retry failed: %d", ret);
1543 goto out;
1544 }
1545
1546out:
1547 kfree(acx);
1548 return ret;
1549}
1550
1551int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl)
1552{
1553 struct wl1271_acx_sta_max_tx_retry *acx = NULL;
1554 int ret;
1555
1556 wl1271_debug(DEBUG_ACX, "acx sta max tx retry");
1557
1558 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1559 if (!acx)
1560 return -ENOMEM;
1561
1562 acx->max_tx_retry = wl->conf.tx.max_tx_retries;
1563
1564 ret = wl1271_cmd_configure(wl, ACX_CONS_TX_FAILURE, acx, sizeof(*acx));
1565 if (ret < 0) {
1566 wl1271_warning("acx sta max tx retry failed: %d", ret);
1543 goto out; 1567 goto out;
1544 } 1568 }
1545 1569
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index 0a40caeab2a2..942908cd53a3 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -1145,7 +1145,7 @@ struct wl1271_acx_fw_tsf_information {
1145 u8 padding[3]; 1145 u8 padding[3];
1146} __packed; 1146} __packed;
1147 1147
1148struct wl1271_acx_max_tx_retry { 1148struct wl1271_acx_ap_max_tx_retry {
1149 struct acx_header header; 1149 struct acx_header header;
1150 1150
1151 /* 1151 /*
@@ -1156,6 +1156,13 @@ struct wl1271_acx_max_tx_retry {
1156 u8 padding_1[2]; 1156 u8 padding_1[2];
1157} __packed; 1157} __packed;
1158 1158
1159struct wl1271_acx_sta_max_tx_retry {
1160 struct acx_header header;
1161
1162 u8 max_tx_retry;
1163 u8 padding_1[3];
1164} __packed;
1165
1159struct wl1271_acx_config_ps { 1166struct wl1271_acx_config_ps {
1160 struct acx_header header; 1167 struct acx_header header;
1161 1168
@@ -1307,7 +1314,8 @@ int wl1271_acx_set_ba_session(struct wl1271 *wl,
1307int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, 1314int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
1308 bool enable); 1315 bool enable);
1309int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); 1316int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
1310int wl1271_acx_max_tx_retry(struct wl1271 *wl); 1317int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl);
1318int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl);
1311int wl1271_acx_config_ps(struct wl1271 *wl); 1319int wl1271_acx_config_ps(struct wl1271 *wl);
1312int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); 1320int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
1313 1321
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c
index 2b0cf85788b3..d263ebb6f974 100644
--- a/drivers/net/wireless/wl12xx/boot.c
+++ b/drivers/net/wireless/wl12xx/boot.c
@@ -478,10 +478,12 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
478 DISCONNECT_EVENT_COMPLETE_ID | 478 DISCONNECT_EVENT_COMPLETE_ID |
479 RSSI_SNR_TRIGGER_0_EVENT_ID | 479 RSSI_SNR_TRIGGER_0_EVENT_ID |
480 PSPOLL_DELIVERY_FAILURE_EVENT_ID | 480 PSPOLL_DELIVERY_FAILURE_EVENT_ID |
481 SOFT_GEMINI_SENSE_EVENT_ID; 481 SOFT_GEMINI_SENSE_EVENT_ID |
482 MAX_TX_RETRY_EVENT_ID;
482 483
483 if (wl->bss_type == BSS_TYPE_AP_BSS) 484 if (wl->bss_type == BSS_TYPE_AP_BSS)
484 wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; 485 wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID |
486 INACTIVE_STA_EVENT_ID;
485 else 487 else
486 wl->event_mask |= DUMMY_PACKET_EVENT_ID; 488 wl->event_mask |= DUMMY_PACKET_EVENT_ID;
487 489
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 246804428517..d48331682e7e 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -1070,7 +1070,7 @@ int wl1271_cmd_start_bss(struct wl1271 *wl)
1070 1070
1071 memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN); 1071 memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN);
1072 1072
1073 cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC); 1073 cmd->aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
1074 cmd->bss_index = WL1271_AP_BSS_INDEX; 1074 cmd->bss_index = WL1271_AP_BSS_INDEX;
1075 cmd->global_hlid = WL1271_AP_GLOBAL_HLID; 1075 cmd->global_hlid = WL1271_AP_GLOBAL_HLID;
1076 cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID; 1076 cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID;
diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index 6c9e3a673e6c..d16094f2604f 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -683,10 +683,18 @@ struct conf_tx_settings {
683 struct conf_tx_rate_class ap_bcst_conf; 683 struct conf_tx_rate_class ap_bcst_conf;
684 684
685 /* 685 /*
686 * AP-mode - allow this number of TX retries to a station before an 686 * Allow this number of TX retries to a connected station/AP before an
687 * event is triggered from FW. 687 * event is triggered from FW.
688 * In AP-mode the hlids of unreachable stations are given in the
689 * "sta_tx_retry_exceeded" member in the event mailbox.
688 */ 690 */
689 u16 ap_max_tx_retries; 691 u8 max_tx_retries;
692
693 /*
694 * AP-mode - after this number of seconds a connected station is
695 * considered inactive.
696 */
697 u16 ap_aging_period;
690 698
691 /* 699 /*
692 * Configuration for TID parameters. 700 * Configuration for TID parameters.
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c
index ae69330e807c..d7be3aec6fc3 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/event.c
@@ -174,6 +174,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
174 u32 vector; 174 u32 vector;
175 bool beacon_loss = false; 175 bool beacon_loss = false;
176 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); 176 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
177 bool disconnect_sta = false;
178 unsigned long sta_bitmap = 0;
177 179
178 wl1271_event_mbox_dump(mbox); 180 wl1271_event_mbox_dump(mbox);
179 181
@@ -235,9 +237,54 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
235 wl1271_tx_dummy_packet(wl); 237 wl1271_tx_dummy_packet(wl);
236 } 238 }
237 239
240 /*
241 * "TX retries exceeded" has a different meaning according to mode.
242 * In AP mode the offending station is disconnected. In STA mode we
243 * report connection loss.
244 */
245 if (vector & MAX_TX_RETRY_EVENT_ID) {
246 wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID");
247 if (is_ap) {
248 sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded);
249 disconnect_sta = true;
250 } else {
251 beacon_loss = true;
252 }
253 }
254
255 if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) {
256 wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID");
257 sta_bitmap |= le16_to_cpu(mbox->sta_aging_status);
258 disconnect_sta = true;
259 }
260
238 if (wl->vif && beacon_loss) 261 if (wl->vif && beacon_loss)
239 ieee80211_connection_loss(wl->vif); 262 ieee80211_connection_loss(wl->vif);
240 263
264 if (is_ap && disconnect_sta) {
265 u32 num_packets = wl->conf.tx.max_tx_retries;
266 struct ieee80211_sta *sta;
267 const u8 *addr;
268 int h;
269
270 for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS);
271 h < AP_MAX_LINKS;
272 h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) {
273 if (!wl1271_is_active_sta(wl, h))
274 continue;
275
276 addr = wl->links[h].addr;
277
278 rcu_read_lock();
279 sta = ieee80211_find_sta(wl->vif, addr);
280 if (sta) {
281 wl1271_debug(DEBUG_EVENT, "remove sta %d", h);
282 ieee80211_report_low_ack(sta, num_packets);
283 }
284 rcu_read_unlock();
285 }
286 }
287
241 return 0; 288 return 0;
242} 289}
243 290
diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h
index b6cf06e565a4..7ae5a0821241 100644
--- a/drivers/net/wireless/wl12xx/event.h
+++ b/drivers/net/wireless/wl12xx/event.h
@@ -58,13 +58,16 @@ enum {
58 CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), 58 CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17),
59 BSS_LOSE_EVENT_ID = BIT(18), 59 BSS_LOSE_EVENT_ID = BIT(18),
60 REGAINED_BSS_EVENT_ID = BIT(19), 60 REGAINED_BSS_EVENT_ID = BIT(19),
61 ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), 61 MAX_TX_RETRY_EVENT_ID = BIT(20),
62 /* STA: dummy paket for dynamic mem blocks */ 62 /* STA: dummy paket for dynamic mem blocks */
63 DUMMY_PACKET_EVENT_ID = BIT(21), 63 DUMMY_PACKET_EVENT_ID = BIT(21),
64 /* AP: STA remove complete */ 64 /* AP: STA remove complete */
65 STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), 65 STA_REMOVE_COMPLETE_EVENT_ID = BIT(21),
66 SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), 66 SOFT_GEMINI_SENSE_EVENT_ID = BIT(22),
67 /* STA: SG prediction */
67 SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), 68 SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23),
69 /* AP: Inactive STA */
70 INACTIVE_STA_EVENT_ID = BIT(23),
68 SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), 71 SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24),
69 PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), 72 PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25),
70 DBG_EVENT_ID = BIT(26), 73 DBG_EVENT_ID = BIT(26),
@@ -119,7 +122,11 @@ struct event_mailbox {
119 122
120 /* AP FW only */ 123 /* AP FW only */
121 u8 hlid_removed; 124 u8 hlid_removed;
125
126 /* a bitmap of hlids for stations that have been inactive too long */
122 __le16 sta_aging_status; 127 __le16 sta_aging_status;
128
129 /* a bitmap of hlids for stations which didn't respond to TX */
123 __le16 sta_tx_retry_exceeded; 130 __le16 sta_tx_retry_exceeded;
124 131
125 u8 reserved_5[24]; 132 u8 reserved_5[24];
@@ -130,4 +137,7 @@ void wl1271_event_mbox_config(struct wl1271 *wl);
130int wl1271_event_handle(struct wl1271 *wl, u8 mbox); 137int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
131void wl1271_pspoll_work(struct work_struct *work); 138void wl1271_pspoll_work(struct work_struct *work);
132 139
140/* Functions from main.c */
141bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid);
142
133#endif 143#endif
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index cf466074237d..ab3b1e21de29 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -375,6 +375,10 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
375 if (ret < 0) 375 if (ret < 0)
376 return ret; 376 return ret;
377 377
378 ret = wl1271_acx_sta_max_tx_retry(wl);
379 if (ret < 0)
380 return ret;
381
378 ret = wl1271_acx_sta_mem_cfg(wl); 382 ret = wl1271_acx_sta_mem_cfg(wl);
379 if (ret < 0) 383 if (ret < 0)
380 return ret; 384 return ret;
@@ -441,7 +445,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
441 if (ret < 0) 445 if (ret < 0)
442 return ret; 446 return ret;
443 447
444 ret = wl1271_acx_max_tx_retry(wl); 448 ret = wl1271_acx_ap_max_tx_retry(wl);
445 if (ret < 0) 449 if (ret < 0)
446 return ret; 450 return ret;
447 451
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 866453bc1d1f..0c69e959d0de 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -192,7 +192,8 @@ static struct conf_drv_settings default_conf = {
192 .long_retry_limit = 10, 192 .long_retry_limit = 10,
193 .aflags = 0, 193 .aflags = 0,
194 }, 194 },
195 .ap_max_tx_retries = 100, 195 .max_tx_retries = 100,
196 .ap_aging_period = 300,
196 .tid_conf_count = 4, 197 .tid_conf_count = 4,
197 .tid_conf = { 198 .tid_conf = {
198 [CONF_TX_AC_BE] = { 199 [CONF_TX_AC_BE] = {
@@ -2953,6 +2954,12 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
2953 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); 2954 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
2954} 2955}
2955 2956
2957bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
2958{
2959 int id = hlid - WL1271_AP_STA_HLID_START;
2960 return test_bit(id, wl->ap_hlid_map);
2961}
2962
2956static int wl1271_op_sta_add(struct ieee80211_hw *hw, 2963static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2957 struct ieee80211_vif *vif, 2964 struct ieee80211_vif *vif,
2958 struct ieee80211_sta *sta) 2965 struct ieee80211_sta *sta)
@@ -3535,7 +3542,6 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
3535 IEEE80211_HW_HAS_RATE_CONTROL | 3542 IEEE80211_HW_HAS_RATE_CONTROL |
3536 IEEE80211_HW_CONNECTION_MONITOR | 3543 IEEE80211_HW_CONNECTION_MONITOR |
3537 IEEE80211_HW_SUPPORTS_CQM_RSSI | 3544 IEEE80211_HW_SUPPORTS_CQM_RSSI |
3538 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
3539 IEEE80211_HW_AP_LINK_PS; 3545 IEEE80211_HW_AP_LINK_PS;
3540 3546
3541 wl->hw->wiphy->cipher_suites = cipher_suites; 3547 wl->hw->wiphy->cipher_suites = cipher_suites;
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index fb2b79fa42b4..7c521af58e7d 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -172,7 +172,6 @@ extern u32 wl12xx_debug_level;
172#define WL1271_PS_STA_MAX_BLOCKS (2 * 9) 172#define WL1271_PS_STA_MAX_BLOCKS (2 * 9)
173 173
174#define WL1271_AP_BSS_INDEX 0 174#define WL1271_AP_BSS_INDEX 0
175#define WL1271_AP_DEF_INACTIV_SEC 300
176#define WL1271_AP_DEF_BEACON_EXP 20 175#define WL1271_AP_DEF_BEACON_EXP 20
177 176
178#define ACX_TX_DESCRIPTORS 32 177#define ACX_TX_DESCRIPTORS 32