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;
43 struct r8192_priv *priv = ieee80211_priv(dev);
45 u16 frag_length = 0, frag_offset = 0;
46 rt_firmware *pfirmware = priv->pFirmware;
48 unsigned char *seg_ptr;
52 PTX_FWINFO_8190PCI pTxFwInfo = NULL;
55 RT_TRACE(COMP_CMDPKT,"%s(),buffer_len is %d\n",__FUNCTION__,buffer_len);
56 firmware_init_param(dev);
57 //Fragmentation might be required
58 frag_threshold = pfirmware->cmdpacket_frag_thresold;
60 if((buffer_len - frag_offset) > frag_threshold) {
61 frag_length = frag_threshold ;
65 frag_length =(u16)(buffer_len - frag_offset);
70 /* Allocate skb buffer to contain firmware info and tx descriptor info
71 * add 4 to avoid packet appending overflow.
73 skb = dev_alloc_skb(frag_length + priv->ieee80211->tx_headroom + 4);
75 rt_status = RT_STATUS_FAILURE;
79 memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
80 tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE);
81 tcb_desc->queue_index = TXCMD_QUEUE;
82 tcb_desc->bCmdOrInit = packettype;
83 tcb_desc->bLastIniPkt = bLastIniPkt;
84 tcb_desc->pkt_size = frag_length;
86 //seg_ptr = skb_put(skb, frag_length + priv->ieee80211->tx_headroom);
87 seg_ptr = skb_put(skb, priv->ieee80211->tx_headroom);
89 pTxFwInfo = (PTX_FWINFO_8190PCI)seg_ptr;
90 memset(pTxFwInfo,0,sizeof(TX_FWINFO_8190PCI));
91 memset(pTxFwInfo,0x12,8);
93 seg_ptr +=sizeof(TX_FWINFO_8190PCI);
96 * Transform from little endian to big endian
99 seg_ptr = skb_tail_pointer(skb);
100 for(i=0 ; i < frag_length; i+=4) {
101 *seg_ptr++ = ((i+0)<frag_length)?code_virtual_address[i+3]:0;
102 *seg_ptr++ = ((i+1)<frag_length)?code_virtual_address[i+2]:0;
103 *seg_ptr++ = ((i+2)<frag_length)?code_virtual_address[i+1]:0;
104 *seg_ptr++ = ((i+3)<frag_length)?code_virtual_address[i+0]:0;
107 priv->ieee80211->softmac_hard_start_xmit(skb, priv->ieee80211);
109 code_virtual_address += frag_length;
110 frag_offset += frag_length;
112 }while(frag_offset < buffer_len);
119 cmpk_count_txstatistic(
120 struct net_device *dev,
121 cmpk_txfb_t *pstx_fb)
123 struct r8192_priv *priv = ieee80211_priv(dev);
125 RT_RF_POWER_STATE rtState;
127 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
129 // When RF is off, we should not count the packet for hw/sw synchronize
130 // reason, ie. there may be a duration while sw switch is changed and hw
131 // switch is being changed. 2006.12.04, by shien chang.
132 if (rtState == eRfOff)
139 if(pAdapter->bInHctTest)
142 /* We can not know the packet length and transmit type: broadcast or uni
143 or multicast. So the relative statistics must be collected in tx
147 priv->stats.txoktotal++;
149 /* We can not make sure broadcast/multicast or unicast mode. */
150 if (pstx_fb->pkt_type != PACKET_MULTICAST &&
151 pstx_fb->pkt_type != PACKET_BROADCAST) {
152 priv->stats.txbytesunicast += pstx_fb->pkt_length;
160 * The function is responsible for extract the message inside TX
161 * feedbck message from firmware. It will contain dedicated info in
162 * ws-06-0063-rtl8190-command-packet-specification. Please
163 * refer to chapter "TX Feedback Element". We have to read 20 bytes
164 * in the command packet.
167 cmpk_handle_tx_feedback(
168 struct net_device *dev,
171 struct r8192_priv *priv = ieee80211_priv(dev);
172 cmpk_txfb_t rx_tx_fb; /* */
174 priv->stats.txfeedback++;
176 memcpy((u8*)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
177 /* Use tx feedback info to count TX statistics. */
178 cmpk_count_txstatistic(dev, &rx_tx_fb);
183 * The function is responsible for extract the message from
184 * firmware. It will contain dedicated info in
185 * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
186 * Please refer to chapter "Interrupt Status Element".
189 cmpk_handle_interrupt_status(
190 struct net_device *dev,
193 cmpk_intr_sta_t rx_intr_status; /* */
194 struct r8192_priv *priv = ieee80211_priv(dev);
196 DMESG("---> cmpk_Handle_Interrupt_Status()\n");
198 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
199 /* It seems that FW use big endian(MIPS) and DRV use little endian in
200 windows OS. So we have to read the content byte by byte or transfer
201 endian type before copy the message copy. */
202 //rx_bcn_state.Element_ID = pMsg[0];
203 //rx_bcn_state.Length = pMsg[1];
204 rx_intr_status.length = pmsg[1];
205 if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2))
207 DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
212 // Statistics of beacon for ad-hoc mode.
213 if( priv->ieee80211->iw_mode == IW_MODE_ADHOC)
215 //2 maybe need endian transform?
216 rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
217 //rx_intr_status.InterruptStatus = N2H4BYTE(*((UINT32 *)(pMsg + 4)));
219 DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status);
221 if (rx_intr_status.interrupt_status & ISR_TxBcnOk)
223 priv->ieee80211->bibsscoordinator = true;
224 priv->stats.txbeaconokint++;
226 else if (rx_intr_status.interrupt_status & ISR_TxBcnErr)
228 priv->ieee80211->bibsscoordinator = false;
229 priv->stats.txbeaconerr++;
233 // Other informations in interrupt status we need?
236 DMESG("<---- cmpk_handle_interrupt_status()\n");
242 * The function is responsible for extract the message from
243 * firmware. It will contain dedicated info in
244 * ws-06-0063-rtl8190-command-packet-specification. Please
245 * refer to chapter "Beacon State Element".
248 cmpk_handle_query_config_rx(
249 struct net_device *dev,
252 cmpk_query_cfg_t rx_query_cfg; /* */
254 /* 0. Display received message. */
255 //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
257 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
258 /* It seems that FW use big endian(MIPS) and DRV use little endian in
259 windows OS. So we have to read the content byte by byte or transfer
260 endian type before copy the message copy. */
261 //rx_query_cfg.Element_ID = pMsg[0];
262 //rx_query_cfg.Length = pMsg[1];
263 rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000)>>31;
264 rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5;
265 rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3;
266 rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0;
267 rx_query_cfg.cfg_offset = pmsg[7];
268 rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) |
269 (pmsg[10] << 8) | (pmsg[11] << 0);
270 rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) |
271 (pmsg[14] << 8) | (pmsg[15] << 0);
277 * Count aggregated tx status from firmwar of one type rx command
278 * packet element id = RX_TX_STATUS.
280 static void cmpk_count_tx_status( struct net_device *dev,
281 cmpk_tx_status_t *pstx_status)
283 struct r8192_priv *priv = ieee80211_priv(dev);
287 RT_RF_POWER_STATE rtstate;
289 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
291 // When RF is off, we should not count the packet for hw/sw synchronize
292 // reason, ie. there may be a duration while sw switch is changed and hw
293 // switch is being changed. 2006.12.04, by shien chang.
294 if (rtState == eRfOff)
300 priv->stats.txfeedbackok += pstx_status->txok;
301 priv->stats.txoktotal += pstx_status->txok;
303 priv->stats.txbytesunicast += pstx_status->txuclength;
309 * Firmware add a new tx feedback status to reduce rx command
310 * packet buffer operation load.
313 cmpk_handle_tx_status(
314 struct net_device *dev,
317 cmpk_tx_status_t rx_tx_sts; /* */
319 memcpy((void*)&rx_tx_sts, (void*)pmsg, sizeof(cmpk_tx_status_t));
320 /* 2. Use tx feedback info to count TX statistics. */
321 cmpk_count_tx_status(dev, &rx_tx_sts);
326 /* Firmware add a new tx rate history */
328 cmpk_handle_tx_rate_history(
329 struct net_device *dev,
333 u16 length = sizeof(cmpk_tx_rahis_t);
337 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
339 // When RF is off, we should not count the packet for hw/sw synchronize
340 // reason, ie. there may be a duration while sw switch is changed and hw
341 // switch is being changed. 2006.12.04, by shien chang.
342 if (rtState == eRfOff)
351 // Do endian transfer to word alignment(16 bits) for windows system.
352 // You must do different endian transfer for linux and MAC OS
354 for (i = 0; i < (length/4); i++)
358 temp1 = ptemp[i]&0x0000FFFF;
359 temp2 = ptemp[i]>>16;
360 ptemp[i] = (temp1<<16)|temp2;
366 * In the function, we will capture different RX command packet
367 * info. Every RX command packet element has different message
368 * length and meaning in content. We only support three type of RX
369 * command packet now. Please refer to document
370 * ws-06-0063-rtl8190-command-packet-specification.
372 u32 cmpk_message_handle_rx(struct net_device *dev, struct ieee80211_rx_stats *pstats)
374 // u32 debug_level = DBG_LOUD;
376 u8 cmd_length, exe_cnt = 0;
380 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx()\n");
382 /* 0. Check inpt arguments. If is is a command queue message or pointer is
384 if (/*(prfd->queue_id != CMPK_RX_QUEUE_ID) || */(pstats== NULL))
386 /* Print error message. */
387 /*RT_TRACE(COMP_SEND, DebugLevel,
388 ("\n\r[CMPK]-->Err queue id or pointer"));*/
389 return 0; /* This is not a command packet. */
392 /* 1. Read received command packet message length from RFD. */
393 total_length = pstats->Length;
395 /* 2. Read virtual address from RFD. */
396 pcmd_buff = pstats->virtual_address;
398 /* 3. Read command pakcet element id and length. */
399 element_id = pcmd_buff[0];
400 /*RT_TRACE(COMP_SEND, DebugLevel,
401 ("\n\r[CMPK]-->element ID=%d Len=%d", element_id, total_length));*/
403 /* 4. Check every received command packet conent according to different
404 element type. Because FW may aggregate RX command packet to minimize
405 transmit time between DRV and FW.*/
406 // Add a counter to prevent to locked in the loop too long
407 while (total_length > 0 || exe_cnt++ >100)
409 /* 2007/01/17 MH We support aggregation of different cmd in the same packet. */
410 element_id = pcmd_buff[0];
416 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_FEEDBACK\n");
417 cmpk_handle_tx_feedback (dev, pcmd_buff);
418 cmd_length = CMPK_RX_TX_FB_SIZE;
421 case RX_INTERRUPT_STATUS:
423 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_INTERRUPT_STATUS\n");
424 cmpk_handle_interrupt_status(dev, pcmd_buff);
425 cmd_length = sizeof(cmpk_intr_sta_t);
428 case BOTH_QUERY_CONFIG:
430 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():BOTH_QUERY_CONFIG\n");
431 cmpk_handle_query_config_rx(dev, pcmd_buff);
432 cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
437 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_STATUS\n");
438 cmpk_handle_tx_status(dev, pcmd_buff);
439 cmd_length = CMPK_RX_TX_STS_SIZE;
442 case RX_TX_PER_PKT_FEEDBACK:
443 // You must at lease add a switch case element here,
444 // Otherwise, we will jump to default case.
445 //DbgPrint("CCX Test\r\n");
446 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_PER_PKT_FEEDBACK\n");
447 cmd_length = CMPK_RX_TX_FB_SIZE;
450 case RX_TX_RATE_HISTORY:
451 //DbgPrint(" rx tx rate history\r\n");
453 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_HISTORY\n");
454 cmpk_handle_tx_rate_history(dev, pcmd_buff);
455 cmd_length = CMPK_TX_RAHIS_SIZE;
460 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():unknown CMD Element\n");
461 return 1; /* This is a command packet. */
464 total_length -= cmd_length;
465 pcmd_buff += cmd_length;
466 } /* while (total_length > 0) */
467 return 1; /* This is a command packet. */
469 RT_TRACE(COMP_EVENTS, "<----cmpk_message_handle_rx()\n");