| Wey-Yi Guy | be663ab | 2011-02-21 11:27:26 -0800 | [diff] [blame] | 1 | /****************************************************************************** | 
 | 2 |  * | 
 | 3 |  * GPL LICENSE SUMMARY | 
 | 4 |  * | 
 | 5 |  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | 
 | 6 |  * | 
 | 7 |  * This program is free software; you can redistribute it and/or modify | 
 | 8 |  * it under the terms of version 2 of the GNU General Public License as | 
 | 9 |  * published by the Free Software Foundation. | 
 | 10 |  * | 
 | 11 |  * This program is distributed in the hope that it will be useful, but | 
 | 12 |  * WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 13 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 | 14 |  * General Public License for more details. | 
 | 15 |  * | 
 | 16 |  * You should have received a copy of the GNU General Public License | 
 | 17 |  * along with this program; if not, write to the Free Software | 
 | 18 |  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | 
 | 19 |  * USA | 
 | 20 |  * | 
 | 21 |  * The full GNU General Public License is included in this distribution | 
 | 22 |  * in the file called LICENSE.GPL. | 
 | 23 |  * | 
 | 24 |  * Contact Information: | 
 | 25 |  *  Intel Linux Wireless <ilw@linux.intel.com> | 
 | 26 |  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | 
 | 27 |  * | 
 | 28 |  *****************************************************************************/ | 
 | 29 |  | 
 | 30 | #include <linux/kernel.h> | 
 | 31 | #include <linux/module.h> | 
 | 32 | #include <linux/init.h> | 
 | 33 | #include <linux/sched.h> | 
 | 34 |  | 
 | 35 | #include "iwl-dev.h" | 
 | 36 | #include "iwl-core.h" | 
 | 37 | #include "iwl-sta.h" | 
 | 38 | #include "iwl-io.h" | 
 | 39 | #include "iwl-helpers.h" | 
 | 40 | #include "iwl-4965-hw.h" | 
 | 41 | #include "iwl-4965.h" | 
 | 42 |  | 
 | 43 | /* | 
 | 44 |  * mac80211 queues, ACs, hardware queues, FIFOs. | 
 | 45 |  * | 
 | 46 |  * Cf. http://wireless.kernel.org/en/developers/Documentation/mac80211/queues | 
 | 47 |  * | 
 | 48 |  * Mac80211 uses the following numbers, which we get as from it | 
 | 49 |  * by way of skb_get_queue_mapping(skb): | 
 | 50 |  * | 
 | 51 |  *	VO	0 | 
 | 52 |  *	VI	1 | 
 | 53 |  *	BE	2 | 
 | 54 |  *	BK	3 | 
 | 55 |  * | 
 | 56 |  * | 
 | 57 |  * Regular (not A-MPDU) frames are put into hardware queues corresponding | 
 | 58 |  * to the FIFOs, see comments in iwl-prph.h. Aggregated frames get their | 
 | 59 |  * own queue per aggregation session (RA/TID combination), such queues are | 
 | 60 |  * set up to map into FIFOs too, for which we need an AC->FIFO mapping. In | 
 | 61 |  * order to map frames to the right queue, we also need an AC->hw queue | 
 | 62 |  * mapping. This is implemented here. | 
 | 63 |  * | 
 | 64 |  * Due to the way hw queues are set up (by the hw specific modules like | 
 | 65 |  * iwl-4965.c), the AC->hw queue mapping is the identity | 
 | 66 |  * mapping. | 
 | 67 |  */ | 
 | 68 |  | 
 | 69 | static const u8 tid_to_ac[] = { | 
 | 70 | 	IEEE80211_AC_BE, | 
 | 71 | 	IEEE80211_AC_BK, | 
 | 72 | 	IEEE80211_AC_BK, | 
 | 73 | 	IEEE80211_AC_BE, | 
 | 74 | 	IEEE80211_AC_VI, | 
 | 75 | 	IEEE80211_AC_VI, | 
 | 76 | 	IEEE80211_AC_VO, | 
 | 77 | 	IEEE80211_AC_VO | 
 | 78 | }; | 
 | 79 |  | 
 | 80 | static inline int iwl4965_get_ac_from_tid(u16 tid) | 
 | 81 | { | 
 | 82 | 	if (likely(tid < ARRAY_SIZE(tid_to_ac))) | 
 | 83 | 		return tid_to_ac[tid]; | 
 | 84 |  | 
 | 85 | 	/* no support for TIDs 8-15 yet */ | 
 | 86 | 	return -EINVAL; | 
 | 87 | } | 
 | 88 |  | 
 | 89 | static inline int | 
 | 90 | iwl4965_get_fifo_from_tid(struct iwl_rxon_context *ctx, u16 tid) | 
 | 91 | { | 
 | 92 | 	if (likely(tid < ARRAY_SIZE(tid_to_ac))) | 
 | 93 | 		return ctx->ac_to_fifo[tid_to_ac[tid]]; | 
 | 94 |  | 
 | 95 | 	/* no support for TIDs 8-15 yet */ | 
 | 96 | 	return -EINVAL; | 
 | 97 | } | 
 | 98 |  | 
 | 99 | /* | 
 | 100 |  * handle build REPLY_TX command notification. | 
 | 101 |  */ | 
 | 102 | static void iwl4965_tx_cmd_build_basic(struct iwl_priv *priv, | 
 | 103 | 					struct sk_buff *skb, | 
 | 104 | 					struct iwl_tx_cmd *tx_cmd, | 
 | 105 | 					struct ieee80211_tx_info *info, | 
 | 106 | 					struct ieee80211_hdr *hdr, | 
 | 107 | 					u8 std_id) | 
 | 108 | { | 
 | 109 | 	__le16 fc = hdr->frame_control; | 
 | 110 | 	__le32 tx_flags = tx_cmd->tx_flags; | 
 | 111 |  | 
 | 112 | 	tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; | 
 | 113 | 	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { | 
 | 114 | 		tx_flags |= TX_CMD_FLG_ACK_MSK; | 
 | 115 | 		if (ieee80211_is_mgmt(fc)) | 
 | 116 | 			tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; | 
 | 117 | 		if (ieee80211_is_probe_resp(fc) && | 
 | 118 | 		    !(le16_to_cpu(hdr->seq_ctrl) & 0xf)) | 
 | 119 | 			tx_flags |= TX_CMD_FLG_TSF_MSK; | 
 | 120 | 	} else { | 
 | 121 | 		tx_flags &= (~TX_CMD_FLG_ACK_MSK); | 
 | 122 | 		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; | 
 | 123 | 	} | 
 | 124 |  | 
 | 125 | 	if (ieee80211_is_back_req(fc)) | 
 | 126 | 		tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK; | 
 | 127 |  | 
 | 128 | 	tx_cmd->sta_id = std_id; | 
 | 129 | 	if (ieee80211_has_morefrags(fc)) | 
 | 130 | 		tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; | 
 | 131 |  | 
 | 132 | 	if (ieee80211_is_data_qos(fc)) { | 
 | 133 | 		u8 *qc = ieee80211_get_qos_ctl(hdr); | 
 | 134 | 		tx_cmd->tid_tspec = qc[0] & 0xf; | 
 | 135 | 		tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; | 
 | 136 | 	} else { | 
 | 137 | 		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; | 
 | 138 | 	} | 
 | 139 |  | 
 | 140 | 	iwl_legacy_tx_cmd_protection(priv, info, fc, &tx_flags); | 
 | 141 |  | 
 | 142 | 	tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); | 
 | 143 | 	if (ieee80211_is_mgmt(fc)) { | 
 | 144 | 		if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) | 
 | 145 | 			tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3); | 
 | 146 | 		else | 
 | 147 | 			tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2); | 
 | 148 | 	} else { | 
 | 149 | 		tx_cmd->timeout.pm_frame_timeout = 0; | 
 | 150 | 	} | 
 | 151 |  | 
 | 152 | 	tx_cmd->driver_txop = 0; | 
 | 153 | 	tx_cmd->tx_flags = tx_flags; | 
 | 154 | 	tx_cmd->next_frame_len = 0; | 
 | 155 | } | 
 | 156 |  | 
 | 157 | #define RTS_DFAULT_RETRY_LIMIT		60 | 
 | 158 |  | 
 | 159 | static void iwl4965_tx_cmd_build_rate(struct iwl_priv *priv, | 
 | 160 | 			      struct iwl_tx_cmd *tx_cmd, | 
 | 161 | 			      struct ieee80211_tx_info *info, | 
 | 162 | 			      __le16 fc) | 
 | 163 | { | 
 | 164 | 	u32 rate_flags; | 
 | 165 | 	int rate_idx; | 
 | 166 | 	u8 rts_retry_limit; | 
 | 167 | 	u8 data_retry_limit; | 
 | 168 | 	u8 rate_plcp; | 
 | 169 |  | 
 | 170 | 	/* Set retry limit on DATA packets and Probe Responses*/ | 
 | 171 | 	if (ieee80211_is_probe_resp(fc)) | 
 | 172 | 		data_retry_limit = 3; | 
 | 173 | 	else | 
 | 174 | 		data_retry_limit = IWL4965_DEFAULT_TX_RETRY; | 
 | 175 | 	tx_cmd->data_retry_limit = data_retry_limit; | 
 | 176 |  | 
 | 177 | 	/* Set retry limit on RTS packets */ | 
 | 178 | 	rts_retry_limit = RTS_DFAULT_RETRY_LIMIT; | 
 | 179 | 	if (data_retry_limit < rts_retry_limit) | 
 | 180 | 		rts_retry_limit = data_retry_limit; | 
 | 181 | 	tx_cmd->rts_retry_limit = rts_retry_limit; | 
 | 182 |  | 
 | 183 | 	/* DATA packets will use the uCode station table for rate/antenna | 
 | 184 | 	 * selection */ | 
 | 185 | 	if (ieee80211_is_data(fc)) { | 
 | 186 | 		tx_cmd->initial_rate_index = 0; | 
 | 187 | 		tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK; | 
 | 188 | 		return; | 
 | 189 | 	} | 
 | 190 |  | 
 | 191 | 	/** | 
 | 192 | 	 * If the current TX rate stored in mac80211 has the MCS bit set, it's | 
 | 193 | 	 * not really a TX rate.  Thus, we use the lowest supported rate for | 
 | 194 | 	 * this band.  Also use the lowest supported rate if the stored rate | 
 | 195 | 	 * index is invalid. | 
 | 196 | 	 */ | 
 | 197 | 	rate_idx = info->control.rates[0].idx; | 
 | 198 | 	if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS || | 
 | 199 | 			(rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY)) | 
 | 200 | 		rate_idx = rate_lowest_index(&priv->bands[info->band], | 
 | 201 | 				info->control.sta); | 
 | 202 | 	/* For 5 GHZ band, remap mac80211 rate indices into driver indices */ | 
 | 203 | 	if (info->band == IEEE80211_BAND_5GHZ) | 
 | 204 | 		rate_idx += IWL_FIRST_OFDM_RATE; | 
 | 205 | 	/* Get PLCP rate for tx_cmd->rate_n_flags */ | 
| John W. Linville | ef33417 | 2011-02-25 15:51:01 -0500 | [diff] [blame] | 206 | 	rate_plcp = iwlegacy_rates[rate_idx].plcp; | 
| Wey-Yi Guy | be663ab | 2011-02-21 11:27:26 -0800 | [diff] [blame] | 207 | 	/* Zero out flags for this packet */ | 
 | 208 | 	rate_flags = 0; | 
 | 209 |  | 
 | 210 | 	/* Set CCK flag as needed */ | 
 | 211 | 	if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) | 
 | 212 | 		rate_flags |= RATE_MCS_CCK_MSK; | 
 | 213 |  | 
 | 214 | 	/* Set up antennas */ | 
 | 215 | 	priv->mgmt_tx_ant = iwl4965_toggle_tx_ant(priv, priv->mgmt_tx_ant, | 
 | 216 | 				      priv->hw_params.valid_tx_ant); | 
 | 217 |  | 
 | 218 | 	rate_flags |= iwl4965_ant_idx_to_flags(priv->mgmt_tx_ant); | 
 | 219 |  | 
 | 220 | 	/* Set the rate in the TX cmd */ | 
 | 221 | 	tx_cmd->rate_n_flags = iwl4965_hw_set_rate_n_flags(rate_plcp, rate_flags); | 
 | 222 | } | 
 | 223 |  | 
 | 224 | static void iwl4965_tx_cmd_build_hwcrypto(struct iwl_priv *priv, | 
 | 225 | 				      struct ieee80211_tx_info *info, | 
 | 226 | 				      struct iwl_tx_cmd *tx_cmd, | 
 | 227 | 				      struct sk_buff *skb_frag, | 
 | 228 | 				      int sta_id) | 
 | 229 | { | 
 | 230 | 	struct ieee80211_key_conf *keyconf = info->control.hw_key; | 
 | 231 |  | 
 | 232 | 	switch (keyconf->cipher) { | 
 | 233 | 	case WLAN_CIPHER_SUITE_CCMP: | 
 | 234 | 		tx_cmd->sec_ctl = TX_CMD_SEC_CCM; | 
 | 235 | 		memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); | 
 | 236 | 		if (info->flags & IEEE80211_TX_CTL_AMPDU) | 
 | 237 | 			tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; | 
 | 238 | 		IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n"); | 
 | 239 | 		break; | 
 | 240 |  | 
 | 241 | 	case WLAN_CIPHER_SUITE_TKIP: | 
 | 242 | 		tx_cmd->sec_ctl = TX_CMD_SEC_TKIP; | 
 | 243 | 		ieee80211_get_tkip_key(keyconf, skb_frag, | 
 | 244 | 			IEEE80211_TKIP_P2_KEY, tx_cmd->key); | 
 | 245 | 		IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n"); | 
 | 246 | 		break; | 
 | 247 |  | 
 | 248 | 	case WLAN_CIPHER_SUITE_WEP104: | 
 | 249 | 		tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; | 
 | 250 | 		/* fall through */ | 
 | 251 | 	case WLAN_CIPHER_SUITE_WEP40: | 
 | 252 | 		tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP | | 
 | 253 | 			(keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT); | 
 | 254 |  | 
 | 255 | 		memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen); | 
 | 256 |  | 
 | 257 | 		IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption " | 
 | 258 | 			     "with key %d\n", keyconf->keyidx); | 
 | 259 | 		break; | 
 | 260 |  | 
 | 261 | 	default: | 
 | 262 | 		IWL_ERR(priv, "Unknown encode cipher %x\n", keyconf->cipher); | 
 | 263 | 		break; | 
 | 264 | 	} | 
 | 265 | } | 
 | 266 |  | 
 | 267 | /* | 
 | 268 |  * start REPLY_TX command process | 
 | 269 |  */ | 
 | 270 | int iwl4965_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | 
 | 271 | { | 
 | 272 | 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 
 | 273 | 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 
 | 274 | 	struct ieee80211_sta *sta = info->control.sta; | 
 | 275 | 	struct iwl_station_priv *sta_priv = NULL; | 
 | 276 | 	struct iwl_tx_queue *txq; | 
 | 277 | 	struct iwl_queue *q; | 
 | 278 | 	struct iwl_device_cmd *out_cmd; | 
 | 279 | 	struct iwl_cmd_meta *out_meta; | 
 | 280 | 	struct iwl_tx_cmd *tx_cmd; | 
 | 281 | 	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; | 
 | 282 | 	int txq_id; | 
 | 283 | 	dma_addr_t phys_addr; | 
 | 284 | 	dma_addr_t txcmd_phys; | 
 | 285 | 	dma_addr_t scratch_phys; | 
 | 286 | 	u16 len, firstlen, secondlen; | 
 | 287 | 	u16 seq_number = 0; | 
 | 288 | 	__le16 fc; | 
 | 289 | 	u8 hdr_len; | 
 | 290 | 	u8 sta_id; | 
 | 291 | 	u8 wait_write_ptr = 0; | 
 | 292 | 	u8 tid = 0; | 
 | 293 | 	u8 *qc = NULL; | 
 | 294 | 	unsigned long flags; | 
 | 295 | 	bool is_agg = false; | 
 | 296 |  | 
 | 297 | 	if (info->control.vif) | 
 | 298 | 		ctx = iwl_legacy_rxon_ctx_from_vif(info->control.vif); | 
 | 299 |  | 
 | 300 | 	spin_lock_irqsave(&priv->lock, flags); | 
 | 301 | 	if (iwl_legacy_is_rfkill(priv)) { | 
 | 302 | 		IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n"); | 
 | 303 | 		goto drop_unlock; | 
 | 304 | 	} | 
 | 305 |  | 
 | 306 | 	fc = hdr->frame_control; | 
 | 307 |  | 
 | 308 | #ifdef CONFIG_IWLWIFI_LEGACY_DEBUG | 
 | 309 | 	if (ieee80211_is_auth(fc)) | 
 | 310 | 		IWL_DEBUG_TX(priv, "Sending AUTH frame\n"); | 
 | 311 | 	else if (ieee80211_is_assoc_req(fc)) | 
 | 312 | 		IWL_DEBUG_TX(priv, "Sending ASSOC frame\n"); | 
 | 313 | 	else if (ieee80211_is_reassoc_req(fc)) | 
 | 314 | 		IWL_DEBUG_TX(priv, "Sending REASSOC frame\n"); | 
 | 315 | #endif | 
 | 316 |  | 
 | 317 | 	hdr_len = ieee80211_hdrlen(fc); | 
 | 318 |  | 
 | 319 | 	/* Find index into station table for destination station */ | 
 | 320 | 	sta_id = iwl_legacy_sta_id_or_broadcast(priv, ctx, info->control.sta); | 
 | 321 | 	if (sta_id == IWL_INVALID_STATION) { | 
 | 322 | 		IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", | 
 | 323 | 			       hdr->addr1); | 
 | 324 | 		goto drop_unlock; | 
 | 325 | 	} | 
 | 326 |  | 
 | 327 | 	IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); | 
 | 328 |  | 
 | 329 | 	if (sta) | 
 | 330 | 		sta_priv = (void *)sta->drv_priv; | 
 | 331 |  | 
 | 332 | 	if (sta_priv && sta_priv->asleep && | 
 | 333 | 	    (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)) { | 
 | 334 | 		/* | 
 | 335 | 		 * This sends an asynchronous command to the device, | 
 | 336 | 		 * but we can rely on it being processed before the | 
 | 337 | 		 * next frame is processed -- and the next frame to | 
 | 338 | 		 * this station is the one that will consume this | 
 | 339 | 		 * counter. | 
 | 340 | 		 * For now set the counter to just 1 since we do not | 
 | 341 | 		 * support uAPSD yet. | 
 | 342 | 		 */ | 
 | 343 | 		iwl4965_sta_modify_sleep_tx_count(priv, sta_id, 1); | 
 | 344 | 	} | 
 | 345 |  | 
 | 346 | 	/* | 
 | 347 | 	 * Send this frame after DTIM -- there's a special queue | 
 | 348 | 	 * reserved for this for contexts that support AP mode. | 
 | 349 | 	 */ | 
 | 350 | 	if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { | 
 | 351 | 		txq_id = ctx->mcast_queue; | 
 | 352 | 		/* | 
 | 353 | 		 * The microcode will clear the more data | 
 | 354 | 		 * bit in the last frame it transmits. | 
 | 355 | 		 */ | 
 | 356 | 		hdr->frame_control |= | 
 | 357 | 			cpu_to_le16(IEEE80211_FCTL_MOREDATA); | 
 | 358 | 	} else | 
 | 359 | 		txq_id = ctx->ac_to_queue[skb_get_queue_mapping(skb)]; | 
 | 360 |  | 
 | 361 | 	/* irqs already disabled/saved above when locking priv->lock */ | 
 | 362 | 	spin_lock(&priv->sta_lock); | 
 | 363 |  | 
 | 364 | 	if (ieee80211_is_data_qos(fc)) { | 
 | 365 | 		qc = ieee80211_get_qos_ctl(hdr); | 
 | 366 | 		tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; | 
 | 367 | 		if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) { | 
 | 368 | 			spin_unlock(&priv->sta_lock); | 
 | 369 | 			goto drop_unlock; | 
 | 370 | 		} | 
 | 371 | 		seq_number = priv->stations[sta_id].tid[tid].seq_number; | 
 | 372 | 		seq_number &= IEEE80211_SCTL_SEQ; | 
 | 373 | 		hdr->seq_ctrl = hdr->seq_ctrl & | 
 | 374 | 				cpu_to_le16(IEEE80211_SCTL_FRAG); | 
 | 375 | 		hdr->seq_ctrl |= cpu_to_le16(seq_number); | 
 | 376 | 		seq_number += 0x10; | 
 | 377 | 		/* aggregation is on for this <sta,tid> */ | 
 | 378 | 		if (info->flags & IEEE80211_TX_CTL_AMPDU && | 
 | 379 | 		    priv->stations[sta_id].tid[tid].agg.state == IWL_AGG_ON) { | 
 | 380 | 			txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; | 
 | 381 | 			is_agg = true; | 
 | 382 | 		} | 
 | 383 | 	} | 
 | 384 |  | 
 | 385 | 	txq = &priv->txq[txq_id]; | 
 | 386 | 	q = &txq->q; | 
 | 387 |  | 
 | 388 | 	if (unlikely(iwl_legacy_queue_space(q) < q->high_mark)) { | 
 | 389 | 		spin_unlock(&priv->sta_lock); | 
 | 390 | 		goto drop_unlock; | 
 | 391 | 	} | 
 | 392 |  | 
 | 393 | 	if (ieee80211_is_data_qos(fc)) { | 
 | 394 | 		priv->stations[sta_id].tid[tid].tfds_in_queue++; | 
 | 395 | 		if (!ieee80211_has_morefrags(fc)) | 
 | 396 | 			priv->stations[sta_id].tid[tid].seq_number = seq_number; | 
 | 397 | 	} | 
 | 398 |  | 
 | 399 | 	spin_unlock(&priv->sta_lock); | 
 | 400 |  | 
 | 401 | 	/* Set up driver data for this TFD */ | 
 | 402 | 	memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); | 
 | 403 | 	txq->txb[q->write_ptr].skb = skb; | 
 | 404 | 	txq->txb[q->write_ptr].ctx = ctx; | 
 | 405 |  | 
 | 406 | 	/* Set up first empty entry in queue's array of Tx/cmd buffers */ | 
 | 407 | 	out_cmd = txq->cmd[q->write_ptr]; | 
 | 408 | 	out_meta = &txq->meta[q->write_ptr]; | 
 | 409 | 	tx_cmd = &out_cmd->cmd.tx; | 
 | 410 | 	memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); | 
 | 411 | 	memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd)); | 
 | 412 |  | 
 | 413 | 	/* | 
 | 414 | 	 * Set up the Tx-command (not MAC!) header. | 
 | 415 | 	 * Store the chosen Tx queue and TFD index within the sequence field; | 
 | 416 | 	 * after Tx, uCode's Tx response will return this value so driver can | 
 | 417 | 	 * locate the frame within the tx queue and do post-tx processing. | 
 | 418 | 	 */ | 
 | 419 | 	out_cmd->hdr.cmd = REPLY_TX; | 
 | 420 | 	out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | | 
 | 421 | 				INDEX_TO_SEQ(q->write_ptr))); | 
 | 422 |  | 
 | 423 | 	/* Copy MAC header from skb into command buffer */ | 
 | 424 | 	memcpy(tx_cmd->hdr, hdr, hdr_len); | 
 | 425 |  | 
 | 426 |  | 
 | 427 | 	/* Total # bytes to be transmitted */ | 
 | 428 | 	len = (u16)skb->len; | 
 | 429 | 	tx_cmd->len = cpu_to_le16(len); | 
 | 430 |  | 
 | 431 | 	if (info->control.hw_key) | 
 | 432 | 		iwl4965_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id); | 
 | 433 |  | 
 | 434 | 	/* TODO need this for burst mode later on */ | 
 | 435 | 	iwl4965_tx_cmd_build_basic(priv, skb, tx_cmd, info, hdr, sta_id); | 
 | 436 | 	iwl_legacy_dbg_log_tx_data_frame(priv, len, hdr); | 
 | 437 |  | 
 | 438 | 	iwl4965_tx_cmd_build_rate(priv, tx_cmd, info, fc); | 
 | 439 |  | 
 | 440 | 	iwl_legacy_update_stats(priv, true, fc, len); | 
 | 441 | 	/* | 
 | 442 | 	 * Use the first empty entry in this queue's command buffer array | 
 | 443 | 	 * to contain the Tx command and MAC header concatenated together | 
 | 444 | 	 * (payload data will be in another buffer). | 
 | 445 | 	 * Size of this varies, due to varying MAC header length. | 
 | 446 | 	 * If end is not dword aligned, we'll have 2 extra bytes at the end | 
 | 447 | 	 * of the MAC header (device reads on dword boundaries). | 
 | 448 | 	 * We'll tell device about this padding later. | 
 | 449 | 	 */ | 
 | 450 | 	len = sizeof(struct iwl_tx_cmd) + | 
 | 451 | 		sizeof(struct iwl_cmd_header) + hdr_len; | 
 | 452 | 	firstlen = (len + 3) & ~3; | 
 | 453 |  | 
 | 454 | 	/* Tell NIC about any 2-byte padding after MAC header */ | 
 | 455 | 	if (firstlen != len) | 
 | 456 | 		tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; | 
 | 457 |  | 
 | 458 | 	/* Physical address of this Tx command's header (not MAC header!), | 
 | 459 | 	 * within command buffer array. */ | 
 | 460 | 	txcmd_phys = pci_map_single(priv->pci_dev, | 
 | 461 | 				    &out_cmd->hdr, firstlen, | 
 | 462 | 				    PCI_DMA_BIDIRECTIONAL); | 
 | 463 | 	dma_unmap_addr_set(out_meta, mapping, txcmd_phys); | 
 | 464 | 	dma_unmap_len_set(out_meta, len, firstlen); | 
 | 465 | 	/* Add buffer containing Tx command and MAC(!) header to TFD's | 
 | 466 | 	 * first entry */ | 
 | 467 | 	priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, | 
 | 468 | 						   txcmd_phys, firstlen, 1, 0); | 
 | 469 |  | 
 | 470 | 	if (!ieee80211_has_morefrags(hdr->frame_control)) { | 
 | 471 | 		txq->need_update = 1; | 
 | 472 | 	} else { | 
 | 473 | 		wait_write_ptr = 1; | 
 | 474 | 		txq->need_update = 0; | 
 | 475 | 	} | 
 | 476 |  | 
 | 477 | 	/* Set up TFD's 2nd entry to point directly to remainder of skb, | 
 | 478 | 	 * if any (802.11 null frames have no payload). */ | 
 | 479 | 	secondlen = skb->len - hdr_len; | 
 | 480 | 	if (secondlen > 0) { | 
 | 481 | 		phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, | 
 | 482 | 					   secondlen, PCI_DMA_TODEVICE); | 
 | 483 | 		priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, | 
 | 484 | 							   phys_addr, secondlen, | 
 | 485 | 							   0, 0); | 
 | 486 | 	} | 
 | 487 |  | 
 | 488 | 	scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + | 
 | 489 | 				offsetof(struct iwl_tx_cmd, scratch); | 
 | 490 |  | 
 | 491 | 	/* take back ownership of DMA buffer to enable update */ | 
 | 492 | 	pci_dma_sync_single_for_cpu(priv->pci_dev, txcmd_phys, | 
 | 493 | 				    firstlen, PCI_DMA_BIDIRECTIONAL); | 
 | 494 | 	tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); | 
 | 495 | 	tx_cmd->dram_msb_ptr = iwl_legacy_get_dma_hi_addr(scratch_phys); | 
 | 496 |  | 
 | 497 | 	IWL_DEBUG_TX(priv, "sequence nr = 0X%x\n", | 
 | 498 | 		     le16_to_cpu(out_cmd->hdr.sequence)); | 
 | 499 | 	IWL_DEBUG_TX(priv, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); | 
 | 500 | 	iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); | 
 | 501 | 	iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); | 
 | 502 |  | 
 | 503 | 	/* Set up entry for this TFD in Tx byte-count array */ | 
 | 504 | 	if (info->flags & IEEE80211_TX_CTL_AMPDU) | 
 | 505 | 		priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, | 
 | 506 | 						     le16_to_cpu(tx_cmd->len)); | 
 | 507 |  | 
 | 508 | 	pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys, | 
 | 509 | 				       firstlen, PCI_DMA_BIDIRECTIONAL); | 
 | 510 |  | 
 | 511 | 	trace_iwlwifi_legacy_dev_tx(priv, | 
 | 512 | 			     &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr], | 
 | 513 | 			     sizeof(struct iwl_tfd), | 
 | 514 | 			     &out_cmd->hdr, firstlen, | 
 | 515 | 			     skb->data + hdr_len, secondlen); | 
 | 516 |  | 
 | 517 | 	/* Tell device the write index *just past* this latest filled TFD */ | 
 | 518 | 	q->write_ptr = iwl_legacy_queue_inc_wrap(q->write_ptr, q->n_bd); | 
 | 519 | 	iwl_legacy_txq_update_write_ptr(priv, txq); | 
 | 520 | 	spin_unlock_irqrestore(&priv->lock, flags); | 
 | 521 |  | 
 | 522 | 	/* | 
 | 523 | 	 * At this point the frame is "transmitted" successfully | 
 | 524 | 	 * and we will get a TX status notification eventually, | 
 | 525 | 	 * regardless of the value of ret. "ret" only indicates | 
 | 526 | 	 * whether or not we should update the write pointer. | 
 | 527 | 	 */ | 
 | 528 |  | 
 | 529 | 	/* | 
 | 530 | 	 * Avoid atomic ops if it isn't an associated client. | 
 | 531 | 	 * Also, if this is a packet for aggregation, don't | 
 | 532 | 	 * increase the counter because the ucode will stop | 
 | 533 | 	 * aggregation queues when their respective station | 
 | 534 | 	 * goes to sleep. | 
 | 535 | 	 */ | 
 | 536 | 	if (sta_priv && sta_priv->client && !is_agg) | 
 | 537 | 		atomic_inc(&sta_priv->pending_frames); | 
 | 538 |  | 
 | 539 | 	if ((iwl_legacy_queue_space(q) < q->high_mark) && | 
 | 540 | 			priv->mac80211_registered) { | 
 | 541 | 		if (wait_write_ptr) { | 
 | 542 | 			spin_lock_irqsave(&priv->lock, flags); | 
 | 543 | 			txq->need_update = 1; | 
 | 544 | 			iwl_legacy_txq_update_write_ptr(priv, txq); | 
 | 545 | 			spin_unlock_irqrestore(&priv->lock, flags); | 
 | 546 | 		} else { | 
 | 547 | 			iwl_legacy_stop_queue(priv, txq); | 
 | 548 | 		} | 
 | 549 | 	} | 
 | 550 |  | 
 | 551 | 	return 0; | 
 | 552 |  | 
 | 553 | drop_unlock: | 
 | 554 | 	spin_unlock_irqrestore(&priv->lock, flags); | 
 | 555 | 	return -1; | 
 | 556 | } | 
 | 557 |  | 
 | 558 | static inline int iwl4965_alloc_dma_ptr(struct iwl_priv *priv, | 
 | 559 | 				    struct iwl_dma_ptr *ptr, size_t size) | 
 | 560 | { | 
 | 561 | 	ptr->addr = dma_alloc_coherent(&priv->pci_dev->dev, size, &ptr->dma, | 
 | 562 | 				       GFP_KERNEL); | 
 | 563 | 	if (!ptr->addr) | 
 | 564 | 		return -ENOMEM; | 
 | 565 | 	ptr->size = size; | 
 | 566 | 	return 0; | 
 | 567 | } | 
 | 568 |  | 
 | 569 | static inline void iwl4965_free_dma_ptr(struct iwl_priv *priv, | 
 | 570 | 				    struct iwl_dma_ptr *ptr) | 
 | 571 | { | 
 | 572 | 	if (unlikely(!ptr->addr)) | 
 | 573 | 		return; | 
 | 574 |  | 
 | 575 | 	dma_free_coherent(&priv->pci_dev->dev, ptr->size, ptr->addr, ptr->dma); | 
 | 576 | 	memset(ptr, 0, sizeof(*ptr)); | 
 | 577 | } | 
 | 578 |  | 
 | 579 | /** | 
 | 580 |  * iwl4965_hw_txq_ctx_free - Free TXQ Context | 
 | 581 |  * | 
 | 582 |  * Destroy all TX DMA queues and structures | 
 | 583 |  */ | 
 | 584 | void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv) | 
 | 585 | { | 
 | 586 | 	int txq_id; | 
 | 587 |  | 
 | 588 | 	/* Tx queues */ | 
 | 589 | 	if (priv->txq) { | 
 | 590 | 		for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) | 
 | 591 | 			if (txq_id == priv->cmd_queue) | 
 | 592 | 				iwl_legacy_cmd_queue_free(priv); | 
 | 593 | 			else | 
 | 594 | 				iwl_legacy_tx_queue_free(priv, txq_id); | 
 | 595 | 	} | 
 | 596 | 	iwl4965_free_dma_ptr(priv, &priv->kw); | 
 | 597 |  | 
 | 598 | 	iwl4965_free_dma_ptr(priv, &priv->scd_bc_tbls); | 
 | 599 |  | 
 | 600 | 	/* free tx queue structure */ | 
 | 601 | 	iwl_legacy_txq_mem(priv); | 
 | 602 | } | 
 | 603 |  | 
 | 604 | /** | 
 | 605 |  * iwl4965_txq_ctx_alloc - allocate TX queue context | 
 | 606 |  * Allocate all Tx DMA structures and initialize them | 
 | 607 |  * | 
 | 608 |  * @param priv | 
 | 609 |  * @return error code | 
 | 610 |  */ | 
 | 611 | int iwl4965_txq_ctx_alloc(struct iwl_priv *priv) | 
 | 612 | { | 
 | 613 | 	int ret; | 
 | 614 | 	int txq_id, slots_num; | 
 | 615 | 	unsigned long flags; | 
 | 616 |  | 
 | 617 | 	/* Free all tx/cmd queues and keep-warm buffer */ | 
 | 618 | 	iwl4965_hw_txq_ctx_free(priv); | 
 | 619 |  | 
 | 620 | 	ret = iwl4965_alloc_dma_ptr(priv, &priv->scd_bc_tbls, | 
 | 621 | 				priv->hw_params.scd_bc_tbls_size); | 
 | 622 | 	if (ret) { | 
 | 623 | 		IWL_ERR(priv, "Scheduler BC Table allocation failed\n"); | 
 | 624 | 		goto error_bc_tbls; | 
 | 625 | 	} | 
 | 626 | 	/* Alloc keep-warm buffer */ | 
 | 627 | 	ret = iwl4965_alloc_dma_ptr(priv, &priv->kw, IWL_KW_SIZE); | 
 | 628 | 	if (ret) { | 
 | 629 | 		IWL_ERR(priv, "Keep Warm allocation failed\n"); | 
 | 630 | 		goto error_kw; | 
 | 631 | 	} | 
 | 632 |  | 
 | 633 | 	/* allocate tx queue structure */ | 
 | 634 | 	ret = iwl_legacy_alloc_txq_mem(priv); | 
 | 635 | 	if (ret) | 
 | 636 | 		goto error; | 
 | 637 |  | 
 | 638 | 	spin_lock_irqsave(&priv->lock, flags); | 
 | 639 |  | 
 | 640 | 	/* Turn off all Tx DMA fifos */ | 
 | 641 | 	iwl4965_txq_set_sched(priv, 0); | 
 | 642 |  | 
 | 643 | 	/* Tell NIC where to find the "keep warm" buffer */ | 
 | 644 | 	iwl_legacy_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4); | 
 | 645 |  | 
 | 646 | 	spin_unlock_irqrestore(&priv->lock, flags); | 
 | 647 |  | 
 | 648 | 	/* Alloc and init all Tx queues, including the command queue (#4/#9) */ | 
 | 649 | 	for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { | 
 | 650 | 		slots_num = (txq_id == priv->cmd_queue) ? | 
 | 651 | 					TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; | 
 | 652 | 		ret = iwl_legacy_tx_queue_init(priv, | 
 | 653 | 					&priv->txq[txq_id], slots_num, | 
 | 654 | 				       txq_id); | 
 | 655 | 		if (ret) { | 
 | 656 | 			IWL_ERR(priv, "Tx %d queue init failed\n", txq_id); | 
 | 657 | 			goto error; | 
 | 658 | 		} | 
 | 659 | 	} | 
 | 660 |  | 
 | 661 | 	return ret; | 
 | 662 |  | 
 | 663 |  error: | 
 | 664 | 	iwl4965_hw_txq_ctx_free(priv); | 
 | 665 | 	iwl4965_free_dma_ptr(priv, &priv->kw); | 
 | 666 |  error_kw: | 
 | 667 | 	iwl4965_free_dma_ptr(priv, &priv->scd_bc_tbls); | 
 | 668 |  error_bc_tbls: | 
 | 669 | 	return ret; | 
 | 670 | } | 
 | 671 |  | 
 | 672 | void iwl4965_txq_ctx_reset(struct iwl_priv *priv) | 
 | 673 | { | 
 | 674 | 	int txq_id, slots_num; | 
 | 675 | 	unsigned long flags; | 
 | 676 |  | 
 | 677 | 	spin_lock_irqsave(&priv->lock, flags); | 
 | 678 |  | 
 | 679 | 	/* Turn off all Tx DMA fifos */ | 
 | 680 | 	iwl4965_txq_set_sched(priv, 0); | 
 | 681 |  | 
 | 682 | 	/* Tell NIC where to find the "keep warm" buffer */ | 
 | 683 | 	iwl_legacy_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4); | 
 | 684 |  | 
 | 685 | 	spin_unlock_irqrestore(&priv->lock, flags); | 
 | 686 |  | 
 | 687 | 	/* Alloc and init all Tx queues, including the command queue (#4) */ | 
 | 688 | 	for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { | 
 | 689 | 		slots_num = txq_id == priv->cmd_queue ? | 
 | 690 | 			    TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; | 
 | 691 | 		iwl_legacy_tx_queue_reset(priv, &priv->txq[txq_id], | 
 | 692 | 						slots_num, txq_id); | 
 | 693 | 	} | 
 | 694 | } | 
 | 695 |  | 
 | 696 | /** | 
 | 697 |  * iwl4965_txq_ctx_stop - Stop all Tx DMA channels | 
 | 698 |  */ | 
 | 699 | void iwl4965_txq_ctx_stop(struct iwl_priv *priv) | 
 | 700 | { | 
| Stanislaw Gruszka | 8a032c1 | 2011-02-28 14:33:14 +0100 | [diff] [blame^] | 701 | 	int ch, txq_id; | 
| Wey-Yi Guy | be663ab | 2011-02-21 11:27:26 -0800 | [diff] [blame] | 702 | 	unsigned long flags; | 
 | 703 |  | 
 | 704 | 	/* Turn off all Tx DMA fifos */ | 
 | 705 | 	spin_lock_irqsave(&priv->lock, flags); | 
 | 706 |  | 
 | 707 | 	iwl4965_txq_set_sched(priv, 0); | 
 | 708 |  | 
 | 709 | 	/* Stop each Tx DMA channel, and wait for it to be idle */ | 
 | 710 | 	for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) { | 
 | 711 | 		iwl_legacy_write_direct32(priv, | 
 | 712 | 				FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0); | 
 | 713 | 		if (iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG, | 
 | 714 | 				    FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), | 
 | 715 | 				    1000)) | 
 | 716 | 			IWL_ERR(priv, "Failing on timeout while stopping" | 
 | 717 | 			    " DMA channel %d [0x%08x]", ch, | 
 | 718 | 			    iwl_legacy_read_direct32(priv, | 
 | 719 | 					FH_TSSR_TX_STATUS_REG)); | 
 | 720 | 	} | 
 | 721 | 	spin_unlock_irqrestore(&priv->lock, flags); | 
| Stanislaw Gruszka | 8a032c1 | 2011-02-28 14:33:14 +0100 | [diff] [blame^] | 722 |  | 
 | 723 | 	if (!priv->txq) | 
 | 724 | 		return; | 
 | 725 |  | 
 | 726 | 	/* Unmap DMA from host system and free skb's */ | 
 | 727 | 	for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) | 
 | 728 | 		if (txq_id == priv->cmd_queue) | 
 | 729 | 			iwl_legacy_cmd_queue_unmap(priv); | 
 | 730 | 		else | 
 | 731 | 			iwl_legacy_tx_queue_unmap(priv, txq_id); | 
| Wey-Yi Guy | be663ab | 2011-02-21 11:27:26 -0800 | [diff] [blame] | 732 | } | 
 | 733 |  | 
 | 734 | /* | 
 | 735 |  * Find first available (lowest unused) Tx Queue, mark it "active". | 
 | 736 |  * Called only when finding queue for aggregation. | 
 | 737 |  * Should never return anything < 7, because they should already | 
 | 738 |  * be in use as EDCA AC (0-3), Command (4), reserved (5, 6) | 
 | 739 |  */ | 
 | 740 | static int iwl4965_txq_ctx_activate_free(struct iwl_priv *priv) | 
 | 741 | { | 
 | 742 | 	int txq_id; | 
 | 743 |  | 
 | 744 | 	for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) | 
 | 745 | 		if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk)) | 
 | 746 | 			return txq_id; | 
 | 747 | 	return -1; | 
 | 748 | } | 
 | 749 |  | 
 | 750 | /** | 
 | 751 |  * iwl4965_tx_queue_stop_scheduler - Stop queue, but keep configuration | 
 | 752 |  */ | 
 | 753 | static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv, | 
 | 754 | 					    u16 txq_id) | 
 | 755 | { | 
 | 756 | 	/* Simply stop the queue, but don't change any configuration; | 
 | 757 | 	 * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */ | 
 | 758 | 	iwl_legacy_write_prph(priv, | 
 | 759 | 		IWL49_SCD_QUEUE_STATUS_BITS(txq_id), | 
 | 760 | 		(0 << IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE)| | 
 | 761 | 		(1 << IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); | 
 | 762 | } | 
 | 763 |  | 
 | 764 | /** | 
 | 765 |  * iwl4965_tx_queue_set_q2ratid - Map unique receiver/tid combination to a queue | 
 | 766 |  */ | 
 | 767 | static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, | 
 | 768 | 					u16 txq_id) | 
 | 769 | { | 
 | 770 | 	u32 tbl_dw_addr; | 
 | 771 | 	u32 tbl_dw; | 
 | 772 | 	u16 scd_q2ratid; | 
 | 773 |  | 
 | 774 | 	scd_q2ratid = ra_tid & IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK; | 
 | 775 |  | 
 | 776 | 	tbl_dw_addr = priv->scd_base_addr + | 
 | 777 | 			IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id); | 
 | 778 |  | 
 | 779 | 	tbl_dw = iwl_legacy_read_targ_mem(priv, tbl_dw_addr); | 
 | 780 |  | 
 | 781 | 	if (txq_id & 0x1) | 
 | 782 | 		tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF); | 
 | 783 | 	else | 
 | 784 | 		tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000); | 
 | 785 |  | 
 | 786 | 	iwl_legacy_write_targ_mem(priv, tbl_dw_addr, tbl_dw); | 
 | 787 |  | 
 | 788 | 	return 0; | 
 | 789 | } | 
 | 790 |  | 
 | 791 | /** | 
 | 792 |  * iwl4965_tx_queue_agg_enable - Set up & enable aggregation for selected queue | 
 | 793 |  * | 
 | 794 |  * NOTE:  txq_id must be greater than IWL49_FIRST_AMPDU_QUEUE, | 
 | 795 |  *        i.e. it must be one of the higher queues used for aggregation | 
 | 796 |  */ | 
 | 797 | static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, | 
 | 798 | 				  int tx_fifo, int sta_id, int tid, u16 ssn_idx) | 
 | 799 | { | 
 | 800 | 	unsigned long flags; | 
 | 801 | 	u16 ra_tid; | 
 | 802 | 	int ret; | 
 | 803 |  | 
 | 804 | 	if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || | 
 | 805 | 	    (IWL49_FIRST_AMPDU_QUEUE + | 
 | 806 | 		priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { | 
 | 807 | 		IWL_WARN(priv, | 
 | 808 | 			"queue number out of range: %d, must be %d to %d\n", | 
 | 809 | 			txq_id, IWL49_FIRST_AMPDU_QUEUE, | 
 | 810 | 			IWL49_FIRST_AMPDU_QUEUE + | 
 | 811 | 			priv->cfg->base_params->num_of_ampdu_queues - 1); | 
 | 812 | 		return -EINVAL; | 
 | 813 | 	} | 
 | 814 |  | 
 | 815 | 	ra_tid = BUILD_RAxTID(sta_id, tid); | 
 | 816 |  | 
 | 817 | 	/* Modify device's station table to Tx this TID */ | 
 | 818 | 	ret = iwl4965_sta_tx_modify_enable_tid(priv, sta_id, tid); | 
 | 819 | 	if (ret) | 
 | 820 | 		return ret; | 
 | 821 |  | 
 | 822 | 	spin_lock_irqsave(&priv->lock, flags); | 
 | 823 |  | 
 | 824 | 	/* Stop this Tx queue before configuring it */ | 
 | 825 | 	iwl4965_tx_queue_stop_scheduler(priv, txq_id); | 
 | 826 |  | 
 | 827 | 	/* Map receiver-address / traffic-ID to this queue */ | 
 | 828 | 	iwl4965_tx_queue_set_q2ratid(priv, ra_tid, txq_id); | 
 | 829 |  | 
 | 830 | 	/* Set this queue as a chain-building queue */ | 
 | 831 | 	iwl_legacy_set_bits_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, (1 << txq_id)); | 
 | 832 |  | 
 | 833 | 	/* Place first TFD at index corresponding to start sequence number. | 
 | 834 | 	 * Assumes that ssn_idx is valid (!= 0xFFF) */ | 
 | 835 | 	priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff); | 
 | 836 | 	priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff); | 
 | 837 | 	iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx); | 
 | 838 |  | 
 | 839 | 	/* Set up Tx window size and frame limit for this queue */ | 
 | 840 | 	iwl_legacy_write_targ_mem(priv, | 
 | 841 | 		priv->scd_base_addr + IWL49_SCD_CONTEXT_QUEUE_OFFSET(txq_id), | 
 | 842 | 		(SCD_WIN_SIZE << IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & | 
 | 843 | 		IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); | 
 | 844 |  | 
 | 845 | 	iwl_legacy_write_targ_mem(priv, priv->scd_base_addr + | 
 | 846 | 		IWL49_SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), | 
 | 847 | 		(SCD_FRAME_LIMIT << IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) | 
 | 848 | 		& IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); | 
 | 849 |  | 
 | 850 | 	iwl_legacy_set_bits_prph(priv, IWL49_SCD_INTERRUPT_MASK, (1 << txq_id)); | 
 | 851 |  | 
 | 852 | 	/* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ | 
 | 853 | 	iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); | 
 | 854 |  | 
 | 855 | 	spin_unlock_irqrestore(&priv->lock, flags); | 
 | 856 |  | 
 | 857 | 	return 0; | 
 | 858 | } | 
 | 859 |  | 
 | 860 |  | 
 | 861 | int iwl4965_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, | 
 | 862 | 			struct ieee80211_sta *sta, u16 tid, u16 *ssn) | 
 | 863 | { | 
 | 864 | 	int sta_id; | 
 | 865 | 	int tx_fifo; | 
 | 866 | 	int txq_id; | 
 | 867 | 	int ret; | 
 | 868 | 	unsigned long flags; | 
 | 869 | 	struct iwl_tid_data *tid_data; | 
 | 870 |  | 
 | 871 | 	tx_fifo = iwl4965_get_fifo_from_tid(iwl_legacy_rxon_ctx_from_vif(vif), tid); | 
 | 872 | 	if (unlikely(tx_fifo < 0)) | 
 | 873 | 		return tx_fifo; | 
 | 874 |  | 
 | 875 | 	IWL_WARN(priv, "%s on ra = %pM tid = %d\n", | 
 | 876 | 			__func__, sta->addr, tid); | 
 | 877 |  | 
 | 878 | 	sta_id = iwl_legacy_sta_id(sta); | 
 | 879 | 	if (sta_id == IWL_INVALID_STATION) { | 
 | 880 | 		IWL_ERR(priv, "Start AGG on invalid station\n"); | 
 | 881 | 		return -ENXIO; | 
 | 882 | 	} | 
 | 883 | 	if (unlikely(tid >= MAX_TID_COUNT)) | 
 | 884 | 		return -EINVAL; | 
 | 885 |  | 
 | 886 | 	if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) { | 
 | 887 | 		IWL_ERR(priv, "Start AGG when state is not IWL_AGG_OFF !\n"); | 
 | 888 | 		return -ENXIO; | 
 | 889 | 	} | 
 | 890 |  | 
 | 891 | 	txq_id = iwl4965_txq_ctx_activate_free(priv); | 
 | 892 | 	if (txq_id == -1) { | 
 | 893 | 		IWL_ERR(priv, "No free aggregation queue available\n"); | 
 | 894 | 		return -ENXIO; | 
 | 895 | 	} | 
 | 896 |  | 
 | 897 | 	spin_lock_irqsave(&priv->sta_lock, flags); | 
 | 898 | 	tid_data = &priv->stations[sta_id].tid[tid]; | 
 | 899 | 	*ssn = SEQ_TO_SN(tid_data->seq_number); | 
 | 900 | 	tid_data->agg.txq_id = txq_id; | 
 | 901 | 	iwl_legacy_set_swq_id(&priv->txq[txq_id], | 
 | 902 | 				iwl4965_get_ac_from_tid(tid), txq_id); | 
 | 903 | 	spin_unlock_irqrestore(&priv->sta_lock, flags); | 
 | 904 |  | 
 | 905 | 	ret = iwl4965_txq_agg_enable(priv, txq_id, tx_fifo, | 
 | 906 | 						  sta_id, tid, *ssn); | 
 | 907 | 	if (ret) | 
 | 908 | 		return ret; | 
 | 909 |  | 
 | 910 | 	spin_lock_irqsave(&priv->sta_lock, flags); | 
 | 911 | 	tid_data = &priv->stations[sta_id].tid[tid]; | 
 | 912 | 	if (tid_data->tfds_in_queue == 0) { | 
 | 913 | 		IWL_DEBUG_HT(priv, "HW queue is empty\n"); | 
 | 914 | 		tid_data->agg.state = IWL_AGG_ON; | 
 | 915 | 		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); | 
 | 916 | 	} else { | 
 | 917 | 		IWL_DEBUG_HT(priv, | 
 | 918 | 			"HW queue is NOT empty: %d packets in HW queue\n", | 
 | 919 | 			     tid_data->tfds_in_queue); | 
 | 920 | 		tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; | 
 | 921 | 	} | 
 | 922 | 	spin_unlock_irqrestore(&priv->sta_lock, flags); | 
 | 923 | 	return ret; | 
 | 924 | } | 
 | 925 |  | 
 | 926 | /** | 
 | 927 |  * txq_id must be greater than IWL49_FIRST_AMPDU_QUEUE | 
 | 928 |  * priv->lock must be held by the caller | 
 | 929 |  */ | 
 | 930 | static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, | 
 | 931 | 				   u16 ssn_idx, u8 tx_fifo) | 
 | 932 | { | 
 | 933 | 	if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || | 
 | 934 | 	    (IWL49_FIRST_AMPDU_QUEUE + | 
 | 935 | 		priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { | 
 | 936 | 		IWL_WARN(priv, | 
 | 937 | 			"queue number out of range: %d, must be %d to %d\n", | 
 | 938 | 			txq_id, IWL49_FIRST_AMPDU_QUEUE, | 
 | 939 | 			IWL49_FIRST_AMPDU_QUEUE + | 
 | 940 | 			priv->cfg->base_params->num_of_ampdu_queues - 1); | 
 | 941 | 		return -EINVAL; | 
 | 942 | 	} | 
 | 943 |  | 
 | 944 | 	iwl4965_tx_queue_stop_scheduler(priv, txq_id); | 
 | 945 |  | 
 | 946 | 	iwl_legacy_clear_bits_prph(priv, | 
 | 947 | 			IWL49_SCD_QUEUECHAIN_SEL, (1 << txq_id)); | 
 | 948 |  | 
 | 949 | 	priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff); | 
 | 950 | 	priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff); | 
 | 951 | 	/* supposes that ssn_idx is valid (!= 0xFFF) */ | 
 | 952 | 	iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx); | 
 | 953 |  | 
 | 954 | 	iwl_legacy_clear_bits_prph(priv, | 
 | 955 | 			 IWL49_SCD_INTERRUPT_MASK, (1 << txq_id)); | 
 | 956 | 	iwl_txq_ctx_deactivate(priv, txq_id); | 
 | 957 | 	iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); | 
 | 958 |  | 
 | 959 | 	return 0; | 
 | 960 | } | 
 | 961 |  | 
 | 962 | int iwl4965_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, | 
 | 963 | 		       struct ieee80211_sta *sta, u16 tid) | 
 | 964 | { | 
 | 965 | 	int tx_fifo_id, txq_id, sta_id, ssn; | 
 | 966 | 	struct iwl_tid_data *tid_data; | 
 | 967 | 	int write_ptr, read_ptr; | 
 | 968 | 	unsigned long flags; | 
 | 969 |  | 
 | 970 | 	tx_fifo_id = iwl4965_get_fifo_from_tid(iwl_legacy_rxon_ctx_from_vif(vif), tid); | 
 | 971 | 	if (unlikely(tx_fifo_id < 0)) | 
 | 972 | 		return tx_fifo_id; | 
 | 973 |  | 
 | 974 | 	sta_id = iwl_legacy_sta_id(sta); | 
 | 975 |  | 
 | 976 | 	if (sta_id == IWL_INVALID_STATION) { | 
 | 977 | 		IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid); | 
 | 978 | 		return -ENXIO; | 
 | 979 | 	} | 
 | 980 |  | 
 | 981 | 	spin_lock_irqsave(&priv->sta_lock, flags); | 
 | 982 |  | 
 | 983 | 	tid_data = &priv->stations[sta_id].tid[tid]; | 
 | 984 | 	ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4; | 
 | 985 | 	txq_id = tid_data->agg.txq_id; | 
 | 986 |  | 
 | 987 | 	switch (priv->stations[sta_id].tid[tid].agg.state) { | 
 | 988 | 	case IWL_EMPTYING_HW_QUEUE_ADDBA: | 
 | 989 | 		/* | 
 | 990 | 		 * This can happen if the peer stops aggregation | 
 | 991 | 		 * again before we've had a chance to drain the | 
 | 992 | 		 * queue we selected previously, i.e. before the | 
 | 993 | 		 * session was really started completely. | 
 | 994 | 		 */ | 
 | 995 | 		IWL_DEBUG_HT(priv, "AGG stop before setup done\n"); | 
 | 996 | 		goto turn_off; | 
 | 997 | 	case IWL_AGG_ON: | 
 | 998 | 		break; | 
 | 999 | 	default: | 
 | 1000 | 		IWL_WARN(priv, "Stopping AGG while state not ON or starting\n"); | 
 | 1001 | 	} | 
 | 1002 |  | 
 | 1003 | 	write_ptr = priv->txq[txq_id].q.write_ptr; | 
 | 1004 | 	read_ptr = priv->txq[txq_id].q.read_ptr; | 
 | 1005 |  | 
 | 1006 | 	/* The queue is not empty */ | 
 | 1007 | 	if (write_ptr != read_ptr) { | 
 | 1008 | 		IWL_DEBUG_HT(priv, "Stopping a non empty AGG HW QUEUE\n"); | 
 | 1009 | 		priv->stations[sta_id].tid[tid].agg.state = | 
 | 1010 | 				IWL_EMPTYING_HW_QUEUE_DELBA; | 
 | 1011 | 		spin_unlock_irqrestore(&priv->sta_lock, flags); | 
 | 1012 | 		return 0; | 
 | 1013 | 	} | 
 | 1014 |  | 
 | 1015 | 	IWL_DEBUG_HT(priv, "HW queue is empty\n"); | 
 | 1016 |  turn_off: | 
 | 1017 | 	priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; | 
 | 1018 |  | 
 | 1019 | 	/* do not restore/save irqs */ | 
 | 1020 | 	spin_unlock(&priv->sta_lock); | 
 | 1021 | 	spin_lock(&priv->lock); | 
 | 1022 |  | 
 | 1023 | 	/* | 
 | 1024 | 	 * the only reason this call can fail is queue number out of range, | 
 | 1025 | 	 * which can happen if uCode is reloaded and all the station | 
 | 1026 | 	 * information are lost. if it is outside the range, there is no need | 
 | 1027 | 	 * to deactivate the uCode queue, just return "success" to allow | 
 | 1028 | 	 *  mac80211 to clean up it own data. | 
 | 1029 | 	 */ | 
 | 1030 | 	iwl4965_txq_agg_disable(priv, txq_id, ssn, tx_fifo_id); | 
 | 1031 | 	spin_unlock_irqrestore(&priv->lock, flags); | 
 | 1032 |  | 
 | 1033 | 	ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | 
 | 1034 |  | 
 | 1035 | 	return 0; | 
 | 1036 | } | 
 | 1037 |  | 
 | 1038 | int iwl4965_txq_check_empty(struct iwl_priv *priv, | 
 | 1039 | 			   int sta_id, u8 tid, int txq_id) | 
 | 1040 | { | 
 | 1041 | 	struct iwl_queue *q = &priv->txq[txq_id].q; | 
 | 1042 | 	u8 *addr = priv->stations[sta_id].sta.sta.addr; | 
 | 1043 | 	struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid]; | 
 | 1044 | 	struct iwl_rxon_context *ctx; | 
 | 1045 |  | 
 | 1046 | 	ctx = &priv->contexts[priv->stations[sta_id].ctxid]; | 
 | 1047 |  | 
 | 1048 | 	lockdep_assert_held(&priv->sta_lock); | 
 | 1049 |  | 
 | 1050 | 	switch (priv->stations[sta_id].tid[tid].agg.state) { | 
 | 1051 | 	case IWL_EMPTYING_HW_QUEUE_DELBA: | 
 | 1052 | 		/* We are reclaiming the last packet of the */ | 
 | 1053 | 		/* aggregated HW queue */ | 
 | 1054 | 		if ((txq_id  == tid_data->agg.txq_id) && | 
 | 1055 | 		    (q->read_ptr == q->write_ptr)) { | 
 | 1056 | 			u16 ssn = SEQ_TO_SN(tid_data->seq_number); | 
 | 1057 | 			int tx_fifo = iwl4965_get_fifo_from_tid(ctx, tid); | 
 | 1058 | 			IWL_DEBUG_HT(priv, | 
 | 1059 | 				"HW queue empty: continue DELBA flow\n"); | 
 | 1060 | 			iwl4965_txq_agg_disable(priv, txq_id, ssn, tx_fifo); | 
 | 1061 | 			tid_data->agg.state = IWL_AGG_OFF; | 
 | 1062 | 			ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid); | 
 | 1063 | 		} | 
 | 1064 | 		break; | 
 | 1065 | 	case IWL_EMPTYING_HW_QUEUE_ADDBA: | 
 | 1066 | 		/* We are reclaiming the last packet of the queue */ | 
 | 1067 | 		if (tid_data->tfds_in_queue == 0) { | 
 | 1068 | 			IWL_DEBUG_HT(priv, | 
 | 1069 | 				"HW queue empty: continue ADDBA flow\n"); | 
 | 1070 | 			tid_data->agg.state = IWL_AGG_ON; | 
 | 1071 | 			ieee80211_start_tx_ba_cb_irqsafe(ctx->vif, addr, tid); | 
 | 1072 | 		} | 
 | 1073 | 		break; | 
 | 1074 | 	} | 
 | 1075 |  | 
 | 1076 | 	return 0; | 
 | 1077 | } | 
 | 1078 |  | 
 | 1079 | static void iwl4965_non_agg_tx_status(struct iwl_priv *priv, | 
 | 1080 | 				     struct iwl_rxon_context *ctx, | 
 | 1081 | 				     const u8 *addr1) | 
 | 1082 | { | 
 | 1083 | 	struct ieee80211_sta *sta; | 
 | 1084 | 	struct iwl_station_priv *sta_priv; | 
 | 1085 |  | 
 | 1086 | 	rcu_read_lock(); | 
 | 1087 | 	sta = ieee80211_find_sta(ctx->vif, addr1); | 
 | 1088 | 	if (sta) { | 
 | 1089 | 		sta_priv = (void *)sta->drv_priv; | 
 | 1090 | 		/* avoid atomic ops if this isn't a client */ | 
 | 1091 | 		if (sta_priv->client && | 
 | 1092 | 		    atomic_dec_return(&sta_priv->pending_frames) == 0) | 
 | 1093 | 			ieee80211_sta_block_awake(priv->hw, sta, false); | 
 | 1094 | 	} | 
 | 1095 | 	rcu_read_unlock(); | 
 | 1096 | } | 
 | 1097 |  | 
 | 1098 | static void | 
 | 1099 | iwl4965_tx_status(struct iwl_priv *priv, struct iwl_tx_info *tx_info, | 
 | 1100 | 			     bool is_agg) | 
 | 1101 | { | 
 | 1102 | 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx_info->skb->data; | 
 | 1103 |  | 
 | 1104 | 	if (!is_agg) | 
 | 1105 | 		iwl4965_non_agg_tx_status(priv, tx_info->ctx, hdr->addr1); | 
 | 1106 |  | 
 | 1107 | 	ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb); | 
 | 1108 | } | 
 | 1109 |  | 
 | 1110 | int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) | 
 | 1111 | { | 
 | 1112 | 	struct iwl_tx_queue *txq = &priv->txq[txq_id]; | 
 | 1113 | 	struct iwl_queue *q = &txq->q; | 
 | 1114 | 	struct iwl_tx_info *tx_info; | 
 | 1115 | 	int nfreed = 0; | 
 | 1116 | 	struct ieee80211_hdr *hdr; | 
 | 1117 |  | 
 | 1118 | 	if ((index >= q->n_bd) || (iwl_legacy_queue_used(q, index) == 0)) { | 
 | 1119 | 		IWL_ERR(priv, "Read index for DMA queue txq id (%d), index %d, " | 
 | 1120 | 			  "is out of range [0-%d] %d %d.\n", txq_id, | 
 | 1121 | 			  index, q->n_bd, q->write_ptr, q->read_ptr); | 
 | 1122 | 		return 0; | 
 | 1123 | 	} | 
 | 1124 |  | 
 | 1125 | 	for (index = iwl_legacy_queue_inc_wrap(index, q->n_bd); | 
 | 1126 | 	     q->read_ptr != index; | 
 | 1127 | 	     q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd)) { | 
 | 1128 |  | 
 | 1129 | 		tx_info = &txq->txb[txq->q.read_ptr]; | 
 | 1130 | 		iwl4965_tx_status(priv, tx_info, | 
 | 1131 | 				 txq_id >= IWL4965_FIRST_AMPDU_QUEUE); | 
 | 1132 |  | 
 | 1133 | 		hdr = (struct ieee80211_hdr *)tx_info->skb->data; | 
 | 1134 | 		if (hdr && ieee80211_is_data_qos(hdr->frame_control)) | 
 | 1135 | 			nfreed++; | 
 | 1136 | 		tx_info->skb = NULL; | 
 | 1137 |  | 
 | 1138 | 		priv->cfg->ops->lib->txq_free_tfd(priv, txq); | 
 | 1139 | 	} | 
 | 1140 | 	return nfreed; | 
 | 1141 | } | 
 | 1142 |  | 
 | 1143 | /** | 
 | 1144 |  * iwl4965_tx_status_reply_compressed_ba - Update tx status from block-ack | 
 | 1145 |  * | 
 | 1146 |  * Go through block-ack's bitmap of ACK'd frames, update driver's record of | 
 | 1147 |  * ACK vs. not.  This gets sent to mac80211, then to rate scaling algo. | 
 | 1148 |  */ | 
 | 1149 | static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv, | 
 | 1150 | 				 struct iwl_ht_agg *agg, | 
 | 1151 | 				 struct iwl_compressed_ba_resp *ba_resp) | 
 | 1152 |  | 
 | 1153 | { | 
 | 1154 | 	int i, sh, ack; | 
 | 1155 | 	u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); | 
 | 1156 | 	u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); | 
 | 1157 | 	int successes = 0; | 
 | 1158 | 	struct ieee80211_tx_info *info; | 
 | 1159 | 	u64 bitmap, sent_bitmap; | 
 | 1160 |  | 
 | 1161 | 	if (unlikely(!agg->wait_for_ba))  { | 
 | 1162 | 		if (unlikely(ba_resp->bitmap)) | 
 | 1163 | 			IWL_ERR(priv, "Received BA when not expected\n"); | 
 | 1164 | 		return -EINVAL; | 
 | 1165 | 	} | 
 | 1166 |  | 
 | 1167 | 	/* Mark that the expected block-ack response arrived */ | 
 | 1168 | 	agg->wait_for_ba = 0; | 
 | 1169 | 	IWL_DEBUG_TX_REPLY(priv, "BA %d %d\n", agg->start_idx, | 
 | 1170 | 							ba_resp->seq_ctl); | 
 | 1171 |  | 
 | 1172 | 	/* Calculate shift to align block-ack bits with our Tx window bits */ | 
 | 1173 | 	sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4); | 
 | 1174 | 	if (sh < 0) /* tbw something is wrong with indices */ | 
 | 1175 | 		sh += 0x100; | 
 | 1176 |  | 
 | 1177 | 	if (agg->frame_count > (64 - sh)) { | 
 | 1178 | 		IWL_DEBUG_TX_REPLY(priv, "more frames than bitmap size"); | 
 | 1179 | 		return -1; | 
 | 1180 | 	} | 
 | 1181 |  | 
 | 1182 | 	/* don't use 64-bit values for now */ | 
 | 1183 | 	bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; | 
 | 1184 |  | 
 | 1185 | 	/* check for success or failure according to the | 
 | 1186 | 	 * transmitted bitmap and block-ack bitmap */ | 
 | 1187 | 	sent_bitmap = bitmap & agg->bitmap; | 
 | 1188 |  | 
 | 1189 | 	/* For each frame attempted in aggregation, | 
 | 1190 | 	 * update driver's record of tx frame's status. */ | 
 | 1191 | 	i = 0; | 
 | 1192 | 	while (sent_bitmap) { | 
 | 1193 | 		ack = sent_bitmap & 1ULL; | 
 | 1194 | 		successes += ack; | 
 | 1195 | 		IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n", | 
 | 1196 | 			ack ? "ACK" : "NACK", i, | 
 | 1197 | 			(agg->start_idx + i) & 0xff, | 
 | 1198 | 			agg->start_idx + i); | 
 | 1199 | 		sent_bitmap >>= 1; | 
 | 1200 | 		++i; | 
 | 1201 | 	} | 
 | 1202 |  | 
 | 1203 | 	IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n", | 
 | 1204 | 				   (unsigned long long)bitmap); | 
 | 1205 |  | 
 | 1206 | 	info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb); | 
 | 1207 | 	memset(&info->status, 0, sizeof(info->status)); | 
 | 1208 | 	info->flags |= IEEE80211_TX_STAT_ACK; | 
 | 1209 | 	info->flags |= IEEE80211_TX_STAT_AMPDU; | 
 | 1210 | 	info->status.ampdu_ack_len = successes; | 
 | 1211 | 	info->status.ampdu_len = agg->frame_count; | 
 | 1212 | 	iwl4965_hwrate_to_tx_control(priv, agg->rate_n_flags, info); | 
 | 1213 |  | 
 | 1214 | 	return 0; | 
 | 1215 | } | 
 | 1216 |  | 
 | 1217 | /** | 
 | 1218 |  * translate ucode response to mac80211 tx status control values | 
 | 1219 |  */ | 
 | 1220 | void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, | 
 | 1221 | 				  struct ieee80211_tx_info *info) | 
 | 1222 | { | 
 | 1223 | 	struct ieee80211_tx_rate *r = &info->control.rates[0]; | 
 | 1224 |  | 
 | 1225 | 	info->antenna_sel_tx = | 
 | 1226 | 		((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); | 
 | 1227 | 	if (rate_n_flags & RATE_MCS_HT_MSK) | 
 | 1228 | 		r->flags |= IEEE80211_TX_RC_MCS; | 
 | 1229 | 	if (rate_n_flags & RATE_MCS_GF_MSK) | 
 | 1230 | 		r->flags |= IEEE80211_TX_RC_GREEN_FIELD; | 
 | 1231 | 	if (rate_n_flags & RATE_MCS_HT40_MSK) | 
 | 1232 | 		r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | 
 | 1233 | 	if (rate_n_flags & RATE_MCS_DUP_MSK) | 
 | 1234 | 		r->flags |= IEEE80211_TX_RC_DUP_DATA; | 
 | 1235 | 	if (rate_n_flags & RATE_MCS_SGI_MSK) | 
 | 1236 | 		r->flags |= IEEE80211_TX_RC_SHORT_GI; | 
 | 1237 | 	r->idx = iwl4965_hwrate_to_mac80211_idx(rate_n_flags, info->band); | 
 | 1238 | } | 
 | 1239 |  | 
 | 1240 | /** | 
 | 1241 |  * iwl4965_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA | 
 | 1242 |  * | 
 | 1243 |  * Handles block-acknowledge notification from device, which reports success | 
 | 1244 |  * of frames sent via aggregation. | 
 | 1245 |  */ | 
 | 1246 | void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, | 
 | 1247 | 					   struct iwl_rx_mem_buffer *rxb) | 
 | 1248 | { | 
 | 1249 | 	struct iwl_rx_packet *pkt = rxb_addr(rxb); | 
 | 1250 | 	struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; | 
 | 1251 | 	struct iwl_tx_queue *txq = NULL; | 
 | 1252 | 	struct iwl_ht_agg *agg; | 
 | 1253 | 	int index; | 
 | 1254 | 	int sta_id; | 
 | 1255 | 	int tid; | 
 | 1256 | 	unsigned long flags; | 
 | 1257 |  | 
 | 1258 | 	/* "flow" corresponds to Tx queue */ | 
 | 1259 | 	u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); | 
 | 1260 |  | 
 | 1261 | 	/* "ssn" is start of block-ack Tx window, corresponds to index | 
 | 1262 | 	 * (in Tx queue's circular buffer) of first TFD/frame in window */ | 
 | 1263 | 	u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn); | 
 | 1264 |  | 
 | 1265 | 	if (scd_flow >= priv->hw_params.max_txq_num) { | 
 | 1266 | 		IWL_ERR(priv, | 
 | 1267 | 			"BUG_ON scd_flow is bigger than number of queues\n"); | 
 | 1268 | 		return; | 
 | 1269 | 	} | 
 | 1270 |  | 
 | 1271 | 	txq = &priv->txq[scd_flow]; | 
 | 1272 | 	sta_id = ba_resp->sta_id; | 
 | 1273 | 	tid = ba_resp->tid; | 
 | 1274 | 	agg = &priv->stations[sta_id].tid[tid].agg; | 
 | 1275 | 	if (unlikely(agg->txq_id != scd_flow)) { | 
 | 1276 | 		/* | 
 | 1277 | 		 * FIXME: this is a uCode bug which need to be addressed, | 
 | 1278 | 		 * log the information and return for now! | 
 | 1279 | 		 * since it is possible happen very often and in order | 
 | 1280 | 		 * not to fill the syslog, don't enable the logging by default | 
 | 1281 | 		 */ | 
 | 1282 | 		IWL_DEBUG_TX_REPLY(priv, | 
 | 1283 | 			"BA scd_flow %d does not match txq_id %d\n", | 
 | 1284 | 			scd_flow, agg->txq_id); | 
 | 1285 | 		return; | 
 | 1286 | 	} | 
 | 1287 |  | 
 | 1288 | 	/* Find index just before block-ack window */ | 
 | 1289 | 	index = iwl_legacy_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); | 
 | 1290 |  | 
 | 1291 | 	spin_lock_irqsave(&priv->sta_lock, flags); | 
 | 1292 |  | 
 | 1293 | 	IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, " | 
 | 1294 | 			   "sta_id = %d\n", | 
 | 1295 | 			   agg->wait_for_ba, | 
 | 1296 | 			   (u8 *) &ba_resp->sta_addr_lo32, | 
 | 1297 | 			   ba_resp->sta_id); | 
 | 1298 | 	IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx," | 
 | 1299 | 			"scd_flow = " | 
 | 1300 | 			   "%d, scd_ssn = %d\n", | 
 | 1301 | 			   ba_resp->tid, | 
 | 1302 | 			   ba_resp->seq_ctl, | 
 | 1303 | 			   (unsigned long long)le64_to_cpu(ba_resp->bitmap), | 
 | 1304 | 			   ba_resp->scd_flow, | 
 | 1305 | 			   ba_resp->scd_ssn); | 
 | 1306 | 	IWL_DEBUG_TX_REPLY(priv, "DAT start_idx = %d, bitmap = 0x%llx\n", | 
 | 1307 | 			   agg->start_idx, | 
 | 1308 | 			   (unsigned long long)agg->bitmap); | 
 | 1309 |  | 
 | 1310 | 	/* Update driver's record of ACK vs. not for each frame in window */ | 
 | 1311 | 	iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp); | 
 | 1312 |  | 
 | 1313 | 	/* Release all TFDs before the SSN, i.e. all TFDs in front of | 
 | 1314 | 	 * block-ack window (we assume that they've been successfully | 
 | 1315 | 	 * transmitted ... if not, it's too late anyway). */ | 
 | 1316 | 	if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) { | 
 | 1317 | 		/* calculate mac80211 ampdu sw queue to wake */ | 
 | 1318 | 		int freed = iwl4965_tx_queue_reclaim(priv, scd_flow, index); | 
 | 1319 | 		iwl4965_free_tfds_in_queue(priv, sta_id, tid, freed); | 
 | 1320 |  | 
 | 1321 | 		if ((iwl_legacy_queue_space(&txq->q) > txq->q.low_mark) && | 
 | 1322 | 		    priv->mac80211_registered && | 
 | 1323 | 		    (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) | 
 | 1324 | 			iwl_legacy_wake_queue(priv, txq); | 
 | 1325 |  | 
 | 1326 | 		iwl4965_txq_check_empty(priv, sta_id, tid, scd_flow); | 
 | 1327 | 	} | 
 | 1328 |  | 
 | 1329 | 	spin_unlock_irqrestore(&priv->sta_lock, flags); | 
 | 1330 | } | 
 | 1331 |  | 
 | 1332 | #ifdef CONFIG_IWLWIFI_LEGACY_DEBUG | 
 | 1333 | const char *iwl4965_get_tx_fail_reason(u32 status) | 
 | 1334 | { | 
 | 1335 | #define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x | 
 | 1336 | #define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x | 
 | 1337 |  | 
 | 1338 | 	switch (status & TX_STATUS_MSK) { | 
 | 1339 | 	case TX_STATUS_SUCCESS: | 
 | 1340 | 		return "SUCCESS"; | 
 | 1341 | 	TX_STATUS_POSTPONE(DELAY); | 
 | 1342 | 	TX_STATUS_POSTPONE(FEW_BYTES); | 
 | 1343 | 	TX_STATUS_POSTPONE(QUIET_PERIOD); | 
 | 1344 | 	TX_STATUS_POSTPONE(CALC_TTAK); | 
 | 1345 | 	TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY); | 
 | 1346 | 	TX_STATUS_FAIL(SHORT_LIMIT); | 
 | 1347 | 	TX_STATUS_FAIL(LONG_LIMIT); | 
 | 1348 | 	TX_STATUS_FAIL(FIFO_UNDERRUN); | 
 | 1349 | 	TX_STATUS_FAIL(DRAIN_FLOW); | 
 | 1350 | 	TX_STATUS_FAIL(RFKILL_FLUSH); | 
 | 1351 | 	TX_STATUS_FAIL(LIFE_EXPIRE); | 
 | 1352 | 	TX_STATUS_FAIL(DEST_PS); | 
 | 1353 | 	TX_STATUS_FAIL(HOST_ABORTED); | 
 | 1354 | 	TX_STATUS_FAIL(BT_RETRY); | 
 | 1355 | 	TX_STATUS_FAIL(STA_INVALID); | 
 | 1356 | 	TX_STATUS_FAIL(FRAG_DROPPED); | 
 | 1357 | 	TX_STATUS_FAIL(TID_DISABLE); | 
 | 1358 | 	TX_STATUS_FAIL(FIFO_FLUSHED); | 
 | 1359 | 	TX_STATUS_FAIL(INSUFFICIENT_CF_POLL); | 
 | 1360 | 	TX_STATUS_FAIL(PASSIVE_NO_RX); | 
 | 1361 | 	TX_STATUS_FAIL(NO_BEACON_ON_RADAR); | 
 | 1362 | 	} | 
 | 1363 |  | 
 | 1364 | 	return "UNKNOWN"; | 
 | 1365 |  | 
 | 1366 | #undef TX_STATUS_FAIL | 
 | 1367 | #undef TX_STATUS_POSTPONE | 
 | 1368 | } | 
 | 1369 | #endif /* CONFIG_IWLWIFI_LEGACY_DEBUG */ |