1 //------------------------------------------------------------------------------
2 // <copyright file="ar6k_prot_hciUart.c" company="Atheros">
3 // Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
6 // Permission to use, copy, modify, and/or distribute this software for any
7 // purpose with or without fee is hereby granted, provided that the above
8 // copyright notice and this permission notice appear in all copies.
10 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 //------------------------------------------------------------------------------
20 //==============================================================================
21 // Protocol module for use in bridging HCI-UART packets over the GMBOX interface
23 // Author(s): ="Atheros"
24 //==============================================================================
29 #include "../htc_debug.h"
31 #include "htc_packet.h"
33 #include "hci_transport_api.h"
35 #include "ar6000_diag.h"
36 #include "hw/apb_map.h"
37 #include "hw/mbox_reg.h"
39 #ifdef ATH_AR6K_ENABLE_GMBOX
40 #define HCI_UART_COMMAND_PKT 0x01
41 #define HCI_UART_ACL_PKT 0x02
42 #define HCI_UART_SCO_PKT 0x03
43 #define HCI_UART_EVENT_PKT 0x04
45 #define HCI_RECV_WAIT_BUFFERS (1 << 0)
47 #define HCI_SEND_WAIT_CREDITS (1 << 0)
49 #define HCI_UART_BRIDGE_CREDIT_SIZE 128
51 #define CREDIT_POLL_COUNT 256
53 #define HCI_DELAY_PER_INTERVAL_MS 10
54 #define BTON_TIMEOUT_MS 500
55 #define BTOFF_TIMEOUT_MS 500
56 #define BAUD_TIMEOUT_MS 1
57 #define BTPWRSAV_TIMEOUT_MS 1
59 struct gmbox_proto_hci_uart
{
60 struct hci_transport_config_info HCIConfig
;
65 HCI_TRANSPORT_PACKET_TYPE WaitBufferType
;
66 struct htc_packet_queue SendQueue
; /* write queue holding HCI Command and ACL packets */
67 struct htc_packet_queue HCIACLRecvBuffers
; /* recv queue holding buffers for incomming ACL packets */
68 struct htc_packet_queue HCIEventBuffers
; /* recv queue holding buffers for incomming event packets */
69 struct ar6k_device
*pDev
;
76 int CreditsCurrentSeek
;
80 #define LOCK_HCI_RX(t) A_MUTEX_LOCK(&(t)->HCIRxLock);
81 #define UNLOCK_HCI_RX(t) A_MUTEX_UNLOCK(&(t)->HCIRxLock);
82 #define LOCK_HCI_TX(t) A_MUTEX_LOCK(&(t)->HCITxLock);
83 #define UNLOCK_HCI_TX(t) A_MUTEX_UNLOCK(&(t)->HCITxLock);
85 #define DO_HCI_RECV_INDICATION(p, pt) \
87 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, \
88 ("HCI: Indicate Recv on packet:0x%lX status:%d len:%d type:%d \n", \
89 (unsigned long)(pt), \
91 !(pt)->Status ? (pt)->ActualLength : 0, \
92 HCI_GET_PACKET_TYPE(pt))); \
93 (p)->HCIConfig.pHCIPktRecv((p)->HCIConfig.pContext, (pt)); \
96 #define DO_HCI_SEND_INDICATION(p,pt) \
97 { AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: Indicate Send on packet:0x%lX status:%d type:%d \n", \
98 (unsigned long)(pt),(pt)->Status,HCI_GET_PACKET_TYPE(pt))); \
99 (p)->HCIConfig.pHCISendComplete((p)->HCIConfig.pContext, (pt)); \
102 static int HCITrySend(struct gmbox_proto_hci_uart
*pProt
, struct htc_packet
*pPacket
, bool Synchronous
);
104 static void HCIUartCleanup(struct gmbox_proto_hci_uart
*pProtocol
)
106 A_ASSERT(pProtocol
!= NULL
);
108 A_MUTEX_DELETE(&pProtocol
->HCIRxLock
);
109 A_MUTEX_DELETE(&pProtocol
->HCITxLock
);
114 static int InitTxCreditState(struct gmbox_proto_hci_uart
*pProt
)
118 int creditPollCount
= CREDIT_POLL_COUNT
;
119 bool gotCredits
= false;
121 pProt
->CreditsConsumed
= 0;
125 if (pProt
->CreditsMax
!= 0) {
126 /* we can only call this only once per target reset */
127 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("HCI: InitTxCreditState - already called! \n"));
133 /* read the credit counter. At startup the target will set the credit counter
134 * to the max available, we read this in a loop because it may take
135 * multiple credit counter reads to get all credits */
137 while (creditPollCount
) {
141 status
= DevGMboxReadCreditCounter(pProt
->pDev
, PROC_IO_SYNC
, &credits
);
147 if (!gotCredits
&& (0 == credits
)) {
149 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("HCI: credit is 0, retrying (%d) \n",creditPollCount
));
150 A_MDELAY(HCI_DELAY_PER_INTERVAL_MS
);
160 pProt
->CreditsMax
+= credits
;
167 if (0 == creditPollCount
) {
168 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
169 ("** HCI : Failed to get credits! GMBOX Target was not available \n"));
174 /* now get the size */
175 status
= DevGMboxReadCreditSize(pProt
->pDev
, &pProt
->CreditSize
);
184 pProt
->CreditsAvailable
= pProt
->CreditsMax
;
185 AR_DEBUG_PRINTF(ATH_DEBUG_ANY
,("HCI : InitTxCreditState - credits avail: %d, size: %d \n",
186 pProt
->CreditsAvailable
, pProt
->CreditSize
));
192 static int CreditsAvailableCallback(void *pContext
, int Credits
, bool CreditIRQEnabled
)
194 struct gmbox_proto_hci_uart
*pProt
= (struct gmbox_proto_hci_uart
*)pContext
;
195 bool enableCreditIrq
= false;
196 bool disableCreditIrq
= false;
197 bool doPendingSends
= false;
200 /** this callback is called under 2 conditions:
201 * 1. The credit IRQ interrupt was enabled and signaled.
202 * 2. A credit counter read completed.
204 * The function must not assume that the calling context can block !
207 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("+CreditsAvailableCallback (Credits:%d, IRQ:%s) \n",
208 Credits
, CreditIRQEnabled
? "ON" : "OFF"));
215 if (!CreditIRQEnabled
) {
216 /* enable credit IRQ */
217 enableCreditIrq
= true;
222 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("HCI: current credit state, consumed:%d available:%d max:%d seek:%d\n",
223 pProt
->CreditsConsumed
,
224 pProt
->CreditsAvailable
,
226 pProt
->CreditsCurrentSeek
));
228 pProt
->CreditsAvailable
+= Credits
;
229 A_ASSERT(pProt
->CreditsAvailable
<= pProt
->CreditsMax
);
230 pProt
->CreditsConsumed
-= Credits
;
231 A_ASSERT(pProt
->CreditsConsumed
>= 0);
233 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("HCI: new credit state, consumed:%d available:%d max:%d seek:%d\n",
234 pProt
->CreditsConsumed
,
235 pProt
->CreditsAvailable
,
237 pProt
->CreditsCurrentSeek
));
239 if (pProt
->CreditsAvailable
>= pProt
->CreditsCurrentSeek
) {
240 /* we have enough credits to fulfill at least 1 packet waiting in the queue */
241 pProt
->CreditsCurrentSeek
= 0;
242 pProt
->SendStateFlags
&= ~HCI_SEND_WAIT_CREDITS
;
243 doPendingSends
= true;
244 if (CreditIRQEnabled
) {
245 /* credit IRQ was enabled, we shouldn't need it anymore */
246 disableCreditIrq
= true;
249 /* not enough credits yet, enable credit IRQ if we haven't already */
250 if (!CreditIRQEnabled
) {
251 enableCreditIrq
= true;
257 UNLOCK_HCI_TX(pProt
);
259 if (enableCreditIrq
) {
260 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,(" Enabling credit count IRQ...\n"));
261 /* must use async only */
262 status
= DevGMboxIRQAction(pProt
->pDev
, GMBOX_CREDIT_IRQ_ENABLE
, PROC_IO_ASYNC
);
263 } else if (disableCreditIrq
) {
264 /* must use async only */
265 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,(" Disabling credit count IRQ...\n"));
266 status
= DevGMboxIRQAction(pProt
->pDev
, GMBOX_CREDIT_IRQ_DISABLE
, PROC_IO_ASYNC
);
269 if (doPendingSends
) {
270 HCITrySend(pProt
, NULL
, false);
273 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("+CreditsAvailableCallback \n"));
277 static INLINE
void NotifyTransportFailure(struct gmbox_proto_hci_uart
*pProt
, int status
)
279 if (pProt
->HCIConfig
.TransportFailure
!= NULL
) {
280 pProt
->HCIConfig
.TransportFailure(pProt
->HCIConfig
.pContext
, status
);
284 static void FailureCallback(void *pContext
, int Status
)
286 struct gmbox_proto_hci_uart
*pProt
= (struct gmbox_proto_hci_uart
*)pContext
;
288 /* target assertion occurred */
289 NotifyTransportFailure(pProt
, Status
);
292 static void StateDumpCallback(void *pContext
)
294 struct gmbox_proto_hci_uart
*pProt
= (struct gmbox_proto_hci_uart
*)pContext
;
296 AR_DEBUG_PRINTF(ATH_DEBUG_ANY
,("============ HCIUart State ======================\n"));
297 AR_DEBUG_PRINTF(ATH_DEBUG_ANY
,("RecvStateFlags : 0x%X \n",pProt
->RecvStateFlags
));
298 AR_DEBUG_PRINTF(ATH_DEBUG_ANY
,("SendStateFlags : 0x%X \n",pProt
->SendStateFlags
));
299 AR_DEBUG_PRINTF(ATH_DEBUG_ANY
,("WaitBufferType : %d \n",pProt
->WaitBufferType
));
300 AR_DEBUG_PRINTF(ATH_DEBUG_ANY
,("SendQueue Depth : %d \n",HTC_PACKET_QUEUE_DEPTH(&pProt
->SendQueue
)));
301 AR_DEBUG_PRINTF(ATH_DEBUG_ANY
,("CreditsMax : %d \n",pProt
->CreditsMax
));
302 AR_DEBUG_PRINTF(ATH_DEBUG_ANY
,("CreditsConsumed : %d \n",pProt
->CreditsConsumed
));
303 AR_DEBUG_PRINTF(ATH_DEBUG_ANY
,("CreditsAvailable : %d \n",pProt
->CreditsAvailable
));
304 AR_DEBUG_PRINTF(ATH_DEBUG_ANY
,("==================================================\n"));
307 static int HCIUartMessagePending(void *pContext
, u8 LookAheadBytes
[], int ValidBytes
)
309 struct gmbox_proto_hci_uart
*pProt
= (struct gmbox_proto_hci_uart
*)pContext
;
311 int totalRecvLength
= 0;
312 HCI_TRANSPORT_PACKET_TYPE pktType
= HCI_PACKET_INVALID
;
313 bool recvRefillCalled
= false;
314 bool blockRecv
= false;
315 struct htc_packet
*pPacket
= NULL
;
317 /** caller guarantees that this is a fully block-able context (synch I/O is allowed) */
319 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("+HCIUartMessagePending Lookahead Bytes:%d \n",ValidBytes
));
325 if (ValidBytes
< 3) {
326 /* not enough for ACL or event header */
330 if ((LookAheadBytes
[0] == HCI_UART_ACL_PKT
) && (ValidBytes
< 5)) {
331 /* not enough for ACL data header */
335 switch (LookAheadBytes
[0]) {
336 case HCI_UART_EVENT_PKT
:
337 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("HCI Event: %d param length: %d \n",
338 LookAheadBytes
[1], LookAheadBytes
[2]));
339 totalRecvLength
= LookAheadBytes
[2];
340 totalRecvLength
+= 3; /* add type + event code + length field */
341 pktType
= HCI_EVENT_TYPE
;
343 case HCI_UART_ACL_PKT
:
344 totalRecvLength
= (LookAheadBytes
[4] << 8) | LookAheadBytes
[3];
345 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("HCI ACL: conn:0x%X length: %d \n",
346 ((LookAheadBytes
[2] & 0xF0) << 8) | LookAheadBytes
[1], totalRecvLength
));
347 totalRecvLength
+= 5; /* add type + connection handle + length field */
348 pktType
= HCI_ACL_TYPE
;
351 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("**Invalid HCI packet type: %d \n",LookAheadBytes
[0]));
360 if (pProt
->HCIConfig
.pHCIPktRecvAlloc
!= NULL
) {
361 UNLOCK_HCI_RX(pProt
);
362 /* user is using a per-packet allocation callback */
363 pPacket
= pProt
->HCIConfig
.pHCIPktRecvAlloc(pProt
->HCIConfig
.pContext
,
369 struct htc_packet_queue
*pQueue
;
370 /* user is using a refill handler that can refill multiple HTC buffers */
372 /* select buffer queue */
373 if (pktType
== HCI_ACL_TYPE
) {
374 pQueue
= &pProt
->HCIACLRecvBuffers
;
376 pQueue
= &pProt
->HCIEventBuffers
;
379 if (HTC_QUEUE_EMPTY(pQueue
)) {
380 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,
381 ("** HCI pkt type: %d has no buffers available calling allocation handler \n",
383 /* check for refill handler */
384 if (pProt
->HCIConfig
.pHCIPktRecvRefill
!= NULL
) {
385 recvRefillCalled
= true;
386 UNLOCK_HCI_RX(pProt
);
387 /* call the re-fill handler */
388 pProt
->HCIConfig
.pHCIPktRecvRefill(pProt
->HCIConfig
.pContext
,
392 /* check if we have more buffers */
393 pPacket
= HTC_PACKET_DEQUEUE(pQueue
);
397 pPacket
= HTC_PACKET_DEQUEUE(pQueue
);
398 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,
399 ("HCI pkt type: %d now has %d recv buffers left \n",
400 pktType
, HTC_PACKET_QUEUE_DEPTH(pQueue
)));
404 if (NULL
== pPacket
) {
405 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,
406 ("** HCI pkt type: %d has no buffers available stopping recv...\n", pktType
));
407 /* this is not an error, we simply need to mark that we are waiting for buffers.*/
408 pProt
->RecvStateFlags
|= HCI_RECV_WAIT_BUFFERS
;
409 pProt
->WaitBufferType
= pktType
;
414 if (totalRecvLength
> (int)pPacket
->BufferLength
) {
415 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("** HCI-UART pkt: %d requires %d bytes (%d buffer bytes avail) ! \n",
416 LookAheadBytes
[0], totalRecvLength
, pPacket
->BufferLength
));
423 UNLOCK_HCI_RX(pProt
);
425 /* locks are released, we can go fetch the packet */
429 if (status
|| (NULL
== pPacket
)) {
433 /* do this synchronously, we don't need to be fast here */
434 pPacket
->Completion
= NULL
;
436 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("HCI : getting recv packet len:%d hci-uart-type: %s \n",
437 totalRecvLength
, (LookAheadBytes
[0] == HCI_UART_EVENT_PKT
) ? "EVENT" : "ACL"));
439 status
= DevGMboxRead(pProt
->pDev
, pPacket
, totalRecvLength
);
445 if (pPacket
->pBuffer
[0] != LookAheadBytes
[0]) {
446 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("** HCI buffer does not contain expected packet type: %d ! \n",
447 pPacket
->pBuffer
[0]));
452 if (pPacket
->pBuffer
[0] == HCI_UART_EVENT_PKT
) {
453 /* validate event header fields */
454 if ((pPacket
->pBuffer
[1] != LookAheadBytes
[1]) ||
455 (pPacket
->pBuffer
[2] != LookAheadBytes
[2])) {
456 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("** HCI buffer does not match lookahead! \n"));
457 DebugDumpBytes(LookAheadBytes
, 3, "Expected HCI-UART Header");
458 DebugDumpBytes(pPacket
->pBuffer
, 3, "** Bad HCI-UART Header");
462 } else if (pPacket
->pBuffer
[0] == HCI_UART_ACL_PKT
) {
463 /* validate acl header fields */
464 if ((pPacket
->pBuffer
[1] != LookAheadBytes
[1]) ||
465 (pPacket
->pBuffer
[2] != LookAheadBytes
[2]) ||
466 (pPacket
->pBuffer
[3] != LookAheadBytes
[3]) ||
467 (pPacket
->pBuffer
[4] != LookAheadBytes
[4])) {
468 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("** HCI buffer does not match lookahead! \n"));
469 DebugDumpBytes(LookAheadBytes
, 5, "Expected HCI-UART Header");
470 DebugDumpBytes(pPacket
->pBuffer
, 5, "** Bad HCI-UART Header");
476 /* adjust buffer to move past packet ID */
478 pPacket
->ActualLength
= totalRecvLength
- 1;
480 /* indicate packet */
481 DO_HCI_RECV_INDICATION(pProt
,pPacket
);
484 /* check if we need to refill recv buffers */
485 if ((pProt
->HCIConfig
.pHCIPktRecvRefill
!= NULL
) && !recvRefillCalled
) {
486 struct htc_packet_queue
*pQueue
;
489 if (pktType
== HCI_ACL_TYPE
) {
490 watermark
= pProt
->HCIConfig
.ACLRecvBufferWaterMark
;
491 pQueue
= &pProt
->HCIACLRecvBuffers
;
493 watermark
= pProt
->HCIConfig
.EventRecvBufferWaterMark
;
494 pQueue
= &pProt
->HCIEventBuffers
;
497 if (HTC_PACKET_QUEUE_DEPTH(pQueue
) < watermark
) {
498 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,
499 ("** HCI pkt type: %d watermark hit (%d) current:%d \n",
500 pktType
, watermark
, HTC_PACKET_QUEUE_DEPTH(pQueue
)));
501 /* call the re-fill handler */
502 pProt
->HCIConfig
.pHCIPktRecvRefill(pProt
->HCIConfig
.pContext
,
504 HTC_PACKET_QUEUE_DEPTH(pQueue
));
510 /* check if we need to disable the receiver */
511 if (status
|| blockRecv
) {
512 DevGMboxIRQAction(pProt
->pDev
, GMBOX_RECV_IRQ_DISABLE
, PROC_IO_SYNC
);
515 /* see if we need to recycle the recv buffer */
516 if (status
&& (pPacket
!= NULL
)) {
517 struct htc_packet_queue queue
;
519 if (A_EPROTO
== status
) {
520 DebugDumpBytes(pPacket
->pBuffer
, totalRecvLength
, "Bad HCI-UART Recv packet");
523 HTC_PACKET_RESET_RX(pPacket
);
524 INIT_HTC_PACKET_QUEUE_AND_ADD(&queue
,pPacket
);
525 HCI_TransportAddReceivePkts(pProt
,&queue
);
526 NotifyTransportFailure(pProt
,status
);
530 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("-HCIUartMessagePending \n"));
535 static void HCISendPacketCompletion(void *Context
, struct htc_packet
*pPacket
)
537 struct gmbox_proto_hci_uart
*pProt
= (struct gmbox_proto_hci_uart
*)Context
;
538 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("+HCISendPacketCompletion (pPacket:0x%lX) \n",(unsigned long)pPacket
));
540 if (pPacket
->Status
) {
541 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,(" Send Packet (0x%lX) failed: %d , len:%d \n",
542 (unsigned long)pPacket
, pPacket
->Status
, pPacket
->ActualLength
));
545 DO_HCI_SEND_INDICATION(pProt
,pPacket
);
547 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("+HCISendPacketCompletion \n"));
550 static int SeekCreditsSynch(struct gmbox_proto_hci_uart
*pProt
)
558 status
= DevGMboxReadCreditCounter(pProt
->pDev
, PROC_IO_SYNC
, &credits
);
563 pProt
->CreditsAvailable
+= credits
;
564 pProt
->CreditsConsumed
-= credits
;
565 if (pProt
->CreditsAvailable
>= pProt
->CreditsCurrentSeek
) {
566 pProt
->CreditsCurrentSeek
= 0;
567 UNLOCK_HCI_TX(pProt
);
570 UNLOCK_HCI_TX(pProt
);
582 static int HCITrySend(struct gmbox_proto_hci_uart
*pProt
, struct htc_packet
*pPacket
, bool Synchronous
)
586 int creditsRequired
, remainder
;
588 bool synchSendComplete
= false;
590 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("+HCITrySend (pPacket:0x%lX) %s \n",(unsigned long)pPacket
,
591 Synchronous
? "SYNC" :"ASYNC"));
595 /* increment write processing count on entry */
596 pProt
->SendProcessCount
++;
600 if (pProt
->HCIStopped
) {
601 status
= A_ECANCELED
;
605 if (pPacket
!= NULL
) {
606 /* packet was supplied */
608 /* in synchronous mode, the send queue can only hold 1 packet */
609 if (!HTC_QUEUE_EMPTY(&pProt
->SendQueue
)) {
615 if (pProt
->SendProcessCount
> 1) {
616 /* another thread or task is draining the TX queues */
622 HTC_PACKET_ENQUEUE(&pProt
->SendQueue
,pPacket
);
625 /* see if adding this packet hits the max depth (asynchronous mode only) */
626 if ((pProt
->HCIConfig
.MaxSendQueueDepth
> 0) &&
627 ((HTC_PACKET_QUEUE_DEPTH(&pProt
->SendQueue
) + 1) >= pProt
->HCIConfig
.MaxSendQueueDepth
)) {
628 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
, ("HCI Send queue is full, Depth:%d, Max:%d \n",
629 HTC_PACKET_QUEUE_DEPTH(&pProt
->SendQueue
),
630 pProt
->HCIConfig
.MaxSendQueueDepth
));
631 /* queue will be full, invoke any callbacks to determine what action to take */
632 if (pProt
->HCIConfig
.pHCISendFull
!= NULL
) {
633 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,
634 ("HCI : Calling driver's send full callback.... \n"));
635 if (pProt
->HCIConfig
.pHCISendFull(pProt
->HCIConfig
.pContext
,
636 pPacket
) == HCI_SEND_FULL_DROP
) {
638 status
= A_NO_RESOURCE
;
644 HTC_PACKET_ENQUEUE(&pProt
->SendQueue
,pPacket
);
649 if (pProt
->SendStateFlags
& HCI_SEND_WAIT_CREDITS
) {
653 if (pProt
->SendProcessCount
> 1) {
654 /* another thread or task is draining the TX queues */
658 /***** beyond this point only 1 thread may enter ******/
660 /* now drain the send queue for transmission as long as we have enough
662 while (!HTC_QUEUE_EMPTY(&pProt
->SendQueue
)) {
664 pPacket
= HTC_PACKET_DEQUEUE(&pProt
->SendQueue
);
666 switch (HCI_GET_PACKET_TYPE(pPacket
)) {
667 case HCI_COMMAND_TYPE
:
668 hciUartType
= HCI_UART_COMMAND_PKT
;
671 hciUartType
= HCI_UART_ACL_PKT
;
683 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("HCI: Got head packet:0x%lX , Type:%d Length: %d Remaining Queue Depth: %d\n",
684 (unsigned long)pPacket
, HCI_GET_PACKET_TYPE(pPacket
), pPacket
->ActualLength
,
685 HTC_PACKET_QUEUE_DEPTH(&pProt
->SendQueue
)));
687 transferLength
= 1; /* UART type header is 1 byte */
688 transferLength
+= pPacket
->ActualLength
;
689 transferLength
= DEV_CALC_SEND_PADDED_LEN(pProt
->pDev
, transferLength
);
691 /* figure out how many credits this message requires */
692 creditsRequired
= transferLength
/ pProt
->CreditSize
;
693 remainder
= transferLength
% pProt
->CreditSize
;
699 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("HCI: Creds Required:%d Got:%d\n",
700 creditsRequired
, pProt
->CreditsAvailable
));
702 if (creditsRequired
> pProt
->CreditsAvailable
) {
704 /* in synchronous mode we need to seek credits in synchronously */
705 pProt
->CreditsCurrentSeek
= creditsRequired
;
706 UNLOCK_HCI_TX(pProt
);
707 status
= SeekCreditsSynch(pProt
);
712 /* fall through and continue processing this send op */
714 /* not enough credits, queue back to the head */
715 HTC_PACKET_ENQUEUE_TO_HEAD(&pProt
->SendQueue
,pPacket
);
716 /* waiting for credits */
717 pProt
->SendStateFlags
|= HCI_SEND_WAIT_CREDITS
;
718 /* provide a hint to reduce attempts to re-send if credits are dribbling back
719 * this hint is the short fall of credits */
720 pProt
->CreditsCurrentSeek
= creditsRequired
;
721 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("HCI: packet:0x%lX placed back in queue. head packet needs: %d credits \n",
722 (unsigned long)pPacket
, pProt
->CreditsCurrentSeek
));
724 UNLOCK_HCI_TX(pProt
);
726 /* schedule a credit counter read, our CreditsAvailableCallback callback will be called
728 DevGMboxReadCreditCounter(pProt
->pDev
, PROC_IO_ASYNC
, NULL
);
735 /* caller guarantees some head room */
737 pPacket
->pBuffer
[0] = hciUartType
;
739 pProt
->CreditsAvailable
-= creditsRequired
;
740 pProt
->CreditsConsumed
+= creditsRequired
;
741 A_ASSERT(pProt
->CreditsConsumed
<= pProt
->CreditsMax
);
743 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("HCI: new credit state: consumed:%d available:%d max:%d\n",
744 pProt
->CreditsConsumed
, pProt
->CreditsAvailable
, pProt
->CreditsMax
));
746 UNLOCK_HCI_TX(pProt
);
750 pPacket
->Completion
= NULL
;
751 pPacket
->pContext
= NULL
;
753 pPacket
->Completion
= HCISendPacketCompletion
;
754 pPacket
->pContext
= pProt
;
757 status
= DevGMboxWrite(pProt
->pDev
,pPacket
,transferLength
);
759 synchSendComplete
= true;
770 pProt
->SendProcessCount
--;
771 A_ASSERT(pProt
->SendProcessCount
>= 0);
772 UNLOCK_HCI_TX(pProt
);
775 A_ASSERT(pPacket
!= NULL
);
776 if (!status
&& (!synchSendComplete
)) {
780 if (pPacket
->ListLink
.pNext
!= NULL
) {
781 /* remove from the queue */
782 HTC_PACKET_REMOVE(&pProt
->SendQueue
,pPacket
);
784 UNLOCK_HCI_TX(pProt
);
787 if (status
&& (pPacket
!= NULL
)) {
788 pPacket
->Status
= status
;
789 DO_HCI_SEND_INDICATION(pProt
,pPacket
);
793 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("-HCITrySend: \n"));
797 static void FlushSendQueue(struct gmbox_proto_hci_uart
*pProt
)
799 struct htc_packet
*pPacket
;
800 struct htc_packet_queue discardQueue
;
802 INIT_HTC_PACKET_QUEUE(&discardQueue
);
806 if (!HTC_QUEUE_EMPTY(&pProt
->SendQueue
)) {
807 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&discardQueue
,&pProt
->SendQueue
);
810 UNLOCK_HCI_TX(pProt
);
812 /* discard packets */
813 while (!HTC_QUEUE_EMPTY(&discardQueue
)) {
814 pPacket
= HTC_PACKET_DEQUEUE(&discardQueue
);
815 pPacket
->Status
= A_ECANCELED
;
816 DO_HCI_SEND_INDICATION(pProt
,pPacket
);
821 static void FlushRecvBuffers(struct gmbox_proto_hci_uart
*pProt
)
823 struct htc_packet_queue discardQueue
;
824 struct htc_packet
*pPacket
;
826 INIT_HTC_PACKET_QUEUE(&discardQueue
);
829 /*transfer list items from ACL and event buffer queues to the discard queue */
830 if (!HTC_QUEUE_EMPTY(&pProt
->HCIACLRecvBuffers
)) {
831 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&discardQueue
,&pProt
->HCIACLRecvBuffers
);
833 if (!HTC_QUEUE_EMPTY(&pProt
->HCIEventBuffers
)) {
834 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&discardQueue
,&pProt
->HCIEventBuffers
);
836 UNLOCK_HCI_RX(pProt
);
838 /* now empty the discard queue */
839 while (!HTC_QUEUE_EMPTY(&discardQueue
)) {
840 pPacket
= HTC_PACKET_DEQUEUE(&discardQueue
);
841 pPacket
->Status
= A_ECANCELED
;
842 DO_HCI_RECV_INDICATION(pProt
,pPacket
);
847 /*** protocol module install entry point ***/
849 int GMboxProtocolInstall(struct ar6k_device
*pDev
)
852 struct gmbox_proto_hci_uart
*pProtocol
= NULL
;
856 pProtocol
= A_MALLOC(sizeof(struct gmbox_proto_hci_uart
));
858 if (NULL
== pProtocol
) {
859 status
= A_NO_MEMORY
;
863 A_MEMZERO(pProtocol
, sizeof(*pProtocol
));
864 pProtocol
->pDev
= pDev
;
865 INIT_HTC_PACKET_QUEUE(&pProtocol
->SendQueue
);
866 INIT_HTC_PACKET_QUEUE(&pProtocol
->HCIACLRecvBuffers
);
867 INIT_HTC_PACKET_QUEUE(&pProtocol
->HCIEventBuffers
);
868 A_MUTEX_INIT(&pProtocol
->HCIRxLock
);
869 A_MUTEX_INIT(&pProtocol
->HCITxLock
);
875 DEV_GMBOX_SET_PROTOCOL(pDev
,
876 HCIUartMessagePending
,
877 CreditsAvailableCallback
,
883 if (pProtocol
!= NULL
) {
884 HCIUartCleanup(pProtocol
);
891 /*** protocol module uninstall entry point ***/
892 void GMboxProtocolUninstall(struct ar6k_device
*pDev
)
894 struct gmbox_proto_hci_uart
*pProtocol
= (struct gmbox_proto_hci_uart
*)DEV_GMBOX_GET_PROTOCOL(pDev
);
896 if (pProtocol
!= NULL
) {
898 /* notify anyone attached */
899 if (pProtocol
->HCIAttached
) {
900 A_ASSERT(pProtocol
->HCIConfig
.TransportRemoved
!= NULL
);
901 pProtocol
->HCIConfig
.TransportRemoved(pProtocol
->HCIConfig
.pContext
);
902 pProtocol
->HCIAttached
= false;
905 HCIUartCleanup(pProtocol
);
906 DEV_GMBOX_SET_PROTOCOL(pDev
,NULL
,NULL
,NULL
,NULL
,NULL
);
911 static int NotifyTransportReady(struct gmbox_proto_hci_uart
*pProt
)
913 struct hci_transport_properties props
;
918 A_MEMZERO(&props
,sizeof(props
));
920 /* HCI UART only needs one extra byte at the head to indicate the packet TYPE */
923 props
.IOBlockPad
= pProt
->pDev
->BlockSize
;
924 if (pProt
->HCIAttached
) {
925 AR_DEBUG_PRINTF(ATH_DEBUG_ANY
,("HCI: notifying attached client to transport... \n"));
926 A_ASSERT(pProt
->HCIConfig
.TransportReady
!= NULL
);
927 status
= pProt
->HCIConfig
.TransportReady(pProt
,
929 pProt
->HCIConfig
.pContext
);
937 /*********** HCI UART protocol implementation ************************************************/
939 HCI_TRANSPORT_HANDLE
HCI_TransportAttach(void *HTCHandle
, struct hci_transport_config_info
*pInfo
)
941 struct gmbox_proto_hci_uart
*pProtocol
= NULL
;
942 struct ar6k_device
*pDev
;
944 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
,("+HCI_TransportAttach \n"));
946 pDev
= HTCGetAR6KDevice(HTCHandle
);
952 pProtocol
= (struct gmbox_proto_hci_uart
*)DEV_GMBOX_GET_PROTOCOL(pDev
);
954 if (NULL
== pProtocol
) {
955 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("GMBOX protocol not installed! \n"));
959 if (pProtocol
->HCIAttached
) {
960 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("GMBOX protocol already attached! \n"));
964 memcpy(&pProtocol
->HCIConfig
, pInfo
, sizeof(struct hci_transport_config_info
));
966 A_ASSERT(pProtocol
->HCIConfig
.pHCIPktRecv
!= NULL
);
967 A_ASSERT(pProtocol
->HCIConfig
.pHCISendComplete
!= NULL
);
969 pProtocol
->HCIAttached
= true;
975 if (pProtocol
!= NULL
) {
976 /* TODO ... should we use a worker? */
977 NotifyTransportReady(pProtocol
);
980 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
,("-HCI_TransportAttach (0x%lX) \n",(unsigned long)pProtocol
));
981 return (HCI_TRANSPORT_HANDLE
)pProtocol
;
984 void HCI_TransportDetach(HCI_TRANSPORT_HANDLE HciTrans
)
986 struct gmbox_proto_hci_uart
*pProtocol
= (struct gmbox_proto_hci_uart
*)HciTrans
;
987 struct ar6k_device
*pDev
= pProtocol
->pDev
;
989 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
,("+HCI_TransportDetach \n"));
992 if (!pProtocol
->HCIAttached
) {
993 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("GMBOX protocol not attached! \n"));
997 pProtocol
->HCIAttached
= false;
1000 HCI_TransportStop(HciTrans
);
1001 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
,("-HCI_TransportAttach \n"));
1004 int HCI_TransportAddReceivePkts(HCI_TRANSPORT_HANDLE HciTrans
, struct htc_packet_queue
*pQueue
)
1006 struct gmbox_proto_hci_uart
*pProt
= (struct gmbox_proto_hci_uart
*)HciTrans
;
1008 bool unblockRecv
= false;
1009 struct htc_packet
*pPacket
;
1011 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("+HCI_TransportAddReceivePkt \n"));
1017 if (pProt
->HCIStopped
) {
1018 status
= A_ECANCELED
;
1022 pPacket
= HTC_GET_PKT_AT_HEAD(pQueue
);
1024 if (NULL
== pPacket
) {
1029 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,(" HCI recv packet added, type :%d, len:%d num:%d \n",
1030 HCI_GET_PACKET_TYPE(pPacket
), pPacket
->BufferLength
, HTC_PACKET_QUEUE_DEPTH(pQueue
)));
1032 if (HCI_GET_PACKET_TYPE(pPacket
) == HCI_EVENT_TYPE
) {
1033 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pProt
->HCIEventBuffers
, pQueue
);
1034 } else if (HCI_GET_PACKET_TYPE(pPacket
) == HCI_ACL_TYPE
) {
1035 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pProt
->HCIACLRecvBuffers
, pQueue
);
1041 if (pProt
->RecvStateFlags
& HCI_RECV_WAIT_BUFFERS
) {
1042 if (pProt
->WaitBufferType
== HCI_GET_PACKET_TYPE(pPacket
)) {
1043 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,(" HCI recv was blocked on packet type :%d, unblocking.. \n",
1044 pProt
->WaitBufferType
));
1045 pProt
->RecvStateFlags
&= ~HCI_RECV_WAIT_BUFFERS
;
1046 pProt
->WaitBufferType
= HCI_PACKET_INVALID
;
1053 UNLOCK_HCI_RX(pProt
);
1056 while (!HTC_QUEUE_EMPTY(pQueue
)) {
1057 pPacket
= HTC_PACKET_DEQUEUE(pQueue
);
1058 pPacket
->Status
= A_ECANCELED
;
1059 DO_HCI_RECV_INDICATION(pProt
,pPacket
);
1064 DevGMboxIRQAction(pProt
->pDev
, GMBOX_RECV_IRQ_ENABLE
, PROC_IO_ASYNC
);
1067 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("-HCI_TransportAddReceivePkt \n"));
1072 int HCI_TransportSendPkt(HCI_TRANSPORT_HANDLE HciTrans
, struct htc_packet
*pPacket
, bool Synchronous
)
1074 struct gmbox_proto_hci_uart
*pProt
= (struct gmbox_proto_hci_uart
*)HciTrans
;
1076 return HCITrySend(pProt
,pPacket
,Synchronous
);
1079 void HCI_TransportStop(HCI_TRANSPORT_HANDLE HciTrans
)
1081 struct gmbox_proto_hci_uart
*pProt
= (struct gmbox_proto_hci_uart
*)HciTrans
;
1083 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
,("+HCI_TransportStop \n"));
1085 LOCK_AR6K(pProt
->pDev
);
1086 if (pProt
->HCIStopped
) {
1087 UNLOCK_AR6K(pProt
->pDev
);
1088 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
,("-HCI_TransportStop \n"));
1091 pProt
->HCIStopped
= true;
1092 UNLOCK_AR6K(pProt
->pDev
);
1094 /* disable interrupts */
1095 DevGMboxIRQAction(pProt
->pDev
, GMBOX_DISABLE_ALL
, PROC_IO_SYNC
);
1096 FlushSendQueue(pProt
);
1097 FlushRecvBuffers(pProt
);
1099 /* signal bridge side to power down BT */
1100 DevGMboxSetTargetInterrupt(pProt
->pDev
, MBOX_SIG_HCI_BRIDGE_BT_OFF
, BTOFF_TIMEOUT_MS
);
1102 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
,("-HCI_TransportStop \n"));
1105 int HCI_TransportStart(HCI_TRANSPORT_HANDLE HciTrans
)
1108 struct gmbox_proto_hci_uart
*pProt
= (struct gmbox_proto_hci_uart
*)HciTrans
;
1110 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
,("+HCI_TransportStart \n"));
1112 /* set stopped in case we have a problem in starting */
1113 pProt
->HCIStopped
= true;
1117 status
= InitTxCreditState(pProt
);
1123 status
= DevGMboxIRQAction(pProt
->pDev
, GMBOX_ERRORS_IRQ_ENABLE
, PROC_IO_SYNC
);
1129 status
= DevGMboxIRQAction(pProt
->pDev
, GMBOX_RECV_IRQ_ENABLE
, PROC_IO_SYNC
);
1134 /* signal bridge side to power up BT */
1135 status
= DevGMboxSetTargetInterrupt(pProt
->pDev
, MBOX_SIG_HCI_BRIDGE_BT_ON
, BTON_TIMEOUT_MS
);
1138 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("HCI_TransportStart : Failed to trigger BT ON \n"));
1143 pProt
->HCIStopped
= false;
1147 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
,("-HCI_TransportStart \n"));
1152 int HCI_TransportEnableDisableAsyncRecv(HCI_TRANSPORT_HANDLE HciTrans
, bool Enable
)
1154 struct gmbox_proto_hci_uart
*pProt
= (struct gmbox_proto_hci_uart
*)HciTrans
;
1155 return DevGMboxIRQAction(pProt
->pDev
,
1156 Enable
? GMBOX_RECV_IRQ_ENABLE
: GMBOX_RECV_IRQ_DISABLE
,
1161 int HCI_TransportRecvHCIEventSync(HCI_TRANSPORT_HANDLE HciTrans
,
1162 struct htc_packet
*pPacket
,
1165 struct gmbox_proto_hci_uart
*pProt
= (struct gmbox_proto_hci_uart
*)HciTrans
;
1169 int totalRecvLength
;
1171 MaxPollMS
= MaxPollMS
/ 16;
1173 if (MaxPollMS
< 2) {
1179 bytes
= sizeof(lookAhead
);
1180 status
= DevGMboxRecvLookAheadPeek(pProt
->pDev
,lookAhead
,&bytes
);
1186 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("HCI recv poll got bytes: %d, retry : %d \n",
1193 totalRecvLength
= 0;
1194 switch (lookAhead
[0]) {
1195 case HCI_UART_EVENT_PKT
:
1196 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("HCI Event: %d param length: %d \n",
1197 lookAhead
[1], lookAhead
[2]));
1198 totalRecvLength
= lookAhead
[2];
1199 totalRecvLength
+= 3; /* add type + event code + length field */
1202 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("**Invalid HCI packet type: %d \n",lookAhead
[0]));
1211 pPacket
->Completion
= NULL
;
1212 status
= DevGMboxRead(pProt
->pDev
,pPacket
,totalRecvLength
);
1218 pPacket
->ActualLength
= totalRecvLength
- 1;
1219 pPacket
->Status
= 0;
1223 if (MaxPollMS
== 0) {
1224 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("HCI recv poll timeout! \n"));
1231 #define LSB_SCRATCH_IDX 4
1232 #define MSB_SCRATCH_IDX 5
1233 int HCI_TransportSetBaudRate(HCI_TRANSPORT_HANDLE HciTrans
, u32 Baud
)
1235 struct gmbox_proto_hci_uart
*pProt
= (struct gmbox_proto_hci_uart
*)HciTrans
;
1236 struct hif_device
*pHIFDevice
= (struct hif_device
*)(pProt
->pDev
->HIFDevice
);
1237 u32 scaledBaud
, scratchAddr
;
1240 /* Divide the desired baud rate by 100
1241 * Store the LSB in the local scratch register 4 and the MSB in the local
1242 * scratch register 5 for the target to read
1244 scratchAddr
= MBOX_BASE_ADDRESS
| (LOCAL_SCRATCH_ADDRESS
+ 4 * LSB_SCRATCH_IDX
);
1245 scaledBaud
= (Baud
/ 100) & LOCAL_SCRATCH_VALUE_MASK
;
1246 status
= ar6000_WriteRegDiag(pHIFDevice
, &scratchAddr
, &scaledBaud
);
1247 scratchAddr
= MBOX_BASE_ADDRESS
| (LOCAL_SCRATCH_ADDRESS
+ 4 * MSB_SCRATCH_IDX
);
1248 scaledBaud
= ((Baud
/ 100) >> (LOCAL_SCRATCH_VALUE_MSB
+1)) & LOCAL_SCRATCH_VALUE_MASK
;
1249 status
|= ar6000_WriteRegDiag(pHIFDevice
, &scratchAddr
, &scaledBaud
);
1251 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, ("Failed to set up baud rate in scratch register!"));
1255 /* Now interrupt the target to tell it about the baud rate */
1256 status
= DevGMboxSetTargetInterrupt(pProt
->pDev
, MBOX_SIG_HCI_BRIDGE_BAUD_SET
, BAUD_TIMEOUT_MS
);
1258 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, ("Failed to tell target to change baud rate!"));
1264 int HCI_TransportEnablePowerMgmt(HCI_TRANSPORT_HANDLE HciTrans
, bool Enable
)
1267 struct gmbox_proto_hci_uart
*pProt
= (struct gmbox_proto_hci_uart
*)HciTrans
;
1270 status
= DevGMboxSetTargetInterrupt(pProt
->pDev
, MBOX_SIG_HCI_BRIDGE_PWR_SAV_ON
, BTPWRSAV_TIMEOUT_MS
);
1272 status
= DevGMboxSetTargetInterrupt(pProt
->pDev
, MBOX_SIG_HCI_BRIDGE_PWR_SAV_OFF
, BTPWRSAV_TIMEOUT_MS
);
1276 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("Failed to enable/disable HCI power management!\n"));
1278 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("HCI power management enabled/disabled!\n"));
1284 #endif //ATH_AR6K_ENABLE_GMBOX