From 5ea74a6dc1505557d7bcef7b833275ccd8845dd6 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 12 Apr 2010 15:20:53 -0400 Subject: [PATCH] --- yaml --- r: 194258 b: refs/heads/master c: b1f90866fb3a329b1c4ebfff93ae9c110943e50a h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/drivers/net/wireless/iwlwifi/iwl-4965.c | 13 ++- trunk/drivers/net/wireless/wl12xx/wl1271.h | 4 + .../drivers/net/wireless/wl12xx/wl1271_acx.c | 71 ++++++++++++ .../drivers/net/wireless/wl12xx/wl1271_acx.h | 56 +++++++++- .../drivers/net/wireless/wl12xx/wl1271_boot.c | 3 +- .../drivers/net/wireless/wl12xx/wl1271_conf.h | 103 +++++++----------- .../net/wireless/wl12xx/wl1271_event.c | 24 ++++ .../net/wireless/wl12xx/wl1271_event.h | 8 ++ .../drivers/net/wireless/wl12xx/wl1271_init.c | 5 + .../drivers/net/wireless/wl12xx/wl1271_main.c | 84 ++++++++------ trunk/drivers/net/wireless/wl12xx/wl1271_ps.c | 6 +- trunk/net/mac80211/debugfs_sta.c | 2 +- trunk/net/mac80211/rx.c | 16 +-- trunk/net/mac80211/work.c | 7 +- 15 files changed, 285 insertions(+), 119 deletions(-) diff --git a/[refs] b/[refs] index 9a1bb9c16b8f..a209d6b7b2da 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 470058e0ad82fcfaaffd57307d8bf8c094e8e9d7 +refs/heads/master: b1f90866fb3a329b1c4ebfff93ae9c110943e50a diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-4965.c b/trunk/drivers/net/wireless/iwlwifi/iwl-4965.c index c710b26a1c86..2e3cda75f3ad 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2014,7 +2014,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim scd_ssn " "%d index %d\n", scd_ssn , index); freed = iwlagn_tx_queue_reclaim(priv, txq_id, index); - iwl_free_tfds_in_queue(priv, sta_id, tid, freed); + if (qc) + iwl_free_tfds_in_queue(priv, sta_id, + tid, freed); if (priv->mac80211_registered && (iwl_queue_space(&txq->q) > txq->q.low_mark) && @@ -2040,14 +2042,17 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, tx_resp->failure_frame); freed = iwlagn_tx_queue_reclaim(priv, txq_id, index); - iwl_free_tfds_in_queue(priv, sta_id, tid, freed); + if (qc && likely(sta_id != IWL_INVALID_STATION)) + iwl_free_tfds_in_queue(priv, sta_id, tid, freed); + else if (sta_id == IWL_INVALID_STATION) + IWL_DEBUG_TX_REPLY(priv, "Station not known\n"); if (priv->mac80211_registered && (iwl_queue_space(&txq->q) > txq->q.low_mark)) iwl_wake_queue(priv, txq_id); } - - iwlagn_txq_check_empty(priv, sta_id, tid, txq_id); + if (qc && likely(sta_id != IWL_INVALID_STATION)) + iwlagn_txq_check_empty(priv, sta_id, tid, txq_id); iwl_check_abort_status(priv, tx_resp->frame_count, status); } diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271.h b/trunk/drivers/net/wireless/wl12xx/wl1271.h index a29969efc861..75887e74205b 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1271.h @@ -374,6 +374,7 @@ struct wl1271 { #define WL1271_FLAG_PSM_REQUESTED (8) #define WL1271_FLAG_IRQ_PENDING (9) #define WL1271_FLAG_IRQ_RUNNING (10) +#define WL1271_FLAG_IDLE (11) unsigned long flags; struct wl1271_partition_set part; @@ -472,6 +473,9 @@ struct wl1271 { /* in dBm */ int power_level; + int rssi_thold; + int last_rssi_event; + struct wl1271_stats stats; struct wl1271_debugfs debugfs; diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_acx.c b/trunk/drivers/net/wireless/wl12xx/wl1271_acx.c index 621c94691e7e..1a6b2ec1db58 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -1165,6 +1165,7 @@ int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable) kfree(acx); return ret; } + int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid) { struct wl1271_acx_keep_alive_config *acx = NULL; @@ -1194,3 +1195,73 @@ int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid) kfree(acx); return ret; } + +int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable, + s16 thold, u8 hyst) +{ + struct wl1271_acx_rssi_snr_trigger *acx = NULL; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx rssi snr trigger"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + wl->last_rssi_event = -1; + + acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing); + acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON; + acx->type = WL1271_ACX_TRIG_TYPE_EDGE; + if (enable) + acx->enable = WL1271_ACX_TRIG_ENABLE; + else + acx->enable = WL1271_ACX_TRIG_DISABLE; + + acx->index = WL1271_ACX_TRIG_IDX_RSSI; + acx->dir = WL1271_ACX_TRIG_DIR_BIDIR; + acx->threshold = cpu_to_le16(thold); + acx->hysteresis = hyst; + + ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_TRIGGER, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx rssi snr trigger setting failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl) +{ + struct wl1271_acx_rssi_snr_avg_weights *acx = NULL; + struct conf_roam_trigger_settings *c = &wl->conf.roam_trigger; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx rssi snr avg weights"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->rssi_beacon = c->avg_weight_rssi_beacon; + acx->rssi_data = c->avg_weight_rssi_data; + acx->snr_beacon = c->avg_weight_snr_beacon; + acx->snr_data = c->avg_weight_snr_data; + + ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_WEIGHTS, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx rssi snr trigger weights failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_acx.h b/trunk/drivers/net/wireless/wl12xx/wl1271_acx.h index 15cc56192de9..420e7e2fc021 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -942,6 +942,57 @@ struct wl1271_acx_keep_alive_config { u8 padding; } __attribute__ ((packed)); +enum { + WL1271_ACX_TRIG_TYPE_LEVEL = 0, + WL1271_ACX_TRIG_TYPE_EDGE, +}; + +enum { + WL1271_ACX_TRIG_DIR_LOW = 0, + WL1271_ACX_TRIG_DIR_HIGH, + WL1271_ACX_TRIG_DIR_BIDIR, +}; + +enum { + WL1271_ACX_TRIG_ENABLE = 1, + WL1271_ACX_TRIG_DISABLE, +}; + +enum { + WL1271_ACX_TRIG_METRIC_RSSI_BEACON = 0, + WL1271_ACX_TRIG_METRIC_RSSI_DATA, + WL1271_ACX_TRIG_METRIC_SNR_BEACON, + WL1271_ACX_TRIG_METRIC_SNR_DATA, +}; + +enum { + WL1271_ACX_TRIG_IDX_RSSI = 0, + WL1271_ACX_TRIG_COUNT = 8, +}; + +struct wl1271_acx_rssi_snr_trigger { + struct acx_header header; + + __le16 threshold; + __le16 pacing; /* 0 - 60000 ms */ + u8 metric; + u8 type; + u8 dir; + u8 hysteresis; + u8 index; + u8 enable; + u8 padding[2]; +}; + +struct wl1271_acx_rssi_snr_avg_weights { + struct acx_header header; + + u8 rssi_beacon; + u8 rssi_data; + u8 snr_beacon; + u8 snr_data; +}; + enum { ACX_WAKE_UP_CONDITIONS = 0x0002, ACX_MEM_CFG = 0x0003, @@ -990,7 +1041,7 @@ enum { ACX_FRAG_CFG = 0x004F, ACX_BET_ENABLE = 0x0050, ACX_RSSI_SNR_TRIGGER = 0x0051, - ACX_RSSI_SNR_WEIGHTS = 0x0051, + ACX_RSSI_SNR_WEIGHTS = 0x0052, ACX_KEEP_ALIVE_MODE = 0x0053, ACX_SET_KEEP_ALIVE_CONFIG = 0x0054, ACX_BA_SESSION_RESPONDER_POLICY = 0x0055, @@ -1060,5 +1111,8 @@ int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address, int wl1271_acx_pm_config(struct wl1271 *wl); int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable); int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid); +int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable, + s16 thold, u8 hyst); +int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl); #endif /* __WL1271_ACX_H__ */ diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_boot.c b/trunk/drivers/net/wireless/wl12xx/wl1271_boot.c index 7acef88df1fe..f16d15bd5643 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -412,7 +412,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) SCAN_COMPLETE_EVENT_ID | PS_REPORT_EVENT_ID | JOIN_EVENT_COMPLETE_ID | - DISCONNECT_EVENT_COMPLETE_ID; + DISCONNECT_EVENT_COMPLETE_ID | + RSSI_SNR_TRIGGER_0_EVENT_ID; ret = wl1271_event_unmask(wl); if (ret < 0) { diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_conf.h b/trunk/drivers/net/wireless/wl12xx/wl1271_conf.h index d76ae03762a3..c44307c4bcf8 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -756,65 +756,6 @@ enum { CONF_TRIG_EVENT_DIR_BIDIR }; - -struct conf_sig_trigger { - /* - * The RSSI / SNR threshold value. - * - * FIXME: what is the range? - */ - s16 threshold; - - /* - * Minimum delay between two trigger events for this trigger in ms. - * - * Range: 0 - 60000 - */ - u16 pacing; - - /* - * The measurement data source for this trigger. - * - * Range: CONF_TRIG_METRIC_* - */ - u8 metric; - - /* - * The trigger type of this trigger. - * - * Range: CONF_TRIG_EVENT_TYPE_* - */ - u8 type; - - /* - * The direction of the trigger. - * - * Range: CONF_TRIG_EVENT_DIR_* - */ - u8 direction; - - /* - * Hysteresis range of the trigger around the threshold (in dB) - * - * Range: u8 - */ - u8 hysteresis; - - /* - * Index of the trigger rule. - * - * Range: 0 - CONF_MAX_RSSI_SNR_TRIGGERS-1 - */ - u8 index; - - /* - * Enable / disable this rule (to use for clearing rules.) - * - * Range: 1 - Enabled, 2 - Not enabled - */ - u8 enable; -}; - struct conf_sig_weights { /* @@ -932,12 +873,6 @@ struct conf_conn_settings { */ u8 ps_poll_threshold; - /* - * Configuration of signal (rssi/snr) triggers. - */ - u8 sig_trigger_count; - struct conf_sig_trigger sig_trigger[CONF_MAX_RSSI_SNR_TRIGGERS]; - /* * Configuration of signal average weights. */ @@ -1045,6 +980,43 @@ struct conf_pm_config_settings { bool host_fast_wakeup_support; }; +struct conf_roam_trigger_settings { + /* + * The minimum interval between two trigger events. + * + * Range: 0 - 60000 ms + */ + u16 trigger_pacing; + + /* + * The weight for rssi/beacon average calculation + * + * Range: 0 - 255 + */ + u8 avg_weight_rssi_beacon; + + /* + * The weight for rssi/data frame average calculation + * + * Range: 0 - 255 + */ + u8 avg_weight_rssi_data; + + /* + * The weight for snr/beacon average calculation + * + * Range: 0 - 255 + */ + u8 avg_weight_snr_beacon; + + /* + * The weight for snr/data frame average calculation + * + * Range: 0 - 255 + */ + u8 avg_weight_snr_data; +}; + struct conf_drv_settings { struct conf_sg_settings sg; struct conf_rx_settings rx; @@ -1053,6 +1025,7 @@ struct conf_drv_settings { struct conf_init_settings init; struct conf_itrim_settings itrim; struct conf_pm_config_settings pm_config; + struct conf_roam_trigger_settings roam_trigger; }; #endif diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_event.c b/trunk/drivers/net/wireless/wl12xx/wl1271_event.c index daacf176cf09..cf37aa6eb137 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_event.c @@ -125,6 +125,24 @@ static int wl1271_event_ps_report(struct wl1271 *wl, return ret; } +static void wl1271_event_rssi_trigger(struct wl1271 *wl, + struct event_mailbox *mbox) +{ + enum nl80211_cqm_rssi_threshold_event event; + s8 metric = mbox->rssi_snr_trigger_metric[0]; + + wl1271_debug(DEBUG_EVENT, "RSSI trigger metric: %d", metric); + + if (metric <= wl->rssi_thold) + event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; + else + event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; + + if (event != wl->last_rssi_event) + ieee80211_cqm_rssi_notify(wl->vif, event, GFP_KERNEL); + wl->last_rssi_event = event; +} + static void wl1271_event_mbox_dump(struct event_mailbox *mbox) { wl1271_debug(DEBUG_EVENT, "MBOX DUMP:"); @@ -173,6 +191,12 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) return ret; } + if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT"); + if (wl->vif) + wl1271_event_rssi_trigger(wl, mbox); + } + if (wl->vif && beacon_loss) ieee80211_connection_loss(wl->vif); diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_event.h b/trunk/drivers/net/wireless/wl12xx/wl1271_event.h index 278f9206aa56..58371008f270 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_event.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_event.h @@ -38,6 +38,14 @@ */ enum { + RSSI_SNR_TRIGGER_0_EVENT_ID = BIT(0), + RSSI_SNR_TRIGGER_1_EVENT_ID = BIT(1), + RSSI_SNR_TRIGGER_2_EVENT_ID = BIT(2), + RSSI_SNR_TRIGGER_3_EVENT_ID = BIT(3), + RSSI_SNR_TRIGGER_4_EVENT_ID = BIT(4), + RSSI_SNR_TRIGGER_5_EVENT_ID = BIT(5), + RSSI_SNR_TRIGGER_6_EVENT_ID = BIT(6), + RSSI_SNR_TRIGGER_7_EVENT_ID = BIT(7), MEASUREMENT_START_EVENT_ID = BIT(8), MEASUREMENT_COMPLETE_EVENT_ID = BIT(9), SCAN_COMPLETE_EVENT_ID = BIT(10), diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_init.c b/trunk/drivers/net/wireless/wl12xx/wl1271_init.c index 9ab336829044..b880382cf15d 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_init.c @@ -352,6 +352,11 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; + /* Configure rssi/snr averaging weights */ + ret = wl1271_acx_rssi_snr_avg_weights(wl); + if (ret < 0) + goto out_free_memmap; + return 0; out_free_memmap: diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_main.c b/trunk/drivers/net/wireless/wl12xx/wl1271_main.c index 5c32d8d72361..283d5dade1ae 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_main.c @@ -234,35 +234,6 @@ static struct conf_drv_settings default_conf = { .broadcast_timeout = 20000, .rx_broadcast_in_ps = 1, .ps_poll_threshold = 20, - .sig_trigger_count = 2, - .sig_trigger = { - [0] = { - .threshold = -75, - .pacing = 500, - .metric = CONF_TRIG_METRIC_RSSI_BEACON, - .type = CONF_TRIG_EVENT_TYPE_EDGE, - .direction = CONF_TRIG_EVENT_DIR_LOW, - .hysteresis = 2, - .index = 0, - .enable = 1 - }, - [1] = { - .threshold = -75, - .pacing = 500, - .metric = CONF_TRIG_METRIC_RSSI_BEACON, - .type = CONF_TRIG_EVENT_TYPE_EDGE, - .direction = CONF_TRIG_EVENT_DIR_HIGH, - .hysteresis = 2, - .index = 1, - .enable = 1 - } - }, - .sig_weights = { - .rssi_bcn_avg_weight = 10, - .rssi_pkt_avg_weight = 10, - .snr_bcn_avg_weight = 10, - .snr_pkt_avg_weight = 10 - }, .bet_enable = CONF_BET_MODE_ENABLE, .bet_max_consecutive = 10, .psm_entry_retries = 3, @@ -281,6 +252,14 @@ static struct conf_drv_settings default_conf = { .pm_config = { .host_clk_settling_time = 5000, .host_fast_wakeup_support = false + }, + .roam_trigger = { + /* FIXME: due to firmware bug, must use value 1 for now */ + .trigger_pacing = 1, + .avg_weight_rssi_beacon = 20, + .avg_weight_rssi_data = 10, + .avg_weight_snr_beacon = 20, + .avg_weight_snr_data = 10 } }; @@ -1093,6 +1072,14 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, wl->tx_blocks_freed[i] = 0; wl1271_debugfs_reset(wl); + + kfree(wl->fw_status); + wl->fw_status = NULL; + kfree(wl->tx_res_if); + wl->tx_res_if = NULL; + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + mutex_unlock(&wl->mutex); } @@ -1215,6 +1202,9 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&wl->mutex); + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + ret = wl1271_ps_elp_wakeup(wl, false); if (ret < 0) goto out; @@ -1261,7 +1251,9 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) wl1271_acx_keep_alive_config( wl, CMD_TEMPL_KLV_IDX_NULL_DATA, ACX_KEEP_ALIVE_TPL_INVALID); - } + set_bit(WL1271_FLAG_IDLE, &wl->flags); + } else + clear_bit(WL1271_FLAG_IDLE, &wl->flags); } if (conf->flags & IEEE80211_CONF_PS && @@ -1316,8 +1308,12 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, struct dev_addr_list *mc_list) { struct wl1271_filter_params *fp; + struct wl1271 *wl = hw->priv; int i; + if (unlikely(wl->state == WL1271_STATE_OFF)) + return 0; + fp = kzalloc(sizeof(*fp), GFP_ATOMIC); if (!fp) { wl1271_error("Out of memory setting filters."); @@ -1364,15 +1360,16 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - if (wl->state == WL1271_STATE_OFF) + *total &= WL1271_SUPPORTED_FILTERS; + changed &= WL1271_SUPPORTED_FILTERS; + + if (unlikely(wl->state == WL1271_STATE_OFF)) goto out; ret = wl1271_ps_elp_wakeup(wl, false); if (ret < 0) goto out; - *total &= WL1271_SUPPORTED_FILTERS; - changed &= WL1271_SUPPORTED_FILTERS; if (*total & FIF_ALLMULTI) ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0); @@ -1566,10 +1563,13 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { struct wl1271 *wl = hw->priv; - int ret; + int ret = 0; mutex_lock(&wl->mutex); + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + ret = wl1271_ps_elp_wakeup(wl, false); if (ret < 0) goto out; @@ -1682,6 +1682,18 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, do_join = true; } + if (changed & BSS_CHANGED_CQM) { + bool enable = false; + if (bss_conf->cqm_rssi_thold) + enable = true; + ret = wl1271_acx_rssi_snr_trigger(wl, enable, + bss_conf->cqm_rssi_thold, + bss_conf->cqm_rssi_hyst); + if (ret < 0) + goto out; + wl->rssi_thold = bss_conf->cqm_rssi_thold; + } + if ((changed & BSS_CHANGED_BSSID) && /* * Now we know the correct bssid, so we send a new join command @@ -2262,7 +2274,8 @@ int wl1271_init_ieee80211(struct wl1271 *wl) IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_UAPSD | IEEE80211_HW_HAS_RATE_CONTROL | - IEEE80211_HW_CONNECTION_MONITOR; + IEEE80211_HW_CONNECTION_MONITOR | + IEEE80211_HW_SUPPORTS_CQM_RSSI; wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); @@ -2387,7 +2400,6 @@ int wl1271_free_hw(struct wl1271 *wl) wl1271_debugfs_exit(wl); - kfree(wl->target_mem_map); vfree(wl->fw); wl->fw = NULL; kfree(wl->nvs); diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_ps.c b/trunk/drivers/net/wireless/wl12xx/wl1271_ps.c index 5a04482b9353..a5e60e0403e5 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_ps.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_ps.c @@ -40,7 +40,8 @@ void wl1271_elp_work(struct work_struct *work) mutex_lock(&wl->mutex); if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) || - !test_bit(WL1271_FLAG_PSM, &wl->flags)) + (!test_bit(WL1271_FLAG_PSM, &wl->flags) && + !test_bit(WL1271_FLAG_IDLE, &wl->flags))) goto out; wl1271_debug(DEBUG_PSM, "chip to elp"); @@ -56,7 +57,8 @@ void wl1271_elp_work(struct work_struct *work) /* Routines to toggle sleep mode while in ELP */ void wl1271_ps_elp_sleep(struct wl1271 *wl) { - if (test_bit(WL1271_FLAG_PSM, &wl->flags)) { + if (test_bit(WL1271_FLAG_PSM, &wl->flags) || + test_bit(WL1271_FLAG_IDLE, &wl->flags)) { cancel_delayed_work(&wl->elp_work); ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, msecs_to_jiffies(ELP_ENTRY_DELAY)); diff --git a/trunk/net/mac80211/debugfs_sta.c b/trunk/net/mac80211/debugfs_sta.c index 740ff6c5b92c..6bc9b07c3eda 100644 --- a/trunk/net/mac80211/debugfs_sta.c +++ b/trunk/net/mac80211/debugfs_sta.c @@ -176,7 +176,7 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, if (htc->ht_supported) { p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.4x\n", htc->cap); - PRINT_HT_CAP((htc->cap & BIT(0)), "RX LDCP"); + PRINT_HT_CAP((htc->cap & BIT(0)), "RX LDPC"); PRINT_HT_CAP((htc->cap & BIT(1)), "HT20/HT40"); PRINT_HT_CAP(!(htc->cap & BIT(1)), "HT20"); diff --git a/trunk/net/mac80211/rx.c b/trunk/net/mac80211/rx.c index d08ede44ac7e..8ee7db193269 100644 --- a/trunk/net/mac80211/rx.c +++ b/trunk/net/mac80211/rx.c @@ -820,7 +820,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) { struct sk_buff *skb = rx->skb; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); - struct ieee80211_hdr *hdr; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; int keyidx; int hdrlen; ieee80211_rx_result result = RX_DROP_UNUSABLE; @@ -861,11 +861,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) if (!(rx->flags & IEEE80211_RX_RA_MATCH)) return RX_CONTINUE; - if (skb_linearize(rx->skb)) - return RX_DROP_UNUSABLE; - - hdr = (struct ieee80211_hdr *)skb->data; - /* start without a key */ rx->key = NULL; @@ -906,6 +901,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) rx->key = key; return RX_CONTINUE; } else { + u8 keyid; /* * The device doesn't give us the IV so we won't be * able to look up the key. That's ok though, we @@ -928,7 +924,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) * no need to call ieee80211_wep_get_keyidx, * it verifies a bunch of things we've done already */ - keyidx = rx->skb->data[hdrlen + 3] >> 6; + skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1); + keyidx = keyid >> 6; rx->key = rcu_dereference(rx->sdata->keys[keyidx]); @@ -949,6 +946,11 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) return RX_DROP_MONITOR; } + if (skb_linearize(rx->skb)) + return RX_DROP_UNUSABLE; + + hdr = (struct ieee80211_hdr *)rx->skb->data; + /* Check for weak IVs if possible */ if (rx->sta && rx->key->conf.alg == ALG_WEP && ieee80211_is_data(hdr->frame_control) && diff --git a/trunk/net/mac80211/work.c b/trunk/net/mac80211/work.c index 1e1ea3007b06..7bd8670379de 100644 --- a/trunk/net/mac80211/work.c +++ b/trunk/net/mac80211/work.c @@ -919,11 +919,16 @@ static void ieee80211_work_work(struct work_struct *work) run_again(local, jiffies + HZ/2); } - if (list_empty(&local->work_list) && local->scan_req) + mutex_lock(&local->scan_mtx); + + if (list_empty(&local->work_list) && local->scan_req && + !local->scanning) ieee80211_queue_delayed_work(&local->hw, &local->scan_work, round_jiffies_relative(0)); + mutex_unlock(&local->scan_mtx); + mutex_unlock(&local->work_mtx); ieee80211_recalc_idle(local);