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(struct htc_target
*target
);
46 void HTCFreeControlBuffer(struct htc_target
*target
, struct htc_packet
*pPacket
, struct htc_packet_queue
*pList
)
49 HTC_PACKET_ENQUEUE(pList
,pPacket
);
53 struct htc_packet
*HTCAllocControlBuffer(struct htc_target
*target
, struct htc_packet_queue
*pList
)
55 struct htc_packet
*pPacket
;
58 pPacket
= HTC_PACKET_DEQUEUE(pList
);
64 /* cleanup the HTC instance */
65 static void HTCCleanup(struct htc_target
*target
)
69 DevCleanup(&target
->Device
);
71 for (i
= 0;i
< NUM_CONTROL_BUFFERS
;i
++) {
72 if (target
->HTCControlBuffers
[i
].Buffer
) {
73 kfree(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
, struct htc_init_info
*pInfo
)
95 struct 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
= (struct htc_target
*)A_MALLOC(sizeof(struct htc_target
))) == NULL
) {
109 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, ("Unable to allocate memory\n"));
114 A_MEMZERO(target
, sizeof(struct 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(struct 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 struct 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 struct 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 struct 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 struct 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 struct htc_target
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
229 struct htc_packet
*pPacket
= NULL
;
230 HTC_READY_EX_MSG
*pRdyMsg
;
232 struct htc_service_connect_req connect
;
233 struct 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 struct htc_target
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
375 struct htc_packet
*pPacket
;
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(struct 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 A_MEMZERO(&pEndpoint
->EndPointStats
,sizeof(pEndpoint
->EndPointStats
));
452 INIT_HTC_PACKET_QUEUE(&pEndpoint
->RxBuffers
);
453 INIT_HTC_PACKET_QUEUE(&pEndpoint
->TxQueue
);
454 INIT_HTC_PACKET_QUEUE(&pEndpoint
->RecvIndicationQueue
);
455 pEndpoint
->target
= target
;
457 /* reset distribution list */
458 target
->EpCreditDistributionListHead
= NULL
;
461 /* stop HTC communications, i.e. stop interrupt reception, and flush all queued buffers */
462 void HTCStop(HTC_HANDLE HTCHandle
)
464 struct htc_target
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
465 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
, ("+HTCStop \n"));
468 /* mark that we are shutting down .. */
469 target
->OpStateFlags
|= HTC_OP_STATE_STOPPING
;
472 /* Masking interrupts is a synchronous operation, when this function returns
473 * all pending HIF I/O has completed, we can safely flush the queues */
474 DevMaskInterrupts(&target
->Device
);
478 // Is this delay required
480 A_MDELAY(200); // wait for IRQ process done
482 /* flush all send packets */
483 HTCFlushSendPkts(target
);
484 /* flush all recv buffers */
485 HTCFlushRecvBuffers(target
);
487 DevCleanupMsgBundling(&target
->Device
);
489 ResetEndpointStates(target
);
491 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
, ("-HTCStop \n"));
494 #ifdef ATH_DEBUG_MODULE
495 void HTCDumpCreditStates(HTC_HANDLE HTCHandle
)
497 struct htc_target
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
501 DumpCreditDistStates(target
);
503 UNLOCK_HTC_TX(target
);
505 DumpAR6KDevState(&target
->Device
);
508 /* report a target failure from the device, this is a callback from the device layer
509 * which uses a mechanism to report errors from the target (i.e. special interrupts) */
510 static void HTCReportFailure(void *Context
)
512 struct htc_target
*target
= (struct htc_target
*)Context
;
514 target
->TargetFailure
= true;
516 if (target
->HTCInitInfo
.TargetFailure
!= NULL
) {
517 /* let upper layer know, it needs to call HTCStop() */
518 target
->HTCInitInfo
.TargetFailure(target
->HTCInitInfo
.pContext
, A_ERROR
);
522 bool HTCGetEndpointStatistics(HTC_HANDLE HTCHandle
,
523 HTC_ENDPOINT_ID Endpoint
,
524 HTC_ENDPOINT_STAT_ACTION Action
,
525 struct htc_endpoint_stats
*pStats
)
528 struct htc_target
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
529 bool clearStats
= false;
533 case HTC_EP_STAT_SAMPLE
:
536 case HTC_EP_STAT_SAMPLE_AND_CLEAR
:
540 case HTC_EP_STAT_CLEAR
:
547 A_ASSERT(Endpoint
< ENDPOINT_MAX
);
549 /* lock out TX and RX while we sample and/or clear */
554 A_ASSERT(pStats
!= NULL
);
555 /* return the stats to the caller */
556 memcpy(pStats
, &target
->EndPoint
[Endpoint
].EndPointStats
, sizeof(struct htc_endpoint_stats
));
561 A_MEMZERO(&target
->EndPoint
[Endpoint
].EndPointStats
, sizeof(struct htc_endpoint_stats
));
564 UNLOCK_HTC_RX(target
);
565 UNLOCK_HTC_TX(target
);
570 struct ar6k_device
*HTCGetAR6KDevice(void *HTCHandle
)
572 struct htc_target
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
573 return &target
->Device
;