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 "r8192E_hw.h"
26 #include "r819xE_cmdpkt.h"
29 * Driver internal module can call the API to send message to
30 * firmware side. For example, you can send a debug command packet.
31 * Or you can send a request for FW to modify RLX4181 LBUS HW bank.
32 * Otherwise, you can change MAC/PHT/RF register by firmware at
33 * run time. We do not support message more than one segment now.
35 RT_STATUS cmpk_message_handle_tx(
36 struct net_device *dev,
37 u8* code_virtual_address,
42 RT_STATUS rt_status = RT_STATUS_SUCCESS;
46 struct r8192_priv *priv = ieee80211_priv(dev);
48 u16 frag_length = 0, frag_offset = 0;
49 rt_firmware *pfirmware = priv->pFirmware;
51 unsigned char *seg_ptr;
55 PTX_FWINFO_8190PCI pTxFwInfo = NULL;
58 //spin_lock_irqsave(&priv->tx_lock,flags);
59 RT_TRACE(COMP_CMDPKT,"%s(),buffer_len is %d\n",__FUNCTION__,buffer_len);
60 firmware_init_param(dev);
61 //Fragmentation might be required
62 frag_threshold = pfirmware->cmdpacket_frag_thresold;
64 if((buffer_len - frag_offset) > frag_threshold) {
65 frag_length = frag_threshold ;
69 frag_length =(u16)(buffer_len - frag_offset);
74 /* Allocate skb buffer to contain firmware info and tx descriptor info
75 * add 4 to avoid packet appending overflow.
78 skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4);
80 skb = dev_alloc_skb(frag_length + priv->ieee80211->tx_headroom + 4);
83 rt_status = RT_STATUS_FAILURE;
87 memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
88 tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE);
89 tcb_desc->queue_index = TXCMD_QUEUE;
90 tcb_desc->bCmdOrInit = packettype;
91 tcb_desc->bLastIniPkt = bLastIniPkt;
92 tcb_desc->pkt_size = frag_length;
95 skb_reserve(skb, USB_HWDESC_HEADER_LEN);
98 //seg_ptr = skb_put(skb, frag_length + priv->ieee80211->tx_headroom);
99 seg_ptr = skb_put(skb, priv->ieee80211->tx_headroom);
101 pTxFwInfo = (PTX_FWINFO_8190PCI)seg_ptr;
102 memset(pTxFwInfo,0,sizeof(TX_FWINFO_8190PCI));
103 memset(pTxFwInfo,0x12,8);
105 seg_ptr +=sizeof(TX_FWINFO_8190PCI);
108 * Transform from little endian to big endian
111 seg_ptr = skb_tail_pointer(skb);
112 for(i=0 ; i < frag_length; i+=4) {
113 *seg_ptr++ = ((i+0)<frag_length)?code_virtual_address[i+3]:0;
114 *seg_ptr++ = ((i+1)<frag_length)?code_virtual_address[i+2]:0;
115 *seg_ptr++ = ((i+2)<frag_length)?code_virtual_address[i+1]:0;
116 *seg_ptr++ = ((i+3)<frag_length)?code_virtual_address[i+0]:0;
119 priv->ieee80211->softmac_hard_start_xmit(skb,dev);
121 code_virtual_address += frag_length;
122 frag_offset += frag_length;
124 }while(frag_offset < buffer_len);
127 //spin_unlock_irqrestore(&priv->tx_lock,flags);
135 cmpk_count_txstatistic(
136 struct net_device *dev,
137 cmpk_txfb_t *pstx_fb)
139 struct r8192_priv *priv = ieee80211_priv(dev);
141 RT_RF_POWER_STATE rtState;
143 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
145 // When RF is off, we should not count the packet for hw/sw synchronize
146 // reason, ie. there may be a duration while sw switch is changed and hw
147 // switch is being changed. 2006.12.04, by shien chang.
148 if (rtState == eRfOff)
155 if(pAdapter->bInHctTest)
158 /* We can not know the packet length and transmit type: broadcast or uni
159 or multicast. So the relative statistics must be collected in tx
163 priv->stats.txfeedbackok++;
164 priv->stats.txoktotal++;
165 priv->stats.txokbytestotal += pstx_fb->pkt_length;
166 priv->stats.txokinperiod++;
168 /* We can not make sure broadcast/multicast or unicast mode. */
169 if (pstx_fb->pkt_type == PACKET_MULTICAST)
171 priv->stats.txmulticast++;
172 priv->stats.txbytesmulticast += pstx_fb->pkt_length;
174 else if (pstx_fb->pkt_type == PACKET_BROADCAST)
176 priv->stats.txbroadcast++;
177 priv->stats.txbytesbroadcast += pstx_fb->pkt_length;
181 priv->stats.txunicast++;
182 priv->stats.txbytesunicast += pstx_fb->pkt_length;
187 priv->stats.txfeedbackfail++;
188 priv->stats.txerrtotal++;
189 priv->stats.txerrbytestotal += pstx_fb->pkt_length;
191 /* We can not make sure broadcast/multicast or unicast mode. */
192 if (pstx_fb->pkt_type == PACKET_MULTICAST)
194 priv->stats.txerrmulticast++;
196 else if (pstx_fb->pkt_type == PACKET_BROADCAST)
198 priv->stats.txerrbroadcast++;
202 priv->stats.txerrunicast++;
206 priv->stats.txretrycount += pstx_fb->retry_cnt;
207 priv->stats.txfeedbackretry += pstx_fb->retry_cnt;
214 * The function is responsible for extract the message inside TX
215 * feedbck message from firmware. It will contain dedicated info in
216 * ws-06-0063-rtl8190-command-packet-specification. Please
217 * refer to chapter "TX Feedback Element". We have to read 20 bytes
218 * in the command packet.
221 cmpk_handle_tx_feedback(
222 struct net_device *dev,
225 struct r8192_priv *priv = ieee80211_priv(dev);
226 cmpk_txfb_t rx_tx_fb; /* */
228 priv->stats.txfeedback++;
230 /* 0. Display received message. */
231 //cmpk_Display_Message(CMPK_RX_TX_FB_SIZE, pMsg);
233 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
234 /* It seems that FW use big endian(MIPS) and DRV use little endian in
235 windows OS. So we have to read the content byte by byte or transfer
236 endian type before copy the message copy. */
237 #if 0 // The TX FEEDBACK packet element address
238 //rx_tx_fb.Element_ID = pMsg[0];
239 //rx_tx_fb.Length = pMsg[1];
240 rx_tx_fb.TOK = pMsg[2]>>7;
241 rx_tx_fb.Fail_Reason = (pMsg[2] & 0x70) >> 4;
242 rx_tx_fb.TID = (pMsg[2] & 0x0F);
243 rx_tx_fb.Qos_Pkt = pMsg[3] >> 7;
244 rx_tx_fb.Bandwidth = (pMsg[3] & 0x40) >> 6;
245 rx_tx_fb.Retry_Cnt = pMsg[5];
246 rx_tx_fb.Pkt_ID = (pMsg[6] << 8) | pMsg[7];
247 rx_tx_fb.Seq_Num = (pMsg[8] << 8) | pMsg[9];
248 rx_tx_fb.S_Rate = pMsg[10];
249 rx_tx_fb.F_Rate = pMsg[11];
250 rx_tx_fb.S_RTS_Rate = pMsg[12];
251 rx_tx_fb.F_RTS_Rate = pMsg[13];
252 rx_tx_fb.pkt_length = (pMsg[14] << 8) | pMsg[15];
254 /* 2007/07/05 MH Use pointer to transfer structure memory. */
255 //memcpy((UINT8 *)&rx_tx_fb, pMsg, sizeof(CMPK_TXFB_T));
256 memcpy((u8*)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
257 /* 2. Use tx feedback info to count TX statistics. */
258 cmpk_count_txstatistic(dev, &rx_tx_fb);
260 /* 2007/07/11 MH Assign current operate rate. */
261 if (pAdapter->RegWirelessMode == WIRELESS_MODE_A ||
262 pAdapter->RegWirelessMode == WIRELESS_MODE_B ||
263 pAdapter->RegWirelessMode == WIRELESS_MODE_G)
265 pMgntInfo->CurrentOperaRate = (rx_tx_fb.F_Rate & 0x7F);
267 else if (pAdapter->RegWirelessMode == WIRELESS_MODE_N_24G ||
268 pAdapter->RegWirelessMode == WIRELESS_MODE_N_5G)
270 pMgntInfo->HTCurrentOperaRate = (rx_tx_fb.F_Rate & 0x8F);
273 /* 2007/01/17 MH Comment previous method for TX statistic function. */
274 /* Collect info TX feedback packet to fill TCB. */
275 /* We can not know the packet length and transmit type: broadcast or uni
277 //CountTxStatistics( pAdapter, &tcb );
283 * The function is responsible for extract the message from
284 * firmware. It will contain dedicated info in
285 * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
286 * Please refer to chapter "Interrupt Status Element".
289 cmpk_handle_interrupt_status(
290 struct net_device *dev,
293 cmpk_intr_sta_t rx_intr_status; /* */
294 struct r8192_priv *priv = ieee80211_priv(dev);
296 DMESG("---> cmpk_Handle_Interrupt_Status()\n");
298 /* 0. Display received message. */
299 //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
301 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
302 /* It seems that FW use big endian(MIPS) and DRV use little endian in
303 windows OS. So we have to read the content byte by byte or transfer
304 endian type before copy the message copy. */
305 //rx_bcn_state.Element_ID = pMsg[0];
306 //rx_bcn_state.Length = pMsg[1];
307 rx_intr_status.length = pmsg[1];
308 if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2))
310 DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
315 // Statistics of beacon for ad-hoc mode.
316 if( priv->ieee80211->iw_mode == IW_MODE_ADHOC)
318 //2 maybe need endian transform?
319 rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
320 //rx_intr_status.InterruptStatus = N2H4BYTE(*((UINT32 *)(pMsg + 4)));
322 DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status);
324 if (rx_intr_status.interrupt_status & ISR_TxBcnOk)
326 priv->ieee80211->bibsscoordinator = true;
327 priv->stats.txbeaconokint++;
329 else if (rx_intr_status.interrupt_status & ISR_TxBcnErr)
331 priv->ieee80211->bibsscoordinator = false;
332 priv->stats.txbeaconerr++;
336 // Other informations in interrupt status we need?
339 DMESG("<---- cmpk_handle_interrupt_status()\n");
345 * The function is responsible for extract the message from
346 * firmware. It will contain dedicated info in
347 * ws-06-0063-rtl8190-command-packet-specification. Please
348 * refer to chapter "Beacon State Element".
351 cmpk_handle_query_config_rx(
352 struct net_device *dev,
355 cmpk_query_cfg_t rx_query_cfg; /* */
357 /* 0. Display received message. */
358 //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
360 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
361 /* It seems that FW use big endian(MIPS) and DRV use little endian in
362 windows OS. So we have to read the content byte by byte or transfer
363 endian type before copy the message copy. */
364 //rx_query_cfg.Element_ID = pMsg[0];
365 //rx_query_cfg.Length = pMsg[1];
366 rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000)>>31;
367 rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5;
368 rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3;
369 rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0;
370 rx_query_cfg.cfg_offset = pmsg[7];
371 rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) |
372 (pmsg[10] << 8) | (pmsg[11] << 0);
373 rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) |
374 (pmsg[14] << 8) | (pmsg[15] << 0);
380 * Count aggregated tx status from firmwar of one type rx command
381 * packet element id = RX_TX_STATUS.
383 static void cmpk_count_tx_status( struct net_device *dev,
384 cmpk_tx_status_t *pstx_status)
386 struct r8192_priv *priv = ieee80211_priv(dev);
390 RT_RF_POWER_STATE rtstate;
392 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
394 // When RF is off, we should not count the packet for hw/sw synchronize
395 // reason, ie. there may be a duration while sw switch is changed and hw
396 // switch is being changed. 2006.12.04, by shien chang.
397 if (rtState == eRfOff)
403 priv->stats.txfeedbackok += pstx_status->txok;
404 priv->stats.txoktotal += pstx_status->txok;
406 priv->stats.txfeedbackfail += pstx_status->txfail;
407 priv->stats.txerrtotal += pstx_status->txfail;
409 priv->stats.txretrycount += pstx_status->txretry;
410 priv->stats.txfeedbackretry += pstx_status->txretry;
412 //pAdapter->TxStats.NumTxOkBytesTotal += psTx_FB->pkt_length;
413 //pAdapter->TxStats.NumTxErrBytesTotal += psTx_FB->pkt_length;
414 //pAdapter->MgntInfo.LinkDetectInfo.NumTxOkInPeriod++;
416 priv->stats.txmulticast += pstx_status->txmcok;
417 priv->stats.txbroadcast += pstx_status->txbcok;
418 priv->stats.txunicast += pstx_status->txucok;
420 priv->stats.txerrmulticast += pstx_status->txmcfail;
421 priv->stats.txerrbroadcast += pstx_status->txbcfail;
422 priv->stats.txerrunicast += pstx_status->txucfail;
424 priv->stats.txbytesmulticast += pstx_status->txmclength;
425 priv->stats.txbytesbroadcast += pstx_status->txbclength;
426 priv->stats.txbytesunicast += pstx_status->txuclength;
428 priv->stats.last_packet_rate = pstx_status->rate;
434 * Firmware add a new tx feedback status to reduce rx command
435 * packet buffer operation load.
438 cmpk_handle_tx_status(
439 struct net_device *dev,
442 cmpk_tx_status_t rx_tx_sts; /* */
444 memcpy((void*)&rx_tx_sts, (void*)pmsg, sizeof(cmpk_tx_status_t));
445 /* 2. Use tx feedback info to count TX statistics. */
446 cmpk_count_tx_status(dev, &rx_tx_sts);
451 /* Firmware add a new tx rate history */
453 cmpk_handle_tx_rate_history(
454 struct net_device *dev,
457 cmpk_tx_rahis_t *ptxrate;
458 // RT_RF_POWER_STATE rtState;
460 u16 length = sizeof(cmpk_tx_rahis_t);
462 struct r8192_priv *priv = ieee80211_priv(dev);
466 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
468 // When RF is off, we should not count the packet for hw/sw synchronize
469 // reason, ie. there may be a duration while sw switch is changed and hw
470 // switch is being changed. 2006.12.04, by shien chang.
471 if (rtState == eRfOff)
480 // Do endian transfer to word alignment(16 bits) for windows system.
481 // You must do different endian transfer for linux and MAC OS
483 for (i = 0; i < (length/4); i++)
487 temp1 = ptemp[i]&0x0000FFFF;
488 temp2 = ptemp[i]>>16;
489 ptemp[i] = (temp1<<16)|temp2;
492 ptxrate = (cmpk_tx_rahis_t *)pmsg;
494 if (ptxrate == NULL )
499 for (i = 0; i < 16; i++)
501 // Collect CCK rate packet num
503 priv->stats.txrate.cck[i] += ptxrate->cck[i];
505 // Collect OFDM rate packet num
507 priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i];
509 for (j = 0; j < 4; j++)
510 priv->stats.txrate.ht_mcs[j][i] += ptxrate->ht_mcs[j][i];
517 * In the function, we will capture different RX command packet
518 * info. Every RX command packet element has different message
519 * length and meaning in content. We only support three type of RX
520 * command packet now. Please refer to document
521 * ws-06-0063-rtl8190-command-packet-specification.
523 u32 cmpk_message_handle_rx(struct net_device *dev, struct ieee80211_rx_stats *pstats)
525 // u32 debug_level = DBG_LOUD;
526 struct r8192_priv *priv = ieee80211_priv(dev);
528 u8 cmd_length, exe_cnt = 0;
532 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx()\n");
534 /* 0. Check inpt arguments. If is is a command queue message or pointer is
536 if (/*(prfd->queue_id != CMPK_RX_QUEUE_ID) || */(pstats== NULL))
538 /* Print error message. */
539 /*RT_TRACE(COMP_SEND, DebugLevel,
540 ("\n\r[CMPK]-->Err queue id or pointer"));*/
541 return 0; /* This is not a command packet. */
544 /* 1. Read received command packet message length from RFD. */
545 total_length = pstats->Length;
547 /* 2. Read virtual address from RFD. */
548 pcmd_buff = pstats->virtual_address;
550 /* 3. Read command pakcet element id and length. */
551 element_id = pcmd_buff[0];
552 /*RT_TRACE(COMP_SEND, DebugLevel,
553 ("\n\r[CMPK]-->element ID=%d Len=%d", element_id, total_length));*/
555 /* 4. Check every received command packet conent according to different
556 element type. Because FW may aggregate RX command packet to minimize
557 transmit time between DRV and FW.*/
558 // Add a counter to prevent to locked in the loop too long
559 while (total_length > 0 || exe_cnt++ >100)
561 /* 2007/01/17 MH We support aggregation of different cmd in the same packet. */
562 element_id = pcmd_buff[0];
568 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_FEEDBACK\n");
569 cmpk_handle_tx_feedback (dev, pcmd_buff);
570 cmd_length = CMPK_RX_TX_FB_SIZE;
573 case RX_INTERRUPT_STATUS:
575 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_INTERRUPT_STATUS\n");
576 cmpk_handle_interrupt_status(dev, pcmd_buff);
577 cmd_length = sizeof(cmpk_intr_sta_t);
580 case BOTH_QUERY_CONFIG:
582 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():BOTH_QUERY_CONFIG\n");
583 cmpk_handle_query_config_rx(dev, pcmd_buff);
584 cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
589 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_STATUS\n");
590 cmpk_handle_tx_status(dev, pcmd_buff);
591 cmd_length = CMPK_RX_TX_STS_SIZE;
594 case RX_TX_PER_PKT_FEEDBACK:
595 // You must at lease add a switch case element here,
596 // Otherwise, we will jump to default case.
597 //DbgPrint("CCX Test\r\n");
598 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_PER_PKT_FEEDBACK\n");
599 cmd_length = CMPK_RX_TX_FB_SIZE;
602 case RX_TX_RATE_HISTORY:
603 //DbgPrint(" rx tx rate history\r\n");
605 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_HISTORY\n");
606 cmpk_handle_tx_rate_history(dev, pcmd_buff);
607 cmd_length = CMPK_TX_RAHIS_SIZE;
612 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():unknown CMD Element\n");
613 return 1; /* This is a command packet. */
615 // 2007/01/22 MH Display received rx command packet info.
616 //cmpk_Display_Message(cmd_length, pcmd_buff);
618 // 2007/01/22 MH Add to display tx statistic.
619 //cmpk_DisplayTxStatistic(pAdapter);
621 /* 2007/03/09 MH Collect sidderent cmd element pkt num. */
622 priv->stats.rxcmdpkt[element_id]++;
624 total_length -= cmd_length;
625 pcmd_buff += cmd_length;
626 } /* while (total_length > 0) */
627 return 1; /* This is a command packet. */
629 RT_TRACE(COMP_EVENTS, "<----cmpk_message_handle_rx()\n");