[go: nahoru, domu]

1/******************************************************************************
2 *
3 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 ******************************************************************************/
15#define _RTL8192C_XMIT_C_
16#include <osdep_service.h>
17#include <drv_types.h>
18#include <wifi.h>
19#include <osdep_intf.h>
20#include <usb_ops.h>
21/* include <rtl8192c_hal.h> */
22#include <rtl8723a_hal.h>
23
24static void do_queue_select(struct rtw_adapter	*padapter, struct pkt_attrib *pattrib)
25{
26	u8 qsel;
27
28	qsel = pattrib->priority;
29	RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
30		 ("### do_queue_select priority =%d , qsel = %d\n",
31		  pattrib->priority, qsel));
32
33	pattrib->qsel = qsel;
34}
35
36static int urb_zero_packet_chk(struct rtw_adapter *padapter, int sz)
37{
38	int blnSetTxDescOffset;
39	struct dvobj_priv	*pdvobj = adapter_to_dvobj(padapter);
40
41	if (pdvobj->ishighspeed) {
42		if (((sz + TXDESC_SIZE) % 512) == 0)
43			blnSetTxDescOffset = 1;
44		else
45			blnSetTxDescOffset = 0;
46	} else {
47		if (((sz + TXDESC_SIZE) % 64) == 0)
48			blnSetTxDescOffset = 1;
49		else
50			blnSetTxDescOffset = 0;
51	}
52	return blnSetTxDescOffset;
53}
54
55static void rtl8192cu_cal_txdesc_chksum(struct tx_desc	*ptxdesc)
56{
57		u16	*usPtr = (u16 *)ptxdesc;
58		u32 count = 16;		/*  (32 bytes / 2 bytes per XOR) => 16 times */
59		u32 index;
60		u16 checksum = 0;
61
62		/* Clear first */
63		ptxdesc->txdw7 &= cpu_to_le32(0xffff0000);
64
65		for (index = 0 ; index < count ; index++)
66			checksum = checksum ^ le16_to_cpu(*(usPtr + index));
67
68		ptxdesc->txdw7 |= cpu_to_le32(0x0000ffff&checksum);
69}
70
71static void fill_txdesc_sectype(struct pkt_attrib *pattrib, struct tx_desc *ptxdesc)
72{
73	if ((pattrib->encrypt > 0) && !pattrib->bswenc) {
74		switch (pattrib->encrypt) {
75		/* SEC_TYPE */
76		case WLAN_CIPHER_SUITE_WEP40:
77		case WLAN_CIPHER_SUITE_WEP104:
78			ptxdesc->txdw1 |= cpu_to_le32((0x01<<22)&0x00c00000);
79			break;
80		case WLAN_CIPHER_SUITE_TKIP:
81			/* ptxdesc->txdw1 |= cpu_to_le32((0x02<<22)&0x00c00000); */
82			ptxdesc->txdw1 |= cpu_to_le32((0x01<<22)&0x00c00000);
83			break;
84		case WLAN_CIPHER_SUITE_CCMP:
85			ptxdesc->txdw1 |= cpu_to_le32((0x03<<22)&0x00c00000);
86			break;
87		case 0:
88		default:
89			break;
90		}
91	}
92}
93
94static void fill_txdesc_vcs(struct pkt_attrib *pattrib, u32 *pdw)
95{
96	/* DBG_8723A("cvs_mode =%d\n", pattrib->vcs_mode); */
97
98	switch (pattrib->vcs_mode) {
99	case RTS_CTS:
100		*pdw |= cpu_to_le32(BIT(12));
101		break;
102	case CTS_TO_SELF:
103		*pdw |= cpu_to_le32(BIT(11));
104		break;
105	case NONE_VCS:
106	default:
107		break;
108	}
109
110	if (pattrib->vcs_mode) {
111		*pdw |= cpu_to_le32(BIT(13));
112
113		/*  Set RTS BW */
114		if (pattrib->ht_en) {
115			*pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ?	cpu_to_le32(BIT(27)) : 0;
116
117			if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
118				*pdw |= cpu_to_le32((0x01<<28)&0x30000000);
119			else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
120				*pdw |= cpu_to_le32((0x02<<28)&0x30000000);
121			else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)
122				*pdw |= 0;
123			else
124				*pdw |= cpu_to_le32((0x03<<28)&0x30000000);
125		}
126	}
127}
128
129static void fill_txdesc_phy(struct pkt_attrib *pattrib, u32 *pdw)
130{
131	if (pattrib->ht_en) {
132		*pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(25)) : 0;
133
134		if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
135			*pdw |= cpu_to_le32((0x01<<20)&0x003f0000);
136		else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
137			*pdw |= cpu_to_le32((0x02<<20)&0x003f0000);
138		else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)
139			*pdw |= 0;
140		else
141			*pdw |= cpu_to_le32((0x03<<20)&0x003f0000);
142	}
143}
144
145static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz, u8 bagg_pkt)
146{
147	int	pull = 0;
148	uint	qsel;
149	struct rtw_adapter	*padapter = pxmitframe->padapter;
150	struct pkt_attrib	*pattrib = &pxmitframe->attrib;
151	struct hal_data_8723a	*pHalData = GET_HAL_DATA(padapter);
152	struct dm_priv	*pdmpriv = &pHalData->dmpriv;
153	struct tx_desc	*ptxdesc = (struct tx_desc *)pmem;
154	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
155	struct mlme_ext_info	*pmlmeinfo = &pmlmeext->mlmext_info;
156	int	bmcst = is_multicast_ether_addr(pattrib->ra);
157
158	if ((!bagg_pkt) && (urb_zero_packet_chk(padapter, sz) == 0)) {
159		ptxdesc = (struct tx_desc *)(pmem+PACKET_OFFSET_SZ);
160		pull = 1;
161		pxmitframe->pkt_offset--;
162	}
163
164	memset(ptxdesc, 0, sizeof(struct tx_desc));
165
166	if ((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) {
167		/* offset 4 */
168		ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id&0x1f);
169
170		qsel = (uint)(pattrib->qsel & 0x0000001f);
171		ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00);
172
173		ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid<<16) & 0x000f0000);
174
175		fill_txdesc_sectype(pattrib, ptxdesc);
176
177		if (pattrib->ampdu_en)
178			ptxdesc->txdw1 |= cpu_to_le32(BIT(5));/* AGG EN */
179		else
180			ptxdesc->txdw1 |= cpu_to_le32(BIT(6));/* AGG BK */
181
182		/* offset 8 */
183
184		/* offset 12 */
185		ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000);
186
187		/* offset 16 , offset 20 */
188		if (pattrib->qos_en)
189			ptxdesc->txdw4 |= cpu_to_le32(BIT(6));/* QoS */
190
191		if ((pattrib->ether_type != 0x888e) &&
192		    (pattrib->ether_type != 0x0806) &&
193		    (pattrib->dhcp_pkt != 1)) {
194			/* Non EAP & ARP & DHCP type data packet */
195
196			fill_txdesc_vcs(pattrib, &ptxdesc->txdw4);
197			fill_txdesc_phy(pattrib, &ptxdesc->txdw4);
198
199			ptxdesc->txdw4 |= cpu_to_le32(0x00000008);/* RTS Rate = 24M */
200			ptxdesc->txdw5 |= cpu_to_le32(0x0001ff00);/*  */
201
202			/* use REG_INIDATA_RATE_SEL value */
203			ptxdesc->txdw5 |= cpu_to_le32(pdmpriv->INIDATA_RATE[pattrib->mac_id]);
204		} else {
205			/*  EAP data packet and ARP packet. */
206			/*  Use the 1M data rate to send the EAP/ARP packet. */
207			/*  This will maybe make the handshake smooth. */
208
209			ptxdesc->txdw1 |= cpu_to_le32(BIT(6));/* AGG BK */
210
211			ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */
212
213			if (pmlmeinfo->preamble_mode == PREAMBLE_SHORT)
214				ptxdesc->txdw4 |= cpu_to_le32(BIT(24));/*  DATA_SHORT */
215
216			ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate23a(pmlmeext->tx_rate));
217		}
218	} else if ((pxmitframe->frame_tag&0x0f) == MGNT_FRAMETAG) {
219		/* offset 4 */
220		ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id&0x1f);
221
222		qsel = (uint)(pattrib->qsel&0x0000001f);
223		ptxdesc->txdw1 |= cpu_to_le32((qsel<<QSEL_SHT)&0x00001f00);
224
225		ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid<<16) & 0x000f0000);
226
227		/* offset 8 */
228		/* CCX-TXRPT ack for xmit mgmt frames. */
229		if (pxmitframe->ack_report)
230			ptxdesc->txdw2 |= cpu_to_le32(BIT(19));
231
232		/* offset 12 */
233		ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000);
234
235		/* offset 16 */
236		ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */
237
238		/* offset 20 */
239		ptxdesc->txdw5 |= cpu_to_le32(BIT(17));/* retry limit enable */
240		ptxdesc->txdw5 |= cpu_to_le32(0x00180000);/* retry limit = 6 */
241
242		ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate23a(pmlmeext->tx_rate));
243	} else if ((pxmitframe->frame_tag&0x0f) == TXAGG_FRAMETAG) {
244		DBG_8723A("pxmitframe->frame_tag == TXAGG_FRAMETAG\n");
245	} else {
246		DBG_8723A("pxmitframe->frame_tag = %d\n", pxmitframe->frame_tag);
247
248		/* offset 4 */
249		ptxdesc->txdw1 |= cpu_to_le32((4)&0x1f);/* CAM_ID(MAC_ID) */
250
251		ptxdesc->txdw1 |= cpu_to_le32((6<<16) & 0x000f0000);/* raid */
252
253		/* offset 8 */
254
255		/* offset 12 */
256		ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000);
257
258		/* offset 16 */
259		ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */
260
261		/* offset 20 */
262		ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate23a(pmlmeext->tx_rate));
263	}
264
265	/*  (1) The sequence number of each non-Qos frame / broadcast / multicast / */
266	/*  mgnt frame should be controled by Hw because Fw will also send null data */
267	/*  which we cannot control when Fw LPS enable. */
268	/*  --> default enable non-Qos data sequense number. 2010.06.23. by tynli. */
269	/*  (2) Enable HW SEQ control for beacon packet, because we use Hw beacon. */
270	/*  (3) Use HW Qos SEQ to control the seq num of Ext port non-Qos packets. */
271	if (!pattrib->qos_en) {
272		/*  Hw set sequence number */
273		ptxdesc->txdw4 |= cpu_to_le32(BIT(7));
274		/* set bit3 to 1. */
275		ptxdesc->txdw3 |= cpu_to_le32((8 << 28));
276	}
277
278	/* offset 0 */
279	ptxdesc->txdw0 |= cpu_to_le32(sz&0x0000ffff);
280	ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG);
281	ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<<OFFSET_SHT)&0x00ff0000);/* 32 bytes for TX Desc */
282
283	if (bmcst)
284		ptxdesc->txdw0 |= cpu_to_le32(BIT(24));
285
286	RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("offset0-txdesc = 0x%x\n", ptxdesc->txdw0));
287
288	/* offset 4 */
289	/*  pkt_offset, unit:8 bytes padding */
290	if (pxmitframe->pkt_offset > 0)
291		ptxdesc->txdw1 |= cpu_to_le32((pxmitframe->pkt_offset << 26) & 0x7c000000);
292
293	rtl8192cu_cal_txdesc_chksum(ptxdesc);
294	return pull;
295}
296
297static int rtw_dump_xframe(struct rtw_adapter *padapter,
298			   struct xmit_frame *pxmitframe)
299{
300	int ret = _SUCCESS;
301	int inner_ret = _SUCCESS;
302	int t, sz, w_sz, pull = 0;
303	u8 *mem_addr;
304	u32 ff_hwaddr;
305	struct xmit_buf *pxmitbuf = pxmitframe->pxmitbuf;
306	struct pkt_attrib *pattrib = &pxmitframe->attrib;
307	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
308
309	if ((pxmitframe->frame_tag == DATA_FRAMETAG) &&
310	    (pxmitframe->attrib.ether_type != 0x0806) &&
311	    (pxmitframe->attrib.ether_type != 0x888e) &&
312	    (pxmitframe->attrib.dhcp_pkt != 1))
313		rtw_issue_addbareq_cmd23a(padapter, pxmitframe);
314
315	mem_addr = pxmitframe->buf_addr;
316
317	RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_dump_xframe()\n"));
318
319	for (t = 0; t < pattrib->nr_frags; t++) {
320		if (inner_ret != _SUCCESS && ret == _SUCCESS)
321			ret = _FAIL;
322
323		if (t != (pattrib->nr_frags - 1)) {
324			RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
325				 ("pattrib->nr_frags =%d\n", pattrib->nr_frags));
326
327			sz = pxmitpriv->frag_len;
328			sz = sz - 4 - pattrib->icv_len;
329		} else {
330			/* no frag */
331			sz = pattrib->last_txcmdsz;
332		}
333
334		pull = update_txdesc(pxmitframe, mem_addr, sz, false);
335
336		if (pull) {
337			mem_addr += PACKET_OFFSET_SZ; /* pull txdesc head */
338
339			pxmitframe->buf_addr = mem_addr;
340
341			w_sz = sz + TXDESC_SIZE;
342		} else {
343			w_sz = sz + TXDESC_SIZE + PACKET_OFFSET_SZ;
344		}
345
346		ff_hwaddr = rtw_get_ff_hwaddr23a(pxmitframe);
347		inner_ret = rtl8723au_write_port(padapter, ff_hwaddr,
348						 w_sz, pxmitbuf);
349		rtw_count_tx_stats23a(padapter, pxmitframe, sz);
350
351		RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
352			 ("rtw_write_port, w_sz =%d\n", w_sz));
353
354		mem_addr += w_sz;
355
356		mem_addr = PTR_ALIGN(mem_addr, 4);
357	}
358
359	rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
360
361	if  (ret != _SUCCESS)
362		rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_UNKNOWN);
363
364	return ret;
365}
366
367bool rtl8723au_xmitframe_complete(struct rtw_adapter *padapter,
368				  struct xmit_priv *pxmitpriv,
369				  struct xmit_buf *pxmitbuf)
370{
371	struct hw_xmit *phwxmits;
372	struct xmit_frame *pxmitframe;
373	int hwentry;
374	int res = _SUCCESS, xcnt = 0;
375
376	phwxmits = pxmitpriv->hwxmits;
377	hwentry = pxmitpriv->hwxmit_entry;
378
379	RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("xmitframe_complete()\n"));
380
381	if (pxmitbuf == NULL) {
382		pxmitbuf = rtw_alloc_xmitbuf23a(pxmitpriv);
383		if (!pxmitbuf)
384			return false;
385	}
386	pxmitframe =  rtw_dequeue_xframe23a(pxmitpriv, phwxmits, hwentry);
387
388	if (pxmitframe) {
389		pxmitframe->pxmitbuf = pxmitbuf;
390
391		pxmitframe->buf_addr = pxmitbuf->pbuf;
392
393		pxmitbuf->priv_data = pxmitframe;
394
395		if ((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) {
396			if (pxmitframe->attrib.priority <= 15)/* TID0~15 */
397				res = rtw_xmitframe_coalesce23a(padapter, pxmitframe->pkt, pxmitframe);
398
399			rtw_os_xmit_complete23a(padapter, pxmitframe);/* always return ndis_packet after rtw_xmitframe_coalesce23a */
400		}
401
402		RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("xmitframe_complete(): rtw_dump_xframe\n"));
403
404		if (res == _SUCCESS) {
405			rtw_dump_xframe(padapter, pxmitframe);
406		} else {
407			rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf);
408			rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
409		}
410		xcnt++;
411	} else {
412		rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf);
413		return false;
414	}
415	return true;
416}
417
418static int xmitframe_direct(struct rtw_adapter *padapter,
419			    struct xmit_frame *pxmitframe)
420{
421	int res;
422
423	res = rtw_xmitframe_coalesce23a(padapter, pxmitframe->pkt, pxmitframe);
424	if (res == _SUCCESS)
425		rtw_dump_xframe(padapter, pxmitframe);
426	return res;
427}
428
429/*
430 * Return
431 *	true	dump packet directly
432 *	false	enqueue packet
433 */
434bool rtl8723au_hal_xmit(struct rtw_adapter *padapter,
435			struct xmit_frame *pxmitframe)
436{
437	int res;
438	struct xmit_buf *pxmitbuf = NULL;
439	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
440	struct pkt_attrib *pattrib = &pxmitframe->attrib;
441	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
442
443	do_queue_select(padapter, pattrib);
444	spin_lock_bh(&pxmitpriv->lock);
445
446#ifdef CONFIG_8723AU_AP_MODE
447	if (xmitframe_enqueue_for_sleeping_sta23a(padapter, pxmitframe)) {
448		struct sta_info *psta;
449		struct sta_priv *pstapriv = &padapter->stapriv;
450
451		spin_unlock_bh(&pxmitpriv->lock);
452
453		if (pattrib->psta)
454			psta = pattrib->psta;
455		else
456			psta = rtw_get_stainfo23a(pstapriv, pattrib->ra);
457
458		if (psta) {
459			if (psta->sleepq_len > (NR_XMITFRAME>>3))
460				wakeup_sta_to_xmit23a(padapter, psta);
461		}
462
463		return false;
464	}
465#endif
466
467	if (rtw_txframes_sta_ac_pending23a(padapter, pattrib) > 0)
468		goto enqueue;
469
470	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true)
471		goto enqueue;
472
473	pxmitbuf = rtw_alloc_xmitbuf23a(pxmitpriv);
474	if (pxmitbuf == NULL)
475		goto enqueue;
476
477	spin_unlock_bh(&pxmitpriv->lock);
478
479	pxmitframe->pxmitbuf = pxmitbuf;
480	pxmitframe->buf_addr = pxmitbuf->pbuf;
481	pxmitbuf->priv_data = pxmitframe;
482
483	if (xmitframe_direct(padapter, pxmitframe) != _SUCCESS) {
484		rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf);
485		rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
486	}
487	return true;
488
489enqueue:
490	res = rtw_xmitframe_enqueue23a(padapter, pxmitframe);
491	spin_unlock_bh(&pxmitpriv->lock);
492
493	if (res != _SUCCESS) {
494		RT_TRACE(_module_xmit_osdep_c_, _drv_err_,
495			 ("pre_xmitframe: enqueue xmitframe fail\n"));
496		rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
497
498		/*  Trick, make the statistics correct */
499		pxmitpriv->tx_pkts--;
500		pxmitpriv->tx_drop++;
501		return true;
502	}
503	return false;
504}
505
506int rtl8723au_mgnt_xmit(struct rtw_adapter *padapter,
507			struct xmit_frame *pmgntframe)
508{
509	return rtw_dump_xframe(padapter, pmgntframe);
510}
511
512int rtl8723au_hal_xmitframe_enqueue(struct rtw_adapter *padapter,
513				    struct xmit_frame *pxmitframe)
514{
515	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
516	int err;
517
518	err = rtw_xmitframe_enqueue23a(padapter, pxmitframe);
519	if (err != _SUCCESS) {
520		rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
521
522		/*  Trick, make the statistics correct */
523		pxmitpriv->tx_pkts--;
524		pxmitpriv->tx_drop++;
525	} else {
526		tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
527	}
528	return err;
529}
530