PageRenderTime 29ms CodeModel.GetById 6ms app.highlight 19ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/staging/ath6kl/htc2/htc.c

https://bitbucket.org/wisechild/galaxy-nexus
C | 575 lines | 378 code | 113 blank | 84 comment | 62 complexity | 75744dbbba330360633e74d4bc6b98ff MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  1//------------------------------------------------------------------------------
  2// <copyright file="htc.c" company="Atheros">
  3//    Copyright (c) 2007-2010 Atheros Corporation.  All rights reserved.
  4// 
  5//
  6// Permission to use, copy, modify, and/or distribute this software for any
  7// purpose with or without fee is hereby granted, provided that the above
  8// copyright notice and this permission notice appear in all copies.
  9//
 10// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 11// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 12// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 13// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 14// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 15// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 16// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 17//
 18//
 19//------------------------------------------------------------------------------
 20//==============================================================================
 21// Author(s): ="Atheros"
 22//==============================================================================
 23#include "htc_internal.h"
 24
 25#ifdef ATH_DEBUG_MODULE
 26static struct ath_debug_mask_description g_HTCDebugDescription[] = {
 27    { ATH_DEBUG_SEND , "Send"},
 28    { ATH_DEBUG_RECV , "Recv"},
 29    { ATH_DEBUG_SYNC , "Sync"},
 30    { ATH_DEBUG_DUMP , "Dump Data (RX or TX)"},
 31    { ATH_DEBUG_IRQ  , "Interrupt Processing"}
 32};
 33
 34ATH_DEBUG_INSTANTIATE_MODULE_VAR(htc,
 35                                 "htc",
 36                                 "Host Target Communications",
 37                                 ATH_DEBUG_MASK_DEFAULTS,
 38                                 ATH_DEBUG_DESCRIPTION_COUNT(g_HTCDebugDescription),
 39                                 g_HTCDebugDescription);
 40                                 
 41#endif
 42
 43static void HTCReportFailure(void *Context);
 44static void ResetEndpointStates(struct htc_target *target);
 45
 46void HTCFreeControlBuffer(struct htc_target *target, struct htc_packet *pPacket, struct htc_packet_queue *pList)
 47{
 48    LOCK_HTC(target);
 49    HTC_PACKET_ENQUEUE(pList,pPacket);
 50    UNLOCK_HTC(target);
 51}
 52
 53struct htc_packet *HTCAllocControlBuffer(struct htc_target *target,  struct htc_packet_queue *pList)
 54{
 55    struct htc_packet *pPacket;
 56
 57    LOCK_HTC(target);
 58    pPacket = HTC_PACKET_DEQUEUE(pList);
 59    UNLOCK_HTC(target);
 60
 61    return pPacket;
 62}
 63
 64/* cleanup the HTC instance */
 65static void HTCCleanup(struct htc_target *target)
 66{
 67    s32 i;
 68
 69    DevCleanup(&target->Device);
 70    
 71    for (i = 0;i < NUM_CONTROL_BUFFERS;i++) {
 72        if (target->HTCControlBuffers[i].Buffer) {
 73            kfree(target->HTCControlBuffers[i].Buffer);
 74        }
 75    }
 76    
 77    if (A_IS_MUTEX_VALID(&target->HTCLock)) {
 78        A_MUTEX_DELETE(&target->HTCLock);
 79    }
 80
 81    if (A_IS_MUTEX_VALID(&target->HTCRxLock)) {
 82        A_MUTEX_DELETE(&target->HTCRxLock);
 83    }
 84
 85    if (A_IS_MUTEX_VALID(&target->HTCTxLock)) {
 86        A_MUTEX_DELETE(&target->HTCTxLock);
 87    }
 88        /* free our instance */
 89    kfree(target);
 90}
 91
 92/* registered target arrival callback from the HIF layer */
 93HTC_HANDLE HTCCreate(void *hif_handle, struct htc_init_info *pInfo)
 94{
 95    struct htc_target              *target = NULL;
 96    int                 status = 0;
 97    int                      i;
 98    u32 ctrl_bufsz;
 99    u32 blocksizes[HTC_MAILBOX_NUM_MAX];
100
101    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCCreate - Enter\n"));
102
103    A_REGISTER_MODULE_DEBUG_INFO(htc);
104    
105    do {
106
107            /* allocate target memory */
108        if ((target = (struct htc_target *)A_MALLOC(sizeof(struct htc_target))) == NULL) {
109            AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to allocate memory\n"));
110            status = A_ERROR;
111            break;
112        }
113
114        A_MEMZERO(target, sizeof(struct htc_target));
115        A_MUTEX_INIT(&target->HTCLock);
116        A_MUTEX_INIT(&target->HTCRxLock);
117        A_MUTEX_INIT(&target->HTCTxLock);
118        INIT_HTC_PACKET_QUEUE(&target->ControlBufferTXFreeList);
119        INIT_HTC_PACKET_QUEUE(&target->ControlBufferRXFreeList);
120        
121            /* give device layer the hif device handle */
122        target->Device.HIFDevice = hif_handle;
123            /* give the device layer our context (for event processing)
124             * the device layer will register it's own context with HIF
125             * so we need to set this so we can fetch it in the target remove handler */
126        target->Device.HTCContext = target;
127            /* set device layer target failure callback */
128        target->Device.TargetFailureCallback = HTCReportFailure;
129            /* set device layer recv message pending callback */
130        target->Device.MessagePendingCallback = HTCRecvMessagePendingHandler;
131        target->EpWaitingForBuffers = ENDPOINT_MAX;
132
133        memcpy(&target->HTCInitInfo,pInfo,sizeof(struct htc_init_info));
134        
135        ResetEndpointStates(target);
136          
137            /* setup device layer */
138        status = DevSetup(&target->Device);
139
140        if (status) {
141            break;
142        }
143
144
145        /* get the block sizes */
146        status = HIFConfigureDevice(hif_handle, HIF_DEVICE_GET_MBOX_BLOCK_SIZE,
147                                    blocksizes, sizeof(blocksizes));
148        if (status) {
149            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to get block size info from HIF layer...\n"));
150            break;
151        }
152
153        /* Set the control buffer size based on the block size */
154        if (blocksizes[1] > HTC_MAX_CONTROL_MESSAGE_LENGTH) {
155            ctrl_bufsz = blocksizes[1] + HTC_HDR_LENGTH;
156        } else {
157            ctrl_bufsz = HTC_MAX_CONTROL_MESSAGE_LENGTH + HTC_HDR_LENGTH;
158        }
159        for (i = 0;i < NUM_CONTROL_BUFFERS;i++) {
160            target->HTCControlBuffers[i].Buffer = A_MALLOC(ctrl_bufsz);
161            if (target->HTCControlBuffers[i].Buffer == NULL) {
162                AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to allocate memory\n"));
163                status = A_ERROR;
164                break;
165            }
166        }
167
168        if (status) {
169            break;
170        }
171
172            /* carve up buffers/packets for control messages */
173        for (i = 0; i < NUM_CONTROL_RX_BUFFERS; i++) {
174            struct htc_packet *pControlPacket;
175            pControlPacket = &target->HTCControlBuffers[i].HtcPacket;
176            SET_HTC_PACKET_INFO_RX_REFILL(pControlPacket,
177                                          target,
178                                          target->HTCControlBuffers[i].Buffer,
179                                          ctrl_bufsz,
180                                          ENDPOINT_0);
181            HTC_FREE_CONTROL_RX(target,pControlPacket);
182        }
183
184        for (;i < NUM_CONTROL_BUFFERS;i++) {
185             struct htc_packet *pControlPacket;
186             pControlPacket = &target->HTCControlBuffers[i].HtcPacket;
187             INIT_HTC_PACKET_INFO(pControlPacket,
188                                  target->HTCControlBuffers[i].Buffer,
189                                  ctrl_bufsz);
190             HTC_FREE_CONTROL_TX(target,pControlPacket);
191        }
192
193    } while (false);
194
195    if (status) {
196        if (target != NULL) {
197            HTCCleanup(target);
198            target = NULL;
199        }
200    }
201
202    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCCreate - Exit\n"));
203
204    return target;
205}
206
207void  HTCDestroy(HTC_HANDLE HTCHandle)
208{
209    struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
210    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCDestroy ..  Destroying :0x%lX \n",(unsigned long)target));
211    HTCCleanup(target);
212    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCDestroy \n"));
213}
214
215/* get the low level HIF device for the caller , the caller may wish to do low level
216 * HIF requests */
217void *HTCGetHifDevice(HTC_HANDLE HTCHandle)
218{
219    struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
220    return target->Device.HIFDevice;
221}
222
223/* wait for the target to arrive (sends HTC Ready message)
224 * this operation is fully synchronous and the message is polled for */
225int HTCWaitTarget(HTC_HANDLE HTCHandle)
226{
227    struct htc_target              *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
228    int                 status;
229    struct htc_packet              *pPacket = NULL;
230    HTC_READY_EX_MSG        *pRdyMsg;
231
232    struct htc_service_connect_req  connect;
233    struct htc_service_connect_resp resp;
234
235    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Enter (target:0x%lX) \n", (unsigned long)target));
236
237    do {
238
239#ifdef MBOXHW_UNIT_TEST
240
241        status = DoMboxHWTest(&target->Device);
242
243        if (status) {
244            break;
245        }
246
247#endif
248
249            /* we should be getting 1 control message that the target is ready */
250        status = HTCWaitforControlMessage(target, &pPacket);
251
252        if (status) {
253            AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Target Not Available!!\n"));
254            break;
255        }
256
257            /* we controlled the buffer creation so it has to be properly aligned */
258        pRdyMsg = (HTC_READY_EX_MSG *)pPacket->pBuffer;
259
260        if ((pRdyMsg->Version2_0_Info.MessageID != HTC_MSG_READY_ID) ||
261            (pPacket->ActualLength < sizeof(HTC_READY_MSG))) {
262                /* this message is not valid */
263            AR_DEBUG_ASSERT(false);
264            status = A_EPROTO;
265            break;
266        }
267
268        
269        if (pRdyMsg->Version2_0_Info.CreditCount == 0 || pRdyMsg->Version2_0_Info.CreditSize == 0) {
270              /* this message is not valid */
271            AR_DEBUG_ASSERT(false);
272            status = A_EPROTO;
273            break;
274        }
275
276        target->TargetCredits = pRdyMsg->Version2_0_Info.CreditCount;
277        target->TargetCreditSize = pRdyMsg->Version2_0_Info.CreditSize;
278        
279        AR_DEBUG_PRINTF(ATH_DEBUG_WARN, (" Target Ready: credits: %d credit size: %d\n",
280                target->TargetCredits, target->TargetCreditSize));
281        
282            /* check if this is an extended ready message */        
283        if (pPacket->ActualLength >= sizeof(HTC_READY_EX_MSG)) {
284                /* this is an extended message */    
285            target->HTCTargetVersion = pRdyMsg->HTCVersion;   
286            target->MaxMsgPerBundle = pRdyMsg->MaxMsgsPerHTCBundle;     
287        } else {
288                /* legacy */
289            target->HTCTargetVersion = HTC_VERSION_2P0;
290            target->MaxMsgPerBundle = 0;    
291        }
292        
293#ifdef HTC_FORCE_LEGACY_2P0   
294            /* for testing and comparison...*/     
295        target->HTCTargetVersion = HTC_VERSION_2P0;
296        target->MaxMsgPerBundle = 0;
297#endif
298           
299        AR_DEBUG_PRINTF(ATH_DEBUG_TRC, 
300                    ("Using HTC Protocol Version : %s (%d)\n ", 
301                    (target->HTCTargetVersion == HTC_VERSION_2P0) ? "2.0" : ">= 2.1",
302                    target->HTCTargetVersion));
303                    
304        if (target->MaxMsgPerBundle > 0) {
305                /* limit what HTC can handle */
306            target->MaxMsgPerBundle = min(HTC_HOST_MAX_MSG_PER_BUNDLE, target->MaxMsgPerBundle);          
307                /* target supports message bundling, setup device layer */
308            if (DevSetupMsgBundling(&target->Device,target->MaxMsgPerBundle)) {
309                    /* device layer can't handle bundling */
310                target->MaxMsgPerBundle = 0;        
311            } else {
312                    /* limit bundle what the device layer can handle */
313                target->MaxMsgPerBundle = min(DEV_GET_MAX_MSG_PER_BUNDLE(&target->Device),
314                                              target->MaxMsgPerBundle);     
315            }
316        }
317        
318        if (target->MaxMsgPerBundle > 0) {
319            AR_DEBUG_PRINTF(ATH_DEBUG_TRC, 
320                    (" HTC bundling allowed. Max Msg Per HTC Bundle: %d\n", target->MaxMsgPerBundle));    
321           
322            if (DEV_GET_MAX_BUNDLE_SEND_LENGTH(&target->Device) != 0) {           
323                target->SendBundlingEnabled = true;
324            }            
325            if (DEV_GET_MAX_BUNDLE_RECV_LENGTH(&target->Device) != 0) {    
326                target->RecvBundlingEnabled = true;
327            }
328                            
329            if (!DEV_IS_LEN_BLOCK_ALIGNED(&target->Device,target->TargetCreditSize)) {
330                AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("*** Credit size: %d is not block aligned! Disabling send bundling \n",
331                        target->TargetCreditSize));    
332                    /* disallow send bundling since the credit size is not aligned to a block size
333                     * the I/O block padding will spill into the next credit buffer which is fatal */
334                target->SendBundlingEnabled = false;
335            }
336        }
337           
338            /* setup our pseudo HTC control endpoint connection */
339        A_MEMZERO(&connect,sizeof(connect));
340        A_MEMZERO(&resp,sizeof(resp));
341        connect.EpCallbacks.pContext = target;
342        connect.EpCallbacks.EpTxComplete = HTCControlTxComplete;
343        connect.EpCallbacks.EpRecv = HTCControlRecv;
344        connect.EpCallbacks.EpRecvRefill = NULL;  /* not needed */
345        connect.EpCallbacks.EpSendFull = NULL;    /* not nedded */
346        connect.MaxSendQueueDepth = NUM_CONTROL_BUFFERS;
347        connect.ServiceID = HTC_CTRL_RSVD_SVC;
348
349            /* connect fake service */
350        status = HTCConnectService((HTC_HANDLE)target,
351                                   &connect,
352                                   &resp);
353
354        if (!status) {
355            break;
356        }
357
358    } while (false);
359
360    if (pPacket != NULL) {
361        HTC_FREE_CONTROL_RX(target,pPacket);
362    }
363
364    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Exit\n"));
365
366    return status;
367}
368
369
370
371/* Start HTC, enable interrupts and let the target know host has finished setup */
372int HTCStart(HTC_HANDLE HTCHandle)
373{
374    struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
375    struct htc_packet *pPacket;
376    int   status;
377
378    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Enter\n"));
379
380        /* make sure interrupts are disabled at the chip level,
381         * this function can be called again from a reboot of the target without shutting down HTC */
382    DevDisableInterrupts(&target->Device);
383        /* make sure state is cleared again */
384    target->OpStateFlags = 0;
385    target->RecvStateFlags = 0;
386      
387        /* now that we are starting, push control receive buffers into the
388         * HTC control endpoint */
389
390    while (1) {
391        pPacket = HTC_ALLOC_CONTROL_RX(target);
392        if (NULL == pPacket) {
393            break;
394        }
395        HTCAddReceivePkt((HTC_HANDLE)target,pPacket);
396    }
397
398    do {
399
400        AR_DEBUG_ASSERT(target->InitCredits != NULL);
401        AR_DEBUG_ASSERT(target->EpCreditDistributionListHead != NULL);
402        AR_DEBUG_ASSERT(target->EpCreditDistributionListHead->pNext != NULL);
403
404            /* call init credits callback to do the distribution ,
405             * NOTE: the first entry in the distribution list is ENDPOINT_0, so
406             * we pass the start of the list after this one. */
407        target->InitCredits(target->pCredDistContext,
408                            target->EpCreditDistributionListHead->pNext,
409                            target->TargetCredits);
410
411#ifdef ATH_DEBUG_MODULE
412
413        if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_TRC)) {
414            DumpCreditDistStates(target);
415        }
416#endif
417
418            /* the caller is done connecting to services, so we can indicate to the
419            * target that the setup phase is complete */
420        status = HTCSendSetupComplete(target);
421
422        if (status) {
423            break;
424        }
425
426            /* unmask interrupts */
427        status = DevUnmaskInterrupts(&target->Device);
428
429        if (status) {
430            HTCStop(target);
431        }
432
433    } while (false);
434
435    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Exit\n"));
436    return status;
437}
438
439static void ResetEndpointStates(struct htc_target *target)
440{
441    struct htc_endpoint        *pEndpoint;
442    int                  i;
443
444    for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
445        pEndpoint = &target->EndPoint[i];
446        
447        A_MEMZERO(&pEndpoint->CreditDist, sizeof(pEndpoint->CreditDist));
448        pEndpoint->ServiceID = 0;
449        pEndpoint->MaxMsgLength = 0;
450        pEndpoint->MaxTxQueueDepth = 0;
451        A_MEMZERO(&pEndpoint->EndPointStats,sizeof(pEndpoint->EndPointStats));
452        INIT_HTC_PACKET_QUEUE(&pEndpoint->RxBuffers);
453        INIT_HTC_PACKET_QUEUE(&pEndpoint->TxQueue);
454        INIT_HTC_PACKET_QUEUE(&pEndpoint->RecvIndicationQueue);
455        pEndpoint->target = target;
456    }
457        /* reset distribution list */
458    target->EpCreditDistributionListHead = NULL;
459}
460
461/* stop HTC communications, i.e. stop interrupt reception, and flush all queued buffers */
462void HTCStop(HTC_HANDLE HTCHandle)
463{
464    struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
465    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCStop \n"));
466
467    LOCK_HTC(target);
468        /* mark that we are shutting down .. */
469    target->OpStateFlags |= HTC_OP_STATE_STOPPING;
470    UNLOCK_HTC(target);
471    
472        /* Masking interrupts is a synchronous operation, when this function returns
473         * all pending HIF I/O has completed, we can safely flush the queues */
474    DevMaskInterrupts(&target->Device);
475
476#ifdef THREAD_X
477	//
478	//	Is this delay required
479	//
480    A_MDELAY(200); // wait for IRQ process done
481#endif
482        /* flush all send packets */
483    HTCFlushSendPkts(target);
484        /* flush all recv buffers */
485    HTCFlushRecvBuffers(target);
486
487    DevCleanupMsgBundling(&target->Device);
488
489    ResetEndpointStates(target);
490   
491    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCStop \n"));
492}
493
494#ifdef ATH_DEBUG_MODULE
495void HTCDumpCreditStates(HTC_HANDLE HTCHandle)
496{
497    struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
498
499    LOCK_HTC_TX(target);
500
501    DumpCreditDistStates(target);
502
503    UNLOCK_HTC_TX(target);
504    
505    DumpAR6KDevState(&target->Device);
506}
507#endif
508/* report a target failure from the device, this is a callback from the device layer
509 * which uses a mechanism to report errors from the target (i.e. special interrupts) */
510static void HTCReportFailure(void *Context)
511{
512    struct htc_target *target = (struct htc_target *)Context;
513
514    target->TargetFailure = true;
515
516    if (target->HTCInitInfo.TargetFailure != NULL) {
517            /* let upper layer know, it needs to call HTCStop() */
518        target->HTCInitInfo.TargetFailure(target->HTCInitInfo.pContext, A_ERROR);
519    }
520}
521
522bool HTCGetEndpointStatistics(HTC_HANDLE               HTCHandle,
523                                HTC_ENDPOINT_ID          Endpoint,
524                                HTC_ENDPOINT_STAT_ACTION Action,
525                                struct htc_endpoint_stats       *pStats)
526{
527
528    struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
529    bool     clearStats = false;
530    bool     sample = false;
531
532    switch (Action) {
533        case HTC_EP_STAT_SAMPLE :
534            sample = true;
535            break;
536        case HTC_EP_STAT_SAMPLE_AND_CLEAR :
537            sample = true;
538            clearStats = true;
539            break;
540        case HTC_EP_STAT_CLEAR :
541            clearStats = true;
542            break;
543        default:
544            break;
545    }
546
547    A_ASSERT(Endpoint < ENDPOINT_MAX);
548
549        /* lock out TX and RX while we sample and/or clear */
550    LOCK_HTC_TX(target);
551    LOCK_HTC_RX(target);
552
553    if (sample) {
554        A_ASSERT(pStats != NULL);
555            /* return the stats to the caller */
556        memcpy(pStats, &target->EndPoint[Endpoint].EndPointStats, sizeof(struct htc_endpoint_stats));
557    }
558
559    if (clearStats) {
560            /* reset stats */
561        A_MEMZERO(&target->EndPoint[Endpoint].EndPointStats, sizeof(struct htc_endpoint_stats));
562    }
563
564    UNLOCK_HTC_RX(target);
565    UNLOCK_HTC_TX(target);
566
567    return true;
568}
569
570struct ar6k_device  *HTCGetAR6KDevice(void *HTCHandle)
571{
572    struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
573    return &target->Device;
574}
575