blob: 374001155feb08067723b35eb84d4b73c3a4b3fe [file] [log] [blame]
Vipin Mehta30295c82010-09-01 12:06:33 -07001//------------------------------------------------------------------------------
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 */
Luis R. Rodriguezc6528e22011-03-14 10:58:57 -070057extern void AR6KFreeIOPacket(struct ar6k_device *pDev, struct htc_packet *pPacket);
58extern struct htc_packet *AR6KAllocIOPacket(struct ar6k_device *pDev);
Vipin Mehta30295c82010-09-01 12:06:33 -070059
60
61/* callback when our fetch to enable/disable completes */
Luis R. Rodriguezc6528e22011-03-14 10:58:57 -070062static void DevGMboxIRQActionAsyncHandler(void *Context, struct htc_packet *pPacket)
Vipin Mehta30295c82010-09-01 12:06:33 -070063{
Luis R. Rodriguez495abc72011-03-10 18:55:36 -080064 struct ar6k_device *pDev = (struct ar6k_device *)Context;
Vipin Mehta30295c82010-09-01 12:06:33 -070065
66 AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevGMboxIRQActionAsyncHandler: (dev: 0x%lX)\n", (unsigned long)pDev));
67
Joe Perches391bb212011-01-27 20:04:21 -080068 if (pPacket->Status) {
Vipin Mehta30295c82010-09-01 12:06:33 -070069 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
Luis R. Rodriguez495abc72011-03-10 18:55:36 -080077static int DevGMboxCounterEnableDisable(struct ar6k_device *pDev, GMBOX_IRQ_ACTION_TYPE IrqAction, bool AsyncMode)
Vipin Mehta30295c82010-09-01 12:06:33 -070078{
Joe Perches4f69cef2011-02-02 14:05:57 -080079 int status = 0;
Luis R. Rodriguezdfaa26b2011-03-10 18:55:40 -080080 struct ar6k_irq_enable_registers regs;
Luis R. Rodriguezc6528e22011-03-14 10:58:57 -070081 struct htc_packet *pIOPacket = NULL;
Vipin Mehta30295c82010-09-01 12:06:33 -070082
83 LOCK_AR6K(pDev);
84
85 if (GMBOX_CREDIT_IRQ_ENABLE == IrqAction) {
Joe Perches1071a132011-02-02 14:05:47 -080086 pDev->GMboxInfo.CreditCountIRQEnabled = true;
Vipin Mehta30295c82010-09-01 12:06:33 -070087 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 {
Joe Perches1071a132011-02-02 14:05:47 -080091 pDev->GMboxInfo.CreditCountIRQEnabled = false;
Vipin Mehta30295c82010-09-01 12:06:33 -070092 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 */
Luis R. Rodriguez05209262011-03-10 18:55:29 -080096 memcpy(&regs,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE);
Vipin Mehta30295c82010-09-01 12:06:33 -070097
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;
Joe Perches1071a132011-02-02 14:05:47 -0800108 A_ASSERT(false);
Vipin Mehta30295c82010-09-01 12:06:33 -0700109 break;
110 }
111
112 /* copy values to write to our async I/O buffer */
Luis R. Rodriguez05209262011-03-10 18:55:29 -0800113 memcpy(pIOPacket->pBuffer,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE);
Vipin Mehta30295c82010-09-01 12:06:33 -0700114
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);
Joe Perches1071a132011-02-02 14:05:47 -0800138 } while (false);
Vipin Mehta30295c82010-09-01 12:06:33 -0700139
Joe Perches391bb212011-01-27 20:04:21 -0800140 if (status) {
Vipin Mehta30295c82010-09-01 12:06:33 -0700141 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
Luis R. Rodriguez495abc72011-03-10 18:55:36 -0800158int DevGMboxIRQAction(struct ar6k_device *pDev, GMBOX_IRQ_ACTION_TYPE IrqAction, bool AsyncMode)
Vipin Mehta30295c82010-09-01 12:06:33 -0700159{
Joe Perches4f69cef2011-02-02 14:05:57 -0800160 int status = 0;
Luis R. Rodriguezc6528e22011-03-14 10:58:57 -0700161 struct htc_packet *pIOPacket = NULL;
Joe Perchesab3655d2011-02-02 14:05:49 -0800162 u8 GMboxIntControl[4];
Vipin Mehta30295c82010-09-01 12:06:33 -0700163
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:
Joe Perches1071a132011-02-02 14:05:47 -0800195 A_ASSERT(false);
Vipin Mehta30295c82010-09-01 12:06:33 -0700196 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;
Joe Perches1071a132011-02-02 14:05:47 -0800214 A_ASSERT(false);
Vipin Mehta30295c82010-09-01 12:06:33 -0700215 break;
216 }
217
218 /* copy values to write to our async I/O buffer */
Luis R. Rodriguez05209262011-03-10 18:55:29 -0800219 memcpy(pIOPacket->pBuffer,GMboxIntControl,sizeof(GMboxIntControl));
Vipin Mehta30295c82010-09-01 12:06:33 -0700220
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
Joe Perches1071a132011-02-02 14:05:47 -0800245 } while (false);
Vipin Mehta30295c82010-09-01 12:06:33 -0700246
Joe Perches391bb212011-01-27 20:04:21 -0800247 if (status) {
Vipin Mehta30295c82010-09-01 12:06:33 -0700248 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
Luis R. Rodriguez495abc72011-03-10 18:55:36 -0800264void DevCleanupGMbox(struct ar6k_device *pDev)
Vipin Mehta30295c82010-09-01 12:06:33 -0700265{
266 if (pDev->GMboxEnabled) {
Joe Perches1071a132011-02-02 14:05:47 -0800267 pDev->GMboxEnabled = false;
Vipin Mehta30295c82010-09-01 12:06:33 -0700268 GMboxProtocolUninstall(pDev);
269 }
270}
271
Luis R. Rodriguez495abc72011-03-10 18:55:36 -0800272int DevSetupGMbox(struct ar6k_device *pDev)
Vipin Mehta30295c82010-09-01 12:06:33 -0700273{
Joe Perches4f69cef2011-02-02 14:05:57 -0800274 int status = 0;
Joe Perchesab3655d2011-02-02 14:05:49 -0800275 u8 muxControl[4];
Vipin Mehta30295c82010-09-01 12:06:33 -0700276
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
Joe Perches391bb212011-01-27 20:04:21 -0800288 if (status) {
Vipin Mehta30295c82010-09-01 12:06:33 -0700289 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
Joe Perches391bb212011-01-27 20:04:21 -0800308 if (status) {
Vipin Mehta30295c82010-09-01 12:06:33 -0700309 break;
310 }
311
312 status = GMboxProtocolInstall(pDev);
313
Joe Perches391bb212011-01-27 20:04:21 -0800314 if (status) {
Vipin Mehta30295c82010-09-01 12:06:33 -0700315 break;
316 }
317
Joe Perches1071a132011-02-02 14:05:47 -0800318 pDev->GMboxEnabled = true;
Vipin Mehta30295c82010-09-01 12:06:33 -0700319
Joe Perches1071a132011-02-02 14:05:47 -0800320 } while (false);
Vipin Mehta30295c82010-09-01 12:06:33 -0700321
322 return status;
323}
324
Luis R. Rodriguez495abc72011-03-10 18:55:36 -0800325int DevCheckGMboxInterrupts(struct ar6k_device *pDev)
Vipin Mehta30295c82010-09-01 12:06:33 -0700326{
Joe Perches4f69cef2011-02-02 14:05:57 -0800327 int status = 0;
Joe Perchesab3655d2011-02-02 14:05:49 -0800328 u8 counter_int_status;
Vipin Mehta30295c82010-09-01 12:06:33 -0700329 int credits;
Joe Perchesab3655d2011-02-02 14:05:49 -0800330 u8 host_int_status2;
Vipin Mehta30295c82010-09-01 12:06:33 -0700331
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
Joe Perches391bb212011-01-27 20:04:21 -0800351 if (status) {
Vipin Mehta30295c82010-09-01 12:06:33 -0700352 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,
Joe Perchesab3655d2011-02-02 14:05:49 -0800363 (u8 *)&pDev->IrqProcRegisters.rx_gmbox_lookahead_alias[0],
Vipin Mehta30295c82010-09-01 12:06:33 -0700364 pDev->IrqProcRegisters.gmbox_rx_avail);
365 }
366 }
367
Joe Perches391bb212011-01-27 20:04:21 -0800368 if (status) {
Vipin Mehta30295c82010-09-01 12:06:33 -0700369 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
Joe Perches391bb212011-01-27 20:04:21 -0800381 if (status) {
Vipin Mehta30295c82010-09-01 12:06:33 -0700382 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
Joe Perches1071a132011-02-02 14:05:47 -0800391 } while (false);
Vipin Mehta30295c82010-09-01 12:06:33 -0700392
393 AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("-DevCheckGMboxInterrupts (%d) \n",status));
394
395 return status;
396}
397
398
Luis R. Rodriguezc6528e22011-03-14 10:58:57 -0700399int DevGMboxWrite(struct ar6k_device *pDev, struct htc_packet *pPacket, u32 WriteLength)
Vipin Mehta30295c82010-09-01 12:06:33 -0700400{
Joe Perchese1ce2a32011-02-02 14:05:51 -0800401 u32 paddedLength;
Joe Perches1071a132011-02-02 14:05:47 -0800402 bool sync = (pPacket->Completion == NULL) ? true : false;
Joe Perches1f4c34b2011-01-27 20:04:19 -0800403 int status;
Joe Perchese1ce2a32011-02-02 14:05:51 -0800404 u32 address;
Vipin Mehta30295c82010-09-01 12:06:33 -0700405
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) {
Joe Perches4f69cef2011-02-02 14:05:57 -0800429 status = 0;
Vipin Mehta30295c82010-09-01 12:06:33 -0700430 }
431 }
432
433 return status;
434}
435
Luis R. Rodriguezc6528e22011-03-14 10:58:57 -0700436int DevGMboxRead(struct ar6k_device *pDev, struct htc_packet *pPacket, u32 ReadLength)
Vipin Mehta30295c82010-09-01 12:06:33 -0700437{
438
Joe Perchese1ce2a32011-02-02 14:05:51 -0800439 u32 paddedLength;
Joe Perches1f4c34b2011-01-27 20:04:19 -0800440 int status;
Joe Perches1071a132011-02-02 14:05:47 -0800441 bool sync = (pPacket->Completion == NULL) ? true : false;
Vipin Mehta30295c82010-09-01 12:06:33 -0700442
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) {
Joe Perches1071a132011-02-02 14:05:47 -0800447 A_ASSERT(false);
Vipin Mehta30295c82010-09-01 12:06:33 -0700448 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);
Joe Perches4f69cef2011-02-02 14:05:57 -0800453 return 0;
Vipin Mehta30295c82010-09-01 12:06:33 -0700454 }
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
Joe Perchesab3655d2011-02-02 14:05:49 -0800480static int ProcessCreditCounterReadBuffer(u8 *pBuffer, int Length)
Vipin Mehta30295c82010-09-01 12:06:33 -0700481{
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 */
Luis R. Rodriguezc6528e22011-03-14 10:58:57 -0700519static void DevGMboxReadCreditsAsyncHandler(void *Context, struct htc_packet *pPacket)
Vipin Mehta30295c82010-09-01 12:06:33 -0700520{
Luis R. Rodriguez495abc72011-03-10 18:55:36 -0800521 struct ar6k_device *pDev = (struct ar6k_device *)Context;
Vipin Mehta30295c82010-09-01 12:06:33 -0700522
523 AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevGMboxReadCreditsAsyncHandler: (dev: 0x%lX)\n", (unsigned long)pDev));
524
Joe Perches391bb212011-01-27 20:04:21 -0800525 if (pPacket->Status) {
Vipin Mehta30295c82010-09-01 12:06:33 -0700526 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
Luis R. Rodriguez495abc72011-03-10 18:55:36 -0800542int DevGMboxReadCreditCounter(struct ar6k_device *pDev, bool AsyncMode, int *pCredits)
Vipin Mehta30295c82010-09-01 12:06:33 -0700543{
Joe Perches4f69cef2011-02-02 14:05:57 -0800544 int status = 0;
Luis R. Rodriguezc6528e22011-03-14 10:58:57 -0700545 struct htc_packet *pIOPacket = NULL;
Vipin Mehta30295c82010-09-01 12:06:33 -0700546
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;
Joe Perches1071a132011-02-02 14:05:47 -0800555 A_ASSERT(false);
Vipin Mehta30295c82010-09-01 12:06:33 -0700556 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);
Joe Perches1071a132011-02-02 14:05:47 -0800584 } while (false);
Vipin Mehta30295c82010-09-01 12:06:33 -0700585
Joe Perches391bb212011-01-27 20:04:21 -0800586 if (status) {
Vipin Mehta30295c82010-09-01 12:06:33 -0700587 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
588 (" DevGMboxReadCreditCounter failed! status:%d \n", status));
589 }
590
591 if (pIOPacket != NULL) {
Joe Perches509c9d92011-01-27 20:04:20 -0800592 if (!status) {
Vipin Mehta30295c82010-09-01 12:06:33 -0700593 /* 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
Luis R. Rodriguez495abc72011-03-10 18:55:36 -0800605int DevGMboxReadCreditSize(struct ar6k_device *pDev, int *pCreditSize)
Vipin Mehta30295c82010-09-01 12:06:33 -0700606{
Joe Perches1f4c34b2011-01-27 20:04:19 -0800607 int status;
Joe Perchesab3655d2011-02-02 14:05:49 -0800608 u8 buffer[4];
Vipin Mehta30295c82010-09-01 12:06:33 -0700609
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
Joe Perches509c9d92011-01-27 20:04:20 -0800617 if (!status) {
Vipin Mehta30295c82010-09-01 12:06:33 -0700618 if (buffer[0] == 0) {
619 *pCreditSize = 256;
620 } else {
621 *pCreditSize = buffer[0];
622 }
623
624 }
625
626 return status;
627}
628
Luis R. Rodriguez495abc72011-03-10 18:55:36 -0800629void DevNotifyGMboxTargetFailure(struct ar6k_device *pDev)
Vipin Mehta30295c82010-09-01 12:06:33 -0700630{
631 /* Target ASSERTED!!! */
632 if (pDev->GMboxInfo.pTargetFailureCallback != NULL) {
633 pDev->GMboxInfo.pTargetFailureCallback(pDev->GMboxInfo.pProtocolContext, A_HARDWARE);
634 }
635}
636
Luis R. Rodriguez495abc72011-03-10 18:55:36 -0800637int DevGMboxRecvLookAheadPeek(struct ar6k_device *pDev, u8 *pLookAheadBuffer, int *pLookAheadBytes)
Vipin Mehta30295c82010-09-01 12:06:33 -0700638{
639
Joe Perches4f69cef2011-02-02 14:05:57 -0800640 int status = 0;
Luis R. Rodrigueze6998a52011-03-10 18:55:41 -0800641 struct ar6k_irq_proc_registers procRegs;
Vipin Mehta30295c82010-09-01 12:06:33 -0700642 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)) {
Joe Perches1071a132011-02-02 14:05:47 -0800647 A_ASSERT(false);
Vipin Mehta30295c82010-09-01 12:06:33 -0700648 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,
Joe Perchesab3655d2011-02-02 14:05:49 -0800657 (u8 *)&procRegs,
Vipin Mehta30295c82010-09-01 12:06:33 -0700658 AR6K_IRQ_PROC_REGS_SIZE,
659 HIF_RD_SYNC_BYTE_INC,
660 NULL);
661
Joe Perches391bb212011-01-27 20:04:21 -0800662 if (status) {
Vipin Mehta30295c82010-09-01 12:06:33 -0700663 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;
Luis R. Rodriguez05209262011-03-10 18:55:29 -0800670 memcpy(pLookAheadBuffer,&procRegs.rx_gmbox_lookahead_alias[0],bytes);
Vipin Mehta30295c82010-09-01 12:06:33 -0700671 *pLookAheadBytes = bytes;
672 }
673
Joe Perches1071a132011-02-02 14:05:47 -0800674 } while (false);
Vipin Mehta30295c82010-09-01 12:06:33 -0700675
676 return status;
677}
678
Luis R. Rodriguez495abc72011-03-10 18:55:36 -0800679int DevGMboxSetTargetInterrupt(struct ar6k_device *pDev, int Signal, int AckTimeoutMS)
Vipin Mehta30295c82010-09-01 12:06:33 -0700680{
Joe Perches4f69cef2011-02-02 14:05:57 -0800681 int status = 0;
Vipin Mehta30295c82010-09-01 12:06:33 -0700682 int i;
Joe Perchesab3655d2011-02-02 14:05:49 -0800683 u8 buffer[4];
Vipin Mehta30295c82010-09-01 12:06:33 -0700684
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
Joe Perches391bb212011-01-27 20:04:21 -0800704 if (status) {
Vipin Mehta30295c82010-09-01 12:06:33 -0700705 break;
706 }
707
Joe Perches1071a132011-02-02 14:05:47 -0800708 } while (false);
Vipin Mehta30295c82010-09-01 12:06:33 -0700709
710
Joe Perches509c9d92011-01-27 20:04:20 -0800711 if (!status) {
Vipin Mehta30295c82010-09-01 12:06:33 -0700712 /* 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
Joe Perches391bb212011-01-27 20:04:21 -0800721 if (status) {
Vipin Mehta30295c82010-09-01 12:06:33 -0700722 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