• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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