1 /******************************************************************************
3 * (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
5 * Module: r819xusb_cmdpkt.c
6 * (RTL8190 TX/RX command packet handler Source C File)
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
22 * 05/06/2008 amy Create initial version porting from
25 ******************************************************************************/
27 #include "r819xU_cmdpkt.h"
29 rt_status SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen)
31 rt_status rtStatus = RT_STATUS_SUCCESS;
32 struct r8192_priv *priv = ieee80211_priv(dev);
35 unsigned char *ptr_buf;
37 /* Get TCB and local buffer from common pool.
38 (It is shared by CmdQ, MgntQ, and USB coalesce DataQ) */
39 skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + DataLen + 4);
40 memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
41 tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
42 tcb_desc->queue_index = TXCMD_QUEUE;
43 tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL;
44 tcb_desc->bLastIniPkt = 0;
45 skb_reserve(skb, USB_HWDESC_HEADER_LEN);
46 ptr_buf = skb_put(skb, DataLen);
47 memcpy(ptr_buf, pData, DataLen);
48 tcb_desc->txbuf_size = (u16)DataLen;
50 if (!priv->ieee80211->check_nic_enough_desc(dev, tcb_desc->queue_index) ||
51 (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index])) ||
52 (priv->ieee80211->queue_stop)) {
53 RT_TRACE(COMP_FIRMWARE, "=== NULL packet ======> tx full!\n");
54 skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
56 priv->ieee80211->softmac_hard_start_xmit(skb, dev);
62 /*-----------------------------------------------------------------------------
63 * Function: cmpk_counttxstatistic()
67 * Input: PADAPTER pAdapter
68 * CMPK_TXFB_T *psTx_FB
76 * 05/12/2008 amy Create Version 0 porting from windows code.
78 *---------------------------------------------------------------------------*/
79 static void cmpk_count_txstatistic(struct net_device *dev, cmpk_txfb_t *pstx_fb)
81 struct r8192_priv *priv = ieee80211_priv(dev);
83 RT_RF_POWER_STATE rtState;
85 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
88 /* When RF is off, we should not count the packet for hw/sw synchronize
89 reason, ie. there may be a duration while sw switch is changed and
90 hw switch is being changed. */
91 if (rtState == eRfOff)
96 if (pAdapter->bInHctTest)
99 /* We can not know the packet length and transmit type:
100 broadcast or uni or multicast. So the relative statistics
101 must be collected in tx feedback info. */
103 priv->stats.txfeedbackok++;
104 priv->stats.txoktotal++;
105 priv->stats.txokbytestotal += pstx_fb->pkt_length;
106 priv->stats.txokinperiod++;
108 /* We can not make sure broadcast/multicast or unicast mode. */
109 if (pstx_fb->pkt_type == PACKET_MULTICAST) {
110 priv->stats.txmulticast++;
111 priv->stats.txbytesmulticast += pstx_fb->pkt_length;
112 } else if (pstx_fb->pkt_type == PACKET_BROADCAST) {
113 priv->stats.txbroadcast++;
114 priv->stats.txbytesbroadcast += pstx_fb->pkt_length;
116 priv->stats.txunicast++;
117 priv->stats.txbytesunicast += pstx_fb->pkt_length;
120 priv->stats.txfeedbackfail++;
121 priv->stats.txerrtotal++;
122 priv->stats.txerrbytestotal += pstx_fb->pkt_length;
124 /* We can not make sure broadcast/multicast or unicast mode. */
125 if (pstx_fb->pkt_type == PACKET_MULTICAST)
126 priv->stats.txerrmulticast++;
127 else if (pstx_fb->pkt_type == PACKET_BROADCAST)
128 priv->stats.txerrbroadcast++;
130 priv->stats.txerrunicast++;
133 priv->stats.txretrycount += pstx_fb->retry_cnt;
134 priv->stats.txfeedbackretry += pstx_fb->retry_cnt;
140 /*-----------------------------------------------------------------------------
141 * Function: cmpk_handle_tx_feedback()
143 * Overview: The function is responsible for extract the message inside TX
144 * feedbck message from firmware. It will contain dedicated info in
145 * ws-06-0063-rtl8190-command-packet-specification.
146 * Please refer to chapter "TX Feedback Element".
147 * We have to read 20 bytes in the command packet.
149 * Input: struct net_device *dev
150 * u8 *pmsg - Msg Ptr of the command packet.
158 * 05/08/2008 amy Create Version 0 porting from windows code.
160 *---------------------------------------------------------------------------*/
161 static void cmpk_handle_tx_feedback(struct net_device *dev, u8 *pmsg)
163 struct r8192_priv *priv = ieee80211_priv(dev);
164 cmpk_txfb_t rx_tx_fb;
166 priv->stats.txfeedback++;
168 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
169 /* It seems that FW use big endian(MIPS) and DRV use little endian in
170 windows OS. So we have to read the content byte by byte or transfer
171 endian type before copy the message copy. */
172 /* Use pointer to transfer structure memory. */
173 memcpy((u8 *)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
174 /* 2. Use tx feedback info to count TX statistics. */
175 cmpk_count_txstatistic(dev, &rx_tx_fb);
176 /* Comment previous method for TX statistic function. */
177 /* Collect info TX feedback packet to fill TCB. */
178 /* We can not know the packet length and transmit type: broadcast or uni
183 void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev)
185 struct r8192_priv *priv = ieee80211_priv(dev);
187 /* 87B have to S/W beacon for DTM encryption_cmn. */
188 if (priv->ieee80211->current_network.mode == IEEE_A ||
189 priv->ieee80211->current_network.mode == IEEE_N_5G ||
190 (priv->ieee80211->current_network.mode == IEEE_N_24G &&
191 (!priv->ieee80211->pHTInfo->bCurSuppCCK))) {
193 DMESG("send beacon frame tx rate is 6Mbpm\n");
196 DMESG("send beacon frame tx rate is 1Mbpm\n");
199 rtl819xusb_beacon_tx(dev, tx_rate); /* HW Beacon */
207 /*-----------------------------------------------------------------------------
208 * Function: cmpk_handle_interrupt_status()
210 * Overview: The function is responsible for extract the message from
211 * firmware. It will contain dedicated info in
212 * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
213 * Please refer to chapter "Interrupt Status Element".
215 * Input: struct net_device *dev
216 * u8 *pmsg - Message Pointer of the command packet.
224 * 05/12/2008 amy Add this for rtl8192 porting from windows code.
226 *---------------------------------------------------------------------------*/
227 static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg)
229 cmpk_intr_sta_t rx_intr_status; /* */
230 struct r8192_priv *priv = ieee80211_priv(dev);
232 DMESG("---> cmpk_Handle_Interrupt_Status()\n");
234 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
235 /* It seems that FW use big endian(MIPS) and DRV use little endian in
236 windows OS. So we have to read the content byte by byte or transfer
237 endian type before copy the message copy. */
238 rx_intr_status.length = pmsg[1];
239 if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2)) {
240 DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
245 /* Statistics of beacon for ad-hoc mode. */
246 if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) {
247 /* 2 maybe need endian transform? */
248 rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
250 DMESG("interrupt status = 0x%x\n",
251 rx_intr_status.interrupt_status);
253 if (rx_intr_status.interrupt_status & ISR_TxBcnOk) {
254 priv->ieee80211->bibsscoordinator = true;
255 priv->stats.txbeaconokint++;
256 } else if (rx_intr_status.interrupt_status & ISR_TxBcnErr) {
257 priv->ieee80211->bibsscoordinator = false;
258 priv->stats.txbeaconerr++;
261 if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr)
262 cmdpkt_beacontimerinterrupt_819xusb(dev);
266 /* Other informations in interrupt status we need? */
269 DMESG("<---- cmpk_handle_interrupt_status()\n");
274 /*-----------------------------------------------------------------------------
275 * Function: cmpk_handle_query_config_rx()
277 * Overview: The function is responsible for extract the message from
278 * firmware. It will contain dedicated info in
279 * ws-06-0063-rtl8190-command-packet-specification. Please
280 * refer to chapter "Beacon State Element".
282 * Input: u8 *pmsg - Message Pointer of the command packet.
290 * 05/12/2008 amy Create Version 0 porting from windows code.
292 *---------------------------------------------------------------------------*/
293 static void cmpk_handle_query_config_rx(struct net_device *dev, u8 *pmsg)
295 cmpk_query_cfg_t rx_query_cfg;
298 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
299 /* It seems that FW use big endian(MIPS) and DRV use little endian in
300 windows OS. So we have to read the content byte by byte or transfer
301 endian type before copy the message copy. */
302 rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000) >> 31;
303 rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5;
304 rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3;
305 rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0;
306 rx_query_cfg.cfg_offset = pmsg[7];
307 rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) |
308 (pmsg[10] << 8) | (pmsg[11] << 0);
309 rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) |
310 (pmsg[14] << 8) | (pmsg[15] << 0);
315 /*-----------------------------------------------------------------------------
316 * Function: cmpk_count_tx_status()
318 * Overview: Count aggregated tx status from firmwar of one type rx command
319 * packet element id = RX_TX_STATUS.
329 * 05/12/2008 amy Create Version 0 porting from windows code.
331 *---------------------------------------------------------------------------*/
332 static void cmpk_count_tx_status(struct net_device *dev,
333 cmpk_tx_status_t *pstx_status)
335 struct r8192_priv *priv = ieee80211_priv(dev);
339 RT_RF_POWER_STATE rtstate;
341 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
342 (pu1Byte)(&rtState));
344 /* When RF is off, we should not count the packet for hw/sw synchronize
345 reason, ie. there may be a duration while sw switch is changed and
346 hw switch is being changed. */
347 if (rtState == eRfOff)
351 priv->stats.txfeedbackok += pstx_status->txok;
352 priv->stats.txoktotal += pstx_status->txok;
354 priv->stats.txfeedbackfail += pstx_status->txfail;
355 priv->stats.txerrtotal += pstx_status->txfail;
357 priv->stats.txretrycount += pstx_status->txretry;
358 priv->stats.txfeedbackretry += pstx_status->txretry;
361 priv->stats.txmulticast += pstx_status->txmcok;
362 priv->stats.txbroadcast += pstx_status->txbcok;
363 priv->stats.txunicast += pstx_status->txucok;
365 priv->stats.txerrmulticast += pstx_status->txmcfail;
366 priv->stats.txerrbroadcast += pstx_status->txbcfail;
367 priv->stats.txerrunicast += pstx_status->txucfail;
369 priv->stats.txbytesmulticast += pstx_status->txmclength;
370 priv->stats.txbytesbroadcast += pstx_status->txbclength;
371 priv->stats.txbytesunicast += pstx_status->txuclength;
373 priv->stats.last_packet_rate = pstx_status->rate;
378 /*-----------------------------------------------------------------------------
379 * Function: cmpk_handle_tx_status()
381 * Overview: Firmware add a new tx feedback status to reduce rx command
382 * packet buffer operation load.
392 * 05/12/2008 amy Create Version 0 porting from windows code.
394 *---------------------------------------------------------------------------*/
395 static void cmpk_handle_tx_status(struct net_device *dev, u8 *pmsg)
397 cmpk_tx_status_t rx_tx_sts;
399 memcpy((void *)&rx_tx_sts, (void *)pmsg, sizeof(cmpk_tx_status_t));
400 /* 2. Use tx feedback info to count TX statistics. */
401 cmpk_count_tx_status(dev, &rx_tx_sts);
406 /*-----------------------------------------------------------------------------
407 * Function: cmpk_handle_tx_rate_history()
409 * Overview: Firmware add a new tx rate history
419 * 05/12/2008 amy Create Version 0 porting from windows code.
421 *---------------------------------------------------------------------------*/
422 static void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg)
424 cmpk_tx_rahis_t *ptxrate;
426 u16 length = sizeof(cmpk_tx_rahis_t);
428 struct r8192_priv *priv = ieee80211_priv(dev);
432 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
433 (pu1Byte)(&rtState));
435 /* When RF is off, we should not count the packet for hw/sw synchronize
436 reason, ie. there may be a duration while sw switch is changed and
437 hw switch is being changed. */
438 if (rtState == eRfOff)
444 /* Do endian transfer to word alignment(16 bits) for windows system.
445 You must do different endian transfer for linux and MAC OS */
446 for (i = 0; i < (length/4); i++) {
449 temp1 = ptemp[i] & 0x0000FFFF;
450 temp2 = ptemp[i] >> 16;
451 ptemp[i] = (temp1 << 16) | temp2;
454 ptxrate = (cmpk_tx_rahis_t *)pmsg;
459 for (i = 0; i < 16; i++) {
460 /* Collect CCK rate packet num */
462 priv->stats.txrate.cck[i] += ptxrate->cck[i];
464 /* Collect OFDM rate packet num */
466 priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i];
468 for (j = 0; j < 4; j++)
469 priv->stats.txrate.ht_mcs[j][i] += ptxrate->ht_mcs[j][i];
475 /*-----------------------------------------------------------------------------
476 * Function: cmpk_message_handle_rx()
478 * Overview: In the function, we will capture different RX command packet
479 * info. Every RX command packet element has different message
480 * length and meaning in content. We only support three type of RX
481 * command packet now. Please refer to document
482 * ws-06-0063-rtl8190-command-packet-specification.
492 * 05/06/2008 amy Create Version 0 porting from windows code.
494 *---------------------------------------------------------------------------*/
495 extern u32 cmpk_message_handle_rx(struct net_device *dev,
496 struct ieee80211_rx_stats *pstats)
499 u8 cmd_length, exe_cnt = 0;
503 /* 0. Check inpt arguments. If is is a command queue message or
506 return 0; /* This is not a command packet. */
508 /* 1. Read received command packet message length from RFD. */
509 total_length = pstats->Length;
511 /* 2. Read virtual address from RFD. */
512 pcmd_buff = pstats->virtual_address;
514 /* 3. Read command packet element id and length. */
515 element_id = pcmd_buff[0];
517 /* 4. Check every received command packet content according to different
518 element type. Because FW may aggregate RX command packet to
519 minimize transmit time between DRV and FW.*/
520 /* Add a counter to prevent the lock in the loop from being held too
522 while (total_length > 0 && exe_cnt++ < 100) {
523 /* We support aggregation of different cmd in the same packet */
524 element_id = pcmd_buff[0];
526 switch (element_id) {
528 cmpk_handle_tx_feedback(dev, pcmd_buff);
529 cmd_length = CMPK_RX_TX_FB_SIZE;
532 case RX_INTERRUPT_STATUS:
533 cmpk_handle_interrupt_status(dev, pcmd_buff);
534 cmd_length = sizeof(cmpk_intr_sta_t);
537 case BOTH_QUERY_CONFIG:
538 cmpk_handle_query_config_rx(dev, pcmd_buff);
539 cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
543 cmpk_handle_tx_status(dev, pcmd_buff);
544 cmd_length = CMPK_RX_TX_STS_SIZE;
547 case RX_TX_PER_PKT_FEEDBACK:
548 /* You must at lease add a switch case element here,
549 Otherwise, we will jump to default case. */
550 cmd_length = CMPK_RX_TX_FB_SIZE;
553 case RX_TX_RATE_HISTORY:
554 cmpk_handle_tx_rate_history(dev, pcmd_buff);
555 cmd_length = CMPK_TX_RAHIS_SIZE;
560 RT_TRACE(COMP_ERR, "---->%s():unknown CMD Element\n",
562 return 1; /* This is a command packet. */
565 total_length -= cmd_length;
566 pcmd_buff += cmd_length;
568 return 1; /* This is a command packet. */