1 /*
2 * txXfer.c
3 *
4 * Copyright(c) 1998 - 2009 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 /** \file txXfer.c
36 * \brief Handle Tx packets transfer to the firmware.
37 *
38 * This module gets the upper driver's Tx packets after FW resources were
39 * allocated for them, aggregates them if possible, and handles their transfer
40 * to the FW via the host slave (indirect) interface, using the TwIf Transaction API.
41 * The aggregation processing is completed by the BusDrv where the packets are combined
42 * and sent to the FW in one transaction.
43 *
44 * \see
45 */
46
47
48 #define __FILE_ID__ FILE_ID_108
49 #include "tidef.h"
50 #include "osApi.h"
51 #include "report.h"
52 #include "TwIf.h"
53 #include "TWDriver.h"
54 #include "txXfer_api.h"
55
56
57 #ifdef TI_DBG
58 #define DBG_MAX_AGGREG_PKTS 16
59 #endif
60
61 typedef struct
62 {
63 TTxnStruct tTxnStruct;
64 TI_UINT32 uPktsCntr;
65 } TPktsCntrTxn;
66
67 /* The TxXfer module object. */
68 typedef struct
69 {
70 TI_HANDLE hOs;
71 TI_HANDLE hReport;
72 TI_HANDLE hTwIf;
73
74 TI_UINT32 uAggregMaxPkts; /* Max number of packets that may be aggregated */
75 TI_UINT32 uAggregMaxLen; /* Max length in bytes of a single aggregation */
76 TI_UINT32 uAggregPktsNum; /* Number of packets in current aggregation */
77 TI_UINT32 uAggregPktsLen; /* Aggregated length of current aggregation */
78 TTxCtrlBlk * pAggregFirstPkt; /* Pointer to the first packet of current aggregation */
79 TTxCtrlBlk * pAggregLastPkt; /* Pointer to the last packet of current aggregation */
80 TSendPacketTranferCb fSendPacketTransferCb; /* Upper layer Xfer-Complete callback */
81 TI_HANDLE hSendPacketTransferHndl; /* Upper layer Xfer-Complete callback handle */
82 TTxnDoneCb fXferCompleteLocalCb; /* TxXfer local CB for pkt transfer completion (NULL is not needed!) */
83 TI_UINT32 uPktsCntr; /* Counts all Tx packets. Written to FW after each packet transaction */
84 TI_UINT32 uPktsCntrTxnIndex; /* The current indext of the aPktsCntrTxn[] used for the counter workaround transactions */
85 TPktsCntrTxn aPktsCntrTxn[CTRL_BLK_ENTRIES_NUM]; /* Transaction structures for sending the packets counter */
86 #ifdef TI_DBG
87 TI_UINT32 aDbgCountPktAggreg[DBG_MAX_AGGREG_PKTS];
88 #endif
89
90 } TTxXferObj;
91
92 static ETxnStatus txXfer_SendAggregatedPkts (TTxXferObj *pTxXfer, TI_BOOL bLastPktSentNow);
93 static void txXfer_TransferDoneCb (TI_HANDLE hTxXfer, TTxnStruct *pTxn);
94
95
96 /********************************************************************************
97 * *
98 * PUBLIC FUNCTIONS IMPLEMENTATION *
99 * *
100 *********************************************************************************/
101
102
txXfer_Create(TI_HANDLE hOs)103 TI_HANDLE txXfer_Create(TI_HANDLE hOs)
104 {
105 TTxXferObj *pTxXfer;
106
107 pTxXfer = os_memoryAlloc (hOs, sizeof(TTxXferObj));
108 if (pTxXfer == NULL)
109 {
110 return NULL;
111 }
112
113 os_memoryZero (hOs, pTxXfer, sizeof(TTxXferObj));
114
115 pTxXfer->hOs = hOs;
116
117 return (TI_HANDLE)pTxXfer;
118 }
119
120
txXfer_Destroy(TI_HANDLE hTxXfer)121 TI_STATUS txXfer_Destroy(TI_HANDLE hTxXfer)
122 {
123 TTxXferObj *pTxXfer = (TTxXferObj *)hTxXfer;
124
125 if (pTxXfer)
126 {
127 os_memoryFree (pTxXfer->hOs, pTxXfer, sizeof(TTxXferObj));
128 }
129
130 return TI_OK;
131 }
132
133
txXfer_Init(TI_HANDLE hTxXfer,TI_HANDLE hReport,TI_HANDLE hTwIf)134 TI_STATUS txXfer_Init (TI_HANDLE hTxXfer, TI_HANDLE hReport, TI_HANDLE hTwIf)
135 {
136 TTxXferObj *pTxXfer = (TTxXferObj *)hTxXfer;
137 TTxnStruct *pTxn;
138 TI_UINT8 i;
139
140 pTxXfer->hReport = hReport;
141 pTxXfer->hTwIf = hTwIf;
142 pTxXfer->fSendPacketTransferCb = NULL;
143 pTxXfer->fXferCompleteLocalCb = NULL;
144
145 for (i = 0; i < CTRL_BLK_ENTRIES_NUM; i++)
146 {
147 pTxn = &(pTxXfer->aPktsCntrTxn[i].tTxnStruct);
148 TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR)
149 BUILD_TTxnStruct(pTxn, HOST_WR_ACCESS_REG, &pTxXfer->aPktsCntrTxn[i].uPktsCntr, REGISTER_SIZE, NULL, NULL)
150 }
151
152 return txXfer_Restart(hTxXfer);
153 }
154
155
txXfer_Restart(TI_HANDLE hTxXfer)156 TI_STATUS txXfer_Restart (TI_HANDLE hTxXfer)
157 {
158 TTxXferObj *pTxXfer = (TTxXferObj *)hTxXfer;
159
160 pTxXfer->uPktsCntr = 0;
161 pTxXfer->uPktsCntrTxnIndex = 0;
162 pTxXfer->uAggregPktsNum = 0;
163
164 return TI_OK;
165 }
166
167
txXfer_SetDefaults(TI_HANDLE hTxXfer,TTwdInitParams * pInitParams)168 void txXfer_SetDefaults (TI_HANDLE hTxXfer, TTwdInitParams *pInitParams)
169 {
170 TTxXferObj *pTxXfer = (TTxXferObj *)hTxXfer;
171
172 pTxXfer->uAggregMaxPkts = pInitParams->tGeneral.uTxAggregPktsLimit;
173 }
174
175
txXfer_SetBusParams(TI_HANDLE hTxXfer,TI_UINT32 uDmaBufLen)176 void txXfer_SetBusParams (TI_HANDLE hTxXfer, TI_UINT32 uDmaBufLen)
177 {
178 TTxXferObj *pTxXfer = (TTxXferObj *)hTxXfer;
179
180 pTxXfer->uAggregMaxLen = uDmaBufLen;
181 }
182
183
txXfer_RegisterCb(TI_HANDLE hTxXfer,TI_UINT32 CallBackID,void * CBFunc,TI_HANDLE CBObj)184 void txXfer_RegisterCb (TI_HANDLE hTxXfer, TI_UINT32 CallBackID, void *CBFunc, TI_HANDLE CBObj)
185 {
186 TTxXferObj* pTxXfer = (TTxXferObj*)hTxXfer;
187
188 TRACE3(pTxXfer->hReport, REPORT_SEVERITY_INFORMATION, "txXfer_RegisterCb: CallBackID=%d, CBFunc=0x%x, CBObj=0x%x\n", CallBackID, CBFunc, CBObj);
189
190 switch(CallBackID)
191 {
192 /* Save upper layers Transfer-Done callback */
193 case TWD_INT_SEND_PACKET_TRANSFER:
194 pTxXfer->fSendPacketTransferCb = (TSendPacketTranferCb)CBFunc;
195 pTxXfer->hSendPacketTransferHndl = CBObj;
196 /* Set also the local CB so we are called upon Async transaction completion to call the upper CB */
197 pTxXfer->fXferCompleteLocalCb = (TTxnDoneCb)txXfer_TransferDoneCb;
198 break;
199
200 default:
201 TRACE0(pTxXfer->hReport, REPORT_SEVERITY_ERROR, " - Illegal value\n");
202 break;
203 }
204 }
205
206
txXfer_SendPacket(TI_HANDLE hTxXfer,TTxCtrlBlk * pPktCtrlBlk)207 ETxnStatus txXfer_SendPacket (TI_HANDLE hTxXfer, TTxCtrlBlk *pPktCtrlBlk)
208 {
209 TTxXferObj *pTxXfer = (TTxXferObj *)hTxXfer;
210 TI_UINT32 uPktLen = ENDIAN_HANDLE_WORD(pPktCtrlBlk->tTxDescriptor.length << 2); /* swap back for endianess if needed */
211 ETxnStatus eStatus;
212
213 /* If starting a new aggregation, prepare it, and send packet if aggregation is disabled. */
214 if (pTxXfer->uAggregPktsNum == 0)
215 {
216 pTxXfer->uAggregPktsNum = 1;
217 pTxXfer->uAggregPktsLen = uPktLen;
218 pTxXfer->pAggregFirstPkt = pPktCtrlBlk;
219 pTxXfer->pAggregLastPkt = pPktCtrlBlk;
220 pPktCtrlBlk->pNextAggregEntry = pPktCtrlBlk; /* First packet points to itself */
221 if (pTxXfer->uAggregMaxPkts <= 1)
222 {
223 eStatus = txXfer_SendAggregatedPkts (pTxXfer, TI_TRUE);
224 pTxXfer->uAggregPktsNum = 0;
225 }
226 else
227 {
228 eStatus = TXN_STATUS_PENDING;
229 }
230 }
231
232 /* Else, if new packet can be added to aggregation, add it and set status as Pending. */
233 else if ((pTxXfer->uAggregPktsNum + 1 <= pTxXfer->uAggregMaxPkts) &&
234 (pTxXfer->uAggregPktsLen + uPktLen <= pTxXfer->uAggregMaxLen))
235 {
236 pTxXfer->uAggregPktsNum++;
237 pTxXfer->uAggregPktsLen += uPktLen;
238 pTxXfer->pAggregLastPkt->pNextAggregEntry = pPktCtrlBlk; /* Link new packet to last */
239 pTxXfer->pAggregLastPkt = pPktCtrlBlk; /* Save new packet as last */
240 pPktCtrlBlk->pNextAggregEntry = pTxXfer->pAggregFirstPkt; /* Point from last to first */
241 eStatus = TXN_STATUS_PENDING;
242 }
243
244 /* Else, we can't add the new packet, so send current aggregation and start a new one */
245 else
246 {
247 txXfer_SendAggregatedPkts (pTxXfer, TI_FALSE);
248 eStatus = TXN_STATUS_PENDING; /* The current packet is not sent yet so return Pending */
249 pTxXfer->uAggregPktsNum = 1;
250 pTxXfer->uAggregPktsLen = uPktLen;
251 pTxXfer->pAggregFirstPkt = pPktCtrlBlk;
252 pTxXfer->pAggregLastPkt = pPktCtrlBlk;
253 pPktCtrlBlk->pNextAggregEntry = pPktCtrlBlk; /* First packet points to itself */
254 }
255
256
257 /* Return the Txn result - COMPLETE or PENDING. */
258 /* Note: For PENDING, a callback function will be called only if registered (needed for WHA) */
259 return eStatus;
260 }
261
262
txXfer_EndOfBurst(TI_HANDLE hTxXfer)263 void txXfer_EndOfBurst (TI_HANDLE hTxXfer)
264 {
265 TTxXferObj *pTxXfer = (TTxXferObj *)hTxXfer;
266
267 if (pTxXfer->uAggregPktsNum > 0)
268 {
269 /* No more packets from TxDataQ so send any aggregated packets and clear aggregation */
270 txXfer_SendAggregatedPkts (pTxXfer, TI_FALSE);
271 pTxXfer->uAggregPktsNum = 0;
272 }
273 }
274
275
276 /********************************************************************************
277 * *
278 * INTERNAL FUNCTIONS IMPLEMENTATION *
279 * *
280 *********************************************************************************/
281
282 /**
283 * \fn txXfer_SendAggregatedPkts
284 * \brief Send aggregated Tx packets to bus Txn layer
285 *
286 * Send aggregated Tx packets to bus Txn layer one by one.
287 * Increase the packets counter by the number of packets and send it to the FW (generates an interrupt).
288 * If xfer completion CB is registered and status is Complete, call CB for all packets (except last one if inseted now).
289 *
290 * \note The BusDrv combines the packets and sends them in one transaction.
291 * \param pTxXfer - The module's object
292 * \param bLastPktSentNow - If TRUE, last packet in the aggregation was inserted in current call to txXfer_SendPacket.
293 * \return COMPLETE if transaction completed in this context, PENDING if not, ERROR if failed
294 * \sa
295 */
txXfer_SendAggregatedPkts(TTxXferObj * pTxXfer,TI_BOOL bLastPktSentNow)296 static ETxnStatus txXfer_SendAggregatedPkts (TTxXferObj *pTxXfer, TI_BOOL bLastPktSentNow)
297 {
298 TTxCtrlBlk *pCurrPkt;
299 TTxnStruct *pTxn;
300 TPktsCntrTxn *pPktsCntrTxn;
301 ETxnStatus eStatus = TXN_STATUS_COMPLETE;
302 TI_UINT32 i;
303
304 /* Prepare and send all aggregated packets (combined and sent in one transaction by the BusDrv) */
305 pCurrPkt = pTxXfer->pAggregFirstPkt;
306 for (i = 0; i < pTxXfer->uAggregPktsNum; i++)
307 {
308 pTxn = (TTxnStruct *)pCurrPkt;
309
310 /* If not last packet, set aggregation flag, clear completion CB and progress to next packet */
311 if (i < pTxXfer->uAggregPktsNum - 1)
312 {
313 TXN_PARAM_SET_AGGREGATE(pTxn, TXN_AGGREGATE_ON);
314 pTxn->fTxnDoneCb = NULL;
315 pCurrPkt = pCurrPkt->pNextAggregEntry;
316 }
317 /* If last packet, clear aggregation flag and set completion CB (exist only if registered) */
318 else
319 {
320 TXN_PARAM_SET_AGGREGATE(pTxn, TXN_AGGREGATE_OFF);
321 pTxn->fTxnDoneCb = pTxXfer->fXferCompleteLocalCb;
322 pTxn->hCbHandle = (TI_HANDLE)pTxXfer;
323 }
324
325 /* Send packet */
326 pTxn->uHwAddr = SLV_MEM_DATA;
327 eStatus = twIf_Transact (pTxXfer->hTwIf, pTxn);
328 }
329
330 #ifdef TI_DBG
331 pTxXfer->aDbgCountPktAggreg[pTxXfer->uAggregPktsNum]++;
332 TRACE5(pTxXfer->hReport, REPORT_SEVERITY_INFORMATION, "txXfer_SendAggregatedPkts: Status=%d, NumPkts=%d, AggregLen=%d, pFirstPkt=0x%x, pLastPkt=0x%x\n", eStatus, pTxXfer->uAggregPktsNum, pTxXfer->uAggregPktsLen, pTxXfer->pAggregFirstPkt, pTxXfer->pAggregLastPkt);
333 if (eStatus == TXN_STATUS_ERROR)
334 {
335 TRACE5(pTxXfer->hReport, REPORT_SEVERITY_ERROR, "txXfer_SendAggregatedPkts: Status=%d, NumPkts=%d, AggregLen=%d, pFirstPkt=0x%x, pLastPkt=0x%x\n", eStatus, pTxXfer->uAggregPktsNum, pTxXfer->uAggregPktsLen, pTxXfer->pAggregFirstPkt, pTxXfer->pAggregLastPkt);
336 return eStatus;
337 }
338 #endif /* TI_DBG */
339
340 /* Write packet counter to FW (generates an interrupt).
341 Note: This may be removed once the host-slave HW counter functionality is verified */
342 pTxXfer->uPktsCntr += pTxXfer->uAggregPktsNum;
343 pTxXfer->uPktsCntrTxnIndex++;
344 if (pTxXfer->uPktsCntrTxnIndex == CTRL_BLK_ENTRIES_NUM)
345 {
346 pTxXfer->uPktsCntrTxnIndex = 0;
347 }
348 pPktsCntrTxn = &(pTxXfer->aPktsCntrTxn[pTxXfer->uPktsCntrTxnIndex]);
349 pPktsCntrTxn->uPktsCntr = ENDIAN_HANDLE_LONG(pTxXfer->uPktsCntr);
350 pPktsCntrTxn->tTxnStruct.uHwAddr = HOST_WR_ACCESS_REG;
351 twIf_Transact(pTxXfer->hTwIf, &pPktsCntrTxn->tTxnStruct);
352
353 /* If xfer completion CB is registered and last packet status is Complete, call the CB for all
354 * packets except the input one (covered by the return code).
355 */
356 if (pTxXfer->fSendPacketTransferCb && (eStatus == TXN_STATUS_COMPLETE))
357 {
358 /* Don't call CB for last packet if inserted in current Tx */
359 TI_UINT32 uNumCbCalls = bLastPktSentNow ? (pTxXfer->uAggregPktsNum - 1) : pTxXfer->uAggregPktsNum;
360
361 pCurrPkt = pTxXfer->pAggregFirstPkt;
362 for (i = 0; i < uNumCbCalls; i++)
363 {
364 pTxXfer->fSendPacketTransferCb (pTxXfer->hSendPacketTransferHndl, pCurrPkt);
365 pCurrPkt = pCurrPkt->pNextAggregEntry;
366 }
367 }
368
369 /* Return the Txn result - COMPLETE or PENDING. */
370 /* Note: For PENDING, a callback function will be called only if registered (needed for WHA) */
371 return eStatus;
372 }
373
374
375 /**
376 * \fn txXfer_TransferDoneCb
377 * \brief Send aggregated Tx packets to bus Txn layer
378 *
379 * Call the upper layers TranferDone CB for all packets of the completed aggregation
380 * This function is called only if the upper layers registered their CB (used only by WHA)
381 *
382 * \note
383 * \param pTxXfer - The module's object
384 * \return COMPLETE if completed in this context, PENDING if not, ERROR if failed
385 * \sa
386 */
txXfer_TransferDoneCb(TI_HANDLE hTxXfer,TTxnStruct * pTxn)387 static void txXfer_TransferDoneCb (TI_HANDLE hTxXfer, TTxnStruct *pTxn)
388 {
389 TTxXferObj *pTxXfer = (TTxXferObj*)hTxXfer;
390 TTxCtrlBlk *pInputPkt = (TTxCtrlBlk *)pTxn; /* This is the last packet of the aggregation */
391 TTxCtrlBlk *pCurrPkt;
392 TI_UINT32 i;
393
394 /* Call the upper layers TranferDone CB for all packets of the completed aggregation */
395 /* Note: If this CB was called it means that the upper CB exists */
396 pCurrPkt = pInputPkt->pNextAggregEntry; /* The last packet of the aggregation point to the first one */
397 for (i = 0; i < pTxXfer->uAggregMaxPkts; i++)
398 {
399 pTxXfer->fSendPacketTransferCb (pTxXfer->hSendPacketTransferHndl, pCurrPkt);
400
401 /* If we got back to the input packet we went over all the aggregation */
402 if (pCurrPkt == pInputPkt)
403 {
404 break;
405 }
406
407 pCurrPkt = pCurrPkt->pNextAggregEntry;
408 }
409
410 TRACE3(pTxXfer->hReport, REPORT_SEVERITY_INFORMATION, "txXfer_TransferDoneCb: NumPkts=%d, pInputPkt=0x%x, pCurrPkt=0x%x\n", i + 1, pInputPkt, pCurrPkt);
411 }
412
413
414 #ifdef TI_DBG
415
txXfer_ClearStats(TI_HANDLE hTxXfer)416 void txXfer_ClearStats (TI_HANDLE hTxXfer)
417 {
418 TTxXferObj *pTxXfer = (TTxXferObj*)hTxXfer;
419
420 os_memoryZero (pTxXfer->hOs, &pTxXfer->aDbgCountPktAggreg, sizeof(pTxXfer->aDbgCountPktAggreg));
421 }
422
txXfer_PrintStats(TI_HANDLE hTxXfer)423 void txXfer_PrintStats (TI_HANDLE hTxXfer)
424 {
425 #ifdef REPORT_LOG
426 TTxXferObj *pTxXfer = (TTxXferObj*)hTxXfer;
427 TI_UINT32 i;
428
429 WLAN_OS_REPORT(("Print Tx Xfer module info\n"));
430 WLAN_OS_REPORT(("=========================\n"));
431 WLAN_OS_REPORT(("uAggregMaxPkts = %d\n", pTxXfer->uAggregMaxPkts));
432 WLAN_OS_REPORT(("uAggregMaxLen = %d\n", pTxXfer->uAggregMaxLen));
433 WLAN_OS_REPORT(("uAggregPktsNum = %d\n", pTxXfer->uAggregPktsNum));
434 WLAN_OS_REPORT(("uAggregPktsLen = %d\n", pTxXfer->uAggregPktsLen));
435 WLAN_OS_REPORT(("uPktsCntr = %d\n", pTxXfer->uPktsCntr));
436 WLAN_OS_REPORT(("uPktsCntrTxnIndex = %d\n", pTxXfer->uPktsCntrTxnIndex));
437 for (i = 1; i < DBG_MAX_AGGREG_PKTS; i++)
438 {
439 WLAN_OS_REPORT(("uCountPktAggreg-%2d = %d\n", i, pTxXfer->aDbgCountPktAggreg[i]));
440 }
441 #endif
442 }
443
444 #endif /* TI_DBG */
445