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