Commit 56e9c0a6 authored by David S. Miller's avatar David S. Miller
parents 6c00055a 9aab3e3e
...@@ -1067,8 +1067,16 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, ...@@ -1067,8 +1067,16 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
tx_status->flags &= ~ATH_TX_BAR; tx_status->flags &= ~ATH_TX_BAR;
} }
if (tx_status->flags)
if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) {
if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
/* Frame was not ACKed, but an ACK was expected */
tx_info->status.excessive_retries = 1; tx_info->status.excessive_retries = 1;
}
} else {
/* Frame was ACKed */
tx_info->flags |= IEEE80211_TX_STAT_ACK;
}
tx_info->status.retry_count = tx_status->retries; tx_info->status.retry_count = tx_status->retries;
......
...@@ -357,9 +357,9 @@ static int ath_tx_prepare(struct ath_softc *sc, ...@@ -357,9 +357,9 @@ static int ath_tx_prepare(struct ath_softc *sc,
txctl->flags = ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ txctl->flags = ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
tx_info->flags |= ATH9K_TXDESC_NOACK; txctl->flags |= ATH9K_TXDESC_NOACK;
if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
tx_info->flags |= ATH9K_TXDESC_RTSENA; txctl->flags |= ATH9K_TXDESC_RTSENA;
/* /*
* Setup for rate calculations. * Setup for rate calculations.
......
...@@ -1153,7 +1153,8 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, ...@@ -1153,7 +1153,8 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
!sta->ht_info.ht_supported) !sta->ht_info.ht_supported)
return -1; return -1;
if (priv->current_ht_config.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC) if (((sta->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS) >> 2)
== IWL_MIMO_PS_STATIC)
return -1; return -1;
/* Need both Tx chains/antennas to support MIMO */ /* Need both Tx chains/antennas to support MIMO */
......
...@@ -181,14 +181,14 @@ static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon) ...@@ -181,14 +181,14 @@ static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
} }
/** /**
* iwl4965_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
* @priv: staging_rxon is compared to active_rxon * @priv: staging_rxon is compared to active_rxon
* *
* If the RXON structure is changing enough to require a new tune, * If the RXON structure is changing enough to require a new tune,
* or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
* a new tune (full RXON command, rather than RXON_ASSOC cmd) is required. * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
*/ */
static int iwl4965_full_rxon_required(struct iwl_priv *priv) static int iwl_full_rxon_required(struct iwl_priv *priv)
{ {
/* These items are only settable from the full RXON command */ /* These items are only settable from the full RXON command */
...@@ -207,7 +207,6 @@ static int iwl4965_full_rxon_required(struct iwl_priv *priv) ...@@ -207,7 +207,6 @@ static int iwl4965_full_rxon_required(struct iwl_priv *priv)
priv->active_rxon.ofdm_ht_single_stream_basic_rates) || priv->active_rxon.ofdm_ht_single_stream_basic_rates) ||
(priv->staging_rxon.ofdm_ht_dual_stream_basic_rates != (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates !=
priv->active_rxon.ofdm_ht_dual_stream_basic_rates) || priv->active_rxon.ofdm_ht_dual_stream_basic_rates) ||
(priv->staging_rxon.rx_chain != priv->active_rxon.rx_chain) ||
(priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id)) (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
return 1; return 1;
...@@ -263,7 +262,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) ...@@ -263,7 +262,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
/* If we don't need to send a full RXON, we can use /* If we don't need to send a full RXON, we can use
* iwl4965_rxon_assoc_cmd which is used to reconfigure filter * iwl4965_rxon_assoc_cmd which is used to reconfigure filter
* and other flags for the current radio configuration. */ * and other flags for the current radio configuration. */
if (!iwl4965_full_rxon_required(priv)) { if (!iwl_full_rxon_required(priv)) {
ret = iwl_send_rxon_assoc(priv); ret = iwl_send_rxon_assoc(priv);
if (ret) { if (ret) {
IWL_ERROR("Error setting RXON_ASSOC (%d)\n", ret); IWL_ERROR("Error setting RXON_ASSOC (%d)\n", ret);
...@@ -587,8 +586,6 @@ static void iwl4965_ht_conf(struct iwl_priv *priv, ...@@ -587,8 +586,6 @@ static void iwl4965_ht_conf(struct iwl_priv *priv,
iwl_conf->supported_chan_width = 0; iwl_conf->supported_chan_width = 0;
} }
iwl_conf->tx_mimo_ps_mode =
(u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
iwl_conf->control_channel = ht_bss_conf->primary_channel; iwl_conf->control_channel = ht_bss_conf->primary_channel;
...@@ -2190,6 +2187,9 @@ static void __iwl4965_down(struct iwl_priv *priv) ...@@ -2190,6 +2187,9 @@ static void __iwl4965_down(struct iwl_priv *priv)
udelay(5); udelay(5);
/* FIXME: apm_ops.suspend(priv) */ /* FIXME: apm_ops.suspend(priv) */
if (exit_pending || test_bit(STATUS_IN_SUSPEND, &priv->status))
priv->cfg->ops->lib->apm_ops.stop(priv);
else
priv->cfg->ops->lib->apm_ops.reset(priv); priv->cfg->ops->lib->apm_ops.reset(priv);
priv->cfg->ops->lib->free_shared_mem(priv); priv->cfg->ops->lib->free_shared_mem(priv);
...@@ -3588,7 +3588,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk ...@@ -3588,7 +3588,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
priv->assoc_id = 0; priv->assoc_id = 0;
timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
priv->timestamp = le64_to_cpu(timestamp) + (priv->beacon_int * 1000); priv->timestamp = le64_to_cpu(timestamp);
IWL_DEBUG_MAC80211("leave\n"); IWL_DEBUG_MAC80211("leave\n");
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
...@@ -4372,14 +4372,17 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) ...@@ -4372,14 +4372,17 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
iwl_dbgfs_unregister(priv); iwl_dbgfs_unregister(priv);
sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
/* ieee80211_unregister_hw call wil cause iwl4965_mac_stop to
* to be called and iwl4965_down since we are removing the device
* we need to set STATUS_EXIT_PENDING bit.
*/
set_bit(STATUS_EXIT_PENDING, &priv->status);
if (priv->mac80211_registered) { if (priv->mac80211_registered) {
ieee80211_unregister_hw(priv->hw); ieee80211_unregister_hw(priv->hw);
priv->mac80211_registered = 0; priv->mac80211_registered = 0;
} } else {
set_bit(STATUS_EXIT_PENDING, &priv->status);
iwl4965_down(priv); iwl4965_down(priv);
}
/* make sure we flush any pending irq or /* make sure we flush any pending irq or
* tasklet for the driver * tasklet for the driver
......
...@@ -592,12 +592,11 @@ static void iwlcore_free_geos(struct iwl_priv *priv) ...@@ -592,12 +592,11 @@ static void iwlcore_free_geos(struct iwl_priv *priv)
clear_bit(STATUS_GEO_CONFIGURED, &priv->status); clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
} }
static u8 is_single_rx_stream(struct iwl_priv *priv) static bool is_single_rx_stream(struct iwl_priv *priv)
{ {
return !priv->current_ht_config.is_ht || return !priv->current_ht_config.is_ht ||
((priv->current_ht_config.supp_mcs_set[1] == 0) && ((priv->current_ht_config.supp_mcs_set[1] == 0) &&
(priv->current_ht_config.supp_mcs_set[2] == 0)) || (priv->current_ht_config.supp_mcs_set[2] == 0));
priv->ps_mode == IWL_MIMO_PS_STATIC;
} }
static u8 iwl_is_channel_extension(struct iwl_priv *priv, static u8 iwl_is_channel_extension(struct iwl_priv *priv,
...@@ -704,33 +703,39 @@ EXPORT_SYMBOL(iwl_set_rxon_ht); ...@@ -704,33 +703,39 @@ EXPORT_SYMBOL(iwl_set_rxon_ht);
* MIMO (dual stream) requires at least 2, but works better with 3. * MIMO (dual stream) requires at least 2, but works better with 3.
* This does not determine *which* chains to use, just how many. * This does not determine *which* chains to use, just how many.
*/ */
static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv, static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
u8 *idle_state, u8 *rx_state)
{ {
u8 is_single = is_single_rx_stream(priv); bool is_single = is_single_rx_stream(priv);
u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1; bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
/* # of Rx chains to use when expecting MIMO. */ /* # of Rx chains to use when expecting MIMO. */
if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC))) if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC)))
*rx_state = 2; return 2;
else else
*rx_state = 3; return 3;
}
static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
{
int idle_cnt;
bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
/* # Rx chains when idling and maybe trying to save power */ /* # Rx chains when idling and maybe trying to save power */
switch (priv->ps_mode) { switch (priv->ps_mode) {
case IWL_MIMO_PS_STATIC: case IWL_MIMO_PS_STATIC:
case IWL_MIMO_PS_DYNAMIC: case IWL_MIMO_PS_DYNAMIC:
*idle_state = (is_cam) ? 2 : 1; idle_cnt = (is_cam) ? 2 : 1;
break; break;
case IWL_MIMO_PS_NONE: case IWL_MIMO_PS_NONE:
*idle_state = (is_cam) ? *rx_state : 1; idle_cnt = (is_cam) ? active_cnt : 1;
break; break;
case IWL_MIMO_PS_INVALID:
default: default:
*idle_state = 1; IWL_ERROR("invalide mimo ps mode %d\n", priv->ps_mode);
WARN_ON(1);
idle_cnt = -1;
break; break;
} }
return idle_cnt;
return 0;
} }
/** /**
...@@ -741,34 +746,44 @@ static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv, ...@@ -741,34 +746,44 @@ static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv,
*/ */
void iwl_set_rxon_chain(struct iwl_priv *priv) void iwl_set_rxon_chain(struct iwl_priv *priv)
{ {
u8 is_single = is_single_rx_stream(priv); bool is_single = is_single_rx_stream(priv);
u8 idle_state, rx_state; bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
u8 idle_rx_cnt, active_rx_cnt;
priv->staging_rxon.rx_chain = 0; u16 rx_chain;
rx_state = idle_state = 3;
/* Tell uCode which antennas are actually connected. /* Tell uCode which antennas are actually connected.
* Before first association, we assume all antennas are connected. * Before first association, we assume all antennas are connected.
* Just after first association, iwl_chain_noise_calibration() * Just after first association, iwl_chain_noise_calibration()
* checks which antennas actually *are* connected. */ * checks which antennas actually *are* connected. */
priv->staging_rxon.rx_chain |= rx_chain = priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
cpu_to_le16(priv->hw_params.valid_rx_ant <<
RXON_RX_CHAIN_VALID_POS);
/* How many receivers should we use? */ /* How many receivers should we use? */
iwlcore_get_rx_chain_counter(priv, &idle_state, &rx_state); active_rx_cnt = iwl_get_active_rx_chain_count(priv);
priv->staging_rxon.rx_chain |= idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt);
cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS);
priv->staging_rxon.rx_chain |= /* correct rx chain count accoridng hw settings */
cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS); if (priv->hw_params.rx_chains_num < active_rx_cnt)
active_rx_cnt = priv->hw_params.rx_chains_num;
if (!is_single && (rx_state >= 2) &&
!test_bit(STATUS_POWER_PMI, &priv->status)) if (priv->hw_params.rx_chains_num < idle_rx_cnt)
idle_rx_cnt = priv->hw_params.rx_chains_num;
rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS;
priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain);
if (!is_single && (active_rx_cnt >= 2) && is_cam)
priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK; priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
else else
priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain); IWL_DEBUG_ASSOC("rx_chain=0x%Xi active=%d idle=%d\n",
priv->staging_rxon.rx_chain,
active_rx_cnt, idle_rx_cnt);
WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 ||
active_rx_cnt < idle_rx_cnt);
} }
EXPORT_SYMBOL(iwl_set_rxon_chain); EXPORT_SYMBOL(iwl_set_rxon_chain);
......
...@@ -412,7 +412,6 @@ struct iwl_ht_info { ...@@ -412,7 +412,6 @@ struct iwl_ht_info {
/* self configuration data */ /* self configuration data */
u8 is_ht; u8 is_ht;
u8 supported_chan_width; u8 supported_chan_width;
u16 tx_mimo_ps_mode;
u8 is_green_field; u8 is_green_field;
u8 sgf; /* HT_SHORT_GI_* short guard interval */ u8 sgf; /* HT_SHORT_GI_* short guard interval */
u8 max_amsdu_size; u8 max_amsdu_size;
......
...@@ -1173,7 +1173,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, ...@@ -1173,7 +1173,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
rx_status.antenna = 0; rx_status.antenna = 0;
rx_status.flag = 0; rx_status.flag = 0;
rx_status.flag |= RX_FLAG_TSFT;
/* TSF isn't reliable. In order to allow smooth user experience,
* this W/A doesn't propagate it to the mac80211 */
/*rx_status.flag |= RX_FLAG_TSFT;*/
if ((unlikely(rx_start->cfg_phy_cnt > 20))) { if ((unlikely(rx_start->cfg_phy_cnt > 20))) {
IWL_DEBUG_DROP("dsp size out of range [0,20]: %d/n", IWL_DEBUG_DROP("dsp size out of range [0,20]: %d/n",
......
...@@ -421,7 +421,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, ...@@ -421,7 +421,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
else else
scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
if ((scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) && n_probes) if (n_probes)
scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes); scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
scan_ch->active_dwell = cpu_to_le16(active_dwell); scan_ch->active_dwell = cpu_to_le16(active_dwell);
......
...@@ -402,12 +402,11 @@ static int iwl_hw_tx_queue_init(struct iwl_priv *priv, ...@@ -402,12 +402,11 @@ static int iwl_hw_tx_queue_init(struct iwl_priv *priv,
/** /**
* iwl_tx_queue_init - Allocate and initialize one tx/cmd queue * iwl_tx_queue_init - Allocate and initialize one tx/cmd queue
*/ */
static int iwl_tx_queue_init(struct iwl_priv *priv, static int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
struct iwl_tx_queue *txq,
int slots_num, u32 txq_id) int slots_num, u32 txq_id)
{ {
int i, len; int i, len;
int rc = 0; int ret;
/* /*
* Alloc buffer array for commands (Tx or other types of commands). * Alloc buffer array for commands (Tx or other types of commands).
...@@ -428,17 +427,14 @@ static int iwl_tx_queue_init(struct iwl_priv *priv, ...@@ -428,17 +427,14 @@ static int iwl_tx_queue_init(struct iwl_priv *priv,
txq->cmd[i] = kmalloc(len, GFP_KERNEL); txq->cmd[i] = kmalloc(len, GFP_KERNEL);
if (!txq->cmd[i]) if (!txq->cmd[i])
return -ENOMEM; goto err;
} }
/* Alloc driver data array and TFD circular buffer */ /* Alloc driver data array and TFD circular buffer */
rc = iwl_tx_queue_alloc(priv, txq, txq_id); ret = iwl_tx_queue_alloc(priv, txq, txq_id);
if (rc) { if (ret)
for (i = 0; i < slots_num; i++) goto err;
kfree(txq->cmd[i]);
return -ENOMEM;
}
txq->need_update = 0; txq->need_update = 0;
/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
...@@ -452,6 +448,17 @@ static int iwl_tx_queue_init(struct iwl_priv *priv, ...@@ -452,6 +448,17 @@ static int iwl_tx_queue_init(struct iwl_priv *priv,
iwl_hw_tx_queue_init(priv, txq); iwl_hw_tx_queue_init(priv, txq);
return 0; return 0;
err:
for (i = 0; i < slots_num; i++) {
kfree(txq->cmd[i]);
txq->cmd[i] = NULL;
}
if (txq_id == IWL_CMD_QUEUE_NUM) {
kfree(txq->cmd[slots_num]);
txq->cmd[slots_num] = NULL;
}
return -ENOMEM;
} }
/** /**
* iwl_hw_txq_ctx_free - Free TXQ Context * iwl_hw_txq_ctx_free - Free TXQ Context
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment