Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
[pandora-kernel.git] / drivers / staging / ath6kl / htc2 / AR6000 / ar6k_gmbox.c
1 //------------------------------------------------------------------------------
2 // <copyright file="ar6k_gmbox.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 // Generic MBOX API implementation
22 // 
23 // Author(s): ="Atheros"
24 //==============================================================================
25 #include "a_config.h"
26 #include "athdefs.h"
27 #include "a_types.h"
28 #include "a_osapi.h"
29 #include "../htc_debug.h"
30 #include "hif.h"
31 #include "htc_packet.h"
32 #include "ar6k.h"
33 #include "hw/mbox_host_reg.h"
34 #include "gmboxif.h"
35
36 /* 
37  * This file provides management functions and a toolbox for GMBOX protocol modules.  
38  * Only one protocol module can be installed at a time. The determination of which protocol
39  * module is installed is determined at compile time.  
40  * 
41  */
42 #ifdef ATH_AR6K_ENABLE_GMBOX
43      /* GMBOX definitions */
44 #define GMBOX_INT_STATUS_ENABLE_REG     0x488
45 #define GMBOX_INT_STATUS_RX_DATA        (1 << 0)
46 #define GMBOX_INT_STATUS_TX_OVERFLOW    (1 << 1)
47 #define GMBOX_INT_STATUS_RX_OVERFLOW    (1 << 2)
48
49 #define GMBOX_LOOKAHEAD_MUX_REG         0x498
50 #define GMBOX_LA_MUX_OVERRIDE_2_3       (1 << 0)
51
52 #define AR6K_GMBOX_CREDIT_DEC_ADDRESS   (COUNT_DEC_ADDRESS + 4 * AR6K_GMBOX_CREDIT_COUNTER)
53 #define AR6K_GMBOX_CREDIT_SIZE_ADDRESS  (COUNT_ADDRESS     + AR6K_GMBOX_CREDIT_SIZE_COUNTER)
54
55
56     /* external APIs for allocating and freeing internal I/O packets to handle ASYNC I/O */ 
57 extern void AR6KFreeIOPacket(AR6K_DEVICE *pDev, HTC_PACKET *pPacket);
58 extern HTC_PACKET *AR6KAllocIOPacket(AR6K_DEVICE *pDev);
59
60
61 /* callback when our fetch to enable/disable completes */
62 static void DevGMboxIRQActionAsyncHandler(void *Context, HTC_PACKET *pPacket)
63 {
64     AR6K_DEVICE *pDev = (AR6K_DEVICE *)Context;
65
66     AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevGMboxIRQActionAsyncHandler: (dev: 0x%lX)\n", (unsigned long)pDev));
67
68     if (A_FAILED(pPacket->Status)) {
69         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
70                 ("IRQAction Operation (%d) failed! status:%d \n", pPacket->PktInfo.AsRx.HTCRxFlags,pPacket->Status));
71     }
72         /* free this IO packet */
73     AR6KFreeIOPacket(pDev,pPacket);
74     AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevGMboxIRQActionAsyncHandler \n"));
75 }
76
77 static A_STATUS DevGMboxCounterEnableDisable(AR6K_DEVICE *pDev, GMBOX_IRQ_ACTION_TYPE IrqAction, A_BOOL AsyncMode)
78 {
79     A_STATUS                  status = A_OK;
80     AR6K_IRQ_ENABLE_REGISTERS regs;
81     HTC_PACKET                *pIOPacket = NULL;  
82     
83     LOCK_AR6K(pDev);
84     
85     if (GMBOX_CREDIT_IRQ_ENABLE == IrqAction) {
86         pDev->GMboxInfo.CreditCountIRQEnabled = TRUE;
87         pDev->IrqEnableRegisters.counter_int_status_enable |=
88             COUNTER_INT_STATUS_ENABLE_BIT_SET(1 << AR6K_GMBOX_CREDIT_COUNTER);
89         pDev->IrqEnableRegisters.int_status_enable |= INT_STATUS_ENABLE_COUNTER_SET(0x01);
90     } else {
91         pDev->GMboxInfo.CreditCountIRQEnabled = FALSE;
92         pDev->IrqEnableRegisters.counter_int_status_enable &=
93             ~(COUNTER_INT_STATUS_ENABLE_BIT_SET(1 << AR6K_GMBOX_CREDIT_COUNTER));    
94     }
95         /* copy into our temp area */
96     A_MEMCPY(&regs,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE);
97
98     UNLOCK_AR6K(pDev);
99
100     do {
101
102         if (AsyncMode) {
103
104             pIOPacket = AR6KAllocIOPacket(pDev);
105
106             if (NULL == pIOPacket) {
107                 status = A_NO_MEMORY;
108                 A_ASSERT(FALSE);
109                 break;
110             }
111
112                 /* copy values to write to our async I/O buffer */
113             A_MEMCPY(pIOPacket->pBuffer,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE);
114
115                 /* stick in our completion routine when the I/O operation completes */
116             pIOPacket->Completion = DevGMboxIRQActionAsyncHandler;
117             pIOPacket->pContext = pDev;
118             pIOPacket->PktInfo.AsRx.HTCRxFlags = IrqAction;
119                 /* write it out asynchronously */
120             HIFReadWrite(pDev->HIFDevice,
121                          INT_STATUS_ENABLE_ADDRESS,
122                          pIOPacket->pBuffer,
123                          AR6K_IRQ_ENABLE_REGS_SIZE,
124                          HIF_WR_ASYNC_BYTE_INC,
125                          pIOPacket);
126                          
127             pIOPacket = NULL; 
128             break;
129         } 
130
131             /* if we get here we are doing it synchronously */
132         status = HIFReadWrite(pDev->HIFDevice,
133                               INT_STATUS_ENABLE_ADDRESS,
134                               &regs.int_status_enable,
135                               AR6K_IRQ_ENABLE_REGS_SIZE,
136                               HIF_WR_SYNC_BYTE_INC,
137                               NULL);    
138     } while (FALSE);
139     
140     if (A_FAILED(status)) {
141         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
142                 (" IRQAction Operation (%d) failed! status:%d \n", IrqAction, status));    
143     } else {
144         if (!AsyncMode) {
145             AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
146                     (" IRQAction Operation (%d) success \n", IrqAction)); 
147         }       
148     }
149     
150     if (pIOPacket != NULL) {
151         AR6KFreeIOPacket(pDev,pIOPacket);
152     }
153         
154     return status;
155 }
156
157
158 A_STATUS DevGMboxIRQAction(AR6K_DEVICE *pDev, GMBOX_IRQ_ACTION_TYPE IrqAction, A_BOOL AsyncMode)
159 {
160     A_STATUS      status = A_OK;
161     HTC_PACKET    *pIOPacket = NULL;   
162     A_UINT8       GMboxIntControl[4];
163
164     if (GMBOX_CREDIT_IRQ_ENABLE == IrqAction) {
165         return DevGMboxCounterEnableDisable(pDev, GMBOX_CREDIT_IRQ_ENABLE, AsyncMode);
166     } else if(GMBOX_CREDIT_IRQ_DISABLE == IrqAction) {
167         return DevGMboxCounterEnableDisable(pDev, GMBOX_CREDIT_IRQ_DISABLE, AsyncMode);
168     }
169     
170     if (GMBOX_DISABLE_ALL == IrqAction) {
171             /* disable credit IRQ, those are on a different set of registers */
172         DevGMboxCounterEnableDisable(pDev, GMBOX_CREDIT_IRQ_DISABLE, AsyncMode);    
173     }
174             
175         /* take the lock to protect interrupt enable shadows */
176     LOCK_AR6K(pDev);
177
178     switch (IrqAction) {
179         
180         case GMBOX_DISABLE_ALL:
181             pDev->GMboxControlRegisters.int_status_enable = 0;
182             break;
183         case GMBOX_ERRORS_IRQ_ENABLE:
184             pDev->GMboxControlRegisters.int_status_enable |= GMBOX_INT_STATUS_TX_OVERFLOW |
185                                                              GMBOX_INT_STATUS_RX_OVERFLOW;
186             break;
187         case GMBOX_RECV_IRQ_ENABLE:
188             pDev->GMboxControlRegisters.int_status_enable |= GMBOX_INT_STATUS_RX_DATA;
189             break;
190         case GMBOX_RECV_IRQ_DISABLE:
191             pDev->GMboxControlRegisters.int_status_enable &= ~GMBOX_INT_STATUS_RX_DATA;
192             break;
193         case GMBOX_ACTION_NONE:
194         default:
195             A_ASSERT(FALSE);    
196             break;
197     }
198     
199     GMboxIntControl[0] = pDev->GMboxControlRegisters.int_status_enable;
200     GMboxIntControl[1] = GMboxIntControl[0];
201     GMboxIntControl[2] = GMboxIntControl[0];
202     GMboxIntControl[3] = GMboxIntControl[0];
203     
204     UNLOCK_AR6K(pDev);
205
206     do {
207
208         if (AsyncMode) {
209
210             pIOPacket = AR6KAllocIOPacket(pDev);
211
212             if (NULL == pIOPacket) {
213                 status = A_NO_MEMORY;
214                 A_ASSERT(FALSE);
215                 break;
216             }
217
218                 /* copy values to write to our async I/O buffer */
219             A_MEMCPY(pIOPacket->pBuffer,GMboxIntControl,sizeof(GMboxIntControl));
220
221                 /* stick in our completion routine when the I/O operation completes */
222             pIOPacket->Completion = DevGMboxIRQActionAsyncHandler;
223             pIOPacket->pContext = pDev;
224             pIOPacket->PktInfo.AsRx.HTCRxFlags = IrqAction;
225                 /* write it out asynchronously */
226             HIFReadWrite(pDev->HIFDevice,
227                          GMBOX_INT_STATUS_ENABLE_REG,
228                          pIOPacket->pBuffer,
229                          sizeof(GMboxIntControl),
230                          HIF_WR_ASYNC_BYTE_FIX,
231                          pIOPacket);
232             pIOPacket = NULL;
233             break;
234         }
235
236         /* if we get here we are doing it synchronously */
237
238         status = HIFReadWrite(pDev->HIFDevice,
239                               GMBOX_INT_STATUS_ENABLE_REG,
240                               GMboxIntControl,
241                               sizeof(GMboxIntControl),
242                               HIF_WR_SYNC_BYTE_FIX,
243                               NULL);
244
245     } while (FALSE);
246
247     if (A_FAILED(status)) {
248         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
249                 (" IRQAction Operation (%d) failed! status:%d \n", IrqAction, status));    
250     } else {
251         if (!AsyncMode) {
252             AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
253                     (" IRQAction Operation (%d) success \n", IrqAction)); 
254         }      
255     }
256     
257     if (pIOPacket != NULL) {
258         AR6KFreeIOPacket(pDev,pIOPacket);
259     }
260
261     return status;
262 }
263
264 void DevCleanupGMbox(AR6K_DEVICE *pDev)
265 {
266     if (pDev->GMboxEnabled) {
267         pDev->GMboxEnabled = FALSE;
268         GMboxProtocolUninstall(pDev);        
269     }
270 }
271
272 A_STATUS DevSetupGMbox(AR6K_DEVICE *pDev)
273 {
274     A_STATUS    status = A_OK;
275     A_UINT8     muxControl[4];
276     
277     do {
278         
279         if (0 == pDev->MailBoxInfo.GMboxAddress) {
280             break;    
281         }
282     
283         AR_DEBUG_PRINTF(ATH_DEBUG_ANY,(" GMBOX Advertised: Address:0x%X , size:%d \n",
284                     pDev->MailBoxInfo.GMboxAddress, pDev->MailBoxInfo.GMboxSize));
285                     
286         status = DevGMboxIRQAction(pDev, GMBOX_DISABLE_ALL, PROC_IO_SYNC);
287         
288         if (A_FAILED(status)) {
289             break;    
290         }
291        
292             /* write to mailbox look ahead mux control register, we want the
293              * GMBOX lookaheads to appear on lookaheads 2 and 3 
294              * the register is 1-byte wide so we need to hit it 4 times to align the operation 
295              * to 4-bytes */            
296         muxControl[0] = GMBOX_LA_MUX_OVERRIDE_2_3;
297         muxControl[1] = GMBOX_LA_MUX_OVERRIDE_2_3;
298         muxControl[2] = GMBOX_LA_MUX_OVERRIDE_2_3;
299         muxControl[3] = GMBOX_LA_MUX_OVERRIDE_2_3;
300                 
301         status = HIFReadWrite(pDev->HIFDevice,
302                               GMBOX_LOOKAHEAD_MUX_REG,
303                               muxControl,
304                               sizeof(muxControl),
305                               HIF_WR_SYNC_BYTE_FIX,  /* hit this register 4 times */
306                               NULL);
307         
308         if (A_FAILED(status)) {
309             break;    
310         }
311         
312         status = GMboxProtocolInstall(pDev);
313         
314         if (A_FAILED(status)) {
315             break;    
316         }
317         
318         pDev->GMboxEnabled = TRUE;
319         
320     } while (FALSE);
321     
322     return status;
323 }
324
325 A_STATUS DevCheckGMboxInterrupts(AR6K_DEVICE *pDev)
326 {
327     A_STATUS status = A_OK;
328     A_UINT8  counter_int_status;
329     int      credits;
330     A_UINT8  host_int_status2;
331     
332     AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("+DevCheckGMboxInterrupts \n"));
333      
334     /* the caller guarantees that this is a context that allows for blocking I/O */
335     
336     do {
337         
338         host_int_status2 = pDev->IrqProcRegisters.host_int_status2 &
339                            pDev->GMboxControlRegisters.int_status_enable; 
340                 
341         if (host_int_status2 & GMBOX_INT_STATUS_TX_OVERFLOW) {
342             AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("GMBOX : TX Overflow \n"));  
343             status = A_ECOMM;   
344         }
345         
346         if (host_int_status2 & GMBOX_INT_STATUS_RX_OVERFLOW) {
347             AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("GMBOX : RX Overflow \n"));  
348             status = A_ECOMM;    
349         }
350         
351         if (A_FAILED(status)) {
352             if (pDev->GMboxInfo.pTargetFailureCallback != NULL) {
353                 pDev->GMboxInfo.pTargetFailureCallback(pDev->GMboxInfo.pProtocolContext, status);        
354             }
355             break;
356         }
357     
358         if (host_int_status2 & GMBOX_INT_STATUS_RX_DATA) {
359             if (pDev->IrqProcRegisters.gmbox_rx_avail > 0) {
360                 A_ASSERT(pDev->GMboxInfo.pMessagePendingCallBack != NULL);
361                 status = pDev->GMboxInfo.pMessagePendingCallBack(
362                                 pDev->GMboxInfo.pProtocolContext,
363                                 (A_UINT8 *)&pDev->IrqProcRegisters.rx_gmbox_lookahead_alias[0],
364                                 pDev->IrqProcRegisters.gmbox_rx_avail);
365             }
366         } 
367         
368         if (A_FAILED(status)) {
369            break;                
370         }
371         
372         counter_int_status = pDev->IrqProcRegisters.counter_int_status &
373                              pDev->IrqEnableRegisters.counter_int_status_enable;
374     
375             /* check if credit interrupt is pending */
376         if (counter_int_status & (COUNTER_INT_STATUS_ENABLE_BIT_SET(1 << AR6K_GMBOX_CREDIT_COUNTER))) {
377             
378                 /* do synchronous read */
379             status = DevGMboxReadCreditCounter(pDev, PROC_IO_SYNC, &credits);
380             
381             if (A_FAILED(status)) {
382                 break;    
383             }
384             
385             A_ASSERT(pDev->GMboxInfo.pCreditsPendingCallback != NULL);
386             status = pDev->GMboxInfo.pCreditsPendingCallback(pDev->GMboxInfo.pProtocolContext,
387                                                              credits,
388                                                              pDev->GMboxInfo.CreditCountIRQEnabled);
389         }
390         
391     } while (FALSE);
392     
393     AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("-DevCheckGMboxInterrupts (%d) \n",status));
394     
395     return status;
396 }
397
398
399 A_STATUS DevGMboxWrite(AR6K_DEVICE *pDev, HTC_PACKET *pPacket, A_UINT32 WriteLength) 
400 {
401     A_UINT32 paddedLength;
402     A_BOOL   sync = (pPacket->Completion == NULL) ? TRUE : FALSE;
403     A_STATUS status;
404     A_UINT32 address;
405     
406        /* adjust the length to be a multiple of block size if appropriate */
407     paddedLength = DEV_CALC_SEND_PADDED_LEN(pDev, WriteLength);
408     
409     AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
410                 ("DevGMboxWrite, Padded Length: %d Mbox:0x%X (mode:%s)\n",
411                 WriteLength,
412                 pDev->MailBoxInfo.GMboxAddress,
413                 sync ? "SYNC" : "ASYNC"));
414                 
415         /* last byte of packet has to hit the EOM marker */
416     address = pDev->MailBoxInfo.GMboxAddress + pDev->MailBoxInfo.GMboxSize - paddedLength;
417     
418     status = HIFReadWrite(pDev->HIFDevice,
419                           address,
420                           pPacket->pBuffer,
421                           paddedLength,     /* the padded length */
422                           sync ? HIF_WR_SYNC_BLOCK_INC : HIF_WR_ASYNC_BLOCK_INC,
423                           sync ? NULL : pPacket);  /* pass the packet as the context to the HIF request */
424
425     if (sync) {
426         pPacket->Status = status;
427     } else {
428         if (status == A_PENDING) {
429             status = A_OK;    
430         }    
431     }
432
433     return status;
434 }
435
436 A_STATUS DevGMboxRead(AR6K_DEVICE *pDev, HTC_PACKET *pPacket, A_UINT32 ReadLength) 
437 {
438     
439     A_UINT32 paddedLength;
440     A_STATUS status;
441     A_BOOL   sync = (pPacket->Completion == NULL) ? TRUE : FALSE;
442
443         /* adjust the length to be a multiple of block size if appropriate */
444     paddedLength = DEV_CALC_RECV_PADDED_LEN(pDev, ReadLength);
445                     
446     if (paddedLength > pPacket->BufferLength) {
447         A_ASSERT(FALSE);
448         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
449                 ("DevGMboxRead, Not enough space for padlen:%d recvlen:%d bufferlen:%d \n",
450                     paddedLength,ReadLength,pPacket->BufferLength));
451         if (pPacket->Completion != NULL) {
452             COMPLETE_HTC_PACKET(pPacket,A_EINVAL);
453             return A_OK;
454         }
455         return A_EINVAL;
456     }
457
458     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
459                 ("DevGMboxRead (0x%lX : hdr:0x%X) Padded Length: %d Mbox:0x%X (mode:%s)\n",
460                 (unsigned long)pPacket, pPacket->PktInfo.AsRx.ExpectedHdr,
461                 paddedLength,
462                 pDev->MailBoxInfo.GMboxAddress,
463                 sync ? "SYNC" : "ASYNC"));
464
465     status = HIFReadWrite(pDev->HIFDevice,
466                           pDev->MailBoxInfo.GMboxAddress,
467                           pPacket->pBuffer,
468                           paddedLength,
469                           sync ? HIF_RD_SYNC_BLOCK_FIX : HIF_RD_ASYNC_BLOCK_FIX,
470                           sync ? NULL : pPacket);  /* pass the packet as the context to the HIF request */
471
472     if (sync) {
473         pPacket->Status = status;
474     }
475
476     return status;
477 }
478
479
480 static int ProcessCreditCounterReadBuffer(A_UINT8 *pBuffer, int Length)
481 {
482     int     credits = 0;
483     
484     /* theory of how this works:
485      * We read the credit decrement register multiple times on a byte-wide basis. 
486      * The number of times (32) aligns the I/O operation to be a multiple of 4 bytes and provides a 
487      * reasonable chance to acquire "all" pending credits in a single I/O operation. 
488      * 
489      * Once we obtain the filled buffer, we can walk through it looking for credit decrement transitions.
490      * Each non-zero byte represents a single credit decrement (which is a credit given back to the host)
491      * For example if the target provides 3 credits and added 4 more during the 32-byte read operation the following
492      * pattern "could" appear:
493      * 
494      *    0x3 0x2 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x1 0x0 0x1 0x0 ......rest zeros
495      *    <--------->                     <----------------------------->
496      *         \_ credits aleady there              \_ target adding 4 more credits
497      * 
498      *    The total available credits would be 7, since there are 7 non-zero bytes in the buffer.
499      * 
500      * */
501     
502     if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
503         DebugDumpBytes(pBuffer, Length, "GMBOX Credit read buffer");
504     } 
505         
506     while (Length) {
507         if (*pBuffer != 0) {
508             credits++;    
509         }
510         Length--;
511         pBuffer++;   
512     }  
513     
514     return credits;
515 }
516    
517
518 /* callback when our fetch to enable/disable completes */
519 static void DevGMboxReadCreditsAsyncHandler(void *Context, HTC_PACKET *pPacket)
520 {
521     AR6K_DEVICE *pDev = (AR6K_DEVICE *)Context;
522
523     AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevGMboxReadCreditsAsyncHandler: (dev: 0x%lX)\n", (unsigned long)pDev));
524
525     if (A_FAILED(pPacket->Status)) {
526         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
527                 ("Read Credit Operation failed! status:%d \n", pPacket->Status));
528     } else {
529         int credits = 0;
530         credits = ProcessCreditCounterReadBuffer(pPacket->pBuffer, AR6K_REG_IO_BUFFER_SIZE);
531         pDev->GMboxInfo.pCreditsPendingCallback(pDev->GMboxInfo.pProtocolContext,
532                                                 credits,
533                                                 pDev->GMboxInfo.CreditCountIRQEnabled);
534         
535         
536     }
537         /* free this IO packet */
538     AR6KFreeIOPacket(pDev,pPacket);
539     AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevGMboxReadCreditsAsyncHandler \n"));
540 }
541
542 A_STATUS DevGMboxReadCreditCounter(AR6K_DEVICE *pDev, A_BOOL AsyncMode, int *pCredits)
543 {
544     A_STATUS    status = A_OK;
545     HTC_PACKET  *pIOPacket = NULL;  
546     
547     AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+DevGMboxReadCreditCounter (%s) \n", AsyncMode ? "ASYNC" : "SYNC"));
548                                             
549     do {
550         
551         pIOPacket = AR6KAllocIOPacket(pDev);
552
553         if (NULL == pIOPacket) {
554             status = A_NO_MEMORY;
555             A_ASSERT(FALSE);
556             break;
557         }
558         
559         A_MEMZERO(pIOPacket->pBuffer,AR6K_REG_IO_BUFFER_SIZE);
560       
561         if (AsyncMode) {   
562                 /* stick in our completion routine when the I/O operation completes */
563             pIOPacket->Completion = DevGMboxReadCreditsAsyncHandler;
564             pIOPacket->pContext = pDev;
565                 /* read registers asynchronously */
566             HIFReadWrite(pDev->HIFDevice,
567                          AR6K_GMBOX_CREDIT_DEC_ADDRESS,
568                          pIOPacket->pBuffer,
569                          AR6K_REG_IO_BUFFER_SIZE,  /* hit the register multiple times */
570                          HIF_RD_ASYNC_BYTE_FIX,
571                          pIOPacket);
572             pIOPacket = NULL;
573             break;
574         } 
575
576         pIOPacket->Completion = NULL;
577             /* if we get here we are doing it synchronously */
578         status = HIFReadWrite(pDev->HIFDevice,
579                               AR6K_GMBOX_CREDIT_DEC_ADDRESS,
580                               pIOPacket->pBuffer,
581                               AR6K_REG_IO_BUFFER_SIZE,
582                               HIF_RD_SYNC_BYTE_FIX,
583                               NULL);    
584     } while (FALSE);
585     
586     if (A_FAILED(status)) {
587         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
588                 (" DevGMboxReadCreditCounter failed! status:%d \n", status));          
589     }
590     
591     if (pIOPacket != NULL) {
592         if (A_SUCCESS(status)) {
593                 /* sync mode processing */
594             *pCredits = ProcessCreditCounterReadBuffer(pIOPacket->pBuffer, AR6K_REG_IO_BUFFER_SIZE);     
595         }
596         AR6KFreeIOPacket(pDev,pIOPacket);
597     }
598     
599     AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-DevGMboxReadCreditCounter (%s) (%d) \n", 
600             AsyncMode ? "ASYNC" : "SYNC", status));
601     
602     return status;
603 }
604
605 A_STATUS DevGMboxReadCreditSize(AR6K_DEVICE *pDev, int *pCreditSize)
606 {
607     A_STATUS    status;
608     A_UINT8     buffer[4];
609        
610     status = HIFReadWrite(pDev->HIFDevice,
611                           AR6K_GMBOX_CREDIT_SIZE_ADDRESS,
612                           buffer,
613                           sizeof(buffer),
614                           HIF_RD_SYNC_BYTE_FIX, /* hit the register 4 times to align the I/O */
615                           NULL);    
616     
617     if (A_SUCCESS(status)) {
618         if (buffer[0] == 0) {
619             *pCreditSize = 256;    
620         } else {   
621             *pCreditSize = buffer[0];
622         } 
623            
624     } 
625     
626     return status;
627 }
628
629 void DevNotifyGMboxTargetFailure(AR6K_DEVICE *pDev)
630 {
631         /* Target ASSERTED!!! */
632     if (pDev->GMboxInfo.pTargetFailureCallback != NULL) {
633         pDev->GMboxInfo.pTargetFailureCallback(pDev->GMboxInfo.pProtocolContext, A_HARDWARE);        
634     }
635 }
636
637 A_STATUS DevGMboxRecvLookAheadPeek(AR6K_DEVICE *pDev, A_UINT8 *pLookAheadBuffer, int *pLookAheadBytes)
638 {
639
640     A_STATUS                    status = A_OK;
641     AR6K_IRQ_PROC_REGISTERS     procRegs;
642     int                         maxCopy;
643   
644     do {
645             /* on entry the caller provides the length of the lookahead buffer */
646         if (*pLookAheadBytes > sizeof(procRegs.rx_gmbox_lookahead_alias)) {
647             A_ASSERT(FALSE);
648             status = A_EINVAL;
649             break;    
650         }
651         
652         maxCopy = *pLookAheadBytes;
653         *pLookAheadBytes = 0;
654             /* load the register table from the device */
655         status = HIFReadWrite(pDev->HIFDevice,
656                               HOST_INT_STATUS_ADDRESS,
657                               (A_UINT8 *)&procRegs,
658                               AR6K_IRQ_PROC_REGS_SIZE,
659                               HIF_RD_SYNC_BYTE_INC,
660                               NULL);
661
662         if (A_FAILED(status)) {
663             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
664                 ("DevGMboxRecvLookAheadPeek : Failed to read register table (%d) \n",status));
665             break;
666         }
667         
668         if (procRegs.gmbox_rx_avail > 0) {
669             int bytes = procRegs.gmbox_rx_avail > maxCopy ? maxCopy : procRegs.gmbox_rx_avail;
670             A_MEMCPY(pLookAheadBuffer,&procRegs.rx_gmbox_lookahead_alias[0],bytes);
671             *pLookAheadBytes = bytes;
672         }
673         
674     } while (FALSE);
675        
676     return status; 
677 }
678
679 A_STATUS DevGMboxSetTargetInterrupt(AR6K_DEVICE *pDev, int Signal, int AckTimeoutMS)
680 {
681     A_STATUS status = A_OK;
682     int      i;
683     A_UINT8  buffer[4];
684     
685     A_MEMZERO(buffer, sizeof(buffer));
686     
687     do {
688         
689         if (Signal >= MBOX_SIG_HCI_BRIDGE_MAX) {
690             status = A_EINVAL;
691             break;    
692         }
693         
694             /* set the last buffer to do the actual signal trigger */
695         buffer[3] = (1 << Signal);
696         
697         status = HIFReadWrite(pDev->HIFDevice,
698                               INT_WLAN_ADDRESS,
699                               buffer,
700                               sizeof(buffer),
701                               HIF_WR_SYNC_BYTE_FIX, /* hit the register 4 times to align the I/O */
702                               NULL);    
703                           
704         if (A_FAILED(status)) {
705             break;    
706         }
707         
708     } while (FALSE);
709     
710     
711     if (A_SUCCESS(status)) {        
712             /* now read back the register to see if the bit cleared */
713         while (AckTimeoutMS) {        
714             status = HIFReadWrite(pDev->HIFDevice,
715                                   INT_WLAN_ADDRESS,
716                                   buffer,
717                                   sizeof(buffer),
718                                   HIF_RD_SYNC_BYTE_FIX,
719                                   NULL);    
720                           
721             if (A_FAILED(status)) {
722                 break;    
723             }
724                             
725             for (i = 0; i < sizeof(buffer); i++) {
726                 if (buffer[i] & (1 << Signal)) {
727                     /* bit is still set */
728                     break;    
729                 }   
730             }
731             
732             if (i >= sizeof(buffer)) {
733                 /* done */
734                 break;    
735             }
736             
737             AckTimeoutMS--;
738             A_MDELAY(1);  
739         }
740         
741         if (0 == AckTimeoutMS) {
742             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
743                 ("DevGMboxSetTargetInterrupt : Ack Timed-out (sig:%d) \n",Signal));
744             status = A_ERROR;    
745         }        
746     }
747     
748     return status;
749     
750 }
751
752 #endif  //ATH_AR6K_ENABLE_GMBOX
753
754
755
756