1 /******************************************************************************
3 (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
5 Module: r819xusb_cmdpkt.c (RTL8190 TX/RX command packet handler Source C File)
7 Note: The module is responsible for handling TX and RX command packet.
8 1. TX : Send set and query configuration command packet.
9 2. RX : Receive tx feedback, beacon state, query configuration
21 05/06/2008 amy Create initial version porting from windows driver.
23 ******************************************************************************/
25 #include "r819xU_cmdpkt.h"
26 /*---------------------------Define Local Constant---------------------------*/
28 #define CMPK_DEBOUNCE_CNT 1
29 /* 2007/10/24 MH Add for printing a range of data. */
30 #define CMPK_PRINT(Address)\
35 memcpy(temp, Address, 40);\
36 for (i = 0; i <40; i+=4)\
37 printk("\r\n %08x", temp[i]);\
39 /*---------------------------Define functions---------------------------------*/
43 struct net_device *dev,
48 rt_status rtStatus = RT_STATUS_SUCCESS;
49 struct r8192_priv *priv = ieee80211_priv(dev);
52 unsigned char *ptr_buf;
54 //Get TCB and local buffer from common pool. (It is shared by CmdQ, MgntQ, and USB coalesce DataQ)
55 skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + DataLen + 4);
56 memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
57 tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
58 tcb_desc->queue_index = TXCMD_QUEUE;
59 tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL;
60 tcb_desc->bLastIniPkt = 0;
61 skb_reserve(skb, USB_HWDESC_HEADER_LEN);
62 ptr_buf = skb_put(skb, DataLen);
63 memcpy(ptr_buf,pData,DataLen);
64 tcb_desc->txbuf_size= (u16)DataLen;
66 if (!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)||
67 (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\
68 (priv->ieee80211->queue_stop) ) {
69 RT_TRACE(COMP_FIRMWARE,"===================NULL packet==================================> tx full!\n");
70 skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
72 priv->ieee80211->softmac_hard_start_xmit(skb,dev);
78 /*-----------------------------------------------------------------------------
79 * Function: cmpk_message_handle_tx()
81 * Overview: Driver internal module can call the API to send message to
82 * firmware side. For example, you can send a debug command packet.
83 * Or you can send a request for FW to modify RLX4181 LBUS HW bank.
84 * Otherwise, you can change MAC/PHT/RF register by firmware at
85 * run time. We do not support message more than one segment now.
95 * 05/06/2008 amy porting from windows code.
97 *---------------------------------------------------------------------------*/
98 extern rt_status cmpk_message_handle_tx(
99 struct net_device *dev,
100 u8 *codevirtualaddress,
105 bool rt_status = true;
109 struct r8192_priv *priv = ieee80211_priv(dev);
111 u16 frag_length, frag_offset = 0;
113 rt_firmware *pfirmware = priv->pFirmware;
115 unsigned char *seg_ptr;
119 firmware_init_param(dev);
120 //Fragmentation might be required
121 frag_threshold = pfirmware->cmdpacket_frag_thresold;
123 if ((buffer_len - frag_offset) > frag_threshold) {
124 frag_length = frag_threshold ;
128 frag_length = buffer_len - frag_offset;
133 /* Allocate skb buffer to contain firmware info and tx descriptor info
134 * add 4 to avoid packet appending overflow.
137 skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4);
139 skb = dev_alloc_skb(frag_length + 4);
141 memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
142 tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
143 tcb_desc->queue_index = TXCMD_QUEUE;
144 tcb_desc->bCmdOrInit = packettype;
145 tcb_desc->bLastIniPkt = bLastIniPkt;
148 skb_reserve(skb, USB_HWDESC_HEADER_LEN);
151 seg_ptr = skb_put(skb, buffer_len);
153 * Transform from little endian to big endian
156 memcpy(seg_ptr,codevirtualaddress,buffer_len);
157 tcb_desc->txbuf_size= (u16)buffer_len;
160 if (!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)||
161 (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\
162 (priv->ieee80211->queue_stop) ) {
163 RT_TRACE(COMP_FIRMWARE,"=====================================================> tx full!\n");
164 skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
166 priv->ieee80211->softmac_hard_start_xmit(skb,dev);
169 codevirtualaddress += frag_length;
170 frag_offset += frag_length;
172 }while(frag_offset < buffer_len);
178 } /* CMPK_Message_Handle_Tx */
180 /*-----------------------------------------------------------------------------
181 * Function: cmpk_counttxstatistic()
185 * Input: PADAPTER pAdapter - .
186 * CMPK_TXFB_T *psTx_FB - .
194 * 05/12/2008 amy Create Version 0 porting from windows code.
196 *---------------------------------------------------------------------------*/
198 cmpk_count_txstatistic(
199 struct net_device *dev,
200 cmpk_txfb_t *pstx_fb)
202 struct r8192_priv *priv = ieee80211_priv(dev);
204 RT_RF_POWER_STATE rtState;
206 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
208 // When RF is off, we should not count the packet for hw/sw synchronize
209 // reason, ie. there may be a duration while sw switch is changed and hw
210 // switch is being changed. 2006.12.04, by shien chang.
211 if (rtState == eRfOff)
218 if (pAdapter->bInHctTest)
221 /* We can not know the packet length and transmit type: broadcast or uni
222 or multicast. So the relative statistics must be collected in tx
226 priv->stats.txfeedbackok++;
227 priv->stats.txoktotal++;
228 priv->stats.txokbytestotal += pstx_fb->pkt_length;
229 priv->stats.txokinperiod++;
231 /* We can not make sure broadcast/multicast or unicast mode. */
232 if (pstx_fb->pkt_type == PACKET_MULTICAST)
234 priv->stats.txmulticast++;
235 priv->stats.txbytesmulticast += pstx_fb->pkt_length;
237 else if (pstx_fb->pkt_type == PACKET_BROADCAST)
239 priv->stats.txbroadcast++;
240 priv->stats.txbytesbroadcast += pstx_fb->pkt_length;
244 priv->stats.txunicast++;
245 priv->stats.txbytesunicast += pstx_fb->pkt_length;
250 priv->stats.txfeedbackfail++;
251 priv->stats.txerrtotal++;
252 priv->stats.txerrbytestotal += pstx_fb->pkt_length;
254 /* We can not make sure broadcast/multicast or unicast mode. */
255 if (pstx_fb->pkt_type == PACKET_MULTICAST)
257 priv->stats.txerrmulticast++;
259 else if (pstx_fb->pkt_type == PACKET_BROADCAST)
261 priv->stats.txerrbroadcast++;
265 priv->stats.txerrunicast++;
269 priv->stats.txretrycount += pstx_fb->retry_cnt;
270 priv->stats.txfeedbackretry += pstx_fb->retry_cnt;
272 } /* cmpk_CountTxStatistic */
276 /*-----------------------------------------------------------------------------
277 * Function: cmpk_handle_tx_feedback()
279 * Overview: The function is responsible for extract the message inside TX
280 * feedbck message from firmware. It will contain dedicated info in
281 * ws-06-0063-rtl8190-command-packet-specification. Please
282 * refer to chapter "TX Feedback Element". We have to read 20 bytes
283 * in the command packet.
285 * Input: struct net_device * dev
286 * u8 * pmsg - Msg Ptr of the command packet.
294 * 05/08/2008 amy Create Version 0 porting from windows code.
296 *---------------------------------------------------------------------------*/
298 cmpk_handle_tx_feedback(
299 struct net_device *dev,
302 struct r8192_priv *priv = ieee80211_priv(dev);
303 cmpk_txfb_t rx_tx_fb; /* */
305 priv->stats.txfeedback++;
307 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
308 /* It seems that FW use big endian(MIPS) and DRV use little endian in
309 windows OS. So we have to read the content byte by byte or transfer
310 endian type before copy the message copy. */
311 /* 2007/07/05 MH Use pointer to transfer structure memory. */
312 memcpy((u8 *)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
313 /* 2. Use tx feedback info to count TX statistics. */
314 cmpk_count_txstatistic(dev, &rx_tx_fb);
315 /* 2007/01/17 MH Comment previous method for TX statistic function. */
316 /* Collect info TX feedback packet to fill TCB. */
317 /* We can not know the packet length and transmit type: broadcast or uni
320 } /* cmpk_Handle_Tx_Feedback */
323 cmdpkt_beacontimerinterrupt_819xusb(
324 struct net_device *dev
327 struct r8192_priv *priv = ieee80211_priv(dev);
331 // 070117, rcnjko: 87B have to S/W beacon for DTM encryption_cmn.
333 if (priv->ieee80211->current_network.mode == IEEE_A ||
334 priv->ieee80211->current_network.mode == IEEE_N_5G ||
335 (priv->ieee80211->current_network.mode == IEEE_N_24G && (!priv->ieee80211->pHTInfo->bCurSuppCCK)))
338 DMESG("send beacon frame tx rate is 6Mbpm\n");
343 DMESG("send beacon frame tx rate is 1Mbpm\n");
346 rtl819xusb_beacon_tx(dev,tx_rate); // HW Beacon
355 /*-----------------------------------------------------------------------------
356 * Function: cmpk_handle_interrupt_status()
358 * Overview: The function is responsible for extract the message from
359 * firmware. It will contain dedicated info in
360 * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
361 * Please refer to chapter "Interrupt Status Element".
363 * Input: struct net_device *dev,
364 * u8* pmsg - Message Pointer of the command packet.
372 * 05/12/2008 amy Add this for rtl8192 porting from windows code.
374 *---------------------------------------------------------------------------*/
376 cmpk_handle_interrupt_status(
377 struct net_device *dev,
380 cmpk_intr_sta_t rx_intr_status; /* */
381 struct r8192_priv *priv = ieee80211_priv(dev);
383 DMESG("---> cmpk_Handle_Interrupt_Status()\n");
385 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
386 /* It seems that FW use big endian(MIPS) and DRV use little endian in
387 windows OS. So we have to read the content byte by byte or transfer
388 endian type before copy the message copy. */
389 rx_intr_status.length = pmsg[1];
390 if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2))
392 DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
397 // Statistics of beacon for ad-hoc mode.
398 if ( priv->ieee80211->iw_mode == IW_MODE_ADHOC)
400 //2 maybe need endian transform?
401 rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
403 DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status);
405 if (rx_intr_status.interrupt_status & ISR_TxBcnOk)
407 priv->ieee80211->bibsscoordinator = true;
408 priv->stats.txbeaconokint++;
410 else if (rx_intr_status.interrupt_status & ISR_TxBcnErr)
412 priv->ieee80211->bibsscoordinator = false;
413 priv->stats.txbeaconerr++;
416 if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr)
418 cmdpkt_beacontimerinterrupt_819xusb(dev);
423 // Other informations in interrupt status we need?
426 DMESG("<---- cmpk_handle_interrupt_status()\n");
428 } /* cmpk_handle_interrupt_status */
431 /*-----------------------------------------------------------------------------
432 * Function: cmpk_handle_query_config_rx()
434 * Overview: The function is responsible for extract the message from
435 * firmware. It will contain dedicated info in
436 * ws-06-0063-rtl8190-command-packet-specification. Please
437 * refer to chapter "Beacon State Element".
439 * Input: u8 * pmsg - Message Pointer of the command packet.
447 * 05/12/2008 amy Create Version 0 porting from windows code.
449 *---------------------------------------------------------------------------*/
451 cmpk_handle_query_config_rx(
452 struct net_device *dev,
455 cmpk_query_cfg_t rx_query_cfg; /* */
458 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
459 /* It seems that FW use big endian(MIPS) and DRV use little endian in
460 windows OS. So we have to read the content byte by byte or transfer
461 endian type before copy the message copy. */
462 rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000)>>31;
463 rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5;
464 rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3;
465 rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0;
466 rx_query_cfg.cfg_offset = pmsg[7];
467 rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) |
468 (pmsg[10] << 8) | (pmsg[11] << 0);
469 rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) |
470 (pmsg[14] << 8) | (pmsg[15] << 0);
472 } /* cmpk_Handle_Query_Config_Rx */
475 /*-----------------------------------------------------------------------------
476 * Function: cmpk_count_tx_status()
478 * Overview: Count aggregated tx status from firmwar of one type rx command
479 * packet element id = RX_TX_STATUS.
489 * 05/12/2008 amy Create Version 0 porting from windows code.
491 *---------------------------------------------------------------------------*/
492 static void cmpk_count_tx_status( struct net_device *dev,
493 cmpk_tx_status_t *pstx_status)
495 struct r8192_priv *priv = ieee80211_priv(dev);
499 RT_RF_POWER_STATE rtstate;
501 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
503 // When RF is off, we should not count the packet for hw/sw synchronize
504 // reason, ie. there may be a duration while sw switch is changed and hw
505 // switch is being changed. 2006.12.04, by shien chang.
506 if (rtState == eRfOff)
512 priv->stats.txfeedbackok += pstx_status->txok;
513 priv->stats.txoktotal += pstx_status->txok;
515 priv->stats.txfeedbackfail += pstx_status->txfail;
516 priv->stats.txerrtotal += pstx_status->txfail;
518 priv->stats.txretrycount += pstx_status->txretry;
519 priv->stats.txfeedbackretry += pstx_status->txretry;
522 priv->stats.txmulticast += pstx_status->txmcok;
523 priv->stats.txbroadcast += pstx_status->txbcok;
524 priv->stats.txunicast += pstx_status->txucok;
526 priv->stats.txerrmulticast += pstx_status->txmcfail;
527 priv->stats.txerrbroadcast += pstx_status->txbcfail;
528 priv->stats.txerrunicast += pstx_status->txucfail;
530 priv->stats.txbytesmulticast += pstx_status->txmclength;
531 priv->stats.txbytesbroadcast += pstx_status->txbclength;
532 priv->stats.txbytesunicast += pstx_status->txuclength;
534 priv->stats.last_packet_rate = pstx_status->rate;
535 } /* cmpk_CountTxStatus */
539 /*-----------------------------------------------------------------------------
540 * Function: cmpk_handle_tx_status()
542 * Overview: Firmware add a new tx feedback status to reduce rx command
543 * packet buffer operation load.
553 * 05/12/2008 amy Create Version 0 porting from windows code.
555 *---------------------------------------------------------------------------*/
557 cmpk_handle_tx_status(
558 struct net_device *dev,
561 cmpk_tx_status_t rx_tx_sts; /* */
563 memcpy((void *)&rx_tx_sts, (void *)pmsg, sizeof(cmpk_tx_status_t));
564 /* 2. Use tx feedback info to count TX statistics. */
565 cmpk_count_tx_status(dev, &rx_tx_sts);
567 } /* cmpk_Handle_Tx_Status */
570 /*-----------------------------------------------------------------------------
571 * Function: cmpk_handle_tx_rate_history()
573 * Overview: Firmware add a new tx rate history
583 * 05/12/2008 amy Create Version 0 porting from windows code.
585 *---------------------------------------------------------------------------*/
587 cmpk_handle_tx_rate_history(
588 struct net_device *dev,
591 cmpk_tx_rahis_t *ptxrate;
593 u16 length = sizeof(cmpk_tx_rahis_t);
595 struct r8192_priv *priv = ieee80211_priv(dev);
599 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
601 // When RF is off, we should not count the packet for hw/sw synchronize
602 // reason, ie. there may be a duration while sw switch is changed and hw
603 // switch is being changed. 2006.12.04, by shien chang.
604 if (rtState == eRfOff)
613 // Do endian transfer to word alignment(16 bits) for windows system.
614 // You must do different endian transfer for linux and MAC OS
616 for (i = 0; i < (length/4); i++)
620 temp1 = ptemp[i]&0x0000FFFF;
621 temp2 = ptemp[i]>>16;
622 ptemp[i] = (temp1<<16)|temp2;
625 ptxrate = (cmpk_tx_rahis_t *)pmsg;
627 if (ptxrate == NULL )
632 for (i = 0; i < 16; i++)
634 // Collect CCK rate packet num
636 priv->stats.txrate.cck[i] += ptxrate->cck[i];
638 // Collect OFDM rate packet num
640 priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i];
642 for (j = 0; j < 4; j++)
643 priv->stats.txrate.ht_mcs[j][i] += ptxrate->ht_mcs[j][i];
646 } /* cmpk_Handle_Tx_Rate_History */
649 /*-----------------------------------------------------------------------------
650 * Function: cmpk_message_handle_rx()
652 * Overview: In the function, we will capture different RX command packet
653 * info. Every RX command packet element has different message
654 * length and meaning in content. We only support three type of RX
655 * command packet now. Please refer to document
656 * ws-06-0063-rtl8190-command-packet-specification.
666 * 05/06/2008 amy Create Version 0 porting from windows code.
668 *---------------------------------------------------------------------------*/
670 cmpk_message_handle_rx(
671 struct net_device *dev,
672 struct ieee80211_rx_stats *pstats)
675 u8 cmd_length, exe_cnt = 0;
679 /* 0. Check inpt arguments. If is is a command queue message or pointer is
683 return 0; /* This is not a command packet. */
686 /* 1. Read received command packet message length from RFD. */
687 total_length = pstats->Length;
689 /* 2. Read virtual address from RFD. */
690 pcmd_buff = pstats->virtual_address;
692 /* 3. Read command packet element id and length. */
693 element_id = pcmd_buff[0];
695 /* 4. Check every received command packet content according to different
696 element type. Because FW may aggregate RX command packet to minimize
697 transmit time between DRV and FW.*/
698 // Add a counter to prevent the lock in the loop from being held too long
699 while (total_length > 0 && exe_cnt++ < 100)
701 /* 2007/01/17 MH We support aggregation of different cmd in the same packet. */
702 element_id = pcmd_buff[0];
707 cmpk_handle_tx_feedback (dev, pcmd_buff);
708 cmd_length = CMPK_RX_TX_FB_SIZE;
711 case RX_INTERRUPT_STATUS:
712 cmpk_handle_interrupt_status(dev, pcmd_buff);
713 cmd_length = sizeof(cmpk_intr_sta_t);
716 case BOTH_QUERY_CONFIG:
717 cmpk_handle_query_config_rx(dev, pcmd_buff);
718 cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
722 cmpk_handle_tx_status(dev, pcmd_buff);
723 cmd_length = CMPK_RX_TX_STS_SIZE;
726 case RX_TX_PER_PKT_FEEDBACK:
727 // You must at lease add a switch case element here,
728 // Otherwise, we will jump to default case.
729 cmd_length = CMPK_RX_TX_FB_SIZE;
732 case RX_TX_RATE_HISTORY:
733 cmpk_handle_tx_rate_history(dev, pcmd_buff);
734 cmd_length = CMPK_TX_RAHIS_SIZE;
739 RT_TRACE(COMP_ERR, "---->cmpk_message_handle_rx():unknow CMD Element\n");
740 return 1; /* This is a command packet. */
743 total_length -= cmd_length;
744 pcmd_buff += cmd_length;
746 return 1; /* This is a command packet. */
748 } /* CMPK_Message_Handle_Rx */