txrx.c 10.8 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
	struct txpd *local_tx_pd = NULL;
91 92
	struct mwifiex_sta_node *dest_node;
	struct ethhdr *hdr = (void *)skb->data;
93

94 95
	hroom = (adapter->iface_type == MWIFIEX_USB) ? 0 : INTF_HEADER_LEN;

96 97 98 99 100 101 102
	if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) {
		dest_node = mwifiex_get_sta_entry(priv, hdr->h_dest);
		if (dest_node) {
			dest_node->stats.tx_bytes += skb->len;
			dest_node->stats.tx_packets++;
		}

103
		head_ptr = mwifiex_process_uap_txpd(priv, skb);
104
	} else {
105
		head_ptr = mwifiex_process_sta_txpd(priv, skb);
106
	}
107

108 109 110 111 112 113
	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;
	}

114 115
	if (head_ptr) {
		if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
116
			local_tx_pd = (struct txpd *)(head_ptr + hroom);
117 118
		if (adapter->iface_type == MWIFIEX_USB) {
			ret = adapter->if_ops.host_to_card(adapter,
119
							   priv->usb_port,
120 121 122 123 124 125
							   skb, NULL);
		} else {
			ret = adapter->if_ops.host_to_card(adapter,
							   MWIFIEX_TYPE_DATA,
							   skb, tx_param);
		}
126
	}
127 128
	mwifiex_dbg_dump(adapter, DAT_D, "tx pkt:", skb->data,
			 min_t(size_t, skb->len, DEBUG_DUMP_DATA_MAX_LEN));
129 130

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

	return ret;
}

162 163 164 165 166 167 168 169 170 171 172 173 174 175
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) {
176 177
		mwifiex_dbg(adapter, ERROR,
			    "data: priv not found. Drop TX packet\n");
178 179 180 181 182 183 184 185 186 187 188 189 190 191
		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) {
		ret = adapter->if_ops.host_to_card(adapter,
192
						   priv->usb_port,
193 194 195 196 197 198 199 200
						   skb, NULL);
	} else {
		ret = adapter->if_ops.host_to_card(adapter,
						   MWIFIEX_TYPE_DATA,
						   skb, tx_param);
	}
	switch (ret) {
	case -ENOSR:
201
		mwifiex_dbg(adapter, ERROR, "data: -ENOSR is returned\n");
202 203 204 205 206 207 208 209 210 211 212 213 214 215
		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);
216
		mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
217 218
		break;
	case -1:
219 220
		mwifiex_dbg(adapter, ERROR,
			    "mwifiex_write_data_async failed: 0x%X\n", ret);
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
		adapter->dbg.num_tx_host_to_card_failure++;
		mwifiex_write_data_complete(adapter, skb, 0, ret);
		break;
	case -EINPROGRESS:
		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));
}

275 276 277 278 279 280 281 282
/*
 * 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 已提交
283
				struct sk_buff *skb, int aggr, int status)
284
{
A
Avinash Patil 已提交
285
	struct mwifiex_private *priv;
286
	struct mwifiex_txinfo *tx_info;
A
Avinash Patil 已提交
287 288
	struct netdev_queue *txq;
	int index;
289 290 291 292 293

	if (!skb)
		return 0;

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

299
	mwifiex_set_trans_start(priv->netdev);
300 301 302 303 304 305 306

	if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT)
		atomic_dec_return(&adapter->pending_bridged_pkts);

	if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
		goto done;

307 308
	if (!status) {
		priv->stats.tx_packets++;
309
		priv->stats.tx_bytes += tx_info->pkt_len;
310 311
		if (priv->tx_timeout_cnt)
			priv->tx_timeout_cnt = 0;
312 313 314
	} else {
		priv->stats.tx_errors++;
	}
315

A
Avinash Patil 已提交
316 317
	if (aggr)
		/* For skb_aggr, do not wake up tx queue */
318
		goto done;
319

A
Avinash Patil 已提交
320
	atomic_dec(&adapter->tx_pending);
321

A
Avinash Patil 已提交
322 323 324 325 326
	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);
327
			mwifiex_dbg(adapter, DATA, "wake queue: %d\n", index);
A
Avinash Patil 已提交
328
		}
329 330 331 332 333 334
	}
done:
	dev_kfree_skb_any(skb);

	return 0;
}
335
EXPORT_SYMBOL_GPL(mwifiex_write_data_complete);
336

337 338 339 340 341 342
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;
343
	struct mwifiex_txinfo *tx_info;
344 345 346 347 348 349 350 351 352 353

	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);

354 355 356 357 358 359 360
	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 {
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
			/* Remove broadcast address which was added by driver */
			memmove(ack_skb->data +
				sizeof(struct ieee80211_hdr_3addr) +
				MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16),
				ack_skb->data +
				sizeof(struct ieee80211_hdr_3addr) +
				MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16) +
				ETH_ALEN, ack_skb->len -
				(sizeof(struct ieee80211_hdr_3addr) +
				MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16) +
				ETH_ALEN));
			ack_skb->len = ack_skb->len - ETH_ALEN;
			/* Remove driver's proprietary header including 2 bytes
			 * of packet length and pass actual management frame buffer
			 * to cfg80211.
			 */
377
			cfg80211_mgmt_tx_status(&priv->wdev, tx_info->cookie,
378 379 380 381 382
						ack_skb->data +
						MWIFIEX_MGMT_FRAME_HEADER_SIZE +
						sizeof(u16), ack_skb->len -
						(MWIFIEX_MGMT_FRAME_HEADER_SIZE
						 + sizeof(u16)),
383 384 385 386
						!tx_status->status, GFP_ATOMIC);
			dev_kfree_skb_any(ack_skb);
		}
	}
387
}