/drivers/staging/ath6kl/htc2/AR6000/ar6k_gmbox_hciuart.c
C | 1284 lines | 927 code | 250 blank | 107 comment | 198 complexity | 1b29aa484ad4e135bba1ac19582363be MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
- //------------------------------------------------------------------------------
- // <copyright file="ar6k_prot_hciUart.c" company="Atheros">
- // Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
- //
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- //
- //
- //------------------------------------------------------------------------------
- //==============================================================================
- // Protocol module for use in bridging HCI-UART packets over the GMBOX interface
- //
- // Author(s): ="Atheros"
- //==============================================================================
- #include "a_config.h"
- #include "athdefs.h"
- #include "a_osapi.h"
- #include "../htc_debug.h"
- #include "hif.h"
- #include "htc_packet.h"
- #include "ar6k.h"
- #include "hci_transport_api.h"
- #include "gmboxif.h"
- #include "ar6000_diag.h"
- #include "hw/apb_map.h"
- #include "hw/mbox_reg.h"
- #ifdef ATH_AR6K_ENABLE_GMBOX
- #define HCI_UART_COMMAND_PKT 0x01
- #define HCI_UART_ACL_PKT 0x02
- #define HCI_UART_SCO_PKT 0x03
- #define HCI_UART_EVENT_PKT 0x04
- #define HCI_RECV_WAIT_BUFFERS (1 << 0)
- #define HCI_SEND_WAIT_CREDITS (1 << 0)
- #define HCI_UART_BRIDGE_CREDIT_SIZE 128
- #define CREDIT_POLL_COUNT 256
- #define HCI_DELAY_PER_INTERVAL_MS 10
- #define BTON_TIMEOUT_MS 500
- #define BTOFF_TIMEOUT_MS 500
- #define BAUD_TIMEOUT_MS 1
- #define BTPWRSAV_TIMEOUT_MS 1
- struct gmbox_proto_hci_uart {
- struct hci_transport_config_info HCIConfig;
- bool HCIAttached;
- bool HCIStopped;
- u32 RecvStateFlags;
- u32 SendStateFlags;
- HCI_TRANSPORT_PACKET_TYPE WaitBufferType;
- struct htc_packet_queue SendQueue; /* write queue holding HCI Command and ACL packets */
- struct htc_packet_queue HCIACLRecvBuffers; /* recv queue holding buffers for incomming ACL packets */
- struct htc_packet_queue HCIEventBuffers; /* recv queue holding buffers for incomming event packets */
- struct ar6k_device *pDev;
- A_MUTEX_T HCIRxLock;
- A_MUTEX_T HCITxLock;
- int CreditsMax;
- int CreditsConsumed;
- int CreditsAvailable;
- int CreditSize;
- int CreditsCurrentSeek;
- int SendProcessCount;
- };
- #define LOCK_HCI_RX(t) A_MUTEX_LOCK(&(t)->HCIRxLock);
- #define UNLOCK_HCI_RX(t) A_MUTEX_UNLOCK(&(t)->HCIRxLock);
- #define LOCK_HCI_TX(t) A_MUTEX_LOCK(&(t)->HCITxLock);
- #define UNLOCK_HCI_TX(t) A_MUTEX_UNLOCK(&(t)->HCITxLock);
- #define DO_HCI_RECV_INDICATION(p, pt) \
- do { \
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV, \
- ("HCI: Indicate Recv on packet:0x%lX status:%d len:%d type:%d \n", \
- (unsigned long)(pt), \
- (pt)->Status, \
- !(pt)->Status ? (pt)->ActualLength : 0, \
- HCI_GET_PACKET_TYPE(pt))); \
- (p)->HCIConfig.pHCIPktRecv((p)->HCIConfig.pContext, (pt)); \
- } while (0)
- #define DO_HCI_SEND_INDICATION(p,pt) \
- { AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: Indicate Send on packet:0x%lX status:%d type:%d \n", \
- (unsigned long)(pt),(pt)->Status,HCI_GET_PACKET_TYPE(pt))); \
- (p)->HCIConfig.pHCISendComplete((p)->HCIConfig.pContext, (pt)); \
- }
-
- static int HCITrySend(struct gmbox_proto_hci_uart *pProt, struct htc_packet *pPacket, bool Synchronous);
- static void HCIUartCleanup(struct gmbox_proto_hci_uart *pProtocol)
- {
- A_ASSERT(pProtocol != NULL);
-
- A_MUTEX_DELETE(&pProtocol->HCIRxLock);
- A_MUTEX_DELETE(&pProtocol->HCITxLock);
-
- kfree(pProtocol);
- }
- static int InitTxCreditState(struct gmbox_proto_hci_uart *pProt)
- {
- int status;
- int credits;
- int creditPollCount = CREDIT_POLL_COUNT;
- bool gotCredits = false;
- pProt->CreditsConsumed = 0;
-
- do {
-
- if (pProt->CreditsMax != 0) {
- /* we can only call this only once per target reset */
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HCI: InitTxCreditState - already called! \n"));
- A_ASSERT(false);
- status = A_EINVAL;
- break;
- }
-
- /* read the credit counter. At startup the target will set the credit counter
- * to the max available, we read this in a loop because it may take
- * multiple credit counter reads to get all credits */
-
- while (creditPollCount) {
-
- credits = 0;
- status = DevGMboxReadCreditCounter(pProt->pDev, PROC_IO_SYNC, &credits);
-
- if (status) {
- break;
- }
-
- if (!gotCredits && (0 == credits)) {
- creditPollCount--;
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: credit is 0, retrying (%d) \n",creditPollCount));
- A_MDELAY(HCI_DELAY_PER_INTERVAL_MS);
- continue;
- } else {
- gotCredits = true;
- }
-
- if (0 == credits) {
- break;
- }
-
- pProt->CreditsMax += credits;
- }
-
- if (status) {
- break;
- }
-
- if (0 == creditPollCount) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("** HCI : Failed to get credits! GMBOX Target was not available \n"));
- status = A_ERROR;
- break;
- }
-
- /* now get the size */
- status = DevGMboxReadCreditSize(pProt->pDev, &pProt->CreditSize);
-
- if (status) {
- break;
- }
-
- } while (false);
-
- if (!status) {
- pProt->CreditsAvailable = pProt->CreditsMax;
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("HCI : InitTxCreditState - credits avail: %d, size: %d \n",
- pProt->CreditsAvailable, pProt->CreditSize));
- }
-
- return status;
- }
- static int CreditsAvailableCallback(void *pContext, int Credits, bool CreditIRQEnabled)
- {
- struct gmbox_proto_hci_uart *pProt = (struct gmbox_proto_hci_uart *)pContext;
- bool enableCreditIrq = false;
- bool disableCreditIrq = false;
- bool doPendingSends = false;
- int status = 0;
-
- /** this callback is called under 2 conditions:
- * 1. The credit IRQ interrupt was enabled and signaled.
- * 2. A credit counter read completed.
- *
- * The function must not assume that the calling context can block !
- */
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+CreditsAvailableCallback (Credits:%d, IRQ:%s) \n",
- Credits, CreditIRQEnabled ? "ON" : "OFF"));
-
- LOCK_HCI_TX(pProt);
-
- do {
-
- if (0 == Credits) {
- if (!CreditIRQEnabled) {
- /* enable credit IRQ */
- enableCreditIrq = true;
- }
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: current credit state, consumed:%d available:%d max:%d seek:%d\n",
- pProt->CreditsConsumed,
- pProt->CreditsAvailable,
- pProt->CreditsMax,
- pProt->CreditsCurrentSeek));
-
- pProt->CreditsAvailable += Credits;
- A_ASSERT(pProt->CreditsAvailable <= pProt->CreditsMax);
- pProt->CreditsConsumed -= Credits;
- A_ASSERT(pProt->CreditsConsumed >= 0);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: new credit state, consumed:%d available:%d max:%d seek:%d\n",
- pProt->CreditsConsumed,
- pProt->CreditsAvailable,
- pProt->CreditsMax,
- pProt->CreditsCurrentSeek));
-
- if (pProt->CreditsAvailable >= pProt->CreditsCurrentSeek) {
- /* we have enough credits to fulfill at least 1 packet waiting in the queue */
- pProt->CreditsCurrentSeek = 0;
- pProt->SendStateFlags &= ~HCI_SEND_WAIT_CREDITS;
- doPendingSends = true;
- if (CreditIRQEnabled) {
- /* credit IRQ was enabled, we shouldn't need it anymore */
- disableCreditIrq = true;
- }
- } else {
-