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 //spin_lock_irqsave(&priv->tx_lock,flags);
56 RT_TRACE(COMP_CMDPKT,"%s(),buffer_len is %d\n",__FUNCTION__,buffer_len);
57 firmware_init_param(dev);
58 //Fragmentation might be required
59 frag_threshold = pfirmware->cmdpacket_frag_thresold;
61 if((buffer_len - frag_offset) > frag_threshold) {
62 frag_length = frag_threshold ;
66 frag_length =(u16)(buffer_len - frag_offset);
71 /* Allocate skb buffer to contain firmware info and tx descriptor info
72 * add 4 to avoid packet appending overflow.
74 skb = dev_alloc_skb(frag_length + priv->ieee80211->tx_headroom + 4);
76 rt_status = RT_STATUS_FAILURE;
80 memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
81 tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE);
82 tcb_desc->queue_index = TXCMD_QUEUE;
83 tcb_desc->bCmdOrInit = packettype;
84 tcb_desc->bLastIniPkt = bLastIniPkt;
85 tcb_desc->pkt_size = frag_length;
87 //seg_ptr = skb_put(skb, frag_length + priv->ieee80211->tx_headroom);
88 seg_ptr = skb_put(skb, priv->ieee80211->tx_headroom);
90 pTxFwInfo = (PTX_FWINFO_8190PCI)seg_ptr;
91 memset(pTxFwInfo,0,sizeof(TX_FWINFO_8190PCI));
92 memset(pTxFwInfo,0x12,8);
94 seg_ptr +=sizeof(TX_FWINFO_8190PCI);
97 * Transform from little endian to big endian
100 seg_ptr = skb_tail_pointer(skb);
101 for(i=0 ; i < frag_length; i+=4) {
102 *seg_ptr++ = ((i+0)<frag_length)?code_virtual_address[i+3]:0;
103 *seg_ptr++ = ((i+1)<frag_length)?code_virtual_address[i+2]:0;
104 *seg_ptr++ = ((i+2)<frag_length)?code_virtual_address[i+1]:0;
105 *seg_ptr++ = ((i+3)<frag_length)?code_virtual_address[i+0]:0;
108 priv->ieee80211->softmac_hard_start_xmit(skb,dev);
110 code_virtual_address += frag_length;
111 frag_offset += frag_length;
113 }while(frag_offset < buffer_len);
116 //spin_unlock_irqrestore(&priv->tx_lock,flags);
121 cmpk_count_txstatistic(
122 struct net_device *dev,
123 cmpk_txfb_t *pstx_fb)
125 struct r8192_priv *priv = ieee80211_priv(dev);
127 RT_RF_POWER_STATE rtState;
129 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
131 // When RF is off, we should not count the packet for hw/sw synchronize
132 // reason, ie. there may be a duration while sw switch is changed and hw
133 // switch is being changed. 2006.12.04, by shien chang.
134 if (rtState == eRfOff)
141 if(pAdapter->bInHctTest)
144 /* We can not know the packet length and transmit type: broadcast or uni
145 or multicast. So the relative statistics must be collected in tx
149 priv->stats.txoktotal++;
151 /* We can not make sure broadcast/multicast or unicast mode. */
152 if (pstx_fb->pkt_type != PACKET_MULTICAST &&
153 pstx_fb->pkt_type != PACKET_BROADCAST) {
154 priv->stats.txbytesunicast += pstx_fb->pkt_length;
162 * The function is responsible for extract the message inside TX
163 * feedbck message from firmware. It will contain dedicated info in
164 * ws-06-0063-rtl8190-command-packet-specification. Please
165 * refer to chapter "TX Feedback Element". We have to read 20 bytes
166 * in the command packet.
169 cmpk_handle_tx_feedback(
170 struct net_device *dev,
173 struct r8192_priv *priv = ieee80211_priv(dev);
174 cmpk_txfb_t rx_tx_fb; /* */
176 priv->stats.txfeedback++;
178 memcpy((u8*)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
179 /* Use tx feedback info to count TX statistics. */
180 cmpk_count_txstatistic(dev, &rx_tx_fb);
185 * The function is responsible for extract the message from
186 * firmware. It will contain dedicated info in
187 * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
188 * Please refer to chapter "Interrupt Status Element".
191 cmpk_handle_interrupt_status(
192 struct net_device *dev,
195 cmpk_intr_sta_t rx_intr_status; /* */
196 struct r8192_priv *priv = ieee80211_priv(dev);
198 DMESG("---> cmpk_Handle_Interrupt_Status()\n");
200 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
201 /* It seems that FW use big endian(MIPS) and DRV use little endian in
202 windows OS. So we have to read the content byte by byte or transfer
203 endian type before copy the message copy. */
204 //rx_bcn_state.Element_ID = pMsg[0];
205 //rx_bcn_state.Length = pMsg[1];
206 rx_intr_status.length = pmsg[1];
207 if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2))
209 DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
214 // Statistics of beacon for ad-hoc mode.
215 if( priv->ieee80211->iw_mode == IW_MODE_ADHOC)
217 //2 maybe need endian transform?
218 rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
219 //rx_intr_status.InterruptStatus = N2H4BYTE(*((UINT32 *)(pMsg + 4)));
221 DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status);
223 if (rx_intr_status.interrupt_status & ISR_TxBcnOk)
225 priv->ieee80211->bibsscoordinator = true;
226 priv->stats.txbeaconokint++;
228 else if (rx_intr_status.interrupt_status & ISR_TxBcnErr)
230 priv->ieee80211->bibsscoordinator = false;
231 priv->stats.txbeaconerr++;
235 // Other informations in interrupt status we need?
238 DMESG("<---- cmpk_handle_interrupt_status()\n");
244 * The function is responsible for extract the message from
245 * firmware. It will contain dedicated info in
246 * ws-06-0063-rtl8190-command-packet-specification. Please
247 * refer to chapter "Beacon State Element".
250 cmpk_handle_query_config_rx(
251 struct net_device *dev,
254 cmpk_query_cfg_t rx_query_cfg; /* */
256 /* 0. Display received message. */
257 //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
259 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
260 /* It seems that FW use big endian(MIPS) and DRV use little endian in
261 windows OS. So we have to read the content byte by byte or transfer
262 endian type before copy the message copy. */
263 //rx_query_cfg.Element_ID = pMsg[0];
264 //rx_query_cfg.Length = pMsg[1];
265 rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000)>>31;
266 rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5;
267 rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3;
268 rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0;
269 rx_query_cfg.cfg_offset = pmsg[7];
270 rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) |
271 (pmsg[10] << 8) | (pmsg[11] << 0);
272 rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) |
273 (pmsg[14] << 8) | (pmsg[15] << 0);
279 * Count aggregated tx status from firmwar of one type rx command
280 * packet element id = RX_TX_STATUS.
282 static void cmpk_count_tx_status( struct net_device *dev,
283 cmpk_tx_status_t *pstx_status)
285 struct r8192_priv *priv = ieee80211_priv(dev);
289 RT_RF_POWER_STATE rtstate;
291 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
293 // When RF is off, we should not count the packet for hw/sw synchronize
294 // reason, ie. there may be a duration while sw switch is changed and hw
295 // switch is being changed. 2006.12.04, by shien chang.
296 if (rtState == eRfOff)
302 priv->stats.txfeedbackok += pstx_status->txok;
303 priv->stats.txoktotal += pstx_status->txok;
305 priv->stats.txbytesunicast += pstx_status->txuclength;
311 * Firmware add a new tx feedback status to reduce rx command
312 * packet buffer operation load.
315 cmpk_handle_tx_status(
316 struct net_device *dev,
319 cmpk_tx_status_t rx_tx_sts; /* */
321 memcpy((void*)&rx_tx_sts, (void*)pmsg, sizeof(cmpk_tx_status_t));
322 /* 2. Use tx feedback info to count TX statistics. */
323 cmpk_count_tx_status(dev, &rx_tx_sts);
328 /* Firmware add a new tx rate history */
330 cmpk_handle_tx_rate_history(
331 struct net_device *dev,
335 u16 length = sizeof(cmpk_tx_rahis_t);
339 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
341 // When RF is off, we should not count the packet for hw/sw synchronize
342 // reason, ie. there may be a duration while sw switch is changed and hw
343 // switch is being changed. 2006.12.04, by shien chang.
344 if (rtState == eRfOff)
353 // Do endian transfer to word alignment(16 bits) for windows system.
354 // You must do different endian transfer for linux and MAC OS
356 for (i = 0; i < (length/4); i++)
360 temp1 = ptemp[i]&0x0000FFFF;
361 temp2 = ptemp[i]>>16;
362 ptemp[i] = (temp1<<16)|temp2;
368 * In the function, we will capture different RX command packet
369 * info. Every RX command packet element has different message
370 * length and meaning in content. We only support three type of RX
371 * command packet now. Please refer to document
372 * ws-06-0063-rtl8190-command-packet-specification.
374 u32 cmpk_message_handle_rx(struct net_device *dev, struct ieee80211_rx_stats *pstats)
376 // u32 debug_level = DBG_LOUD;
378 u8 cmd_length, exe_cnt = 0;
382 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx()\n");
384 /* 0. Check inpt arguments. If is is a command queue message or pointer is
386 if (/*(prfd->queue_id != CMPK_RX_QUEUE_ID) || */(pstats== NULL))
388 /* Print error message. */
389 /*RT_TRACE(COMP_SEND, DebugLevel,
390 ("\n\r[CMPK]-->Err queue id or pointer"));*/
391 return 0; /* This is not a command packet. */
394 /* 1. Read received command packet message length from RFD. */
395 total_length = pstats->Length;
397 /* 2. Read virtual address from RFD. */
398 pcmd_buff = pstats->virtual_address;
400 /* 3. Read command pakcet element id and length. */
401 element_id = pcmd_buff[0];
402 /*RT_TRACE(COMP_SEND, DebugLevel,
403 ("\n\r[CMPK]-->element ID=%d Len=%d", element_id, total_length));*/
405 /* 4. Check every received command packet conent according to different
406 element type. Because FW may aggregate RX command packet to minimize
407 transmit time between DRV and FW.*/
408 // Add a counter to prevent to locked in the loop too long
409 while (total_length > 0 || exe_cnt++ >100)
411 /* 2007/01/17 MH We support aggregation of different cmd in the same packet. */
412 element_id = pcmd_buff[0];
418 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_FEEDBACK\n");
419 cmpk_handle_tx_feedback (dev, pcmd_buff);
420 cmd_length = CMPK_RX_TX_FB_SIZE;
423 case RX_INTERRUPT_STATUS:
425 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_INTERRUPT_STATUS\n");
426 cmpk_handle_interrupt_status(dev, pcmd_buff);
427 cmd_length = sizeof(cmpk_intr_sta_t);
430 case BOTH_QUERY_CONFIG:
432 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():BOTH_QUERY_CONFIG\n");
433 cmpk_handle_query_config_rx(dev, pcmd_buff);
434 cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
439 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_STATUS\n");
440 cmpk_handle_tx_status(dev, pcmd_buff);
441 cmd_length = CMPK_RX_TX_STS_SIZE;
444 case RX_TX_PER_PKT_FEEDBACK:
445 // You must at lease add a switch case element here,
446 // Otherwise, we will jump to default case.
447 //DbgPrint("CCX Test\r\n");
448 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_PER_PKT_FEEDBACK\n");
449 cmd_length = CMPK_RX_TX_FB_SIZE;
452 case RX_TX_RATE_HISTORY:
453 //DbgPrint(" rx tx rate history\r\n");
455 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_HISTORY\n");
456 cmpk_handle_tx_rate_history(dev, pcmd_buff);
457 cmd_length = CMPK_TX_RAHIS_SIZE;
462 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():unknown CMD Element\n");
463 return 1; /* This is a command packet. */
466 total_length -= cmd_length;
467 pcmd_buff += cmd_length;
468 } /* while (total_length > 0) */
469 return 1; /* This is a command packet. */
471 RT_TRACE(COMP_EVENTS, "<----cmpk_message_handle_rx()\n");