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