1 //------------------------------------------------------------------------------
2 // <copyright file="ar6k_prot_hciUart.c" company="Atheros">
3 //    Copyright (c) 2007-2010 Atheros Corporation.  All rights reserved.
4 //
5 //
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.
9 //
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.
17 //
18 //
19 //------------------------------------------------------------------------------
20 //==============================================================================
21 // Protocol module for use in bridging HCI-UART packets over the GMBOX interface
22 //
23 // Author(s): ="Atheros"
24 //==============================================================================
25 #include "a_config.h"
26 #include "athdefs.h"
27 #include "a_types.h"
28 #include "a_osapi.h"
29 #include "../htc_debug.h"
30 #include "hif.h"
31 #include "htc_packet.h"
32 #include "ar6k.h"
33 #include "hci_transport_api.h"
34 #include "gmboxif.h"
35 #include "ar6000_diag.h"
36 #include "hw/apb_map.h"
37 #include "hw/mbox_reg.h"
38 
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
44 
45 #define HCI_RECV_WAIT_BUFFERS (1 << 0)
46 
47 #define HCI_SEND_WAIT_CREDITS (1 << 0)
48 
49 #define HCI_UART_BRIDGE_CREDIT_SIZE     128
50 
51 #define CREDIT_POLL_COUNT       256
52 
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
58 
59 struct gmbox_proto_hci_uart {
60     struct hci_transport_config_info   HCIConfig;
61     bool                      HCIAttached;
62     bool                      HCIStopped;
63     u32 RecvStateFlags;
64     u32 SendStateFlags;
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;
70     A_MUTEX_T                   HCIRxLock;
71     A_MUTEX_T                   HCITxLock;
72     int                         CreditsMax;
73     int                         CreditsConsumed;
74     int                         CreditsAvailable;
75     int                         CreditSize;
76     int                         CreditsCurrentSeek;
77     int                         SendProcessCount;
78 };
79 
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);
84 
85 #define DO_HCI_RECV_INDICATION(p, pt)				\
86 do {								\
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),				\
90 			 (pt)->Status,					\
91 			 !(pt)->Status ? (pt)->ActualLength : 0,	\
92 			 HCI_GET_PACKET_TYPE(pt)));			\
93 	(p)->HCIConfig.pHCIPktRecv((p)->HCIConfig.pContext, (pt));	\
94 } while (0)
95 
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));                            \
100 }
101 
102 static int HCITrySend(struct gmbox_proto_hci_uart *pProt, struct htc_packet *pPacket, bool Synchronous);
103 
HCIUartCleanup(struct gmbox_proto_hci_uart * pProtocol)104 static void HCIUartCleanup(struct gmbox_proto_hci_uart *pProtocol)
105 {
106     A_ASSERT(pProtocol != NULL);
107 
108     A_MUTEX_DELETE(&pProtocol->HCIRxLock);
109     A_MUTEX_DELETE(&pProtocol->HCITxLock);
110 
111     A_FREE(pProtocol);
112 }
113 
InitTxCreditState(struct gmbox_proto_hci_uart * pProt)114 static int InitTxCreditState(struct gmbox_proto_hci_uart *pProt)
115 {
116     int    status;
117     int         credits;
118     int         creditPollCount = CREDIT_POLL_COUNT;
119     bool      gotCredits = false;
120 
121     pProt->CreditsConsumed = 0;
122 
123     do {
124 
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"));
128             A_ASSERT(false);
129             status = A_EINVAL;
130             break;
131         }
132 
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  */
136 
137         while (creditPollCount) {
138 
139             credits = 0;
140 
141             status = DevGMboxReadCreditCounter(pProt->pDev, PROC_IO_SYNC, &credits);
142 
143             if (status) {
144                 break;
145             }
146 
147             if (!gotCredits && (0 == credits)) {
148                 creditPollCount--;
149                 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: credit is 0, retrying (%d)  \n",creditPollCount));
150                 A_MDELAY(HCI_DELAY_PER_INTERVAL_MS);
151                 continue;
152             } else {
153                 gotCredits = true;
154             }
155 
156             if (0 == credits) {
157                 break;
158             }
159 
160             pProt->CreditsMax += credits;
161         }
162 
163         if (status) {
164             break;
165         }
166 
167         if (0 == creditPollCount) {
168             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
169                     ("** HCI : Failed to get credits! GMBOX Target was not available \n"));
170             status = A_ERROR;
171             break;
172         }
173 
174             /* now get the size */
175         status = DevGMboxReadCreditSize(pProt->pDev, &pProt->CreditSize);
176 
177         if (status) {
178             break;
179         }
180 
181     } while (false);
182 
183     if (!status) {
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));
187     }
188 
189     return status;
190 }
191 
CreditsAvailableCallback(void * pContext,int Credits,bool CreditIRQEnabled)192 static int CreditsAvailableCallback(void *pContext, int Credits, bool CreditIRQEnabled)
193 {
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;
198     int             status = 0;
199 
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.
203      *
204      *   The function must not assume that the calling context can block !
205      */
206 
207     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+CreditsAvailableCallback (Credits:%d, IRQ:%s) \n",
208                 Credits, CreditIRQEnabled ? "ON" : "OFF"));
209 
210     LOCK_HCI_TX(pProt);
211 
212     do {
213 
214         if (0 == Credits) {
215             if (!CreditIRQEnabled) {
216                     /* enable credit IRQ */
217                 enableCreditIrq = true;
218             }
219             break;
220         }
221 
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,
225                          pProt->CreditsMax,
226                          pProt->CreditsCurrentSeek));
227 
228         pProt->CreditsAvailable += Credits;
229         A_ASSERT(pProt->CreditsAvailable <= pProt->CreditsMax);
230         pProt->CreditsConsumed  -= Credits;
231         A_ASSERT(pProt->CreditsConsumed >= 0);
232 
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,
236                          pProt->CreditsMax,
237                          pProt->CreditsCurrentSeek));
238 
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;
247             }
248         } else {
249                 /* not enough credits yet, enable credit IRQ if we haven't already */
250             if (!CreditIRQEnabled) {
251                 enableCreditIrq = true;
252             }
253         }
254 
255     } while (false);
256 
257     UNLOCK_HCI_TX(pProt);
258 
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);
267     }
268 
269     if (doPendingSends) {
270         HCITrySend(pProt, NULL, false);
271     }
272 
273     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+CreditsAvailableCallback \n"));
274     return status;
275 }
276 
NotifyTransportFailure(struct gmbox_proto_hci_uart * pProt,int status)277 static INLINE void NotifyTransportFailure(struct gmbox_proto_hci_uart  *pProt, int status)
278 {
279     if (pProt->HCIConfig.TransportFailure != NULL) {
280         pProt->HCIConfig.TransportFailure(pProt->HCIConfig.pContext, status);
281     }
282 }
283 
FailureCallback(void * pContext,int Status)284 static void FailureCallback(void *pContext, int Status)
285 {
286     struct gmbox_proto_hci_uart  *pProt = (struct gmbox_proto_hci_uart *)pContext;
287 
288         /* target assertion occurred */
289     NotifyTransportFailure(pProt, Status);
290 }
291 
StateDumpCallback(void * pContext)292 static void StateDumpCallback(void *pContext)
293 {
294     struct gmbox_proto_hci_uart  *pProt = (struct gmbox_proto_hci_uart *)pContext;
295 
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"));
305 }
306 
HCIUartMessagePending(void * pContext,u8 LookAheadBytes[],int ValidBytes)307 static int HCIUartMessagePending(void *pContext, u8 LookAheadBytes[], int ValidBytes)
308 {
309     struct gmbox_proto_hci_uart        *pProt = (struct gmbox_proto_hci_uart *)pContext;
310     int                    status = 0;
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;
316 
317     /** caller guarantees that this is a fully block-able context (synch I/O is allowed) */
318 
319     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HCIUartMessagePending Lookahead Bytes:%d \n",ValidBytes));
320 
321     LOCK_HCI_RX(pProt);
322 
323     do {
324 
325         if (ValidBytes < 3) {
326                 /* not enough for ACL or event header */
327             break;
328         }
329 
330         if ((LookAheadBytes[0] == HCI_UART_ACL_PKT) && (ValidBytes < 5)) {
331                 /* not enough for ACL data header */
332             break;
333         }
334 
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;
342                 break;
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;
349                 break;
350             default:
351                 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("**Invalid HCI packet type: %d \n",LookAheadBytes[0]));
352                 status = A_EPROTO;
353                 break;
354         }
355 
356         if (status) {
357             break;
358         }
359 
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,
364                                                         pktType,
365                                                         totalRecvLength);
366             LOCK_HCI_RX(pProt);
367 
368         } else {
369             struct htc_packet_queue *pQueue;
370                 /* user is using a refill handler that can refill multiple HTC buffers */
371 
372                 /* select buffer queue */
373             if (pktType == HCI_ACL_TYPE) {
374                 pQueue = &pProt->HCIACLRecvBuffers;
375             } else {
376                 pQueue = &pProt->HCIEventBuffers;
377             }
378 
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",
382                     pktType));
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,
389                                                        pktType,
390                                                        0);
391                     LOCK_HCI_RX(pProt);
392                         /* check if we have more buffers */
393                     pPacket = HTC_PACKET_DEQUEUE(pQueue);
394                         /* fall through */
395                 }
396             } else {
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)));
401             }
402         }
403 
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;
410             blockRecv = true;
411             break;
412         }
413 
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));
417             status = A_EINVAL;
418             break;
419         }
420 
421     } while (false);
422 
423     UNLOCK_HCI_RX(pProt);
424 
425         /* locks are released, we can go fetch the packet */
426 
427     do {
428 
429         if (status || (NULL == pPacket)) {
430             break;
431         }
432 
433             /* do this synchronously, we don't need to be fast here */
434         pPacket->Completion = NULL;
435 
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"));
438 
439         status = DevGMboxRead(pProt->pDev, pPacket, totalRecvLength);
440 
441         if (status) {
442             break;
443         }
444 
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]));
448             status = A_EPROTO;
449             break;
450         }
451 
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");
459                 status = A_EPROTO;
460                 break;
461             }
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");
471                 status = A_EPROTO;
472                 break;
473             }
474         }
475 
476             /* adjust buffer to move past packet ID */
477         pPacket->pBuffer++;
478         pPacket->ActualLength = totalRecvLength - 1;
479         pPacket->Status = 0;
480             /* indicate packet */
481         DO_HCI_RECV_INDICATION(pProt,pPacket);
482         pPacket = NULL;
483 
484             /* check if we need to refill recv buffers */
485         if ((pProt->HCIConfig.pHCIPktRecvRefill != NULL) && !recvRefillCalled) {
486             struct htc_packet_queue *pQueue;
487             int              watermark;
488 
489             if (pktType == HCI_ACL_TYPE) {
490                 watermark = pProt->HCIConfig.ACLRecvBufferWaterMark;
491                 pQueue = &pProt->HCIACLRecvBuffers;
492             } else {
493                 watermark = pProt->HCIConfig.EventRecvBufferWaterMark;
494                 pQueue = &pProt->HCIEventBuffers;
495             }
496 
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,
503                                                    pktType,
504                                                    HTC_PACKET_QUEUE_DEPTH(pQueue));
505             }
506         }
507 
508     } while (false);
509 
510         /* check if we need to disable the receiver */
511     if (status || blockRecv) {
512         DevGMboxIRQAction(pProt->pDev, GMBOX_RECV_IRQ_DISABLE, PROC_IO_SYNC);
513     }
514 
515         /* see if we need to recycle the recv buffer */
516     if (status && (pPacket != NULL)) {
517         struct htc_packet_queue queue;
518 
519         if (A_EPROTO == status) {
520             DebugDumpBytes(pPacket->pBuffer, totalRecvLength, "Bad HCI-UART Recv packet");
521         }
522             /* recycle 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);
527     }
528 
529 
530     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HCIUartMessagePending \n"));
531 
532     return status;
533 }
534 
HCISendPacketCompletion(void * Context,struct htc_packet * pPacket)535 static void HCISendPacketCompletion(void *Context, struct htc_packet *pPacket)
536 {
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));
539 
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));
543     }
544 
545     DO_HCI_SEND_INDICATION(pProt,pPacket);
546 
547     AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HCISendPacketCompletion \n"));
548 }
549 
SeekCreditsSynch(struct gmbox_proto_hci_uart * pProt)550 static int SeekCreditsSynch(struct gmbox_proto_hci_uart *pProt)
551 {
552     int status = 0;
553     int      credits;
554     int      retry = 100;
555 
556     while (true) {
557         credits = 0;
558         status =  DevGMboxReadCreditCounter(pProt->pDev, PROC_IO_SYNC, &credits);
559         if (status) {
560             break;
561         }
562         LOCK_HCI_TX(pProt);
563         pProt->CreditsAvailable += credits;
564         pProt->CreditsConsumed -= credits;
565         if (pProt->CreditsAvailable >= pProt->CreditsCurrentSeek) {
566             pProt->CreditsCurrentSeek = 0;
567             UNLOCK_HCI_TX(pProt);
568             break;
569         }
570         UNLOCK_HCI_TX(pProt);
571         retry--;
572         if (0 == retry) {
573             status = A_EBUSY;
574             break;
575         }
576         A_MDELAY(20);
577     }
578 
579     return status;
580 }
581 
HCITrySend(struct gmbox_proto_hci_uart * pProt,struct htc_packet * pPacket,bool Synchronous)582 static int HCITrySend(struct gmbox_proto_hci_uart *pProt, struct htc_packet *pPacket, bool Synchronous)
583 {
584     int    status = 0;
585     int         transferLength;
586     int         creditsRequired, remainder;
587     u8 hciUartType;
588     bool      synchSendComplete = false;
589 
590     AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HCITrySend (pPacket:0x%lX) %s \n",(unsigned long)pPacket,
591             Synchronous ? "SYNC" :"ASYNC"));
592 
593     LOCK_HCI_TX(pProt);
594 
595         /* increment write processing count on entry */
596     pProt->SendProcessCount++;
597 
598     do {
599 
600         if (pProt->HCIStopped) {
601             status = A_ECANCELED;
602             break;
603         }
604 
605         if (pPacket != NULL) {
606                 /* packet was supplied */
607             if (Synchronous) {
608                     /* in synchronous mode, the send queue can only hold 1 packet */
609                 if (!HTC_QUEUE_EMPTY(&pProt->SendQueue)) {
610                     status = A_EBUSY;
611                     A_ASSERT(false);
612                     break;
613                 }
614 
615                 if (pProt->SendProcessCount > 1) {
616                         /* another thread or task is draining the TX queues  */
617                     status = A_EBUSY;
618                     A_ASSERT(false);
619                     break;
620                 }
621 
622                 HTC_PACKET_ENQUEUE(&pProt->SendQueue,pPacket);
623 
624             } else {
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) {
637                                 /* drop it */
638                             status = A_NO_RESOURCE;
639                             break;
640                         }
641                     }
642                 }
643 
644                 HTC_PACKET_ENQUEUE(&pProt->SendQueue,pPacket);
645             }
646 
647         }
648 
649         if (pProt->SendStateFlags & HCI_SEND_WAIT_CREDITS) {
650             break;
651         }
652 
653         if (pProt->SendProcessCount > 1) {
654                 /* another thread or task is draining the TX queues  */
655             break;
656         }
657 
658         /***** beyond this point only 1 thread may enter ******/
659 
660         /* now drain the send queue for transmission as long as we have enough
661          * credits */
662         while (!HTC_QUEUE_EMPTY(&pProt->SendQueue)) {
663 
664             pPacket = HTC_PACKET_DEQUEUE(&pProt->SendQueue);
665 
666             switch (HCI_GET_PACKET_TYPE(pPacket)) {
667                 case HCI_COMMAND_TYPE:
668                     hciUartType = HCI_UART_COMMAND_PKT;
669                     break;
670                 case HCI_ACL_TYPE:
671                     hciUartType = HCI_UART_ACL_PKT;
672                     break;
673                 default:
674                     status = A_EINVAL;
675                     A_ASSERT(false);
676                     break;
677             }
678 
679             if (status) {
680                 break;
681             }
682 
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)));
686 
687             transferLength = 1;  /* UART type header is 1 byte */
688             transferLength += pPacket->ActualLength;
689             transferLength = DEV_CALC_SEND_PADDED_LEN(pProt->pDev, transferLength);
690 
691                 /* figure out how many credits this message requires */
692             creditsRequired = transferLength / pProt->CreditSize;
693             remainder = transferLength % pProt->CreditSize;
694 
695             if (remainder) {
696                 creditsRequired++;
697             }
698 
699             AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: Creds Required:%d   Got:%d\n",
700                             creditsRequired, pProt->CreditsAvailable));
701 
702             if (creditsRequired > pProt->CreditsAvailable) {
703                 if (Synchronous) {
704                         /* in synchronous mode we need to seek credits in synchronously */
705                     pProt->CreditsCurrentSeek = creditsRequired;
706                     UNLOCK_HCI_TX(pProt);
707                     status = SeekCreditsSynch(pProt);
708                     LOCK_HCI_TX(pProt);
709                     if (status) {
710                         break;
711                     }
712                     /* fall through and continue processing this send op */
713                 } else {
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));
723                     pPacket = NULL;
724                     UNLOCK_HCI_TX(pProt);
725 
726                         /* schedule a credit counter read, our CreditsAvailableCallback callback will be called
727                          * with the result */
728                     DevGMboxReadCreditCounter(pProt->pDev, PROC_IO_ASYNC, NULL);
729 
730                     LOCK_HCI_TX(pProt);
731                     break;
732                 }
733             }
734 
735                 /* caller guarantees some head room */
736             pPacket->pBuffer--;
737             pPacket->pBuffer[0] = hciUartType;
738 
739             pProt->CreditsAvailable -= creditsRequired;
740             pProt->CreditsConsumed  += creditsRequired;
741             A_ASSERT(pProt->CreditsConsumed <= pProt->CreditsMax);
742 
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));
745 
746             UNLOCK_HCI_TX(pProt);
747 
748                 /* write it out */
749             if (Synchronous) {
750                 pPacket->Completion = NULL;
751                 pPacket->pContext = NULL;
752             } else {
753                 pPacket->Completion = HCISendPacketCompletion;
754                 pPacket->pContext = pProt;
755             }
756 
757             status = DevGMboxWrite(pProt->pDev,pPacket,transferLength);
758             if (Synchronous) {
759                 synchSendComplete = true;
760             } else {
761                 pPacket = NULL;
762             }
763 
764             LOCK_HCI_TX(pProt);
765 
766         }
767 
768     } while (false);
769 
770     pProt->SendProcessCount--;
771     A_ASSERT(pProt->SendProcessCount >= 0);
772     UNLOCK_HCI_TX(pProt);
773 
774     if (Synchronous) {
775         A_ASSERT(pPacket != NULL);
776         if (!status && (!synchSendComplete)) {
777             status = A_EBUSY;
778             A_ASSERT(false);
779             LOCK_HCI_TX(pProt);
780             if (pPacket->ListLink.pNext != NULL) {
781                     /* remove from the queue */
782                 HTC_PACKET_REMOVE(&pProt->SendQueue,pPacket);
783             }
784             UNLOCK_HCI_TX(pProt);
785         }
786     } else {
787         if (status && (pPacket != NULL)) {
788             pPacket->Status = status;
789             DO_HCI_SEND_INDICATION(pProt,pPacket);
790         }
791     }
792 
793     AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HCITrySend:  \n"));
794     return status;
795 }
796 
FlushSendQueue(struct gmbox_proto_hci_uart * pProt)797 static void FlushSendQueue(struct gmbox_proto_hci_uart *pProt)
798 {
799     struct htc_packet          *pPacket;
800     struct htc_packet_queue    discardQueue;
801 
802     INIT_HTC_PACKET_QUEUE(&discardQueue);
803 
804     LOCK_HCI_TX(pProt);
805 
806     if (!HTC_QUEUE_EMPTY(&pProt->SendQueue)) {
807         HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&discardQueue,&pProt->SendQueue);
808     }
809 
810     UNLOCK_HCI_TX(pProt);
811 
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);
817     }
818 
819 }
820 
FlushRecvBuffers(struct gmbox_proto_hci_uart * pProt)821 static void FlushRecvBuffers(struct gmbox_proto_hci_uart *pProt)
822 {
823     struct htc_packet_queue discardQueue;
824     struct htc_packet *pPacket;
825 
826     INIT_HTC_PACKET_QUEUE(&discardQueue);
827 
828     LOCK_HCI_RX(pProt);
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);
832     }
833     if (!HTC_QUEUE_EMPTY(&pProt->HCIEventBuffers)) {
834         HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&discardQueue,&pProt->HCIEventBuffers);
835     }
836     UNLOCK_HCI_RX(pProt);
837 
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);
843     }
844 
845 }
846 
847 /*** protocol module install entry point ***/
848 
GMboxProtocolInstall(struct ar6k_device * pDev)849 int GMboxProtocolInstall(struct ar6k_device *pDev)
850 {
851     int                status = 0;
852     struct gmbox_proto_hci_uart    *pProtocol = NULL;
853 
854     do {
855 
856         pProtocol = A_MALLOC(sizeof(struct gmbox_proto_hci_uart));
857 
858         if (NULL == pProtocol) {
859             status = A_NO_MEMORY;
860             break;
861         }
862 
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);
870 
871     } while (false);
872 
873     if (!status) {
874         LOCK_AR6K(pDev);
875         DEV_GMBOX_SET_PROTOCOL(pDev,
876                                HCIUartMessagePending,
877                                CreditsAvailableCallback,
878                                FailureCallback,
879                                StateDumpCallback,
880                                pProtocol);
881         UNLOCK_AR6K(pDev);
882     } else {
883         if (pProtocol != NULL) {
884             HCIUartCleanup(pProtocol);
885         }
886     }
887 
888     return status;
889 }
890 
891 /*** protocol module uninstall entry point ***/
GMboxProtocolUninstall(struct ar6k_device * pDev)892 void GMboxProtocolUninstall(struct ar6k_device *pDev)
893 {
894     struct gmbox_proto_hci_uart *pProtocol = (struct gmbox_proto_hci_uart *)DEV_GMBOX_GET_PROTOCOL(pDev);
895 
896     if (pProtocol != NULL) {
897 
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;
903         }
904 
905         HCIUartCleanup(pProtocol);
906         DEV_GMBOX_SET_PROTOCOL(pDev,NULL,NULL,NULL,NULL,NULL);
907     }
908 
909 }
910 
NotifyTransportReady(struct gmbox_proto_hci_uart * pProt)911 static int NotifyTransportReady(struct gmbox_proto_hci_uart  *pProt)
912 {
913     struct hci_transport_properties props;
914     int                 status = 0;
915 
916     do {
917 
918         A_MEMZERO(&props,sizeof(props));
919 
920             /* HCI UART only needs one extra byte at the head to indicate the packet TYPE */
921         props.HeadRoom = 1;
922         props.TailRoom = 0;
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,
928                                                     &props,
929                                                     pProt->HCIConfig.pContext);
930         }
931 
932     } while (false);
933 
934     return status;
935 }
936 
937 /***********  HCI UART protocol implementation ************************************************/
938 
HCI_TransportAttach(void * HTCHandle,struct hci_transport_config_info * pInfo)939 HCI_TRANSPORT_HANDLE HCI_TransportAttach(void *HTCHandle, struct hci_transport_config_info *pInfo)
940 {
941     struct gmbox_proto_hci_uart  *pProtocol = NULL;
942     struct ar6k_device           *pDev;
943 
944     AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("+HCI_TransportAttach \n"));
945 
946     pDev = HTCGetAR6KDevice(HTCHandle);
947 
948     LOCK_AR6K(pDev);
949 
950     do {
951 
952         pProtocol = (struct gmbox_proto_hci_uart *)DEV_GMBOX_GET_PROTOCOL(pDev);
953 
954         if (NULL == pProtocol) {
955             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("GMBOX protocol not installed! \n"));
956             break;
957         }
958 
959         if (pProtocol->HCIAttached) {
960             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("GMBOX protocol already attached! \n"));
961             break;
962         }
963 
964         memcpy(&pProtocol->HCIConfig, pInfo, sizeof(struct hci_transport_config_info));
965 
966         A_ASSERT(pProtocol->HCIConfig.pHCIPktRecv != NULL);
967         A_ASSERT(pProtocol->HCIConfig.pHCISendComplete != NULL);
968 
969         pProtocol->HCIAttached = true;
970 
971     } while (false);
972 
973     UNLOCK_AR6K(pDev);
974 
975     if (pProtocol != NULL) {
976             /* TODO ... should we use a worker? */
977         NotifyTransportReady(pProtocol);
978     }
979 
980     AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("-HCI_TransportAttach (0x%lX) \n",(unsigned long)pProtocol));
981     return (HCI_TRANSPORT_HANDLE)pProtocol;
982 }
983 
HCI_TransportDetach(HCI_TRANSPORT_HANDLE HciTrans)984 void HCI_TransportDetach(HCI_TRANSPORT_HANDLE HciTrans)
985 {
986     struct gmbox_proto_hci_uart  *pProtocol = (struct gmbox_proto_hci_uart *)HciTrans;
987     struct ar6k_device           *pDev = pProtocol->pDev;
988 
989     AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("+HCI_TransportDetach \n"));
990 
991     LOCK_AR6K(pDev);
992     if (!pProtocol->HCIAttached) {
993         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("GMBOX protocol not attached! \n"));
994         UNLOCK_AR6K(pDev);
995         return;
996     }
997     pProtocol->HCIAttached = false;
998     UNLOCK_AR6K(pDev);
999 
1000     HCI_TransportStop(HciTrans);
1001     AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("-HCI_TransportAttach \n"));
1002 }
1003 
HCI_TransportAddReceivePkts(HCI_TRANSPORT_HANDLE HciTrans,struct htc_packet_queue * pQueue)1004 int HCI_TransportAddReceivePkts(HCI_TRANSPORT_HANDLE HciTrans, struct htc_packet_queue *pQueue)
1005 {
1006     struct gmbox_proto_hci_uart  *pProt = (struct gmbox_proto_hci_uart *)HciTrans;
1007     int              status = 0;
1008     bool                unblockRecv = false;
1009     struct htc_packet            *pPacket;
1010 
1011     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HCI_TransportAddReceivePkt \n"));
1012 
1013     LOCK_HCI_RX(pProt);
1014 
1015     do {
1016 
1017         if (pProt->HCIStopped) {
1018             status = A_ECANCELED;
1019             break;
1020         }
1021 
1022         pPacket = HTC_GET_PKT_AT_HEAD(pQueue);
1023 
1024         if (NULL == pPacket) {
1025             status = A_EINVAL;
1026             break;
1027         }
1028 
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)));
1031 
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);
1036         } else {
1037             status = A_EINVAL;
1038             break;
1039         }
1040 
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;
1047                 unblockRecv = true;
1048             }
1049         }
1050 
1051     } while (false);
1052 
1053     UNLOCK_HCI_RX(pProt);
1054 
1055     if (status) {
1056         while (!HTC_QUEUE_EMPTY(pQueue)) {
1057             pPacket = HTC_PACKET_DEQUEUE(pQueue);
1058             pPacket->Status = A_ECANCELED;
1059             DO_HCI_RECV_INDICATION(pProt,pPacket);
1060         }
1061     }
1062 
1063     if (unblockRecv) {
1064         DevGMboxIRQAction(pProt->pDev, GMBOX_RECV_IRQ_ENABLE, PROC_IO_ASYNC);
1065     }
1066 
1067     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HCI_TransportAddReceivePkt \n"));
1068 
1069     return 0;
1070 }
1071 
HCI_TransportSendPkt(HCI_TRANSPORT_HANDLE HciTrans,struct htc_packet * pPacket,bool Synchronous)1072 int HCI_TransportSendPkt(HCI_TRANSPORT_HANDLE HciTrans, struct htc_packet *pPacket, bool Synchronous)
1073 {
1074     struct gmbox_proto_hci_uart  *pProt = (struct gmbox_proto_hci_uart *)HciTrans;
1075 
1076     return HCITrySend(pProt,pPacket,Synchronous);
1077 }
1078 
HCI_TransportStop(HCI_TRANSPORT_HANDLE HciTrans)1079 void HCI_TransportStop(HCI_TRANSPORT_HANDLE HciTrans)
1080 {
1081     struct gmbox_proto_hci_uart  *pProt = (struct gmbox_proto_hci_uart *)HciTrans;
1082 
1083     AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("+HCI_TransportStop \n"));
1084 
1085     LOCK_AR6K(pProt->pDev);
1086     if (pProt->HCIStopped) {
1087         UNLOCK_AR6K(pProt->pDev);
1088         AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("-HCI_TransportStop \n"));
1089         return;
1090     }
1091     pProt->HCIStopped = true;
1092     UNLOCK_AR6K(pProt->pDev);
1093 
1094         /* disable interrupts */
1095     DevGMboxIRQAction(pProt->pDev, GMBOX_DISABLE_ALL, PROC_IO_SYNC);
1096     FlushSendQueue(pProt);
1097     FlushRecvBuffers(pProt);
1098 
1099         /* signal bridge side to power down BT */
1100     DevGMboxSetTargetInterrupt(pProt->pDev, MBOX_SIG_HCI_BRIDGE_BT_OFF, BTOFF_TIMEOUT_MS);
1101 
1102     AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("-HCI_TransportStop \n"));
1103 }
1104 
HCI_TransportStart(HCI_TRANSPORT_HANDLE HciTrans)1105 int HCI_TransportStart(HCI_TRANSPORT_HANDLE HciTrans)
1106 {
1107     int              status;
1108     struct gmbox_proto_hci_uart  *pProt = (struct gmbox_proto_hci_uart *)HciTrans;
1109 
1110     AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("+HCI_TransportStart \n"));
1111 
1112         /* set stopped in case we have a problem in starting */
1113     pProt->HCIStopped = true;
1114 
1115     do {
1116 
1117         status = InitTxCreditState(pProt);
1118 
1119         if (status) {
1120             break;
1121         }
1122 
1123         status = DevGMboxIRQAction(pProt->pDev, GMBOX_ERRORS_IRQ_ENABLE, PROC_IO_SYNC);
1124 
1125         if (status) {
1126             break;
1127         }
1128             /* enable recv */
1129         status = DevGMboxIRQAction(pProt->pDev, GMBOX_RECV_IRQ_ENABLE, PROC_IO_SYNC);
1130 
1131         if (status) {
1132             break;
1133         }
1134             /* signal bridge side to power up BT */
1135         status = DevGMboxSetTargetInterrupt(pProt->pDev, MBOX_SIG_HCI_BRIDGE_BT_ON, BTON_TIMEOUT_MS);
1136 
1137         if (status) {
1138             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HCI_TransportStart : Failed to trigger BT ON \n"));
1139             break;
1140         }
1141 
1142             /* we made it */
1143         pProt->HCIStopped = false;
1144 
1145     } while (false);
1146 
1147     AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("-HCI_TransportStart \n"));
1148 
1149     return status;
1150 }
1151 
HCI_TransportEnableDisableAsyncRecv(HCI_TRANSPORT_HANDLE HciTrans,bool Enable)1152 int HCI_TransportEnableDisableAsyncRecv(HCI_TRANSPORT_HANDLE HciTrans, bool Enable)
1153 {
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,
1157                              PROC_IO_SYNC);
1158 
1159 }
1160 
HCI_TransportRecvHCIEventSync(HCI_TRANSPORT_HANDLE HciTrans,struct htc_packet * pPacket,int MaxPollMS)1161 int HCI_TransportRecvHCIEventSync(HCI_TRANSPORT_HANDLE HciTrans,
1162                                        struct htc_packet           *pPacket,
1163                                        int                  MaxPollMS)
1164 {
1165     struct gmbox_proto_hci_uart  *pProt = (struct gmbox_proto_hci_uart *)HciTrans;
1166     int              status = 0;
1167     u8 lookAhead[8];
1168     int                   bytes;
1169     int                   totalRecvLength;
1170 
1171     MaxPollMS = MaxPollMS / 16;
1172 
1173     if (MaxPollMS < 2) {
1174         MaxPollMS = 2;
1175     }
1176 
1177     while (MaxPollMS) {
1178 
1179         bytes = sizeof(lookAhead);
1180         status = DevGMboxRecvLookAheadPeek(pProt->pDev,lookAhead,&bytes);
1181         if (status) {
1182             break;
1183         }
1184 
1185         if (bytes < 3) {
1186             AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("HCI recv poll got bytes: %d, retry : %d \n",
1187                         bytes, MaxPollMS));
1188             A_MDELAY(16);
1189             MaxPollMS--;
1190             continue;
1191         }
1192 
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 */
1200                 break;
1201             default:
1202                 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("**Invalid HCI packet type: %d \n",lookAhead[0]));
1203                 status = A_EPROTO;
1204                 break;
1205         }
1206 
1207         if (status) {
1208             break;
1209         }
1210 
1211         pPacket->Completion = NULL;
1212         status = DevGMboxRead(pProt->pDev,pPacket,totalRecvLength);
1213         if (status) {
1214             break;
1215         }
1216 
1217         pPacket->pBuffer++;
1218         pPacket->ActualLength = totalRecvLength - 1;
1219         pPacket->Status = 0;
1220         break;
1221     }
1222 
1223     if (MaxPollMS == 0) {
1224         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HCI recv poll timeout! \n"));
1225         status = A_ERROR;
1226     }
1227 
1228     return status;
1229 }
1230 
1231 #define LSB_SCRATCH_IDX     4
1232 #define MSB_SCRATCH_IDX     5
HCI_TransportSetBaudRate(HCI_TRANSPORT_HANDLE HciTrans,u32 Baud)1233 int HCI_TransportSetBaudRate(HCI_TRANSPORT_HANDLE HciTrans, u32 Baud)
1234 {
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;
1238     int status = 0;
1239 
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
1243      */
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);
1250     if (0 != status) {
1251         AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to set up baud rate in scratch register!"));
1252         return status;
1253     }
1254 
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);
1257     if (0 != status) {
1258         AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to tell target to change baud rate!"));
1259     }
1260 
1261     return status;
1262 }
1263 
HCI_TransportEnablePowerMgmt(HCI_TRANSPORT_HANDLE HciTrans,bool Enable)1264 int HCI_TransportEnablePowerMgmt(HCI_TRANSPORT_HANDLE HciTrans, bool Enable)
1265 {
1266     int status;
1267     struct gmbox_proto_hci_uart  *pProt = (struct gmbox_proto_hci_uart *)HciTrans;
1268 
1269     if (Enable) {
1270         status = DevGMboxSetTargetInterrupt(pProt->pDev, MBOX_SIG_HCI_BRIDGE_PWR_SAV_ON, BTPWRSAV_TIMEOUT_MS);
1271     } else {
1272         status = DevGMboxSetTargetInterrupt(pProt->pDev, MBOX_SIG_HCI_BRIDGE_PWR_SAV_OFF, BTPWRSAV_TIMEOUT_MS);
1273     }
1274 
1275     if (status) {
1276         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to enable/disable HCI power management!\n"));
1277     } else {
1278         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HCI power management enabled/disabled!\n"));
1279     }
1280 
1281     return status;
1282 }
1283 
1284 #endif  //ATH_AR6K_ENABLE_GMBOX
1285 
1286