Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3fd07a1e authored by Tomas Winkler's avatar Tomas Winkler Committed by John W. Linville
Browse files

iwlwifi: refactor TX response flow



This patch utilize 5000 new TX response command
which contains all necessary information and avoids
back referencing to the original TX frame.
It also change handling of software queue tracking
4965 flow is aligned with changes as much as possible.

Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Reviewed-by: default avatarZhu Yi <yi.zhu@intel.com>
Signed-off-by: default avatarReinette Chatre <reinette.chatre@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 8b30b1fe
Loading
Loading
Loading
Loading
+28 −35
Original line number Diff line number Diff line
@@ -822,7 +822,6 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
	}

	priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
	priv->hw_params.first_ampdu_q = IWL49_FIRST_AMPDU_QUEUE;
	priv->hw_params.max_stations = IWL4965_STATION_COUNT;
	priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID;
	priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE;
@@ -2059,7 +2058,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
	agg->rate_n_flags = rate_n_flags;
	agg->bitmap = 0;

	/* # frames attempted by Tx command */
	/* num frames attempted by Tx command */
	if (agg->frame_count == 1) {
		/* Only one frame was attempted; no block-ack will arrive */
		status = le16_to_cpu(frame_status[0].status);
@@ -2158,12 +2157,13 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
	int txq_id = SEQ_TO_QUEUE(sequence);
	int index = SEQ_TO_INDEX(sequence);
	struct iwl_tx_queue *txq = &priv->txq[txq_id];
	struct ieee80211_hdr *hdr;
	struct ieee80211_tx_info *info;
	struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
	u32  status = le32_to_cpu(tx_resp->u.status);
	int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION;
	__le16 fc;
	struct ieee80211_hdr *hdr;
	int tid = MAX_TID_COUNT;
	int sta_id;
	int freed;
	u8 *qc = NULL;

	if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
@@ -2178,8 +2178,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
	memset(&info->status, 0, sizeof(info->status));

	hdr = iwl_tx_queue_get_hdr(priv, txq_id, index);
	fc = hdr->frame_control;
	if (ieee80211_is_data_qos(fc)) {
	if (ieee80211_is_data_qos(hdr->frame_control)) {
		qc = ieee80211_get_qos_ctl(hdr);
		tid = qc[0] & 0xf;
	}
@@ -2194,8 +2193,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
		const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp);
		struct iwl_ht_agg *agg = NULL;

		if (!qc)
			return;
		WARN_ON(!qc);

		agg = &priv->stations[sta_id].tid[tid].agg;

@@ -2206,54 +2204,49 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
			info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;

		if (txq->q.read_ptr != (scd_ssn & 0xff)) {
			int freed, ampdu_q;
			index = iwl_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);
			freed = iwl_tx_queue_reclaim(priv, txq_id, index);
			priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;

			if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
			    txq_id >= 0 && priv->mac80211_registered &&
			    agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) {
				/* calculate mac80211 ampdu sw queue to wake */
				ampdu_q = txq_id - IWL49_FIRST_AMPDU_QUEUE +
					  priv->hw->queues;
			if (priv->mac80211_registered &&
			    (iwl_queue_space(&txq->q) > txq->q.low_mark) &&
			    (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) {
				if (agg->state == IWL_AGG_OFF)
					ieee80211_wake_queue(priv->hw, txq_id);
				else
					ieee80211_wake_queue(priv->hw, ampdu_q);
					ieee80211_wake_queue(priv->hw,
							     txq->swq_id);
			}
			iwl_txq_check_empty(priv, sta_id, tid, txq_id);
		}
	} else {
		info->status.rates[0].count = tx_resp->failure_frame + 1;
		info->flags |=
			iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0;
		info->flags |= iwl_is_tx_success(status) ?
					IEEE80211_TX_STAT_ACK : 0;
		iwl_hwrate_to_tx_control(priv,
					le32_to_cpu(tx_resp->rate_n_flags),
					info);

		IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags "
			     "0x%x retries %d\n", txq_id,
				iwl_get_tx_fail_reason(status),
				status, le32_to_cpu(tx_resp->rate_n_flags),
		IWL_DEBUG_TX_REPLY("TXQ %d status %s (0x%08x) "
				   "rate_n_flags 0x%x retries %d\n",
				   txq_id,
				   iwl_get_tx_fail_reason(status), status,
				   le32_to_cpu(tx_resp->rate_n_flags),
				   tx_resp->failure_frame);

		IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);

		if (index != -1) {
		    int freed = iwl_tx_queue_reclaim(priv, txq_id, index);
		    if (tid != MAX_TID_COUNT)
		freed = iwl_tx_queue_reclaim(priv, txq_id, index);
		if (qc)
			priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
		    if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
			(txq_id >= 0) && priv->mac80211_registered)

		if (priv->mac80211_registered &&
		    (iwl_queue_space(&txq->q) > txq->q.low_mark))
			ieee80211_wake_queue(priv->hw, txq_id);
		    if (tid != MAX_TID_COUNT)
			iwl_txq_check_empty(priv, sta_id, tid, txq_id);
		}
	}

	if (qc)
		iwl_txq_check_empty(priv, sta_id, tid, txq_id);

	if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
		IWL_ERROR("TODO:  Implement Tx ABORT REQUIRED!!!\n");
}
+34 −47
Original line number Diff line number Diff line
@@ -801,7 +801,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
	}

	priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
	priv->hw_params.first_ampdu_q = IWL50_FIRST_AMPDU_QUEUE;
	priv->hw_params.max_stations = IWL5000_STATION_COUNT;
	priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
	priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE;
@@ -1245,9 +1244,9 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
	struct ieee80211_tx_info *info;
	struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
	u32  status = le16_to_cpu(tx_resp->status.status);
	int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION;
	struct ieee80211_hdr *hdr;
	u8 *qc = NULL;
	int tid;
	int sta_id;
	int freed;

	if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
		IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
@@ -1260,25 +1259,13 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
	info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
	memset(&info->status, 0, sizeof(info->status));

	hdr = iwl_tx_queue_get_hdr(priv, txq_id, index);
	if (ieee80211_is_data_qos(hdr->frame_control)) {
		qc = ieee80211_get_qos_ctl(hdr);
		tid = qc[0] & 0xf;
	}

	sta_id = iwl_get_ra_sta_id(priv, hdr);
	if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) {
		IWL_ERROR("Station not known\n");
		return;
	}
	tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS;
	sta_id = (tx_resp->ra_tid & IWL50_TX_RES_RA_MSK) >> IWL50_TX_RES_RA_POS;

	if (txq->sched_retry) {
		const u32 scd_ssn = iwl5000_get_scd_ssn(tx_resp);
		struct iwl_ht_agg *agg = NULL;

		if (!qc)
			return;

		agg = &priv->stations[sta_id].tid[tid].agg;

		iwl5000_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index);
@@ -1288,53 +1275,53 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
			info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;

		if (txq->q.read_ptr != (scd_ssn & 0xff)) {
			int freed, ampdu_q;
			index = iwl_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);
			IWL_DEBUG_TX_REPLY("Retry scheduler reclaim "
					"scd_ssn=%d idx=%d txq=%d swq=%d\n",
					scd_ssn , index, txq_id, txq->swq_id);

			freed = iwl_tx_queue_reclaim(priv, txq_id, index);
			priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;

			if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
			    txq_id >= 0 && priv->mac80211_registered &&
			    agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) {
				/* calculate mac80211 ampdu sw queue to wake */
				ampdu_q = txq_id - IWL50_FIRST_AMPDU_QUEUE +
					  priv->hw->queues;
			if (priv->mac80211_registered &&
			    (iwl_queue_space(&txq->q) > txq->q.low_mark) &&
			    (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) {
				if (agg->state == IWL_AGG_OFF)
					ieee80211_wake_queue(priv->hw, txq_id);
				else
					ieee80211_wake_queue(priv->hw, ampdu_q);
					ieee80211_wake_queue(priv->hw,
							     txq->swq_id);
			}
			iwl_txq_check_empty(priv, sta_id, tid, txq_id);
		}
	} else {
		BUG_ON(txq_id != txq->swq_id);

		info->status.rates[0].count = tx_resp->failure_frame + 1;
		info->flags =
			iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0;
		info->flags |= iwl_is_tx_success(status) ?
					IEEE80211_TX_STAT_ACK : 0;
		iwl_hwrate_to_tx_control(priv,
					le32_to_cpu(tx_resp->rate_n_flags),
					info);

		IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags "
			     "0x%x retries %d\n", txq_id,
				iwl_get_tx_fail_reason(status),
				status, le32_to_cpu(tx_resp->rate_n_flags),
		IWL_DEBUG_TX_REPLY("TXQ %d status %s (0x%08x) rate_n_flags "
				   "0x%x retries %d\n",
				   txq_id,
				   iwl_get_tx_fail_reason(status), status,
				   le32_to_cpu(tx_resp->rate_n_flags),
				   tx_resp->failure_frame);

		IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
		if (index != -1) {
		    int freed = iwl_tx_queue_reclaim(priv, txq_id, index);
		    if (tid != MAX_TID_COUNT)
		freed = iwl_tx_queue_reclaim(priv, txq_id, index);
		if (ieee80211_is_data_qos(tx_resp->frame_ctrl))
			priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
		    if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
			(txq_id >= 0) && priv->mac80211_registered)

		if (priv->mac80211_registered &&
		    (iwl_queue_space(&txq->q) > txq->q.low_mark))
			ieee80211_wake_queue(priv->hw, txq_id);
		    if (tid != MAX_TID_COUNT)
			iwl_txq_check_empty(priv, sta_id, tid, txq_id);
		}
	}

	if (ieee80211_is_data_qos(tx_resp->frame_ctrl))
		iwl_txq_check_empty(priv, sta_id, tid, txq_id);

	if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
		IWL_ERROR("TODO:  Implement Tx ABORT REQUIRED!!!\n");
}
+37 −13
Original line number Diff line number Diff line
@@ -1423,11 +1423,11 @@ enum {
	TX_ABORT_REQUIRED_MSK = 0x80000000,	/* bits 31:31 */
};

static inline int iwl_is_tx_success(u32 status)
static inline bool iwl_is_tx_success(u32 status)
{
	status &= TX_STATUS_MSK;
	return (status == TX_STATUS_SUCCESS)
	    || (status == TX_STATUS_DIRECT_DONE);
	return (status == TX_STATUS_SUCCESS) ||
	       (status == TX_STATUS_DIRECT_DONE);
}


@@ -1452,8 +1452,7 @@ enum {
	AGG_TX_STATE_DELAY_TX_MSK = 0x400
};

#define AGG_TX_STATE_LAST_SENT_MSK \
(AGG_TX_STATE_LAST_SENT_TTL_MSK | \
#define AGG_TX_STATE_LAST_SENT_MSK  (AGG_TX_STATE_LAST_SENT_TTL_MSK | \
				     AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
				     AGG_TX_STATE_LAST_SENT_BT_KILL_MSK)

@@ -1528,6 +1527,28 @@ struct iwl4965_tx_resp {
	} u;
} __attribute__ ((packed));

/*
 * definitions for initial rate index field
 * bits [3:0] inital rate index
 * bits [6:4] rate table color, used for the initial rate
 * bit-7 invalid rate indication
 *   i.e. rate was not chosen from rate table
 *   or rate table color was changed during frame retries
 * refer tlc rate info
 */

#define IWL50_TX_RES_INIT_RATE_INDEX_POS	0
#define IWL50_TX_RES_INIT_RATE_INDEX_MSK	0x0f
#define IWL50_TX_RES_RATE_TABLE_COLOR_POS	4
#define IWL50_TX_RES_RATE_TABLE_COLOR_MSK	0x70
#define IWL50_TX_RES_INV_RATE_INDEX_MSK	0x80

/* refer to ra_tid */
#define IWL50_TX_RES_TID_POS	0
#define IWL50_TX_RES_TID_MSK	0x0f
#define IWL50_TX_RES_RA_POS	4
#define IWL50_TX_RES_RA_MSK	0xf0

struct iwl5000_tx_resp {
	u8 frame_count;		/* 1 no aggregation, >1 aggregation */
	u8 bt_kill_count;	/* # blocked by bluetooth (unused for agg) */
@@ -1542,14 +1563,17 @@ struct iwl5000_tx_resp {
	 * For agg:  RTS + CTS + aggregation tx time + block-ack time. */
	__le16 wireless_media_time;	/* uSecs */

	__le16 reserved;
	__le32 pa_power1;	/* RF power amplifier measurement (not used) */
	__le32 pa_power2;
	u8 pa_status;		/* RF power amplifier measurement (not used) */
	u8 pa_integ_res_a[3];
	u8 pa_integ_res_b[3];
	u8 pa_integ_res_C[3];

	__le32 tfd_info;
	__le16 seq_ctl;
	__le16 byte_cnt;
	__le32 tlc_info;
	u8 tlc_info;
	u8 ra_tid;		/* tid (0:3), sta_id (4:7) */
	__le16 frame_ctrl;
	/*
	 * For non-agg:  frame status TX_STATUS_*
	 * For agg:  status of 1st frame, AGG_TX_STATE_*; other frame status
+2 −0
Original line number Diff line number Diff line
@@ -183,6 +183,8 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
#define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a)
#define IWL_DEBUG_STATS_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_STATS, f, ## a)
#define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a)
#define IWL_DEBUG_TX_REPLY_LIMIT(f, a...) \
	IWL_DEBUG_LIMIT(IWL_DL_TX_REPLY, f, ## a)
#define IWL_DEBUG_QOS(f, a...)   IWL_DEBUG(IWL_DL_QOS, f, ## a)
#define IWL_DEBUG_RADIO(f, a...)  IWL_DEBUG(IWL_DL_RADIO, f, ## a)
#define IWL_DEBUG_POWER(f, a...)  IWL_DEBUG(IWL_DL_POWER, f, ## a)
+4 −5
Original line number Diff line number Diff line
@@ -135,9 +135,10 @@ struct iwl_tx_queue {
	struct iwl_tfd *tfds;
	struct iwl_cmd *cmd[TFD_TX_CMD_SLOTS];
	struct iwl_tx_info *txb;
	int need_update;
	int sched_retry;
	int active;
	u8 need_update;
	u8 sched_retry;
	u8 active;
	u8 swq_id;
};

#define IWL_NUM_SCAN_RATES         (2)
@@ -519,7 +520,6 @@ struct iwl_sensitivity_ranges {
 * @ct_kill_threshold: temperature threshold
 * @calib_init_cfg: setup initial claibrations for the hw
 * @struct iwl_sensitivity_ranges: range of sensitivity values
 * @first_ampdu_q: first HW queue available for ampdu
 */
struct iwl_hw_params {
	u16 max_txq_num;
@@ -541,7 +541,6 @@ struct iwl_hw_params {
	u32 ct_kill_threshold; /* value in hw-dependent units */
	u32 calib_init_cfg;
	const struct iwl_sensitivity_ranges *sens;
	u8 first_ampdu_q;
};

#define HT_SHORT_GI_20MHZ	(1 << 0)
Loading