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"
22 void HTCControlTxComplete(void *Context
, HTC_PACKET
*pPacket
)
25 * we do not send control TX frames during normal runtime, only during setup */
26 AR_DEBUG_ASSERT(FALSE
);
29 /* callback when a control message arrives on this endpoint */
30 void HTCControlRecv(void *Context
, HTC_PACKET
*pPacket
)
32 AR_DEBUG_ASSERT(pPacket
->Endpoint
== ENDPOINT_0
);
34 /* the only control messages we are expecting are NULL messages (credit resports), which should
36 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
37 ("HTCControlRecv, got message with length:%d \n",
38 pPacket
->ActualLength
+ HTC_HDR_LENGTH
));
40 /* dump header and message */
41 DebugDumpBytes(pPacket
->pBuffer
- HTC_HDR_LENGTH
,
42 pPacket
->ActualLength
+ HTC_HDR_LENGTH
,
43 "Unexpected ENDPOINT 0 Message");
45 HTC_RECYCLE_RX_PKT((HTC_TARGET
*)Context
,pPacket
);
48 A_STATUS
HTCSendSetupComplete(HTC_TARGET
*target
)
50 HTC_PACKET
*pSendPacket
= NULL
;
52 HTC_SETUP_COMPLETE_MSG
*pSetupComplete
;
55 /* allocate a packet to send to the target */
56 pSendPacket
= HTC_ALLOC_CONTROL_TX(target
);
58 if (NULL
== pSendPacket
) {
63 /* assemble setup complete message */
64 pSetupComplete
= (HTC_SETUP_COMPLETE_MSG
*)pSendPacket
->pBuffer
;
65 A_MEMZERO(pSetupComplete
,sizeof(HTC_SETUP_COMPLETE_MSG
));
66 pSetupComplete
->MessageID
= HTC_MSG_SETUP_COMPLETE_ID
;
68 SET_HTC_PACKET_INFO_TX(pSendPacket
,
70 (A_UINT8
*)pSetupComplete
,
71 sizeof(HTC_SETUP_COMPLETE_MSG
),
73 HTC_SERVICE_TX_PACKET_TAG
);
75 /* we want synchronous operation */
76 pSendPacket
->Completion
= NULL
;
77 /* send the message */
78 status
= HTCIssueSend(target
,pSendPacket
,0);
82 if (pSendPacket
!= NULL
) {
83 HTC_FREE_CONTROL_TX(target
,pSendPacket
);
90 A_STATUS
HTCConnectService(HTC_HANDLE HTCHandle
,
91 HTC_SERVICE_CONNECT_REQ
*pConnectReq
,
92 HTC_SERVICE_CONNECT_RESP
*pConnectResp
)
94 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
95 A_STATUS status
= A_OK
;
96 HTC_PACKET
*pRecvPacket
= NULL
;
97 HTC_PACKET
*pSendPacket
= NULL
;
98 HTC_CONNECT_SERVICE_RESPONSE_MSG
*pResponseMsg
;
99 HTC_CONNECT_SERVICE_MSG
*pConnectMsg
;
100 HTC_ENDPOINT_ID assignedEndpoint
= ENDPOINT_MAX
;
101 HTC_ENDPOINT
*pEndpoint
;
104 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
, ("+HTCConnectService, target:0x%X SvcID:0x%X \n",
105 (A_UINT32
)target
, pConnectReq
->ServiceID
));
109 AR_DEBUG_ASSERT(pConnectReq
->ServiceID
!= 0);
111 if (HTC_CTRL_RSVD_SVC
== pConnectReq
->ServiceID
) {
112 /* special case for pseudo control service */
113 assignedEndpoint
= ENDPOINT_0
;
114 maxMsgSize
= HTC_MAX_CONTROL_MESSAGE_LENGTH
;
116 /* allocate a packet to send to the target */
117 pSendPacket
= HTC_ALLOC_CONTROL_TX(target
);
119 if (NULL
== pSendPacket
) {
120 AR_DEBUG_ASSERT(FALSE
);
121 status
= A_NO_MEMORY
;
124 /* assemble connect service message */
125 pConnectMsg
= (HTC_CONNECT_SERVICE_MSG
*)pSendPacket
->pBuffer
;
126 AR_DEBUG_ASSERT(pConnectMsg
!= NULL
);
127 A_MEMZERO(pConnectMsg
,sizeof(HTC_CONNECT_SERVICE_MSG
));
128 pConnectMsg
->MessageID
= HTC_MSG_CONNECT_SERVICE_ID
;
129 pConnectMsg
->ServiceID
= pConnectReq
->ServiceID
;
130 pConnectMsg
->ConnectionFlags
= pConnectReq
->ConnectionFlags
;
131 /* check caller if it wants to transfer meta data */
132 if ((pConnectReq
->pMetaData
!= NULL
) &&
133 (pConnectReq
->MetaDataLength
<= HTC_SERVICE_META_DATA_MAX_LENGTH
)) {
134 /* copy meta data into message buffer (after header ) */
135 A_MEMCPY((A_UINT8
*)pConnectMsg
+ sizeof(HTC_CONNECT_SERVICE_MSG
),
136 pConnectReq
->pMetaData
,
137 pConnectReq
->MetaDataLength
);
138 pConnectMsg
->ServiceMetaLength
= pConnectReq
->MetaDataLength
;
141 SET_HTC_PACKET_INFO_TX(pSendPacket
,
143 (A_UINT8
*)pConnectMsg
,
144 sizeof(HTC_CONNECT_SERVICE_MSG
) + pConnectMsg
->ServiceMetaLength
,
146 HTC_SERVICE_TX_PACKET_TAG
);
148 /* we want synchronous operation */
149 pSendPacket
->Completion
= NULL
;
151 status
= HTCIssueSend(target
,pSendPacket
,0);
153 if (A_FAILED(status
)) {
157 /* wait for response */
158 status
= HTCWaitforControlMessage(target
, &pRecvPacket
);
160 if (A_FAILED(status
)) {
163 /* we controlled the buffer creation so it has to be properly aligned */
164 pResponseMsg
= (HTC_CONNECT_SERVICE_RESPONSE_MSG
*)pRecvPacket
->pBuffer
;
166 if ((pResponseMsg
->MessageID
!= HTC_MSG_CONNECT_SERVICE_RESPONSE_ID
) ||
167 (pRecvPacket
->ActualLength
< sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG
))) {
168 /* this message is not valid */
169 AR_DEBUG_ASSERT(FALSE
);
174 pConnectResp
->ConnectRespCode
= pResponseMsg
->Status
;
175 /* check response status */
176 if (pResponseMsg
->Status
!= HTC_SERVICE_SUCCESS
) {
177 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
178 (" Target failed service 0x%X connect request (status:%d)\n",
179 pResponseMsg
->ServiceID
, pResponseMsg
->Status
));
184 assignedEndpoint
= pResponseMsg
->EndpointID
;
185 maxMsgSize
= pResponseMsg
->MaxMsgSize
;
187 if ((pConnectResp
->pMetaData
!= NULL
) &&
188 (pResponseMsg
->ServiceMetaLength
> 0) &&
189 (pResponseMsg
->ServiceMetaLength
<= HTC_SERVICE_META_DATA_MAX_LENGTH
)) {
190 /* caller supplied a buffer and the target responded with data */
191 int copyLength
= min((int)pConnectResp
->BufferLength
, (int)pResponseMsg
->ServiceMetaLength
);
192 /* copy the meta data */
193 A_MEMCPY(pConnectResp
->pMetaData
,
194 ((A_UINT8
*)pResponseMsg
) + sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG
),
196 pConnectResp
->ActualLength
= copyLength
;
201 /* the rest of these are parameter checks so set the error status */
204 if (assignedEndpoint
>= ENDPOINT_MAX
) {
205 AR_DEBUG_ASSERT(FALSE
);
209 if (0 == maxMsgSize
) {
210 AR_DEBUG_ASSERT(FALSE
);
214 pEndpoint
= &target
->EndPoint
[assignedEndpoint
];
216 if (pEndpoint
->ServiceID
!= 0) {
217 /* endpoint already in use! */
218 AR_DEBUG_ASSERT(FALSE
);
222 /* return assigned endpoint to caller */
223 pConnectResp
->Endpoint
= assignedEndpoint
;
224 pConnectResp
->MaxMsgLength
= maxMsgSize
;
226 /* setup the endpoint */
227 pEndpoint
->ServiceID
= pConnectReq
->ServiceID
; /* this marks the endpoint in use */
228 pEndpoint
->MaxTxQueueDepth
= pConnectReq
->MaxSendQueueDepth
;
229 pEndpoint
->MaxMsgLength
= maxMsgSize
;
230 /* copy all the callbacks */
231 pEndpoint
->EpCallBacks
= pConnectReq
->EpCallbacks
;
232 INIT_HTC_PACKET_QUEUE(&pEndpoint
->RxBuffers
);
233 INIT_HTC_PACKET_QUEUE(&pEndpoint
->TxQueue
);
234 /* set the credit distribution info for this endpoint, this information is
235 * passed back to the credit distribution callback function */
236 pEndpoint
->CreditDist
.ServiceID
= pConnectReq
->ServiceID
;
237 pEndpoint
->CreditDist
.pHTCReserved
= pEndpoint
;
238 pEndpoint
->CreditDist
.Endpoint
= assignedEndpoint
;
239 pEndpoint
->CreditDist
.TxCreditSize
= target
->TargetCreditSize
;
240 pEndpoint
->CreditDist
.TxCreditsPerMaxMsg
= maxMsgSize
/ target
->TargetCreditSize
;
242 if (0 == pEndpoint
->CreditDist
.TxCreditsPerMaxMsg
) {
243 pEndpoint
->CreditDist
.TxCreditsPerMaxMsg
= 1;
250 if (pSendPacket
!= NULL
) {
251 HTC_FREE_CONTROL_TX(target
,pSendPacket
);
254 if (pRecvPacket
!= NULL
) {
255 HTC_FREE_CONTROL_RX(target
,pRecvPacket
);
258 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
, ("-HTCConnectService \n"));
263 static void AddToEndpointDistList(HTC_TARGET
*target
, HTC_ENDPOINT_CREDIT_DIST
*pEpDist
)
265 HTC_ENDPOINT_CREDIT_DIST
*pCurEntry
,*pLastEntry
;
267 if (NULL
== target
->EpCreditDistributionListHead
) {
268 target
->EpCreditDistributionListHead
= pEpDist
;
269 pEpDist
->pNext
= NULL
;
270 pEpDist
->pPrev
= NULL
;
274 /* queue to the end of the list, this does not have to be very
275 * fast since this list is built at startup time */
276 pCurEntry
= target
->EpCreditDistributionListHead
;
279 pLastEntry
= pCurEntry
;
280 pCurEntry
= pCurEntry
->pNext
;
283 pLastEntry
->pNext
= pEpDist
;
284 pEpDist
->pPrev
= pLastEntry
;
285 pEpDist
->pNext
= NULL
;
290 /* default credit init callback */
291 static void HTCDefaultCreditInit(void *Context
,
292 HTC_ENDPOINT_CREDIT_DIST
*pEPList
,
295 HTC_ENDPOINT_CREDIT_DIST
*pCurEpDist
;
297 int creditsPerEndpoint
;
299 pCurEpDist
= pEPList
;
300 /* first run through the list and figure out how many endpoints we are dealing with */
301 while (pCurEpDist
!= NULL
) {
302 pCurEpDist
= pCurEpDist
->pNext
;
306 /* even distribution */
307 creditsPerEndpoint
= TotalCredits
/totalEps
;
309 pCurEpDist
= pEPList
;
310 /* run through the list and set minimum and normal credits and
311 * provide the endpoint with some credits to start */
312 while (pCurEpDist
!= NULL
) {
314 if (creditsPerEndpoint
< pCurEpDist
->TxCreditsPerMaxMsg
) {
315 /* too many endpoints and not enough credits */
316 AR_DEBUG_ASSERT(FALSE
);
319 /* our minimum is set for at least 1 max message */
320 pCurEpDist
->TxCreditsMin
= pCurEpDist
->TxCreditsPerMaxMsg
;
321 /* this value is ignored by our credit alg, since we do
322 * not dynamically adjust credits, this is the policy of
323 * the "default" credit distribution, something simple and easy */
324 pCurEpDist
->TxCreditsNorm
= 0xFFFF;
325 /* give the endpoint minimum credits */
326 pCurEpDist
->TxCredits
= creditsPerEndpoint
;
327 pCurEpDist
->TxCreditsAssigned
= creditsPerEndpoint
;
328 pCurEpDist
= pCurEpDist
->pNext
;
333 /* default credit distribution callback, NOTE, this callback holds the TX lock */
334 void HTCDefaultCreditDist(void *Context
,
335 HTC_ENDPOINT_CREDIT_DIST
*pEPDistList
,
336 HTC_CREDIT_DIST_REASON Reason
)
338 HTC_ENDPOINT_CREDIT_DIST
*pCurEpDist
;
340 if (Reason
== HTC_CREDIT_DIST_SEND_COMPLETE
) {
341 pCurEpDist
= pEPDistList
;
342 /* simple distribution */
343 while (pCurEpDist
!= NULL
) {
344 if (pCurEpDist
->TxCreditsToDist
> 0) {
345 /* just give the endpoint back the credits */
346 pCurEpDist
->TxCredits
+= pCurEpDist
->TxCreditsToDist
;
347 pCurEpDist
->TxCreditsToDist
= 0;
349 pCurEpDist
= pCurEpDist
->pNext
;
353 /* note we do not need to handle the other reason codes as this is a very
354 * simple distribution scheme, no need to seek for more credits or handle inactivity */
357 void HTCSetCreditDistribution(HTC_HANDLE HTCHandle
,
358 void *pCreditDistContext
,
359 HTC_CREDIT_DIST_CALLBACK CreditDistFunc
,
360 HTC_CREDIT_INIT_CALLBACK CreditInitFunc
,
361 HTC_SERVICE_ID ServicePriorityOrder
[],
364 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
368 if (CreditInitFunc
!= NULL
) {
369 /* caller has supplied their own distribution functions */
370 target
->InitCredits
= CreditInitFunc
;
371 AR_DEBUG_ASSERT(CreditDistFunc
!= NULL
);
372 target
->DistributeCredits
= CreditDistFunc
;
373 target
->pCredDistContext
= pCreditDistContext
;
375 /* caller wants HTC to do distribution */
376 /* if caller wants service to handle distributions then
377 * it must set both of these to NULL! */
378 AR_DEBUG_ASSERT(CreditDistFunc
== NULL
);
379 target
->InitCredits
= HTCDefaultCreditInit
;
380 target
->DistributeCredits
= HTCDefaultCreditDist
;
381 target
->pCredDistContext
= target
;
384 /* always add HTC control endpoint first, we only expose the list after the
385 * first one, this is added for TX queue checking */
386 AddToEndpointDistList(target
, &target
->EndPoint
[ENDPOINT_0
].CreditDist
);
388 /* build the list of credit distribution structures in priority order
389 * supplied by the caller, these will follow endpoint 0 */
390 for (i
= 0; i
< ListLength
; i
++) {
391 /* match services with endpoints and add the endpoints to the distribution list
393 for (ep
= ENDPOINT_1
; ep
< ENDPOINT_MAX
; ep
++) {
394 if (target
->EndPoint
[ep
].ServiceID
== ServicePriorityOrder
[i
]) {
395 /* queue this one to the list */
396 AddToEndpointDistList(target
, &target
->EndPoint
[ep
].CreditDist
);
400 AR_DEBUG_ASSERT(ep
< ENDPOINT_MAX
);