2 * AR6K device layer that handles register level I/O
4 * Copyright (c) 2007 Atheros Communications Inc.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation;
12 * Software distributed under the License is distributed on an "AS
13 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * rights and limitations under the License.
23 #include "AR6Khwreg.h"
27 #include "htc_packet.h"
30 #define MAILBOX_FOR_BLOCK_SIZE 1
32 extern A_UINT32 resetok
;
34 static A_STATUS
DevEnableInterrupts(AR6K_DEVICE
*pDev
);
35 static A_STATUS
DevDisableInterrupts(AR6K_DEVICE
*pDev
);
37 #define LOCK_AR6K(p) A_MUTEX_LOCK(&(p)->Lock);
38 #define UNLOCK_AR6K(p) A_MUTEX_UNLOCK(&(p)->Lock);
40 void AR6KFreeIOPacket(AR6K_DEVICE
*pDev
, HTC_PACKET
*pPacket
)
43 HTC_PACKET_ENQUEUE(&pDev
->RegisterIOList
,pPacket
);
47 HTC_PACKET
*AR6KAllocIOPacket(AR6K_DEVICE
*pDev
)
52 pPacket
= HTC_PACKET_DEQUEUE(&pDev
->RegisterIOList
);
58 A_STATUS
DevSetup(AR6K_DEVICE
*pDev
)
60 A_UINT32 mailboxaddrs
[AR6K_MAILBOXES
];
61 A_UINT32 blocksizes
[AR6K_MAILBOXES
];
62 A_STATUS status
= A_OK
;
65 AR_DEBUG_ASSERT(AR6K_IRQ_PROC_REGS_SIZE
== 16);
66 AR_DEBUG_ASSERT(AR6K_IRQ_ENABLE_REGS_SIZE
== 4);
69 /* give a handle to HIF for this target */
70 HIFSetHandle(pDev
->HIFDevice
, (void *)pDev
);
71 /* initialize our free list of IO packets */
72 INIT_HTC_PACKET_QUEUE(&pDev
->RegisterIOList
);
73 A_MUTEX_INIT(&pDev
->Lock
);
75 /* get the addresses for all 4 mailboxes */
76 status
= HIFConfigureDevice(pDev
->HIFDevice
, HIF_DEVICE_GET_MBOX_ADDR
,
77 mailboxaddrs
, sizeof(mailboxaddrs
));
80 AR_DEBUG_ASSERT(FALSE
);
84 /* carve up register I/O packets (these are for ASYNC register I/O ) */
85 for (i
= 0; i
< AR6K_MAX_REG_IO_BUFFERS
; i
++) {
86 HTC_PACKET
*pIOPacket
;
87 pIOPacket
= &pDev
->RegIOBuffers
[i
].HtcPacket
;
88 SET_HTC_PACKET_INFO_RX_REFILL(pIOPacket
,
90 pDev
->RegIOBuffers
[i
].Buffer
,
91 AR6K_REG_IO_BUFFER_SIZE
,
93 AR6KFreeIOPacket(pDev
,pIOPacket
);
96 /* get the address of the mailbox we are using */
97 pDev
->MailboxAddress
= mailboxaddrs
[HTC_MAILBOX
];
99 /* get the block sizes */
100 status
= HIFConfigureDevice(pDev
->HIFDevice
, HIF_DEVICE_GET_MBOX_BLOCK_SIZE
,
101 blocksizes
, sizeof(blocksizes
));
103 if (status
!= A_OK
) {
104 AR_DEBUG_ASSERT(FALSE
);
108 /* note: we actually get the block size of a mailbox other than 0, for SDIO the block
109 * size on mailbox 0 is artificially set to 1. So we use the block size that is set
110 * for the other 3 mailboxes */
111 pDev
->BlockSize
= blocksizes
[MAILBOX_FOR_BLOCK_SIZE
];
112 /* must be a power of 2 */
113 AR_DEBUG_ASSERT((pDev
->BlockSize
& (pDev
->BlockSize
- 1)) == 0);
115 /* assemble mask, used for padding to a block */
116 pDev
->BlockMask
= pDev
->BlockSize
- 1;
118 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
,("BlockSize: %d, MailboxAddress:0x%X \n",
119 pDev
->BlockSize
, pDev
->MailboxAddress
));
121 pDev
->GetPendingEventsFunc
= NULL
;
122 /* see if the HIF layer implements the get pending events function */
123 HIFConfigureDevice(pDev
->HIFDevice
,
124 HIF_DEVICE_GET_PENDING_EVENTS_FUNC
,
125 &pDev
->GetPendingEventsFunc
,
126 sizeof(pDev
->GetPendingEventsFunc
));
128 /* assume we can process HIF interrupt events asynchronously */
129 pDev
->HifIRQProcessingMode
= HIF_DEVICE_IRQ_ASYNC_SYNC
;
131 /* see if the HIF layer overrides this assumption */
132 HIFConfigureDevice(pDev
->HIFDevice
,
133 HIF_DEVICE_GET_IRQ_PROC_MODE
,
134 &pDev
->HifIRQProcessingMode
,
135 sizeof(pDev
->HifIRQProcessingMode
));
137 switch (pDev
->HifIRQProcessingMode
) {
138 case HIF_DEVICE_IRQ_SYNC_ONLY
:
139 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
,("HIF Interrupt processing is SYNC ONLY\n"));
141 case HIF_DEVICE_IRQ_ASYNC_SYNC
:
142 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
,("HIF Interrupt processing is ASYNC and SYNC\n"));
145 AR_DEBUG_ASSERT(FALSE
);
148 pDev
->HifMaskUmaskRecvEvent
= NULL
;
150 /* see if the HIF layer implements the mask/unmask recv events function */
151 HIFConfigureDevice(pDev
->HIFDevice
,
152 HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC
,
153 &pDev
->HifMaskUmaskRecvEvent
,
154 sizeof(pDev
->HifMaskUmaskRecvEvent
));
156 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
,("HIF special overrides : 0x%X , 0x%X\n",
157 (A_UINT32
)pDev
->GetPendingEventsFunc
, (A_UINT32
)pDev
->HifMaskUmaskRecvEvent
));
159 status
= DevDisableInterrupts(pDev
);
163 if (A_FAILED(status
)) {
164 /* make sure handle is cleared */
165 HIFSetHandle(pDev
->HIFDevice
, NULL
);
172 static A_STATUS
DevEnableInterrupts(AR6K_DEVICE
*pDev
)
175 AR6K_IRQ_ENABLE_REGISTERS regs
;
179 /* Enable all the interrupts except for the dragon interrupt */
180 pDev
->IrqEnableRegisters
.int_status_enable
= INT_STATUS_ENABLE_ERROR_SET(0x01) |
181 INT_STATUS_ENABLE_CPU_SET(0x01) |
182 INT_STATUS_ENABLE_COUNTER_SET(0x01);
184 if (NULL
== pDev
->GetPendingEventsFunc
) {
185 pDev
->IrqEnableRegisters
.int_status_enable
|= INT_STATUS_ENABLE_MBOX_DATA_SET(0x01);
187 /* The HIF layer provided us with a pending events function which means that
188 * the detection of pending mbox messages is handled in the HIF layer.
189 * This is the case for the SPI2 interface.
190 * In the normal case we enable MBOX interrupts, for the case
191 * with HIFs that offer this mechanism, we keep these interrupts
193 pDev
->IrqEnableRegisters
.int_status_enable
&= ~INT_STATUS_ENABLE_MBOX_DATA_SET(0x01);
197 /* Set up the CPU Interrupt Status Register */
198 pDev
->IrqEnableRegisters
.cpu_int_status_enable
= CPU_INT_STATUS_ENABLE_BIT_SET(0x00);
200 /* Set up the Error Interrupt Status Register */
201 pDev
->IrqEnableRegisters
.error_status_enable
=
202 ERROR_STATUS_ENABLE_RX_UNDERFLOW_SET(0x01) |
203 ERROR_STATUS_ENABLE_TX_OVERFLOW_SET(0x01);
205 /* Set up the Counter Interrupt Status Register (only for debug interrupt to catch fatal errors) */
206 pDev
->IrqEnableRegisters
.counter_int_status_enable
=
207 COUNTER_INT_STATUS_ENABLE_BIT_SET(AR6K_TARGET_DEBUG_INTR_MASK
);
209 /* copy into our temp area */
210 A_MEMCPY(®s
,&pDev
->IrqEnableRegisters
,AR6K_IRQ_ENABLE_REGS_SIZE
);
214 /* always synchronous */
215 status
= HIFReadWrite(pDev
->HIFDevice
,
216 INT_STATUS_ENABLE_ADDRESS
,
217 ®s
.int_status_enable
,
218 AR6K_IRQ_ENABLE_REGS_SIZE
,
219 HIF_WR_SYNC_BYTE_INC
,
222 if (status
!= A_OK
) {
223 /* Can't write it for some reason */
224 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
225 ("Failed to update interrupt control registers err: %d\n", status
));
232 static A_STATUS
DevDisableInterrupts(AR6K_DEVICE
*pDev
)
234 AR6K_IRQ_ENABLE_REGISTERS regs
;
237 /* Disable all interrupts */
238 pDev
->IrqEnableRegisters
.int_status_enable
= 0;
239 pDev
->IrqEnableRegisters
.cpu_int_status_enable
= 0;
240 pDev
->IrqEnableRegisters
.error_status_enable
= 0;
241 pDev
->IrqEnableRegisters
.counter_int_status_enable
= 0;
242 /* copy into our temp area */
243 A_MEMCPY(®s
,&pDev
->IrqEnableRegisters
,AR6K_IRQ_ENABLE_REGS_SIZE
);
247 /* always synchronous */
248 return HIFReadWrite(pDev
->HIFDevice
,
249 INT_STATUS_ENABLE_ADDRESS
,
250 ®s
.int_status_enable
,
251 AR6K_IRQ_ENABLE_REGS_SIZE
,
252 HIF_WR_SYNC_BYTE_INC
,
256 /* enable device interrupts */
257 A_STATUS
DevUnmaskInterrupts(AR6K_DEVICE
*pDev
)
259 /* Unmask the host controller interrupts */
260 HIFUnMaskInterrupt(pDev
->HIFDevice
);
262 return DevEnableInterrupts(pDev
);
265 /* disable all device interrupts */
266 A_STATUS
DevMaskInterrupts(AR6K_DEVICE
*pDev
)
270 status
= DevDisableInterrupts(pDev
);
272 if (A_SUCCESS(status
)) {
273 /* Disable the interrupt at the HIF layer */
274 HIFMaskInterrupt(pDev
->HIFDevice
);
280 /* callback when our fetch to enable/disable completes */
281 static void DevDoEnableDisableRecvAsyncHandler(void *Context
, HTC_PACKET
*pPacket
)
283 AR6K_DEVICE
*pDev
= (AR6K_DEVICE
*)Context
;
285 AR_DEBUG_PRINTF(ATH_DEBUG_IRQ
,("+DevDoEnableDisableRecvAsyncHandler: (dev: 0x%X)\n", (A_UINT32
)pDev
));
287 if (A_FAILED(pPacket
->Status
)) {
288 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
289 (" Failed to disable receiver, status:%d \n", pPacket
->Status
));
291 /* free this IO packet */
292 AR6KFreeIOPacket(pDev
,pPacket
);
293 AR_DEBUG_PRINTF(ATH_DEBUG_IRQ
,("-DevDoEnableDisableRecvAsyncHandler \n"));
296 /* disable packet reception (used in case the host runs out of buffers)
297 * this is the "override" method when the HIF reports another methods to
298 * disable recv events */
299 static A_STATUS
DevDoEnableDisableRecvOverride(AR6K_DEVICE
*pDev
, A_BOOL EnableRecv
, A_BOOL AsyncMode
)
301 A_STATUS status
= A_OK
;
302 HTC_PACKET
*pIOPacket
= NULL
;
304 AR_DEBUG_PRINTF(ATH_DEBUG_TRC
,("DevDoEnableDisableRecvOverride: Enable:%d Mode:%d\n",
305 EnableRecv
,AsyncMode
));
311 pIOPacket
= AR6KAllocIOPacket(pDev
);
313 if (NULL
== pIOPacket
) {
314 status
= A_NO_MEMORY
;
315 AR_DEBUG_ASSERT(FALSE
);
319 /* stick in our completion routine when the I/O operation completes */
320 pIOPacket
->Completion
= DevDoEnableDisableRecvAsyncHandler
;
321 pIOPacket
->pContext
= pDev
;
323 /* call the HIF layer override and do this asynchronously */
324 status
= pDev
->HifMaskUmaskRecvEvent(pDev
->HIFDevice
,
325 EnableRecv
? HIF_UNMASK_RECV
: HIF_MASK_RECV
,
330 /* if we get here we are doing it synchronously */
331 status
= pDev
->HifMaskUmaskRecvEvent(pDev
->HIFDevice
,
332 EnableRecv
? HIF_UNMASK_RECV
: HIF_MASK_RECV
,
337 if (A_FAILED(status
) && (pIOPacket
!= NULL
)) {
338 AR6KFreeIOPacket(pDev
,pIOPacket
);
344 /* disable packet reception (used in case the host runs out of buffers)
345 * this is the "normal" method using the interrupt enable registers through
347 static A_STATUS
DevDoEnableDisableRecvNormal(AR6K_DEVICE
*pDev
, A_BOOL EnableRecv
, A_BOOL AsyncMode
)
349 A_STATUS status
= A_OK
;
350 HTC_PACKET
*pIOPacket
= NULL
;
351 AR6K_IRQ_ENABLE_REGISTERS regs
;
353 /* take the lock to protect interrupt enable shadows */
357 pDev
->IrqEnableRegisters
.int_status_enable
|= INT_STATUS_ENABLE_MBOX_DATA_SET(0x01);
359 pDev
->IrqEnableRegisters
.int_status_enable
&= ~INT_STATUS_ENABLE_MBOX_DATA_SET(0x01);
362 /* copy into our temp area */
363 A_MEMCPY(®s
,&pDev
->IrqEnableRegisters
,AR6K_IRQ_ENABLE_REGS_SIZE
);
370 pIOPacket
= AR6KAllocIOPacket(pDev
);
372 if (NULL
== pIOPacket
) {
373 status
= A_NO_MEMORY
;
374 AR_DEBUG_ASSERT(FALSE
);
378 /* copy values to write to our async I/O buffer */
379 A_MEMCPY(pIOPacket
->pBuffer
,®s
,AR6K_IRQ_ENABLE_REGS_SIZE
);
381 /* stick in our completion routine when the I/O operation completes */
382 pIOPacket
->Completion
= DevDoEnableDisableRecvAsyncHandler
;
383 pIOPacket
->pContext
= pDev
;
385 /* write it out asynchronously */
386 HIFReadWrite(pDev
->HIFDevice
,
387 INT_STATUS_ENABLE_ADDRESS
,
389 AR6K_IRQ_ENABLE_REGS_SIZE
,
390 HIF_WR_ASYNC_BYTE_INC
,
395 /* if we get here we are doing it synchronously */
397 status
= HIFReadWrite(pDev
->HIFDevice
,
398 INT_STATUS_ENABLE_ADDRESS
,
399 ®s
.int_status_enable
,
400 AR6K_IRQ_ENABLE_REGS_SIZE
,
401 HIF_WR_SYNC_BYTE_INC
,
406 if (A_FAILED(status
) && (pIOPacket
!= NULL
)) {
407 AR6KFreeIOPacket(pDev
,pIOPacket
);
414 A_STATUS
DevStopRecv(AR6K_DEVICE
*pDev
, A_BOOL AsyncMode
)
416 if (NULL
== pDev
->HifMaskUmaskRecvEvent
) {
417 return DevDoEnableDisableRecvNormal(pDev
,FALSE
,AsyncMode
);
419 return DevDoEnableDisableRecvOverride(pDev
,FALSE
,AsyncMode
);
423 A_STATUS
DevEnableRecv(AR6K_DEVICE
*pDev
, A_BOOL AsyncMode
)
425 if (NULL
== pDev
->HifMaskUmaskRecvEvent
) {
426 return DevDoEnableDisableRecvNormal(pDev
,TRUE
,AsyncMode
);
428 return DevDoEnableDisableRecvOverride(pDev
,TRUE
,AsyncMode
);
432 void DevDumpRegisters(AR6K_IRQ_PROC_REGISTERS
*pIrqProcRegs
,
433 AR6K_IRQ_ENABLE_REGISTERS
*pIrqEnableRegs
)
436 AR_DEBUG_PRINTF(ATH_DEBUG_DUMP
, ("\n<------- Register Table -------->\n"));
438 if (pIrqProcRegs
!= NULL
) {
439 AR_DEBUG_PRINTF(ATH_DEBUG_DUMP
,
440 ("Int Status: 0x%x\n",pIrqProcRegs
->host_int_status
));
441 AR_DEBUG_PRINTF(ATH_DEBUG_DUMP
,
442 ("CPU Int Status: 0x%x\n",pIrqProcRegs
->cpu_int_status
));
443 AR_DEBUG_PRINTF(ATH_DEBUG_DUMP
,
444 ("Error Int Status: 0x%x\n",pIrqProcRegs
->error_int_status
));
445 AR_DEBUG_PRINTF(ATH_DEBUG_DUMP
,
446 ("Counter Int Status: 0x%x\n",pIrqProcRegs
->counter_int_status
));
447 AR_DEBUG_PRINTF(ATH_DEBUG_DUMP
,
448 ("Mbox Frame: 0x%x\n",pIrqProcRegs
->mbox_frame
));
449 AR_DEBUG_PRINTF(ATH_DEBUG_DUMP
,
450 ("Rx Lookahead Valid: 0x%x\n",pIrqProcRegs
->rx_lookahead_valid
));
451 AR_DEBUG_PRINTF(ATH_DEBUG_DUMP
,
452 ("Rx Lookahead 0: 0x%x\n",pIrqProcRegs
->rx_lookahead
[0]));
453 AR_DEBUG_PRINTF(ATH_DEBUG_DUMP
,
454 ("Rx Lookahead 1: 0x%x\n",pIrqProcRegs
->rx_lookahead
[1]));
457 if (pIrqEnableRegs
!= NULL
) {
458 AR_DEBUG_PRINTF(ATH_DEBUG_DUMP
,
459 ("Int Status Enable: 0x%x\n",pIrqEnableRegs
->int_status_enable
));
460 AR_DEBUG_PRINTF(ATH_DEBUG_DUMP
,
461 ("Counter Int Status Enable: 0x%x\n",pIrqEnableRegs
->counter_int_status_enable
));
462 AR_DEBUG_PRINTF(ATH_DEBUG_DUMP
, ("<------------------------------->\n"));
467 #ifdef MBOXHW_UNIT_TEST
470 /* This is a mailbox hardware unit test that must be called in a schedulable context
471 * This test is very simple, it will send a list of buffers with a counting pattern
472 * and the target will invert the data and send the message back
474 * the unit test has the following constraints:
476 * The target has at least 8 buffers of 256 bytes each. The host will send
477 * the following pattern of buffers in rapid succession :
479 * 1 buffer - 128 bytes
480 * 1 buffer - 256 bytes
481 * 1 buffer - 512 bytes
482 * 1 buffer - 1024 bytes
484 * The host will send the buffers to one mailbox and wait for buffers to be reflected
485 * back from the same mailbox. The target sends the buffers FIFO order.
486 * Once the final buffer has been received for a mailbox, the next mailbox is tested.
489 * Note: To simplifythe test , we assume that the chosen buffer sizes
490 * will fall on a nice block pad
492 * It is expected that higher-order tests will be written to stress the mailboxes using
493 * a message-based protocol (with some performance timming) that can create more
494 * randomness in the packets sent over mailboxes.
498 #define A_ROUND_UP_PWR2(x, align) (((int) (x) + ((align)-1)) & ~((align)-1))
500 #define BUFFER_BLOCK_PAD 128
516 #define TOTAL_BYTES (A_ROUND_UP_PWR2(BUFFER1,BUFFER_BLOCK_PAD) + \
517 A_ROUND_UP_PWR2(BUFFER2,BUFFER_BLOCK_PAD) + \
518 A_ROUND_UP_PWR2(BUFFER3,BUFFER_BLOCK_PAD) + \
519 A_ROUND_UP_PWR2(BUFFER4,BUFFER_BLOCK_PAD) )
521 #define TEST_BYTES (BUFFER1 + BUFFER2 + BUFFER3 + BUFFER4)
523 #define TEST_CREDITS_RECV_TIMEOUT 100
525 static A_UINT8 g_Buffer
[TOTAL_BYTES
];
526 static A_UINT32 g_MailboxAddrs
[AR6K_MAILBOXES
];
527 static A_UINT32 g_BlockSizes
[AR6K_MAILBOXES
];
529 #define BUFFER_PROC_LIST_DEPTH 4
531 typedef struct _BUFFER_PROC_LIST
{
537 #define PUSH_BUFF_PROC_ENTRY(pList,len,pCurrpos) \
539 (pList)->pBuffer = (pCurrpos); \
540 (pList)->length = (len); \
541 (pCurrpos) += (len); \
545 /* a simple and crude way to send different "message" sizes */
546 static void AssembleBufferList(BUFFER_PROC_LIST
*pList
)
548 A_UINT8
*pBuffer
= g_Buffer
;
550 #if BUFFER_PROC_LIST_DEPTH < 4
551 #error "Buffer processing list depth is not deep enough!!"
554 PUSH_BUFF_PROC_ENTRY(pList
,BUFFER1
,pBuffer
);
555 PUSH_BUFF_PROC_ENTRY(pList
,BUFFER2
,pBuffer
);
556 PUSH_BUFF_PROC_ENTRY(pList
,BUFFER3
,pBuffer
);
557 PUSH_BUFF_PROC_ENTRY(pList
,BUFFER4
,pBuffer
);
561 #define FILL_ZERO TRUE
562 #define FILL_COUNTING FALSE
563 static void InitBuffers(A_BOOL Zero
)
565 A_UINT16
*pBuffer16
= (A_UINT16
*)g_Buffer
;
568 /* fill buffer with 16 bit counting pattern or zeros */
569 for (i
= 0; i
< (TOTAL_BYTES
/ 2) ; i
++) {
571 pBuffer16
[i
] = (A_UINT16
)i
;
579 static A_BOOL
CheckOneBuffer(A_UINT16
*pBuffer16
, int Length
)
583 A_BOOL success
= TRUE
;
585 /* get the starting count */
586 startCount
= pBuffer16
[0];
587 /* invert it, this is the expected value */
588 startCount
= ~startCount
;
589 /* scan the buffer and verify */
590 for (i
= 0; i
< (Length
/ 2) ; i
++,startCount
++) {
591 /* target will invert all the data */
592 if ((A_UINT16
)pBuffer16
[i
] != (A_UINT16
)~startCount
) {
594 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, ("Invalid Data Got:0x%X, Expecting:0x%X (offset:%d, total:%d) \n",
595 pBuffer16
[i
], ((A_UINT16
)~startCount
), i
, Length
));
596 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, ("0x%X 0x%X 0x%X 0x%X \n",
597 pBuffer16
[i
], pBuffer16
[i
+ 1], pBuffer16
[i
+ 2],pBuffer16
[i
+3]));
605 static A_BOOL
CheckBuffers(void)
608 A_BOOL success
= TRUE
;
609 BUFFER_PROC_LIST checkList
[BUFFER_PROC_LIST_DEPTH
];
611 /* assemble the list */
612 AssembleBufferList(checkList
);
614 /* scan the buffers and verify */
615 for (i
= 0; i
< BUFFER_PROC_LIST_DEPTH
; i
++) {
616 success
= CheckOneBuffer((A_UINT16
*)checkList
[i
].pBuffer
, checkList
[i
].length
);
618 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, ("Buffer : 0x%X, Length:%d failed verify \n",
619 (A_UINT32
)checkList
[i
].pBuffer
, checkList
[i
].length
));
627 /* find the end marker for the last buffer we will be sending */
628 static A_UINT16
GetEndMarker(void)
631 BUFFER_PROC_LIST checkList
[BUFFER_PROC_LIST_DEPTH
];
633 /* fill up buffers with the normal counting pattern */
634 InitBuffers(FILL_COUNTING
);
636 /* assemble the list we will be sending down */
637 AssembleBufferList(checkList
);
638 /* point to the last 2 bytes of the last buffer */
639 pBuffer
= &(checkList
[BUFFER_PROC_LIST_DEPTH
- 1].pBuffer
[(checkList
[BUFFER_PROC_LIST_DEPTH
- 1].length
) - 2]);
641 /* the last count in the last buffer is the marker */
642 return (A_UINT16
)pBuffer
[0] | ((A_UINT16
)pBuffer
[1] << 8);
645 #define ATH_PRINT_OUT_ZONE ATH_DEBUG_ERR
647 /* send the ordered buffers to the target */
648 static A_STATUS
SendBuffers(AR6K_DEVICE
*pDev
, int mbox
)
650 A_STATUS status
= A_OK
;
651 A_UINT32 request
= HIF_WR_SYNC_BLOCK_INC
;
652 BUFFER_PROC_LIST sendList
[BUFFER_PROC_LIST_DEPTH
];
656 int totalwPadding
= 0;
658 AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE
, ("Sending buffers on mailbox : %d \n",mbox
));
660 /* fill buffer with counting pattern */
661 InitBuffers(FILL_COUNTING
);
663 /* assemble the order in which we send */
664 AssembleBufferList(sendList
);
666 for (i
= 0; i
< BUFFER_PROC_LIST_DEPTH
; i
++) {
668 /* we are doing block transfers, so we need to pad everything to a block size */
669 paddedLength
= (sendList
[i
].length
+ (g_BlockSizes
[mbox
] - 1)) &
670 (~(g_BlockSizes
[mbox
] - 1));
672 /* send each buffer synchronously */
673 status
= HIFReadWrite(pDev
->HIFDevice
,
674 g_MailboxAddrs
[mbox
],
679 if (status
!= A_OK
) {
682 totalBytes
+= sendList
[i
].length
;
683 totalwPadding
+= paddedLength
;
686 AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE
, ("Sent %d bytes (%d padded bytes) to mailbox : %d \n",totalBytes
,totalwPadding
,mbox
));
691 /* poll the mailbox credit counter until we get a credit or timeout */
692 static A_STATUS
GetCredits(AR6K_DEVICE
*pDev
, int mbox
, int *pCredits
)
694 A_STATUS status
= A_OK
;
695 int timeout
= TEST_CREDITS_RECV_TIMEOUT
;
701 /* Read the counter register to get credits, this auto-decrements */
702 address
= COUNT_DEC_ADDRESS
+ (AR6K_MAILBOXES
+ mbox
) * 4;
703 status
= HIFReadWrite(pDev
->HIFDevice
, address
, &credits
, sizeof(credits
),
704 HIF_RD_SYNC_BYTE_FIX
, NULL
);
705 if (status
!= A_OK
) {
706 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
707 ("Unable to decrement the command credit count register (mbox=%d)\n",mbox
));
719 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
720 (" Timeout reading credit registers (mbox=%d, address:0x%X) \n",mbox
,address
));
725 /* delay a little, target may not be ready */
730 if (status
== A_OK
) {
738 /* wait for the buffers to come back */
739 static A_STATUS
RecvBuffers(AR6K_DEVICE
*pDev
, int mbox
)
741 A_STATUS status
= A_OK
;
742 A_UINT32 request
= HIF_RD_SYNC_BLOCK_INC
;
743 BUFFER_PROC_LIST recvList
[BUFFER_PROC_LIST_DEPTH
];
749 int totalwPadding
= 0;
751 AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE
, ("Waiting for buffers on mailbox : %d \n",mbox
));
753 /* zero the buffers */
754 InitBuffers(FILL_ZERO
);
756 /* assemble the order in which we should receive */
757 AssembleBufferList(recvList
);
761 while (curBuffer
< BUFFER_PROC_LIST_DEPTH
) {
763 /* get number of buffers that have been completed, this blocks
764 * until we get at least 1 credit or it times out */
765 status
= GetCredits(pDev
, mbox
, &credits
);
767 if (status
!= A_OK
) {
771 AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE
, ("Got %d messages on mailbox : %d \n",credits
, mbox
));
773 /* get all the buffers that are sitting on the queue */
774 for (i
= 0; i
< credits
; i
++) {
775 AR_DEBUG_ASSERT(curBuffer
< BUFFER_PROC_LIST_DEPTH
);
776 /* recv the current buffer synchronously, the buffers should come back in
777 * order... with padding applied by the target */
778 paddedLength
= (recvList
[curBuffer
].length
+ (g_BlockSizes
[mbox
] - 1)) &
779 (~(g_BlockSizes
[mbox
] - 1));
781 status
= HIFReadWrite(pDev
->HIFDevice
,
782 g_MailboxAddrs
[mbox
],
783 recvList
[curBuffer
].pBuffer
,
787 if (status
!= A_OK
) {
788 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, ("Failed to read %d bytes on mailbox:%d : address:0x%X \n",
789 recvList
[curBuffer
].length
, mbox
, g_MailboxAddrs
[mbox
]));
793 totalwPadding
+= paddedLength
;
794 totalBytes
+= recvList
[curBuffer
].length
;
798 if (status
!= A_OK
) {
801 /* go back and get some more */
805 if (totalBytes
!= TEST_BYTES
) {
806 AR_DEBUG_ASSERT(FALSE
);
808 AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE
, ("Got all buffers on mbox:%d total recv :%d (w/Padding : %d) \n",
809 mbox
, totalBytes
, totalwPadding
));
817 static A_STATUS
DoOneMboxHWTest(AR6K_DEVICE
*pDev
, int mbox
)
822 /* send out buffers */
823 status
= SendBuffers(pDev
,mbox
);
825 if (status
!= A_OK
) {
826 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, ("Sending buffers Failed : %d mbox:%d\n",status
,mbox
));
830 /* go get them, this will block */
831 status
= RecvBuffers(pDev
, mbox
);
833 if (status
!= A_OK
) {
834 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, ("Recv buffers Failed : %d mbox:%d\n",status
,mbox
));
838 /* check the returned data patterns */
839 if (!CheckBuffers()) {
840 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, ("Buffer Verify Failed : mbox:%d\n",mbox
));
845 AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE
, (" Send/Recv success! mailbox : %d \n",mbox
));
852 /* here is where the test starts */
853 A_STATUS
DoMboxHWTest(AR6K_DEVICE
*pDev
)
864 AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE
, (" DoMboxHWTest START - \n"));
867 /* get the addresses for all 4 mailboxes */
868 status
= HIFConfigureDevice(pDev
->HIFDevice
, HIF_DEVICE_GET_MBOX_ADDR
,
869 g_MailboxAddrs
, sizeof(g_MailboxAddrs
));
871 if (status
!= A_OK
) {
872 AR_DEBUG_ASSERT(FALSE
);
876 /* get the block sizes */
877 status
= HIFConfigureDevice(pDev
->HIFDevice
, HIF_DEVICE_GET_MBOX_BLOCK_SIZE
,
878 g_BlockSizes
, sizeof(g_BlockSizes
));
880 if (status
!= A_OK
) {
881 AR_DEBUG_ASSERT(FALSE
);
885 /* note, the HIF layer usually reports mbox 0 to have a block size of
886 * 1, but our test wants to run in block-mode for all mailboxes, so we treat all mailboxes
888 g_BlockSizes
[0] = g_BlockSizes
[1];
889 AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE
, ("Block Size to use: %d \n",g_BlockSizes
[0]));
891 if (g_BlockSizes
[1] > BUFFER_BLOCK_PAD
) {
892 AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE
, ("%d Block size is too large for buffer pad %d\n",
893 g_BlockSizes
[1], BUFFER_BLOCK_PAD
));
897 AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE
, ("Waiting for target.... \n"));
899 /* the target lets us know it is ready by giving us 1 credit on
901 status
= GetCredits(pDev
, 0, &credits
);
903 if (status
!= A_OK
) {
904 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, ("Failed to wait for target ready \n"));
908 AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE
, ("Target is ready ...\n"));
910 /* read the first 4 scratch registers */
911 status
= HIFReadWrite(pDev
->HIFDevice
,
915 HIF_RD_SYNC_BYTE_INC
,
918 if (status
!= A_OK
) {
919 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, ("Failed to wait get parameters \n"));
924 bufferSize
= (int)(((A_UINT16
)params
[2] << 8) | (A_UINT16
)params
[1]);
926 AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE
,
927 ("Target parameters: bufs per mailbox:%d, buffer size:%d bytes (total space: %d, minimum required space (w/padding): %d) \n",
928 numBufs
, bufferSize
, (numBufs
* bufferSize
), TOTAL_BYTES
));
930 if ((numBufs
* bufferSize
) < TOTAL_BYTES
) {
931 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, ("Not Enough buffer space to run test! need:%d, got:%d \n",
932 TOTAL_BYTES
, (numBufs
*bufferSize
)));
937 temp
= GetEndMarker();
939 status
= HIFReadWrite(pDev
->HIFDevice
,
943 HIF_WR_SYNC_BYTE_INC
,
946 if (status
!= A_OK
) {
947 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, ("Failed to write end marker \n"));
951 AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE
, ("End Marker: 0x%X \n",temp
));
953 temp
= (A_UINT16
)g_BlockSizes
[1];
954 /* convert to a mask */
956 status
= HIFReadWrite(pDev
->HIFDevice
,
960 HIF_WR_SYNC_BYTE_INC
,
963 if (status
!= A_OK
) {
964 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, ("Failed to write block mask \n"));
968 AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE
, ("Set Block Mask: 0x%X \n",temp
));
970 /* execute the test on each mailbox */
971 for (i
= 0; i
< AR6K_MAILBOXES
; i
++) {
972 status
= DoOneMboxHWTest(pDev
, i
);
973 if (status
!= A_OK
) {
980 if (status
== A_OK
) {
981 AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE
, (" DoMboxHWTest DONE - SUCCESS! - \n"));
983 AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE
, (" DoMboxHWTest DONE - FAILED! - \n"));
985 /* don't let HTC_Start continue, the target is actually not running any HTC code */