PageRenderTime 64ms CodeModel.GetById 20ms app.highlight 35ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/staging/rtl8712/rtl8712_recv.c

https://bitbucket.org/slukk/jb-tsm-kernel-4.2
C | 1131 lines | 915 code | 61 blank | 155 comment | 226 complexity | 58eaf99e8d5750688e2c8fa094f7d909 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
   1/******************************************************************************
   2 * rtl8712_recv.c
   3 *
   4 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
   5 * Linux device driver for RTL8192SU
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * 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 WITHOUT
  12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  14 * more details.
  15 *
  16 * You should have received a copy of the GNU General Public License along with
  17 * this program; if not, write to the Free Software Foundation, Inc.,
  18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
  19 *
  20 * Modifications for inclusion into the Linux staging tree are
  21 * Copyright(c) 2010 Larry Finger. All rights reserved.
  22 *
  23 * Contact information:
  24 * WLAN FAE <wlanfae@realtek.com>
  25 * Larry Finger <Larry.Finger@lwfinger.net>
  26 *
  27 ******************************************************************************/
  28
  29#define _RTL8712_RECV_C_
  30
  31#include "osdep_service.h"
  32#include "drv_types.h"
  33#include "recv_osdep.h"
  34#include "mlme_osdep.h"
  35#include "ip.h"
  36#include "if_ether.h"
  37#include "ethernet.h"
  38#include "usb_ops.h"
  39#include "wifi.h"
  40
  41/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
  42static u8 bridge_tunnel_header[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8};
  43
  44/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
  45static u8 rfc1042_header[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
  46
  47static void recv_tasklet(void *priv);
  48
  49int r8712_init_recv_priv(struct recv_priv *precvpriv, struct _adapter *padapter)
  50{
  51	int i;
  52	struct recv_buf *precvbuf;
  53	int res = _SUCCESS;
  54	addr_t tmpaddr = 0;
  55	int alignment = 0;
  56	struct sk_buff *pskb = NULL;
  57
  58	sema_init(&precvpriv->recv_sema, 0);
  59	sema_init(&precvpriv->terminate_recvthread_sema, 0);
  60	/*init recv_buf*/
  61	_init_queue(&precvpriv->free_recv_buf_queue);
  62	precvpriv->pallocated_recv_buf = _malloc(NR_RECVBUFF *
  63					 sizeof(struct recv_buf) + 4);
  64	if (precvpriv->pallocated_recv_buf == NULL)
  65		return _FAIL;
  66	memset(precvpriv->pallocated_recv_buf, 0, NR_RECVBUFF *
  67		sizeof(struct recv_buf) + 4);
  68	precvpriv->precv_buf = precvpriv->pallocated_recv_buf + 4 -
  69			      ((addr_t) (precvpriv->pallocated_recv_buf) & 3);
  70	precvbuf = (struct recv_buf *)precvpriv->precv_buf;
  71	for (i = 0; i < NR_RECVBUFF; i++) {
  72		_init_listhead(&precvbuf->list);
  73		spin_lock_init(&precvbuf->recvbuf_lock);
  74		res = r8712_os_recvbuf_resource_alloc(padapter, precvbuf);
  75		if (res == _FAIL)
  76			break;
  77		precvbuf->ref_cnt = 0;
  78		precvbuf->adapter = padapter;
  79		list_insert_tail(&precvbuf->list,
  80				 &(precvpriv->free_recv_buf_queue.queue));
  81		precvbuf++;
  82	}
  83	precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF;
  84	tasklet_init(&precvpriv->recv_tasklet,
  85	     (void(*)(unsigned long))recv_tasklet,
  86	     (unsigned long)padapter);
  87	skb_queue_head_init(&precvpriv->rx_skb_queue);
  88
  89	skb_queue_head_init(&precvpriv->free_recv_skb_queue);
  90	for (i = 0; i < NR_PREALLOC_RECV_SKB; i++) {
  91		pskb = netdev_alloc_skb(padapter->pnetdev, MAX_RECVBUF_SZ +
  92		       RECVBUFF_ALIGN_SZ);
  93		if (pskb) {
  94			pskb->dev = padapter->pnetdev;
  95			tmpaddr = (addr_t)pskb->data;
  96			alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
  97			skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment));
  98			skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
  99		}
 100		pskb = NULL;
 101	}
 102	return res;
 103}
 104
 105void r8712_free_recv_priv(struct recv_priv *precvpriv)
 106{
 107	int i;
 108	struct recv_buf *precvbuf;
 109	struct _adapter *padapter = precvpriv->adapter;
 110
 111	precvbuf = (struct recv_buf *)precvpriv->precv_buf;
 112	for (i = 0; i < NR_RECVBUFF ; i++) {
 113		r8712_os_recvbuf_resource_free(padapter, precvbuf);
 114		precvbuf++;
 115	}
 116	kfree(precvpriv->pallocated_recv_buf);
 117	skb_queue_purge(&precvpriv->rx_skb_queue);
 118	if (skb_queue_len(&precvpriv->rx_skb_queue))
 119		printk(KERN_WARNING "r8712u: rx_skb_queue not empty\n");
 120	skb_queue_purge(&precvpriv->free_recv_skb_queue);
 121	if (skb_queue_len(&precvpriv->free_recv_skb_queue))
 122		printk(KERN_WARNING "r8712u: free_recv_skb_queue not empty "
 123		       "%d\n", skb_queue_len(&precvpriv->free_recv_skb_queue));
 124}
 125
 126int r8712_init_recvbuf(struct _adapter *padapter, struct recv_buf *precvbuf)
 127{
 128	int res = _SUCCESS;
 129
 130	precvbuf->transfer_len = 0;
 131	precvbuf->len = 0;
 132	precvbuf->ref_cnt = 0;
 133	if (precvbuf->pbuf) {
 134		precvbuf->pdata = precvbuf->pbuf;
 135		precvbuf->phead = precvbuf->pbuf;
 136		precvbuf->ptail = precvbuf->pbuf;
 137		precvbuf->pend = precvbuf->pdata + MAX_RECVBUF_SZ;
 138	}
 139	return res;
 140}
 141
 142int r8712_free_recvframe(union recv_frame *precvframe,
 143		   struct  __queue *pfree_recv_queue)
 144{
 145	unsigned long irqL;
 146	struct _adapter *padapter = precvframe->u.hdr.adapter;
 147	struct recv_priv *precvpriv = &padapter->recvpriv;
 148
 149	if (precvframe->u.hdr.pkt) {
 150		dev_kfree_skb_any(precvframe->u.hdr.pkt);/*free skb by driver*/
 151		precvframe->u.hdr.pkt = NULL;
 152	}
 153	spin_lock_irqsave(&pfree_recv_queue->lock, irqL);
 154	list_delete(&(precvframe->u.hdr.list));
 155	list_insert_tail(&(precvframe->u.hdr.list),
 156			 get_list_head(pfree_recv_queue));
 157	if (padapter != NULL) {
 158		if (pfree_recv_queue == &precvpriv->free_recv_queue)
 159				precvpriv->free_recvframe_cnt++;
 160	}
 161	spin_unlock_irqrestore(&pfree_recv_queue->lock, irqL);
 162	return _SUCCESS;
 163}
 164
 165static void update_recvframe_attrib_from_recvstat(struct rx_pkt_attrib *pattrib,
 166					   struct recv_stat *prxstat)
 167{
 168	u32 *pphy_info;
 169	struct phy_stat *pphy_stat;
 170	u16 drvinfo_sz = 0;
 171
 172	drvinfo_sz = (le32_to_cpu(prxstat->rxdw0)&0x000f0000)>>16;
 173	drvinfo_sz = drvinfo_sz<<3;
 174	/*TODO:
 175	 * Offset 0 */
 176	pattrib->bdecrypted = ((le32_to_cpu(prxstat->rxdw0) & BIT(27)) >> 27)
 177				 ? 0 : 1;
 178	pattrib->crc_err = ((le32_to_cpu(prxstat->rxdw0) & BIT(14)) >> 14);
 179	/*Offset 4*/
 180	/*Offset 8*/
 181	/*Offset 12*/
 182	if (le32_to_cpu(prxstat->rxdw3) & BIT(13)) {
 183		pattrib->tcpchk_valid = 1; /* valid */
 184		if (le32_to_cpu(prxstat->rxdw3) & BIT(11))
 185			pattrib->tcp_chkrpt = 1; /* correct */
 186		else
 187			pattrib->tcp_chkrpt = 0; /* incorrect */
 188		if (le32_to_cpu(prxstat->rxdw3) & BIT(12))
 189			pattrib->ip_chkrpt = 1; /* correct */
 190		else
 191			pattrib->ip_chkrpt = 0; /* incorrect */
 192	} else
 193		pattrib->tcpchk_valid = 0; /* invalid */
 194	pattrib->mcs_rate = (u8)((le32_to_cpu(prxstat->rxdw3)) & 0x3f);
 195	pattrib->htc = (u8)((le32_to_cpu(prxstat->rxdw3) >> 6) & 0x1);
 196	/*Offset 16*/
 197	/*Offset 20*/
 198	/*phy_info*/
 199	if (drvinfo_sz) {
 200		pphy_stat = (struct phy_stat *)(prxstat+1);
 201		pphy_info = (u32 *)prxstat+1;
 202	}
 203}
 204
 205/*perform defrag*/
 206static union recv_frame *recvframe_defrag(struct _adapter *adapter,
 207				   struct  __queue *defrag_q)
 208{
 209	struct list_head *plist, *phead;
 210	u8	wlanhdr_offset;
 211	u8	curfragnum;
 212	struct recv_frame_hdr *pfhdr, *pnfhdr;
 213	union recv_frame *prframe, *pnextrframe;
 214	struct  __queue	*pfree_recv_queue;
 215
 216	pfree_recv_queue = &adapter->recvpriv.free_recv_queue;
 217	phead = get_list_head(defrag_q);
 218	plist = get_next(phead);
 219	prframe = LIST_CONTAINOR(plist, union recv_frame, u);
 220	list_delete(&prframe->u.list);
 221	pfhdr = &prframe->u.hdr;
 222	curfragnum = 0;
 223	if (curfragnum != pfhdr->attrib.frag_num) {
 224		/*the first fragment number must be 0
 225		 *free the whole queue*/
 226		r8712_free_recvframe(prframe, pfree_recv_queue);
 227		prframe = NULL;
 228		goto exit;
 229	}
 230	plist = get_next(phead);
 231	while (end_of_queue_search(phead, plist) == false) {
 232		pnextrframe = LIST_CONTAINOR(plist, union recv_frame, u);
 233		/*check the fragment sequence  (2nd ~n fragment frame) */
 234		pnfhdr = &pnextrframe->u.hdr;
 235		curfragnum++;
 236		if (curfragnum != pnfhdr->attrib.frag_num) {
 237			/* the fragment number must increase  (after decache)
 238			 * release the defrag_q & prframe */
 239			r8712_free_recvframe(prframe, pfree_recv_queue);
 240			prframe = NULL;
 241			goto exit;
 242		}
 243		/* copy the 2nd~n fragment frame's payload to the first fragment
 244		 * get the 2nd~last fragment frame's payload */
 245		wlanhdr_offset = pnfhdr->attrib.hdrlen + pnfhdr->attrib.iv_len;
 246		recvframe_pull(pnextrframe, wlanhdr_offset);
 247		/* append  to first fragment frame's tail (if privacy frame,
 248		 * pull the ICV) */
 249		recvframe_pull_tail(prframe, pfhdr->attrib.icv_len);
 250		memcpy(pfhdr->rx_tail, pnfhdr->rx_data, pnfhdr->len);
 251		recvframe_put(prframe, pnfhdr->len);
 252		pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len;
 253		plist = get_next(plist);
 254	}
 255exit:
 256	/* free the defrag_q queue and return the prframe */
 257	r8712_free_recvframe_queue(defrag_q, pfree_recv_queue);
 258	return prframe;
 259}
 260
 261/* check if need to defrag, if needed queue the frame to defrag_q */
 262union recv_frame *r8712_recvframe_chk_defrag(struct _adapter *padapter,
 263					     union recv_frame *precv_frame)
 264{
 265	u8	ismfrag;
 266	u8	fragnum;
 267	u8   *psta_addr;
 268	struct recv_frame_hdr *pfhdr;
 269	struct sta_info *psta;
 270	struct	sta_priv *pstapriv ;
 271	struct list_head *phead;
 272	union recv_frame *prtnframe = NULL;
 273	struct  __queue *pfree_recv_queue, *pdefrag_q;
 274
 275	pstapriv = &padapter->stapriv;
 276	pfhdr = &precv_frame->u.hdr;
 277	pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
 278	/* need to define struct of wlan header frame ctrl */
 279	ismfrag = pfhdr->attrib.mfrag;
 280	fragnum = pfhdr->attrib.frag_num;
 281	psta_addr = pfhdr->attrib.ta;
 282	psta = r8712_get_stainfo(pstapriv, psta_addr);
 283	if (psta == NULL)
 284		pdefrag_q = NULL;
 285	else
 286		pdefrag_q = &psta->sta_recvpriv.defrag_q;
 287
 288	if ((ismfrag == 0) && (fragnum == 0))
 289		prtnframe = precv_frame;/*isn't a fragment frame*/
 290	if (ismfrag == 1) {
 291		/* 0~(n-1) fragment frame
 292		 * enqueue to defraf_g */
 293		if (pdefrag_q != NULL) {
 294			if (fragnum == 0) {
 295				/*the first fragment*/
 296				if (_queue_empty(pdefrag_q) == false) {
 297					/*free current defrag_q */
 298					r8712_free_recvframe_queue(pdefrag_q,
 299							     pfree_recv_queue);
 300				}
 301			}
 302			/* Then enqueue the 0~(n-1) fragment to the defrag_q */
 303			phead = get_list_head(pdefrag_q);
 304			list_insert_tail(&pfhdr->list, phead);
 305			prtnframe = NULL;
 306		} else {
 307			/* can't find this ta's defrag_queue, so free this
 308			 * recv_frame */
 309			r8712_free_recvframe(precv_frame, pfree_recv_queue);
 310			prtnframe = NULL;
 311		}
 312
 313	}
 314	if ((ismfrag == 0) && (fragnum != 0)) {
 315		/* the last fragment frame
 316		 * enqueue the last fragment */
 317		if (pdefrag_q != NULL) {
 318			phead = get_list_head(pdefrag_q);
 319			list_insert_tail(&pfhdr->list, phead);
 320			/*call recvframe_defrag to defrag*/
 321			precv_frame = recvframe_defrag(padapter, pdefrag_q);
 322			prtnframe = precv_frame;
 323		} else {
 324			/* can't find this ta's defrag_queue, so free this
 325			 *  recv_frame */
 326			r8712_free_recvframe(precv_frame, pfree_recv_queue);
 327			prtnframe = NULL;
 328		}
 329	}
 330	if ((prtnframe != NULL) && (prtnframe->u.hdr.attrib.privacy)) {
 331		/* after defrag we must check tkip mic code */
 332		if (r8712_recvframe_chkmic(padapter, prtnframe) == _FAIL) {
 333			r8712_free_recvframe(prtnframe, pfree_recv_queue);
 334			prtnframe = NULL;
 335		}
 336	}
 337	return prtnframe;
 338}
 339
 340static int amsdu_to_msdu(struct _adapter *padapter, union recv_frame *prframe)
 341{
 342	int	a_len, padding_len;
 343	u16	eth_type, nSubframe_Length;
 344	u8	nr_subframes, i;
 345	unsigned char *data_ptr, *pdata;
 346	struct rx_pkt_attrib *pattrib;
 347	_pkt *sub_skb, *subframes[MAX_SUBFRAME_COUNT];
 348	struct recv_priv *precvpriv = &padapter->recvpriv;
 349	struct  __queue *pfree_recv_queue = &(precvpriv->free_recv_queue);
 350	int	ret = _SUCCESS;
 351
 352	nr_subframes = 0;
 353	pattrib = &prframe->u.hdr.attrib;
 354	recvframe_pull(prframe, prframe->u.hdr.attrib.hdrlen);
 355	if (prframe->u.hdr.attrib.iv_len > 0)
 356		recvframe_pull(prframe, prframe->u.hdr.attrib.iv_len);
 357	a_len = prframe->u.hdr.len;
 358	pdata = prframe->u.hdr.rx_data;
 359	while (a_len > ETH_HLEN) {
 360		/* Offset 12 denote 2 mac address */
 361		nSubframe_Length = *((u16 *)(pdata + 12));
 362		/*==m==>change the length order*/
 363		nSubframe_Length = (nSubframe_Length >> 8) +
 364				   (nSubframe_Length << 8);
 365		if (a_len < (ETHERNET_HEADER_SIZE + nSubframe_Length)) {
 366			printk(KERN_WARNING "r8712u: nRemain_Length is %d and"
 367			    " nSubframe_Length is: %d\n",
 368			    a_len, nSubframe_Length);
 369			goto exit;
 370		}
 371		/* move the data point to data content */
 372		pdata += ETH_HLEN;
 373		a_len -= ETH_HLEN;
 374		/* Allocate new skb for releasing to upper layer */
 375		sub_skb = dev_alloc_skb(nSubframe_Length + 12);
 376		skb_reserve(sub_skb, 12);
 377		data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length);
 378		memcpy(data_ptr, pdata, nSubframe_Length);
 379		subframes[nr_subframes++] = sub_skb;
 380		if (nr_subframes >= MAX_SUBFRAME_COUNT) {
 381			printk(KERN_WARNING "r8712u: ParseSubframe(): Too"
 382			    " many Subframes! Packets dropped!\n");
 383			break;
 384		}
 385		pdata += nSubframe_Length;
 386		a_len -= nSubframe_Length;
 387		if (a_len != 0) {
 388			padding_len = 4 - ((nSubframe_Length + ETH_HLEN) & 3);
 389			if (padding_len == 4)
 390				padding_len = 0;
 391			if (a_len < padding_len)
 392				goto exit;
 393			pdata += padding_len;
 394			a_len -= padding_len;
 395		}
 396	}
 397	for (i = 0; i < nr_subframes; i++) {
 398		sub_skb = subframes[i];
 399		/* convert hdr + possible LLC headers into Ethernet header */
 400		eth_type = (sub_skb->data[6] << 8) | sub_skb->data[7];
 401		if (sub_skb->len >= 8 &&
 402		   ((!memcmp(sub_skb->data, rfc1042_header, SNAP_SIZE) &&
 403		   eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) ||
 404		   !memcmp(sub_skb->data, bridge_tunnel_header, SNAP_SIZE))) {
 405			/* remove RFC1042 or Bridge-Tunnel encapsulation and
 406			 * replace EtherType */
 407			skb_pull(sub_skb, SNAP_SIZE);
 408			memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src,
 409				ETH_ALEN);
 410			memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst,
 411				ETH_ALEN);
 412		} else {
 413			u16 len;
 414			/* Leave Ethernet header part of hdr and full payload */
 415			len = htons(sub_skb->len);
 416			memcpy(skb_push(sub_skb, 2), &len, 2);
 417			memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src,
 418				ETH_ALEN);
 419			memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst,
 420				ETH_ALEN);
 421		}
 422		/* Indicate the packets to upper layer */
 423		if (sub_skb) {
 424			sub_skb->protocol =
 425				 eth_type_trans(sub_skb, padapter->pnetdev);
 426			sub_skb->dev = padapter->pnetdev;
 427			if ((pattrib->tcpchk_valid == 1) &&
 428			    (pattrib->tcp_chkrpt == 1)) {
 429				sub_skb->ip_summed = CHECKSUM_UNNECESSARY;
 430			} else
 431				sub_skb->ip_summed = CHECKSUM_NONE;
 432			netif_rx(sub_skb);
 433		}
 434	}
 435exit:
 436	prframe->u.hdr.len = 0;
 437	r8712_free_recvframe(prframe, pfree_recv_queue);
 438	return ret;
 439}
 440
 441void r8712_rxcmd_event_hdl(struct _adapter *padapter, void *prxcmdbuf)
 442{
 443	uint voffset;
 444	u8 *poffset;
 445	u16 pkt_len, cmd_len, drvinfo_sz;
 446	u8 eid, cmd_seq;
 447	struct recv_stat *prxstat;
 448
 449	poffset = (u8 *)prxcmdbuf;
 450	voffset = *(uint *)poffset;
 451	pkt_len = le32_to_cpu(voffset) & 0x00003fff;
 452	prxstat = (struct recv_stat *)prxcmdbuf;
 453	drvinfo_sz = ((le32_to_cpu(prxstat->rxdw0) & 0x000f0000) >> 16);
 454	drvinfo_sz = drvinfo_sz << 3;
 455	poffset += RXDESC_SIZE + drvinfo_sz;
 456	do {
 457		voffset  = *(uint *)poffset;
 458		cmd_len = (u16)(le32_to_cpu(voffset) & 0xffff);
 459		cmd_seq = (u8)((le32_to_cpu(voffset) >> 24) & 0x7f);
 460		eid = (u8)((le32_to_cpu(voffset) >> 16) & 0xff);
 461		r8712_event_handle(padapter, (uint *)poffset);
 462		poffset += (cmd_len + 8);/*8 bytes aligment*/
 463	} while (le32_to_cpu(voffset) & BIT(31));
 464
 465}
 466
 467static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl,
 468			      u16 seq_num)
 469{
 470	u8 wsize = preorder_ctrl->wsize_b;
 471	u16 wend = (preorder_ctrl->indicate_seq + wsize - 1) % 4096;
 472
 473	/* Rx Reorder initialize condition.*/
 474	if (preorder_ctrl->indicate_seq == 0xffff)
 475		preorder_ctrl->indicate_seq = seq_num;
 476	/* Drop out the packet which SeqNum is smaller than WinStart */
 477	if (SN_LESS(seq_num, preorder_ctrl->indicate_seq))
 478		return false;
 479	/*
 480	 * Sliding window manipulation. Conditions includes:
 481	 * 1. Incoming SeqNum is equal to WinStart =>Window shift 1
 482	 * 2. Incoming SeqNum is larger than the WinEnd => Window shift N
 483	 */
 484	if (SN_EQUAL(seq_num, preorder_ctrl->indicate_seq))
 485		preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq +
 486					      1) % 4096;
 487	else if (SN_LESS(wend, seq_num)) {
 488		if (seq_num >= (wsize - 1))
 489			preorder_ctrl->indicate_seq = seq_num + 1 - wsize;
 490		else
 491			preorder_ctrl->indicate_seq = 4095 - (wsize -
 492						      (seq_num + 1)) + 1;
 493	}
 494	return true;
 495}
 496
 497static int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl,
 498			      union recv_frame *prframe)
 499{
 500	struct list_head *phead, *plist;
 501	union recv_frame *pnextrframe;
 502	struct rx_pkt_attrib *pnextattrib;
 503	struct  __queue *ppending_recvframe_queue =
 504					&preorder_ctrl->pending_recvframe_queue;
 505	struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
 506
 507	phead = get_list_head(ppending_recvframe_queue);
 508	plist = get_next(phead);
 509	while (end_of_queue_search(phead, plist) == false) {
 510		pnextrframe = LIST_CONTAINOR(plist, union recv_frame, u);
 511		pnextattrib = &pnextrframe->u.hdr.attrib;
 512		if (SN_LESS(pnextattrib->seq_num, pattrib->seq_num))
 513			plist = get_next(plist);
 514		else if (SN_EQUAL(pnextattrib->seq_num, pattrib->seq_num))
 515			return false;
 516		else
 517			break;
 518	}
 519	list_delete(&(prframe->u.hdr.list));
 520	list_insert_tail(&(prframe->u.hdr.list), plist);
 521	return true;
 522}
 523
 524int r8712_recv_indicatepkts_in_order(struct _adapter *padapter,
 525			       struct recv_reorder_ctrl *preorder_ctrl,
 526			       int bforced)
 527{
 528	struct list_head *phead, *plist;
 529	union recv_frame *prframe;
 530	struct rx_pkt_attrib *pattrib;
 531	int bPktInBuf = false;
 532	struct recv_priv *precvpriv = &padapter->recvpriv;
 533	struct  __queue *ppending_recvframe_queue =
 534			 &preorder_ctrl->pending_recvframe_queue;
 535
 536	phead = get_list_head(ppending_recvframe_queue);
 537	plist = get_next(phead);
 538	/* Handling some condition for forced indicate case.*/
 539	if (bforced == true) {
 540		if (is_list_empty(phead))
 541			return true;
 542		else {
 543			prframe = LIST_CONTAINOR(plist, union recv_frame, u);
 544			pattrib = &prframe->u.hdr.attrib;
 545			preorder_ctrl->indicate_seq = pattrib->seq_num;
 546		}
 547	}
 548	/* Prepare indication list and indication.
 549	 * Check if there is any packet need indicate. */
 550	while (!is_list_empty(phead)) {
 551		prframe = LIST_CONTAINOR(plist, union recv_frame, u);
 552		pattrib = &prframe->u.hdr.attrib;
 553		if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) {
 554			plist = get_next(plist);
 555			list_delete(&(prframe->u.hdr.list));
 556			if (SN_EQUAL(preorder_ctrl->indicate_seq,
 557			    pattrib->seq_num))
 558				preorder_ctrl->indicate_seq =
 559				  (preorder_ctrl->indicate_seq + 1) % 4096;
 560			/*indicate this recv_frame*/
 561			if (!pattrib->amsdu) {
 562				if ((padapter->bDriverStopped == false) &&
 563				    (padapter->bSurpriseRemoved == false)) {
 564					/* indicate this recv_frame */
 565					r8712_recv_indicatepkt(padapter,
 566							       prframe);
 567				}
 568			} else if (pattrib->amsdu == 1) {
 569				if (amsdu_to_msdu(padapter, prframe) !=
 570				    _SUCCESS)
 571					r8712_free_recvframe(prframe,
 572						   &precvpriv->free_recv_queue);
 573			}
 574			/* Update local variables. */
 575			bPktInBuf = false;
 576		} else {
 577			bPktInBuf = true;
 578			break;
 579		}
 580	}
 581	return bPktInBuf;
 582}
 583
 584static int recv_indicatepkt_reorder(struct _adapter *padapter,
 585			     union recv_frame *prframe)
 586{
 587	unsigned long irql;
 588	struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
 589	struct recv_reorder_ctrl *preorder_ctrl = prframe->u.hdr.preorder_ctrl;
 590	struct  __queue *ppending_recvframe_queue =
 591			 &preorder_ctrl->pending_recvframe_queue;
 592
 593	if (!pattrib->amsdu) {
 594		/* s1. */
 595		r8712_wlanhdr_to_ethhdr(prframe);
 596		if (pattrib->qos != 1) {
 597			if ((padapter->bDriverStopped == false) &&
 598			   (padapter->bSurpriseRemoved == false)) {
 599				r8712_recv_indicatepkt(padapter, prframe);
 600				return _SUCCESS;
 601			} else
 602				return _FAIL;
 603		}
 604	}
 605	spin_lock_irqsave(&ppending_recvframe_queue->lock, irql);
 606	/*s2. check if winstart_b(indicate_seq) needs to been updated*/
 607	if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num))
 608		goto _err_exit;
 609	/*s3. Insert all packet into Reorder Queue to maintain its ordering.*/
 610	if (!enqueue_reorder_recvframe(preorder_ctrl, prframe))
 611		goto _err_exit;
 612	/*s4.
 613	 * Indication process.
 614	 * After Packet dropping and Sliding Window shifting as above, we can
 615	 * now just indicate the packets with the SeqNum smaller than latest
 616	 * WinStart and buffer other packets.
 617	 *
 618	 * For Rx Reorder condition:
 619	 * 1. All packets with SeqNum smaller than WinStart => Indicate
 620	 * 2. All packets with SeqNum larger than or equal to
 621	 * WinStart => Buffer it.
 622	 */
 623	if (r8712_recv_indicatepkts_in_order(padapter, preorder_ctrl, false) ==
 624	    true) {
 625		_set_timer(&preorder_ctrl->reordering_ctrl_timer,
 626			   REORDER_WAIT_TIME);
 627		spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql);
 628	} else {
 629		spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql);
 630		_cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer);
 631	}
 632	return _SUCCESS;
 633_err_exit:
 634	spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql);
 635	return _FAIL;
 636}
 637
 638void r8712_reordering_ctrl_timeout_handler(void *pcontext)
 639{
 640	unsigned long irql;
 641	struct recv_reorder_ctrl *preorder_ctrl =
 642				 (struct recv_reorder_ctrl *)pcontext;
 643	struct _adapter *padapter = preorder_ctrl->padapter;
 644	struct  __queue *ppending_recvframe_queue =
 645				 &preorder_ctrl->pending_recvframe_queue;
 646
 647	if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
 648		return;
 649	spin_lock_irqsave(&ppending_recvframe_queue->lock, irql);
 650	r8712_recv_indicatepkts_in_order(padapter, preorder_ctrl, true);
 651	spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql);
 652}
 653
 654static int r8712_process_recv_indicatepkts(struct _adapter *padapter,
 655			      union recv_frame *prframe)
 656{
 657	int retval = _SUCCESS;
 658	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 659	struct ht_priv	*phtpriv = &pmlmepriv->htpriv;
 660
 661	if (phtpriv->ht_option == 1) { /*B/G/N Mode*/
 662		if (recv_indicatepkt_reorder(padapter, prframe) != _SUCCESS) {
 663			/* including perform A-MPDU Rx Ordering Buffer Control*/
 664			if ((padapter->bDriverStopped == false) &&
 665			    (padapter->bSurpriseRemoved == false))
 666				return _FAIL;
 667		}
 668	} else { /*B/G mode*/
 669		retval = r8712_wlanhdr_to_ethhdr(prframe);
 670		if (retval != _SUCCESS)
 671			return retval;
 672		if ((padapter->bDriverStopped == false) &&
 673		    (padapter->bSurpriseRemoved == false)) {
 674			/* indicate this recv_frame */
 675			r8712_recv_indicatepkt(padapter, prframe);
 676		} else
 677			return _FAIL;
 678	}
 679	return retval;
 680}
 681
 682static u8 query_rx_pwr_percentage(s8 antpower)
 683{
 684	if ((antpower <= -100) || (antpower >= 20))
 685		return	0;
 686	else if (antpower >= 0)
 687		return	100;
 688	else
 689		return 100 + antpower;
 690}
 691
 692static u8 evm_db2percentage(s8 value)
 693{
 694	/*
 695	 * -33dB~0dB to 0%~99%
 696	 */
 697	s8 ret_val;
 698
 699	ret_val = value;
 700	if (ret_val >= 0)
 701		ret_val = 0;
 702	if (ret_val <= -33)
 703		ret_val = -33;
 704	ret_val = -ret_val;
 705	ret_val *= 3;
 706	if (ret_val == 99)
 707		ret_val = 100;
 708	return ret_val;
 709}
 710
 711s32 r8712_signal_scale_mapping(s32 cur_sig)
 712{
 713	s32 ret_sig;
 714
 715	if (cur_sig >= 51 && cur_sig <= 100)
 716		ret_sig = 100;
 717	else if (cur_sig >= 41 && cur_sig <= 50)
 718		ret_sig = 80 + ((cur_sig - 40) * 2);
 719	else if (cur_sig >= 31 && cur_sig <= 40)
 720		ret_sig = 66 + (cur_sig - 30);
 721	else if (cur_sig >= 21 && cur_sig <= 30)
 722		ret_sig = 54 + (cur_sig - 20);
 723	else if (cur_sig >= 10 && cur_sig <= 20)
 724		ret_sig = 42 + (((cur_sig - 10) * 2) / 3);
 725	else if (cur_sig >= 5 && cur_sig <= 9)
 726		ret_sig = 22 + (((cur_sig - 5) * 3) / 2);
 727	else if (cur_sig >= 1 && cur_sig <= 4)
 728		ret_sig = 6 + (((cur_sig - 1) * 3) / 2);
 729	else
 730		ret_sig = cur_sig;
 731	return ret_sig;
 732}
 733
 734static s32  translate2dbm(struct _adapter *padapter, u8 signal_strength_idx)
 735{
 736	s32 signal_power; /* in dBm.*/
 737	/* Translate to dBm (x=0.5y-95).*/
 738	signal_power = (s32)((signal_strength_idx + 1) >> 1);
 739	signal_power -= 95;
 740	return signal_power;
 741}
 742
 743static void query_rx_phy_status(struct _adapter *padapter,
 744				union recv_frame *prframe)
 745{
 746	u8 i, max_spatial_stream, evm;
 747	struct recv_stat *prxstat = (struct recv_stat *)prframe->u.hdr.rx_head;
 748	struct phy_stat *pphy_stat = (struct phy_stat *)(prxstat + 1);
 749	u8 *pphy_head = (u8 *)(prxstat + 1);
 750	s8 rx_pwr[4], rx_pwr_all;
 751	u8 pwdb_all;
 752	u32 rssi, total_rssi = 0;
 753	u8 bcck_rate = 0, rf_rx_num = 0, cck_highpwr = 0;
 754	struct phy_cck_rx_status *pcck_buf;
 755	u8 sq;
 756
 757	/* Record it for next packet processing*/
 758	bcck_rate = (prframe->u.hdr.attrib.mcs_rate <= 3 ? 1 : 0);
 759	if (bcck_rate) {
 760		u8 report;
 761
 762		/* CCK Driver info Structure is not the same as OFDM packet.*/
 763		pcck_buf = (struct phy_cck_rx_status *)pphy_stat;
 764		/* (1)Hardware does not provide RSSI for CCK
 765		 * (2)PWDB, Average PWDB cacluated by hardware
 766		 * (for rate adaptive)
 767		 */
 768		if (!cck_highpwr) {
 769			report = pcck_buf->cck_agc_rpt & 0xc0;
 770			report = report >> 6;
 771			switch (report) {
 772			/* Modify the RF RNA gain value to -40, -20,
 773			 * -2, 14 by Jenyu's suggestion
 774			 * Note: different RF with the different
 775			 * RNA gain. */
 776			case 0x3:
 777				rx_pwr_all = -40 - (pcck_buf->cck_agc_rpt &
 778					     0x3e);
 779				break;
 780			case 0x2:
 781				rx_pwr_all = -20 - (pcck_buf->cck_agc_rpt &
 782					     0x3e);
 783				break;
 784			case 0x1:
 785				rx_pwr_all = -2 - (pcck_buf->cck_agc_rpt &
 786					     0x3e);
 787				break;
 788			case 0x0:
 789				rx_pwr_all = 14 - (pcck_buf->cck_agc_rpt &
 790					     0x3e);
 791				break;
 792			}
 793		} else {
 794			report = ((u8)(le32_to_cpu(pphy_stat->phydw1) >> 8)) &
 795				 0x60;
 796			report = report >> 5;
 797			switch (report) {
 798			case 0x3:
 799				rx_pwr_all = -40 - ((pcck_buf->cck_agc_rpt &
 800					     0x1f) << 1);
 801				break;
 802			case 0x2:
 803				rx_pwr_all = -20 - ((pcck_buf->cck_agc_rpt &
 804					     0x1f) << 1);
 805				break;
 806			case 0x1:
 807				rx_pwr_all = -2 - ((pcck_buf->cck_agc_rpt &
 808					     0x1f) << 1);
 809				break;
 810			case 0x0:
 811				rx_pwr_all = 14 - ((pcck_buf->cck_agc_rpt &
 812					     0x1f) << 1);
 813				break;
 814			}
 815		}
 816		pwdb_all = query_rx_pwr_percentage(rx_pwr_all);
 817		/* CCK gain is smaller than OFDM/MCS gain,*/
 818		/* so we add gain diff by experiences, the val is 6 */
 819		pwdb_all += 6;
 820		if (pwdb_all > 100)
 821			pwdb_all = 100;
 822		/* modify the offset to make the same gain index with OFDM.*/
 823		if (pwdb_all > 34 && pwdb_all <= 42)
 824			pwdb_all -= 2;
 825		else if (pwdb_all > 26 && pwdb_all <= 34)
 826			pwdb_all -= 6;
 827		else if (pwdb_all > 14 && pwdb_all <= 26)
 828			pwdb_all -= 8;
 829		else if (pwdb_all > 4 && pwdb_all <= 14)
 830			pwdb_all -= 4;
 831		/*
 832		 * (3) Get Signal Quality (EVM)
 833		 */
 834		if (pwdb_all > 40)
 835			sq = 100;
 836		else {
 837			sq = pcck_buf->sq_rpt;
 838			if (pcck_buf->sq_rpt > 64)
 839				sq = 0;
 840			else if (pcck_buf->sq_rpt < 20)
 841				sq = 100;
 842			else
 843				sq = ((64-sq) * 100) / 44;
 844		}
 845		prframe->u.hdr.attrib.signal_qual = sq;
 846		prframe->u.hdr.attrib.rx_mimo_signal_qual[0] = sq;
 847		prframe->u.hdr.attrib.rx_mimo_signal_qual[1] = -1;
 848	} else {
 849		/* (1)Get RSSI for HT rate */
 850		for (i = 0; i < ((padapter->registrypriv.rf_config) &
 851			    0x0f) ; i++) {
 852			rf_rx_num++;
 853			rx_pwr[i] = ((pphy_head[PHY_STAT_GAIN_TRSW_SHT + i]
 854				    & 0x3F) * 2) - 110;
 855			/* Translate DBM to percentage. */
 856			rssi = query_rx_pwr_percentage(rx_pwr[i]);
 857			total_rssi += rssi;
 858		}
 859		/* (2)PWDB, Average PWDB cacluated by hardware (for
 860		 * rate adaptive) */
 861		rx_pwr_all = (((pphy_head[PHY_STAT_PWDB_ALL_SHT]) >> 1) & 0x7f)
 862			     - 106;
 863		pwdb_all = query_rx_pwr_percentage(rx_pwr_all);
 864
 865		{
 866			/* (3)EVM of HT rate */
 867			if (prframe->u.hdr.attrib.htc &&
 868			    prframe->u.hdr.attrib.mcs_rate >= 20 &&
 869			    prframe->u.hdr.attrib.mcs_rate <= 27) {
 870				/* both spatial stream make sense */
 871				max_spatial_stream = 2;
 872			} else {
 873				/* only spatial stream 1 makes sense */
 874				max_spatial_stream = 1;
 875			}
 876			for (i = 0; i < max_spatial_stream; i++) {
 877				evm = evm_db2percentage((pphy_head
 878				      [PHY_STAT_RXEVM_SHT + i]));/*dbm*/
 879				prframe->u.hdr.attrib.signal_qual =
 880					 (u8)(evm & 0xff);
 881				prframe->u.hdr.attrib.rx_mimo_signal_qual[i] =
 882					 (u8)(evm & 0xff);
 883			}
 884		}
 885	}
 886	/* UI BSS List signal strength(in percentage), make it good looking,
 887	 * from 0~100. It is assigned to the BSS List in
 888	 * GetValueFromBeaconOrProbeRsp(). */
 889	if (bcck_rate)
 890		prframe->u.hdr.attrib.signal_strength =
 891			 (u8)r8712_signal_scale_mapping(pwdb_all);
 892	else {
 893		if (rf_rx_num != 0)
 894			prframe->u.hdr.attrib.signal_strength =
 895				 (u8)(r8712_signal_scale_mapping(total_rssi /=
 896				 rf_rx_num));
 897	}
 898}
 899
 900static void process_link_qual(struct _adapter *padapter,
 901			      union recv_frame *prframe)
 902{
 903	u32	last_evm = 0, tmpVal;
 904	struct rx_pkt_attrib *pattrib;
 905
 906	if (prframe == NULL || padapter == NULL)
 907		return;
 908	pattrib = &prframe->u.hdr.attrib;
 909	if (pattrib->signal_qual != 0) {
 910		/*
 911		 * 1. Record the general EVM to the sliding window.
 912		 */
 913		if (padapter->recvpriv.signal_qual_data.total_num++ >=
 914				  PHY_LINKQUALITY_SLID_WIN_MAX) {
 915			padapter->recvpriv.signal_qual_data.total_num =
 916				  PHY_LINKQUALITY_SLID_WIN_MAX;
 917			last_evm = padapter->recvpriv.signal_qual_data.elements
 918				  [padapter->recvpriv.signal_qual_data.index];
 919			padapter->recvpriv.signal_qual_data.total_val -=
 920				  last_evm;
 921		}
 922		padapter->recvpriv.signal_qual_data.total_val +=
 923			  pattrib->signal_qual;
 924		padapter->recvpriv.signal_qual_data.elements[padapter->
 925			  recvpriv.signal_qual_data.index++] =
 926			  pattrib->signal_qual;
 927		if (padapter->recvpriv.signal_qual_data.index >=
 928		    PHY_LINKQUALITY_SLID_WIN_MAX)
 929			padapter->recvpriv.signal_qual_data.index = 0;
 930
 931		/* <1> Showed on UI for user, in percentage. */
 932		tmpVal = padapter->recvpriv.signal_qual_data.total_val /
 933			 padapter->recvpriv.signal_qual_data.total_num;
 934		padapter->recvpriv.signal = (u8)tmpVal;
 935	}
 936}
 937
 938static void process_rssi(struct _adapter *padapter, union recv_frame *prframe)
 939{
 940	u32 last_rssi, tmp_val;
 941	struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
 942
 943	if (padapter->recvpriv.signal_strength_data.total_num++ >=
 944	    PHY_RSSI_SLID_WIN_MAX) {
 945		padapter->recvpriv.signal_strength_data.total_num =
 946			 PHY_RSSI_SLID_WIN_MAX;
 947		last_rssi = padapter->recvpriv.signal_strength_data.elements
 948			    [padapter->recvpriv.signal_strength_data.index];
 949		padapter->recvpriv.signal_strength_data.total_val -= last_rssi;
 950	}
 951	padapter->recvpriv.signal_strength_data.total_val +=
 952			pattrib->signal_strength;
 953	padapter->recvpriv.signal_strength_data.elements[padapter->recvpriv.
 954			signal_strength_data.index++] =
 955			pattrib->signal_strength;
 956	if (padapter->recvpriv.signal_strength_data.index >=
 957	    PHY_RSSI_SLID_WIN_MAX)
 958		padapter->recvpriv.signal_strength_data.index = 0;
 959	tmp_val = padapter->recvpriv.signal_strength_data.total_val /
 960		  padapter->recvpriv.signal_strength_data.total_num;
 961	padapter->recvpriv.rssi = (s8)translate2dbm(padapter, (u8)tmp_val);
 962}
 963
 964static void process_phy_info(struct _adapter *padapter,
 965			     union recv_frame *prframe)
 966{
 967	query_rx_phy_status(padapter, prframe);
 968	process_rssi(padapter, prframe);
 969	process_link_qual(padapter,  prframe);
 970}
 971
 972int recv_func(struct _adapter *padapter, void *pcontext)
 973{
 974	struct rx_pkt_attrib *pattrib;
 975	union recv_frame *prframe, *orig_prframe;
 976	int retval = _SUCCESS;
 977	struct  __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
 978	struct	mlme_priv	*pmlmepriv = &padapter->mlmepriv;
 979
 980	prframe = (union recv_frame *)pcontext;
 981	orig_prframe = prframe;
 982	pattrib = &prframe->u.hdr.attrib;
 983	if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true)) {
 984		if (pattrib->crc_err == 1)
 985			padapter->mppriv.rx_crcerrpktcount++;
 986		else
 987			padapter->mppriv.rx_pktcount++;
 988		if (check_fwstate(pmlmepriv, WIFI_MP_LPBK_STATE) == false) {
 989			/* free this recv_frame */
 990			r8712_free_recvframe(orig_prframe, pfree_recv_queue);
 991			goto _exit_recv_func;
 992		}
 993	}
 994	/* check the frame crtl field and decache */
 995	retval = r8712_validate_recv_frame(padapter, prframe);
 996	if (retval != _SUCCESS) {
 997		/* free this recv_frame */
 998		r8712_free_recvframe(orig_prframe, pfree_recv_queue);
 999		goto _exit_recv_func;
1000	}
1001	process_phy_info(padapter, prframe);
1002	prframe = r8712_decryptor(padapter, prframe);
1003	if (prframe == NULL) {
1004		retval = _FAIL;
1005		goto _exit_recv_func;
1006	}
1007	prframe = r8712_recvframe_chk_defrag(padapter, prframe);
1008	if (prframe == NULL)
1009		goto _exit_recv_func;
1010	prframe = r8712_portctrl(padapter, prframe);
1011	if (prframe == NULL) {
1012		retval = _FAIL;
1013		goto _exit_recv_func;
1014	}
1015	retval = r8712_process_recv_indicatepkts(padapter, prframe);
1016	if (retval != _SUCCESS) {
1017		r8712_free_recvframe(orig_prframe, pfree_recv_queue);
1018		goto _exit_recv_func;
1019	}
1020_exit_recv_func:
1021	return retval;
1022}
1023
1024static int recvbuf2recvframe(struct _adapter *padapter, struct sk_buff *pskb)
1025{
1026	u8 *pbuf, shift_sz = 0;
1027	u8	frag, mf;
1028	uint	pkt_len;
1029	u32 transfer_len;
1030	struct recv_stat *prxstat;
1031	u16	pkt_cnt, drvinfo_sz, pkt_offset, tmp_len, alloc_sz;
1032	struct  __queue *pfree_recv_queue;
1033	_pkt  *pkt_copy = NULL;
1034	union recv_frame *precvframe = NULL;
1035	struct recv_priv *precvpriv = &padapter->recvpriv;
1036
1037	pfree_recv_queue = &(precvpriv->free_recv_queue);
1038	pbuf = pskb->data;
1039	prxstat = (struct recv_stat *)pbuf;
1040	pkt_cnt = (le32_to_cpu(prxstat->rxdw2)>>16)&0xff;
1041	pkt_len =  le32_to_cpu(prxstat->rxdw0)&0x00003fff;
1042	transfer_len = pskb->len;
1043	/* Test throughput with Netgear 3700 (No security) with Chariot 3T3R
1044	 * pairs. The packet count will be a big number so that the containing
1045	 * packet will effect the Rx reordering. */
1046	if (transfer_len < pkt_len) {
1047		/* In this case, it means the MAX_RECVBUF_SZ is too small to
1048		 * get the data from 8712u. */
1049		return _FAIL;
1050	}
1051	do {
1052		prxstat = (struct recv_stat *)pbuf;
1053		pkt_len =  le32_to_cpu(prxstat->rxdw0)&0x00003fff;
1054		/* more fragment bit */
1055		mf = (le32_to_cpu(prxstat->rxdw1) >> 27) & 0x1;
1056		/* ragmentation number */
1057		frag = (le32_to_cpu(prxstat->rxdw2) >> 12) & 0xf;
1058		/* uint 2^3 = 8 bytes */
1059		drvinfo_sz = (le32_to_cpu(prxstat->rxdw0) & 0x000f0000) >> 16;
1060		drvinfo_sz = drvinfo_sz<<3;
1061		if (pkt_len <= 0)
1062			goto  _exit_recvbuf2recvframe;
1063		/* Qos data, wireless lan header length is 26 */
1064		if ((le32_to_cpu(prxstat->rxdw0) >> 23) & 0x01)
1065			shift_sz = 2;
1066		precvframe = r8712_alloc_recvframe(pfree_recv_queue);
1067		if (precvframe == NULL)
1068			goto  _exit_recvbuf2recvframe;
1069		_init_listhead(&precvframe->u.hdr.list);
1070		precvframe->u.hdr.precvbuf = NULL; /*can't access the precvbuf*/
1071		precvframe->u.hdr.len = 0;
1072		tmp_len = pkt_len + drvinfo_sz + RXDESC_SIZE;
1073		pkt_offset = (u16)_RND128(tmp_len);
1074		/* for first fragment packet, driver need allocate 1536 +
1075		 * drvinfo_sz + RXDESC_SIZE to defrag packet. */
1076		if ((mf == 1) && (frag == 0))
1077			alloc_sz = 1658;
1078		else
1079			alloc_sz = tmp_len;
1080		/* 2 is for IP header 4 bytes alignment in QoS packet case.
1081		 * 4 is for skb->data 4 bytes alignment. */
1082		alloc_sz += 6;
1083		pkt_copy = netdev_alloc_skb(padapter->pnetdev, alloc_sz);
1084		if (pkt_copy) {
1085			pkt_copy->dev = padapter->pnetdev;
1086			precvframe->u.hdr.pkt = pkt_copy;
1087			skb_reserve(pkt_copy, 4 - ((addr_t)(pkt_copy->data)
1088				    % 4));
1089			skb_reserve(pkt_copy, shift_sz);
1090			memcpy(pkt_copy->data, pbuf, tmp_len);
1091			precvframe->u.hdr.rx_head = precvframe->u.hdr.rx_data =
1092				 precvframe->u.hdr.rx_tail = pkt_copy->data;
1093			precvframe->u.hdr.rx_end = pkt_copy->data + alloc_sz;
1094		} else {
1095			precvframe->u.hdr.pkt = skb_clone(pskb, GFP_ATOMIC);
1096			precvframe->u.hdr.rx_head = pbuf;
1097			precvframe->u.hdr.rx_data = pbuf;
1098			precvframe->u.hdr.rx_tail = pbuf;
1099			precvframe->u.hdr.rx_end = pbuf + alloc_sz;
1100		}
1101		recvframe_put(precvframe, tmp_len);
1102		recvframe_pull(precvframe, drvinfo_sz + RXDESC_SIZE);
1103		/* because the endian issue, driver avoid reference to the
1104		 * rxstat after calling update_recvframe_attrib_from_recvstat();
1105		 */
1106		update_recvframe_attrib_from_recvstat(&precvframe->u.hdr.attrib,
1107						      prxstat);
1108		r8712_recv_entry(precvframe);
1109		transfer_len -= pkt_offset;
1110		pbuf += pkt_offset;
1111		pkt_cnt--;
1112		precvframe = NULL;
1113		pkt_copy = NULL;
1114	} while ((transfer_len > 0) && pkt_cnt > 0);
1115_exit_recvbuf2recvframe:
1116	return _SUCCESS;
1117}
1118
1119static void recv_tasklet(void *priv)
1120{
1121	struct sk_buff *pskb;
1122	struct _adapter *padapter = (struct _adapter *)priv;
1123	struct recv_priv *precvpriv = &padapter->recvpriv;
1124
1125	while (NULL != (pskb = skb_dequeue(&precvpriv->rx_skb_queue))) {
1126		recvbuf2recvframe(padapter, pskb);
1127		skb_reset_tail_pointer(pskb);
1128		pskb->len = 0;
1129		skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
1130	}
1131}