Merge branch 'for-linus-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/mason...
[deliverable/linux.git] / drivers / staging / rtl8192u / r819xU_cmdpkt.c
1 /******************************************************************************
2 *
3 * (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
4 *
5 * Module: r819xusb_cmdpkt.c
6 * (RTL8190 TX/RX command packet handler Source C File)
7 *
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
11 * command packet.
12 *
13 * Function:
14 *
15 * Export:
16 *
17 * Abbrev:
18 *
19 * History:
20 *
21 * Date Who Remark
22 * 05/06/2008 amy Create initial version porting from
23 * windows driver.
24 *
25 ******************************************************************************/
26 #include "r8192U.h"
27 #include "r819xU_cmdpkt.h"
28
29 rt_status SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen)
30 {
31 struct r8192_priv *priv = ieee80211_priv(dev);
32 struct sk_buff *skb;
33 cb_desc *tcb_desc;
34 unsigned char *ptr_buf;
35
36 /* Get TCB and local buffer from common pool.
37 (It is shared by CmdQ, MgntQ, and USB coalesce DataQ) */
38 skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + DataLen + 4);
39 if (!skb)
40 return RT_STATUS_FAILURE;
41 memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
42 tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
43 tcb_desc->queue_index = TXCMD_QUEUE;
44 tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL;
45 tcb_desc->bLastIniPkt = 0;
46 skb_reserve(skb, USB_HWDESC_HEADER_LEN);
47 ptr_buf = skb_put(skb, DataLen);
48 memcpy(ptr_buf, pData, DataLen);
49 tcb_desc->txbuf_size = (u16)DataLen;
50
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);
56 } else {
57 priv->ieee80211->softmac_hard_start_xmit(skb, dev);
58 }
59
60 return RT_STATUS_SUCCESS;
61 }
62
63 /*-----------------------------------------------------------------------------
64 * Function: cmpk_counttxstatistic()
65 *
66 * Overview:
67 *
68 * Input: PADAPTER pAdapter
69 * CMPK_TXFB_T *psTx_FB
70 *
71 * Output: NONE
72 *
73 * Return: NONE
74 *
75 * Revised History:
76 * When Who Remark
77 * 05/12/2008 amy Create Version 0 porting from windows code.
78 *
79 *---------------------------------------------------------------------------*/
80 static void cmpk_count_txstatistic(struct net_device *dev, cmpk_txfb_t *pstx_fb)
81 {
82 struct r8192_priv *priv = ieee80211_priv(dev);
83 #ifdef ENABLE_PS
84 RT_RF_POWER_STATE rtState;
85
86 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
87 (pu1Byte)(&rtState));
88
89 /* When RF is off, we should not count the packet for hw/sw synchronize
90 reason, ie. there may be a duration while sw switch is changed and
91 hw switch is being changed. */
92 if (rtState == eRfOff)
93 return;
94 #endif
95
96 #ifdef TODO
97 if (pAdapter->bInHctTest)
98 return;
99 #endif
100 /* We can not know the packet length and transmit type:
101 broadcast or uni or multicast. So the relative statistics
102 must be collected in tx feedback info. */
103 if (pstx_fb->tok) {
104 priv->stats.txfeedbackok++;
105 priv->stats.txoktotal++;
106 priv->stats.txokbytestotal += pstx_fb->pkt_length;
107 priv->stats.txokinperiod++;
108
109 /* We can not make sure broadcast/multicast or unicast mode. */
110 if (pstx_fb->pkt_type == PACKET_MULTICAST) {
111 priv->stats.txmulticast++;
112 priv->stats.txbytesmulticast += pstx_fb->pkt_length;
113 } else if (pstx_fb->pkt_type == PACKET_BROADCAST) {
114 priv->stats.txbroadcast++;
115 priv->stats.txbytesbroadcast += pstx_fb->pkt_length;
116 } else {
117 priv->stats.txunicast++;
118 priv->stats.txbytesunicast += pstx_fb->pkt_length;
119 }
120 } else {
121 priv->stats.txfeedbackfail++;
122 priv->stats.txerrtotal++;
123 priv->stats.txerrbytestotal += pstx_fb->pkt_length;
124
125 /* We can not make sure broadcast/multicast or unicast mode. */
126 if (pstx_fb->pkt_type == PACKET_MULTICAST)
127 priv->stats.txerrmulticast++;
128 else if (pstx_fb->pkt_type == PACKET_BROADCAST)
129 priv->stats.txerrbroadcast++;
130 else
131 priv->stats.txerrunicast++;
132 }
133
134 priv->stats.txretrycount += pstx_fb->retry_cnt;
135 priv->stats.txfeedbackretry += pstx_fb->retry_cnt;
136
137 }
138
139
140
141 /*-----------------------------------------------------------------------------
142 * Function: cmpk_handle_tx_feedback()
143 *
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.
149 *
150 * Input: struct net_device *dev
151 * u8 *pmsg - Msg Ptr of the command packet.
152 *
153 * Output: NONE
154 *
155 * Return: NONE
156 *
157 * Revised History:
158 * When Who Remark
159 * 05/08/2008 amy Create Version 0 porting from windows code.
160 *
161 *---------------------------------------------------------------------------*/
162 static void cmpk_handle_tx_feedback(struct net_device *dev, u8 *pmsg)
163 {
164 struct r8192_priv *priv = ieee80211_priv(dev);
165 cmpk_txfb_t rx_tx_fb;
166
167 priv->stats.txfeedback++;
168
169 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
170 /* It seems that FW use big endian(MIPS) and DRV use little endian in
171 windows OS. So we have to read the content byte by byte or transfer
172 endian type before copy the message copy. */
173 /* Use pointer to transfer structure memory. */
174 memcpy((u8 *)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
175 /* 2. Use tx feedback info to count TX statistics. */
176 cmpk_count_txstatistic(dev, &rx_tx_fb);
177 /* Comment previous method for TX statistic function. */
178 /* Collect info TX feedback packet to fill TCB. */
179 /* We can not know the packet length and transmit type: broadcast or uni
180 or multicast. */
181
182 }
183
184 static void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev)
185 {
186 struct r8192_priv *priv = ieee80211_priv(dev);
187 u16 tx_rate;
188 /* 87B have to S/W beacon for DTM encryption_cmn. */
189 if (priv->ieee80211->current_network.mode == IEEE_A ||
190 priv->ieee80211->current_network.mode == IEEE_N_5G ||
191 (priv->ieee80211->current_network.mode == IEEE_N_24G &&
192 (!priv->ieee80211->pHTInfo->bCurSuppCCK))) {
193 tx_rate = 60;
194 DMESG("send beacon frame tx rate is 6Mbpm\n");
195 } else {
196 tx_rate = 10;
197 DMESG("send beacon frame tx rate is 1Mbpm\n");
198 }
199
200 rtl819xusb_beacon_tx(dev, tx_rate); /* HW Beacon */
201
202
203 }
204
205
206
207
208 /*-----------------------------------------------------------------------------
209 * Function: cmpk_handle_interrupt_status()
210 *
211 * Overview: The function is responsible for extract the message from
212 * firmware. It will contain dedicated info in
213 * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
214 * Please refer to chapter "Interrupt Status Element".
215 *
216 * Input: struct net_device *dev
217 * u8 *pmsg - Message Pointer of the command packet.
218 *
219 * Output: NONE
220 *
221 * Return: NONE
222 *
223 * Revised History:
224 * When Who Remark
225 * 05/12/2008 amy Add this for rtl8192 porting from windows code.
226 *
227 *---------------------------------------------------------------------------*/
228 static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg)
229 {
230 cmpk_intr_sta_t rx_intr_status; /* */
231 struct r8192_priv *priv = ieee80211_priv(dev);
232
233 DMESG("---> cmpk_Handle_Interrupt_Status()\n");
234
235 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
236 /* It seems that FW use big endian(MIPS) and DRV use little endian in
237 windows OS. So we have to read the content byte by byte or transfer
238 endian type before copy the message copy. */
239 rx_intr_status.length = pmsg[1];
240 if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2)) {
241 DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
242 return;
243 }
244
245
246 /* Statistics of beacon for ad-hoc mode. */
247 if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) {
248 /* 2 maybe need endian transform? */
249 rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
250
251 DMESG("interrupt status = 0x%x\n",
252 rx_intr_status.interrupt_status);
253
254 if (rx_intr_status.interrupt_status & ISR_TxBcnOk) {
255 priv->ieee80211->bibsscoordinator = true;
256 priv->stats.txbeaconokint++;
257 } else if (rx_intr_status.interrupt_status & ISR_TxBcnErr) {
258 priv->ieee80211->bibsscoordinator = false;
259 priv->stats.txbeaconerr++;
260 }
261
262 if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr)
263 cmdpkt_beacontimerinterrupt_819xusb(dev);
264
265 }
266
267 /* Other informations in interrupt status we need? */
268
269
270 DMESG("<---- cmpk_handle_interrupt_status()\n");
271
272 }
273
274
275 /*-----------------------------------------------------------------------------
276 * Function: cmpk_handle_query_config_rx()
277 *
278 * Overview: The function is responsible for extract the message from
279 * firmware. It will contain dedicated info in
280 * ws-06-0063-rtl8190-command-packet-specification. Please
281 * refer to chapter "Beacon State Element".
282 *
283 * Input: u8 *pmsg - Message Pointer of the command packet.
284 *
285 * Output: NONE
286 *
287 * Return: NONE
288 *
289 * Revised History:
290 * When Who Remark
291 * 05/12/2008 amy Create Version 0 porting from windows code.
292 *
293 *---------------------------------------------------------------------------*/
294 static void cmpk_handle_query_config_rx(struct net_device *dev, u8 *pmsg)
295 {
296 cmpk_query_cfg_t rx_query_cfg;
297
298
299 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
300 /* It seems that FW use big endian(MIPS) and DRV use little endian in
301 windows OS. So we have to read the content byte by byte or transfer
302 endian type before copy the message copy. */
303 rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000) >> 31;
304 rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5;
305 rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3;
306 rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0;
307 rx_query_cfg.cfg_offset = pmsg[7];
308 rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) |
309 (pmsg[10] << 8) | (pmsg[11] << 0);
310 rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) |
311 (pmsg[14] << 8) | (pmsg[15] << 0);
312
313 }
314
315
316 /*-----------------------------------------------------------------------------
317 * Function: cmpk_count_tx_status()
318 *
319 * Overview: Count aggregated tx status from firmwar of one type rx command
320 * packet element id = RX_TX_STATUS.
321 *
322 * Input: NONE
323 *
324 * Output: NONE
325 *
326 * Return: NONE
327 *
328 * Revised History:
329 * When Who Remark
330 * 05/12/2008 amy Create Version 0 porting from windows code.
331 *
332 *---------------------------------------------------------------------------*/
333 static void cmpk_count_tx_status(struct net_device *dev,
334 cmpk_tx_status_t *pstx_status)
335 {
336 struct r8192_priv *priv = ieee80211_priv(dev);
337
338 #ifdef ENABLE_PS
339
340 RT_RF_POWER_STATE rtstate;
341
342 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
343 (pu1Byte)(&rtState));
344
345 /* When RF is off, we should not count the packet for hw/sw synchronize
346 reason, ie. there may be a duration while sw switch is changed and
347 hw switch is being changed. */
348 if (rtState == eRfOff)
349 return;
350 #endif
351
352 priv->stats.txfeedbackok += pstx_status->txok;
353 priv->stats.txoktotal += pstx_status->txok;
354
355 priv->stats.txfeedbackfail += pstx_status->txfail;
356 priv->stats.txerrtotal += pstx_status->txfail;
357
358 priv->stats.txretrycount += pstx_status->txretry;
359 priv->stats.txfeedbackretry += pstx_status->txretry;
360
361
362 priv->stats.txmulticast += pstx_status->txmcok;
363 priv->stats.txbroadcast += pstx_status->txbcok;
364 priv->stats.txunicast += pstx_status->txucok;
365
366 priv->stats.txerrmulticast += pstx_status->txmcfail;
367 priv->stats.txerrbroadcast += pstx_status->txbcfail;
368 priv->stats.txerrunicast += pstx_status->txucfail;
369
370 priv->stats.txbytesmulticast += pstx_status->txmclength;
371 priv->stats.txbytesbroadcast += pstx_status->txbclength;
372 priv->stats.txbytesunicast += pstx_status->txuclength;
373
374 priv->stats.last_packet_rate = pstx_status->rate;
375 }
376
377
378
379 /*-----------------------------------------------------------------------------
380 * Function: cmpk_handle_tx_status()
381 *
382 * Overview: Firmware add a new tx feedback status to reduce rx command
383 * packet buffer operation load.
384 *
385 * Input: NONE
386 *
387 * Output: NONE
388 *
389 * Return: NONE
390 *
391 * Revised History:
392 * When Who Remark
393 * 05/12/2008 amy Create Version 0 porting from windows code.
394 *
395 *---------------------------------------------------------------------------*/
396 static void cmpk_handle_tx_status(struct net_device *dev, u8 *pmsg)
397 {
398 cmpk_tx_status_t rx_tx_sts;
399
400 memcpy((void *)&rx_tx_sts, (void *)pmsg, sizeof(cmpk_tx_status_t));
401 /* 2. Use tx feedback info to count TX statistics. */
402 cmpk_count_tx_status(dev, &rx_tx_sts);
403
404 }
405
406
407 /*-----------------------------------------------------------------------------
408 * Function: cmpk_handle_tx_rate_history()
409 *
410 * Overview: Firmware add a new tx rate history
411 *
412 * Input: NONE
413 *
414 * Output: NONE
415 *
416 * Return: NONE
417 *
418 * Revised History:
419 * When Who Remark
420 * 05/12/2008 amy Create Version 0 porting from windows code.
421 *
422 *---------------------------------------------------------------------------*/
423 static void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg)
424 {
425 cmpk_tx_rahis_t *ptxrate;
426 u8 i, j;
427 u16 length = sizeof(cmpk_tx_rahis_t);
428 u32 *ptemp;
429 struct r8192_priv *priv = ieee80211_priv(dev);
430
431
432 #ifdef ENABLE_PS
433 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
434 (pu1Byte)(&rtState));
435
436 /* When RF is off, we should not count the packet for hw/sw synchronize
437 reason, ie. there may be a duration while sw switch is changed and
438 hw switch is being changed. */
439 if (rtState == eRfOff)
440 return;
441 #endif
442
443 ptemp = (u32 *)pmsg;
444
445 /* Do endian transfer to word alignment(16 bits) for windows system.
446 You must do different endian transfer for linux and MAC OS */
447 for (i = 0; i < (length/4); i++) {
448 u16 temp1, temp2;
449
450 temp1 = ptemp[i] & 0x0000FFFF;
451 temp2 = ptemp[i] >> 16;
452 ptemp[i] = (temp1 << 16) | temp2;
453 }
454
455 ptxrate = (cmpk_tx_rahis_t *)pmsg;
456
457 if (ptxrate == NULL)
458 return;
459
460 for (i = 0; i < 16; i++) {
461 /* Collect CCK rate packet num */
462 if (i < 4)
463 priv->stats.txrate.cck[i] += ptxrate->cck[i];
464
465 /* Collect OFDM rate packet num */
466 if (i < 8)
467 priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i];
468
469 for (j = 0; j < 4; j++)
470 priv->stats.txrate.ht_mcs[j][i] += ptxrate->ht_mcs[j][i];
471 }
472
473 }
474
475
476 /*-----------------------------------------------------------------------------
477 * Function: cmpk_message_handle_rx()
478 *
479 * Overview: In the function, we will capture different RX command packet
480 * info. Every RX command packet element has different message
481 * length and meaning in content. We only support three type of RX
482 * command packet now. Please refer to document
483 * ws-06-0063-rtl8190-command-packet-specification.
484 *
485 * Input: NONE
486 *
487 * Output: NONE
488 *
489 * Return: NONE
490 *
491 * Revised History:
492 * When Who Remark
493 * 05/06/2008 amy Create Version 0 porting from windows code.
494 *
495 *---------------------------------------------------------------------------*/
496 u32 cmpk_message_handle_rx(struct net_device *dev,
497 struct ieee80211_rx_stats *pstats)
498 {
499 int total_length;
500 u8 cmd_length, exe_cnt = 0;
501 u8 element_id;
502 u8 *pcmd_buff;
503
504 /* 0. Check inpt arguments. If is is a command queue message or
505 pointer is null. */
506 if (pstats == NULL)
507 return 0; /* This is not a command packet. */
508
509 /* 1. Read received command packet message length from RFD. */
510 total_length = pstats->Length;
511
512 /* 2. Read virtual address from RFD. */
513 pcmd_buff = pstats->virtual_address;
514
515 /* 3. Read command packet element id and length. */
516 element_id = pcmd_buff[0];
517
518 /* 4. Check every received command packet content according to different
519 element type. Because FW may aggregate RX command packet to
520 minimize transmit time between DRV and FW.*/
521 /* Add a counter to prevent the lock in the loop from being held too
522 long */
523 while (total_length > 0 && exe_cnt++ < 100) {
524 /* We support aggregation of different cmd in the same packet */
525 element_id = pcmd_buff[0];
526
527 switch (element_id) {
528 case RX_TX_FEEDBACK:
529 cmpk_handle_tx_feedback(dev, pcmd_buff);
530 cmd_length = CMPK_RX_TX_FB_SIZE;
531 break;
532
533 case RX_INTERRUPT_STATUS:
534 cmpk_handle_interrupt_status(dev, pcmd_buff);
535 cmd_length = sizeof(cmpk_intr_sta_t);
536 break;
537
538 case BOTH_QUERY_CONFIG:
539 cmpk_handle_query_config_rx(dev, pcmd_buff);
540 cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
541 break;
542
543 case RX_TX_STATUS:
544 cmpk_handle_tx_status(dev, pcmd_buff);
545 cmd_length = CMPK_RX_TX_STS_SIZE;
546 break;
547
548 case RX_TX_PER_PKT_FEEDBACK:
549 /* You must at lease add a switch case element here,
550 Otherwise, we will jump to default case. */
551 cmd_length = CMPK_RX_TX_FB_SIZE;
552 break;
553
554 case RX_TX_RATE_HISTORY:
555 cmpk_handle_tx_rate_history(dev, pcmd_buff);
556 cmd_length = CMPK_TX_RAHIS_SIZE;
557 break;
558
559 default:
560
561 RT_TRACE(COMP_ERR, "---->%s():unknown CMD Element\n",
562 __func__);
563 return 1; /* This is a command packet. */
564 }
565
566 total_length -= cmd_length;
567 pcmd_buff += cmd_length;
568 }
569 return 1; /* This is a command packet. */
570
571 }
This page took 0.042009 seconds and 5 git commands to generate.