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(struct ar6k_device *pDev, struct htc_packet *pPacket);
58 extern struct htc_packet *AR6KAllocIOPacket(struct ar6k_device *pDev);
59 
60 
61 /* callback when our fetch to enable/disable completes */
DevGMboxIRQActionAsyncHandler(void * Context,struct htc_packet * pPacket)62 static void DevGMboxIRQActionAsyncHandler(void *Context, struct htc_packet *pPacket)
63 {
64     struct ar6k_device *pDev = (struct ar6k_device *)Context;
65 
66     AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevGMboxIRQActionAsyncHandler: (dev: 0x%lX)\n", (unsigned long)pDev));
67 
68     if (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 
DevGMboxCounterEnableDisable(struct ar6k_device * pDev,GMBOX_IRQ_ACTION_TYPE IrqAction,bool AsyncMode)77 static int DevGMboxCounterEnableDisable(struct ar6k_device *pDev, GMBOX_IRQ_ACTION_TYPE IrqAction, bool AsyncMode)
78 {
79     int                  status = 0;
80     struct ar6k_irq_enable_registers regs;
81     struct 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     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             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 (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 
DevGMboxIRQAction(struct ar6k_device * pDev,GMBOX_IRQ_ACTION_TYPE IrqAction,bool AsyncMode)158 int DevGMboxIRQAction(struct ar6k_device *pDev, GMBOX_IRQ_ACTION_TYPE IrqAction, bool AsyncMode)
159 {
160     int      status = 0;
161     struct htc_packet    *pIOPacket = NULL;
162     u8 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             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 (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 
DevCleanupGMbox(struct ar6k_device * pDev)264 void DevCleanupGMbox(struct ar6k_device *pDev)
265 {
266     if (pDev->GMboxEnabled) {
267         pDev->GMboxEnabled = false;
268         GMboxProtocolUninstall(pDev);
269     }
270 }
271 
DevSetupGMbox(struct ar6k_device * pDev)272 int DevSetupGMbox(struct ar6k_device *pDev)
273 {
274     int    status = 0;
275     u8 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 (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 (status) {
309             break;
310         }
311 
312         status = GMboxProtocolInstall(pDev);
313 
314         if (status) {
315             break;
316         }
317 
318         pDev->GMboxEnabled = true;
319 
320     } while (false);
321 
322     return status;
323 }
324 
DevCheckGMboxInterrupts(struct ar6k_device * pDev)325 int DevCheckGMboxInterrupts(struct ar6k_device *pDev)
326 {
327     int status = 0;
328     u8 counter_int_status;
329     int      credits;
330     u8 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 (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                                 (u8 *)&pDev->IrqProcRegisters.rx_gmbox_lookahead_alias[0],
364                                 pDev->IrqProcRegisters.gmbox_rx_avail);
365             }
366         }
367 
368         if (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 (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 
DevGMboxWrite(struct ar6k_device * pDev,struct htc_packet * pPacket,u32 WriteLength)399 int DevGMboxWrite(struct ar6k_device *pDev, struct htc_packet *pPacket, u32 WriteLength)
400 {
401     u32 paddedLength;
402     bool   sync = (pPacket->Completion == NULL) ? true : false;
403     int status;
404     u32 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 = 0;
430         }
431     }
432 
433     return status;
434 }
435 
DevGMboxRead(struct ar6k_device * pDev,struct htc_packet * pPacket,u32 ReadLength)436 int DevGMboxRead(struct ar6k_device *pDev, struct htc_packet *pPacket, u32 ReadLength)
437 {
438 
439     u32 paddedLength;
440     int status;
441     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 0;
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 
ProcessCreditCounterReadBuffer(u8 * pBuffer,int Length)480 static int ProcessCreditCounterReadBuffer(u8 *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 */
DevGMboxReadCreditsAsyncHandler(void * Context,struct htc_packet * pPacket)519 static void DevGMboxReadCreditsAsyncHandler(void *Context, struct htc_packet *pPacket)
520 {
521     struct ar6k_device *pDev = (struct ar6k_device *)Context;
522 
523     AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevGMboxReadCreditsAsyncHandler: (dev: 0x%lX)\n", (unsigned long)pDev));
524 
525     if (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 
DevGMboxReadCreditCounter(struct ar6k_device * pDev,bool AsyncMode,int * pCredits)542 int DevGMboxReadCreditCounter(struct ar6k_device *pDev, bool AsyncMode, int *pCredits)
543 {
544     int    status = 0;
545     struct 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 (status) {
587         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
588                 (" DevGMboxReadCreditCounter failed! status:%d \n", status));
589     }
590 
591     if (pIOPacket != NULL) {
592         if (!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 
DevGMboxReadCreditSize(struct ar6k_device * pDev,int * pCreditSize)605 int DevGMboxReadCreditSize(struct ar6k_device *pDev, int *pCreditSize)
606 {
607     int    status;
608     u8 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 (!status) {
618         if (buffer[0] == 0) {
619             *pCreditSize = 256;
620         } else {
621             *pCreditSize = buffer[0];
622         }
623 
624     }
625 
626     return status;
627 }
628 
DevNotifyGMboxTargetFailure(struct ar6k_device * pDev)629 void DevNotifyGMboxTargetFailure(struct 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 
DevGMboxRecvLookAheadPeek(struct ar6k_device * pDev,u8 * pLookAheadBuffer,int * pLookAheadBytes)637 int DevGMboxRecvLookAheadPeek(struct ar6k_device *pDev, u8 *pLookAheadBuffer, int *pLookAheadBytes)
638 {
639 
640     int                    status = 0;
641     struct 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                               (u8 *)&procRegs,
658                               AR6K_IRQ_PROC_REGS_SIZE,
659                               HIF_RD_SYNC_BYTE_INC,
660                               NULL);
661 
662         if (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             memcpy(pLookAheadBuffer,&procRegs.rx_gmbox_lookahead_alias[0],bytes);
671             *pLookAheadBytes = bytes;
672         }
673 
674     } while (false);
675 
676     return status;
677 }
678 
DevGMboxSetTargetInterrupt(struct ar6k_device * pDev,int Signal,int AckTimeoutMS)679 int DevGMboxSetTargetInterrupt(struct ar6k_device *pDev, int Signal, int AckTimeoutMS)
680 {
681     int status = 0;
682     int      i;
683     u8 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 (status) {
705             break;
706         }
707 
708     } while (false);
709 
710 
711     if (!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 (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 
757