3 * Copyright (c) 2007 Atheros Communications Inc.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation;
11 * Software distributed under the License is distributed on an "AS
12 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
13 * implied. See the License for the specific language governing
14 * rights and limitations under the License.
20 #include "htc_internal.h"
23 static HTC_INIT_INFO HTCInitInfo = {NULL,NULL,NULL};
24 static A_BOOL HTCInitialized = FALSE;
26 static A_STATUS HTCTargetInsertedHandler(void *hif_handle);
27 static A_STATUS HTCTargetRemovedHandler(void *handle, A_STATUS status);
28 static void HTCReportFailure(void *Context);
30 /* Initializes the HTC layer */
31 A_STATUS HTCInit(HTC_INIT_INFO *pInitInfo)
33 HTC_CALLBACKS htcCallbacks;
35 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCInit: Enter\n"));
37 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCInit: Exit\n"));
41 A_MEMCPY(&HTCInitInfo,pInitInfo,sizeof(HTC_INIT_INFO));
43 A_MEMZERO(&htcCallbacks, sizeof(HTC_CALLBACKS));
45 /* setup HIF layer callbacks */
46 htcCallbacks.deviceInsertedHandler = HTCTargetInsertedHandler;
47 htcCallbacks.deviceRemovedHandler = HTCTargetRemovedHandler;
48 /* the device layer handles these */
49 htcCallbacks.rwCompletionHandler = DevRWCompletionHandler;
50 htcCallbacks.dsrHandler = DevDsrHandler;
51 HIFInit(&htcCallbacks);
52 HTCInitialized = TRUE;
54 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCInit: Exit\n"));
58 void HTCFreeControlBuffer(HTC_TARGET *target, HTC_PACKET *pPacket, HTC_PACKET_QUEUE *pList)
61 HTC_PACKET_ENQUEUE(pList,pPacket);
65 HTC_PACKET *HTCAllocControlBuffer(HTC_TARGET *target, HTC_PACKET_QUEUE *pList)
70 pPacket = HTC_PACKET_DEQUEUE(pList);
76 /* cleanup the HTC instance */
77 static void HTCCleanup(HTC_TARGET *target)
79 if (A_IS_MUTEX_VALID(&target->HTCLock)) {
80 A_MUTEX_DELETE(&target->HTCLock);
83 if (A_IS_MUTEX_VALID(&target->HTCRxLock)) {
84 A_MUTEX_DELETE(&target->HTCRxLock);
87 if (A_IS_MUTEX_VALID(&target->HTCTxLock)) {
88 A_MUTEX_DELETE(&target->HTCTxLock);
90 /* free our instance */
94 /* registered target arrival callback from the HIF layer */
95 static A_STATUS HTCTargetInsertedHandler(void *hif_handle)
97 HTC_TARGET *target = NULL;
101 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcTargetInserted - Enter\n"));
105 /* allocate target memory */
106 if ((target = (HTC_TARGET *)A_MALLOC(sizeof(HTC_TARGET))) == NULL) {
107 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to allocate memory\n"));
112 A_MEMZERO(target, sizeof(HTC_TARGET));
113 A_MUTEX_INIT(&target->HTCLock);
114 A_MUTEX_INIT(&target->HTCRxLock);
115 A_MUTEX_INIT(&target->HTCTxLock);
116 INIT_HTC_PACKET_QUEUE(&target->ControlBufferTXFreeList);
117 INIT_HTC_PACKET_QUEUE(&target->ControlBufferRXFreeList);
119 /* give device layer the hif device handle */
120 target->Device.HIFDevice = hif_handle;
121 /* give the device layer our context (for event processing)
122 * the device layer will register it's own context with HIF
123 * so we need to set this so we can fetch it in the target remove handler */
124 target->Device.HTCContext = target;
125 /* set device layer target failure callback */
126 target->Device.TargetFailureCallback = HTCReportFailure;
127 /* set device layer recv message pending callback */
128 target->Device.MessagePendingCallback = HTCRecvMessagePendingHandler;
129 target->EpWaitingForBuffers = ENDPOINT_MAX;
131 /* setup device layer */
132 status = DevSetup(&target->Device);
134 if (A_FAILED(status)) {
138 /* carve up buffers/packets for control messages */
139 for (i = 0; i < NUM_CONTROL_RX_BUFFERS; i++) {
140 HTC_PACKET *pControlPacket;
141 pControlPacket = &target->HTCControlBuffers[i].HtcPacket;
142 SET_HTC_PACKET_INFO_RX_REFILL(pControlPacket,
144 target->HTCControlBuffers[i].Buffer,
145 HTC_CONTROL_BUFFER_SIZE,
147 HTC_FREE_CONTROL_RX(target,pControlPacket);
150 for (;i < NUM_CONTROL_BUFFERS;i++) {
151 HTC_PACKET *pControlPacket;
152 pControlPacket = &target->HTCControlBuffers[i].HtcPacket;
153 INIT_HTC_PACKET_INFO(pControlPacket,
154 target->HTCControlBuffers[i].Buffer,
155 HTC_CONTROL_BUFFER_SIZE);
156 HTC_FREE_CONTROL_TX(target,pControlPacket);
161 if (A_SUCCESS(status)) {
162 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" calling AddInstance callback \n"));
163 /* announce ourselves */
164 HTCInitInfo.AddInstance((HTC_HANDLE)target);
166 if (target != NULL) {
171 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcTargetInserted - Exit\n"));
176 /* registered removal callback from the HIF layer */
177 static A_STATUS HTCTargetRemovedHandler(void *handle, A_STATUS status)
181 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCTargetRemovedHandler handle:0x%X \n",(A_UINT32)handle));
183 if (NULL == handle) {
184 /* this could be NULL in the event that target initialization failed */
188 target = ((AR6K_DEVICE *)handle)->HTCContext;
190 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" removing target:0x%X instance:0x%X ... \n",
191 (A_UINT32)target, (A_UINT32)target->pInstanceContext));
193 if (target->pInstanceContext != NULL) {
194 /* let upper layer know, it needs to call HTCStop() */
195 HTCInitInfo.DeleteInstance(target->pInstanceContext);
198 HIFShutDownDevice(target->Device.HIFDevice);
201 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCTargetRemovedHandler \n"));
205 /* get the low level HIF device for the caller , the caller may wish to do low level
207 void *HTCGetHifDevice(HTC_HANDLE HTCHandle)
209 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
210 return target->Device.HIFDevice;
213 /* set the instance block for this HTC handle, so that on removal, the blob can be
214 * returned to the caller */
215 void HTCSetInstance(HTC_HANDLE HTCHandle, void *Instance)
217 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
219 target->pInstanceContext = Instance;
222 /* wait for the target to arrive (sends HTC Ready message)
223 * this operation is fully synchronous and the message is polled for */
224 A_STATUS HTCWaitTarget(HTC_HANDLE HTCHandle)
226 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
228 HTC_PACKET *pPacket = NULL;
229 HTC_READY_MSG *pRdyMsg;
230 HTC_SERVICE_CONNECT_REQ connect;
231 HTC_SERVICE_CONNECT_RESP resp;
233 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Enter (target:0x%X) \n", (A_UINT32)target));
237 #ifdef MBOXHW_UNIT_TEST
239 status = DoMboxHWTest(&target->Device);
241 if (status != A_OK) {
247 /* we should be getting 1 control message that the target is ready */
248 status = HTCWaitforControlMessage(target, &pPacket);
250 if (A_FAILED(status)) {
251 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Target Not Available!!\n"));
255 /* we controlled the buffer creation so it has to be properly aligned */
256 pRdyMsg = (HTC_READY_MSG *)pPacket->pBuffer;
258 if ((pRdyMsg->MessageID != HTC_MSG_READY_ID) ||
259 (pPacket->ActualLength < sizeof(HTC_READY_MSG))) {
260 /* this message is not valid */
261 AR_DEBUG_ASSERT(FALSE);
266 if (pRdyMsg->CreditCount == 0 || pRdyMsg->CreditSize == 0) {
267 /* this message is not valid */
268 AR_DEBUG_ASSERT(FALSE);
273 target->TargetCredits = pRdyMsg->CreditCount;
274 target->TargetCreditSize = pRdyMsg->CreditSize;
276 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" Target Ready: credits: %d credit size: %d\n",
277 target->TargetCredits, target->TargetCreditSize));
279 /* setup our pseudo HTC control endpoint connection */
280 A_MEMZERO(&connect,sizeof(connect));
281 A_MEMZERO(&resp,sizeof(resp));
282 connect.EpCallbacks.pContext = target;
283 connect.EpCallbacks.EpTxComplete = HTCControlTxComplete;
284 connect.EpCallbacks.EpRecv = HTCControlRecv;
285 connect.EpCallbacks.EpRecvRefill = NULL; /* not needed */
286 connect.EpCallbacks.EpSendFull = NULL; /* not needed */
287 connect.EpCallbacks.EpSendAvail = NULL; /* not needed */
288 connect.MaxSendQueueDepth = NUM_CONTROL_BUFFERS;
289 connect.ServiceID = HTC_CTRL_RSVD_SVC;
291 /* connect fake service */
292 status = HTCConnectService((HTC_HANDLE)target,
296 if (!A_FAILED(status)) {
302 if (pPacket != NULL) {
303 HTC_FREE_CONTROL_RX(target,pPacket);
306 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Exit\n"));
313 /* Start HTC, enable interrupts and let the target know host has finished setup */
314 A_STATUS HTCStart(HTC_HANDLE HTCHandle)
316 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
320 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Enter\n"));
322 /* now that we are starting, push control receive buffers into the
323 * HTC control endpoint */
326 pPacket = HTC_ALLOC_CONTROL_RX(target);
327 if (NULL == pPacket) {
330 HTCAddReceivePkt((HTC_HANDLE)target,pPacket);
335 AR_DEBUG_ASSERT(target->InitCredits != NULL);
336 AR_DEBUG_ASSERT(target->EpCreditDistributionListHead != NULL);
337 AR_DEBUG_ASSERT(target->EpCreditDistributionListHead->pNext != NULL);
339 /* call init credits callback to do the distribution ,
340 * NOTE: the first entry in the distribution list is ENDPOINT_0, so
341 * we pass the start of the list after this one. */
342 target->InitCredits(target->pCredDistContext,
343 target->EpCreditDistributionListHead->pNext,
344 target->TargetCredits);
346 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_TRC)) {
347 DumpCreditDistStates(target);
350 /* the caller is done connecting to services, so we can indicate to the
351 * target that the setup phase is complete */
352 status = HTCSendSetupComplete(target);
354 if (A_FAILED(status)) {
358 /* unmask interrupts */
359 status = DevUnmaskInterrupts(&target->Device);
361 if (A_FAILED(status)) {
367 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Exit\n"));
372 /* stop HTC communications, i.e. stop interrupt reception, and flush all queued buffers */
373 void HTCStop(HTC_HANDLE HTCHandle)
375 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
376 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCStop \n"));
378 /* mark that we are shutting down .. */
379 target->HTCStateFlags |= HTC_STATE_STOPPING;
381 /* Masking interrupts is a synchronous operation, when this function returns
382 * all pending HIF I/O has completed, we can safely flush the queues */
383 DevMaskInterrupts(&target->Device);
385 /* flush all send packets */
386 HTCFlushSendPkts(target);
387 /* flush all recv buffers */
388 HTCFlushRecvBuffers(target);
390 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCStop \n"));
393 /* undo what was done in HTCInit() */
394 void HTCShutDown(void)
396 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCShutDown: \n"));
397 HTCInitialized = FALSE;
399 HIFShutDownDevice(NULL);
400 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCShutDown: \n"));
403 void HTCDumpCreditStates(HTC_HANDLE HTCHandle)
405 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
409 DumpCreditDistStates(target);
411 UNLOCK_HTC_TX(target);
414 /* report a target failure from the device, this is a callback from the device layer
415 * which uses a mechanism to report errors from the target (i.e. special interrupts) */
416 static void HTCReportFailure(void *Context)
418 HTC_TARGET *target = (HTC_TARGET *)Context;
420 target->TargetFailure = TRUE;
422 if ((target->pInstanceContext != NULL) && (HTCInitInfo.TargetFailure != NULL)) {
423 /* let upper layer know, it needs to call HTCStop() */
424 HTCInitInfo.TargetFailure(target->pInstanceContext, A_ERROR);
428 void DebugDumpBytes(A_UCHAR *buffer, A_UINT16 length, char *pDescription)
432 A_UINT16 offset, count;
434 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("<---------Dumping %d Bytes : %s ------>\n", length, pDescription));
438 for(i = 0; i < length; i++) {
439 sprintf(stream + offset, "%2.2X ", buffer[i]);
446 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("[H]: %s\n", stream));
447 A_MEMZERO(stream, 60);
452 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("[H]: %s\n", stream));
455 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("<------------------------------------------------->\n"));
458 A_BOOL HTCGetEndpointStatistics(HTC_HANDLE HTCHandle,
459 HTC_ENDPOINT_ID Endpoint,
460 HTC_ENDPOINT_STAT_ACTION Action,
461 HTC_ENDPOINT_STATS *pStats)
464 #ifdef HTC_EP_STAT_PROFILING
465 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
466 A_BOOL clearStats = FALSE;
467 A_BOOL sample = FALSE;
470 case HTC_EP_STAT_SAMPLE :
473 case HTC_EP_STAT_SAMPLE_AND_CLEAR :
477 case HTC_EP_STAT_CLEAR :
484 A_ASSERT(Endpoint < ENDPOINT_MAX);
486 /* lock out TX and RX while we sample and/or clear */
491 A_ASSERT(pStats != NULL);
492 /* return the stats to the caller */
493 A_MEMCPY(pStats, &target->EndPoint[Endpoint].EndPointStats, sizeof(HTC_ENDPOINT_STATS));
498 A_MEMZERO(&target->EndPoint[Endpoint].EndPointStats, sizeof(HTC_ENDPOINT_STATS));
501 UNLOCK_HTC_RX(target);
502 UNLOCK_HTC_TX(target);