r819xU_cmdpkt.c 17 KB

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