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