]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/staging/ath6kl/htc2/AR6000/ar6k_gmbox_hciuart.c
Fix common misspellings
[mirror_ubuntu-bionic-kernel.git] / drivers / staging / ath6kl / htc2 / AR6000 / ar6k_gmbox_hciuart.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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 ***/
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
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
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
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
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
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
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
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
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
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
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
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