e5d50d16ddc7d80ab5aab3605f246c0b22f0a35c
[openwrt/staging/florian.git] / target / linux / s3c24xx / files-2.6.31 / drivers / ar6000 / htc / htc_services.c
1 /*
2 *
3 * Copyright (c) 2007 Atheros Communications Inc.
4 * All rights reserved.
5 *
6 *
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;
10 *
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.
15 *
16 *
17 *
18 */
19
20 #include "htc_internal.h"
21
22 void HTCControlTxComplete(void *Context, HTC_PACKET *pPacket)
23 {
24 /* not implemented
25 * we do not send control TX frames during normal runtime, only during setup */
26 AR_DEBUG_ASSERT(FALSE);
27 }
28
29 /* callback when a control message arrives on this endpoint */
30 void HTCControlRecv(void *Context, HTC_PACKET *pPacket)
31 {
32 AR_DEBUG_ASSERT(pPacket->Endpoint == ENDPOINT_0);
33
34 /* the only control messages we are expecting are NULL messages (credit resports), which should
35 * never get here */
36 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
37 ("HTCControlRecv, got message with length:%d \n",
38 pPacket->ActualLength + HTC_HDR_LENGTH));
39
40 /* dump header and message */
41 DebugDumpBytes(pPacket->pBuffer - HTC_HDR_LENGTH,
42 pPacket->ActualLength + HTC_HDR_LENGTH,
43 "Unexpected ENDPOINT 0 Message");
44
45 HTC_RECYCLE_RX_PKT((HTC_TARGET*)Context,pPacket);
46 }
47
48 A_STATUS HTCSendSetupComplete(HTC_TARGET *target)
49 {
50 HTC_PACKET *pSendPacket = NULL;
51 A_STATUS status;
52 HTC_SETUP_COMPLETE_MSG *pSetupComplete;
53
54 do {
55 /* allocate a packet to send to the target */
56 pSendPacket = HTC_ALLOC_CONTROL_TX(target);
57
58 if (NULL == pSendPacket) {
59 status = A_NO_MEMORY;
60 break;
61 }
62
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;
67
68 SET_HTC_PACKET_INFO_TX(pSendPacket,
69 NULL,
70 (A_UINT8 *)pSetupComplete,
71 sizeof(HTC_SETUP_COMPLETE_MSG),
72 ENDPOINT_0,
73 HTC_SERVICE_TX_PACKET_TAG);
74
75 /* we want synchronous operation */
76 pSendPacket->Completion = NULL;
77 /* send the message */
78 status = HTCIssueSend(target,pSendPacket,0);
79
80 } while (FALSE);
81
82 if (pSendPacket != NULL) {
83 HTC_FREE_CONTROL_TX(target,pSendPacket);
84 }
85
86 return status;
87 }
88
89
90 A_STATUS HTCConnectService(HTC_HANDLE HTCHandle,
91 HTC_SERVICE_CONNECT_REQ *pConnectReq,
92 HTC_SERVICE_CONNECT_RESP *pConnectResp)
93 {
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;
102 int maxMsgSize = 0;
103
104 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCConnectService, target:0x%X SvcID:0x%X \n",
105 (A_UINT32)target, pConnectReq->ServiceID));
106
107 do {
108
109 AR_DEBUG_ASSERT(pConnectReq->ServiceID != 0);
110
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;
115 } else {
116 /* allocate a packet to send to the target */
117 pSendPacket = HTC_ALLOC_CONTROL_TX(target);
118
119 if (NULL == pSendPacket) {
120 AR_DEBUG_ASSERT(FALSE);
121 status = A_NO_MEMORY;
122 break;
123 }
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;
139 }
140
141 SET_HTC_PACKET_INFO_TX(pSendPacket,
142 NULL,
143 (A_UINT8 *)pConnectMsg,
144 sizeof(HTC_CONNECT_SERVICE_MSG) + pConnectMsg->ServiceMetaLength,
145 ENDPOINT_0,
146 HTC_SERVICE_TX_PACKET_TAG);
147
148 /* we want synchronous operation */
149 pSendPacket->Completion = NULL;
150
151 status = HTCIssueSend(target,pSendPacket,0);
152
153 if (A_FAILED(status)) {
154 break;
155 }
156
157 /* wait for response */
158 status = HTCWaitforControlMessage(target, &pRecvPacket);
159
160 if (A_FAILED(status)) {
161 break;
162 }
163 /* we controlled the buffer creation so it has to be properly aligned */
164 pResponseMsg = (HTC_CONNECT_SERVICE_RESPONSE_MSG *)pRecvPacket->pBuffer;
165
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);
170 status = A_EPROTO;
171 break;
172 }
173
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));
180 status = A_EPROTO;
181 break;
182 }
183
184 assignedEndpoint = pResponseMsg->EndpointID;
185 maxMsgSize = pResponseMsg->MaxMsgSize;
186
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),
195 copyLength);
196 pConnectResp->ActualLength = copyLength;
197 }
198
199 }
200
201 /* the rest of these are parameter checks so set the error status */
202 status = A_EPROTO;
203
204 if (assignedEndpoint >= ENDPOINT_MAX) {
205 AR_DEBUG_ASSERT(FALSE);
206 break;
207 }
208
209 if (0 == maxMsgSize) {
210 AR_DEBUG_ASSERT(FALSE);
211 break;
212 }
213
214 pEndpoint = &target->EndPoint[assignedEndpoint];
215
216 if (pEndpoint->ServiceID != 0) {
217 /* endpoint already in use! */
218 AR_DEBUG_ASSERT(FALSE);
219 break;
220 }
221
222 /* return assigned endpoint to caller */
223 pConnectResp->Endpoint = assignedEndpoint;
224 pConnectResp->MaxMsgLength = maxMsgSize;
225
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;
241
242 if (0 == pEndpoint->CreditDist.TxCreditsPerMaxMsg) {
243 pEndpoint->CreditDist.TxCreditsPerMaxMsg = 1;
244 }
245
246 status = A_OK;
247
248 } while (FALSE);
249
250 if (pSendPacket != NULL) {
251 HTC_FREE_CONTROL_TX(target,pSendPacket);
252 }
253
254 if (pRecvPacket != NULL) {
255 HTC_FREE_CONTROL_RX(target,pRecvPacket);
256 }
257
258 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCConnectService \n"));
259
260 return status;
261 }
262
263 static void AddToEndpointDistList(HTC_TARGET *target, HTC_ENDPOINT_CREDIT_DIST *pEpDist)
264 {
265 HTC_ENDPOINT_CREDIT_DIST *pCurEntry,*pLastEntry;
266
267 if (NULL == target->EpCreditDistributionListHead) {
268 target->EpCreditDistributionListHead = pEpDist;
269 pEpDist->pNext = NULL;
270 pEpDist->pPrev = NULL;
271 return;
272 }
273
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;
277
278 while (pCurEntry) {
279 pLastEntry = pCurEntry;
280 pCurEntry = pCurEntry->pNext;
281 }
282
283 pLastEntry->pNext = pEpDist;
284 pEpDist->pPrev = pLastEntry;
285 pEpDist->pNext = NULL;
286 }
287
288
289
290 /* default credit init callback */
291 static void HTCDefaultCreditInit(void *Context,
292 HTC_ENDPOINT_CREDIT_DIST *pEPList,
293 int TotalCredits)
294 {
295 HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
296 int totalEps = 0;
297 int creditsPerEndpoint;
298
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;
303 totalEps++;
304 }
305
306 /* even distribution */
307 creditsPerEndpoint = TotalCredits/totalEps;
308
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) {
313
314 if (creditsPerEndpoint < pCurEpDist->TxCreditsPerMaxMsg) {
315 /* too many endpoints and not enough credits */
316 AR_DEBUG_ASSERT(FALSE);
317 break;
318 }
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;
329 }
330
331 }
332
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)
337 {
338 HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
339
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;
348 }
349 pCurEpDist = pCurEpDist->pNext;
350 }
351 }
352
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 */
355 }
356
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[],
362 int ListLength)
363 {
364 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
365 int i;
366 int ep;
367
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;
374 } else {
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;
382 }
383
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);
387
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
392 * in FIFO order */
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);
397 break;
398 }
399 }
400 AR_DEBUG_ASSERT(ep < ENDPOINT_MAX);
401 }
402
403 }