[x86] add rootwait option to the kernel command line (#6209)
[openwrt.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 }