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
);