1 //------------------------------------------------------------------------------
2 // <copyright file="htc.c" company="Atheros">
3 // Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
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.
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.
19 //------------------------------------------------------------------------------
20 //==============================================================================
21 // Author(s): ="Atheros"
22 //==============================================================================
23 #include "htc_internal.h"
25 #ifdef ATH_DEBUG_MODULE
26 static struct ath_debug_mask_description g_HTCDebugDescription
[] = {
27 { ATH_DEBUG_SEND
, "Send"},
28 { ATH_DEBUG_RECV
, "Recv"},
29 { ATH_DEBUG_SYNC
, "Sync"},
30 { ATH_DEBUG_DUMP
, "Dump Data (RX or TX)"},
31 { ATH_DEBUG_IRQ
, "Interrupt Processing"}
34 ATH_DEBUG_INSTANTIATE_MODULE_VAR(htc
,
36 "Host Target Communications",
37 ATH_DEBUG_MASK_DEFAULTS
,
38 ATH_DEBUG_DESCRIPTION_COUNT(g_HTCDebugDescription
),
39 g_HTCDebugDescription
);
43 static void HTCReportFailure(void *Context
);
44 static void ResetEndpointStates(HTC_TARGET
*target
);
46 void HTCFreeControlBuffer(HTC_TARGET
*target
, HTC_PACKET
*pPacket
, HTC_PACKET_QUEUE
*pList
)
49 HTC_PACKET_ENQUEUE(pList
,pPacket
);
53 HTC_PACKET
*HTCAllocControlBuffer(HTC_TARGET
*target
, HTC_PACKET_QUEUE
*pList
)
58 pPacket
= HTC_PACKET_DEQUEUE(pList
);
64 /* cleanup the HTC instance */
65 static void HTCCleanup(HTC_TARGET
*target
)
69 DevCleanup(&target
->Device
);
71 for (i
= 0;i
< NUM_CONTROL_BUFFERS
;i
++) {
72 if (target
->HTCControlBuffers
[i
].Buffer
) {
73 A_FREE(target
->HTCControlBuffers
[i
].Buffer
);
77 if (A_IS_MUTEX_VALID(&target
->HTCLock
)) {
78 A_MUTEX_DELETE(&target
->HTCLock
);
81 if (A_IS_MUTEX_VALID(&target
->HTCRxLock
)) {
82 A_MUTEX_DELETE(&target
->HTCRxLock
);
85 if (A_IS_MUTEX_VALID(&target
->HTCTxLock
)) {
86 A_MUTEX_DELETE(&target
->HTCTxLock
);
88 /* free our instance */
92 /* registered target arrival callback from the HIF layer */
93 HTC_HANDLE
HTCCreate(void *hif_handle
, HTC_INIT_INFO
*pInfo
)
95 HTC_TARGET
*target
= NULL
;
99 u32 blocksizes
[HTC_MAILBOX_NUM_MAX
];
101 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
, ("HTCCreate - Enter\n"));
103 A_REGISTER_MODULE_DEBUG_INFO(htc
);
107 /* allocate target memory */
108 if ((target
= (HTC_TARGET
*)A_MALLOC(sizeof(HTC_TARGET
))) == NULL
) {
109 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, ("Unable to allocate memory\n"));
114 A_MEMZERO(target
, sizeof(HTC_TARGET
));
115 A_MUTEX_INIT(&target
->HTCLock
);
116 A_MUTEX_INIT(&target
->HTCRxLock
);
117 A_MUTEX_INIT(&target
->HTCTxLock
);
118 INIT_HTC_PACKET_QUEUE(&target
->ControlBufferTXFreeList
);
119 INIT_HTC_PACKET_QUEUE(&target
->ControlBufferRXFreeList
);
121 /* give device layer the hif device handle */
122 target
->Device
.HIFDevice
= hif_handle
;
123 /* give the device layer our context (for event processing)
124 * the device layer will register it's own context with HIF
125 * so we need to set this so we can fetch it in the target remove handler */
126 target
->Device
.HTCContext
= target
;
127 /* set device layer target failure callback */
128 target
->Device
.TargetFailureCallback
= HTCReportFailure
;
129 /* set device layer recv message pending callback */
130 target
->Device
.MessagePendingCallback
= HTCRecvMessagePendingHandler
;
131 target
->EpWaitingForBuffers
= ENDPOINT_MAX
;
133 memcpy(&target
->HTCInitInfo
,pInfo
,sizeof(HTC_INIT_INFO
));
135 ResetEndpointStates(target
);
137 /* setup device layer */
138 status
= DevSetup(&target
->Device
);
145 /* get the block sizes */
146 status
= HIFConfigureDevice(hif_handle
, HIF_DEVICE_GET_MBOX_BLOCK_SIZE
,
147 blocksizes
, sizeof(blocksizes
));
149 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("Failed to get block size info from HIF layer...\n"));
153 /* Set the control buffer size based on the block size */
154 if (blocksizes
[1] > HTC_MAX_CONTROL_MESSAGE_LENGTH
) {
155 ctrl_bufsz
= blocksizes
[1] + HTC_HDR_LENGTH
;
157 ctrl_bufsz
= HTC_MAX_CONTROL_MESSAGE_LENGTH
+ HTC_HDR_LENGTH
;
159 for (i
= 0;i
< NUM_CONTROL_BUFFERS
;i
++) {
160 target
->HTCControlBuffers
[i
].Buffer
= A_MALLOC(ctrl_bufsz
);
161 if (target
->HTCControlBuffers
[i
].Buffer
== NULL
) {
162 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, ("Unable to allocate memory\n"));
172 /* carve up buffers/packets for control messages */
173 for (i
= 0; i
< NUM_CONTROL_RX_BUFFERS
; i
++) {
174 HTC_PACKET
*pControlPacket
;
175 pControlPacket
= &target
->HTCControlBuffers
[i
].HtcPacket
;
176 SET_HTC_PACKET_INFO_RX_REFILL(pControlPacket
,
178 target
->HTCControlBuffers
[i
].Buffer
,
181 HTC_FREE_CONTROL_RX(target
,pControlPacket
);
184 for (;i
< NUM_CONTROL_BUFFERS
;i
++) {
185 HTC_PACKET
*pControlPacket
;
186 pControlPacket
= &target
->HTCControlBuffers
[i
].HtcPacket
;
187 INIT_HTC_PACKET_INFO(pControlPacket
,
188 target
->HTCControlBuffers
[i
].Buffer
,
190 HTC_FREE_CONTROL_TX(target
,pControlPacket
);
196 if (target
!= NULL
) {
202 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
, ("HTCCreate - Exit\n"));
207 void HTCDestroy(HTC_HANDLE HTCHandle
)
209 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
210 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
, ("+HTCDestroy .. Destroying :0x%lX \n",(unsigned long)target
));
212 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
, ("-HTCDestroy \n"));
215 /* get the low level HIF device for the caller , the caller may wish to do low level
217 void *HTCGetHifDevice(HTC_HANDLE HTCHandle
)
219 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
220 return target
->Device
.HIFDevice
;
223 /* wait for the target to arrive (sends HTC Ready message)
224 * this operation is fully synchronous and the message is polled for */
225 int HTCWaitTarget(HTC_HANDLE HTCHandle
)
227 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
229 HTC_PACKET
*pPacket
= NULL
;
230 HTC_READY_EX_MSG
*pRdyMsg
;
232 HTC_SERVICE_CONNECT_REQ connect
;
233 HTC_SERVICE_CONNECT_RESP resp
;
235 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
, ("HTCWaitTarget - Enter (target:0x%lX) \n", (unsigned long)target
));
239 #ifdef MBOXHW_UNIT_TEST
241 status
= DoMboxHWTest(&target
->Device
);
249 /* we should be getting 1 control message that the target is ready */
250 status
= HTCWaitforControlMessage(target
, &pPacket
);
253 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, (" Target Not Available!!\n"));
257 /* we controlled the buffer creation so it has to be properly aligned */
258 pRdyMsg
= (HTC_READY_EX_MSG
*)pPacket
->pBuffer
;
260 if ((pRdyMsg
->Version2_0_Info
.MessageID
!= HTC_MSG_READY_ID
) ||
261 (pPacket
->ActualLength
< sizeof(HTC_READY_MSG
))) {
262 /* this message is not valid */
263 AR_DEBUG_ASSERT(false);
269 if (pRdyMsg
->Version2_0_Info
.CreditCount
== 0 || pRdyMsg
->Version2_0_Info
.CreditSize
== 0) {
270 /* this message is not valid */
271 AR_DEBUG_ASSERT(false);
276 target
->TargetCredits
= pRdyMsg
->Version2_0_Info
.CreditCount
;
277 target
->TargetCreditSize
= pRdyMsg
->Version2_0_Info
.CreditSize
;
279 AR_DEBUG_PRINTF(ATH_DEBUG_WARN
, (" Target Ready: credits: %d credit size: %d\n",
280 target
->TargetCredits
, target
->TargetCreditSize
));
282 /* check if this is an extended ready message */
283 if (pPacket
->ActualLength
>= sizeof(HTC_READY_EX_MSG
)) {
284 /* this is an extended message */
285 target
->HTCTargetVersion
= pRdyMsg
->HTCVersion
;
286 target
->MaxMsgPerBundle
= pRdyMsg
->MaxMsgsPerHTCBundle
;
289 target
->HTCTargetVersion
= HTC_VERSION_2P0
;
290 target
->MaxMsgPerBundle
= 0;
293 #ifdef HTC_FORCE_LEGACY_2P0
294 /* for testing and comparison...*/
295 target
->HTCTargetVersion
= HTC_VERSION_2P0
;
296 target
->MaxMsgPerBundle
= 0;
299 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
,
300 ("Using HTC Protocol Version : %s (%d)\n ",
301 (target
->HTCTargetVersion
== HTC_VERSION_2P0
) ? "2.0" : ">= 2.1",
302 target
->HTCTargetVersion
));
304 if (target
->MaxMsgPerBundle
> 0) {
305 /* limit what HTC can handle */
306 target
->MaxMsgPerBundle
= min(HTC_HOST_MAX_MSG_PER_BUNDLE
, target
->MaxMsgPerBundle
);
307 /* target supports message bundling, setup device layer */
308 if (DevSetupMsgBundling(&target
->Device
,target
->MaxMsgPerBundle
)) {
309 /* device layer can't handle bundling */
310 target
->MaxMsgPerBundle
= 0;
312 /* limit bundle what the device layer can handle */
313 target
->MaxMsgPerBundle
= min(DEV_GET_MAX_MSG_PER_BUNDLE(&target
->Device
),
314 target
->MaxMsgPerBundle
);
318 if (target
->MaxMsgPerBundle
> 0) {
319 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
,
320 (" HTC bundling allowed. Max Msg Per HTC Bundle: %d\n", target
->MaxMsgPerBundle
));
322 if (DEV_GET_MAX_BUNDLE_SEND_LENGTH(&target
->Device
) != 0) {
323 target
->SendBundlingEnabled
= true;
325 if (DEV_GET_MAX_BUNDLE_RECV_LENGTH(&target
->Device
) != 0) {
326 target
->RecvBundlingEnabled
= true;
329 if (!DEV_IS_LEN_BLOCK_ALIGNED(&target
->Device
,target
->TargetCreditSize
)) {
330 AR_DEBUG_PRINTF(ATH_DEBUG_WARN
, ("*** Credit size: %d is not block aligned! Disabling send bundling \n",
331 target
->TargetCreditSize
));
332 /* disallow send bundling since the credit size is not aligned to a block size
333 * the I/O block padding will spill into the next credit buffer which is fatal */
334 target
->SendBundlingEnabled
= false;
338 /* setup our pseudo HTC control endpoint connection */
339 A_MEMZERO(&connect
,sizeof(connect
));
340 A_MEMZERO(&resp
,sizeof(resp
));
341 connect
.EpCallbacks
.pContext
= target
;
342 connect
.EpCallbacks
.EpTxComplete
= HTCControlTxComplete
;
343 connect
.EpCallbacks
.EpRecv
= HTCControlRecv
;
344 connect
.EpCallbacks
.EpRecvRefill
= NULL
; /* not needed */
345 connect
.EpCallbacks
.EpSendFull
= NULL
; /* not nedded */
346 connect
.MaxSendQueueDepth
= NUM_CONTROL_BUFFERS
;
347 connect
.ServiceID
= HTC_CTRL_RSVD_SVC
;
349 /* connect fake service */
350 status
= HTCConnectService((HTC_HANDLE
)target
,
360 if (pPacket
!= NULL
) {
361 HTC_FREE_CONTROL_RX(target
,pPacket
);
364 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
, ("HTCWaitTarget - Exit\n"));
371 /* Start HTC, enable interrupts and let the target know host has finished setup */
372 int HTCStart(HTC_HANDLE HTCHandle
)
374 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
378 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
, ("HTCStart Enter\n"));
380 /* make sure interrupts are disabled at the chip level,
381 * this function can be called again from a reboot of the target without shutting down HTC */
382 DevDisableInterrupts(&target
->Device
);
383 /* make sure state is cleared again */
384 target
->OpStateFlags
= 0;
385 target
->RecvStateFlags
= 0;
387 /* now that we are starting, push control receive buffers into the
388 * HTC control endpoint */
391 pPacket
= HTC_ALLOC_CONTROL_RX(target
);
392 if (NULL
== pPacket
) {
395 HTCAddReceivePkt((HTC_HANDLE
)target
,pPacket
);
400 AR_DEBUG_ASSERT(target
->InitCredits
!= NULL
);
401 AR_DEBUG_ASSERT(target
->EpCreditDistributionListHead
!= NULL
);
402 AR_DEBUG_ASSERT(target
->EpCreditDistributionListHead
->pNext
!= NULL
);
404 /* call init credits callback to do the distribution ,
405 * NOTE: the first entry in the distribution list is ENDPOINT_0, so
406 * we pass the start of the list after this one. */
407 target
->InitCredits(target
->pCredDistContext
,
408 target
->EpCreditDistributionListHead
->pNext
,
409 target
->TargetCredits
);
411 #ifdef ATH_DEBUG_MODULE
413 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_TRC
)) {
414 DumpCreditDistStates(target
);
418 /* the caller is done connecting to services, so we can indicate to the
419 * target that the setup phase is complete */
420 status
= HTCSendSetupComplete(target
);
426 /* unmask interrupts */
427 status
= DevUnmaskInterrupts(&target
->Device
);
435 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
, ("HTCStart Exit\n"));
439 static void ResetEndpointStates(HTC_TARGET
*target
)
441 struct htc_endpoint
*pEndpoint
;
444 for (i
= ENDPOINT_0
; i
< ENDPOINT_MAX
; i
++) {
445 pEndpoint
= &target
->EndPoint
[i
];
447 A_MEMZERO(&pEndpoint
->CreditDist
, sizeof(pEndpoint
->CreditDist
));
448 pEndpoint
->ServiceID
= 0;
449 pEndpoint
->MaxMsgLength
= 0;
450 pEndpoint
->MaxTxQueueDepth
= 0;
451 #ifdef HTC_EP_STAT_PROFILING
452 A_MEMZERO(&pEndpoint
->EndPointStats
,sizeof(pEndpoint
->EndPointStats
));
454 INIT_HTC_PACKET_QUEUE(&pEndpoint
->RxBuffers
);
455 INIT_HTC_PACKET_QUEUE(&pEndpoint
->TxQueue
);
456 INIT_HTC_PACKET_QUEUE(&pEndpoint
->RecvIndicationQueue
);
457 pEndpoint
->target
= target
;
459 /* reset distribution list */
460 target
->EpCreditDistributionListHead
= NULL
;
463 /* stop HTC communications, i.e. stop interrupt reception, and flush all queued buffers */
464 void HTCStop(HTC_HANDLE HTCHandle
)
466 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
467 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
, ("+HTCStop \n"));
470 /* mark that we are shutting down .. */
471 target
->OpStateFlags
|= HTC_OP_STATE_STOPPING
;
474 /* Masking interrupts is a synchronous operation, when this function returns
475 * all pending HIF I/O has completed, we can safely flush the queues */
476 DevMaskInterrupts(&target
->Device
);
480 // Is this delay required
482 A_MDELAY(200); // wait for IRQ process done
484 /* flush all send packets */
485 HTCFlushSendPkts(target
);
486 /* flush all recv buffers */
487 HTCFlushRecvBuffers(target
);
489 DevCleanupMsgBundling(&target
->Device
);
491 ResetEndpointStates(target
);
493 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
, ("-HTCStop \n"));
496 #ifdef ATH_DEBUG_MODULE
497 void HTCDumpCreditStates(HTC_HANDLE HTCHandle
)
499 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
503 DumpCreditDistStates(target
);
505 UNLOCK_HTC_TX(target
);
507 DumpAR6KDevState(&target
->Device
);
510 /* report a target failure from the device, this is a callback from the device layer
511 * which uses a mechanism to report errors from the target (i.e. special interrupts) */
512 static void HTCReportFailure(void *Context
)
514 HTC_TARGET
*target
= (HTC_TARGET
*)Context
;
516 target
->TargetFailure
= true;
518 if (target
->HTCInitInfo
.TargetFailure
!= NULL
) {
519 /* let upper layer know, it needs to call HTCStop() */
520 target
->HTCInitInfo
.TargetFailure(target
->HTCInitInfo
.pContext
, A_ERROR
);
524 bool HTCGetEndpointStatistics(HTC_HANDLE HTCHandle
,
525 HTC_ENDPOINT_ID Endpoint
,
526 HTC_ENDPOINT_STAT_ACTION Action
,
527 HTC_ENDPOINT_STATS
*pStats
)
530 #ifdef HTC_EP_STAT_PROFILING
531 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
532 bool clearStats
= false;
536 case HTC_EP_STAT_SAMPLE
:
539 case HTC_EP_STAT_SAMPLE_AND_CLEAR
:
543 case HTC_EP_STAT_CLEAR
:
550 A_ASSERT(Endpoint
< ENDPOINT_MAX
);
552 /* lock out TX and RX while we sample and/or clear */
557 A_ASSERT(pStats
!= NULL
);
558 /* return the stats to the caller */
559 memcpy(pStats
, &target
->EndPoint
[Endpoint
].EndPointStats
, sizeof(HTC_ENDPOINT_STATS
));
564 A_MEMZERO(&target
->EndPoint
[Endpoint
].EndPointStats
, sizeof(HTC_ENDPOINT_STATS
));
567 UNLOCK_HTC_RX(target
);
568 UNLOCK_HTC_TX(target
);
576 struct ar6k_device
*HTCGetAR6KDevice(void *HTCHandle
)
578 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
579 return &target
->Device
;