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