blob: 756e0660bbe54b3526d6786d7a28a89d2b17944f [file] [log] [blame]
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -07001/******************************************************************************
2
3 (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
4
5 Module: r819xusb_cmdpkt.c (RTL8190 TX/RX command packet handler Source C File)
6
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
10 command packet.
11
12 Function:
13
14 Export:
15
16 Abbrev:
17
18 History:
19 Data Who Remark
20
21 05/06/2008 amy Create initial version porting from windows driver.
22
23******************************************************************************/
24#include "r8192E.h"
25#include "r8192E_hw.h"
26#include "r819xE_cmdpkt.h"
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070027
Mike McCormack533d1ff2010-09-08 22:05:21 +090028/*
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.
34 */
Greg Kroah-Hartman5e1ad182009-08-10 16:34:22 -070035RT_STATUS cmpk_message_handle_tx(
Mike McCormack83970d92011-03-10 22:40:53 +090036 struct r8192_priv *priv,
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070037 u8* code_virtual_address,
38 u32 packettype,
39 u32 buffer_len)
40{
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070041 RT_STATUS rt_status = RT_STATUS_SUCCESS;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070042 u16 frag_threshold;
43 u16 frag_length = 0, frag_offset = 0;
44 rt_firmware *pfirmware = priv->pFirmware;
45 struct sk_buff *skb;
46 unsigned char *seg_ptr;
47 cb_desc *tcb_desc;
48 u8 bLastIniPkt;
49
50 PTX_FWINFO_8190PCI pTxFwInfo = NULL;
51 int i;
52
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070053 RT_TRACE(COMP_CMDPKT,"%s(),buffer_len is %d\n",__FUNCTION__,buffer_len);
Mike McCormackef8efe52011-03-10 22:40:36 +090054 firmware_init_param(priv);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070055 //Fragmentation might be required
56 frag_threshold = pfirmware->cmdpacket_frag_thresold;
57 do {
58 if((buffer_len - frag_offset) > frag_threshold) {
59 frag_length = frag_threshold ;
60 bLastIniPkt = 0;
61
62 } else {
63 frag_length =(u16)(buffer_len - frag_offset);
64 bLastIniPkt = 1;
65
66 }
67
68 /* Allocate skb buffer to contain firmware info and tx descriptor info
69 * add 4 to avoid packet appending overflow.
70 * */
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070071 skb = dev_alloc_skb(frag_length + priv->ieee80211->tx_headroom + 4);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070072 if(skb == NULL) {
73 rt_status = RT_STATUS_FAILURE;
74 goto Failed;
75 }
76
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070077 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;
82
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070083 //seg_ptr = skb_put(skb, frag_length + priv->ieee80211->tx_headroom);
84 seg_ptr = skb_put(skb, priv->ieee80211->tx_headroom);
85
86 pTxFwInfo = (PTX_FWINFO_8190PCI)seg_ptr;
87 memset(pTxFwInfo,0,sizeof(TX_FWINFO_8190PCI));
88 memset(pTxFwInfo,0x12,8);
89
90 seg_ptr +=sizeof(TX_FWINFO_8190PCI);
91
92 /*
93 * Transform from little endian to big endian
94 * and pending zero
95 */
Jeff Mahoney1c7ec2e2010-01-11 10:54:27 -050096 seg_ptr = skb_tail_pointer(skb);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -070097 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;
102 }
103 skb_put(skb, i);
Mike McCormack09145962011-03-10 22:33:36 +0900104 priv->ieee80211->softmac_hard_start_xmit(skb, priv->ieee80211);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700105
106 code_virtual_address += frag_length;
107 frag_offset += frag_length;
108
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700109 }while(frag_offset < buffer_len);
110
111Failed:
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700112 return rt_status;
Mike McCormackd5abdf72010-09-08 22:03:59 +0900113}
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700114
Mike McCormack83970d92011-03-10 22:40:53 +0900115static void cmpk_count_txstatistic(struct r8192_priv *priv, cmpk_txfb_t *pstx_fb)
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700116{
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700117#ifdef ENABLE_PS
118 RT_RF_POWER_STATE rtState;
119
120 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
121
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)
126 {
127 return;
128 }
129#endif
130
131#ifdef TODO
132 if(pAdapter->bInHctTest)
133 return;
134#endif
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
137 feedback info. */
138 if (pstx_fb->tok)
139 {
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700140 priv->stats.txoktotal++;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700141
142 /* We can not make sure broadcast/multicast or unicast mode. */
Mike McCormack8cbe7ae2011-01-24 23:22:21 +0900143 if (pstx_fb->pkt_type != PACKET_MULTICAST &&
144 pstx_fb->pkt_type != PACKET_BROADCAST) {
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700145 priv->stats.txbytesunicast += pstx_fb->pkt_length;
146 }
147 }
Mike McCormackd5abdf72010-09-08 22:03:59 +0900148}
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700149
150
151
Mike McCormack533d1ff2010-09-08 22:05:21 +0900152/*
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.
158 */
Mike McCormack83970d92011-03-10 22:40:53 +0900159static void cmpk_handle_tx_feedback(struct r8192_priv *priv, u8 *pmsg)
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700160{
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700161 cmpk_txfb_t rx_tx_fb; /* */
162
163 priv->stats.txfeedback++;
164
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700165 memcpy((u8*)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
Mike McCormack679b5f62011-02-06 22:53:45 +0900166 /* Use tx feedback info to count TX statistics. */
Mike McCormack83970d92011-03-10 22:40:53 +0900167 cmpk_count_txstatistic(priv, &rx_tx_fb);
Mike McCormackd5abdf72010-09-08 22:03:59 +0900168}
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700169
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700170
Mike McCormack533d1ff2010-09-08 22:05:21 +0900171/*
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".
176 */
Mike McCormack83970d92011-03-10 22:40:53 +0900177static void cmpk_handle_interrupt_status(struct r8192_priv *priv, u8 *pmsg)
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700178{
179 cmpk_intr_sta_t rx_intr_status; /* */
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700180
181 DMESG("---> cmpk_Handle_Interrupt_Status()\n");
182
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700183 /* 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))
191 {
192 DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
193 return;
194 }
195
196
197 // Statistics of beacon for ad-hoc mode.
198 if( priv->ieee80211->iw_mode == IW_MODE_ADHOC)
199 {
200 //2 maybe need endian transform?
201 rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
202 //rx_intr_status.InterruptStatus = N2H4BYTE(*((UINT32 *)(pMsg + 4)));
203
204 DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status);
205
206 if (rx_intr_status.interrupt_status & ISR_TxBcnOk)
207 {
208 priv->ieee80211->bibsscoordinator = true;
209 priv->stats.txbeaconokint++;
210 }
211 else if (rx_intr_status.interrupt_status & ISR_TxBcnErr)
212 {
213 priv->ieee80211->bibsscoordinator = false;
214 priv->stats.txbeaconerr++;
215 }
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700216 }
217
218 // Other informations in interrupt status we need?
219
220
221 DMESG("<---- cmpk_handle_interrupt_status()\n");
222
Mike McCormackd5abdf72010-09-08 22:03:59 +0900223}
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700224
225
Mike McCormack533d1ff2010-09-08 22:05:21 +0900226/*
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".
231 */
Mike McCormack83970d92011-03-10 22:40:53 +0900232static void cmpk_handle_query_config_rx(struct r8192_priv *priv, u8 *pmsg)
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700233{
234 cmpk_query_cfg_t rx_query_cfg; /* */
235
236 /* 0. Display received message. */
237 //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
238
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);
254
Mike McCormackd5abdf72010-09-08 22:03:59 +0900255}
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700256
257
Mike McCormack533d1ff2010-09-08 22:05:21 +0900258/*
259 * Count aggregated tx status from firmwar of one type rx command
260 * packet element id = RX_TX_STATUS.
261 */
Mike McCormack83970d92011-03-10 22:40:53 +0900262static void cmpk_count_tx_status(struct r8192_priv *priv, cmpk_tx_status_t *pstx_status)
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700263{
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700264
265#ifdef ENABLE_PS
266
267 RT_RF_POWER_STATE rtstate;
268
269 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
270
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)
275 {
276 return;
277 }
278#endif
279
280 priv->stats.txfeedbackok += pstx_status->txok;
281 priv->stats.txoktotal += pstx_status->txok;
282
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700283 priv->stats.txbytesunicast += pstx_status->txuclength;
Mike McCormackd5abdf72010-09-08 22:03:59 +0900284}
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700285
286
287
Mike McCormack533d1ff2010-09-08 22:05:21 +0900288/*
289 * Firmware add a new tx feedback status to reduce rx command
290 * packet buffer operation load.
291 */
Mike McCormack83970d92011-03-10 22:40:53 +0900292static void cmpk_handle_tx_status(struct r8192_priv *priv, u8 *pmsg)
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700293{
294 cmpk_tx_status_t rx_tx_sts; /* */
295
296 memcpy((void*)&rx_tx_sts, (void*)pmsg, sizeof(cmpk_tx_status_t));
297 /* 2. Use tx feedback info to count TX statistics. */
Mike McCormack83970d92011-03-10 22:40:53 +0900298 cmpk_count_tx_status(priv, &rx_tx_sts);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700299
Mike McCormackd5abdf72010-09-08 22:03:59 +0900300}
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700301
302
Mike McCormack533d1ff2010-09-08 22:05:21 +0900303/* Firmware add a new tx rate history */
Mike McCormack83970d92011-03-10 22:40:53 +0900304static void cmpk_handle_tx_rate_history(struct r8192_priv *priv, u8 *pmsg)
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700305{
Mike McCormack8cbe7ae2011-01-24 23:22:21 +0900306 u8 i;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700307 u16 length = sizeof(cmpk_tx_rahis_t);
308 u32 *ptemp;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700309
310#ifdef ENABLE_PS
311 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
312
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)
317 {
318 return;
319 }
320#endif
321
322 ptemp = (u32 *)pmsg;
323
324 //
325 // Do endian transfer to word alignment(16 bits) for windows system.
326 // You must do different endian transfer for linux and MAC OS
327 //
328 for (i = 0; i < (length/4); i++)
329 {
330 u16 temp1, temp2;
331
332 temp1 = ptemp[i]&0x0000FFFF;
333 temp2 = ptemp[i]>>16;
334 ptemp[i] = (temp1<<16)|temp2;
335 }
Mike McCormackd5abdf72010-09-08 22:03:59 +0900336}
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700337
338
Mike McCormack533d1ff2010-09-08 22:05:21 +0900339/*
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.
345 */
Mike McCormack83970d92011-03-10 22:40:53 +0900346u32 cmpk_message_handle_rx(struct r8192_priv *priv, struct ieee80211_rx_stats *pstats)
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700347{
348// u32 debug_level = DBG_LOUD;
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700349 int total_length;
350 u8 cmd_length, exe_cnt = 0;
351 u8 element_id;
352 u8 *pcmd_buff;
353
354 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx()\n");
355
356 /* 0. Check inpt arguments. If is is a command queue message or pointer is
357 null. */
358 if (/*(prfd->queue_id != CMPK_RX_QUEUE_ID) || */(pstats== NULL))
359 {
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. */
364 }
365
366 /* 1. Read received command packet message length from RFD. */
367 total_length = pstats->Length;
368
369 /* 2. Read virtual address from RFD. */
370 pcmd_buff = pstats->virtual_address;
371
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));*/
376
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)
382 {
383 /* 2007/01/17 MH We support aggregation of different cmd in the same packet. */
384 element_id = pcmd_buff[0];
385
386 switch(element_id)
387 {
388 case RX_TX_FEEDBACK:
389
390 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_FEEDBACK\n");
Mike McCormack83970d92011-03-10 22:40:53 +0900391 cmpk_handle_tx_feedback(priv, pcmd_buff);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700392 cmd_length = CMPK_RX_TX_FB_SIZE;
393 break;
394
395 case RX_INTERRUPT_STATUS:
396
397 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_INTERRUPT_STATUS\n");
Mike McCormack83970d92011-03-10 22:40:53 +0900398 cmpk_handle_interrupt_status(priv, pcmd_buff);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700399 cmd_length = sizeof(cmpk_intr_sta_t);
400 break;
401
402 case BOTH_QUERY_CONFIG:
403
404 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():BOTH_QUERY_CONFIG\n");
Mike McCormack83970d92011-03-10 22:40:53 +0900405 cmpk_handle_query_config_rx(priv, pcmd_buff);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700406 cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
407 break;
408
409 case RX_TX_STATUS:
410
411 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_STATUS\n");
Mike McCormack83970d92011-03-10 22:40:53 +0900412 cmpk_handle_tx_status(priv, pcmd_buff);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700413 cmd_length = CMPK_RX_TX_STS_SIZE;
414 break;
415
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;
422 break;
423
424 case RX_TX_RATE_HISTORY:
425 //DbgPrint(" rx tx rate history\r\n");
426
427 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_HISTORY\n");
Mike McCormack83970d92011-03-10 22:40:53 +0900428 cmpk_handle_tx_rate_history(priv, pcmd_buff);
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700429 cmd_length = CMPK_TX_RAHIS_SIZE;
430 break;
431
432 default:
433
André Goddard Rosabbc9a992009-11-14 13:09:06 -0200434 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():unknown CMD Element\n");
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700435 return 1; /* This is a command packet. */
436 }
Greg Kroah-Hartmanecdfa442009-08-04 15:57:55 -0700437
438 total_length -= cmd_length;
439 pcmd_buff += cmd_length;
440 } /* while (total_length > 0) */
441 return 1; /* This is a command packet. */
442
443 RT_TRACE(COMP_EVENTS, "<----cmpk_message_handle_rx()\n");
Mike McCormackd5abdf72010-09-08 22:03:59 +0900444}