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