Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / staging / rtl8192e / rtl8192e / r8192E_cmdpkt.c
1 /******************************************************************************
2  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
3  *
4  * This program is distributed in the hope that it will be useful, but WITHOUT
5  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
6  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
7  * more details.
8  *
9  * You should have received a copy of the GNU General Public License along with
10  * this program; if not, write to the Free Software Foundation, Inc.,
11  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
12  *
13  * The full GNU General Public License is included in this distribution in the
14  * file called LICENSE.
15  *
16  * Contact Information:
17  * wlanfae <wlanfae@realtek.com>
18 ******************************************************************************/
19
20 #include "rtl_core.h"
21 #include "r8192E_hw.h"
22 #include "r8192E_cmdpkt.h"
23
24 bool cmpk_message_handle_tx(
25         struct net_device *dev,
26         u8      *code_virtual_address,
27         u32     packettype,
28         u32     buffer_len)
29 {
30
31         bool                            rt_status = true;
32         struct r8192_priv *priv = rtllib_priv(dev);
33         u16                             frag_threshold;
34         u16                             frag_length = 0, frag_offset = 0;
35         struct rt_firmware *pfirmware = priv->pFirmware;
36         struct sk_buff          *skb;
37         unsigned char           *seg_ptr;
38         struct cb_desc *tcb_desc;
39         u8                              bLastIniPkt;
40
41         struct tx_fwinfo_8190pci *pTxFwInfo = NULL;
42
43         RT_TRACE(COMP_CMDPKT, "%s(),buffer_len is %d\n", __func__, buffer_len);
44         firmware_init_param(dev);
45         frag_threshold = pfirmware->cmdpacket_frag_thresold;
46
47         do {
48                 if ((buffer_len - frag_offset) > frag_threshold) {
49                         frag_length = frag_threshold;
50                         bLastIniPkt = 0;
51
52                 } else {
53                         frag_length = (u16)(buffer_len - frag_offset);
54                         bLastIniPkt = 1;
55                 }
56
57                 skb  = dev_alloc_skb(frag_length +
58                                      priv->rtllib->tx_headroom + 4);
59
60                 if (skb == NULL) {
61                         rt_status = false;
62                         goto Failed;
63                 }
64
65                 memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
66                 tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
67                 tcb_desc->queue_index = TXCMD_QUEUE;
68                 tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL;
69                 tcb_desc->bLastIniPkt = bLastIniPkt;
70                 tcb_desc->pkt_size = frag_length;
71
72                 seg_ptr = skb_put(skb, priv->rtllib->tx_headroom);
73                 pTxFwInfo = (struct tx_fwinfo_8190pci *)seg_ptr;
74                 memset(pTxFwInfo, 0, sizeof(struct tx_fwinfo_8190pci));
75                 memset(pTxFwInfo, 0x12, 8);
76
77                 seg_ptr = skb_put(skb, frag_length);
78                 memcpy(seg_ptr, code_virtual_address, (u32)frag_length);
79
80                 priv->rtllib->softmac_hard_start_xmit(skb, dev);
81
82                 code_virtual_address += frag_length;
83                 frag_offset += frag_length;
84
85         } while (frag_offset < buffer_len);
86
87         write_nic_byte(dev, TPPoll, TPPoll_CQ);
88 Failed:
89         return rt_status;
90 }
91
92 static  void
93 cmpk_count_txstatistic(
94         struct net_device *dev,
95         struct cmpk_txfb *pstx_fb)
96 {
97         struct r8192_priv *priv = rtllib_priv(dev);
98 #ifdef ENABLE_PS
99         enum rt_rf_power_state rtState;
100
101         pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
102                                           (pu1Byte)(&rtState));
103
104         if (rtState == eRfOff)
105                 return;
106 #endif
107
108         if (pstx_fb->tok) {
109                 priv->stats.txfeedbackok++;
110                 priv->stats.txoktotal++;
111                 priv->stats.txokbytestotal += pstx_fb->pkt_length;
112                 priv->stats.txokinperiod++;
113
114                 if (pstx_fb->pkt_type == PACKET_MULTICAST) {
115                         priv->stats.txmulticast++;
116                         priv->stats.txbytesmulticast += pstx_fb->pkt_length;
117                 } else if (pstx_fb->pkt_type == PACKET_BROADCAST) {
118                         priv->stats.txbroadcast++;
119                         priv->stats.txbytesbroadcast += pstx_fb->pkt_length;
120                 } else {
121                         priv->stats.txunicast++;
122                         priv->stats.txbytesunicast += pstx_fb->pkt_length;
123                 }
124         } else {
125                 priv->stats.txfeedbackfail++;
126                 priv->stats.txerrtotal++;
127                 priv->stats.txerrbytestotal += pstx_fb->pkt_length;
128
129                 if (pstx_fb->pkt_type == PACKET_MULTICAST)
130                         priv->stats.txerrmulticast++;
131                 else if (pstx_fb->pkt_type == PACKET_BROADCAST)
132                         priv->stats.txerrbroadcast++;
133                 else
134                         priv->stats.txerrunicast++;
135         }
136
137         priv->stats.txretrycount += pstx_fb->retry_cnt;
138         priv->stats.txfeedbackretry += pstx_fb->retry_cnt;
139 }
140
141 static void cmpk_handle_tx_feedback(struct net_device *dev, u8 *pmsg)
142 {
143         struct r8192_priv *priv = rtllib_priv(dev);
144         struct cmpk_txfb rx_tx_fb;
145
146         priv->stats.txfeedback++;
147
148
149         memcpy((u8 *)&rx_tx_fb, pmsg, sizeof(struct cmpk_txfb));
150         cmpk_count_txstatistic(dev, &rx_tx_fb);
151 }
152
153 static void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev)
154 {
155         struct r8192_priv *priv = rtllib_priv(dev);
156
157         if ((priv->rtllib->current_network.mode == IEEE_A)  ||
158             (priv->rtllib->current_network.mode == IEEE_N_5G) ||
159             ((priv->rtllib->current_network.mode == IEEE_N_24G)  &&
160             (!priv->rtllib->pHTInfo->bCurSuppCCK)))
161                 DMESG("send beacon frame  tx rate is 6Mbpm\n");
162         else
163                 DMESG("send beacon frame  tx rate is 1Mbpm\n");
164 }
165
166 static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg)
167 {
168         struct cmpk_intr_sta rx_intr_status;
169         struct r8192_priv *priv = rtllib_priv(dev);
170
171         DMESG("---> cmpk_Handle_Interrupt_Status()\n");
172
173         rx_intr_status.length = pmsg[1];
174         if (rx_intr_status.length != (sizeof(struct cmpk_intr_sta) - 2)) {
175                 DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
176                 return;
177         }
178
179         if (priv->rtllib->iw_mode == IW_MODE_ADHOC) {
180                 rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
181
182                 DMESG("interrupt status = 0x%x\n",
183                       rx_intr_status.interrupt_status);
184
185                 if (rx_intr_status.interrupt_status & ISR_TxBcnOk) {
186                         priv->rtllib->bibsscoordinator = true;
187                         priv->stats.txbeaconokint++;
188                 } else if (rx_intr_status.interrupt_status & ISR_TxBcnErr) {
189                         priv->rtllib->bibsscoordinator = false;
190                         priv->stats.txbeaconerr++;
191                 }
192
193                 if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr)
194                         cmdpkt_beacontimerinterrupt_819xusb(dev);
195         }
196
197         DMESG("<---- cmpk_handle_interrupt_status()\n");
198
199 }
200
201 static  void cmpk_handle_query_config_rx(struct net_device *dev, u8 *pmsg)
202 {
203         cmpk_query_cfg_t        rx_query_cfg;
204
205
206         rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000)>>31;
207         rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5;
208         rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3;
209         rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0;
210         rx_query_cfg.cfg_offset  = pmsg[7];
211         rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) |
212                              (pmsg[10] << 8) | (pmsg[11] << 0);
213         rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) |
214                             (pmsg[14] << 8) | (pmsg[15] << 0);
215
216 }
217
218 static void cmpk_count_tx_status(struct net_device *dev,
219                                  struct cmpk_tx_status *pstx_status)
220 {
221         struct r8192_priv *priv = rtllib_priv(dev);
222
223 #ifdef ENABLE_PS
224
225         enum rt_rf_power_state rtstate;
226
227         pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
228                                           (pu1Byte)(&rtState));
229
230         if (rtState == eRfOff)
231                 return;
232 #endif
233
234         priv->stats.txfeedbackok        += pstx_status->txok;
235         priv->stats.txoktotal           += pstx_status->txok;
236
237         priv->stats.txfeedbackfail      += pstx_status->txfail;
238         priv->stats.txerrtotal          += pstx_status->txfail;
239
240         priv->stats.txretrycount                += pstx_status->txretry;
241         priv->stats.txfeedbackretry     += pstx_status->txretry;
242
243
244         priv->stats.txmulticast += pstx_status->txmcok;
245         priv->stats.txbroadcast += pstx_status->txbcok;
246         priv->stats.txunicast           += pstx_status->txucok;
247
248         priv->stats.txerrmulticast      += pstx_status->txmcfail;
249         priv->stats.txerrbroadcast      += pstx_status->txbcfail;
250         priv->stats.txerrunicast        += pstx_status->txucfail;
251
252         priv->stats.txbytesmulticast    += pstx_status->txmclength;
253         priv->stats.txbytesbroadcast    += pstx_status->txbclength;
254         priv->stats.txbytesunicast              += pstx_status->txuclength;
255
256         priv->stats.last_packet_rate            = pstx_status->rate;
257 }
258
259 static  void cmpk_handle_tx_status(struct net_device *dev, u8 *pmsg)
260 {
261         struct cmpk_tx_status rx_tx_sts;
262
263         memcpy((void *)&rx_tx_sts, (void *)pmsg, sizeof(struct cmpk_tx_status));
264         cmpk_count_tx_status(dev, &rx_tx_sts);
265 }
266
267 static  void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg)
268 {
269         struct cmpk_tx_rahis *ptxrate;
270         u8 i, j;
271         u16                             length = sizeof(struct cmpk_tx_rahis);
272         u32 *ptemp;
273         struct r8192_priv *priv = rtllib_priv(dev);
274
275 #ifdef ENABLE_PS
276         pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
277                                          (pu1Byte)(&rtState));
278
279         if (rtState == eRfOff)
280                 return;
281 #endif
282
283         ptemp = (u32 *)pmsg;
284
285         for (i = 0; i < (length / 4); i++) {
286                 u16      temp1, temp2;
287
288                 temp1 = ptemp[i] & 0x0000FFFF;
289                 temp2 = ptemp[i] >> 16;
290                 ptemp[i] = (temp1 << 16) | temp2;
291         }
292
293         ptxrate = (struct cmpk_tx_rahis *)pmsg;
294
295         if (ptxrate == NULL)
296                 return;
297
298         for (i = 0; i < 16; i++) {
299                 if (i < 4)
300                         priv->stats.txrate.cck[i] += ptxrate->cck[i];
301
302                 if (i < 8)
303                         priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i];
304
305                 for (j = 0; j < 4; j++)
306                         priv->stats.txrate.ht_mcs[j][i] +=
307                                                          ptxrate->ht_mcs[j][i];
308         }
309 }
310
311 u32 cmpk_message_handle_rx(struct net_device *dev,
312                            struct rtllib_rx_stats *pstats)
313 {
314         int                     total_length;
315         u8                      cmd_length, exe_cnt = 0;
316         u8                      element_id;
317         u8                      *pcmd_buff;
318
319         RT_TRACE(COMP_CMDPKT, "---->cmpk_message_handle_rx()\n");
320
321         if (pstats == NULL)
322                 return 0;
323
324         total_length = pstats->Length;
325
326         pcmd_buff = pstats->virtual_address;
327
328         element_id = pcmd_buff[0];
329
330         while (total_length > 0 || exe_cnt++ > 100) {
331                 element_id = pcmd_buff[0];
332
333                 switch (element_id) {
334                 case RX_TX_FEEDBACK:
335                         RT_TRACE(COMP_CMDPKT,
336                                  "---->cmpk_message_handle_rx():RX_TX_FEEDBACK\n");
337                         cmpk_handle_tx_feedback(dev, pcmd_buff);
338                         cmd_length = CMPK_RX_TX_FB_SIZE;
339                         break;
340                 case RX_INTERRUPT_STATUS:
341                         RT_TRACE(COMP_CMDPKT,
342                                  "---->cmpk_message_handle_rx():RX_INTERRUPT_STATUS\n");
343                         cmpk_handle_interrupt_status(dev, pcmd_buff);
344                         cmd_length = sizeof(struct cmpk_intr_sta);
345                         break;
346                 case BOTH_QUERY_CONFIG:
347                         RT_TRACE(COMP_CMDPKT,
348                                  "---->cmpk_message_handle_rx():BOTH_QUERY_CONFIG\n");
349                         cmpk_handle_query_config_rx(dev, pcmd_buff);
350                         cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
351                         break;
352                 case RX_TX_STATUS:
353                         RT_TRACE(COMP_CMDPKT,
354                                  "---->cmpk_message_handle_rx():RX_TX_STATUS\n");
355                         cmpk_handle_tx_status(dev, pcmd_buff);
356                         cmd_length = CMPK_RX_TX_STS_SIZE;
357                         break;
358                 case RX_TX_PER_PKT_FEEDBACK:
359                         RT_TRACE(COMP_CMDPKT,
360                                  "---->cmpk_message_handle_rx():RX_TX_PER_PKT_FEEDBACK\n");
361                         cmd_length = CMPK_RX_TX_FB_SIZE;
362                         break;
363                 case RX_TX_RATE_HISTORY:
364                         RT_TRACE(COMP_CMDPKT,
365                                  "---->cmpk_message_handle_rx():RX_TX_HISTORY\n");
366                         cmpk_handle_tx_rate_history(dev, pcmd_buff);
367                         cmd_length = CMPK_TX_RAHIS_SIZE;
368                         break;
369                 default:
370
371                         RT_TRACE(COMP_CMDPKT,
372                                  "---->cmpk_message_handle_rx():unknown CMD Element\n");
373                         return 1;
374                 }
375
376                 total_length -= cmd_length;
377                 pcmd_buff    += cmd_length;
378         }
379         return  1;
380 }