aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl1251
diff options
context:
space:
mode:
authorDavid Gnedt <david.gnedt@davizone.at>2011-01-30 14:11:00 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-02-03 16:44:42 -0500
commit8964e492b5740dae0f4f68e08f4a9a45d4b57620 (patch)
tree8e7d58b7bf211b76469ffd7907d15df214d867ee /drivers/net/wireless/wl1251
parentc3e334d29484423e78009790a3d3fa78da8b43a1 (diff)
wl1251: implement connection quality monitoring
Implement connection quality monitoring similar to the wl1271 driver. It triggers ieee80211_cqm_rssi_notify with the corresponding event when RSSI drops blow RSSI threshold or rises again above the RSSI threshold. It should be noted that wl1251 doesn't support RSSI hysteresis, instead it uses RSSI averageing and delays events until a certain count of frames proved RSSI change. Signed-off-by: David Gnedt <david.gnedt@davizone.at> Acked-by: Kalle Valo <kvalo@adurom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/wl1251')
-rw-r--r--drivers/net/wireless/wl1251/acx.c25
-rw-r--r--drivers/net/wireless/wl1251/acx.h45
-rw-r--r--drivers/net/wireless/wl1251/event.c18
-rw-r--r--drivers/net/wireless/wl1251/main.c15
-rw-r--r--drivers/net/wireless/wl1251/wl1251.h5
5 files changed, 107 insertions, 1 deletions
diff --git a/drivers/net/wireless/wl1251/acx.c b/drivers/net/wireless/wl1251/acx.c
index 8c943661f2d..ef8370edace 100644
--- a/drivers/net/wireless/wl1251/acx.c
+++ b/drivers/net/wireless/wl1251/acx.c
@@ -776,6 +776,31 @@ out:
776 return ret; 776 return ret;
777} 777}
778 778
779int wl1251_acx_low_rssi(struct wl1251 *wl, s8 threshold, u8 weight,
780 u8 depth, enum wl1251_acx_low_rssi_type type)
781{
782 struct acx_low_rssi *rssi;
783 int ret;
784
785 wl1251_debug(DEBUG_ACX, "acx low rssi");
786
787 rssi = kzalloc(sizeof(*rssi), GFP_KERNEL);
788 if (!rssi)
789 return -ENOMEM;
790
791 rssi->threshold = threshold;
792 rssi->weight = weight;
793 rssi->depth = depth;
794 rssi->type = type;
795
796 ret = wl1251_cmd_configure(wl, ACX_LOW_RSSI, rssi, sizeof(*rssi));
797 if (ret < 0)
798 wl1251_warning("failed to set low rssi threshold: %d", ret);
799
800 kfree(rssi);
801 return ret;
802}
803
779int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble) 804int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble)
780{ 805{
781 struct acx_preamble *acx; 806 struct acx_preamble *acx;
diff --git a/drivers/net/wireless/wl1251/acx.h b/drivers/net/wireless/wl1251/acx.h
index 6a19f38958f..c2ba100f9b1 100644
--- a/drivers/net/wireless/wl1251/acx.h
+++ b/drivers/net/wireless/wl1251/acx.h
@@ -399,6 +399,49 @@ struct acx_rts_threshold {
399 u8 pad[2]; 399 u8 pad[2];
400} __packed; 400} __packed;
401 401
402enum wl1251_acx_low_rssi_type {
403 /*
404 * The event is a "Level" indication which keeps triggering
405 * as long as the average RSSI is below the threshold.
406 */
407 WL1251_ACX_LOW_RSSI_TYPE_LEVEL = 0,
408
409 /*
410 * The event is an "Edge" indication which triggers
411 * only when the RSSI threshold is crossed from above.
412 */
413 WL1251_ACX_LOW_RSSI_TYPE_EDGE = 1,
414};
415
416struct acx_low_rssi {
417 struct acx_header header;
418
419 /*
420 * The threshold (in dBm) below (or above after low rssi
421 * indication) which the firmware generates an interrupt to the
422 * host. This parameter is signed.
423 */
424 s8 threshold;
425
426 /*
427 * The weight of the current RSSI sample, before adding the new
428 * sample, that is used to calculate the average RSSI.
429 */
430 u8 weight;
431
432 /*
433 * The number of Beacons/Probe response frames that will be
434 * received before issuing the Low or Regained RSSI event.
435 */
436 u8 depth;
437
438 /*
439 * Configures how the Low RSSI Event is triggered. Refer to
440 * enum wl1251_acx_low_rssi_type for more.
441 */
442 u8 type;
443} __packed;
444
402struct acx_beacon_filter_option { 445struct acx_beacon_filter_option {
403 struct acx_header header; 446 struct acx_header header;
404 447
@@ -1418,6 +1461,8 @@ int wl1251_acx_cca_threshold(struct wl1251 *wl);
1418int wl1251_acx_bcn_dtim_options(struct wl1251 *wl); 1461int wl1251_acx_bcn_dtim_options(struct wl1251 *wl);
1419int wl1251_acx_aid(struct wl1251 *wl, u16 aid); 1462int wl1251_acx_aid(struct wl1251 *wl, u16 aid);
1420int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask); 1463int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask);
1464int wl1251_acx_low_rssi(struct wl1251 *wl, s8 threshold, u8 weight,
1465 u8 depth, enum wl1251_acx_low_rssi_type type);
1421int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble); 1466int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble);
1422int wl1251_acx_cts_protect(struct wl1251 *wl, 1467int wl1251_acx_cts_protect(struct wl1251 *wl,
1423 enum acx_ctsprotect_type ctsprotect); 1468 enum acx_ctsprotect_type ctsprotect);
diff --git a/drivers/net/wireless/wl1251/event.c b/drivers/net/wireless/wl1251/event.c
index 712372e50a8..dfc4579acb0 100644
--- a/drivers/net/wireless/wl1251/event.c
+++ b/drivers/net/wireless/wl1251/event.c
@@ -90,6 +90,24 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
90 } 90 }
91 } 91 }
92 92
93 if (wl->vif && wl->rssi_thold) {
94 if (vector & ROAMING_TRIGGER_LOW_RSSI_EVENT_ID) {
95 wl1251_debug(DEBUG_EVENT,
96 "ROAMING_TRIGGER_LOW_RSSI_EVENT");
97 ieee80211_cqm_rssi_notify(wl->vif,
98 NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
99 GFP_KERNEL);
100 }
101
102 if (vector & ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID) {
103 wl1251_debug(DEBUG_EVENT,
104 "ROAMING_TRIGGER_REGAINED_RSSI_EVENT");
105 ieee80211_cqm_rssi_notify(wl->vif,
106 NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
107 GFP_KERNEL);
108 }
109 }
110
93 return 0; 111 return 0;
94} 112}
95 113
diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c
index 012e1a4016f..0325643b707 100644
--- a/drivers/net/wireless/wl1251/main.c
+++ b/drivers/net/wireless/wl1251/main.c
@@ -502,6 +502,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
502 wl->psm = 0; 502 wl->psm = 0;
503 wl->tx_queue_stopped = false; 503 wl->tx_queue_stopped = false;
504 wl->power_level = WL1251_DEFAULT_POWER_LEVEL; 504 wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
505 wl->rssi_thold = 0;
505 wl->channel = WL1251_DEFAULT_CHANNEL; 506 wl->channel = WL1251_DEFAULT_CHANNEL;
506 507
507 wl1251_debugfs_reset(wl); 508 wl1251_debugfs_reset(wl);
@@ -959,6 +960,16 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
959 if (ret < 0) 960 if (ret < 0)
960 goto out; 961 goto out;
961 962
963 if (changed & BSS_CHANGED_CQM) {
964 ret = wl1251_acx_low_rssi(wl, bss_conf->cqm_rssi_thold,
965 WL1251_DEFAULT_LOW_RSSI_WEIGHT,
966 WL1251_DEFAULT_LOW_RSSI_DEPTH,
967 WL1251_ACX_LOW_RSSI_TYPE_EDGE);
968 if (ret < 0)
969 goto out;
970 wl->rssi_thold = bss_conf->cqm_rssi_thold;
971 }
972
962 if (changed & BSS_CHANGED_BSSID) { 973 if (changed & BSS_CHANGED_BSSID) {
963 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); 974 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
964 975
@@ -1310,7 +1321,8 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
1310 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | 1321 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
1311 IEEE80211_HW_SUPPORTS_PS | 1322 IEEE80211_HW_SUPPORTS_PS |
1312 IEEE80211_HW_BEACON_FILTER | 1323 IEEE80211_HW_BEACON_FILTER |
1313 IEEE80211_HW_SUPPORTS_UAPSD; 1324 IEEE80211_HW_SUPPORTS_UAPSD |
1325 IEEE80211_HW_SUPPORTS_CQM_RSSI;
1314 1326
1315 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); 1327 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
1316 wl->hw->wiphy->max_scan_ssids = 1; 1328 wl->hw->wiphy->max_scan_ssids = 1;
@@ -1374,6 +1386,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
1374 wl->psm_requested = false; 1386 wl->psm_requested = false;
1375 wl->tx_queue_stopped = false; 1387 wl->tx_queue_stopped = false;
1376 wl->power_level = WL1251_DEFAULT_POWER_LEVEL; 1388 wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
1389 wl->rssi_thold = 0;
1377 wl->beacon_int = WL1251_DEFAULT_BEACON_INT; 1390 wl->beacon_int = WL1251_DEFAULT_BEACON_INT;
1378 wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; 1391 wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD;
1379 wl->vif = NULL; 1392 wl->vif = NULL;
diff --git a/drivers/net/wireless/wl1251/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h
index 462ac5b2058..bb23cd522b2 100644
--- a/drivers/net/wireless/wl1251/wl1251.h
+++ b/drivers/net/wireless/wl1251/wl1251.h
@@ -370,6 +370,8 @@ struct wl1251 {
370 /* in dBm */ 370 /* in dBm */
371 int power_level; 371 int power_level;
372 372
373 int rssi_thold;
374
373 struct wl1251_stats stats; 375 struct wl1251_stats stats;
374 struct wl1251_debugfs debugfs; 376 struct wl1251_debugfs debugfs;
375 377
@@ -433,4 +435,7 @@ void wl1251_disable_interrupts(struct wl1251 *wl);
433#define WL1251_PART_WORK_REG_START REGISTERS_BASE 435#define WL1251_PART_WORK_REG_START REGISTERS_BASE
434#define WL1251_PART_WORK_REG_SIZE REGISTERS_WORK_SIZE 436#define WL1251_PART_WORK_REG_SIZE REGISTERS_WORK_SIZE
435 437
438#define WL1251_DEFAULT_LOW_RSSI_WEIGHT 10
439#define WL1251_DEFAULT_LOW_RSSI_DEPTH 10
440
436#endif 441#endif