diff options
-rw-r--r-- | drivers/net/wireless/wl1251/acx.c | 25 | ||||
-rw-r--r-- | drivers/net/wireless/wl1251/acx.h | 45 | ||||
-rw-r--r-- | drivers/net/wireless/wl1251/event.c | 18 | ||||
-rw-r--r-- | drivers/net/wireless/wl1251/main.c | 15 | ||||
-rw-r--r-- | drivers/net/wireless/wl1251/wl1251.h | 5 |
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 | ||
779 | int 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 | |||
779 | int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble) | 804 | int 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 | ||
402 | enum 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 | |||
416 | struct 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 | |||
402 | struct acx_beacon_filter_option { | 445 | struct 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); | |||
1418 | int wl1251_acx_bcn_dtim_options(struct wl1251 *wl); | 1461 | int wl1251_acx_bcn_dtim_options(struct wl1251 *wl); |
1419 | int wl1251_acx_aid(struct wl1251 *wl, u16 aid); | 1462 | int wl1251_acx_aid(struct wl1251 *wl, u16 aid); |
1420 | int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask); | 1463 | int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask); |
1464 | int wl1251_acx_low_rssi(struct wl1251 *wl, s8 threshold, u8 weight, | ||
1465 | u8 depth, enum wl1251_acx_low_rssi_type type); | ||
1421 | int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble); | 1466 | int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble); |
1422 | int wl1251_acx_cts_protect(struct wl1251 *wl, | 1467 | int 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 |