staging: rtl8192e: Pass rtl8192_priv to dm functions
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / staging / rtl8192e / r819xE_cmdpkt.c
1 /******************************************************************************
2
3      (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
4
5  Module:        r819xusb_cmdpkt.c       (RTL8190 TX/RX command packet handler Source C File)
6
7  Note:      The module is responsible for handling TX and RX command packet.
8                         1. TX : Send set and query configuration command packet.
9                         2. RX : Receive tx feedback, beacon state, query configuration
10                                 command packet.
11
12  Function:
13
14  Export:
15
16  Abbrev:
17
18  History:
19         Data            Who             Remark
20
21         05/06/2008  amy         Create initial version porting from windows driver.
22
23 ******************************************************************************/
24 #include "r8192E.h"
25 #include "r8192E_hw.h"
26 #include "r819xE_cmdpkt.h"
27
28 /*
29  * Driver internal module can call the API to send message to
30  * firmware side. For example, you can send a debug command packet.
31  * Or you can send a request for FW to modify RLX4181 LBUS HW bank.
32  * Otherwise, you can change MAC/PHT/RF register by firmware at
33  * run time. We do not support message more than one segment now.
34  */
35 RT_STATUS cmpk_message_handle_tx(
36         struct net_device *dev,
37         u8*     code_virtual_address,
38         u32     packettype,
39         u32     buffer_len)
40 {
41
42         RT_STATUS           rt_status = RT_STATUS_SUCCESS;
43         struct r8192_priv   *priv = ieee80211_priv(dev);
44         u16                 frag_threshold;
45         u16                 frag_length = 0, frag_offset = 0;
46         rt_firmware         *pfirmware = priv->pFirmware;
47         struct sk_buff      *skb;
48         unsigned char       *seg_ptr;
49         cb_desc             *tcb_desc;
50         u8                  bLastIniPkt;
51
52         PTX_FWINFO_8190PCI      pTxFwInfo = NULL;
53         int i;
54
55         RT_TRACE(COMP_CMDPKT,"%s(),buffer_len is %d\n",__FUNCTION__,buffer_len);
56         firmware_init_param(dev);
57         //Fragmentation might be required
58         frag_threshold = pfirmware->cmdpacket_frag_thresold;
59         do {
60             if((buffer_len - frag_offset) > frag_threshold) {
61                 frag_length = frag_threshold ;
62                 bLastIniPkt = 0;
63
64             } else {
65                 frag_length =(u16)(buffer_len - frag_offset);
66                 bLastIniPkt = 1;
67
68             }
69
70             /* Allocate skb buffer to contain firmware info and tx descriptor info
71              * add 4 to avoid packet appending overflow.
72              * */
73             skb  = dev_alloc_skb(frag_length + priv->ieee80211->tx_headroom + 4);
74             if(skb == NULL) {
75                 rt_status = RT_STATUS_FAILURE;
76                 goto Failed;
77             }
78
79             memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
80             tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE);
81             tcb_desc->queue_index = TXCMD_QUEUE;
82             tcb_desc->bCmdOrInit = packettype;
83             tcb_desc->bLastIniPkt = bLastIniPkt;
84             tcb_desc->pkt_size = frag_length;
85
86             //seg_ptr = skb_put(skb, frag_length + priv->ieee80211->tx_headroom);
87             seg_ptr = skb_put(skb, priv->ieee80211->tx_headroom);
88
89             pTxFwInfo = (PTX_FWINFO_8190PCI)seg_ptr;
90             memset(pTxFwInfo,0,sizeof(TX_FWINFO_8190PCI));
91             memset(pTxFwInfo,0x12,8);
92
93             seg_ptr +=sizeof(TX_FWINFO_8190PCI);
94
95             /*
96              * Transform from little endian to big endian
97              * and pending  zero
98              */
99             seg_ptr = skb_tail_pointer(skb);
100             for(i=0 ; i < frag_length; i+=4) {
101                 *seg_ptr++ = ((i+0)<frag_length)?code_virtual_address[i+3]:0;
102                 *seg_ptr++ = ((i+1)<frag_length)?code_virtual_address[i+2]:0;
103                 *seg_ptr++ = ((i+2)<frag_length)?code_virtual_address[i+1]:0;
104                 *seg_ptr++ = ((i+3)<frag_length)?code_virtual_address[i+0]:0;
105             }
106             skb_put(skb, i);
107             priv->ieee80211->softmac_hard_start_xmit(skb, priv->ieee80211);
108
109             code_virtual_address += frag_length;
110             frag_offset += frag_length;
111
112         }while(frag_offset < buffer_len);
113
114 Failed:
115         return rt_status;
116 }
117
118 static void
119 cmpk_count_txstatistic(
120         struct net_device *dev,
121         cmpk_txfb_t     *pstx_fb)
122 {
123         struct r8192_priv *priv = ieee80211_priv(dev);
124 #ifdef ENABLE_PS
125         RT_RF_POWER_STATE       rtState;
126
127         pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
128
129         // When RF is off, we should not count the packet for hw/sw synchronize
130         // reason, ie. there may be a duration while sw switch is changed and hw
131         // switch is being changed. 2006.12.04, by shien chang.
132         if (rtState == eRfOff)
133         {
134                 return;
135         }
136 #endif
137
138 #ifdef TODO
139         if(pAdapter->bInHctTest)
140                 return;
141 #endif
142         /* We can not know the packet length and transmit type: broadcast or uni
143            or multicast. So the relative statistics must be collected in tx
144            feedback info. */
145         if (pstx_fb->tok)
146         {
147                 priv->stats.txoktotal++;
148
149                 /* We can not make sure broadcast/multicast or unicast mode. */
150                 if (pstx_fb->pkt_type != PACKET_MULTICAST &&
151                     pstx_fb->pkt_type != PACKET_BROADCAST) {
152                         priv->stats.txbytesunicast += pstx_fb->pkt_length;
153                 }
154         }
155 }
156
157
158
159 /*
160  * The function is responsible for extract the message inside TX
161  * feedbck message from firmware. It will contain dedicated info in
162  * ws-06-0063-rtl8190-command-packet-specification. Please
163  * refer to chapter "TX Feedback Element". We have to read 20 bytes
164  * in the command packet.
165  */
166 static void
167 cmpk_handle_tx_feedback(
168         struct net_device *dev,
169         u8      *       pmsg)
170 {
171         struct r8192_priv *priv = ieee80211_priv(dev);
172         cmpk_txfb_t             rx_tx_fb;       /* */
173
174         priv->stats.txfeedback++;
175
176         memcpy((u8*)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
177         /* Use tx feedback info to count TX statistics. */
178         cmpk_count_txstatistic(dev, &rx_tx_fb);
179 }
180
181
182 /*
183  * The function is responsible for extract the message from
184  * firmware. It will contain dedicated info in
185  * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
186  * Please refer to chapter "Interrupt Status Element".
187  */
188 static  void
189 cmpk_handle_interrupt_status(
190         struct net_device *dev,
191         u8*     pmsg)
192 {
193         cmpk_intr_sta_t         rx_intr_status; /* */
194         struct r8192_priv *priv = ieee80211_priv(dev);
195
196         DMESG("---> cmpk_Handle_Interrupt_Status()\n");
197
198         /* 1. Extract TX feedback info from RFD to temp structure buffer. */
199         /* It seems that FW use big endian(MIPS) and DRV use little endian in
200            windows OS. So we have to read the content byte by byte or transfer
201            endian type before copy the message copy. */
202         //rx_bcn_state.Element_ID       = pMsg[0];
203         //rx_bcn_state.Length           = pMsg[1];
204         rx_intr_status.length = pmsg[1];
205         if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2))
206         {
207                 DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
208                 return;
209         }
210
211
212         // Statistics of beacon for ad-hoc mode.
213         if(     priv->ieee80211->iw_mode == IW_MODE_ADHOC)
214         {
215                 //2 maybe need endian transform?
216                 rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
217                 //rx_intr_status.InterruptStatus = N2H4BYTE(*((UINT32 *)(pMsg + 4)));
218
219                 DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status);
220
221                 if (rx_intr_status.interrupt_status & ISR_TxBcnOk)
222                 {
223                         priv->ieee80211->bibsscoordinator = true;
224                         priv->stats.txbeaconokint++;
225                 }
226                 else if (rx_intr_status.interrupt_status & ISR_TxBcnErr)
227                 {
228                         priv->ieee80211->bibsscoordinator = false;
229                         priv->stats.txbeaconerr++;
230                 }
231         }
232
233          // Other informations in interrupt status we need?
234
235
236         DMESG("<---- cmpk_handle_interrupt_status()\n");
237
238 }
239
240
241 /*
242  * The function is responsible for extract the message from
243  * firmware. It will contain dedicated info in
244  * ws-06-0063-rtl8190-command-packet-specification. Please
245  * refer to chapter "Beacon State Element".
246  */
247 static  void
248 cmpk_handle_query_config_rx(
249         struct net_device *dev,
250         u8*        pmsg)
251 {
252         cmpk_query_cfg_t        rx_query_cfg;   /* */
253
254         /* 0. Display received message. */
255         //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
256
257         /* 1. Extract TX feedback info from RFD to temp structure buffer. */
258         /* It seems that FW use big endian(MIPS) and DRV use little endian in
259            windows OS. So we have to read the content byte by byte or transfer
260            endian type before copy the message copy. */
261         //rx_query_cfg.Element_ID       = pMsg[0];
262         //rx_query_cfg.Length           = pMsg[1];
263         rx_query_cfg.cfg_action         = (pmsg[4] & 0x80000000)>>31;
264         rx_query_cfg.cfg_type           = (pmsg[4] & 0x60) >> 5;
265         rx_query_cfg.cfg_size           = (pmsg[4] & 0x18) >> 3;
266         rx_query_cfg.cfg_page           = (pmsg[6] & 0x0F) >> 0;
267         rx_query_cfg.cfg_offset                 = pmsg[7];
268         rx_query_cfg.value                      = (pmsg[8] << 24) | (pmsg[9] << 16) |
269                                                                   (pmsg[10] << 8) | (pmsg[11] << 0);
270         rx_query_cfg.mask                       = (pmsg[12] << 24) | (pmsg[13] << 16) |
271                                                                   (pmsg[14] << 8) | (pmsg[15] << 0);
272
273 }
274
275
276 /*
277  * Count aggregated tx status from firmwar of one type rx command
278  * packet element id = RX_TX_STATUS.
279  */
280 static  void    cmpk_count_tx_status(   struct net_device *dev,
281                                                                         cmpk_tx_status_t        *pstx_status)
282 {
283         struct r8192_priv *priv = ieee80211_priv(dev);
284
285 #ifdef ENABLE_PS
286
287         RT_RF_POWER_STATE       rtstate;
288
289         pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
290
291         // When RF is off, we should not count the packet for hw/sw synchronize
292         // reason, ie. there may be a duration while sw switch is changed and hw
293         // switch is being changed. 2006.12.04, by shien chang.
294         if (rtState == eRfOff)
295         {
296                 return;
297         }
298 #endif
299
300         priv->stats.txfeedbackok        += pstx_status->txok;
301         priv->stats.txoktotal           += pstx_status->txok;
302
303         priv->stats.txbytesunicast              += pstx_status->txuclength;
304 }
305
306
307
308 /*
309  * Firmware add a new tx feedback status to reduce rx command
310  * packet buffer operation load.
311  */
312 static  void
313 cmpk_handle_tx_status(
314         struct net_device *dev,
315         u8*        pmsg)
316 {
317         cmpk_tx_status_t        rx_tx_sts;      /* */
318
319         memcpy((void*)&rx_tx_sts, (void*)pmsg, sizeof(cmpk_tx_status_t));
320         /* 2. Use tx feedback info to count TX statistics. */
321         cmpk_count_tx_status(dev, &rx_tx_sts);
322
323 }
324
325
326 /* Firmware add a new tx rate history */
327 static  void
328 cmpk_handle_tx_rate_history(
329         struct net_device *dev,
330         u8*        pmsg)
331 {
332         u8                              i;
333         u16                             length = sizeof(cmpk_tx_rahis_t);
334         u32                             *ptemp;
335
336 #ifdef ENABLE_PS
337         pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
338
339         // When RF is off, we should not count the packet for hw/sw synchronize
340         // reason, ie. there may be a duration while sw switch is changed and hw
341         // switch is being changed. 2006.12.04, by shien chang.
342         if (rtState == eRfOff)
343         {
344                 return;
345         }
346 #endif
347
348         ptemp = (u32 *)pmsg;
349
350         //
351         // Do endian transfer to word alignment(16 bits) for windows system.
352         // You must do different endian transfer for linux and MAC OS
353         //
354         for (i = 0; i < (length/4); i++)
355         {
356                 u16      temp1, temp2;
357
358                 temp1 = ptemp[i]&0x0000FFFF;
359                 temp2 = ptemp[i]>>16;
360                 ptemp[i] = (temp1<<16)|temp2;
361         }
362 }
363
364
365 /*
366  * In the function, we will capture different RX command packet
367  * info. Every RX command packet element has different message
368  * length and meaning in content. We only support three type of RX
369  * command packet now. Please refer to document
370  * ws-06-0063-rtl8190-command-packet-specification.
371  */
372 u32 cmpk_message_handle_rx(struct net_device *dev, struct ieee80211_rx_stats *pstats)
373 {
374 //      u32                     debug_level = DBG_LOUD;
375         int                     total_length;
376         u8                      cmd_length, exe_cnt = 0;
377         u8                      element_id;
378         u8                      *pcmd_buff;
379
380         RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx()\n");
381
382         /* 0. Check inpt arguments. If is is a command queue message or pointer is
383               null. */
384         if (/*(prfd->queue_id != CMPK_RX_QUEUE_ID) || */(pstats== NULL))
385         {
386                 /* Print error message. */
387                 /*RT_TRACE(COMP_SEND, DebugLevel,
388                                 ("\n\r[CMPK]-->Err queue id or pointer"));*/
389                 return 0;       /* This is not a command packet. */
390         }
391
392         /* 1. Read received command packet message length from RFD. */
393         total_length = pstats->Length;
394
395         /* 2. Read virtual address from RFD. */
396         pcmd_buff = pstats->virtual_address;
397
398         /* 3. Read command pakcet element id and length. */
399         element_id = pcmd_buff[0];
400         /*RT_TRACE(COMP_SEND, DebugLevel,
401                         ("\n\r[CMPK]-->element ID=%d Len=%d", element_id, total_length));*/
402
403         /* 4. Check every received command packet conent according to different
404               element type. Because FW may aggregate RX command packet to minimize
405               transmit time between DRV and FW.*/
406         // Add a counter to prevent to locked in the loop too long
407         while (total_length > 0 || exe_cnt++ >100)
408         {
409                 /* 2007/01/17 MH We support aggregation of different cmd in the same packet. */
410                 element_id = pcmd_buff[0];
411
412                 switch(element_id)
413                 {
414                         case RX_TX_FEEDBACK:
415
416                                 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_FEEDBACK\n");
417                                 cmpk_handle_tx_feedback (dev, pcmd_buff);
418                                 cmd_length = CMPK_RX_TX_FB_SIZE;
419                                 break;
420
421                         case RX_INTERRUPT_STATUS:
422
423                                 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_INTERRUPT_STATUS\n");
424                                 cmpk_handle_interrupt_status(dev, pcmd_buff);
425                                 cmd_length = sizeof(cmpk_intr_sta_t);
426                                 break;
427
428                         case BOTH_QUERY_CONFIG:
429
430                                 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():BOTH_QUERY_CONFIG\n");
431                                 cmpk_handle_query_config_rx(dev, pcmd_buff);
432                                 cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
433                                 break;
434
435                         case RX_TX_STATUS:
436
437                                 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_STATUS\n");
438                                 cmpk_handle_tx_status(dev, pcmd_buff);
439                                 cmd_length = CMPK_RX_TX_STS_SIZE;
440                                 break;
441
442                         case RX_TX_PER_PKT_FEEDBACK:
443                                 // You must at lease add a switch case element here,
444                                 // Otherwise, we will jump to default case.
445                                 //DbgPrint("CCX Test\r\n");
446                                 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_PER_PKT_FEEDBACK\n");
447                                 cmd_length = CMPK_RX_TX_FB_SIZE;
448                                 break;
449
450                         case RX_TX_RATE_HISTORY:
451                                 //DbgPrint(" rx tx rate history\r\n");
452
453                                 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_HISTORY\n");
454                                 cmpk_handle_tx_rate_history(dev, pcmd_buff);
455                                 cmd_length = CMPK_TX_RAHIS_SIZE;
456                                 break;
457
458                         default:
459
460                                 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():unknown CMD Element\n");
461                                 return 1;       /* This is a command packet. */
462                 }
463
464                 total_length -= cmd_length;
465                 pcmd_buff    += cmd_length;
466         }       /* while (total_length > 0) */
467         return  1;      /* This is a command packet. */
468
469         RT_TRACE(COMP_EVENTS, "<----cmpk_message_handle_rx()\n");
470 }