r819xU_cmdpkt.c revision f6150b40e9a4426aaa819ca0736f8db8af3c4a75
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 29rt_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 *---------------------------------------------------------------------------*/ 79static 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 *---------------------------------------------------------------------------*/ 161static 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 183void 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 *---------------------------------------------------------------------------*/ 227static 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 *---------------------------------------------------------------------------*/ 293static 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 *---------------------------------------------------------------------------*/ 332static 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 *---------------------------------------------------------------------------*/ 395static 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 *---------------------------------------------------------------------------*/ 422static 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 *---------------------------------------------------------------------------*/ 495extern 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} 571