• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *  (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
4  *
5  *  Module:	r819xusb_cmdpkt.c
6  *		(RTL8190 TX/RX command packet handler Source C File)
7  *
8  *  Note:	The module is responsible for handling TX and RX command packet.
9  *		1. TX : Send set and query configuration command packet.
10  *		2. RX : Receive tx feedback, beacon state, query configuration
11  *			command packet.
12  *
13  *  Function:
14  *
15  *  Export:
16  *
17  *  Abbrev:
18  *
19  *  History:
20  *
21  *	Date		Who		Remark
22  *	05/06/2008	amy		Create initial version porting from
23  *					windows driver.
24  *
25  ******************************************************************************/
26 #include "r8192U.h"
27 #include "r819xU_cmdpkt.h"
28 
SendTxCommandPacket(struct net_device * dev,void * pData,u32 DataLen)29 rt_status SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen)
30 {
31 	struct r8192_priv   *priv = ieee80211_priv(dev);
32 	struct sk_buff	    *skb;
33 	cb_desc		    *tcb_desc;
34 	unsigned char	    *ptr_buf;
35 
36 	/* Get TCB and local buffer from common pool.
37 	   (It is shared by CmdQ, MgntQ, and USB coalesce DataQ) */
38 	skb  = dev_alloc_skb(USB_HWDESC_HEADER_LEN + DataLen + 4);
39 	if (!skb)
40 		return RT_STATUS_FAILURE;
41 	memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
42 	tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
43 	tcb_desc->queue_index = TXCMD_QUEUE;
44 	tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL;
45 	tcb_desc->bLastIniPkt = 0;
46 	skb_reserve(skb, USB_HWDESC_HEADER_LEN);
47 	ptr_buf = skb_put(skb, DataLen);
48 	memcpy(ptr_buf, pData, DataLen);
49 	tcb_desc->txbuf_size = (u16)DataLen;
50 
51 	if (!priv->ieee80211->check_nic_enough_desc(dev, tcb_desc->queue_index) ||
52 	    (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index])) ||
53 	    (priv->ieee80211->queue_stop)) {
54 		RT_TRACE(COMP_FIRMWARE, "=== NULL packet ======> tx full!\n");
55 		skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
56 	} else {
57 		priv->ieee80211->softmac_hard_start_xmit(skb, dev);
58 	}
59 
60 	return RT_STATUS_SUCCESS;
61 }
62 
63 /*-----------------------------------------------------------------------------
64  * Function:    cmpk_counttxstatistic()
65  *
66  * Overview:
67  *
68  * Input:       PADAPTER	pAdapter
69  *              CMPK_TXFB_T	*psTx_FB
70  *
71  * Output:      NONE
72  *
73  * Return:      NONE
74  *
75  * Revised History:
76  *  When		Who	Remark
77  *  05/12/2008		amy	Create Version 0 porting from windows code.
78  *
79  *---------------------------------------------------------------------------*/
cmpk_count_txstatistic(struct net_device * dev,cmpk_txfb_t * pstx_fb)80 static void cmpk_count_txstatistic(struct net_device *dev, cmpk_txfb_t *pstx_fb)
81 {
82 	struct r8192_priv *priv = ieee80211_priv(dev);
83 #ifdef ENABLE_PS
84 	RT_RF_POWER_STATE	rtState;
85 
86 	pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
87 					  (pu1Byte)(&rtState));
88 
89 	/* When RF is off, we should not count the packet for hw/sw synchronize
90 	   reason, ie. there may be a duration while sw switch is changed and
91 	   hw switch is being changed. */
92 	if (rtState == eRfOff)
93 		return;
94 #endif
95 
96 #ifdef TODO
97 	if (pAdapter->bInHctTest)
98 		return;
99 #endif
100 	/* We can not know the packet length and transmit type:
101 	   broadcast or uni or multicast. So the relative statistics
102 	   must be collected in tx feedback info. */
103 	if (pstx_fb->tok) {
104 		priv->stats.txfeedbackok++;
105 		priv->stats.txoktotal++;
106 		priv->stats.txokbytestotal += pstx_fb->pkt_length;
107 		priv->stats.txokinperiod++;
108 
109 		/* We can not make sure broadcast/multicast or unicast mode. */
110 		if (pstx_fb->pkt_type == PACKET_MULTICAST) {
111 			priv->stats.txmulticast++;
112 			priv->stats.txbytesmulticast += pstx_fb->pkt_length;
113 		} else if (pstx_fb->pkt_type == PACKET_BROADCAST) {
114 			priv->stats.txbroadcast++;
115 			priv->stats.txbytesbroadcast += pstx_fb->pkt_length;
116 		} else {
117 			priv->stats.txunicast++;
118 			priv->stats.txbytesunicast += pstx_fb->pkt_length;
119 		}
120 	} else {
121 		priv->stats.txfeedbackfail++;
122 		priv->stats.txerrtotal++;
123 		priv->stats.txerrbytestotal += pstx_fb->pkt_length;
124 
125 		/* We can not make sure broadcast/multicast or unicast mode. */
126 		if (pstx_fb->pkt_type == PACKET_MULTICAST)
127 			priv->stats.txerrmulticast++;
128 		else if (pstx_fb->pkt_type == PACKET_BROADCAST)
129 			priv->stats.txerrbroadcast++;
130 		else
131 			priv->stats.txerrunicast++;
132 	}
133 
134 	priv->stats.txretrycount += pstx_fb->retry_cnt;
135 	priv->stats.txfeedbackretry += pstx_fb->retry_cnt;
136 
137 }
138 
139 
140 
141 /*-----------------------------------------------------------------------------
142  * Function:    cmpk_handle_tx_feedback()
143  *
144  * Overview:	The function is responsible for extract the message inside TX
145  *		feedbck message from firmware. It will contain dedicated info in
146  *		ws-06-0063-rtl8190-command-packet-specification.
147  *		Please refer to chapter "TX Feedback Element".
148  *              We have to read 20 bytes in the command packet.
149  *
150  * Input:       struct net_device	*dev
151  *              u8			*pmsg	- Msg Ptr of the command packet.
152  *
153  * Output:      NONE
154  *
155  * Return:      NONE
156  *
157  * Revised History:
158  *  When		Who	Remark
159  *  05/08/2008		amy	Create Version 0 porting from windows code.
160  *
161  *---------------------------------------------------------------------------*/
cmpk_handle_tx_feedback(struct net_device * dev,u8 * pmsg)162 static void cmpk_handle_tx_feedback(struct net_device *dev, u8 *pmsg)
163 {
164 	struct r8192_priv *priv = ieee80211_priv(dev);
165 	cmpk_txfb_t		rx_tx_fb;
166 
167 	priv->stats.txfeedback++;
168 
169 	/* 1. Extract TX feedback info from RFD to temp structure buffer. */
170 	/* It seems that FW use big endian(MIPS) and DRV use little endian in
171 	   windows OS. So we have to read the content byte by byte or transfer
172 	   endian type before copy the message copy. */
173 	/* Use pointer to transfer structure memory. */
174 	memcpy((u8 *)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
175 	/* 2. Use tx feedback info to count TX statistics. */
176 	cmpk_count_txstatistic(dev, &rx_tx_fb);
177 	/* Comment previous method for TX statistic function. */
178 	/* Collect info TX feedback packet to fill TCB. */
179 	/* We can not know the packet length and transmit type: broadcast or uni
180 	   or multicast. */
181 
182 }
183 
cmdpkt_beacontimerinterrupt_819xusb(struct net_device * dev)184 static void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev)
185 {
186 	struct r8192_priv *priv = ieee80211_priv(dev);
187 	u16 tx_rate;
188 		/* 87B have to S/W beacon for DTM encryption_cmn. */
189 		if (priv->ieee80211->current_network.mode == IEEE_A ||
190 			priv->ieee80211->current_network.mode == IEEE_N_5G ||
191 			(priv->ieee80211->current_network.mode == IEEE_N_24G &&
192 			 (!priv->ieee80211->pHTInfo->bCurSuppCCK))) {
193 			tx_rate = 60;
194 			DMESG("send beacon frame  tx rate is 6Mbpm\n");
195 		} else {
196 			tx_rate = 10;
197 			DMESG("send beacon frame  tx rate is 1Mbpm\n");
198 		}
199 
200 		rtl819xusb_beacon_tx(dev, tx_rate); /* HW Beacon */
201 
202 
203 }
204 
205 
206 
207 
208 /*-----------------------------------------------------------------------------
209  * Function:    cmpk_handle_interrupt_status()
210  *
211  * Overview:    The function is responsible for extract the message from
212  *		firmware. It will contain dedicated info in
213  *		ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
214  *		Please refer to chapter "Interrupt Status Element".
215  *
216  * Input:       struct net_device *dev
217  *              u8 *pmsg		- Message Pointer of the command packet.
218  *
219  * Output:      NONE
220  *
221  * Return:      NONE
222  *
223  * Revised History:
224  *  When		Who	Remark
225  *  05/12/2008		amy	Add this for rtl8192 porting from windows code.
226  *
227  *---------------------------------------------------------------------------*/
cmpk_handle_interrupt_status(struct net_device * dev,u8 * pmsg)228 static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg)
229 {
230 	cmpk_intr_sta_t		rx_intr_status;	/* */
231 	struct r8192_priv *priv = ieee80211_priv(dev);
232 
233 	DMESG("---> cmpk_Handle_Interrupt_Status()\n");
234 
235 	/* 1. Extract TX feedback info from RFD to temp structure buffer. */
236 	/* It seems that FW use big endian(MIPS) and DRV use little endian in
237 	   windows OS. So we have to read the content byte by byte or transfer
238 	   endian type before copy the message copy. */
239 	rx_intr_status.length = pmsg[1];
240 	if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2)) {
241 		DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
242 		return;
243 	}
244 
245 
246 	/* Statistics of beacon for ad-hoc mode. */
247 	if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) {
248 		/* 2 maybe need endian transform? */
249 		rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
250 
251 		DMESG("interrupt status = 0x%x\n",
252 		      rx_intr_status.interrupt_status);
253 
254 		if (rx_intr_status.interrupt_status & ISR_TxBcnOk) {
255 			priv->ieee80211->bibsscoordinator = true;
256 			priv->stats.txbeaconokint++;
257 		} else if (rx_intr_status.interrupt_status & ISR_TxBcnErr) {
258 			priv->ieee80211->bibsscoordinator = false;
259 			priv->stats.txbeaconerr++;
260 		}
261 
262 		if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr)
263 			cmdpkt_beacontimerinterrupt_819xusb(dev);
264 
265 	}
266 
267 	/* Other informations in interrupt status we need? */
268 
269 
270 	DMESG("<---- cmpk_handle_interrupt_status()\n");
271 
272 }
273 
274 
275 /*-----------------------------------------------------------------------------
276  * Function:    cmpk_handle_query_config_rx()
277  *
278  * Overview:    The function is responsible for extract the message from
279  *		firmware. It will contain dedicated info in
280  *		ws-06-0063-rtl8190-command-packet-specification. Please
281  *		refer to chapter "Beacon State Element".
282  *
283  * Input:       u8    *pmsg	-	Message Pointer of the command packet.
284  *
285  * Output:      NONE
286  *
287  * Return:      NONE
288  *
289  * Revised History:
290  *  When		Who	Remark
291  *  05/12/2008		amy	Create Version 0 porting from windows code.
292  *
293  *---------------------------------------------------------------------------*/
cmpk_handle_query_config_rx(struct net_device * dev,u8 * pmsg)294 static void cmpk_handle_query_config_rx(struct net_device *dev, u8 *pmsg)
295 {
296 	cmpk_query_cfg_t	rx_query_cfg;
297 
298 
299 	/* 1. Extract TX feedback info from RFD to temp structure buffer. */
300 	/* It seems that FW use big endian(MIPS) and DRV use little endian in
301 	   windows OS. So we have to read the content byte by byte or transfer
302 	   endian type before copy the message copy. */
303 	rx_query_cfg.cfg_action		= (pmsg[4] & 0x80000000) >> 31;
304 	rx_query_cfg.cfg_type		= (pmsg[4] & 0x60) >> 5;
305 	rx_query_cfg.cfg_size		= (pmsg[4] & 0x18) >> 3;
306 	rx_query_cfg.cfg_page		= (pmsg[6] & 0x0F) >> 0;
307 	rx_query_cfg.cfg_offset		= pmsg[7];
308 	rx_query_cfg.value		= (pmsg[8]  << 24) | (pmsg[9]  << 16) |
309 					  (pmsg[10] <<  8) | (pmsg[11] <<  0);
310 	rx_query_cfg.mask		= (pmsg[12] << 24) | (pmsg[13] << 16) |
311 					  (pmsg[14] <<  8) | (pmsg[15] <<  0);
312 
313 }
314 
315 
316 /*-----------------------------------------------------------------------------
317  * Function:	cmpk_count_tx_status()
318  *
319  * Overview:	Count aggregated tx status from firmwar of one type rx command
320  *		packet element id = RX_TX_STATUS.
321  *
322  * Input:	NONE
323  *
324  * Output:	NONE
325  *
326  * Return:	NONE
327  *
328  * Revised History:
329  *	When		Who	Remark
330  *	05/12/2008	amy	Create Version 0 porting from windows code.
331  *
332  *---------------------------------------------------------------------------*/
cmpk_count_tx_status(struct net_device * dev,cmpk_tx_status_t * pstx_status)333 static void cmpk_count_tx_status(struct net_device *dev,
334 				 cmpk_tx_status_t *pstx_status)
335 {
336 	struct r8192_priv *priv = ieee80211_priv(dev);
337 
338 #ifdef ENABLE_PS
339 
340 	RT_RF_POWER_STATE	rtstate;
341 
342 	pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
343 					  (pu1Byte)(&rtState));
344 
345 	/* When RF is off, we should not count the packet for hw/sw synchronize
346 	   reason, ie. there may be a duration while sw switch is changed and
347 	   hw switch is being changed. */
348 	if (rtState == eRfOff)
349 		return;
350 #endif
351 
352 	priv->stats.txfeedbackok	+= pstx_status->txok;
353 	priv->stats.txoktotal		+= pstx_status->txok;
354 
355 	priv->stats.txfeedbackfail	+= pstx_status->txfail;
356 	priv->stats.txerrtotal		+= pstx_status->txfail;
357 
358 	priv->stats.txretrycount	+= pstx_status->txretry;
359 	priv->stats.txfeedbackretry	+= pstx_status->txretry;
360 
361 
362 	priv->stats.txmulticast		+= pstx_status->txmcok;
363 	priv->stats.txbroadcast		+= pstx_status->txbcok;
364 	priv->stats.txunicast		+= pstx_status->txucok;
365 
366 	priv->stats.txerrmulticast	+= pstx_status->txmcfail;
367 	priv->stats.txerrbroadcast	+= pstx_status->txbcfail;
368 	priv->stats.txerrunicast	+= pstx_status->txucfail;
369 
370 	priv->stats.txbytesmulticast	+= pstx_status->txmclength;
371 	priv->stats.txbytesbroadcast	+= pstx_status->txbclength;
372 	priv->stats.txbytesunicast	+= pstx_status->txuclength;
373 
374 	priv->stats.last_packet_rate	= pstx_status->rate;
375 }
376 
377 
378 
379 /*-----------------------------------------------------------------------------
380  * Function:	cmpk_handle_tx_status()
381  *
382  * Overview:	Firmware add a new tx feedback status to reduce rx command
383  *		packet buffer operation load.
384  *
385  * Input:		NONE
386  *
387  * Output:		NONE
388  *
389  * Return:		NONE
390  *
391  * Revised History:
392  *	When		Who	Remark
393  *	05/12/2008	amy	Create Version 0 porting from windows code.
394  *
395  *---------------------------------------------------------------------------*/
cmpk_handle_tx_status(struct net_device * dev,u8 * pmsg)396 static void cmpk_handle_tx_status(struct net_device *dev, u8 *pmsg)
397 {
398 	cmpk_tx_status_t	rx_tx_sts;
399 
400 	memcpy((void *)&rx_tx_sts, (void *)pmsg, sizeof(cmpk_tx_status_t));
401 	/* 2. Use tx feedback info to count TX statistics. */
402 	cmpk_count_tx_status(dev, &rx_tx_sts);
403 
404 }
405 
406 
407 /*-----------------------------------------------------------------------------
408  * Function:	cmpk_handle_tx_rate_history()
409  *
410  * Overview:	Firmware add a new tx rate history
411  *
412  * Input:		NONE
413  *
414  * Output:		NONE
415  *
416  * Return:		NONE
417  *
418  * Revised History:
419  *	When		Who	Remark
420  *	05/12/2008	amy	Create Version 0 porting from windows code.
421  *
422  *---------------------------------------------------------------------------*/
cmpk_handle_tx_rate_history(struct net_device * dev,u8 * pmsg)423 static void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg)
424 {
425 	cmpk_tx_rahis_t	*ptxrate;
426 	u8		i, j;
427 	u16		length = sizeof(cmpk_tx_rahis_t);
428 	u32		*ptemp;
429 	struct r8192_priv *priv = ieee80211_priv(dev);
430 
431 
432 #ifdef ENABLE_PS
433 	pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
434 					  (pu1Byte)(&rtState));
435 
436 	/* When RF is off, we should not count the packet for hw/sw synchronize
437 	   reason, ie. there may be a duration while sw switch is changed and
438 	   hw switch is being changed. */
439 	if (rtState == eRfOff)
440 		return;
441 #endif
442 
443 	ptemp = (u32 *)pmsg;
444 
445 	/* Do endian transfer to word alignment(16 bits) for windows system.
446 	   You must do different endian transfer for linux and MAC OS */
447 	for (i = 0; i < (length/4); i++) {
448 		u16	 temp1, temp2;
449 
450 		temp1 = ptemp[i] & 0x0000FFFF;
451 		temp2 = ptemp[i] >> 16;
452 		ptemp[i] = (temp1 << 16) | temp2;
453 	}
454 
455 	ptxrate = (cmpk_tx_rahis_t *)pmsg;
456 
457 	if (ptxrate == NULL)
458 		return;
459 
460 	for (i = 0; i < 16; i++) {
461 		/* Collect CCK rate packet num */
462 		if (i < 4)
463 			priv->stats.txrate.cck[i] += ptxrate->cck[i];
464 
465 		/* Collect OFDM rate packet num */
466 		if (i < 8)
467 			priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i];
468 
469 		for (j = 0; j < 4; j++)
470 			priv->stats.txrate.ht_mcs[j][i] += ptxrate->ht_mcs[j][i];
471 	}
472 
473 }
474 
475 
476 /*-----------------------------------------------------------------------------
477  * Function:    cmpk_message_handle_rx()
478  *
479  * Overview:    In the function, we will capture different RX command packet
480  *		info. Every RX command packet element has different message
481  *		length and meaning in content. We only support three type of RX
482  *		command packet now. Please refer to document
483  *		ws-06-0063-rtl8190-command-packet-specification.
484  *
485  * Input:       NONE
486  *
487  * Output:      NONE
488  *
489  * Return:      NONE
490  *
491  * Revised History:
492  *  When		Who	Remark
493  *  05/06/2008		amy	Create Version 0 porting from windows code.
494  *
495  *---------------------------------------------------------------------------*/
cmpk_message_handle_rx(struct net_device * dev,struct ieee80211_rx_stats * pstats)496 u32 cmpk_message_handle_rx(struct net_device *dev,
497 			   struct ieee80211_rx_stats *pstats)
498 {
499 	int			total_length;
500 	u8			cmd_length, exe_cnt = 0;
501 	u8			element_id;
502 	u8			*pcmd_buff;
503 
504 	/* 0. Check inpt arguments. If is is a command queue message or
505 	   pointer is null. */
506 	if (pstats == NULL)
507 		return 0;	/* This is not a command packet. */
508 
509 	/* 1. Read received command packet message length from RFD. */
510 	total_length = pstats->Length;
511 
512 	/* 2. Read virtual address from RFD. */
513 	pcmd_buff = pstats->virtual_address;
514 
515 	/* 3. Read command packet element id and length. */
516 	element_id = pcmd_buff[0];
517 
518 	/* 4. Check every received command packet content according to different
519 	      element type. Because FW may aggregate RX command packet to
520 	      minimize transmit time between DRV and FW.*/
521 	/* Add a counter to prevent the lock in the loop from being held too
522 	   long */
523 	while (total_length > 0 && exe_cnt++ < 100) {
524 		/* We support aggregation of different cmd in the same packet */
525 		element_id = pcmd_buff[0];
526 
527 		switch (element_id) {
528 		case RX_TX_FEEDBACK:
529 			cmpk_handle_tx_feedback(dev, pcmd_buff);
530 			cmd_length = CMPK_RX_TX_FB_SIZE;
531 			break;
532 
533 		case RX_INTERRUPT_STATUS:
534 			cmpk_handle_interrupt_status(dev, pcmd_buff);
535 			cmd_length = sizeof(cmpk_intr_sta_t);
536 			break;
537 
538 		case BOTH_QUERY_CONFIG:
539 			cmpk_handle_query_config_rx(dev, pcmd_buff);
540 			cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
541 			break;
542 
543 		case RX_TX_STATUS:
544 			cmpk_handle_tx_status(dev, pcmd_buff);
545 			cmd_length = CMPK_RX_TX_STS_SIZE;
546 			break;
547 
548 		case RX_TX_PER_PKT_FEEDBACK:
549 			/* You must at lease add a switch case element here,
550 			   Otherwise, we will jump to default case. */
551 			cmd_length = CMPK_RX_TX_FB_SIZE;
552 			break;
553 
554 		case RX_TX_RATE_HISTORY:
555 			cmpk_handle_tx_rate_history(dev, pcmd_buff);
556 			cmd_length = CMPK_TX_RAHIS_SIZE;
557 			break;
558 
559 		default:
560 
561 			RT_TRACE(COMP_ERR, "---->%s():unknown CMD Element\n",
562 				 __func__);
563 			return 1;	/* This is a command packet. */
564 		}
565 
566 		total_length -= cmd_length;
567 		pcmd_buff    += cmd_length;
568 	}
569 	return	1;	/* This is a command packet. */
570 
571 }
572