1 /******************************************************************************
3 * (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
5 * Module: r819xusb_cmdpkt.c
6 * (RTL8190 TX/RX command packet handler Source C File)
8 * Note: The module is responsible for handling TX and RX command packet.
9 * 1. TX : Send set and query configuration command packet.
10 * 2. RX : Receive tx feedback, beacon state, query configuration
22 * 05/06/2008 amy Create initial version porting from
25 ******************************************************************************/
27 #include "r819xU_cmdpkt.h"
29 rt_status
SendTxCommandPacket(struct net_device
*dev
, void *pData
, u32 DataLen
)
31 struct r8192_priv
*priv
= ieee80211_priv(dev
);
33 struct cb_desc
*tcb_desc
;
34 unsigned char *ptr_buf
;
36 /* Get TCB and local buffer from common pool.
37 * (It is shared by CmdQ, MgntQ, and USB coalesce DataQ)
39 skb
= dev_alloc_skb(USB_HWDESC_HEADER_LEN
+ DataLen
+ 4);
41 return RT_STATUS_FAILURE
;
42 memcpy((unsigned char *)(skb
->cb
), &dev
, sizeof(dev
));
43 tcb_desc
= (struct cb_desc
*)(skb
->cb
+ MAX_DEV_ADDR_SIZE
);
44 tcb_desc
->queue_index
= TXCMD_QUEUE
;
45 tcb_desc
->bCmdOrInit
= DESC_PACKET_TYPE_NORMAL
;
46 tcb_desc
->bLastIniPkt
= 0;
47 skb_reserve(skb
, USB_HWDESC_HEADER_LEN
);
48 ptr_buf
= skb_put_data(skb
, pData
, DataLen
);
49 tcb_desc
->txbuf_size
= (u16
)DataLen
;
51 if (!priv
->ieee80211
->check_nic_enough_desc(dev
, tcb_desc
->queue_index
) ||
52 (!skb_queue_empty(&priv
->ieee80211
->skb_waitQ
[tcb_desc
->queue_index
])) ||
53 (priv
->ieee80211
->queue_stop
)) {
54 RT_TRACE(COMP_FIRMWARE
, "=== NULL packet ======> tx full!\n");
55 skb_queue_tail(&priv
->ieee80211
->skb_waitQ
[tcb_desc
->queue_index
], skb
);
57 priv
->ieee80211
->softmac_hard_start_xmit(skb
, dev
);
60 return RT_STATUS_SUCCESS
;
63 /*-----------------------------------------------------------------------------
64 * Function: cmpk_counttxstatistic()
68 * Input: PADAPTER pAdapter
69 * CMPK_TXFB_T *psTx_FB
77 * 05/12/2008 amy Create Version 0 porting from windows code.
79 *---------------------------------------------------------------------------
81 static void cmpk_count_txstatistic(struct net_device
*dev
, cmpk_txfb_t
*pstx_fb
)
83 struct r8192_priv
*priv
= ieee80211_priv(dev
);
85 RT_RF_POWER_STATE rtState
;
87 pAdapter
->HalFunc
.GetHwRegHandler(pAdapter
, HW_VAR_RF_STATE
,
90 /* When RF is off, we should not count the packet for hw/sw synchronize
91 * reason, ie. there may be a duration while sw switch is changed and
92 * hw switch is being changed.
94 if (rtState
== eRfOff
)
99 if (pAdapter
->bInHctTest
)
102 /* We can not know the packet length and transmit type:
103 * broadcast or uni or multicast. So the relative statistics
104 * must be collected in tx feedback info.
107 priv
->stats
.txfeedbackok
++;
108 priv
->stats
.txoktotal
++;
109 priv
->stats
.txokbytestotal
+= pstx_fb
->pkt_length
;
110 priv
->stats
.txokinperiod
++;
112 /* We can not make sure broadcast/multicast or unicast mode. */
113 if (pstx_fb
->pkt_type
== PACKET_MULTICAST
) {
114 priv
->stats
.txmulticast
++;
115 priv
->stats
.txbytesmulticast
+= pstx_fb
->pkt_length
;
116 } else if (pstx_fb
->pkt_type
== PACKET_BROADCAST
) {
117 priv
->stats
.txbroadcast
++;
118 priv
->stats
.txbytesbroadcast
+= pstx_fb
->pkt_length
;
120 priv
->stats
.txunicast
++;
121 priv
->stats
.txbytesunicast
+= pstx_fb
->pkt_length
;
124 priv
->stats
.txfeedbackfail
++;
125 priv
->stats
.txerrtotal
++;
126 priv
->stats
.txerrbytestotal
+= pstx_fb
->pkt_length
;
128 /* We can not make sure broadcast/multicast or unicast mode. */
129 if (pstx_fb
->pkt_type
== PACKET_MULTICAST
)
130 priv
->stats
.txerrmulticast
++;
131 else if (pstx_fb
->pkt_type
== PACKET_BROADCAST
)
132 priv
->stats
.txerrbroadcast
++;
134 priv
->stats
.txerrunicast
++;
137 priv
->stats
.txretrycount
+= pstx_fb
->retry_cnt
;
138 priv
->stats
.txfeedbackretry
+= pstx_fb
->retry_cnt
;
141 /*-----------------------------------------------------------------------------
142 * Function: cmpk_handle_tx_feedback()
144 * Overview: The function is responsible for extract the message inside TX
145 * feedbck message from firmware. It will contain dedicated info in
146 * ws-06-0063-rtl8190-command-packet-specification.
147 * Please refer to chapter "TX Feedback Element".
148 * We have to read 20 bytes in the command packet.
150 * Input: struct net_device *dev
151 * u8 *pmsg - Msg Ptr of the command packet.
159 * 05/08/2008 amy Create Version 0 porting from windows code.
161 *---------------------------------------------------------------------------
163 static void cmpk_handle_tx_feedback(struct net_device
*dev
, u8
*pmsg
)
165 struct r8192_priv
*priv
= ieee80211_priv(dev
);
166 cmpk_txfb_t rx_tx_fb
;
168 priv
->stats
.txfeedback
++;
170 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
171 /* It seems that FW use big endian(MIPS) and DRV use little endian in
172 * windows OS. So we have to read the content byte by byte or transfer
173 * endian type before copy the message copy.
175 /* Use pointer to transfer structure memory. */
176 memcpy((u8
*)&rx_tx_fb
, pmsg
, sizeof(cmpk_txfb_t
));
177 /* 2. Use tx feedback info to count TX statistics. */
178 cmpk_count_txstatistic(dev
, &rx_tx_fb
);
179 /* Comment previous method for TX statistic function. */
180 /* Collect info TX feedback packet to fill TCB. */
181 /* We can not know the packet length and transmit type: broadcast or uni
186 static void cmdpkt_beacontimerinterrupt_819xusb(struct net_device
*dev
)
188 struct r8192_priv
*priv
= ieee80211_priv(dev
);
190 /* 87B have to S/W beacon for DTM encryption_cmn. */
191 if (priv
->ieee80211
->current_network
.mode
== IEEE_A
||
192 priv
->ieee80211
->current_network
.mode
== IEEE_N_5G
||
193 (priv
->ieee80211
->current_network
.mode
== IEEE_N_24G
&&
194 (!priv
->ieee80211
->pHTInfo
->bCurSuppCCK
))) {
196 DMESG("send beacon frame tx rate is 6Mbpm\n");
199 DMESG("send beacon frame tx rate is 1Mbpm\n");
202 rtl819xusb_beacon_tx(dev
, tx_rate
); /* HW Beacon */
205 /*-----------------------------------------------------------------------------
206 * Function: cmpk_handle_interrupt_status()
208 * Overview: The function is responsible for extract the message from
209 * firmware. It will contain dedicated info in
210 * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
211 * Please refer to chapter "Interrupt Status Element".
213 * Input: struct net_device *dev
214 * u8 *pmsg - Message Pointer of the command packet.
222 * 05/12/2008 amy Add this for rtl8192 porting from windows code.
224 *---------------------------------------------------------------------------
226 static void cmpk_handle_interrupt_status(struct net_device
*dev
, u8
*pmsg
)
228 cmpk_intr_sta_t rx_intr_status
; /* */
229 struct r8192_priv
*priv
= ieee80211_priv(dev
);
231 DMESG("---> cmpk_Handle_Interrupt_Status()\n");
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.
238 rx_intr_status
.length
= pmsg
[1];
239 if (rx_intr_status
.length
!= (sizeof(cmpk_intr_sta_t
) - 2)) {
240 DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
244 /* Statistics of beacon for ad-hoc mode. */
245 if (priv
->ieee80211
->iw_mode
== IW_MODE_ADHOC
) {
246 /* 2 maybe need endian transform? */
247 rx_intr_status
.interrupt_status
= *((u32
*)(pmsg
+ 4));
249 DMESG("interrupt status = 0x%x\n",
250 rx_intr_status
.interrupt_status
);
252 if (rx_intr_status
.interrupt_status
& ISR_TxBcnOk
) {
253 priv
->ieee80211
->bibsscoordinator
= true;
254 priv
->stats
.txbeaconokint
++;
255 } else if (rx_intr_status
.interrupt_status
& ISR_TxBcnErr
) {
256 priv
->ieee80211
->bibsscoordinator
= false;
257 priv
->stats
.txbeaconerr
++;
260 if (rx_intr_status
.interrupt_status
& ISR_BcnTimerIntr
)
261 cmdpkt_beacontimerinterrupt_819xusb(dev
);
264 /* Other informations in interrupt status we need? */
266 DMESG("<---- cmpk_handle_interrupt_status()\n");
269 /*-----------------------------------------------------------------------------
270 * Function: cmpk_handle_query_config_rx()
272 * Overview: The function is responsible for extract the message from
273 * firmware. It will contain dedicated info in
274 * ws-06-0063-rtl8190-command-packet-specification. Please
275 * refer to chapter "Beacon State Element".
277 * Input: u8 *pmsg - Message Pointer of the command packet.
285 * 05/12/2008 amy Create Version 0 porting from windows code.
287 *---------------------------------------------------------------------------
289 static void cmpk_handle_query_config_rx(struct net_device
*dev
, u8
*pmsg
)
291 cmpk_query_cfg_t rx_query_cfg
;
293 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
294 /* It seems that FW use big endian(MIPS) and DRV use little endian in
295 * windows OS. So we have to read the content byte by byte or transfer
296 * endian type before copy the message copy.
298 rx_query_cfg
.cfg_action
= (pmsg
[4] & 0x80000000) >> 31;
299 rx_query_cfg
.cfg_type
= (pmsg
[4] & 0x60) >> 5;
300 rx_query_cfg
.cfg_size
= (pmsg
[4] & 0x18) >> 3;
301 rx_query_cfg
.cfg_page
= (pmsg
[6] & 0x0F) >> 0;
302 rx_query_cfg
.cfg_offset
= pmsg
[7];
303 rx_query_cfg
.value
= (pmsg
[8] << 24) | (pmsg
[9] << 16) |
304 (pmsg
[10] << 8) | (pmsg
[11] << 0);
305 rx_query_cfg
.mask
= (pmsg
[12] << 24) | (pmsg
[13] << 16) |
306 (pmsg
[14] << 8) | (pmsg
[15] << 0);
309 /*-----------------------------------------------------------------------------
310 * Function: cmpk_count_tx_status()
312 * Overview: Count aggregated tx status from firmwar of one type rx command
313 * packet element id = RX_TX_STATUS.
323 * 05/12/2008 amy Create Version 0 porting from windows code.
325 *---------------------------------------------------------------------------
327 static void cmpk_count_tx_status(struct net_device
*dev
,
328 cmpk_tx_status_t
*pstx_status
)
330 struct r8192_priv
*priv
= ieee80211_priv(dev
);
334 RT_RF_POWER_STATE rtstate
;
336 pAdapter
->HalFunc
.GetHwRegHandler(pAdapter
, HW_VAR_RF_STATE
,
337 (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
341 * hw switch is being changed.
343 if (rtState
== eRfOff
)
347 priv
->stats
.txfeedbackok
+= pstx_status
->txok
;
348 priv
->stats
.txoktotal
+= pstx_status
->txok
;
350 priv
->stats
.txfeedbackfail
+= pstx_status
->txfail
;
351 priv
->stats
.txerrtotal
+= pstx_status
->txfail
;
353 priv
->stats
.txretrycount
+= pstx_status
->txretry
;
354 priv
->stats
.txfeedbackretry
+= pstx_status
->txretry
;
357 priv
->stats
.txmulticast
+= pstx_status
->txmcok
;
358 priv
->stats
.txbroadcast
+= pstx_status
->txbcok
;
359 priv
->stats
.txunicast
+= pstx_status
->txucok
;
361 priv
->stats
.txerrmulticast
+= pstx_status
->txmcfail
;
362 priv
->stats
.txerrbroadcast
+= pstx_status
->txbcfail
;
363 priv
->stats
.txerrunicast
+= pstx_status
->txucfail
;
365 priv
->stats
.txbytesmulticast
+= pstx_status
->txmclength
;
366 priv
->stats
.txbytesbroadcast
+= pstx_status
->txbclength
;
367 priv
->stats
.txbytesunicast
+= pstx_status
->txuclength
;
369 priv
->stats
.last_packet_rate
= pstx_status
->rate
;
372 /*-----------------------------------------------------------------------------
373 * Function: cmpk_handle_tx_status()
375 * Overview: Firmware add a new tx feedback status to reduce rx command
376 * packet buffer operation load.
386 * 05/12/2008 amy Create Version 0 porting from windows code.
388 *---------------------------------------------------------------------------
390 static void cmpk_handle_tx_status(struct net_device
*dev
, u8
*pmsg
)
392 cmpk_tx_status_t rx_tx_sts
;
394 memcpy((void *)&rx_tx_sts
, (void *)pmsg
, sizeof(cmpk_tx_status_t
));
395 /* 2. Use tx feedback info to count TX statistics. */
396 cmpk_count_tx_status(dev
, &rx_tx_sts
);
399 /*-----------------------------------------------------------------------------
400 * Function: cmpk_handle_tx_rate_history()
402 * Overview: Firmware add a new tx rate history
412 * 05/12/2008 amy Create Version 0 porting from windows code.
414 *---------------------------------------------------------------------------
416 static void cmpk_handle_tx_rate_history(struct net_device
*dev
, u8
*pmsg
)
418 cmpk_tx_rahis_t
*ptxrate
;
420 u16 length
= sizeof(cmpk_tx_rahis_t
);
422 struct r8192_priv
*priv
= ieee80211_priv(dev
);
425 pAdapter
->HalFunc
.GetHwRegHandler(pAdapter
, HW_VAR_RF_STATE
,
426 (pu1Byte
)(&rtState
));
428 /* When RF is off, we should not count the packet for hw/sw synchronize
429 * reason, ie. there may be a duration while sw switch is changed and
430 * hw switch is being changed.
432 if (rtState
== eRfOff
)
438 /* Do endian transfer to word alignment(16 bits) for windows system.
439 * You must do different endian transfer for linux and MAC OS
441 for (i
= 0; i
< (length
/4); i
++) {
444 temp1
= ptemp
[i
] & 0x0000FFFF;
445 temp2
= ptemp
[i
] >> 16;
446 ptemp
[i
] = (temp1
<< 16) | temp2
;
449 ptxrate
= (cmpk_tx_rahis_t
*)pmsg
;
454 for (i
= 0; i
< 16; i
++) {
455 /* Collect CCK rate packet num */
457 priv
->stats
.txrate
.cck
[i
] += ptxrate
->cck
[i
];
459 /* Collect OFDM rate packet num */
461 priv
->stats
.txrate
.ofdm
[i
] += ptxrate
->ofdm
[i
];
463 for (j
= 0; j
< 4; j
++)
464 priv
->stats
.txrate
.ht_mcs
[j
][i
] += ptxrate
->ht_mcs
[j
][i
];
468 /*-----------------------------------------------------------------------------
469 * Function: cmpk_message_handle_rx()
471 * Overview: In the function, we will capture different RX command packet
472 * info. Every RX command packet element has different message
473 * length and meaning in content. We only support three type of RX
474 * command packet now. Please refer to document
475 * ws-06-0063-rtl8190-command-packet-specification.
485 * 05/06/2008 amy Create Version 0 porting from windows code.
487 *---------------------------------------------------------------------------
489 u32
cmpk_message_handle_rx(struct net_device
*dev
,
490 struct ieee80211_rx_stats
*pstats
)
493 u8 cmd_length
, exe_cnt
= 0;
497 /* 0. Check inpt arguments. It is a command queue message or
501 return 0; /* This is not a command packet. */
503 /* 1. Read received command packet message length from RFD. */
504 total_length
= pstats
->Length
;
506 /* 2. Read virtual address from RFD. */
507 pcmd_buff
= pstats
->virtual_address
;
509 /* 3. Read command packet element id and length. */
510 element_id
= pcmd_buff
[0];
512 /* 4. Check every received command packet content according to different
513 * element type. Because FW may aggregate RX command packet to
514 * minimize transmit time between DRV and FW.
516 /* Add a counter to prevent the lock in the loop from being held too
519 while (total_length
> 0 && exe_cnt
++ < 100) {
520 /* We support aggregation of different cmd in the same packet */
521 element_id
= pcmd_buff
[0];
523 switch (element_id
) {
525 cmpk_handle_tx_feedback(dev
, pcmd_buff
);
526 cmd_length
= CMPK_RX_TX_FB_SIZE
;
529 case RX_INTERRUPT_STATUS
:
530 cmpk_handle_interrupt_status(dev
, pcmd_buff
);
531 cmd_length
= sizeof(cmpk_intr_sta_t
);
534 case BOTH_QUERY_CONFIG
:
535 cmpk_handle_query_config_rx(dev
, pcmd_buff
);
536 cmd_length
= CMPK_BOTH_QUERY_CONFIG_SIZE
;
540 cmpk_handle_tx_status(dev
, pcmd_buff
);
541 cmd_length
= CMPK_RX_TX_STS_SIZE
;
544 case RX_TX_PER_PKT_FEEDBACK
:
545 /* You must at lease add a switch case element here,
546 * Otherwise, we will jump to default case.
548 cmd_length
= CMPK_RX_TX_FB_SIZE
;
551 case RX_TX_RATE_HISTORY
:
552 cmpk_handle_tx_rate_history(dev
, pcmd_buff
);
553 cmd_length
= CMPK_TX_RAHIS_SIZE
;
558 RT_TRACE(COMP_ERR
, "---->%s():unknown CMD Element\n",
560 return 1; /* This is a command packet. */
563 total_length
-= cmd_length
;
564 pcmd_buff
+= cmd_length
;
566 return 1; /* This is a command packet. */