Commit fe01b477 authored by Ron Rindjunsky's avatar Ron Rindjunsky Committed by John W. Linville

iwlwifi: A-MPDU Tx conform flows to mac80211

This patch alters the current iwlwifi behavior to fit the flows introduced
by the mac80211, mainly queues handling and start/stop call backs flows
Signed-off-by: default avatarRon Rindjunsky <ron.rindjunsky@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 8114fcf1
......@@ -1300,6 +1300,25 @@ struct iwl4965_tx_resp {
__le32 status; /* TX status (for aggregation status of 1st frame) */
} __attribute__ ((packed));
struct agg_tx_status {
__le16 status;
__le16 sequence;
} __attribute__ ((packed));
struct iwl4965_tx_resp_agg {
u8 frame_count; /* 1 no aggregation, >1 aggregation */
u8 reserved1;
u8 failure_rts;
u8 failure_frame;
__le32 rate_n_flags;
__le16 wireless_media_time;
__le16 reserved3;
__le32 pa_power1;
__le32 pa_power2;
struct agg_tx_status status; /* TX status (for aggregation status */
/* of 1st frame) */
} __attribute__ ((packed));
/*
* REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
*
......@@ -1313,9 +1332,8 @@ struct iwl4965_compressed_ba_resp {
/* Index of recipient (BA-sending) station in uCode's station table */
u8 sta_id;
u8 tid;
__le16 ba_seq_ctl;
__le32 ba_bitmap0;
__le32 ba_bitmap1;
__le16 seq_ctl;
__le64 bitmap;
__le16 scd_flow;
__le16 scd_ssn;
} __attribute__ ((packed));
......
This diff is collapsed.
......@@ -433,7 +433,6 @@ struct iwl4965_rx_queue {
#define IWL_INVALID_VALUE -1
#ifdef CONFIG_IWL4965_HT
#ifdef CONFIG_IWL4965_HT_AGG
/**
* struct iwl4965_ht_agg -- aggregation status while waiting for block-ack
* @txq_id: Tx queue used for Tx attempt
......@@ -453,19 +452,22 @@ struct iwl4965_ht_agg {
u16 frame_count;
u16 wait_for_ba;
u16 start_idx;
u32 bitmap0;
u32 bitmap1;
u64 bitmap;
u32 rate_n_flags;
#define IWL_AGG_OFF 0
#define IWL_AGG_ON 1
#define IWL_EMPTYING_HW_QUEUE_ADDBA 2
#define IWL_EMPTYING_HW_QUEUE_DELBA 3
u8 state;
};
#endif /* CONFIG_IWL4965_HT_AGG */
#endif /* CONFIG_IWL4965_HT */
struct iwl4965_tid_data {
u16 seq_number;
u16 tfds_in_queue;
#ifdef CONFIG_IWL4965_HT
#ifdef CONFIG_IWL4965_HT_AGG
struct iwl4965_ht_agg agg;
#endif /* CONFIG_IWL4965_HT_AGG */
#endif /* CONFIG_IWL4965_HT */
};
......@@ -743,7 +745,7 @@ extern u8 iwl4965_hw_find_station(struct iwl4965_priv *priv, const u8 *bssid);
extern int iwl4965_hw_channel_switch(struct iwl4965_priv *priv, u16 channel);
extern int iwl4965_tx_queue_reclaim(struct iwl4965_priv *priv, int txq_id, int index);
extern int iwl4965_queue_space(const struct iwl4965_queue *q);
struct iwl4965_priv;
/*
......@@ -778,6 +780,8 @@ extern void iwl4965_set_ht_add_station(struct iwl4965_priv *priv, u8 index,
extern int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
enum ieee80211_ampdu_mlme_action action,
const u8 *addr, u16 tid, u16 *ssn);
extern int iwl4965_check_empty_hw_queue(struct iwl4965_priv *priv, int sta_id,
u8 tid, int txq_id);
#ifdef CONFIG_IWL4965_HT_AGG
extern void iwl4965_turn_off_agg(struct iwl4965_priv *priv, u8 tid);
extern void iwl4965_tl_get_stats(struct iwl4965_priv *priv,
......
......@@ -205,7 +205,7 @@ static void iwl4965_print_hex_dump(int level, void *p, u32 len)
* See more detailed info in iwl-4965-hw.h.
***************************************************/
static int iwl4965_queue_space(const struct iwl4965_queue *q)
int iwl4965_queue_space(const struct iwl4965_queue *q)
{
int s = q->read_ptr - q->write_ptr;
......@@ -2972,11 +2972,10 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv,
__constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
seq_number += 0x10;
#ifdef CONFIG_IWL4965_HT
#ifdef CONFIG_IWL4965_HT_AGG
/* aggregation is on for this <sta,tid> */
if (ctl->flags & IEEE80211_TXCTL_HT_MPDU_AGG)
if (ctl->flags & IEEE80211_TXCTL_AMPDU)
txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
#endif /* CONFIG_IWL4965_HT_AGG */
priv->stations[sta_id].tid[tid].tfds_in_queue++;
#endif /* CONFIG_IWL4965_HT */
}
......@@ -3528,10 +3527,10 @@ int iwl4965_tx_queue_reclaim(struct iwl4965_priv *priv, int txq_id, int index)
nfreed++;
}
if (iwl4965_queue_space(q) > q->low_mark && (txq_id >= 0) &&
/* if (iwl4965_queue_space(q) > q->low_mark && (txq_id >= 0) &&
(txq_id != IWL_CMD_QUEUE_NUM) &&
priv->mac80211_registered)
ieee80211_wake_queue(priv->hw, txq_id);
ieee80211_wake_queue(priv->hw, txq_id); */
return nfreed;
......@@ -3550,7 +3549,6 @@ static int iwl4965_is_tx_success(u32 status)
*
******************************************************************************/
#ifdef CONFIG_IWL4965_HT
#ifdef CONFIG_IWL4965_HT_AGG
static inline int iwl4965_get_ra_sta_id(struct iwl4965_priv *priv,
struct ieee80211_hdr *hdr)
......@@ -3585,11 +3583,11 @@ static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp)
*/
static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv,
struct iwl4965_ht_agg *agg,
struct iwl4965_tx_resp *tx_resp,
struct iwl4965_tx_resp_agg *tx_resp,
u16 start_idx)
{
u32 status;
__le32 *frame_status = &tx_resp->status;
u16 status;
struct agg_tx_status *frame_status = &tx_resp->status;
struct ieee80211_tx_status *tx_status = NULL;
struct ieee80211_hdr *hdr = NULL;
int i, sh;
......@@ -3602,26 +3600,25 @@ static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv,
agg->frame_count = tx_resp->frame_count;
agg->start_idx = start_idx;
agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
agg->bitmap0 = agg->bitmap1 = 0;
agg->bitmap = 0;
/* # frames attempted by Tx command */
if (agg->frame_count == 1) {
/* Only one frame was attempted; no block-ack will arrive */
struct iwl4965_tx_queue *txq ;
status = le32_to_cpu(frame_status[0]);
status = le16_to_cpu(frame_status[0].status);
seq = le16_to_cpu(frame_status[0].sequence);
idx = SEQ_TO_INDEX(seq);
txq_id = SEQ_TO_QUEUE(seq);
txq_id = agg->txq_id;
txq = &priv->txq[txq_id];
/* FIXME: code repetition */
IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d \n",
agg->frame_count, agg->start_idx);
IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n",
agg->frame_count, agg->start_idx, idx);
tx_status = &(priv->txq[txq_id].txb[txq->q.read_ptr].status);
tx_status = &(priv->txq[txq_id].txb[idx].status);
tx_status->retry_count = tx_resp->failure_frame;
tx_status->queue_number = status & 0xff;
tx_status->queue_length = tx_resp->bt_kill_count;
tx_status->queue_length |= tx_resp->failure_rts;
tx_status->queue_length = tx_resp->failure_rts;
tx_status->control.flags &= ~IEEE80211_TXCTL_AMPDU;
tx_status->flags = iwl4965_is_tx_success(status)?
IEEE80211_TX_STATUS_ACK : 0;
tx_status->control.tx_rate =
......@@ -3642,8 +3639,8 @@ static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv,
/* Construct bit-map of pending frames within Tx window */
for (i = 0; i < agg->frame_count; i++) {
u16 sc;
status = le32_to_cpu(frame_status[i]);
seq = status >> 16;
status = le16_to_cpu(frame_status[i].status);
seq = le16_to_cpu(frame_status[i].sequence);
idx = SEQ_TO_INDEX(seq);
txq_id = SEQ_TO_QUEUE(seq);
......@@ -3687,13 +3684,12 @@ static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv,
start, (u32)(bitmap & 0xFFFFFFFF));
}
agg->bitmap0 = bitmap & 0xFFFFFFFF;
agg->bitmap1 = bitmap >> 32;
agg->bitmap = bitmap;
agg->start_idx = start;
agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%x\n",
IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n",
agg->frame_count, agg->start_idx,
agg->bitmap0);
agg->bitmap);
if (bitmap)
agg->wait_for_ba = 1;
......@@ -3701,7 +3697,6 @@ static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv,
return 0;
}
#endif
#endif
/**
* iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response
......@@ -3718,9 +3713,9 @@ static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv,
struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
u32 status = le32_to_cpu(tx_resp->status);
#ifdef CONFIG_IWL4965_HT
#ifdef CONFIG_IWL4965_HT_AGG
int tid, sta_id;
#endif
int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION;
struct ieee80211_hdr *hdr;
__le16 *qc;
#endif
if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) {
......@@ -3732,44 +3727,51 @@ static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv,
}
#ifdef CONFIG_IWL4965_HT
#ifdef CONFIG_IWL4965_HT_AGG
if (txq->sched_retry) {
const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp);
struct ieee80211_hdr *hdr =
iwl4965_tx_queue_get_hdr(priv, txq_id, index);
struct iwl4965_ht_agg *agg = NULL;
__le16 *qc = ieee80211_get_qos_ctrl(hdr);
if (qc == NULL) {
IWL_ERROR("BUG_ON qc is null!!!!\n");
return;
}
hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, index);
qc = ieee80211_get_qos_ctrl(hdr);
if (qc)
tid = le16_to_cpu(*qc) & 0xf;
sta_id = iwl4965_get_ra_sta_id(priv, hdr);
if (unlikely(sta_id == IWL_INVALID_STATION)) {
IWL_ERROR("Station not known for\n");
if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) {
IWL_ERROR("Station not known\n");
return;
}
if (txq->sched_retry) {
const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp);
struct iwl4965_ht_agg *agg = NULL;
if (!qc)
return;
agg = &priv->stations[sta_id].tid[tid].agg;
iwl4965_tx_status_reply_tx(priv, agg, tx_resp, index);
iwl4965_tx_status_reply_tx(priv, agg,
(struct iwl4965_tx_resp_agg *)tx_resp, index);
if ((tx_resp->frame_count == 1) &&
!iwl4965_is_tx_success(status)) {
/* TODO: send BAR */
}
if ((txq->q.read_ptr != (scd_ssn & 0xff))) {
if (txq->q.read_ptr != (scd_ssn & 0xff)) {
int freed;
index = iwl4965_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
"%d index %d\n", scd_ssn , index);
iwl4965_tx_queue_reclaim(priv, txq_id, index);
freed = iwl4965_tx_queue_reclaim(priv, txq_id, index);
priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
if (iwl4965_queue_space(&txq->q) > txq->q.low_mark &&
txq_id >= 0 && priv->mac80211_registered &&
agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)
ieee80211_wake_queue(priv->hw, txq_id);
iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id);
}
} else {
#endif /* CONFIG_IWL4965_HT_AGG */
#endif /* CONFIG_IWL4965_HT */
tx_status = &(txq->txb[txq->q.read_ptr].status);
......@@ -3790,12 +3792,21 @@ static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv,
tx_resp->failure_frame);
IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
if (index != -1)
iwl4965_tx_queue_reclaim(priv, txq_id, index);
if (index != -1) {
int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index);
#ifdef CONFIG_IWL4965_HT
if (tid != MAX_TID_COUNT)
priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
if (iwl4965_queue_space(&txq->q) > txq->q.low_mark &&
(txq_id >= 0) &&
priv->mac80211_registered)
ieee80211_wake_queue(priv->hw, txq_id);
if (tid != MAX_TID_COUNT)
iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id);
#endif
}
#ifdef CONFIG_IWL4965_HT
#ifdef CONFIG_IWL4965_HT_AGG
}
#endif /* CONFIG_IWL4965_HT_AGG */
#endif /* CONFIG_IWL4965_HT */
if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
......@@ -9089,10 +9100,8 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
/* Default value; 4 EDCA QOS priorities */
hw->queues = 4;
#ifdef CONFIG_IWL4965_HT
#ifdef CONFIG_IWL4965_HT_AGG
/* Enhanced value; more queues, to support 11n aggregation */
hw->queues = 16;
#endif /* CONFIG_IWL4965_HT_AGG */
#endif /* CONFIG_IWL4965_HT */
spin_lock_init(&priv->lock);
......
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