Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux...
[pandora-kernel.git] / drivers / staging / rtl8192su / r819xU_cmdpkt.c
1 /******************************************************************************
2  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
3  * Linux device driver for RTL8192U
4  *
5  * This program is distributed in the hope that it will be useful, but WITHOUT
6  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
7  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
8  * more details.
9  *
10  * You should have received a copy of the GNU General Public License along with
11  * this program; if not, write to the Free Software Foundation, Inc.,
12  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
13  *
14  * The full GNU General Public License is included in this distribution in the
15  * file called LICENSE.
16  *
17  * Contact Information:
18  * wlanfae <wlanfae@realtek.com>
19 ******************************************************************************/
20 #include "r8192U.h"
21 #include "r819xU_cmdpkt.h"
22
23 bool SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen)
24 {
25         bool    rtStatus = true;
26         struct r8192_priv   *priv = ieee80211_priv(dev);
27         struct sk_buff      *skb;
28         cb_desc             *tcb_desc;
29         unsigned char       *ptr_buf;
30
31         /*
32          * Get TCB and local buffer from common pool.
33          * (It is shared by CmdQ, MgntQ, and USB coalesce DataQ)
34          */
35         skb  = dev_alloc_skb(USB_HWDESC_HEADER_LEN + DataLen + 4);
36         if (!skb)
37                 return false;
38         memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
39         tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
40         tcb_desc->queue_index = TXCMD_QUEUE;
41         tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL;
42         tcb_desc->bLastIniPkt = 0;
43         skb_reserve(skb, USB_HWDESC_HEADER_LEN);
44         ptr_buf = skb_put(skb, DataLen);
45         memcpy(ptr_buf, pData, DataLen);
46         tcb_desc->txbuf_size = (u16)DataLen;
47
48         if (!priv->ieee80211->check_nic_enough_desc(dev, tcb_desc->queue_index) ||
49                 (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index])) ||
50                         (priv->ieee80211->queue_stop)) {
51                         RT_TRACE(COMP_FIRMWARE, "NULL packet => tx full\n");
52                         skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
53                 } else {
54                         priv->ieee80211->softmac_hard_start_xmit(skb, dev);
55                 }
56
57         return rtStatus;
58 }
59
60 /*
61  * Function:    cmpk_message_handle_tx()
62  *
63  * Overview:    Driver internal module can call the API to send message to
64  *              firmware side. For example, you can send a debug command packet.
65  *              Or you can send a request for FW to modify RLX4181 LBUS HW bank.
66  *              Otherwise, you can change MAC/PHT/RF register by firmware at
67  *              run time. We do not support message more than one segment now.
68  *
69  * Input:               NONE
70  *
71  * Output:              NONE
72  *
73  * Return:              NONE
74  */
75  extern bool    cmpk_message_handle_tx(
76         struct net_device *dev,
77         u8 *codevirtualaddress,
78         u32     packettype,
79         u32     buffer_len)
80 {
81         bool rt_status = true;
82         return rt_status;
83 }
84
85 /*
86  * Function: cmpk_counttxstatistic()
87  */
88 static  void
89 cmpk_count_txstatistic(struct net_device *dev, cmpk_txfb_t *pstx_fb)
90 {
91         struct r8192_priv *priv = ieee80211_priv(dev);
92 #ifdef ENABLE_PS
93         RT_RF_POWER_STATE rtState;
94
95         pAdapter->HalFunc.GetHwRegHandler(pAdapter,
96                                                 HW_VAR_RF_STATE,
97                                                 (pu1Byte)(&rtState));
98
99         /*
100          * When RF is off, we should not count the packet for hw/sw synchronize
101          * reason, ie. there may be a duration while sw switch is changed and hw
102          * switch is being changed.
103          */
104         if (rtState == eRfOff)
105                 return;
106 #endif
107
108 #ifdef TODO
109         if (pAdapter->bInHctTest)
110                 return;
111 #endif
112         /*
113          * We can not know the packet length and transmit type:
114          * broadcast or uni or multicast.
115          * So the relative statistics must be collected in tx feedback info
116          */
117         if (pstx_fb->tok) {
118                 priv->stats.txfeedbackok++;
119                 priv->stats.txoktotal++;
120                 priv->stats.txokbytestotal += pstx_fb->pkt_length;
121                 priv->stats.txokinperiod++;
122                 /* We can not make sure broadcast/multicast or unicast mode. */
123                 if (pstx_fb->pkt_type == PACKET_MULTICAST) {
124                         priv->stats.txmulticast++;
125                         priv->stats.txbytesmulticast += pstx_fb->pkt_length;
126                 } else if (pstx_fb->pkt_type == PACKET_BROADCAST) {
127                         priv->stats.txbroadcast++;
128                         priv->stats.txbytesbroadcast += pstx_fb->pkt_length;
129                 } else {
130                         priv->stats.txunicast++;
131                         priv->stats.txbytesunicast += pstx_fb->pkt_length;
132                 }
133         } else {
134                 priv->stats.txfeedbackfail++;
135                 priv->stats.txerrtotal++;
136                 priv->stats.txerrbytestotal += pstx_fb->pkt_length;
137                 /* We can not make sure broadcast/multicast or unicast mode. */
138                 if (pstx_fb->pkt_type == PACKET_MULTICAST)
139                         priv->stats.txerrmulticast++;
140                 else if (pstx_fb->pkt_type == PACKET_BROADCAST)
141                         priv->stats.txerrbroadcast++;
142                 else
143                         priv->stats.txerrunicast++;
144         }
145         priv->stats.txretrycount += pstx_fb->retry_cnt;
146         priv->stats.txfeedbackretry += pstx_fb->retry_cnt;
147 }
148
149 /*
150  * Function:    cmpk_handle_tx_feedback()
151  *
152  * Overview:    The function is responsible for extract the message inside TX
153  *              feedbck message from firmware. It will contain dedicated info in
154  *              ws-06-0063-rtl8190-command-packet-specification. Please
155  *              refer to chapter "TX Feedback Element". We have to read 20 bytes
156  *              in the command packet.
157  *
158  * Input:       struct net_device *    dev
159  *                              u8 *pmsg - Msg Ptr of the command packet.
160  *
161  * Output:      NONE
162  *
163  * Return:      NONE
164  */
165 static void cmpk_handle_tx_feedback(struct net_device *dev, u8 *pmsg)
166 {
167         struct r8192_priv *priv = ieee80211_priv(dev);
168         cmpk_txfb_t rx_tx_fb;
169
170         priv->stats.txfeedback++;
171
172         /* 1. Extract TX feedback info from RFD to temp structure buffer. */
173         memcpy((u8 *)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
174
175         /* 2. Use tx feedback info to count TX statistics. */
176         cmpk_count_txstatistic(dev, &rx_tx_fb);
177 }
178
179 void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev)
180 {
181         struct r8192_priv *priv = ieee80211_priv(dev);
182         u16 tx_rate;
183
184         if (priv->ieee80211->current_network.mode == IEEE_A  ||
185                 priv->ieee80211->current_network.mode == IEEE_N_5G ||
186                 (priv->ieee80211->current_network.mode == IEEE_N_24G  &&
187                 (!priv->ieee80211->pHTInfo->bCurSuppCCK))) {
188                 tx_rate = 60;
189                 DMESG("send beacon frame  tx rate is 6Mbpm\n");
190         } else {
191                 tx_rate = 10;
192                 DMESG("send beacon frame  tx rate is 1Mbpm\n");
193         }
194         rtl819xusb_beacon_tx(dev, tx_rate); /* HW Beacon */
195 }
196
197 /*
198  * Function:    cmpk_handle_interrupt_status()
199  *
200  * Overview:    The function is responsible for extract the message from
201  *              firmware. It will contain dedicated info in
202  *              ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
203  *              Please refer to chapter "Interrupt Status Element".
204  *
205  * Input:       struct net_device *dev,
206  *                      u8* pmsg - Message Pointer of the command packet.
207  *
208  * Output:      NONE
209  *
210  * Return:      NONE
211  */
212 static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg)
213 {
214         cmpk_intr_sta_t         rx_intr_status; /* */
215         struct r8192_priv *priv = ieee80211_priv(dev);
216
217         DMESG("---> cmpk_Handle_Interrupt_Status()\n");
218
219         /* 1. Extract TX feedback info from RFD to temp structure buffer. */
220         rx_intr_status.length = pmsg[1];
221         if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2)) {
222                 DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
223                 return;
224         }
225         /* Statistics of beacon for ad-hoc mode. */
226         if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) {
227                 //2 maybe need endian transform?
228                 rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
229
230                 DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status);
231
232                 if (rx_intr_status.interrupt_status & ISR_TxBcnOk) {
233                         priv->ieee80211->bibsscoordinator = true;
234                         priv->stats.txbeaconokint++;
235                 } else if (rx_intr_status.interrupt_status & ISR_TxBcnErr) {
236                         priv->ieee80211->bibsscoordinator = false;
237                         priv->stats.txbeaconerr++;
238                 }
239
240                 if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr)
241                         cmdpkt_beacontimerinterrupt_819xusb(dev);
242         }
243          /* Other informations in interrupt status we need? */
244         DMESG("<---- cmpk_handle_interrupt_status()\n");
245 }
246
247 /*
248  * Function:    cmpk_handle_query_config_rx()
249  *
250  * Overview:    The function is responsible for extract the message from
251  *                              firmware. It will contain dedicated info in
252  *                              ws-06-0063-rtl8190-command-packet-specification
253  *                              Please refer to chapter "Beacon State Element".
254  *
255  * Input:       u8 *  pmsg      -       Message Pointer of the command packet.
256  *
257  * Output:      NONE
258  *
259  * Return:      NONE
260  *
261  */
262 static void cmpk_handle_query_config_rx(struct net_device *dev, u8 *pmsg)
263 {
264         cmpk_query_cfg_t rx_query_cfg;
265         /*
266          * Extract TX feedback info from RFD to temp structure buffer.
267          */
268         rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000) >> 31;
269         rx_query_cfg.cfg_type   = (pmsg[4] & 0x60) >> 5;
270         rx_query_cfg.cfg_size   = (pmsg[4] & 0x18) >> 3;
271         rx_query_cfg.cfg_page   = (pmsg[6] & 0x0F) >> 0;
272         rx_query_cfg.cfg_offset = pmsg[7];
273         rx_query_cfg.value      = (pmsg[8] << 24) | (pmsg[9] << 16) |
274                                         (pmsg[10] << 8) | (pmsg[11] << 0);
275         rx_query_cfg.mask       = (pmsg[12] << 24) | (pmsg[13] << 16) |
276                                         (pmsg[14] << 8) | (pmsg[15] << 0);
277 }
278
279 /*
280  * Function:    cmpk_count_tx_status()
281  *
282  * Overview:    Count aggregated tx status from firmware of one type rx command
283  *                              packet element id = RX_TX_STATUS.
284  *
285  * Input:               NONE
286  *
287  * Output:              NONE
288  *
289  * Return:              NONE
290  */
291 static void cmpk_count_tx_status(struct net_device *dev,
292                                         cmpk_tx_status_t *pstx_status)
293 {
294         struct r8192_priv *priv = ieee80211_priv(dev);
295
296 #ifdef ENABLE_PS
297
298         RT_RF_POWER_STATE       rtstate;
299
300         pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
301
302         /*
303          * When RF is off, we should not count the packet for hw/sw synchronize
304          * reason, ie. there may be a duration while sw switch is changed and hw
305          * switch is being changed.
306          */
307         if (rtState == eRfOff)
308                 return;
309 #endif
310
311         priv->stats.txfeedbackok        += pstx_status->txok;
312         priv->stats.txoktotal           += pstx_status->txok;
313
314         priv->stats.txfeedbackfail      += pstx_status->txfail;
315         priv->stats.txerrtotal          += pstx_status->txfail;
316
317         priv->stats.txretrycount        += pstx_status->txretry;
318         priv->stats.txfeedbackretry     += pstx_status->txretry;
319
320         priv->stats.txmulticast         += pstx_status->txmcok;
321         priv->stats.txbroadcast         += pstx_status->txbcok;
322         priv->stats.txunicast           += pstx_status->txucok;
323
324         priv->stats.txerrmulticast      += pstx_status->txmcfail;
325         priv->stats.txerrbroadcast      += pstx_status->txbcfail;
326         priv->stats.txerrunicast        += pstx_status->txucfail;
327
328         priv->stats.txbytesmulticast    += pstx_status->txmclength;
329         priv->stats.txbytesbroadcast    += pstx_status->txbclength;
330         priv->stats.txbytesunicast      += pstx_status->txuclength;
331
332         priv->stats.last_packet_rate    = pstx_status->rate;
333 }
334
335 /*
336  * Function:    cmpk_handle_tx_status()
337  *
338  * Overview:    Firmware add a new tx feedback status to reduce rx command
339  *                              packet buffer operation load.
340  *
341  * Input:               NONE
342  *
343  * Output:              NONE
344  *
345  * Return:              NONE
346  */
347 static  void
348 cmpk_handle_tx_status(struct net_device *dev, u8 *pmsg)
349 {
350         cmpk_tx_status_t rx_tx_sts;
351
352         memcpy((void *)&rx_tx_sts, (void *)pmsg, sizeof(cmpk_tx_status_t));
353         /* 2. Use tx feedback info to count TX statistics. */
354         cmpk_count_tx_status(dev, &rx_tx_sts);
355 }
356
357 /*
358  * Function:    cmpk_handle_tx_rate_history()
359  *
360  * Overview:    Firmware add a new tx rate history
361  *
362  * Input:               NONE
363  *
364  * Output:              NONE
365  *
366  * Return:              NONE
367  */
368 static void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg)
369 {
370         cmpk_tx_rahis_t *ptxrate;
371         u8 i, j;
372         u16 length = sizeof(cmpk_tx_rahis_t);
373         u32 *ptemp;
374         struct r8192_priv *priv = ieee80211_priv(dev);
375
376 #ifdef ENABLE_PS
377         pAdapter->HalFunc.GetHwRegHandler(pAdapter,
378                                                 HW_VAR_RF_STATE,
379                                                 (pu1Byte)(&rtState));
380         /*
381          * When RF is off, we should not count the packet for hw/sw synchronize
382          * reason, ie. there may be a duration while sw switch is changed and hw
383          * switch is being changed.
384          */
385         if (rtState == eRfOff)
386                 return;
387 #endif
388         ptemp = (u32 *)pmsg;
389
390         /*
391          * Do endian transfer to word alignment(16 bits) for windows system.
392          * You must do different endian transfer for linux and MAC OS
393          */
394         for (i = 0; i < (length/4); i++) {
395                 u16 temp1, temp2;
396                 temp1 = ptemp[i] & 0x0000FFFF;
397                 temp2 = ptemp[i] >> 16;
398                 ptemp[i] = (temp1 << 16) | temp2;
399         }
400
401         ptxrate = (cmpk_tx_rahis_t *)pmsg;
402
403         if (ptxrate == NULL)
404                 return;
405
406         for (i = 0; i < 16; i++) {
407                 /* Collect CCK rate packet num */
408                 if (i < 4)
409                         priv->stats.txrate.cck[i] += ptxrate->cck[i];
410                 /* Collect OFDM rate packet num */
411                 if (i < 8)
412                         priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i];
413                 for (j = 0; j < 4; j++)
414                         priv->stats.txrate.ht_mcs[j][i] += ptxrate->ht_mcs[j][i];
415         }
416
417 }
418
419 /*
420  * Function:    cmpk_message_handle_rx()
421  *
422  * Overview:    In the function, we will capture different RX command packet
423  *              info. Every RX command packet element has different message
424  *              length and meaning in content. We only support three type of RX
425  *              command packet now. Please refer to document
426  *              ws-06-0063-rtl8190-command-packet-specification.
427  *
428  * Input:       NONE
429  *
430  * Output:      NONE
431  *
432  * Return:      NONE
433  */
434 extern  u32
435 cmpk_message_handle_rx(
436         struct net_device *dev,
437         struct ieee80211_rx_stats *pstats)
438 {
439         struct r8192_priv *priv = ieee80211_priv(dev);
440         int                     total_length;
441         u8                      cmd_length, exe_cnt = 0;
442         u8                      element_id;
443         u8                      *pcmd_buff;
444
445         /*
446          * 0. Check input arguments.
447          * If is is a command queue message or pointer is null
448          */
449         if ((pstats == NULL))
450                 return 0;       /* This is not a command packet. */
451
452         /* 1. Read received command packet message length from RFD. */
453         total_length = pstats->Length;
454
455         /* 2. Read virtual address from RFD. */
456         pcmd_buff = pstats->virtual_address;
457
458         /* 3. Read command pakcet element id and length. */
459         element_id = pcmd_buff[0];
460
461         /*
462          * 4. Check every received command packet conent according to different
463          * element type. Because FW may aggregate RX command packet to minimize
464          * transmit time between DRV and FW.
465          */
466
467         /* Add a counter to prevent to locked in the loop too long */
468         while (total_length > 0 || exe_cnt++ > 100) {
469                 /* We support aggregation of different cmd in the same packet */
470                 element_id = pcmd_buff[0];
471                 switch (element_id) {
472                 case RX_TX_FEEDBACK:
473                         cmpk_handle_tx_feedback(dev, pcmd_buff);
474                         cmd_length = CMPK_RX_TX_FB_SIZE;
475                         break;
476                 case RX_INTERRUPT_STATUS:
477                         cmpk_handle_interrupt_status(dev, pcmd_buff);
478                         cmd_length = sizeof(cmpk_intr_sta_t);
479                         break;
480                 case BOTH_QUERY_CONFIG:
481                         cmpk_handle_query_config_rx(dev, pcmd_buff);
482                         cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
483                         break;
484                 case RX_TX_STATUS:
485                         cmpk_handle_tx_status(dev, pcmd_buff);
486                         cmd_length = CMPK_RX_TX_STS_SIZE;
487                         break;
488                 case RX_TX_PER_PKT_FEEDBACK:
489                         cmd_length = CMPK_RX_TX_FB_SIZE;
490                         break;
491                 case RX_TX_RATE_HISTORY:
492                         cmpk_handle_tx_rate_history(dev, pcmd_buff);
493                         cmd_length = CMPK_TX_RAHIS_SIZE;
494                         break;
495                 case RX_TX_TSSI_MEAN_BACK:
496                         {
497                                 u32     *pMsg;
498                                 pMsg = (u32 *)pcmd_buff;
499                         }
500                         cmd_length = 32;
501                         break;
502                 default:
503                          RT_TRACE(COMP_ERR, "(%s): unknown CMD Element\n",
504                                                                 __func__);
505                         return 1;       /* This is a command packet. */
506                 }
507                 priv->stats.rxcmdpkt[element_id]++;
508                 total_length -= cmd_length;
509                 pcmd_buff    += cmd_length;
510         }
511         return 1;       /* This is a command packet. */
512 }