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