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