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 struct r8192_priv *priv = ieee80211_priv(dev);
34 unsigned char *ptr_buf;
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);
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;
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);
57 priv->ieee80211->softmac_hard_start_xmit(skb, dev);
60 return RT_STATUS_SUCCESS;
63 /*-----------------------------------------------------------------------------
64 * Function: cmpk_counttxstatistic()
68 * Input: PADAPTER pAdapter
69 * CMPK_TXFB_T *psTx_FB
77 * 05/12/2008 amy Create Version 0 porting from windows code.
79 *---------------------------------------------------------------------------*/
80 static void cmpk_count_txstatistic(struct net_device *dev, cmpk_txfb_t *pstx_fb)
82 struct r8192_priv *priv = ieee80211_priv(dev);
84 RT_RF_POWER_STATE rtState;
86 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
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)
97 if (pAdapter->bInHctTest)
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. */
104 priv->stats.txfeedbackok++;
105 priv->stats.txoktotal++;
106 priv->stats.txokbytestotal += pstx_fb->pkt_length;
107 priv->stats.txokinperiod++;
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;
117 priv->stats.txunicast++;
118 priv->stats.txbytesunicast += pstx_fb->pkt_length;
121 priv->stats.txfeedbackfail++;
122 priv->stats.txerrtotal++;
123 priv->stats.txerrbytestotal += pstx_fb->pkt_length;
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++;
131 priv->stats.txerrunicast++;
134 priv->stats.txretrycount += pstx_fb->retry_cnt;
135 priv->stats.txfeedbackretry += pstx_fb->retry_cnt;
141 /*-----------------------------------------------------------------------------
142 * Function: cmpk_handle_tx_feedback()
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.
150 * Input: struct net_device *dev
151 * u8 *pmsg - Msg Ptr of the command packet.
159 * 05/08/2008 amy Create Version 0 porting from windows code.
161 *---------------------------------------------------------------------------*/
162 static void cmpk_handle_tx_feedback(struct net_device *dev, u8 *pmsg)
164 struct r8192_priv *priv = ieee80211_priv(dev);
165 cmpk_txfb_t rx_tx_fb;
167 priv->stats.txfeedback++;
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
184 static void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev)
186 struct r8192_priv *priv = ieee80211_priv(dev);
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))) {
194 DMESG("send beacon frame tx rate is 6Mbpm\n");
197 DMESG("send beacon frame tx rate is 1Mbpm\n");
200 rtl819xusb_beacon_tx(dev, tx_rate); /* HW Beacon */
208 /*-----------------------------------------------------------------------------
209 * Function: cmpk_handle_interrupt_status()
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".
216 * Input: struct net_device *dev
217 * u8 *pmsg - Message Pointer of the command packet.
225 * 05/12/2008 amy Add this for rtl8192 porting from windows code.
227 *---------------------------------------------------------------------------*/
228 static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg)
230 cmpk_intr_sta_t rx_intr_status; /* */
231 struct r8192_priv *priv = ieee80211_priv(dev);
233 DMESG("---> cmpk_Handle_Interrupt_Status()\n");
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");
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));
251 DMESG("interrupt status = 0x%x\n",
252 rx_intr_status.interrupt_status);
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++;
262 if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr)
263 cmdpkt_beacontimerinterrupt_819xusb(dev);
267 /* Other informations in interrupt status we need? */
270 DMESG("<---- cmpk_handle_interrupt_status()\n");
275 /*-----------------------------------------------------------------------------
276 * Function: cmpk_handle_query_config_rx()
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".
283 * Input: u8 *pmsg - Message Pointer of the command packet.
291 * 05/12/2008 amy Create Version 0 porting from windows code.
293 *---------------------------------------------------------------------------*/
294 static void cmpk_handle_query_config_rx(struct net_device *dev, u8 *pmsg)
296 cmpk_query_cfg_t rx_query_cfg;
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);
316 /*-----------------------------------------------------------------------------
317 * Function: cmpk_count_tx_status()
319 * Overview: Count aggregated tx status from firmwar of one type rx command
320 * packet element id = RX_TX_STATUS.
330 * 05/12/2008 amy Create Version 0 porting from windows code.
332 *---------------------------------------------------------------------------*/
333 static void cmpk_count_tx_status(struct net_device *dev,
334 cmpk_tx_status_t *pstx_status)
336 struct r8192_priv *priv = ieee80211_priv(dev);
340 RT_RF_POWER_STATE rtstate;
342 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
343 (pu1Byte)(&rtState));
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)
352 priv->stats.txfeedbackok += pstx_status->txok;
353 priv->stats.txoktotal += pstx_status->txok;
355 priv->stats.txfeedbackfail += pstx_status->txfail;
356 priv->stats.txerrtotal += pstx_status->txfail;
358 priv->stats.txretrycount += pstx_status->txretry;
359 priv->stats.txfeedbackretry += pstx_status->txretry;
362 priv->stats.txmulticast += pstx_status->txmcok;
363 priv->stats.txbroadcast += pstx_status->txbcok;
364 priv->stats.txunicast += pstx_status->txucok;
366 priv->stats.txerrmulticast += pstx_status->txmcfail;
367 priv->stats.txerrbroadcast += pstx_status->txbcfail;
368 priv->stats.txerrunicast += pstx_status->txucfail;
370 priv->stats.txbytesmulticast += pstx_status->txmclength;
371 priv->stats.txbytesbroadcast += pstx_status->txbclength;
372 priv->stats.txbytesunicast += pstx_status->txuclength;
374 priv->stats.last_packet_rate = pstx_status->rate;
379 /*-----------------------------------------------------------------------------
380 * Function: cmpk_handle_tx_status()
382 * Overview: Firmware add a new tx feedback status to reduce rx command
383 * packet buffer operation load.
393 * 05/12/2008 amy Create Version 0 porting from windows code.
395 *---------------------------------------------------------------------------*/
396 static void cmpk_handle_tx_status(struct net_device *dev, u8 *pmsg)
398 cmpk_tx_status_t rx_tx_sts;
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);
407 /*-----------------------------------------------------------------------------
408 * Function: cmpk_handle_tx_rate_history()
410 * Overview: Firmware add a new tx rate history
420 * 05/12/2008 amy Create Version 0 porting from windows code.
422 *---------------------------------------------------------------------------*/
423 static void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg)
425 cmpk_tx_rahis_t *ptxrate;
427 u16 length = sizeof(cmpk_tx_rahis_t);
429 struct r8192_priv *priv = ieee80211_priv(dev);
433 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
434 (pu1Byte)(&rtState));
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)
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++) {
450 temp1 = ptemp[i] & 0x0000FFFF;
451 temp2 = ptemp[i] >> 16;
452 ptemp[i] = (temp1 << 16) | temp2;
455 ptxrate = (cmpk_tx_rahis_t *)pmsg;
460 for (i = 0; i < 16; i++) {
461 /* Collect CCK rate packet num */
463 priv->stats.txrate.cck[i] += ptxrate->cck[i];
465 /* Collect OFDM rate packet num */
467 priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i];
469 for (j = 0; j < 4; j++)
470 priv->stats.txrate.ht_mcs[j][i] += ptxrate->ht_mcs[j][i];
476 /*-----------------------------------------------------------------------------
477 * Function: cmpk_message_handle_rx()
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.
493 * 05/06/2008 amy Create Version 0 porting from windows code.
495 *---------------------------------------------------------------------------*/
496 u32 cmpk_message_handle_rx(struct net_device *dev,
497 struct ieee80211_rx_stats *pstats)
500 u8 cmd_length, exe_cnt = 0;
504 /* 0. Check inpt arguments. If is is a command queue message or
507 return 0; /* This is not a command packet. */
509 /* 1. Read received command packet message length from RFD. */
510 total_length = pstats->Length;
512 /* 2. Read virtual address from RFD. */
513 pcmd_buff = pstats->virtual_address;
515 /* 3. Read command packet element id and length. */
516 element_id = pcmd_buff[0];
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
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];
527 switch (element_id) {
529 cmpk_handle_tx_feedback(dev, pcmd_buff);
530 cmd_length = CMPK_RX_TX_FB_SIZE;
533 case RX_INTERRUPT_STATUS:
534 cmpk_handle_interrupt_status(dev, pcmd_buff);
535 cmd_length = sizeof(cmpk_intr_sta_t);
538 case BOTH_QUERY_CONFIG:
539 cmpk_handle_query_config_rx(dev, pcmd_buff);
540 cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
544 cmpk_handle_tx_status(dev, pcmd_buff);
545 cmd_length = CMPK_RX_TX_STS_SIZE;
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;
554 case RX_TX_RATE_HISTORY:
555 cmpk_handle_tx_rate_history(dev, pcmd_buff);
556 cmd_length = CMPK_TX_RAHIS_SIZE;
561 RT_TRACE(COMP_ERR, "---->%s():unknown CMD Element\n",
563 return 1; /* This is a command packet. */
566 total_length -= cmd_length;
567 pcmd_buff += cmd_length;
569 return 1; /* This is a command packet. */