Add ar6000 wireless driver.
[kernel.git] / drivers / ar6000 / htc / htc.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
23 static HTC_INIT_INFO  HTCInitInfo = {NULL,NULL,NULL};
24 static A_BOOL         HTCInitialized = FALSE;
25
26 static A_STATUS HTCTargetInsertedHandler(void *hif_handle);
27 static A_STATUS HTCTargetRemovedHandler(void *handle, A_STATUS status);
28 static void HTCReportFailure(void *Context);
29
30 /* Initializes the HTC layer */
31 A_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
58 void 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
65 HTC_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 */
77 static 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 */
95 static 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 */
177 static 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 */
207 void *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 */
215 void 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 */
224 A_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 */
314 A_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 */
373 void 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() */
394 void 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
403 void 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) */
416 static 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
428 void 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
458 A_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 }