txrx.c 10.3 KB
Newer Older
1 2 3
/*
 * Marvell Wireless LAN device driver: generic TX/RX data handling
 *
X
Xinming Hu 已提交
4
 * Copyright (C) 2011-2014, Marvell International Ltd.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
 *
 * This software file (the "File") is distributed by Marvell International
 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
 * (the "License").  You may use, redistribute and/or modify this File in
 * accordance with the terms and conditions of the License, a copy of which
 * is available by writing to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
 *
 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
 * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
 * this warranty disclaimer.
 */

#include "decl.h"
#include "ioctl.h"
#include "util.h"
#include "fw.h"
#include "main.h"
#include "wmm.h"

/*
 * This function processes the received buffer.
 *
 * Main responsibility of this function is to parse the RxPD to
 * identify the correct interface this packet is headed for and
 * forwarding it to the associated handling function, where the
 * packet will be further processed and sent to kernel/upper layer
 * if required.
 */
int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,
			     struct sk_buff *skb)
{
	struct mwifiex_private *priv =
		mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
	struct rxpd *local_rx_pd;
	struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
43
	int ret;
44 45 46 47 48 49 50 51

	local_rx_pd = (struct rxpd *) (skb->data);
	/* Get the BSS number from rxpd, get corresponding priv */
	priv = mwifiex_get_priv_by_id(adapter, local_rx_pd->bss_num &
				      BSS_NUM_MASK, local_rx_pd->bss_type);
	if (!priv)
		priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);

52
	if (!priv) {
53 54
		mwifiex_dbg(adapter, ERROR,
			    "data: priv not found. Drop RX packet\n");
55 56 57 58
		dev_kfree_skb_any(skb);
		return -1;
	}

59 60 61
	mwifiex_dbg_dump(adapter, DAT_D, "rx pkt:", skb->data,
			 min_t(size_t, skb->len, DEBUG_DUMP_DATA_MAX_LEN));

62
	memset(rx_info, 0, sizeof(*rx_info));
63 64
	rx_info->bss_num = priv->bss_num;
	rx_info->bss_type = priv->bss_type;
65

A
Avinash Patil 已提交
66
	if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
67 68 69
		ret = mwifiex_process_uap_rx_packet(priv, skb);
	else
		ret = mwifiex_process_sta_rx_packet(priv, skb);
A
Avinash Patil 已提交
70

71
	return ret;
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
}
EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet);

/*
 * This function sends a packet to device.
 *
 * It processes the packet to add the TxPD, checks condition and
 * sends the processed packet to firmware for transmission.
 *
 * On successful completion, the function calls the completion callback
 * and logs the time.
 */
int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
		       struct mwifiex_tx_param *tx_param)
{
87
	int hroom, ret = -1;
88
	struct mwifiex_adapter *adapter = priv->adapter;
89
	u8 *head_ptr;
90 91
	struct txpd *local_tx_pd = NULL;

92 93
	hroom = (adapter->iface_type == MWIFIEX_USB) ? 0 : INTF_HEADER_LEN;

94 95 96 97 98
	if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
		head_ptr = mwifiex_process_uap_txpd(priv, skb);
	else
		head_ptr = mwifiex_process_sta_txpd(priv, skb);

99 100 101 102 103 104
	if ((adapter->data_sent || adapter->tx_lock_flag) && head_ptr) {
		skb_queue_tail(&adapter->tx_data_q, skb);
		atomic_inc(&adapter->tx_queued);
		return 0;
	}

105 106
	if (head_ptr) {
		if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
107
			local_tx_pd = (struct txpd *)(head_ptr + hroom);
108 109 110 111 112 113 114 115 116 117
		if (adapter->iface_type == MWIFIEX_USB) {
			adapter->data_sent = true;
			ret = adapter->if_ops.host_to_card(adapter,
							   MWIFIEX_USB_EP_DATA,
							   skb, NULL);
		} else {
			ret = adapter->if_ops.host_to_card(adapter,
							   MWIFIEX_TYPE_DATA,
							   skb, tx_param);
		}
118
	}
119 120
	mwifiex_dbg_dump(adapter, DAT_D, "tx pkt:", skb->data,
			 min_t(size_t, skb->len, DEBUG_DUMP_DATA_MAX_LEN));
121 122

	switch (ret) {
123
	case -ENOSR:
124
		mwifiex_dbg(adapter, ERROR, "data: -ENOSR is returned\n");
125
		break;
126 127
	case -EBUSY:
		if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
128
		    (adapter->pps_uapsd_mode) && (adapter->tx_lock_flag)) {
129
				priv->adapter->tx_lock_flag = false;
Y
Yogesh Ashok Powar 已提交
130 131
				if (local_tx_pd)
					local_tx_pd->flags = 0;
132
		}
133
		mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
134 135
		break;
	case -1:
136 137
		if (adapter->iface_type != MWIFIEX_PCIE)
			adapter->data_sent = false;
138 139 140
		mwifiex_dbg(adapter, ERROR,
			    "mwifiex_write_data_async failed: 0x%X\n",
			    ret);
141
		adapter->dbg.num_tx_host_to_card_failure++;
A
Avinash Patil 已提交
142
		mwifiex_write_data_complete(adapter, skb, 0, ret);
143 144
		break;
	case -EINPROGRESS:
145 146
		if (adapter->iface_type != MWIFIEX_PCIE)
			adapter->data_sent = false;
147 148
		break;
	case 0:
A
Avinash Patil 已提交
149
		mwifiex_write_data_complete(adapter, skb, 0, ret);
150 151 152 153 154 155 156 157
		break;
	default:
		break;
	}

	return ret;
}

158 159 160 161 162 163 164 165 166 167 168 169 170 171
static int mwifiex_host_to_card(struct mwifiex_adapter *adapter,
				struct sk_buff *skb,
				struct mwifiex_tx_param *tx_param)
{
	struct txpd *local_tx_pd = NULL;
	u8 *head_ptr = skb->data;
	int ret = 0;
	struct mwifiex_private *priv;
	struct mwifiex_txinfo *tx_info;

	tx_info = MWIFIEX_SKB_TXCB(skb);
	priv = mwifiex_get_priv_by_id(adapter, tx_info->bss_num,
				      tx_info->bss_type);
	if (!priv) {
172 173
		mwifiex_dbg(adapter, ERROR,
			    "data: priv not found. Drop TX packet\n");
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
		adapter->dbg.num_tx_host_to_card_failure++;
		mwifiex_write_data_complete(adapter, skb, 0, 0);
		return ret;
	}
	if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
		if (adapter->iface_type == MWIFIEX_USB)
			local_tx_pd = (struct txpd *)head_ptr;
		else
			local_tx_pd = (struct txpd *) (head_ptr +
				INTF_HEADER_LEN);
	}

	if (adapter->iface_type == MWIFIEX_USB) {
		adapter->data_sent = true;
		ret = adapter->if_ops.host_to_card(adapter,
						   MWIFIEX_USB_EP_DATA,
						   skb, NULL);
	} else {
		ret = adapter->if_ops.host_to_card(adapter,
						   MWIFIEX_TYPE_DATA,
						   skb, tx_param);
	}
	switch (ret) {
	case -ENOSR:
198
		mwifiex_dbg(adapter, ERROR, "data: -ENOSR is returned\n");
199 200 201 202 203 204 205 206 207 208 209 210 211 212
		break;
	case -EBUSY:
		if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
		    (adapter->pps_uapsd_mode) &&
		    (adapter->tx_lock_flag)) {
			priv->adapter->tx_lock_flag = false;
			if (local_tx_pd)
				local_tx_pd->flags = 0;
		}
		skb_queue_head(&adapter->tx_data_q, skb);
		if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
			atomic_add(tx_info->aggr_num, &adapter->tx_queued);
		else
			atomic_inc(&adapter->tx_queued);
213
		mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
214 215 216 217
		break;
	case -1:
		if (adapter->iface_type != MWIFIEX_PCIE)
			adapter->data_sent = false;
218 219
		mwifiex_dbg(adapter, ERROR,
			    "mwifiex_write_data_async failed: 0x%X\n", ret);
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
		adapter->dbg.num_tx_host_to_card_failure++;
		mwifiex_write_data_complete(adapter, skb, 0, ret);
		break;
	case -EINPROGRESS:
		if (adapter->iface_type != MWIFIEX_PCIE)
			adapter->data_sent = false;
		break;
	case 0:
		mwifiex_write_data_complete(adapter, skb, 0, ret);
		break;
	default:
		break;
	}
	return ret;
}

static int
mwifiex_dequeue_tx_queue(struct mwifiex_adapter *adapter)
{
	struct sk_buff *skb, *skb_next;
	struct mwifiex_txinfo *tx_info;
	struct mwifiex_tx_param tx_param;

	skb = skb_dequeue(&adapter->tx_data_q);
	if (!skb)
		return -1;

	tx_info = MWIFIEX_SKB_TXCB(skb);
	if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
		atomic_sub(tx_info->aggr_num, &adapter->tx_queued);
	else
		atomic_dec(&adapter->tx_queued);

	if (!skb_queue_empty(&adapter->tx_data_q))
		skb_next = skb_peek(&adapter->tx_data_q);
	else
		skb_next = NULL;
	tx_param.next_pkt_len = ((skb_next) ? skb_next->len : 0);
	if (!tx_param.next_pkt_len) {
		if (!mwifiex_wmm_lists_empty(adapter))
			tx_param.next_pkt_len = 1;
	}
	return mwifiex_host_to_card(adapter, skb, &tx_param);
}

void
mwifiex_process_tx_queue(struct mwifiex_adapter *adapter)
{
	do {
		if (adapter->data_sent || adapter->tx_lock_flag)
			break;
		if (mwifiex_dequeue_tx_queue(adapter))
			break;
	} while (!skb_queue_empty(&adapter->tx_data_q));
}

276 277 278 279 280 281 282 283
/*
 * Packet send completion callback handler.
 *
 * It either frees the buffer directly or forwards it to another
 * completion callback which checks conditions, updates statistics,
 * wakes up stalled traffic queue if required, and then frees the buffer.
 */
int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
A
Avinash Patil 已提交
284
				struct sk_buff *skb, int aggr, int status)
285
{
A
Avinash Patil 已提交
286
	struct mwifiex_private *priv;
287
	struct mwifiex_txinfo *tx_info;
A
Avinash Patil 已提交
288 289
	struct netdev_queue *txq;
	int index;
290 291 292 293 294

	if (!skb)
		return 0;

	tx_info = MWIFIEX_SKB_TXCB(skb);
295
	priv = mwifiex_get_priv_by_id(adapter, tx_info->bss_num,
296
				      tx_info->bss_type);
297 298 299
	if (!priv)
		goto done;

300 301 302
	if (adapter->iface_type == MWIFIEX_USB)
		adapter->data_sent = false;

303
	mwifiex_set_trans_start(priv->netdev);
304 305
	if (!status) {
		priv->stats.tx_packets++;
306
		priv->stats.tx_bytes += tx_info->pkt_len;
307 308
		if (priv->tx_timeout_cnt)
			priv->tx_timeout_cnt = 0;
309 310 311
	} else {
		priv->stats.tx_errors++;
	}
312

313
	if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT) {
A
Avinash Patil 已提交
314
		atomic_dec_return(&adapter->pending_bridged_pkts);
315 316
		if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
			goto done;
317
	}
A
Avinash Patil 已提交
318 319 320

	if (aggr)
		/* For skb_aggr, do not wake up tx queue */
321
		goto done;
322

A
Avinash Patil 已提交
323
	atomic_dec(&adapter->tx_pending);
324

A
Avinash Patil 已提交
325 326 327 328 329
	index = mwifiex_1d_to_wmm_queue[skb->priority];
	if (atomic_dec_return(&priv->wmm_tx_pending[index]) < LOW_TX_PENDING) {
		txq = netdev_get_tx_queue(priv->netdev, index);
		if (netif_tx_queue_stopped(txq)) {
			netif_tx_wake_queue(txq);
330
			mwifiex_dbg(adapter, DATA, "wake queue: %d\n", index);
A
Avinash Patil 已提交
331
		}
332 333 334 335 336 337
	}
done:
	dev_kfree_skb_any(skb);

	return 0;
}
338
EXPORT_SYMBOL_GPL(mwifiex_write_data_complete);
339

340 341 342 343 344 345
void mwifiex_parse_tx_status_event(struct mwifiex_private *priv,
				   void *event_body)
{
	struct tx_status_event *tx_status = (void *)priv->adapter->event_body;
	struct sk_buff *ack_skb;
	unsigned long flags;
346
	struct mwifiex_txinfo *tx_info;
347 348 349 350 351 352 353 354 355 356

	if (!tx_status->tx_token_id)
		return;

	spin_lock_irqsave(&priv->ack_status_lock, flags);
	ack_skb = idr_find(&priv->ack_status_frames, tx_status->tx_token_id);
	if (ack_skb)
		idr_remove(&priv->ack_status_frames, tx_status->tx_token_id);
	spin_unlock_irqrestore(&priv->ack_status_lock, flags);

357 358 359 360 361 362 363
	if (ack_skb) {
		tx_info = MWIFIEX_SKB_TXCB(ack_skb);

		if (tx_info->flags & MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS) {
			/* consumes ack_skb */
			skb_complete_wifi_ack(ack_skb, !tx_status->status);
		} else {
364
			cfg80211_mgmt_tx_status(&priv->wdev, tx_info->cookie,
365 366 367 368 369
						ack_skb->data, ack_skb->len,
						!tx_status->status, GFP_ATOMIC);
			dev_kfree_skb_any(ack_skb);
		}
	}
370
}