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 r8192_priv
*priv
,
37 u8
* code_virtual_address
,
41 RT_STATUS rt_status
= RT_STATUS_SUCCESS
;
43 u16 frag_length
= 0, frag_offset
= 0;
44 rt_firmware
*pfirmware
= priv
->pFirmware
;
46 unsigned char *seg_ptr
;
50 PTX_FWINFO_8190PCI pTxFwInfo
= NULL
;
53 RT_TRACE(COMP_CMDPKT
,"%s(),buffer_len is %d\n",__FUNCTION__
,buffer_len
);
54 firmware_init_param(priv
);
55 //Fragmentation might be required
56 frag_threshold
= pfirmware
->cmdpacket_frag_thresold
;
58 if((buffer_len
- frag_offset
) > frag_threshold
) {
59 frag_length
= frag_threshold
;
63 frag_length
=(u16
)(buffer_len
- frag_offset
);
68 /* Allocate skb buffer to contain firmware info and tx descriptor info
69 * add 4 to avoid packet appending overflow.
71 skb
= dev_alloc_skb(frag_length
+ priv
->ieee80211
->tx_headroom
+ 4);
73 rt_status
= RT_STATUS_FAILURE
;
77 tcb_desc
= (cb_desc
*)(skb
->cb
+ MAX_DEV_ADDR_SIZE
);
78 tcb_desc
->queue_index
= TXCMD_QUEUE
;
79 tcb_desc
->bCmdOrInit
= packettype
;
80 tcb_desc
->bLastIniPkt
= bLastIniPkt
;
81 tcb_desc
->pkt_size
= frag_length
;
83 //seg_ptr = skb_put(skb, frag_length + priv->ieee80211->tx_headroom);
84 seg_ptr
= skb_put(skb
, priv
->ieee80211
->tx_headroom
);
86 pTxFwInfo
= (PTX_FWINFO_8190PCI
)seg_ptr
;
87 memset(pTxFwInfo
,0,sizeof(TX_FWINFO_8190PCI
));
88 memset(pTxFwInfo
,0x12,8);
90 seg_ptr
+=sizeof(TX_FWINFO_8190PCI
);
93 * Transform from little endian to big endian
96 seg_ptr
= skb_tail_pointer(skb
);
97 for(i
=0 ; i
< frag_length
; i
+=4) {
98 *seg_ptr
++ = ((i
+0)<frag_length
)?code_virtual_address
[i
+3]:0;
99 *seg_ptr
++ = ((i
+1)<frag_length
)?code_virtual_address
[i
+2]:0;
100 *seg_ptr
++ = ((i
+2)<frag_length
)?code_virtual_address
[i
+1]:0;
101 *seg_ptr
++ = ((i
+3)<frag_length
)?code_virtual_address
[i
+0]:0;
104 priv
->ieee80211
->softmac_hard_start_xmit(skb
, priv
->ieee80211
);
106 code_virtual_address
+= frag_length
;
107 frag_offset
+= frag_length
;
109 }while(frag_offset
< buffer_len
);
115 static void cmpk_count_txstatistic(struct r8192_priv
*priv
, cmpk_txfb_t
*pstx_fb
)
118 RT_RF_POWER_STATE rtState
;
120 pAdapter
->HalFunc
.GetHwRegHandler(pAdapter
, HW_VAR_RF_STATE
, (pu1Byte
)(&rtState
));
122 // When RF is off, we should not count the packet for hw/sw synchronize
123 // reason, ie. there may be a duration while sw switch is changed and hw
124 // switch is being changed. 2006.12.04, by shien chang.
125 if (rtState
== eRfOff
)
132 if(pAdapter
->bInHctTest
)
135 /* We can not know the packet length and transmit type: broadcast or uni
136 or multicast. So the relative statistics must be collected in tx
140 priv
->stats
.txoktotal
++;
142 /* We can not make sure broadcast/multicast or unicast mode. */
143 if (pstx_fb
->pkt_type
!= PACKET_MULTICAST
&&
144 pstx_fb
->pkt_type
!= PACKET_BROADCAST
) {
145 priv
->stats
.txbytesunicast
+= pstx_fb
->pkt_length
;
153 * The function is responsible for extract the message inside TX
154 * feedbck message from firmware. It will contain dedicated info in
155 * ws-06-0063-rtl8190-command-packet-specification. Please
156 * refer to chapter "TX Feedback Element". We have to read 20 bytes
157 * in the command packet.
159 static void cmpk_handle_tx_feedback(struct r8192_priv
*priv
, u8
*pmsg
)
161 cmpk_txfb_t rx_tx_fb
; /* */
163 priv
->stats
.txfeedback
++;
165 memcpy((u8
*)&rx_tx_fb
, pmsg
, sizeof(cmpk_txfb_t
));
166 /* Use tx feedback info to count TX statistics. */
167 cmpk_count_txstatistic(priv
, &rx_tx_fb
);
172 * The function is responsible for extract the message from
173 * firmware. It will contain dedicated info in
174 * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
175 * Please refer to chapter "Interrupt Status Element".
177 static void cmpk_handle_interrupt_status(struct r8192_priv
*priv
, u8
*pmsg
)
179 cmpk_intr_sta_t rx_intr_status
; /* */
181 DMESG("---> cmpk_Handle_Interrupt_Status()\n");
183 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
184 /* It seems that FW use big endian(MIPS) and DRV use little endian in
185 windows OS. So we have to read the content byte by byte or transfer
186 endian type before copy the message copy. */
187 //rx_bcn_state.Element_ID = pMsg[0];
188 //rx_bcn_state.Length = pMsg[1];
189 rx_intr_status
.length
= pmsg
[1];
190 if (rx_intr_status
.length
!= (sizeof(cmpk_intr_sta_t
) - 2))
192 DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
197 // Statistics of beacon for ad-hoc mode.
198 if( priv
->ieee80211
->iw_mode
== IW_MODE_ADHOC
)
200 //2 maybe need endian transform?
201 rx_intr_status
.interrupt_status
= *((u32
*)(pmsg
+ 4));
202 //rx_intr_status.InterruptStatus = N2H4BYTE(*((UINT32 *)(pMsg + 4)));
204 DMESG("interrupt status = 0x%x\n", rx_intr_status
.interrupt_status
);
206 if (rx_intr_status
.interrupt_status
& ISR_TxBcnOk
)
208 priv
->ieee80211
->bibsscoordinator
= true;
209 priv
->stats
.txbeaconokint
++;
211 else if (rx_intr_status
.interrupt_status
& ISR_TxBcnErr
)
213 priv
->ieee80211
->bibsscoordinator
= false;
214 priv
->stats
.txbeaconerr
++;
218 // Other informations in interrupt status we need?
221 DMESG("<---- cmpk_handle_interrupt_status()\n");
227 * The function is responsible for extract the message from
228 * firmware. It will contain dedicated info in
229 * ws-06-0063-rtl8190-command-packet-specification. Please
230 * refer to chapter "Beacon State Element".
232 static void cmpk_handle_query_config_rx(struct r8192_priv
*priv
, u8
*pmsg
)
234 cmpk_query_cfg_t rx_query_cfg
; /* */
236 /* 0. Display received message. */
237 //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
239 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
240 /* It seems that FW use big endian(MIPS) and DRV use little endian in
241 windows OS. So we have to read the content byte by byte or transfer
242 endian type before copy the message copy. */
243 //rx_query_cfg.Element_ID = pMsg[0];
244 //rx_query_cfg.Length = pMsg[1];
245 rx_query_cfg
.cfg_action
= (pmsg
[4] & 0x80000000)>>31;
246 rx_query_cfg
.cfg_type
= (pmsg
[4] & 0x60) >> 5;
247 rx_query_cfg
.cfg_size
= (pmsg
[4] & 0x18) >> 3;
248 rx_query_cfg
.cfg_page
= (pmsg
[6] & 0x0F) >> 0;
249 rx_query_cfg
.cfg_offset
= pmsg
[7];
250 rx_query_cfg
.value
= (pmsg
[8] << 24) | (pmsg
[9] << 16) |
251 (pmsg
[10] << 8) | (pmsg
[11] << 0);
252 rx_query_cfg
.mask
= (pmsg
[12] << 24) | (pmsg
[13] << 16) |
253 (pmsg
[14] << 8) | (pmsg
[15] << 0);
259 * Count aggregated tx status from firmwar of one type rx command
260 * packet element id = RX_TX_STATUS.
262 static void cmpk_count_tx_status(struct r8192_priv
*priv
, cmpk_tx_status_t
*pstx_status
)
267 RT_RF_POWER_STATE rtstate
;
269 pAdapter
->HalFunc
.GetHwRegHandler(pAdapter
, HW_VAR_RF_STATE
, (pu1Byte
)(&rtState
));
271 // When RF is off, we should not count the packet for hw/sw synchronize
272 // reason, ie. there may be a duration while sw switch is changed and hw
273 // switch is being changed. 2006.12.04, by shien chang.
274 if (rtState
== eRfOff
)
280 priv
->stats
.txfeedbackok
+= pstx_status
->txok
;
281 priv
->stats
.txoktotal
+= pstx_status
->txok
;
283 priv
->stats
.txbytesunicast
+= pstx_status
->txuclength
;
289 * Firmware add a new tx feedback status to reduce rx command
290 * packet buffer operation load.
292 static void cmpk_handle_tx_status(struct r8192_priv
*priv
, u8
*pmsg
)
294 cmpk_tx_status_t rx_tx_sts
; /* */
296 memcpy((void*)&rx_tx_sts
, (void*)pmsg
, sizeof(cmpk_tx_status_t
));
297 /* 2. Use tx feedback info to count TX statistics. */
298 cmpk_count_tx_status(priv
, &rx_tx_sts
);
303 /* Firmware add a new tx rate history */
304 static void cmpk_handle_tx_rate_history(struct r8192_priv
*priv
, u8
*pmsg
)
307 u16 length
= sizeof(cmpk_tx_rahis_t
);
311 pAdapter
->HalFunc
.GetHwRegHandler(pAdapter
, HW_VAR_RF_STATE
, (pu1Byte
)(&rtState
));
313 // When RF is off, we should not count the packet for hw/sw synchronize
314 // reason, ie. there may be a duration while sw switch is changed and hw
315 // switch is being changed. 2006.12.04, by shien chang.
316 if (rtState
== eRfOff
)
325 // Do endian transfer to word alignment(16 bits) for windows system.
326 // You must do different endian transfer for linux and MAC OS
328 for (i
= 0; i
< (length
/4); i
++)
332 temp1
= ptemp
[i
]&0x0000FFFF;
333 temp2
= ptemp
[i
]>>16;
334 ptemp
[i
] = (temp1
<<16)|temp2
;
340 * In the function, we will capture different RX command packet
341 * info. Every RX command packet element has different message
342 * length and meaning in content. We only support three type of RX
343 * command packet now. Please refer to document
344 * ws-06-0063-rtl8190-command-packet-specification.
346 u32
cmpk_message_handle_rx(struct r8192_priv
*priv
, struct ieee80211_rx_stats
*pstats
)
348 // u32 debug_level = DBG_LOUD;
350 u8 cmd_length
, exe_cnt
= 0;
354 RT_TRACE(COMP_EVENTS
, "---->cmpk_message_handle_rx()\n");
356 /* 0. Check inpt arguments. If is is a command queue message or pointer is
358 if (/*(prfd->queue_id != CMPK_RX_QUEUE_ID) || */(pstats
== NULL
))
360 /* Print error message. */
361 /*RT_TRACE(COMP_SEND, DebugLevel,
362 ("\n\r[CMPK]-->Err queue id or pointer"));*/
363 return 0; /* This is not a command packet. */
366 /* 1. Read received command packet message length from RFD. */
367 total_length
= pstats
->Length
;
369 /* 2. Read virtual address from RFD. */
370 pcmd_buff
= pstats
->virtual_address
;
372 /* 3. Read command pakcet element id and length. */
373 element_id
= pcmd_buff
[0];
374 /*RT_TRACE(COMP_SEND, DebugLevel,
375 ("\n\r[CMPK]-->element ID=%d Len=%d", element_id, total_length));*/
377 /* 4. Check every received command packet conent according to different
378 element type. Because FW may aggregate RX command packet to minimize
379 transmit time between DRV and FW.*/
380 // Add a counter to prevent to locked in the loop too long
381 while (total_length
> 0 || exe_cnt
++ >100)
383 /* 2007/01/17 MH We support aggregation of different cmd in the same packet. */
384 element_id
= pcmd_buff
[0];
390 RT_TRACE(COMP_EVENTS
, "---->cmpk_message_handle_rx():RX_TX_FEEDBACK\n");
391 cmpk_handle_tx_feedback(priv
, pcmd_buff
);
392 cmd_length
= CMPK_RX_TX_FB_SIZE
;
395 case RX_INTERRUPT_STATUS
:
397 RT_TRACE(COMP_EVENTS
, "---->cmpk_message_handle_rx():RX_INTERRUPT_STATUS\n");
398 cmpk_handle_interrupt_status(priv
, pcmd_buff
);
399 cmd_length
= sizeof(cmpk_intr_sta_t
);
402 case BOTH_QUERY_CONFIG
:
404 RT_TRACE(COMP_EVENTS
, "---->cmpk_message_handle_rx():BOTH_QUERY_CONFIG\n");
405 cmpk_handle_query_config_rx(priv
, pcmd_buff
);
406 cmd_length
= CMPK_BOTH_QUERY_CONFIG_SIZE
;
411 RT_TRACE(COMP_EVENTS
, "---->cmpk_message_handle_rx():RX_TX_STATUS\n");
412 cmpk_handle_tx_status(priv
, pcmd_buff
);
413 cmd_length
= CMPK_RX_TX_STS_SIZE
;
416 case RX_TX_PER_PKT_FEEDBACK
:
417 // You must at lease add a switch case element here,
418 // Otherwise, we will jump to default case.
419 //DbgPrint("CCX Test\r\n");
420 RT_TRACE(COMP_EVENTS
, "---->cmpk_message_handle_rx():RX_TX_PER_PKT_FEEDBACK\n");
421 cmd_length
= CMPK_RX_TX_FB_SIZE
;
424 case RX_TX_RATE_HISTORY
:
425 //DbgPrint(" rx tx rate history\r\n");
427 RT_TRACE(COMP_EVENTS
, "---->cmpk_message_handle_rx():RX_TX_HISTORY\n");
428 cmpk_handle_tx_rate_history(priv
, pcmd_buff
);
429 cmd_length
= CMPK_TX_RAHIS_SIZE
;
434 RT_TRACE(COMP_EVENTS
, "---->cmpk_message_handle_rx():unknown CMD Element\n");
435 return 1; /* This is a command packet. */
438 total_length
-= cmd_length
;
439 pcmd_buff
+= cmd_length
;
440 } /* while (total_length > 0) */
441 return 1; /* This is a command packet. */
443 RT_TRACE(COMP_EVENTS
, "<----cmpk_message_handle_rx()\n");