1 //------------------------------------------------------------------------------
2 // <copyright file="htc_services.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 void HTCControlTxComplete(void *Context
, HTC_PACKET
*pPacket
)
28 * we do not send control TX frames during normal runtime, only during setup */
29 AR_DEBUG_ASSERT(false);
32 /* callback when a control message arrives on this endpoint */
33 void HTCControlRecv(void *Context
, HTC_PACKET
*pPacket
)
35 AR_DEBUG_ASSERT(pPacket
->Endpoint
== ENDPOINT_0
);
37 if (pPacket
->Status
== A_ECANCELED
) {
38 /* this is a flush operation, return the control packet back to the pool */
39 HTC_FREE_CONTROL_RX((HTC_TARGET
*)Context
,pPacket
);
43 /* the only control messages we are expecting are NULL messages (credit resports) */
44 if (pPacket
->ActualLength
> 0) {
45 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
46 ("HTCControlRecv, got message with length:%d \n",
47 pPacket
->ActualLength
+ (u32
)HTC_HDR_LENGTH
));
49 #ifdef ATH_DEBUG_MODULE
50 /* dump header and message */
51 DebugDumpBytes(pPacket
->pBuffer
- HTC_HDR_LENGTH
,
52 pPacket
->ActualLength
+ HTC_HDR_LENGTH
,
53 "Unexpected ENDPOINT 0 Message");
57 HTC_RECYCLE_RX_PKT((HTC_TARGET
*)Context
,pPacket
,&((HTC_TARGET
*)Context
)->EndPoint
[0]);
60 int HTCSendSetupComplete(HTC_TARGET
*target
)
62 HTC_PACKET
*pSendPacket
= NULL
;
66 /* allocate a packet to send to the target */
67 pSendPacket
= HTC_ALLOC_CONTROL_TX(target
);
69 if (NULL
== pSendPacket
) {
74 if (target
->HTCTargetVersion
>= HTC_VERSION_2P1
) {
75 HTC_SETUP_COMPLETE_EX_MSG
*pSetupCompleteEx
;
78 pSetupCompleteEx
= (HTC_SETUP_COMPLETE_EX_MSG
*)pSendPacket
->pBuffer
;
79 A_MEMZERO(pSetupCompleteEx
, sizeof(HTC_SETUP_COMPLETE_EX_MSG
));
80 pSetupCompleteEx
->MessageID
= HTC_MSG_SETUP_COMPLETE_EX_ID
;
81 if (target
->MaxMsgPerBundle
> 0) {
82 /* host can do HTC bundling, indicate this to the target */
83 setupFlags
|= HTC_SETUP_COMPLETE_FLAGS_ENABLE_BUNDLE_RECV
;
84 pSetupCompleteEx
->MaxMsgsPerBundledRecv
= target
->MaxMsgPerBundle
;
86 A_MEMCPY(&pSetupCompleteEx
->SetupFlags
, &setupFlags
, sizeof(pSetupCompleteEx
->SetupFlags
));
87 SET_HTC_PACKET_INFO_TX(pSendPacket
,
89 (u8
*)pSetupCompleteEx
,
90 sizeof(HTC_SETUP_COMPLETE_EX_MSG
),
92 HTC_SERVICE_TX_PACKET_TAG
);
95 HTC_SETUP_COMPLETE_MSG
*pSetupComplete
;
96 /* assemble setup complete message */
97 pSetupComplete
= (HTC_SETUP_COMPLETE_MSG
*)pSendPacket
->pBuffer
;
98 A_MEMZERO(pSetupComplete
, sizeof(HTC_SETUP_COMPLETE_MSG
));
99 pSetupComplete
->MessageID
= HTC_MSG_SETUP_COMPLETE_ID
;
100 SET_HTC_PACKET_INFO_TX(pSendPacket
,
102 (u8
*)pSetupComplete
,
103 sizeof(HTC_SETUP_COMPLETE_MSG
),
105 HTC_SERVICE_TX_PACKET_TAG
);
108 /* we want synchronous operation */
109 pSendPacket
->Completion
= NULL
;
110 HTC_PREPARE_SEND_PKT(pSendPacket
,0,0,0);
111 /* send the message */
112 status
= HTCIssueSend(target
,pSendPacket
);
116 if (pSendPacket
!= NULL
) {
117 HTC_FREE_CONTROL_TX(target
,pSendPacket
);
124 int HTCConnectService(HTC_HANDLE HTCHandle
,
125 HTC_SERVICE_CONNECT_REQ
*pConnectReq
,
126 HTC_SERVICE_CONNECT_RESP
*pConnectResp
)
128 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
130 HTC_PACKET
*pRecvPacket
= NULL
;
131 HTC_PACKET
*pSendPacket
= NULL
;
132 HTC_CONNECT_SERVICE_RESPONSE_MSG
*pResponseMsg
;
133 HTC_CONNECT_SERVICE_MSG
*pConnectMsg
;
134 HTC_ENDPOINT_ID assignedEndpoint
= ENDPOINT_MAX
;
135 HTC_ENDPOINT
*pEndpoint
;
136 unsigned int maxMsgSize
= 0;
138 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
, ("+HTCConnectService, target:0x%lX SvcID:0x%X \n",
139 (unsigned long)target
, pConnectReq
->ServiceID
));
143 AR_DEBUG_ASSERT(pConnectReq
->ServiceID
!= 0);
145 if (HTC_CTRL_RSVD_SVC
== pConnectReq
->ServiceID
) {
146 /* special case for pseudo control service */
147 assignedEndpoint
= ENDPOINT_0
;
148 maxMsgSize
= HTC_MAX_CONTROL_MESSAGE_LENGTH
;
150 /* allocate a packet to send to the target */
151 pSendPacket
= HTC_ALLOC_CONTROL_TX(target
);
153 if (NULL
== pSendPacket
) {
154 AR_DEBUG_ASSERT(false);
155 status
= A_NO_MEMORY
;
158 /* assemble connect service message */
159 pConnectMsg
= (HTC_CONNECT_SERVICE_MSG
*)pSendPacket
->pBuffer
;
160 AR_DEBUG_ASSERT(pConnectMsg
!= NULL
);
161 A_MEMZERO(pConnectMsg
,sizeof(HTC_CONNECT_SERVICE_MSG
));
162 pConnectMsg
->MessageID
= HTC_MSG_CONNECT_SERVICE_ID
;
163 pConnectMsg
->ServiceID
= pConnectReq
->ServiceID
;
164 pConnectMsg
->ConnectionFlags
= pConnectReq
->ConnectionFlags
;
165 /* check caller if it wants to transfer meta data */
166 if ((pConnectReq
->pMetaData
!= NULL
) &&
167 (pConnectReq
->MetaDataLength
<= HTC_SERVICE_META_DATA_MAX_LENGTH
)) {
168 /* copy meta data into message buffer (after header ) */
169 A_MEMCPY((u8
*)pConnectMsg
+ sizeof(HTC_CONNECT_SERVICE_MSG
),
170 pConnectReq
->pMetaData
,
171 pConnectReq
->MetaDataLength
);
172 pConnectMsg
->ServiceMetaLength
= pConnectReq
->MetaDataLength
;
175 SET_HTC_PACKET_INFO_TX(pSendPacket
,
178 sizeof(HTC_CONNECT_SERVICE_MSG
) + pConnectMsg
->ServiceMetaLength
,
180 HTC_SERVICE_TX_PACKET_TAG
);
182 /* we want synchronous operation */
183 pSendPacket
->Completion
= NULL
;
184 HTC_PREPARE_SEND_PKT(pSendPacket
,0,0,0);
185 status
= HTCIssueSend(target
,pSendPacket
);
191 /* wait for response */
192 status
= HTCWaitforControlMessage(target
, &pRecvPacket
);
197 /* we controlled the buffer creation so it has to be properly aligned */
198 pResponseMsg
= (HTC_CONNECT_SERVICE_RESPONSE_MSG
*)pRecvPacket
->pBuffer
;
200 if ((pResponseMsg
->MessageID
!= HTC_MSG_CONNECT_SERVICE_RESPONSE_ID
) ||
201 (pRecvPacket
->ActualLength
< sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG
))) {
202 /* this message is not valid */
203 AR_DEBUG_ASSERT(false);
208 pConnectResp
->ConnectRespCode
= pResponseMsg
->Status
;
209 /* check response status */
210 if (pResponseMsg
->Status
!= HTC_SERVICE_SUCCESS
) {
211 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
212 (" Target failed service 0x%X connect request (status:%d)\n",
213 pResponseMsg
->ServiceID
, pResponseMsg
->Status
));
218 assignedEndpoint
= (HTC_ENDPOINT_ID
) pResponseMsg
->EndpointID
;
219 maxMsgSize
= pResponseMsg
->MaxMsgSize
;
221 if ((pConnectResp
->pMetaData
!= NULL
) &&
222 (pResponseMsg
->ServiceMetaLength
> 0) &&
223 (pResponseMsg
->ServiceMetaLength
<= HTC_SERVICE_META_DATA_MAX_LENGTH
)) {
224 /* caller supplied a buffer and the target responded with data */
225 int copyLength
= min((int)pConnectResp
->BufferLength
, (int)pResponseMsg
->ServiceMetaLength
);
226 /* copy the meta data */
227 A_MEMCPY(pConnectResp
->pMetaData
,
228 ((u8
*)pResponseMsg
) + sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG
),
230 pConnectResp
->ActualLength
= copyLength
;
235 /* the rest of these are parameter checks so set the error status */
238 if (assignedEndpoint
>= ENDPOINT_MAX
) {
239 AR_DEBUG_ASSERT(false);
243 if (0 == maxMsgSize
) {
244 AR_DEBUG_ASSERT(false);
248 pEndpoint
= &target
->EndPoint
[assignedEndpoint
];
249 pEndpoint
->Id
= assignedEndpoint
;
250 if (pEndpoint
->ServiceID
!= 0) {
251 /* endpoint already in use! */
252 AR_DEBUG_ASSERT(false);
256 /* return assigned endpoint to caller */
257 pConnectResp
->Endpoint
= assignedEndpoint
;
258 pConnectResp
->MaxMsgLength
= maxMsgSize
;
260 /* setup the endpoint */
261 pEndpoint
->ServiceID
= pConnectReq
->ServiceID
; /* this marks the endpoint in use */
262 pEndpoint
->MaxTxQueueDepth
= pConnectReq
->MaxSendQueueDepth
;
263 pEndpoint
->MaxMsgLength
= maxMsgSize
;
264 /* copy all the callbacks */
265 pEndpoint
->EpCallBacks
= pConnectReq
->EpCallbacks
;
266 /* set the credit distribution info for this endpoint, this information is
267 * passed back to the credit distribution callback function */
268 pEndpoint
->CreditDist
.ServiceID
= pConnectReq
->ServiceID
;
269 pEndpoint
->CreditDist
.pHTCReserved
= pEndpoint
;
270 pEndpoint
->CreditDist
.Endpoint
= assignedEndpoint
;
271 pEndpoint
->CreditDist
.TxCreditSize
= target
->TargetCreditSize
;
273 if (pConnectReq
->MaxSendMsgSize
!= 0) {
274 /* override TxCreditsPerMaxMsg calculation, this optimizes the credit-low indications
275 * since the host will actually issue smaller messages in the Send path */
276 if (pConnectReq
->MaxSendMsgSize
> maxMsgSize
) {
277 /* can't be larger than the maximum the target can support */
278 AR_DEBUG_ASSERT(false);
281 pEndpoint
->CreditDist
.TxCreditsPerMaxMsg
= pConnectReq
->MaxSendMsgSize
/ target
->TargetCreditSize
;
283 pEndpoint
->CreditDist
.TxCreditsPerMaxMsg
= maxMsgSize
/ target
->TargetCreditSize
;
286 if (0 == pEndpoint
->CreditDist
.TxCreditsPerMaxMsg
) {
287 pEndpoint
->CreditDist
.TxCreditsPerMaxMsg
= 1;
290 /* save local connection flags */
291 pEndpoint
->LocalConnectionFlags
= pConnectReq
->LocalConnectionFlags
;
297 if (pSendPacket
!= NULL
) {
298 HTC_FREE_CONTROL_TX(target
,pSendPacket
);
301 if (pRecvPacket
!= NULL
) {
302 HTC_FREE_CONTROL_RX(target
,pRecvPacket
);
305 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
, ("-HTCConnectService \n"));
310 static void AddToEndpointDistList(HTC_TARGET
*target
, HTC_ENDPOINT_CREDIT_DIST
*pEpDist
)
312 HTC_ENDPOINT_CREDIT_DIST
*pCurEntry
,*pLastEntry
;
314 if (NULL
== target
->EpCreditDistributionListHead
) {
315 target
->EpCreditDistributionListHead
= pEpDist
;
316 pEpDist
->pNext
= NULL
;
317 pEpDist
->pPrev
= NULL
;
321 /* queue to the end of the list, this does not have to be very
322 * fast since this list is built at startup time */
323 pCurEntry
= target
->EpCreditDistributionListHead
;
326 pLastEntry
= pCurEntry
;
327 pCurEntry
= pCurEntry
->pNext
;
330 pLastEntry
->pNext
= pEpDist
;
331 pEpDist
->pPrev
= pLastEntry
;
332 pEpDist
->pNext
= NULL
;
337 /* default credit init callback */
338 static void HTCDefaultCreditInit(void *Context
,
339 HTC_ENDPOINT_CREDIT_DIST
*pEPList
,
342 HTC_ENDPOINT_CREDIT_DIST
*pCurEpDist
;
344 int creditsPerEndpoint
;
346 pCurEpDist
= pEPList
;
347 /* first run through the list and figure out how many endpoints we are dealing with */
348 while (pCurEpDist
!= NULL
) {
349 pCurEpDist
= pCurEpDist
->pNext
;
353 /* even distribution */
354 creditsPerEndpoint
= TotalCredits
/totalEps
;
356 pCurEpDist
= pEPList
;
357 /* run through the list and set minimum and normal credits and
358 * provide the endpoint with some credits to start */
359 while (pCurEpDist
!= NULL
) {
361 if (creditsPerEndpoint
< pCurEpDist
->TxCreditsPerMaxMsg
) {
362 /* too many endpoints and not enough credits */
363 AR_DEBUG_ASSERT(false);
366 /* our minimum is set for at least 1 max message */
367 pCurEpDist
->TxCreditsMin
= pCurEpDist
->TxCreditsPerMaxMsg
;
368 /* this value is ignored by our credit alg, since we do
369 * not dynamically adjust credits, this is the policy of
370 * the "default" credit distribution, something simple and easy */
371 pCurEpDist
->TxCreditsNorm
= 0xFFFF;
372 /* give the endpoint minimum credits */
373 pCurEpDist
->TxCredits
= creditsPerEndpoint
;
374 pCurEpDist
->TxCreditsAssigned
= creditsPerEndpoint
;
375 pCurEpDist
= pCurEpDist
->pNext
;
380 /* default credit distribution callback, NOTE, this callback holds the TX lock */
381 void HTCDefaultCreditDist(void *Context
,
382 HTC_ENDPOINT_CREDIT_DIST
*pEPDistList
,
383 HTC_CREDIT_DIST_REASON Reason
)
385 HTC_ENDPOINT_CREDIT_DIST
*pCurEpDist
;
387 if (Reason
== HTC_CREDIT_DIST_SEND_COMPLETE
) {
388 pCurEpDist
= pEPDistList
;
389 /* simple distribution */
390 while (pCurEpDist
!= NULL
) {
391 if (pCurEpDist
->TxCreditsToDist
> 0) {
392 /* just give the endpoint back the credits */
393 pCurEpDist
->TxCredits
+= pCurEpDist
->TxCreditsToDist
;
394 pCurEpDist
->TxCreditsToDist
= 0;
396 pCurEpDist
= pCurEpDist
->pNext
;
400 /* note we do not need to handle the other reason codes as this is a very
401 * simple distribution scheme, no need to seek for more credits or handle inactivity */
404 void HTCSetCreditDistribution(HTC_HANDLE HTCHandle
,
405 void *pCreditDistContext
,
406 HTC_CREDIT_DIST_CALLBACK CreditDistFunc
,
407 HTC_CREDIT_INIT_CALLBACK CreditInitFunc
,
408 HTC_SERVICE_ID ServicePriorityOrder
[],
411 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
415 if (CreditInitFunc
!= NULL
) {
416 /* caller has supplied their own distribution functions */
417 target
->InitCredits
= CreditInitFunc
;
418 AR_DEBUG_ASSERT(CreditDistFunc
!= NULL
);
419 target
->DistributeCredits
= CreditDistFunc
;
420 target
->pCredDistContext
= pCreditDistContext
;
422 /* caller wants HTC to do distribution */
423 /* if caller wants service to handle distributions then
424 * it must set both of these to NULL! */
425 AR_DEBUG_ASSERT(CreditDistFunc
== NULL
);
426 target
->InitCredits
= HTCDefaultCreditInit
;
427 target
->DistributeCredits
= HTCDefaultCreditDist
;
428 target
->pCredDistContext
= target
;
431 /* always add HTC control endpoint first, we only expose the list after the
432 * first one, this is added for TX queue checking */
433 AddToEndpointDistList(target
, &target
->EndPoint
[ENDPOINT_0
].CreditDist
);
435 /* build the list of credit distribution structures in priority order
436 * supplied by the caller, these will follow endpoint 0 */
437 for (i
= 0; i
< ListLength
; i
++) {
438 /* match services with endpoints and add the endpoints to the distribution list
440 for (ep
= ENDPOINT_1
; ep
< ENDPOINT_MAX
; ep
++) {
441 if (target
->EndPoint
[ep
].ServiceID
== ServicePriorityOrder
[i
]) {
442 /* queue this one to the list */
443 AddToEndpointDistList(target
, &target
->EndPoint
[ep
].CreditDist
);
447 AR_DEBUG_ASSERT(ep
< ENDPOINT_MAX
);