From 1e5cf9b0be4e8902c06bf9600ea0b256e731c862 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 21 Jun 2011 04:30:56 -0700 Subject: [PATCH 1/5] iwlagn: use PM ops macro Simplify the code and use SIMPLE_DEV_PM_OPS to define iwl_dev_pm_ops instead of doing the same thing manually. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-pci.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c index 7328fbff7f7b..3927c802a5d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-pci.c +++ b/drivers/net/wireless/iwlwifi/iwl-pci.c @@ -530,14 +530,7 @@ static int iwl_pci_resume(struct device *device) return iwl_resume(priv); } -static const struct dev_pm_ops iwl_dev_pm_ops = { - .suspend = iwl_pci_suspend, - .resume = iwl_pci_resume, - .freeze = iwl_pci_suspend, - .thaw = iwl_pci_resume, - .poweroff = iwl_pci_suspend, - .restore = iwl_pci_resume, -}; +static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume); #define IWL_PM_OPS (&iwl_dev_pm_ops) From f8d651a56ef5c9e26a1cddd4f169f5bf4f8dfa9b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Jun 2011 04:25:57 -0700 Subject: [PATCH 2/5] iwlagn: fix cmd queue unmap When we stop the device while a command is in flight that uses multiple TBs, we can leak the DMA buffers for the second and higher TBs. Fix this by using iwlagn_unmap_tfd() as we do when we normally recover the entry. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-tx.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index fd8aee9972c1..cf8fc9afa1ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -309,10 +309,7 @@ void iwl_cmd_queue_unmap(struct iwl_priv *priv) i = get_cmd_index(q, q->read_ptr); if (txq->meta[i].flags & CMD_MAPPED) { - dma_unmap_single(priv->bus.dev, - dma_unmap_addr(&txq->meta[i], mapping), - dma_unmap_len(&txq->meta[i], len), - DMA_BIDIRECTIONAL); + iwlagn_unmap_tfd(priv, &txq->meta[i], &txq->tfds[i]); txq->meta[i].flags = 0; } From 81704d2db99386d718e277cd5ac92663abec8a66 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Jun 2011 06:39:43 -0700 Subject: [PATCH 3/5] iwlagn: extend host command timeout We've infrequently seen timeouts, make the wait time match the windows driver; hopefully our driver is just too impatient. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-hcmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 7cdb1ec73b54..e3e5fb614178 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -113,7 +113,7 @@ const char *get_cmd_string(u8 cmd) } } -#define HOST_COMPLETE_TIMEOUT (HZ / 2) +#define HOST_COMPLETE_TIMEOUT (2 * HZ) static void iwl_generic_cmd_callback(struct iwl_priv *priv, struct iwl_device_cmd *cmd, From 0b5b3ff15b301338ccec77ebc051308ac614d05d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Jun 2011 06:33:43 -0700 Subject: [PATCH 4/5] iwlagn: fill beacon TX rate properly Use the rate that mac80211 requested to fill the uCode TX command for the beacon. Unfortunately, the uCode is (currently?) ignoring it, but now at least fill it properly. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-agn.c | 26 +++++++++++++++++++++---- drivers/net/wireless/iwlwifi/iwl-core.c | 13 ------------- drivers/net/wireless/iwlwifi/iwl-core.h | 7 ------- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 77ceb8deff75..e2f6b2ab0d45 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -132,6 +132,7 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv) struct iwl_host_cmd cmd = { .id = REPLY_TX_BEACON, }; + struct ieee80211_tx_info *info; u32 frame_size; u32 rate_flags; u32 rate; @@ -172,14 +173,31 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv) frame_size); /* Set up packet rate and flags */ - rate = iwl_rate_get_lowest_plcp(priv, priv->beacon_ctx); + info = IEEE80211_SKB_CB(priv->beacon_skb); + + /* + * Let's set up the rate at least somewhat correctly; + * it will currently not actually be used by the uCode, + * it uses the broadcast station's rate instead. + */ + if (info->control.rates[0].idx < 0 || + info->control.rates[0].flags & IEEE80211_TX_RC_MCS) + rate = 0; + else + rate = info->control.rates[0].idx; + priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant, priv->hw_params.valid_tx_ant); rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant); - if ((rate >= IWL_FIRST_CCK_RATE) && (rate <= IWL_LAST_CCK_RATE)) + + /* In mac80211, rates for 5 GHz start at 0 */ + if (info->band == IEEE80211_BAND_5GHZ) + rate += IWL_FIRST_OFDM_RATE; + else if (rate >= IWL_FIRST_CCK_RATE && rate <= IWL_LAST_CCK_RATE) rate_flags |= RATE_MCS_CCK_MSK; - tx_beacon_cmd->tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate, - rate_flags); + + tx_beacon_cmd->tx.rate_n_flags = + iwl_hw_set_rate_n_flags(rate, rate_flags); /* Submit command */ cmd.len[0] = sizeof(*tx_beacon_cmd); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index cde725326c32..f0eabbc07c95 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -526,19 +526,6 @@ int iwl_full_rxon_required(struct iwl_priv *priv, return 0; } -u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - /* - * Assign the lowest rate -- should really get this from - * the beacon skb from mac80211. - */ - if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) - return IWL_RATE_1M_PLCP; - else - return IWL_RATE_6M_PLCP; -} - static void _iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf, struct iwl_rxon_context *ctx) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index adf9f9b2efb5..f881678be762 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -408,13 +408,6 @@ void iwl_setup_watchdog(struct iwl_priv *priv); ****************************************************/ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); -/******************************************************************************* - * Rate - ******************************************************************************/ - -u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv, - struct iwl_rxon_context *ctx); - /******************************************************************************* * Scanning ******************************************************************************/ From f775aa06d2de583bd291d4bf5814784c9ff7b9cc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Jun 2011 06:34:09 -0700 Subject: [PATCH 5/5] iwlagn: don't use CCK rates for P2P interfaces P2P interfaces must not use CCK rates, only OFDM rates are allowed. To set this up, we need to set up the broadcast station to start with 6M instead of starting with 1M. Since the interface type can change, also reset the broadcast station when RXON changes. This will affect beacons as well. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-agn-sta.c | 17 +++++++++++------ drivers/net/wireless/iwlwifi/iwl-agn.h | 2 ++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index a7c66c4e5f2a..8fa43d427811 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -210,6 +210,8 @@ static int iwlagn_rxon_disconn(struct iwl_priv *priv, * keys, so we have to restore those afterwards. */ iwl_clear_ucode_stations(priv, ctx); + /* update -- might need P2P now */ + iwl_update_bcast_station(priv, ctx); iwl_restore_stations(priv, ctx); ret = iwl_restore_default_wep_keys(priv, ctx); if (ret) { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index 0bd722cee5ae..9b32f83f0b7f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -35,7 +35,7 @@ #include "iwl-agn.h" static struct iwl_link_quality_cmd * -iwl_sta_alloc_lq(struct iwl_priv *priv, u8 sta_id) +iwl_sta_alloc_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, u8 sta_id) { int i, r; struct iwl_link_quality_cmd *link_cmd; @@ -47,10 +47,15 @@ iwl_sta_alloc_lq(struct iwl_priv *priv, u8 sta_id) IWL_ERR(priv, "Unable to allocate memory for LQ cmd.\n"); return NULL; } + + lockdep_assert_held(&priv->mutex); + /* Set up the rate scaling to start at selected rate, fall back * all the way down to 1M in IEEE order, and then spin on 1M */ if (priv->band == IEEE80211_BAND_5GHZ) r = IWL_RATE_6M_INDEX; + else if (ctx && ctx->vif && ctx->vif->p2p) + r = IWL_RATE_6M_INDEX; else r = IWL_RATE_1M_INDEX; @@ -115,7 +120,7 @@ int iwlagn_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx spin_unlock_irqrestore(&priv->sta_lock, flags); /* Set up default rate scaling table in device's station table */ - link_cmd = iwl_sta_alloc_lq(priv, sta_id); + link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id); if (!link_cmd) { IWL_ERR(priv, "Unable to initialize rate scaling for station %pM.\n", addr); @@ -554,7 +559,7 @@ int iwlagn_alloc_bcast_station(struct iwl_priv *priv, priv->stations[sta_id].used |= IWL_STA_BCAST; spin_unlock_irqrestore(&priv->sta_lock, flags); - link_cmd = iwl_sta_alloc_lq(priv, sta_id); + link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id); if (!link_cmd) { IWL_ERR(priv, "Unable to initialize rate scaling for bcast station.\n"); @@ -574,14 +579,14 @@ int iwlagn_alloc_bcast_station(struct iwl_priv *priv, * Only used by iwlagn. Placed here to have all bcast station management * code together. */ -static int iwl_update_bcast_station(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) +int iwl_update_bcast_station(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) { unsigned long flags; struct iwl_link_quality_cmd *link_cmd; u8 sta_id = ctx->bcast_sta_id; - link_cmd = iwl_sta_alloc_lq(priv, sta_id); + link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id); if (!link_cmd) { IWL_ERR(priv, "Unable to initialize rate scaling for bcast station.\n"); return -ENOMEM; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 6d5584ae5ebf..dcdf2259520f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -304,6 +304,8 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta, int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta, int tid); void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt); +int iwl_update_bcast_station(struct iwl_priv *priv, + struct iwl_rxon_context *ctx); int iwl_update_bcast_stations(struct iwl_priv *priv); void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,