bump to 2.6.30-rc6
[openwrt/openwrt.git] / target / linux / s3c24xx / files-2.6.30 / drivers / ar6000 / htc / htc_send.c
1 /*
2 *
3 * Copyright (c) 2007 Atheros Communications Inc.
4 * All rights reserved.
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation;
10 *
11 * Software distributed under the License is distributed on an "AS
12 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
13 * implied. See the License for the specific language governing
14 * rights and limitations under the License.
15 *
16 *
17 *
18 */
19
20 #include "htc_internal.h"
21
22 #define DO_EP_TX_COMPLETION(ep,p) \
23 { \
24 (p)->Completion = NULL; \
25 (ep)->EpCallBacks.EpTxComplete((ep)->EpCallBacks.pContext,(p)); \
26 }
27
28
29 /* call the distribute credits callback with the distribution */
30 #define DO_DISTRIBUTION(t,reason,description,pList) \
31 { \
32 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, \
33 (" calling distribute function (%s) (dfn:0x%X, ctxt:0x%X, dist:0x%X) \n", \
34 (description), \
35 (A_UINT32)(t)->DistributeCredits, \
36 (A_UINT32)(t)->pCredDistContext, \
37 (A_UINT32)pList)); \
38 (t)->DistributeCredits((t)->pCredDistContext, \
39 (pList), \
40 (reason)); \
41 }
42
43 /* our internal send packet completion handler when packets are submited to the AR6K device
44 * layer */
45 static void HTCSendPktCompletionHandler(void *Context, HTC_PACKET *pPacket)
46 {
47 HTC_TARGET *target = (HTC_TARGET *)Context;
48 HTC_ENDPOINT *pEndpoint = &target->EndPoint[pPacket->Endpoint];
49
50
51 if (A_FAILED(pPacket->Status)) {
52 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
53 ("HTCSendPktCompletionHandler: request failed (status:%d, ep:%d) \n",
54 pPacket->Status, pPacket->Endpoint));
55 }
56 /* first, fixup the head room we allocated */
57 pPacket->pBuffer += HTC_HDR_LENGTH;
58 /* do completion */
59 DO_EP_TX_COMPLETION(pEndpoint,pPacket);
60 }
61
62 A_STATUS HTCIssueSend(HTC_TARGET *target, HTC_PACKET *pPacket, A_UINT8 SendFlags)
63 {
64 A_STATUS status;
65 A_UINT8 *pHdrBuf;
66 A_BOOL sync = FALSE;
67
68 /* caller always provides headrooom */
69 pPacket->pBuffer -= HTC_HDR_LENGTH;
70 pHdrBuf = pPacket->pBuffer;
71 /* setup frame header */
72 A_SET_UINT16_FIELD(pHdrBuf,HTC_FRAME_HDR,PayloadLen,(A_UINT16)pPacket->ActualLength);
73 A_SET_UINT8_FIELD(pHdrBuf,HTC_FRAME_HDR,Flags,SendFlags);
74 A_SET_UINT8_FIELD(pHdrBuf,HTC_FRAME_HDR,EndpointID, (A_UINT8)pPacket->Endpoint);
75
76 if (pPacket->Completion == NULL) {
77 /* mark that this request was synchronously issued */
78 sync = TRUE;
79 }
80
81 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
82 ("+-HTCIssueSend: transmit length : %d (%s) \n",
83 pPacket->ActualLength + HTC_HDR_LENGTH,
84 sync ? "SYNC" : "ASYNC" ));
85
86 /* send message to device */
87 status = DevSendPacket(&target->Device,
88 pPacket,
89 pPacket->ActualLength + HTC_HDR_LENGTH);
90
91 if (sync) {
92 /* use local sync variable. If this was issued asynchronously, pPacket is no longer
93 * safe to access. */
94 pPacket->pBuffer += HTC_HDR_LENGTH;
95 }
96
97 /* if this request was asynchronous, the packet completion routine will be invoked by
98 * the device layer when the HIF layer completes the request */
99
100 return status;
101 }
102
103 /* try to send the current packet or a packet at the head of the TX queue,
104 * if there are no credits, the packet remains in the queue. */
105 static void HTCTrySend(HTC_TARGET *target,
106 HTC_PACKET *pPacketToSend,
107 HTC_ENDPOINT_ID ep)
108 {
109 HTC_PACKET *pPacket;
110 HTC_ENDPOINT *pEndpoint;
111 int creditsRequired;
112 A_UINT8 sendFlags;
113
114 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HTCTrySend (pPkt:0x%X)\n",(A_UINT32)pPacketToSend));
115
116 pEndpoint = &target->EndPoint[ep];
117
118 LOCK_HTC_TX(target);
119
120 if (pPacketToSend != NULL) {
121 /* caller supplied us a packet to queue to the tail of the HTC TX queue before
122 * we check the tx queue */
123 HTC_PACKET_ENQUEUE(&pEndpoint->TxQueue,pPacketToSend);
124 pEndpoint->CurrentTxQueueDepth++;
125 }
126
127 /* now drain the TX queue for transmission as long as we have enough
128 * credits */
129
130 while (1) {
131
132 if (HTC_QUEUE_EMPTY(&pEndpoint->TxQueue)) {
133 /* nothing in the queue */
134 break;
135 }
136
137 sendFlags = 0;
138
139 /* get packet at head, but don't remove it */
140 pPacket = HTC_GET_PKT_AT_HEAD(&pEndpoint->TxQueue);
141 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Got head packet:0x%X , Queue Depth: %d\n",
142 (A_UINT32)pPacket, pEndpoint->CurrentTxQueueDepth));
143
144 /* figure out how many credits this message requires */
145 creditsRequired = pPacket->ActualLength + HTC_HDR_LENGTH;
146 creditsRequired += target->TargetCreditSize - 1;
147 creditsRequired /= target->TargetCreditSize;
148
149 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Creds Required:%d Got:%d\n",
150 creditsRequired, pEndpoint->CreditDist.TxCredits));
151
152 if (pEndpoint->CreditDist.TxCredits < creditsRequired) {
153
154 /* not enough credits */
155
156 if (pPacket->Endpoint == ENDPOINT_0) {
157 /* leave it in the queue */
158 break;
159 }
160 /* invoke the registered distribution function only if this is not
161 * endpoint 0, we let the driver layer provide more credits if it can.
162 * We pass the credit distribution list starting at the endpoint in question
163 * */
164
165 /* set how many credits we need */
166 pEndpoint->CreditDist.TxCreditsSeek =
167 creditsRequired - pEndpoint->CreditDist.TxCredits;
168 DO_DISTRIBUTION(target,
169 HTC_CREDIT_DIST_SEEK_CREDITS,
170 "Seek Credits",
171 &pEndpoint->CreditDist);
172
173 pEndpoint->CreditDist.TxCreditsSeek = 0;
174
175 if (pEndpoint->CreditDist.TxCredits < creditsRequired) {
176 /* still not enough credits to send, leave packet in the queue */
177 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
178 (" Not enough credits for ep %d leaving packet in queue..\n",
179 pPacket->Endpoint));
180 break;
181 }
182
183 }
184
185 pEndpoint->CreditDist.TxCredits -= creditsRequired;
186 INC_HTC_EP_STAT(pEndpoint, TxCreditsConsummed, creditsRequired);
187
188 /* check if we need credits */
189 if (pEndpoint->CreditDist.TxCredits < pEndpoint->CreditDist.TxCreditsPerMaxMsg) {
190 sendFlags |= HTC_FLAGS_NEED_CREDIT_UPDATE;
191 INC_HTC_EP_STAT(pEndpoint, TxCreditLowIndications, 1);
192 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Host Needs Credits \n"));
193 }
194
195 /* now we can fully dequeue */
196 pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->TxQueue);
197 pEndpoint->CurrentTxQueueDepth--;
198
199 INC_HTC_EP_STAT(pEndpoint, TxIssued, 1);
200
201 UNLOCK_HTC_TX(target);
202
203 HTCIssueSend(target, pPacket, sendFlags);
204
205 LOCK_HTC_TX(target);
206
207 /* go back and check for more messages */
208 }
209
210 if (pEndpoint->CurrentTxQueueDepth >= pEndpoint->MaxTxQueueDepth) {
211 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Endpoint %d, TX queue is full, Depth:%d, Max:%d \n",
212 ep, pEndpoint->CurrentTxQueueDepth, pEndpoint->MaxTxQueueDepth));
213 UNLOCK_HTC_TX(target);
214 /* queue is now full, let caller know */
215 if (pEndpoint->EpCallBacks.EpSendFull != NULL) {
216 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Calling driver's send full callback.... \n"));
217 pEndpoint->EpCallBacks.EpSendFull(pEndpoint->EpCallBacks.pContext, ep);
218 }
219 } else {
220 UNLOCK_HTC_TX(target);
221 /* queue is now available for new packet, let caller know */
222 if (pEndpoint->EpCallBacks.EpSendAvail)
223 pEndpoint->EpCallBacks.EpSendAvail(pEndpoint->EpCallBacks.pContext, ep);
224 }
225
226 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCTrySend: \n"));
227 }
228
229 /* HTC API - HTCSendPkt */
230 A_STATUS HTCSendPkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket)
231 {
232 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
233 HTC_ENDPOINT *pEndpoint;
234 HTC_ENDPOINT_ID ep;
235 A_STATUS status = A_OK;
236
237 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
238 ("+HTCSendPkt: Enter endPointId: %d, buffer: 0x%X, length: %d \n",
239 pPacket->Endpoint, (A_UINT32)pPacket->pBuffer, pPacket->ActualLength));
240
241 ep = pPacket->Endpoint;
242 AR_DEBUG_ASSERT(ep < ENDPOINT_MAX);
243 pEndpoint = &target->EndPoint[ep];
244
245 do {
246
247 if (HTC_STOPPING(target)) {
248 status = A_ECANCELED;
249 pPacket->Status = status;
250 DO_EP_TX_COMPLETION(pEndpoint,pPacket);
251 break;
252 }
253 /* everything sent through this interface is asynchronous */
254 /* fill in HTC completion routines */
255 pPacket->Completion = HTCSendPktCompletionHandler;
256 pPacket->pContext = target;
257
258 HTCTrySend(target, pPacket, ep);
259
260 } while (FALSE);
261
262 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCSendPkt \n"));
263
264 return status;
265 }
266
267
268 /* check TX queues to drain because of credit distribution update */
269 static INLINE void HTCCheckEndpointTxQueues(HTC_TARGET *target)
270 {
271 HTC_ENDPOINT *pEndpoint;
272 HTC_ENDPOINT_CREDIT_DIST *pDistItem;
273
274 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCCheckEndpointTxQueues \n"));
275 pDistItem = target->EpCreditDistributionListHead;
276
277 /* run through the credit distribution list to see
278 * if there are packets queued
279 * NOTE: no locks need to be taken since the distribution list
280 * is not dynamic (cannot be re-ordered) and we are not modifying any state */
281 while (pDistItem != NULL) {
282 pEndpoint = (HTC_ENDPOINT *)pDistItem->pHTCReserved;
283
284 if (pEndpoint->CurrentTxQueueDepth > 0) {
285 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Ep %d has %d credits and %d Packets in TX Queue \n",
286 pDistItem->Endpoint, pEndpoint->CreditDist.TxCredits, pEndpoint->CurrentTxQueueDepth));
287 /* try to start the stalled queue, this list is ordered by priority.
288 * Highest priority queue get's processed first, if there are credits available the
289 * highest priority queue will get a chance to reclaim credits from lower priority
290 * ones */
291 HTCTrySend(target, NULL, pDistItem->Endpoint);
292 }
293
294 pDistItem = pDistItem->pNext;
295 }
296
297 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCCheckEndpointTxQueues \n"));
298 }
299
300 /* process credit reports and call distribution function */
301 void HTCProcessCreditRpt(HTC_TARGET *target, HTC_CREDIT_REPORT *pRpt, int NumEntries, HTC_ENDPOINT_ID FromEndpoint)
302 {
303 int i;
304 HTC_ENDPOINT *pEndpoint;
305 int totalCredits = 0;
306 A_BOOL doDist = FALSE;
307
308 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCProcessCreditRpt, Credit Report Entries:%d \n", NumEntries));
309
310 /* lock out TX while we update credits */
311 LOCK_HTC_TX(target);
312
313 for (i = 0; i < NumEntries; i++, pRpt++) {
314 if (pRpt->EndpointID >= ENDPOINT_MAX) {
315 AR_DEBUG_ASSERT(FALSE);
316 break;
317 }
318
319 pEndpoint = &target->EndPoint[pRpt->EndpointID];
320
321 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Endpoint %d got %d credits \n",
322 pRpt->EndpointID, pRpt->Credits));
323
324
325 #ifdef HTC_EP_STAT_PROFILING
326
327 INC_HTC_EP_STAT(pEndpoint, TxCreditRpts, 1);
328 INC_HTC_EP_STAT(pEndpoint, TxCreditsReturned, pRpt->Credits);
329
330 if (FromEndpoint == pRpt->EndpointID) {
331 /* this credit report arrived on the same endpoint indicating it arrived in an RX
332 * packet */
333 INC_HTC_EP_STAT(pEndpoint, TxCreditsFromRx, pRpt->Credits);
334 INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromRx, 1);
335 } else if (FromEndpoint == ENDPOINT_0) {
336 /* this credit arrived on endpoint 0 as a NULL message */
337 INC_HTC_EP_STAT(pEndpoint, TxCreditsFromEp0, pRpt->Credits);
338 INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromEp0, 1);
339 } else {
340 /* arrived on another endpoint */
341 INC_HTC_EP_STAT(pEndpoint, TxCreditsFromOther, pRpt->Credits);
342 INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromOther, 1);
343 }
344
345 #endif
346
347 if (ENDPOINT_0 == pRpt->EndpointID) {
348 /* always give endpoint 0 credits back */
349 pEndpoint->CreditDist.TxCredits += pRpt->Credits;
350 } else {
351 /* for all other endpoints, update credits to distribute, the distribution function
352 * will handle giving out credits back to the endpoints */
353 pEndpoint->CreditDist.TxCreditsToDist += pRpt->Credits;
354 /* flag that we have to do the distribution */
355 doDist = TRUE;
356 }
357
358 totalCredits += pRpt->Credits;
359 }
360
361 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Report indicated %d credits to distribute \n", totalCredits));
362
363 if (doDist) {
364 /* this was a credit return based on a completed send operations
365 * note, this is done with the lock held */
366 DO_DISTRIBUTION(target,
367 HTC_CREDIT_DIST_SEND_COMPLETE,
368 "Send Complete",
369 target->EpCreditDistributionListHead->pNext);
370 }
371
372 UNLOCK_HTC_TX(target);
373
374 if (totalCredits) {
375 HTCCheckEndpointTxQueues(target);
376 }
377
378 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCProcessCreditRpt \n"));
379 }
380
381 /* flush endpoint TX queue */
382 static void HTCFlushEndpointTX(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint, HTC_TX_TAG Tag)
383 {
384 HTC_PACKET *pPacket;
385 HTC_PACKET_QUEUE discardQueue;
386
387 /* initialize the discard queue */
388 INIT_HTC_PACKET_QUEUE(&discardQueue);
389
390 LOCK_HTC_TX(target);
391
392 /* interate from the front of the TX queue and flush out packets */
393 ITERATE_OVER_LIST_ALLOW_REMOVE(&pEndpoint->TxQueue, pPacket, HTC_PACKET, ListLink) {
394
395 /* check for removal */
396 if ((HTC_TX_PACKET_TAG_ALL == Tag) || (Tag == pPacket->PktInfo.AsTx.Tag)) {
397 /* remove from queue */
398 HTC_PACKET_REMOVE(pPacket);
399 /* add it to the discard pile */
400 HTC_PACKET_ENQUEUE(&discardQueue, pPacket);
401 pEndpoint->CurrentTxQueueDepth--;
402 }
403
404 } ITERATE_END;
405
406 UNLOCK_HTC_TX(target);
407
408 /* empty the discard queue */
409 while (1) {
410 pPacket = HTC_PACKET_DEQUEUE(&discardQueue);
411 if (NULL == pPacket) {
412 break;
413 }
414 pPacket->Status = A_ECANCELED;
415 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" Flushing TX packet:0x%X, length:%d, ep:%d tag:0x%X \n",
416 (A_UINT32)pPacket, pPacket->ActualLength, pPacket->Endpoint, pPacket->PktInfo.AsTx.Tag));
417 DO_EP_TX_COMPLETION(pEndpoint,pPacket);
418 }
419
420 }
421
422 void DumpCreditDist(HTC_ENDPOINT_CREDIT_DIST *pEPDist)
423 {
424 #ifdef DEBUG
425 HTC_ENDPOINT *pEndpoint = (HTC_ENDPOINT *)pEPDist->pHTCReserved;
426 #endif
427
428 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("--- EP : %d ServiceID: 0x%X --------------\n",
429 pEPDist->Endpoint, pEPDist->ServiceID));
430 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" this:0x%X next:0x%X prev:0x%X\n",
431 (A_UINT32)pEPDist, (A_UINT32)pEPDist->pNext, (A_UINT32)pEPDist->pPrev));
432 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" DistFlags : 0x%X \n", pEPDist->DistFlags));
433 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsNorm : %d \n", pEPDist->TxCreditsNorm));
434 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsMin : %d \n", pEPDist->TxCreditsMin));
435 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCredits : %d \n", pEPDist->TxCredits));
436 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsAssigned : %d \n", pEPDist->TxCreditsAssigned));
437 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsSeek : %d \n", pEPDist->TxCreditsSeek));
438 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditSize : %d \n", pEPDist->TxCreditSize));
439 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsPerMaxMsg : %d \n", pEPDist->TxCreditsPerMaxMsg));
440 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsToDist : %d \n", pEPDist->TxCreditsToDist));
441 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxQueueDepth : %d \n", pEndpoint->CurrentTxQueueDepth));
442 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("----------------------------------------------------\n"));
443 }
444
445 void DumpCreditDistStates(HTC_TARGET *target)
446 {
447 HTC_ENDPOINT_CREDIT_DIST *pEPList = target->EpCreditDistributionListHead;
448
449 while (pEPList != NULL) {
450 DumpCreditDist(pEPList);
451 pEPList = pEPList->pNext;
452 }
453
454 if (target->DistributeCredits != NULL) {
455 DO_DISTRIBUTION(target,
456 HTC_DUMP_CREDIT_STATE,
457 "Dump State",
458 NULL);
459 }
460 }
461
462 /* flush all send packets from all endpoint queues */
463 void HTCFlushSendPkts(HTC_TARGET *target)
464 {
465 HTC_ENDPOINT *pEndpoint;
466 int i;
467
468 DumpCreditDistStates(target);
469
470 for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
471 pEndpoint = &target->EndPoint[i];
472 if (pEndpoint->ServiceID == 0) {
473 /* not in use.. */
474 continue;
475 }
476 HTCFlushEndpointTX(target,pEndpoint,HTC_TX_PACKET_TAG_ALL);
477 }
478
479 }
480
481 /* HTC API to flush an endpoint's TX queue*/
482 void HTCFlushEndpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint, HTC_TX_TAG Tag)
483 {
484 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
485 HTC_ENDPOINT *pEndpoint = &target->EndPoint[Endpoint];
486
487 if (pEndpoint->ServiceID == 0) {
488 AR_DEBUG_ASSERT(FALSE);
489 /* not in use.. */
490 return;
491 }
492
493 HTCFlushEndpointTX(target, pEndpoint, Tag);
494 }
495
496 /* HTC API to indicate activity to the credit distribution function */
497 void HTCIndicateActivityChange(HTC_HANDLE HTCHandle,
498 HTC_ENDPOINT_ID Endpoint,
499 A_BOOL Active)
500 {
501 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
502 HTC_ENDPOINT *pEndpoint = &target->EndPoint[Endpoint];
503 A_BOOL doDist = FALSE;
504
505 if (pEndpoint->ServiceID == 0) {
506 AR_DEBUG_ASSERT(FALSE);
507 /* not in use.. */
508 return;
509 }
510
511 LOCK_HTC_TX(target);
512
513 if (Active) {
514 if (!(pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE)) {
515 /* mark active now */
516 pEndpoint->CreditDist.DistFlags |= HTC_EP_ACTIVE;
517 doDist = TRUE;
518 }
519 } else {
520 if (pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE) {
521 /* mark inactive now */
522 pEndpoint->CreditDist.DistFlags &= ~HTC_EP_ACTIVE;
523 doDist = TRUE;
524 }
525 }
526
527 if (doDist) {
528 /* do distribution again based on activity change
529 * note, this is done with the lock held */
530 DO_DISTRIBUTION(target,
531 HTC_CREDIT_DIST_ACTIVITY_CHANGE,
532 "Activity Change",
533 target->EpCreditDistributionListHead->pNext);
534 }
535
536 UNLOCK_HTC_TX(target);
537
538 }