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
23static HTC_INIT_INFO  HTCInitInfo = {NULL,NULL,NULL};
24static A_BOOL         HTCInitialized = FALSE;
25
26static A_STATUS HTCTargetInsertedHandler(void *hif_handle);
27static A_STATUS HTCTargetRemovedHandler(void *handle, A_STATUS status);
28static void HTCReportFailure(void *Context);
29
30/* Initializes the HTC layer */
31A_STATUS HTCInit(HTC_INIT_INFO *pInitInfo)
32{
33    HTC_CALLBACKS htcCallbacks;
34
35    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCInit: Enter\n"));
36    if (HTCInitialized) {
37        AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCInit: Exit\n"));
38        return A_OK;
39    }
40
41    A_MEMCPY(&HTCInitInfo,pInitInfo,sizeof(HTC_INIT_INFO));
42
43    A_MEMZERO(&htcCallbacks, sizeof(HTC_CALLBACKS));
44
45        /* setup HIF layer callbacks */
46    htcCallbacks.deviceInsertedHandler = HTCTargetInsertedHandler;
47    htcCallbacks.deviceRemovedHandler = HTCTargetRemovedHandler;
48        /* the device layer handles these */
49    htcCallbacks.rwCompletionHandler = DevRWCompletionHandler;
50    htcCallbacks.dsrHandler = DevDsrHandler;
51    HIFInit(&htcCallbacks);
52    HTCInitialized = TRUE;
53
54    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCInit: Exit\n"));
55    return A_OK;
56}
57
58void HTCFreeControlBuffer(HTC_TARGET *target, HTC_PACKET *pPacket, HTC_PACKET_QUEUE *pList)
59{
60    LOCK_HTC(target);
61    HTC_PACKET_ENQUEUE(pList,pPacket);
62    UNLOCK_HTC(target);
63}
64
65HTC_PACKET *HTCAllocControlBuffer(HTC_TARGET *target,  HTC_PACKET_QUEUE *pList)
66{
67    HTC_PACKET *pPacket;
68
69    LOCK_HTC(target);
70    pPacket = HTC_PACKET_DEQUEUE(pList);
71    UNLOCK_HTC(target);
72
73    return pPacket;
74}
75
76/* cleanup the HTC instance */
77static void HTCCleanup(HTC_TARGET *target)
78{
79    if (A_IS_MUTEX_VALID(&target->HTCLock)) {
80        A_MUTEX_DELETE(&target->HTCLock);
81    }
82
83    if (A_IS_MUTEX_VALID(&target->HTCRxLock)) {
84        A_MUTEX_DELETE(&target->HTCRxLock);
85    }
86
87    if (A_IS_MUTEX_VALID(&target->HTCTxLock)) {
88        A_MUTEX_DELETE(&target->HTCTxLock);
89    }
90        /* free our instance */
91    A_FREE(target);
92}
93
94/* registered target arrival callback from the HIF layer */
95static A_STATUS HTCTargetInsertedHandler(void *hif_handle)
96{
97    HTC_TARGET              *target = NULL;
98    A_STATUS                 status;
99    int                      i;
100
101    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcTargetInserted - Enter\n"));
102
103    do {
104
105            /* allocate target memory */
106        if ((target = (HTC_TARGET *)A_MALLOC(sizeof(HTC_TARGET))) == NULL) {
107            AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to allocate memory\n"));
108            status = A_ERROR;
109            break;
110        }
111
112        A_MEMZERO(target, sizeof(HTC_TARGET));
113        A_MUTEX_INIT(&target->HTCLock);
114        A_MUTEX_INIT(&target->HTCRxLock);
115        A_MUTEX_INIT(&target->HTCTxLock);
116        INIT_HTC_PACKET_QUEUE(&target->ControlBufferTXFreeList);
117        INIT_HTC_PACKET_QUEUE(&target->ControlBufferRXFreeList);
118
119            /* give device layer the hif device handle */
120        target->Device.HIFDevice = hif_handle;
121            /* give the device layer our context (for event processing)
122             * the device layer will register it's own context with HIF
123             * so we need to set this so we can fetch it in the target remove handler */
124        target->Device.HTCContext = target;
125            /* set device layer target failure callback */
126        target->Device.TargetFailureCallback = HTCReportFailure;
127            /* set device layer recv message pending callback */
128        target->Device.MessagePendingCallback = HTCRecvMessagePendingHandler;
129        target->EpWaitingForBuffers = ENDPOINT_MAX;
130
131            /* setup device layer */
132        status = DevSetup(&target->Device);
133
134        if (A_FAILED(status)) {
135            break;
136        }
137
138            /* carve up buffers/packets for control messages */
139        for (i = 0; i < NUM_CONTROL_RX_BUFFERS; i++) {
140            HTC_PACKET *pControlPacket;
141            pControlPacket = &target->HTCControlBuffers[i].HtcPacket;
142            SET_HTC_PACKET_INFO_RX_REFILL(pControlPacket,
143                                          target,
144                                          target->HTCControlBuffers[i].Buffer,
145                                          HTC_CONTROL_BUFFER_SIZE,
146                                          ENDPOINT_0);
147            HTC_FREE_CONTROL_RX(target,pControlPacket);
148        }
149
150        for (;i < NUM_CONTROL_BUFFERS;i++) {
151             HTC_PACKET *pControlPacket;
152             pControlPacket = &target->HTCControlBuffers[i].HtcPacket;
153             INIT_HTC_PACKET_INFO(pControlPacket,
154                                  target->HTCControlBuffers[i].Buffer,
155                                  HTC_CONTROL_BUFFER_SIZE);
156             HTC_FREE_CONTROL_TX(target,pControlPacket);
157        }
158
159    } while (FALSE);
160
161    if (A_SUCCESS(status)) {
162        AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" calling AddInstance callback \n"));
163            /* announce ourselves */
164        HTCInitInfo.AddInstance((HTC_HANDLE)target);
165    } else {
166        if (target != NULL) {
167            HTCCleanup(target);
168        }
169    }
170
171    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcTargetInserted - Exit\n"));
172
173    return status;
174}
175
176/* registered removal callback from the HIF layer */
177static A_STATUS HTCTargetRemovedHandler(void *handle, A_STATUS status)
178{
179    HTC_TARGET *target;
180
181    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCTargetRemovedHandler handle:0x%X \n",(A_UINT32)handle));
182
183    if (NULL == handle) {
184            /* this could be NULL in the event that target initialization failed */
185        return A_OK;
186    }
187
188    target = ((AR6K_DEVICE *)handle)->HTCContext;
189
190    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("   removing target:0x%X instance:0x%X ... \n",
191            (A_UINT32)target, (A_UINT32)target->pInstanceContext));
192
193    if (target->pInstanceContext != NULL) {
194            /* let upper layer know, it needs to call HTCStop() */
195        HTCInitInfo.DeleteInstance(target->pInstanceContext);
196    }
197
198    HIFShutDownDevice(target->Device.HIFDevice);
199
200    HTCCleanup(target);
201    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCTargetRemovedHandler \n"));
202    return A_OK;
203}
204
205/* get the low level HIF device for the caller , the caller may wish to do low level
206 * HIF requests */
207void *HTCGetHifDevice(HTC_HANDLE HTCHandle)
208{
209    HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
210    return target->Device.HIFDevice;
211}
212
213/* set the instance block for this HTC handle, so that on removal, the blob can be
214 * returned to the caller */
215void HTCSetInstance(HTC_HANDLE HTCHandle, void *Instance)
216{
217    HTC_TARGET  *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
218
219    target->pInstanceContext = Instance;
220}
221
222/* wait for the target to arrive (sends HTC Ready message)
223 * this operation is fully synchronous and the message is polled for */
224A_STATUS HTCWaitTarget(HTC_HANDLE HTCHandle)
225{
226    HTC_TARGET              *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
227    A_STATUS                 status;
228    HTC_PACKET              *pPacket = NULL;
229    HTC_READY_MSG           *pRdyMsg;
230    HTC_SERVICE_CONNECT_REQ  connect;
231    HTC_SERVICE_CONNECT_RESP resp;
232
233    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Enter (target:0x%X) \n", (A_UINT32)target));
234
235    do {
236
237#ifdef MBOXHW_UNIT_TEST
238
239        status = DoMboxHWTest(&target->Device);
240
241        if (status != A_OK) {
242            break;
243        }
244
245#endif
246
247            /* we should be getting 1 control message that the target is ready */
248        status = HTCWaitforControlMessage(target, &pPacket);
249
250        if (A_FAILED(status)) {
251            AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Target Not Available!!\n"));
252            break;
253        }
254
255            /* we controlled the buffer creation so it has to be properly aligned */
256        pRdyMsg = (HTC_READY_MSG *)pPacket->pBuffer;
257
258        if ((pRdyMsg->MessageID != HTC_MSG_READY_ID) ||
259            (pPacket->ActualLength < sizeof(HTC_READY_MSG))) {
260                /* this message is not valid */
261            AR_DEBUG_ASSERT(FALSE);
262            status = A_EPROTO;
263            break;
264        }
265
266        if (pRdyMsg->CreditCount == 0 || pRdyMsg->CreditSize == 0) {
267              /* this message is not valid */
268            AR_DEBUG_ASSERT(FALSE);
269            status = A_EPROTO;
270            break;
271        }
272
273        target->TargetCredits = pRdyMsg->CreditCount;
274        target->TargetCreditSize = pRdyMsg->CreditSize;
275
276        AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" Target Ready: credits: %d credit size: %d\n",
277                target->TargetCredits, target->TargetCreditSize));
278
279            /* setup our pseudo HTC control endpoint connection */
280        A_MEMZERO(&connect,sizeof(connect));
281        A_MEMZERO(&resp,sizeof(resp));
282        connect.EpCallbacks.pContext = target;
283        connect.EpCallbacks.EpTxComplete = HTCControlTxComplete;
284        connect.EpCallbacks.EpRecv = HTCControlRecv;
285        connect.EpCallbacks.EpRecvRefill = NULL;  /* not needed */
286        connect.EpCallbacks.EpSendFull = NULL;    /* not needed */
287        connect.EpCallbacks.EpSendAvail = NULL;   /* not needed */
288        connect.MaxSendQueueDepth = NUM_CONTROL_BUFFERS;
289        connect.ServiceID = HTC_CTRL_RSVD_SVC;
290
291            /* connect fake service */
292        status = HTCConnectService((HTC_HANDLE)target,
293                                   &connect,
294                                   &resp);
295
296        if (!A_FAILED(status)) {
297            break;
298        }
299
300    } while (FALSE);
301
302    if (pPacket != NULL) {
303        HTC_FREE_CONTROL_RX(target,pPacket);
304    }
305
306    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Exit\n"));
307
308    return status;
309}
310
311
312
313/* Start HTC, enable interrupts and let the target know host has finished setup */
314A_STATUS HTCStart(HTC_HANDLE HTCHandle)
315{
316    HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
317    HTC_PACKET *pPacket;
318    A_STATUS   status;
319
320    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Enter\n"));
321
322        /* now that we are starting, push control receive buffers into the
323         * HTC control endpoint */
324
325    while (1) {
326        pPacket = HTC_ALLOC_CONTROL_RX(target);
327        if (NULL == pPacket) {
328            break;
329        }
330        HTCAddReceivePkt((HTC_HANDLE)target,pPacket);
331    }
332
333    do {
334
335        AR_DEBUG_ASSERT(target->InitCredits != NULL);
336        AR_DEBUG_ASSERT(target->EpCreditDistributionListHead != NULL);
337        AR_DEBUG_ASSERT(target->EpCreditDistributionListHead->pNext != NULL);
338
339            /* call init credits callback to do the distribution ,
340             * NOTE: the first entry in the distribution list is ENDPOINT_0, so
341             * we pass the start of the list after this one. */
342        target->InitCredits(target->pCredDistContext,
343                            target->EpCreditDistributionListHead->pNext,
344                            target->TargetCredits);
345
346        if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_TRC)) {
347            DumpCreditDistStates(target);
348        }
349
350            /* the caller is done connecting to services, so we can indicate to the
351            * target that the setup phase is complete */
352        status = HTCSendSetupComplete(target);
353
354        if (A_FAILED(status)) {
355            break;
356        }
357
358            /* unmask interrupts */
359        status = DevUnmaskInterrupts(&target->Device);
360
361        if (A_FAILED(status)) {
362            HTCStop(target);
363        }
364
365    } while (FALSE);
366
367    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Exit\n"));
368    return status;
369}
370
371
372/* stop HTC communications, i.e. stop interrupt reception, and flush all queued buffers */
373void HTCStop(HTC_HANDLE HTCHandle)
374{
375    HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
376    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCStop \n"));
377
378        /* mark that we are shutting down .. */
379    target->HTCStateFlags |= HTC_STATE_STOPPING;
380
381        /* Masking interrupts is a synchronous operation, when this function returns
382         * all pending HIF I/O has completed, we can safely flush the queues */
383    DevMaskInterrupts(&target->Device);
384
385        /* flush all send packets */
386    HTCFlushSendPkts(target);
387        /* flush all recv buffers */
388    HTCFlushRecvBuffers(target);
389
390    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCStop \n"));
391}
392
393/* undo what was done in HTCInit() */
394void HTCShutDown(void)
395{
396    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCShutDown: \n"));
397    HTCInitialized = FALSE;
398        /* undo HTCInit */
399    HIFShutDownDevice(NULL);
400    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCShutDown: \n"));
401}
402
403void HTCDumpCreditStates(HTC_HANDLE HTCHandle)
404{
405    HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
406
407    LOCK_HTC_TX(target);
408
409    DumpCreditDistStates(target);
410
411    UNLOCK_HTC_TX(target);
412}
413
414/* report a target failure from the device, this is a callback from the device layer
415 * which uses a mechanism to report errors from the target (i.e. special interrupts) */
416static void HTCReportFailure(void *Context)
417{
418    HTC_TARGET *target = (HTC_TARGET *)Context;
419
420    target->TargetFailure = TRUE;
421
422    if ((target->pInstanceContext != NULL) && (HTCInitInfo.TargetFailure != NULL)) {
423            /* let upper layer know, it needs to call HTCStop() */
424        HTCInitInfo.TargetFailure(target->pInstanceContext, A_ERROR);
425    }
426}
427
428void DebugDumpBytes(A_UCHAR *buffer, A_UINT16 length, char *pDescription)
429{
430    A_CHAR stream[60];
431    A_UINT32 i;
432    A_UINT16 offset, count;
433
434    AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("<---------Dumping %d Bytes : %s ------>\n", length, pDescription));
435
436    count = 0;
437    offset = 0;
438    for(i = 0; i < length; i++) {
439        sprintf(stream + offset, "%2.2X ", buffer[i]);
440        count ++;
441        offset += 3;
442
443        if(count == 16) {
444            count = 0;
445            offset = 0;
446            AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("[H]: %s\n", stream));
447            A_MEMZERO(stream, 60);
448        }
449    }
450
451    if(offset != 0) {
452        AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("[H]: %s\n", stream));
453    }
454
455    AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("<------------------------------------------------->\n"));
456}
457
458A_BOOL HTCGetEndpointStatistics(HTC_HANDLE               HTCHandle,
459                                HTC_ENDPOINT_ID          Endpoint,
460                                HTC_ENDPOINT_STAT_ACTION Action,
461                                HTC_ENDPOINT_STATS       *pStats)
462{
463
464#ifdef HTC_EP_STAT_PROFILING
465    HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
466    A_BOOL     clearStats = FALSE;
467    A_BOOL     sample = FALSE;
468
469    switch (Action) {
470        case HTC_EP_STAT_SAMPLE :
471            sample = TRUE;
472            break;
473        case HTC_EP_STAT_SAMPLE_AND_CLEAR :
474            sample = TRUE;
475            clearStats = TRUE;
476            break;
477        case HTC_EP_STAT_CLEAR :
478            clearStats = TRUE;
479            break;
480        default:
481            break;
482    }
483
484    A_ASSERT(Endpoint < ENDPOINT_MAX);
485
486        /* lock out TX and RX while we sample and/or clear */
487    LOCK_HTC_TX(target);
488    LOCK_HTC_RX(target);
489
490    if (sample) {
491        A_ASSERT(pStats != NULL);
492            /* return the stats to the caller */
493        A_MEMCPY(pStats, &target->EndPoint[Endpoint].EndPointStats, sizeof(HTC_ENDPOINT_STATS));
494    }
495
496    if (clearStats) {
497            /* reset stats */
498        A_MEMZERO(&target->EndPoint[Endpoint].EndPointStats, sizeof(HTC_ENDPOINT_STATS));
499    }
500
501    UNLOCK_HTC_RX(target);
502    UNLOCK_HTC_TX(target);
503
504    return TRUE;
505#else
506    return FALSE;
507#endif
508}
509