Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / 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 }