From 4c9c79642d1c8353a339e5b662c0a735fdcae424 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 23 Sep 2009 14:27:26 +0200 Subject: Add ar6000 wireless driver. --- drivers/ar6000/htc/htc.c | 508 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 508 insertions(+) create mode 100644 drivers/ar6000/htc/htc.c (limited to 'drivers/ar6000/htc/htc.c') diff --git a/drivers/ar6000/htc/htc.c b/drivers/ar6000/htc/htc.c new file mode 100644 index 00000000000..d52ed944e0d --- /dev/null +++ b/drivers/ar6000/htc/htc.c @@ -0,0 +1,508 @@ +/* + * + * Copyright (c) 2007 Atheros Communications Inc. + * All rights reserved. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + */ + +#include "htc_internal.h" + + +static HTC_INIT_INFO HTCInitInfo = {NULL,NULL,NULL}; +static A_BOOL HTCInitialized = FALSE; + +static A_STATUS HTCTargetInsertedHandler(void *hif_handle); +static A_STATUS HTCTargetRemovedHandler(void *handle, A_STATUS status); +static void HTCReportFailure(void *Context); + +/* Initializes the HTC layer */ +A_STATUS HTCInit(HTC_INIT_INFO *pInitInfo) +{ + HTC_CALLBACKS htcCallbacks; + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCInit: Enter\n")); + if (HTCInitialized) { + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCInit: Exit\n")); + return A_OK; + } + + A_MEMCPY(&HTCInitInfo,pInitInfo,sizeof(HTC_INIT_INFO)); + + A_MEMZERO(&htcCallbacks, sizeof(HTC_CALLBACKS)); + + /* setup HIF layer callbacks */ + htcCallbacks.deviceInsertedHandler = HTCTargetInsertedHandler; + htcCallbacks.deviceRemovedHandler = HTCTargetRemovedHandler; + /* the device layer handles these */ + htcCallbacks.rwCompletionHandler = DevRWCompletionHandler; + htcCallbacks.dsrHandler = DevDsrHandler; + HIFInit(&htcCallbacks); + HTCInitialized = TRUE; + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCInit: Exit\n")); + return A_OK; +} + +void HTCFreeControlBuffer(HTC_TARGET *target, HTC_PACKET *pPacket, HTC_PACKET_QUEUE *pList) +{ + LOCK_HTC(target); + HTC_PACKET_ENQUEUE(pList,pPacket); + UNLOCK_HTC(target); +} + +HTC_PACKET *HTCAllocControlBuffer(HTC_TARGET *target, HTC_PACKET_QUEUE *pList) +{ + HTC_PACKET *pPacket; + + LOCK_HTC(target); + pPacket = HTC_PACKET_DEQUEUE(pList); + UNLOCK_HTC(target); + + return pPacket; +} + +/* cleanup the HTC instance */ +static void HTCCleanup(HTC_TARGET *target) +{ + if (A_IS_MUTEX_VALID(&target->HTCLock)) { + A_MUTEX_DELETE(&target->HTCLock); + } + + if (A_IS_MUTEX_VALID(&target->HTCRxLock)) { + A_MUTEX_DELETE(&target->HTCRxLock); + } + + if (A_IS_MUTEX_VALID(&target->HTCTxLock)) { + A_MUTEX_DELETE(&target->HTCTxLock); + } + /* free our instance */ + A_FREE(target); +} + +/* registered target arrival callback from the HIF layer */ +static A_STATUS HTCTargetInsertedHandler(void *hif_handle) +{ + HTC_TARGET *target = NULL; + A_STATUS status; + int i; + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcTargetInserted - Enter\n")); + + do { + + /* allocate target memory */ + if ((target = (HTC_TARGET *)A_MALLOC(sizeof(HTC_TARGET))) == NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to allocate memory\n")); + status = A_ERROR; + break; + } + + A_MEMZERO(target, sizeof(HTC_TARGET)); + A_MUTEX_INIT(&target->HTCLock); + A_MUTEX_INIT(&target->HTCRxLock); + A_MUTEX_INIT(&target->HTCTxLock); + INIT_HTC_PACKET_QUEUE(&target->ControlBufferTXFreeList); + INIT_HTC_PACKET_QUEUE(&target->ControlBufferRXFreeList); + + /* give device layer the hif device handle */ + target->Device.HIFDevice = hif_handle; + /* give the device layer our context (for event processing) + * the device layer will register it's own context with HIF + * so we need to set this so we can fetch it in the target remove handler */ + target->Device.HTCContext = target; + /* set device layer target failure callback */ + target->Device.TargetFailureCallback = HTCReportFailure; + /* set device layer recv message pending callback */ + target->Device.MessagePendingCallback = HTCRecvMessagePendingHandler; + target->EpWaitingForBuffers = ENDPOINT_MAX; + + /* setup device layer */ + status = DevSetup(&target->Device); + + if (A_FAILED(status)) { + break; + } + + /* carve up buffers/packets for control messages */ + for (i = 0; i < NUM_CONTROL_RX_BUFFERS; i++) { + HTC_PACKET *pControlPacket; + pControlPacket = &target->HTCControlBuffers[i].HtcPacket; + SET_HTC_PACKET_INFO_RX_REFILL(pControlPacket, + target, + target->HTCControlBuffers[i].Buffer, + HTC_CONTROL_BUFFER_SIZE, + ENDPOINT_0); + HTC_FREE_CONTROL_RX(target,pControlPacket); + } + + for (;i < NUM_CONTROL_BUFFERS;i++) { + HTC_PACKET *pControlPacket; + pControlPacket = &target->HTCControlBuffers[i].HtcPacket; + INIT_HTC_PACKET_INFO(pControlPacket, + target->HTCControlBuffers[i].Buffer, + HTC_CONTROL_BUFFER_SIZE); + HTC_FREE_CONTROL_TX(target,pControlPacket); + } + + } while (FALSE); + + if (A_SUCCESS(status)) { + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" calling AddInstance callback \n")); + /* announce ourselves */ + HTCInitInfo.AddInstance((HTC_HANDLE)target); + } else { + if (target != NULL) { + HTCCleanup(target); + } + } + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcTargetInserted - Exit\n")); + + return status; +} + +/* registered removal callback from the HIF layer */ +static A_STATUS HTCTargetRemovedHandler(void *handle, A_STATUS status) +{ + HTC_TARGET *target; + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCTargetRemovedHandler handle:0x%X \n",(A_UINT32)handle)); + + if (NULL == handle) { + /* this could be NULL in the event that target initialization failed */ + return A_OK; + } + + target = ((AR6K_DEVICE *)handle)->HTCContext; + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" removing target:0x%X instance:0x%X ... \n", + (A_UINT32)target, (A_UINT32)target->pInstanceContext)); + + if (target->pInstanceContext != NULL) { + /* let upper layer know, it needs to call HTCStop() */ + HTCInitInfo.DeleteInstance(target->pInstanceContext); + } + + HIFShutDownDevice(target->Device.HIFDevice); + + HTCCleanup(target); + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCTargetRemovedHandler \n")); + return A_OK; +} + +/* get the low level HIF device for the caller , the caller may wish to do low level + * HIF requests */ +void *HTCGetHifDevice(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + return target->Device.HIFDevice; +} + +/* set the instance block for this HTC handle, so that on removal, the blob can be + * returned to the caller */ +void HTCSetInstance(HTC_HANDLE HTCHandle, void *Instance) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + + target->pInstanceContext = Instance; +} + +/* wait for the target to arrive (sends HTC Ready message) + * this operation is fully synchronous and the message is polled for */ +A_STATUS HTCWaitTarget(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + A_STATUS status; + HTC_PACKET *pPacket = NULL; + HTC_READY_MSG *pRdyMsg; + HTC_SERVICE_CONNECT_REQ connect; + HTC_SERVICE_CONNECT_RESP resp; + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Enter (target:0x%X) \n", (A_UINT32)target)); + + do { + +#ifdef MBOXHW_UNIT_TEST + + status = DoMboxHWTest(&target->Device); + + if (status != A_OK) { + break; + } + +#endif + + /* we should be getting 1 control message that the target is ready */ + status = HTCWaitforControlMessage(target, &pPacket); + + if (A_FAILED(status)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Target Not Available!!\n")); + break; + } + + /* we controlled the buffer creation so it has to be properly aligned */ + pRdyMsg = (HTC_READY_MSG *)pPacket->pBuffer; + + if ((pRdyMsg->MessageID != HTC_MSG_READY_ID) || + (pPacket->ActualLength < sizeof(HTC_READY_MSG))) { + /* this message is not valid */ + AR_DEBUG_ASSERT(FALSE); + status = A_EPROTO; + break; + } + + if (pRdyMsg->CreditCount == 0 || pRdyMsg->CreditSize == 0) { + /* this message is not valid */ + AR_DEBUG_ASSERT(FALSE); + status = A_EPROTO; + break; + } + + target->TargetCredits = pRdyMsg->CreditCount; + target->TargetCreditSize = pRdyMsg->CreditSize; + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" Target Ready: credits: %d credit size: %d\n", + target->TargetCredits, target->TargetCreditSize)); + + /* setup our pseudo HTC control endpoint connection */ + A_MEMZERO(&connect,sizeof(connect)); + A_MEMZERO(&resp,sizeof(resp)); + connect.EpCallbacks.pContext = target; + connect.EpCallbacks.EpTxComplete = HTCControlTxComplete; + connect.EpCallbacks.EpRecv = HTCControlRecv; + connect.EpCallbacks.EpRecvRefill = NULL; /* not needed */ + connect.EpCallbacks.EpSendFull = NULL; /* not needed */ + connect.EpCallbacks.EpSendAvail = NULL; /* not needed */ + connect.MaxSendQueueDepth = NUM_CONTROL_BUFFERS; + connect.ServiceID = HTC_CTRL_RSVD_SVC; + + /* connect fake service */ + status = HTCConnectService((HTC_HANDLE)target, + &connect, + &resp); + + if (!A_FAILED(status)) { + break; + } + + } while (FALSE); + + if (pPacket != NULL) { + HTC_FREE_CONTROL_RX(target,pPacket); + } + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Exit\n")); + + return status; +} + + + +/* Start HTC, enable interrupts and let the target know host has finished setup */ +A_STATUS HTCStart(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_PACKET *pPacket; + A_STATUS status; + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Enter\n")); + + /* now that we are starting, push control receive buffers into the + * HTC control endpoint */ + + while (1) { + pPacket = HTC_ALLOC_CONTROL_RX(target); + if (NULL == pPacket) { + break; + } + HTCAddReceivePkt((HTC_HANDLE)target,pPacket); + } + + do { + + AR_DEBUG_ASSERT(target->InitCredits != NULL); + AR_DEBUG_ASSERT(target->EpCreditDistributionListHead != NULL); + AR_DEBUG_ASSERT(target->EpCreditDistributionListHead->pNext != NULL); + + /* call init credits callback to do the distribution , + * NOTE: the first entry in the distribution list is ENDPOINT_0, so + * we pass the start of the list after this one. */ + target->InitCredits(target->pCredDistContext, + target->EpCreditDistributionListHead->pNext, + target->TargetCredits); + + if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_TRC)) { + DumpCreditDistStates(target); + } + + /* the caller is done connecting to services, so we can indicate to the + * target that the setup phase is complete */ + status = HTCSendSetupComplete(target); + + if (A_FAILED(status)) { + break; + } + + /* unmask interrupts */ + status = DevUnmaskInterrupts(&target->Device); + + if (A_FAILED(status)) { + HTCStop(target); + } + + } while (FALSE); + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Exit\n")); + return status; +} + + +/* stop HTC communications, i.e. stop interrupt reception, and flush all queued buffers */ +void HTCStop(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCStop \n")); + + /* mark that we are shutting down .. */ + target->HTCStateFlags |= HTC_STATE_STOPPING; + + /* Masking interrupts is a synchronous operation, when this function returns + * all pending HIF I/O has completed, we can safely flush the queues */ + DevMaskInterrupts(&target->Device); + + /* flush all send packets */ + HTCFlushSendPkts(target); + /* flush all recv buffers */ + HTCFlushRecvBuffers(target); + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCStop \n")); +} + +/* undo what was done in HTCInit() */ +void HTCShutDown(void) +{ + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCShutDown: \n")); + HTCInitialized = FALSE; + /* undo HTCInit */ + HIFShutDownDevice(NULL); + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCShutDown: \n")); +} + +void HTCDumpCreditStates(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + + LOCK_HTC_TX(target); + + DumpCreditDistStates(target); + + UNLOCK_HTC_TX(target); +} + +/* report a target failure from the device, this is a callback from the device layer + * which uses a mechanism to report errors from the target (i.e. special interrupts) */ +static void HTCReportFailure(void *Context) +{ + HTC_TARGET *target = (HTC_TARGET *)Context; + + target->TargetFailure = TRUE; + + if ((target->pInstanceContext != NULL) && (HTCInitInfo.TargetFailure != NULL)) { + /* let upper layer know, it needs to call HTCStop() */ + HTCInitInfo.TargetFailure(target->pInstanceContext, A_ERROR); + } +} + +void DebugDumpBytes(A_UCHAR *buffer, A_UINT16 length, char *pDescription) +{ + A_CHAR stream[60]; + A_UINT32 i; + A_UINT16 offset, count; + + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("<---------Dumping %d Bytes : %s ------>\n", length, pDescription)); + + count = 0; + offset = 0; + for(i = 0; i < length; i++) { + sprintf(stream + offset, "%2.2X ", buffer[i]); + count ++; + offset += 3; + + if(count == 16) { + count = 0; + offset = 0; + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("[H]: %s\n", stream)); + A_MEMZERO(stream, 60); + } + } + + if(offset != 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("[H]: %s\n", stream)); + } + + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("<------------------------------------------------->\n")); +} + +A_BOOL HTCGetEndpointStatistics(HTC_HANDLE HTCHandle, + HTC_ENDPOINT_ID Endpoint, + HTC_ENDPOINT_STAT_ACTION Action, + HTC_ENDPOINT_STATS *pStats) +{ + +#ifdef HTC_EP_STAT_PROFILING + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + A_BOOL clearStats = FALSE; + A_BOOL sample = FALSE; + + switch (Action) { + case HTC_EP_STAT_SAMPLE : + sample = TRUE; + break; + case HTC_EP_STAT_SAMPLE_AND_CLEAR : + sample = TRUE; + clearStats = TRUE; + break; + case HTC_EP_STAT_CLEAR : + clearStats = TRUE; + break; + default: + break; + } + + A_ASSERT(Endpoint < ENDPOINT_MAX); + + /* lock out TX and RX while we sample and/or clear */ + LOCK_HTC_TX(target); + LOCK_HTC_RX(target); + + if (sample) { + A_ASSERT(pStats != NULL); + /* return the stats to the caller */ + A_MEMCPY(pStats, &target->EndPoint[Endpoint].EndPointStats, sizeof(HTC_ENDPOINT_STATS)); + } + + if (clearStats) { + /* reset stats */ + A_MEMZERO(&target->EndPoint[Endpoint].EndPointStats, sizeof(HTC_ENDPOINT_STATS)); + } + + UNLOCK_HTC_RX(target); + UNLOCK_HTC_TX(target); + + return TRUE; +#else + return FALSE; +#endif +} -- cgit v1.2.3