PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/net/wireless/tiwlan1251/common/src/TNETW_Driver/FW_Transfer/Tx_Xfer/Slave_Dbl_Buf/txXfer.c

https://bitbucket.org/cyanogenmod/cm-kernel
C | 922 lines | 475 code | 152 blank | 295 comment | 46 complexity | 0da19a72781f83e65e45813e349b2695 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  1. /****************************************************************************
  2. **+-----------------------------------------------------------------------+**
  3. **| |**
  4. **| Copyright(c) 1998 - 2008 Texas Instruments. All rights reserved. |**
  5. **| All rights reserved. |**
  6. **| |**
  7. **| Redistribution and use in source and binary forms, with or without |**
  8. **| modification, are permitted provided that the following conditions |**
  9. **| are met: |**
  10. **| |**
  11. **| * Redistributions of source code must retain the above copyright |**
  12. **| notice, this list of conditions and the following disclaimer. |**
  13. **| * Redistributions in binary form must reproduce the above copyright |**
  14. **| notice, this list of conditions and the following disclaimer in |**
  15. **| the documentation and/or other materials provided with the |**
  16. **| distribution. |**
  17. **| * Neither the name Texas Instruments nor the names of its |**
  18. **| contributors may be used to endorse or promote products derived |**
  19. **| from this software without specific prior written permission. |**
  20. **| |**
  21. **| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |**
  22. **| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |**
  23. **| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |**
  24. **| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |**
  25. **| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |**
  26. **| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |**
  27. **| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |**
  28. **| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |**
  29. **| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |**
  30. **| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |**
  31. **| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |**
  32. **| |**
  33. **+-----------------------------------------------------------------------+**
  34. ****************************************************************************/
  35. /****************************************************************************
  36. *
  37. * MODULE: txXfer.c
  38. *
  39. * PURPOSE: Handle Tx frame transfer to the firmware in slave double-buffer scheme.
  40. *
  41. * DESCRIPTION:
  42. * ============
  43. * This module gets the upper driver's Tx packets after FW resources were
  44. * allocated for it, and handles its transfer to the FW double-buffer.
  45. * It can handle two packets at a time, thus providing a pipe-line behavior.
  46. * It is planned to start an asynchronous copy of one packet to the FW,
  47. * and immediately indicate the upper layer to start handling the next
  48. * packet transmission in parallel.
  49. *
  50. ****************************************************************************/
  51. #include "osTIType.h"
  52. #include "paramIn.h"
  53. #include "commonTypes.h"
  54. #include "TNETWIF.h"
  55. #include "whalCommon.h"
  56. #include "whalHwDefs.h"
  57. #include "txXfer_api.h"
  58. #include "txXfer.h" /* Local definitions */
  59. /****************************************************************************
  60. * txXfer_Create()
  61. ****************************************************************************
  62. * DESCRIPTION: Create the Xfer module object
  63. *
  64. * INPUTS: None
  65. *
  66. * OUTPUT: None
  67. *
  68. * RETURNS: The Created object
  69. ****************************************************************************/
  70. TI_HANDLE txXfer_Create(TI_HANDLE hOs)
  71. {
  72. txXferObj_t *pTxXfer;
  73. pTxXfer = os_memoryAlloc(hOs, sizeof(txXferObj_t));
  74. if (pTxXfer == NULL)
  75. {
  76. return NULL;
  77. }
  78. os_memoryZero(hOs, pTxXfer, sizeof(txXferObj_t));
  79. pTxXfer->hOs = hOs;
  80. return (TI_HANDLE)pTxXfer;
  81. }
  82. /****************************************************************************
  83. * txXfer_Destroy()
  84. ****************************************************************************
  85. * DESCRIPTION: Destroy the Xfer module object
  86. *
  87. * INPUTS: hTxXfer - The object to free
  88. *
  89. * OUTPUT: None
  90. *
  91. * RETURNS: OK or NOK
  92. ****************************************************************************/
  93. TI_STATUS txXfer_Destroy(TI_HANDLE hTxXfer)
  94. {
  95. txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
  96. if (pTxXfer)
  97. {
  98. os_memoryFree(pTxXfer->hOs, pTxXfer, sizeof(txXferObj_t));
  99. }
  100. return OK;
  101. }
  102. /****************************************************************************
  103. * txXfer_init()
  104. ****************************************************************************
  105. DESCRIPTION:
  106. ============
  107. Initialize the Xfer module.
  108. ****************************************************************************/
  109. TI_STATUS txXfer_init(TI_HANDLE hTxXfer, TI_HANDLE hReport, TI_HANDLE hTNETWIF, TI_HANDLE hTxResult)
  110. {
  111. txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
  112. pTxXfer->hReport = hReport;
  113. pTxXfer->hTNETWIF = hTNETWIF;
  114. pTxXfer->hTxResult = hTxResult;
  115. pTxXfer->sendPacketTransferCB = NULL;
  116. pTxXfer->sendPacketDebugCB = NULL;
  117. return txXfer_restart(pTxXfer);
  118. }
  119. /****************************************************************************
  120. * txXfer_config()
  121. ****************************************************************************
  122. * DESCRIPTION:
  123. * Configures the TX XFER module with initialization parameters.
  124. *
  125. * INPUTS:
  126. * hTxXfer The object
  127. * pInitParams initialization parameters values
  128. *
  129. * OUTPUT: None
  130. *
  131. * RETURNS: None
  132. ****************************************************************************/
  133. void txXfer_config(TI_HANDLE hTxXfer, TnetwDrv_InitParams_t *pInitParams)
  134. {
  135. txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
  136. pTxXfer->timeToTxStuckMs = pInitParams->txXferInitParams.timeToTxStuckMs;
  137. }
  138. /****************************************************************************
  139. * txXfer_setHwInfo()
  140. ****************************************************************************
  141. * DESCRIPTION:
  142. * Called after the HW configuration upon init or recovery.
  143. * Store the HW addresses of the Double Buffer and the Tx-status.
  144. *
  145. * INPUTS:
  146. * hTxXfer The object
  147. * pDataPathParams Pointer to the Double Buffer Address
  148. *
  149. * OUTPUT: None
  150. *
  151. * RETURNS: None
  152. ****************************************************************************/
  153. void txXfer_setHwInfo(TI_HANDLE hTxXfer, ACXDataPathParamsResp_t *pDataPathParams)
  154. {
  155. txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
  156. pTxXfer->dblBufAddr[0] = pDataPathParams->txPacketRingAddr;
  157. pTxXfer->dblBufAddr[1] = pDataPathParams->txPacketRingAddr + pDataPathParams->txPacketRingChunkSize;
  158. pTxXfer->txPathStatusAddr = pDataPathParams->txControlAddr;
  159. /* Print of the Tx double buffer address */
  160. WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
  161. ("TX DOUBLE BUFFER Addresses: Buf_0 = 0x%x, Buf_1 = 0x%x\n",
  162. pTxXfer->dblBufAddr[0], pTxXfer->dblBufAddr[1]));
  163. }
  164. /****************************************************************************
  165. * txXfer_restart()
  166. ****************************************************************************
  167. DESCRIPTION:
  168. ============
  169. Restarts the Xfer module.
  170. Should be called upon init and recovery!!
  171. ****************************************************************************/
  172. TI_STATUS txXfer_restart(TI_HANDLE hTxXfer)
  173. {
  174. txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
  175. /* Initialize module variables. */
  176. pTxXfer->txXferState = TX_XFER_STATE_IDLE;
  177. pTxXfer->numBufferedPkts = 0;
  178. pTxXfer->xferDonePostponed = FALSE;
  179. pTxXfer->bRecovery = FALSE;
  180. pTxXfer->dataInCount = 0;
  181. pTxXfer->hwStatusReadLoopCount = 0;
  182. return OK;
  183. }
  184. /****************************************************************************
  185. * txXfer_sendPacket()
  186. ****************************************************************************
  187. * DESCRIPTION:
  188. ============
  189. Handle sent packet according to the number of packets already in the Xfer buffers:
  190. If no buffered pkts:
  191. If in IDLE state, update state to WAIT_BUS and request the bus.
  192. Return SEND_PACKET_SUCCESS.
  193. If one buffered pkt, just buffer the request and return SEND_PACKET_PENDING (can't get more).
  194. If two buffered pkts, return SEND_PACKET_ERROR (not expected to get more packets).
  195. ****************************************************************************/
  196. systemStatus_e txXfer_sendPacket(TI_HANDLE hTxXfer, txCtrlBlkEntry_t *pPktCtrlBlk)
  197. {
  198. txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
  199. TI_STATUS tnetwifStatus;
  200. #ifdef TI_DBG
  201. pTxXfer->sendPacketCount++;
  202. #endif
  203. /* Handle sent packet according to the number of packets already in the Xfer buffers. */
  204. switch(pTxXfer->numBufferedPkts)
  205. {
  206. /* No buffered pkts. */
  207. case 0:
  208. pTxXfer->numBufferedPkts = 1;
  209. pTxXfer->pPktCtrlBlk[0] = pPktCtrlBlk; /* Save the first pkt Ctrl-Blk pointer. */
  210. /* If in IDLE state, update state to WAIT_BUS and request the bus. */
  211. if (pTxXfer->txXferState == TX_XFER_STATE_IDLE)
  212. {
  213. WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
  214. ("txXfer_sendPacket(): First Pkt, IDLE-STATE, Start Bus-Wait\n"));
  215. /* Note: Update the Xfer-SM state before calling the TNETWIF because it will call the
  216. SM immediately if the bus is available. */
  217. pTxXfer->txXferState = TX_XFER_STATE_WAIT_BUS;
  218. /* Set to detect if the Xfer proces is completed in this context (returns XFER_DONE). */
  219. pTxXfer->syncXferIndication = TRUE;
  220. tnetwifStatus = TNETWIF_Start(pTxXfer->hTNETWIF, TX_XFER_MODULE_ID, pTxXfer, xferStateMachine);
  221. if (pTxXfer->bRecovery)
  222. return SEND_PACKET_RECOVERY;
  223. #ifdef TI_DBG
  224. if (tnetwifStatus == TNETWIF_COMPLETE)
  225. {
  226. pTxXfer->busStartSyncCount++;
  227. }
  228. else if (tnetwifStatus == TNETWIF_PENDING)
  229. {
  230. pTxXfer->busStartAsyncCount++;
  231. }
  232. else
  233. {
  234. WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
  235. ("txXfer_sendPacket(): TNETWIF_Start returned error=%d\n", tnetwifStatus));
  236. }
  237. #endif
  238. /* If the Xfer was completed in this context (Synchronous), return XFER_DONE. */
  239. /* Note: In this case xferDone callback will not be called! */
  240. if (pTxXfer->syncXferIndication)
  241. {
  242. pTxXfer->syncXferIndication = FALSE;
  243. if (tnetwifStatus == TNETWIF_COMPLETE) /* The SM was called from the Start function. */
  244. {
  245. #ifdef TI_DBG
  246. pTxXfer->xferDoneSyncCount++;
  247. WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
  248. ("txXfer_sendPacket(): Xfer Completed in upper driver context\n"));
  249. #endif
  250. return SEND_PACKET_XFER_DONE; /* Xfer can get another packet. */
  251. }
  252. }
  253. }
  254. else
  255. {
  256. WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
  257. ("txXfer_sendPacket(): First Pkt, not IDLE-STATE, XferState=%d\n", pTxXfer->txXferState));
  258. }
  259. /* If the Xfer wasn't completed in this context (Asynchronous), return SUCCESS
  260. (xferDone callback will be called). */
  261. return SEND_PACKET_SUCCESS; /* Xfer can get another packet. */
  262. /* If one buffered pkt, just buffer the request and return SEND_PACKET_PENDING (can't get more). */
  263. case 1:
  264. if (pTxXfer->bRecovery)
  265. {
  266. return SEND_PACKET_RECOVERY;
  267. }
  268. else
  269. {
  270. WLAN_REPORT_INFORMATION (pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
  271. ("txXfer_sendPacket(): Second Pkt Buffered, XferState=%d\n", pTxXfer->txXferState));
  272. pTxXfer->numBufferedPkts = 2; /* We now have two packets handled in the Xfer. */
  273. pTxXfer->pPktCtrlBlk[1] = pPktCtrlBlk; /* Save the second pkt Ctrl-Blk pointer. */
  274. return SEND_PACKET_PENDING; /* Xfer can't get further packets. */
  275. }
  276. /* If two buffered pkts, return SEND_PACKET_ERROR (not expected to get more packets). */
  277. default:
  278. WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
  279. ("txXfer_sendPacket(): Two Pkts Allready Buffered, XferState=%d, xferDonePostponed=%d, numPkts=%d\n",
  280. pTxXfer->txXferState, pTxXfer->xferDonePostponed, pTxXfer->numBufferedPkts));
  281. return SEND_PACKET_ERROR;
  282. }
  283. }
  284. #define MAX_RECOVERY_LOOPS 1000
  285. /****************************************************************************
  286. * xferStateMachine()
  287. ****************************************************************************
  288. * DESCRIPTION:
  289. ============
  290. This is the Xfer process state machine.
  291. It handles the transfer of packets sent by the upper driver to the HW via TNETWIF.
  292. The SM supports both Sync and Async accesses to the HW.
  293. It loops and progresses from state to state as long as the HW is accessed synchronously.
  294. Once the access is Asynchronous (TNETWIF_PENDING), it exits and is called later
  295. by the TNETWIF when the HW is ready.
  296. That's why it uses only unspecified-mode accesses (e.g. TNETWIF_ReadMemOpt) which
  297. selects either Sync or Async automatically according to the platform.
  298. When the SM is active (not in IDLE state), it has either one or two packets buffered.
  299. This enables (in Async access) pipeline behavior, where one packet is transfered to
  300. the HW, and the other is being processed from the upper driver to the Xfer in parallel.
  301. The SM steps are:
  302. =================
  303. Event: Send-Pkt Bus-Ready HW-Buffer-Ready Xfer-Done Trigger-Done
  304. | | | | |
  305. V V V V V
  306. State: IDLE ----> WAIT_BUS ----> WAIT_HW_BUFFER ----> WAIT_XFER_DONE ----> WAIT_TRIGGER_DONE ----> IDLE
  307. | |
  308. | |
  309. <---------<---------<---------<---------<---------<----------
  310. Pending-Packet (*)
  311. (*) When a packet transfer is finished but another packet is already waiting in the Xfer
  312. for processing, the Xfer will postpone the Xfer-Done indication of the first packet
  313. until it has started the second one's transfer to the HW.
  314. It will request "Bus Restart" in order to prevent nesting and enable bus allocation
  315. to other tasks.
  316. ****************************************************************************/
  317. static void xferStateMachine(TI_HANDLE hTxXfer, UINT8 module_id, TI_STATUS status)
  318. {
  319. txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
  320. TI_STATUS tnetwifStatus;
  321. #ifdef TI_DBG
  322. if (hTxXfer == NULL)
  323. {
  324. WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
  325. ("xferStateMachine(): **** Called with NULL handle!! ****\n"));
  326. return;
  327. }
  328. #endif
  329. /*
  330. * Loop through the states sequence as long as the process is synchronous.
  331. * Exit when finished or if an Asynchronous process is required. In this case
  332. * the SM process will be resumed later (called back by TNETWIF).
  333. */
  334. while (1)
  335. {
  336. switch (pTxXfer->txXferState)
  337. {
  338. case TX_XFER_STATE_WAIT_BUS:
  339. /* Call debug callback */
  340. if (pTxXfer->sendPacketDebugCB)
  341. {
  342. pTxXfer->sendPacketDebugCB (pTxXfer->sendPacketDebugHandle,
  343. pTxXfer->pPktCtrlBlk[0],
  344. pTxXfer->txXferState);
  345. }
  346. /* We now own the bus, so request to read HW-Tx-Status and go to WAIT_HW_BUFFER state. */
  347. pTxXfer->txXferState = TX_XFER_STATE_WAIT_HW_BUFFER;
  348. /* also mark the time at which the first attemot is done */
  349. pTxXfer->TimeStampFirstHwBufferRead = os_timeStampMs( pTxXfer->hOs );
  350. tnetwifStatus = TNETWIF_ReadMemOpt (pTxXfer->hTNETWIF,
  351. pTxXfer->txPathStatusAddr,
  352. PADREAD (&pTxXfer->hwTxPathStatusRead),
  353. sizeof(UINT32),
  354. TX_XFER_MODULE_ID,
  355. xferStateMachine,
  356. pTxXfer);
  357. break;
  358. case TX_XFER_STATE_WAIT_HW_BUFFER:
  359. /* Call debug callback */
  360. if (pTxXfer->sendPacketDebugCB)
  361. {
  362. pTxXfer->sendPacketDebugCB (pTxXfer->sendPacketDebugHandle,
  363. pTxXfer->pPktCtrlBlk[0],
  364. pTxXfer->txXferState);
  365. }
  366. /* We now have the HW-Tx-Status read, so check if there are HW buffers available. */
  367. if (hwBuffersOccupied(pTxXfer) < DP_TX_PACKET_RING_CHUNK_NUM)
  368. {
  369. /* Handle actual packet transfer to HW buffer. */
  370. tnetwifStatus = transferPacket(pTxXfer);
  371. pTxXfer->txXferState = TX_XFER_STATE_WAIT_XFER_DONE;
  372. /*
  373. * If we've postponed the Xfer-Done callback of the previous transfered
  374. * packet, call it now in parallel with the Xfer of the current packet.
  375. * Note that all variables are updated before calling the XferDone, since
  376. * it may be used to send another packet.
  377. * The current transfered packet pointer is moved to the first buffer.
  378. */
  379. if (pTxXfer->xferDonePostponed)
  380. {
  381. txCtrlBlkEntry_t *pPostponedPktCtrlBlk = pTxXfer->pPktCtrlBlk[0];
  382. pTxXfer->numBufferedPkts = 1;
  383. pTxXfer->pPktCtrlBlk[0] = pTxXfer->pPktCtrlBlk[1];
  384. pTxXfer->xferDonePostponed = FALSE;
  385. pTxXfer->sendPacketTransferCB(pTxXfer->sendPacketTransferHandle, pPostponedPktCtrlBlk);
  386. #ifdef TI_DBG
  387. pTxXfer->xferDoneCallCBCount++;
  388. #endif
  389. }
  390. pTxXfer->hwStatusReadLoopCount = 0;
  391. #ifdef TI_DBG
  392. pTxXfer->hwBufferReadCount++;
  393. #endif
  394. }
  395. /* If HW buffer isn't available, try reading the status again (loop on same state). */
  396. else
  397. {
  398. tnetwifStatus = TNETWIF_ReadMemOpt (pTxXfer->hTNETWIF,
  399. pTxXfer->txPathStatusAddr,
  400. PADREAD (&pTxXfer->hwTxPathStatusRead),
  401. sizeof(UINT32),
  402. TX_XFER_MODULE_ID,
  403. xferStateMachine,
  404. pTxXfer);
  405. #ifdef TI_DBG
  406. /* For Debug: Update counters */
  407. pTxXfer->hwBufferFullCount++;
  408. pTxXfer->hwBufferReadCount++;
  409. #endif
  410. /* Detect endless loop and perform recovery if needed */
  411. pTxXfer->hwStatusReadLoopCount++;
  412. if (os_timeStampMs (pTxXfer->hOs) - pTxXfer->TimeStampFirstHwBufferRead >
  413. pTxXfer->timeToTxStuckMs)
  414. {
  415. WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
  416. ("xferStateMachine(): Looping too long for Tx-Status, LastTxStatus=%d\n",
  417. pTxXfer->hwTxPathStatusRead));
  418. WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
  419. ("Loop count=%d, First time stamp:%d, current time stamp:%d\n",
  420. pTxXfer->hwStatusReadLoopCount, pTxXfer->TimeStampFirstHwBufferRead,
  421. os_timeStampMs( pTxXfer->hOs )) );
  422. #ifdef USE_RECOVERY
  423. pTxXfer->bRecovery = TRUE;
  424. /* Error Reporting - if after a configurable interval we could not
  425. transfer data a recovery will be called */
  426. if (pTxXfer->failureEventFunc)
  427. {
  428. pTxXfer->failureEventFunc(pTxXfer->failureEventObj, TX_STUCK);
  429. }
  430. return;
  431. #endif
  432. }
  433. }
  434. break;
  435. case TX_XFER_STATE_WAIT_XFER_DONE:
  436. /* Call debug callback */
  437. if (pTxXfer->sendPacketDebugCB)
  438. {
  439. pTxXfer->sendPacketDebugCB (pTxXfer->sendPacketDebugHandle,
  440. pTxXfer->pPktCtrlBlk[0],
  441. pTxXfer->txXferState);
  442. }
  443. /* Now the last packet transfer to the HW is finished, so we issue a trigger to the FW. */
  444. {
  445. UINT32 txInterruptRegAddress;
  446. UINT32 txInterruptRegData;
  447. /* Set the Tx-interrupt address and value according to the
  448. HW buffer used for the last transfer. */
  449. if (pTxXfer->dataInCount & 0x1)
  450. {
  451. txInterruptRegAddress = ACX_REG_INTERRUPT_TRIG_H;
  452. txInterruptRegData = INTR_TRIG_TX_PROC1;
  453. }
  454. else
  455. {
  456. txInterruptRegAddress = ACX_REG_INTERRUPT_TRIG;
  457. txInterruptRegData = INTR_TRIG_TX_PROC0;
  458. }
  459. /* Call debug callback */
  460. if (pTxXfer->sendPacketDebugCB)
  461. {
  462. pTxXfer->sendPacketDebugCB (pTxXfer->sendPacketDebugHandle,
  463. pTxXfer->pPktCtrlBlk[0],
  464. 0);
  465. }
  466. /* Issue the Tx interrupt trigger to the FW. */
  467. tnetwifStatus = TNETWIF_WriteRegOpt(pTxXfer->hTNETWIF,
  468. txInterruptRegAddress,
  469. txInterruptRegData,
  470. TX_XFER_MODULE_ID,
  471. xferStateMachine,
  472. pTxXfer);
  473. /* Increment the transfered packets counter modulo 16 (as FW data-out counter). */
  474. pTxXfer->dataInCount = (pTxXfer->dataInCount + 1) & TX_STATUS_DATA_OUT_COUNT_MASK;
  475. pTxXfer->txXferState = TX_XFER_STATE_WAIT_TRIGGER_DONE;
  476. }
  477. break;
  478. case TX_XFER_STATE_WAIT_TRIGGER_DONE:
  479. /* Call debug callback */
  480. if (pTxXfer->sendPacketDebugCB)
  481. {
  482. pTxXfer->sendPacketDebugCB (pTxXfer->sendPacketDebugHandle,
  483. pTxXfer->pPktCtrlBlk[0],
  484. pTxXfer->txXferState);
  485. }
  486. /* Now the HW Tx trigger is done so we can continue to the next packet if waiting. */
  487. /* If we don't have another packet pending for transfer. */
  488. if (pTxXfer->numBufferedPkts == 1)
  489. {
  490. pTxXfer->numBufferedPkts = 0;
  491. /*
  492. * Call the XferDone callback, but only if we are not in the original
  493. * SendPacket context (i.e. completely synchronous).
  494. * This is to avoid nesting, since the callback may start another SendPacket.
  495. */
  496. if (!pTxXfer->syncXferIndication)
  497. {
  498. #ifdef TI_DBG
  499. pTxXfer->xferDoneCallCBCount++;
  500. WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
  501. ("sendPacketTransferCB: CB_Func=0x%x, CB_Handle=0x%x\n",
  502. pTxXfer->sendPacketTransferCB, pTxXfer->sendPacketTransferHandle));
  503. #endif
  504. pTxXfer->sendPacketTransferCB(pTxXfer->sendPacketTransferHandle, pTxXfer->pPktCtrlBlk[0]);
  505. }
  506. /* If still no packet was sent, release bus (Finish), set IDLE state and exit. */
  507. if (pTxXfer->numBufferedPkts == 0)
  508. {
  509. pTxXfer->txXferState = TX_XFER_STATE_IDLE;
  510. TNETWIF_Finish (pTxXfer->hTNETWIF, TX_XFER_MODULE_ID, pTxXfer, NULL);
  511. WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
  512. ("txXferSM Finished -> IDLE: NumPkts=%d, XferDonePostponed=%d, SyncIndication=%d\n",
  513. pTxXfer->numBufferedPkts, pTxXfer->xferDonePostponed, pTxXfer->syncXferIndication));
  514. return; /************ Exit State Machine (back to IDLE) ************/
  515. }
  516. /*
  517. * A new packet was sent (in XferDone callback), so request the bus again using Restart.
  518. * This will call the SM later, and start the process again from WAIT_BUS state.
  519. */
  520. else
  521. {
  522. pTxXfer->txXferState = TX_XFER_STATE_WAIT_BUS;
  523. tnetwifStatus = TNETWIF_Restart(pTxXfer->hTNETWIF, TX_XFER_MODULE_ID, pTxXfer, xferStateMachine);
  524. #ifdef TI_DBG
  525. pTxXfer->busRestartCount++;
  526. #endif
  527. }
  528. }
  529. /*
  530. * We have another packet pending.
  531. * So to enable parallel processing, we postpone the XferDone callback (just set flag).
  532. * Thus, we'll start first the new packet transfer and only than call the postponed
  533. * XferDone (see WAIT_HW_BUFFER state), which may start another SendPacket in
  534. * parallel to the HW transfer.
  535. * Note that we request the bus again using Restart (to avoid nesting or bus starvation).
  536. * This will call the SM later, and start the process again from WAIT_BUS state.
  537. */
  538. else
  539. {
  540. pTxXfer->xferDonePostponed = TRUE;
  541. pTxXfer->txXferState = TX_XFER_STATE_WAIT_BUS;
  542. tnetwifStatus = TNETWIF_Restart(pTxXfer->hTNETWIF, TX_XFER_MODULE_ID, pTxXfer, xferStateMachine);
  543. #ifdef TI_DBG
  544. pTxXfer->busRestartCount++;
  545. pTxXfer->xferDonePostponeCount++;
  546. #endif
  547. }
  548. break;
  549. default:
  550. WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
  551. ("xferStateMachine(): Unexpected state, txXferState=%d, NumPkts=%d\n",
  552. pTxXfer->txXferState, pTxXfer->numBufferedPkts));
  553. return;
  554. } /* switch (pTxXfer->txXferState) */
  555. WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
  556. ("txXferSM(): SmState=%d, NumPkts=%d, XferDonePostponed=%d, TnetwIfStatus=%d, SyncIndication=%d, HwTxStatus=0x%x, DataInCount=0x%x\n",
  557. pTxXfer->txXferState, pTxXfer->numBufferedPkts, pTxXfer->xferDonePostponed,
  558. tnetwifStatus, pTxXfer->syncXferIndication, pTxXfer->hwTxPathStatusRead, pTxXfer->dataInCount));
  559. /*
  560. * If the last HW access request was pended, exit the SM (Asynchronous process).
  561. * The SM will be called back when the HW access is done.
  562. * Also reset the Sync flag to notify that the Xfer wasn't completed in the SendPacket context.
  563. */
  564. if (tnetwifStatus == TNETWIF_PENDING)
  565. {
  566. pTxXfer->syncXferIndication = FALSE;
  567. return; /********** Exit State Machine (to be called back by TNETWIF) **********/
  568. }
  569. #ifdef TI_DBG
  570. else if (tnetwifStatus == TNETWIF_ERROR)
  571. {
  572. WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
  573. ("txXferSM TNETWIF_ERROR: SmState=%d, NumPkts=%d, XferDonePostponed=%d, TnetwIfStatus=%d, SyncIndication=%d, HwTxStatus=0x%x, DataInCount=0x%x\n",
  574. pTxXfer->txXferState, pTxXfer->numBufferedPkts, pTxXfer->xferDonePostponed,
  575. tnetwifStatus, pTxXfer->syncXferIndication, pTxXfer->hwTxPathStatusRead, pTxXfer->dataInCount));
  576. return;
  577. }
  578. #endif
  579. } /* while (1) */
  580. }
  581. /****************************************************************************
  582. * hwBuffersOccupied()
  583. ****************************************************************************
  584. * DESCRIPTION:
  585. ============
  586. Return the number of occupied buffers in the HW Tx double buffer, based on
  587. the last read of the HW Tx path status.
  588. ****************************************************************************/
  589. static UINT32 hwBuffersOccupied(txXferObj_t *pTxXfer)
  590. {
  591. UINT32 dataOutCount = pTxXfer->hwTxPathStatusRead & TX_STATUS_DATA_OUT_COUNT_MASK;
  592. /* Return the difference between the packets transfered to the double buffer (by host)
  593. and the packets copied from it (by FW). The else is for counter wrap around. */
  594. if (pTxXfer->dataInCount >= dataOutCount)
  595. {
  596. return pTxXfer->dataInCount - dataOutCount;
  597. }
  598. else
  599. {
  600. return pTxXfer->dataInCount + TX_STATUS_DATA_OUT_COUNT_MASK + 1 - dataOutCount;
  601. }
  602. }
  603. /****************************************************************************
  604. * transferPacket()
  605. ****************************************************************************
  606. * DESCRIPTION:
  607. ============
  608. Handle the current packet transfer to the HW Tx double buffer.
  609. Return the transfer status:
  610. TNETWIF_COMPLETE - if completed, i.e. Synchronous mode.
  611. TNETWIF_PENDING - if pending, i.e. Asynchronous mode (callback function will be called).
  612. If the packet was pending during disconnect, notify the TxResult to issue Tx-Complete,
  613. and return TNETWIF_COMPLETE, since we don't transfer it to the FW.
  614. ****************************************************************************/
  615. static TI_STATUS transferPacket(txXferObj_t *pTxXfer)
  616. {
  617. UINT16 XferLength; /* The actual length of the transfer. */
  618. txCtrlBlkEntry_t *pPktCtrlBlk; /* The packet control block pointer. */
  619. TI_STATUS status;
  620. /* Get the current packet control-block pointer. If we've postponed the last packet Xfer-Done (i.e.
  621. was transfered but still buffered) than our current packet is the second one. */
  622. pPktCtrlBlk = pTxXfer->pPktCtrlBlk[ ((pTxXfer->xferDonePostponed) ? 1 : 0) ];
  623. /* Get the packet length, add descriptor length and align upward to 32 bit. */
  624. XferLength = (pPktCtrlBlk->txDescriptor.length + sizeof(DbTescriptor) + ALIGN_32BIT_MASK) & ~ALIGN_32BIT_MASK;
  625. /* Initiate the packet transfer. The status indicates if Sync or Async mode was used!! */
  626. status = TNETWIF_WriteMemOpt (pTxXfer->hTNETWIF,
  627. pTxXfer->dblBufAddr[pTxXfer->dataInCount & 0x1],
  628. (UINT8 *)(pPktCtrlBlk->txPktParams.pFrame),
  629. XferLength,
  630. TX_XFER_MODULE_ID,
  631. xferStateMachine,
  632. pTxXfer);
  633. #ifdef TI_DBG
  634. WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
  635. ("transferPacket(): Status=%d, XferLength=%d, DataInCount=0x%x, pPktCtrlBlk=0x%x, dbgPktSeqNum=%d, Expiry=%d\n",
  636. status, XferLength, pTxXfer->dataInCount, pPktCtrlBlk, pPktCtrlBlk->txPktParams.dbgPktSeqNum,
  637. pPktCtrlBlk->txDescriptor.expiryTime));
  638. if (status == TNETWIF_COMPLETE)
  639. {
  640. pTxXfer->pktTransferSyncCount++;
  641. }
  642. else if (status == TNETWIF_PENDING)
  643. {
  644. pTxXfer->pktTransferAsyncCount++;
  645. }
  646. else
  647. {
  648. WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
  649. ("transferPacket - TNETWIF_ERROR: Status=%d, XferLength=%d, DataInCount=0x%x, pPktCtrlBlk=0x%x, dbgPktSeqNum=%d, Expiry=%d\n",
  650. status, XferLength, pTxXfer->dataInCount, pPktCtrlBlk, pPktCtrlBlk->txPktParams.dbgPktSeqNum,
  651. pPktCtrlBlk->txDescriptor.expiryTime));
  652. }
  653. #endif
  654. /* Return the transfer status:
  655. TNETWIF_COMPLETE - if completed, i.e. Synchronous mode.
  656. TNETWIF_PENDING - if pending, i.e. Asynchronous mode (callback function will be called).
  657. */
  658. return status;
  659. }
  660. /****************************************************************************
  661. * txXfer_RegisterCB()
  662. ****************************************************************************
  663. * DESCRIPTION: Register the upper driver Xfer callback functions.
  664. ****************************************************************************/
  665. void txXfer_RegisterCB(TI_HANDLE hTxXfer, tiUINT32 CallBackID, void *CBFunc, TI_HANDLE CBObj)
  666. {
  667. txXferObj_t* pTxXfer = (txXferObj_t*)hTxXfer;
  668. WLAN_REPORT_INFORMATION(pTxXfer->hReport, TNETW_XFER_MODULE_LOG,
  669. ("txXfer_RegisterCB(): CallBackID=%d, CBFunc=0x%x, CBObj=0x%x\n", CallBackID, CBFunc, CBObj));
  670. switch(CallBackID)
  671. {
  672. /* Set Transfer-Done callback */
  673. case TX_XFER_SEND_PKT_TRANSFER:
  674. pTxXfer->sendPacketTransferCB = (SendPacketTranferCB_t)CBFunc;
  675. pTxXfer->sendPacketTransferHandle = CBObj;
  676. break;
  677. case TX_XFER_SEND_PKT_DEBUG:
  678. pTxXfer->sendPacketDebugCB = (SendPacketDebugCB_t)CBFunc;
  679. pTxXfer->sendPacketDebugHandle = CBObj;
  680. break;
  681. default:
  682. WLAN_REPORT_ERROR(pTxXfer->hReport, TNETW_XFER_MODULE_LOG, ("txXfer_RegisterCB - Illegal value\n"));
  683. break;
  684. }
  685. }
  686. /****************************************************************************************
  687. * txXfer_RegisterFailureEventCB *
  688. ****************************************************************************************
  689. DESCRIPTION: Registers a failure event callback for scan error notifications.
  690. INPUT: - hTxXfer - handle to the xfer object.
  691. - failureEventCB - the failure event callback function.\n
  692. - hFailureEventObj - handle to the object passed to the failure event callback function.
  693. OUTPUT:
  694. RETURN: void.
  695. ****************************************************************************************/
  696. void txXfer_RegisterFailureEventCB( TI_HANDLE hTxXfer,
  697. void * failureEventCB, TI_HANDLE hFailureEventObj )
  698. {
  699. txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
  700. pTxXfer->failureEventFunc = (failureEventCB_t)failureEventCB;
  701. pTxXfer->failureEventObj = hFailureEventObj;
  702. }
  703. /****************************************************************************
  704. * txXfer_printInfo()
  705. ****************************************************************************
  706. * DESCRIPTION: Print the txXfer object main fields.
  707. ****************************************************************************/
  708. void txXfer_printInfo(TI_HANDLE hTxXfer)
  709. {
  710. #ifdef TI_DBG
  711. txXferObj_t *pTxXfer = (txXferObj_t *)hTxXfer;
  712. WLAN_OS_REPORT(("Tx-Xfer Module Information:\n"));
  713. WLAN_OS_REPORT(("===========================\n"));
  714. switch (pTxXfer->txXferState)
  715. {
  716. case TX_XFER_STATE_IDLE:
  717. WLAN_OS_REPORT(("State = IDLE\n"));
  718. break;
  719. case TX_XFER_STATE_WAIT_BUS:
  720. WLAN_OS_REPORT(("State = WAIT_BUS\n"));
  721. break;
  722. case TX_XFER_STATE_WAIT_HW_BUFFER:
  723. WLAN_OS_REPORT(("State = WAIT_HW_BUFFER\n"));
  724. break;
  725. case TX_XFER_STATE_WAIT_XFER_DONE:
  726. WLAN_OS_REPORT(("State = WAIT_XFER_DONE\n"));
  727. break;
  728. case TX_XFER_STATE_WAIT_TRIGGER_DONE:
  729. WLAN_OS_REPORT(("State = WAIT_TRIGGER_DONE\n"));
  730. break;
  731. default:
  732. WLAN_OS_REPORT(("State = UNKNOWN !!\n"));
  733. break;
  734. }
  735. WLAN_OS_REPORT(("numBufferedPkts = %d\n", pTxXfer->numBufferedPkts));
  736. WLAN_OS_REPORT(("xferDonePostponed = %d\n", pTxXfer->xferDonePostponed));
  737. WLAN_OS_REPORT(("syncXferIndication = %d\n", pTxXfer->syncXferIndication));
  738. WLAN_OS_REPORT(("pPktCtrlBlk[0] = 0x%x\n", pTxXfer->pPktCtrlBlk[0]));
  739. WLAN_OS_REPORT(("pPktCtrlBlk[1] = 0x%x\n", pTxXfer->pPktCtrlBlk[1]));
  740. WLAN_OS_REPORT(("hwTxPathStatusRead = 0x%x\n", pTxXfer->hwTxPathStatusRead));
  741. WLAN_OS_REPORT(("dataInCount = 0x%x\n", pTxXfer->dataInCount));
  742. WLAN_OS_REPORT(("txPathStatusAddr = 0x%x\n", pTxXfer->txPathStatusAddr));
  743. WLAN_OS_REPORT(("dblBufAddr[0] = 0x%x\n", pTxXfer->dblBufAddr[0]));
  744. WLAN_OS_REPORT(("dblBufAddr[1] = 0x%x\n\n", pTxXfer->dblBufAddr[1]));
  745. WLAN_OS_REPORT(("hwBufferReadCount = %d\n", pTxXfer->hwBufferReadCount));
  746. WLAN_OS_REPORT(("hwBufferFullCount = %d\n", pTxXfer->hwBufferFullCount));
  747. WLAN_OS_REPORT(("sendPacketCount = %d\n", pTxXfer->sendPacketCount));
  748. WLAN_OS_REPORT(("busStartSyncCount = %d\n", pTxXfer->busStartSyncCount));
  749. WLAN_OS_REPORT(("busStartAsyncCount = %d\n", pTxXfer->busStartAsyncCount));
  750. WLAN_OS_REPORT(("pktTransferSyncCount = %d\n", pTxXfer->pktTransferSyncCount));
  751. WLAN_OS_REPORT(("pktTransferAsyncCount = %d\n", pTxXfer->pktTransferAsyncCount));
  752. WLAN_OS_REPORT(("busRestartCount = %d\n", pTxXfer->busRestartCount));
  753. WLAN_OS_REPORT(("xferDonePostponeCount = %d\n", pTxXfer->xferDonePostponeCount));
  754. WLAN_OS_REPORT(("xferDoneSyncCount = %d\n", pTxXfer->xferDoneSyncCount));
  755. WLAN_OS_REPORT(("xferDoneCallCBCount = %d\n", pTxXfer->xferDoneCallCBCount));
  756. #endif /* TI_DBG */
  757. }