| //------------------------------------------------------------------------------ |
| // <copyright file="ar6k.h" company="Atheros"> |
| // Copyright (c) 2007-2010 Atheros Corporation. All rights reserved. |
| // |
| // |
| // Permission to use, copy, modify, and/or distribute this software for any |
| // purpose with or without fee is hereby granted, provided that the above |
| // copyright notice and this permission notice appear in all copies. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| // |
| // |
| //------------------------------------------------------------------------------ |
| //============================================================================== |
| // AR6K device layer that handles register level I/O |
| // |
| // Author(s): ="Atheros" |
| //============================================================================== |
| #ifndef AR6K_H_ |
| #define AR6K_H_ |
| |
| #include "hci_transport_api.h" |
| #include "../htc_debug.h" |
| |
| #define AR6K_MAILBOXES 4 |
| |
| /* HTC runs over mailbox 0 */ |
| #define HTC_MAILBOX 0 |
| |
| #define AR6K_TARGET_DEBUG_INTR_MASK 0x01 |
| |
| #define OTHER_INTS_ENABLED (INT_STATUS_ENABLE_ERROR_MASK | \ |
| INT_STATUS_ENABLE_CPU_MASK | \ |
| INT_STATUS_ENABLE_COUNTER_MASK) |
| |
| |
| //#define MBOXHW_UNIT_TEST 1 |
| |
| #include "athstartpack.h" |
| PREPACK struct ar6k_irq_proc_registers { |
| u8 host_int_status; |
| u8 cpu_int_status; |
| u8 error_int_status; |
| u8 counter_int_status; |
| u8 mbox_frame; |
| u8 rx_lookahead_valid; |
| u8 host_int_status2; |
| u8 gmbox_rx_avail; |
| u32 rx_lookahead[2]; |
| u32 rx_gmbox_lookahead_alias[2]; |
| } POSTPACK; |
| |
| #define AR6K_IRQ_PROC_REGS_SIZE sizeof(struct ar6k_irq_proc_registers) |
| |
| PREPACK struct ar6k_irq_enable_registers { |
| u8 int_status_enable; |
| u8 cpu_int_status_enable; |
| u8 error_status_enable; |
| u8 counter_int_status_enable; |
| } POSTPACK; |
| |
| PREPACK struct ar6k_gmbox_ctrl_registers { |
| u8 int_status_enable; |
| } POSTPACK; |
| |
| #include "athendpack.h" |
| |
| #define AR6K_IRQ_ENABLE_REGS_SIZE sizeof(struct ar6k_irq_enable_registers) |
| |
| #define AR6K_REG_IO_BUFFER_SIZE 32 |
| #define AR6K_MAX_REG_IO_BUFFERS 8 |
| #define FROM_DMA_BUFFER true |
| #define TO_DMA_BUFFER false |
| #define AR6K_SCATTER_ENTRIES_PER_REQ 16 |
| #define AR6K_MAX_TRANSFER_SIZE_PER_SCATTER 16*1024 |
| #define AR6K_SCATTER_REQS 4 |
| #define AR6K_LEGACY_MAX_WRITE_LENGTH 2048 |
| |
| #ifndef A_CACHE_LINE_PAD |
| #define A_CACHE_LINE_PAD 128 |
| #endif |
| #define AR6K_MIN_SCATTER_ENTRIES_PER_REQ 2 |
| #define AR6K_MIN_TRANSFER_SIZE_PER_SCATTER 4*1024 |
| |
| /* buffers for ASYNC I/O */ |
| struct ar6k_async_reg_io_buffer { |
| HTC_PACKET HtcPacket; /* we use an HTC packet as a wrapper for our async register-based I/O */ |
| u8 _Pad1[A_CACHE_LINE_PAD]; |
| u8 Buffer[AR6K_REG_IO_BUFFER_SIZE]; /* cache-line safe with pads around */ |
| u8 _Pad2[A_CACHE_LINE_PAD]; |
| }; |
| |
| struct ar6k_gmbox_info { |
| void *pProtocolContext; |
| int (*pMessagePendingCallBack)(void *pContext, u8 LookAheadBytes[], int ValidBytes); |
| int (*pCreditsPendingCallback)(void *pContext, int NumCredits, bool CreditIRQEnabled); |
| void (*pTargetFailureCallback)(void *pContext, int Status); |
| void (*pStateDumpCallback)(void *pContext); |
| bool CreditCountIRQEnabled; |
| }; |
| |
| struct ar6k_device { |
| A_MUTEX_T Lock; |
| u8 _Pad1[A_CACHE_LINE_PAD]; |
| struct ar6k_irq_proc_registers IrqProcRegisters; /* cache-line safe with pads around */ |
| u8 _Pad2[A_CACHE_LINE_PAD]; |
| struct ar6k_irq_enable_registers IrqEnableRegisters; /* cache-line safe with pads around */ |
| u8 _Pad3[A_CACHE_LINE_PAD]; |
| void *HIFDevice; |
| u32 BlockSize; |
| u32 BlockMask; |
| HIF_DEVICE_MBOX_INFO MailBoxInfo; |
| HIF_PENDING_EVENTS_FUNC GetPendingEventsFunc; |
| void *HTCContext; |
| HTC_PACKET_QUEUE RegisterIOList; |
| struct ar6k_async_reg_io_buffer RegIOBuffers[AR6K_MAX_REG_IO_BUFFERS]; |
| void (*TargetFailureCallback)(void *Context); |
| int (*MessagePendingCallback)(void *Context, |
| u32 LookAheads[], |
| int NumLookAheads, |
| bool *pAsyncProc, |
| int *pNumPktsFetched); |
| HIF_DEVICE_IRQ_PROCESSING_MODE HifIRQProcessingMode; |
| HIF_MASK_UNMASK_RECV_EVENT HifMaskUmaskRecvEvent; |
| bool HifAttached; |
| HIF_DEVICE_IRQ_YIELD_PARAMS HifIRQYieldParams; |
| bool DSRCanYield; |
| int CurrentDSRRecvCount; |
| HIF_DEVICE_SCATTER_SUPPORT_INFO HifScatterInfo; |
| struct dl_list ScatterReqHead; |
| bool ScatterIsVirtual; |
| int MaxRecvBundleSize; |
| int MaxSendBundleSize; |
| struct ar6k_gmbox_info GMboxInfo; |
| bool GMboxEnabled; |
| struct ar6k_gmbox_ctrl_registers GMboxControlRegisters; |
| int RecheckIRQStatusCnt; |
| }; |
| |
| #define LOCK_AR6K(p) A_MUTEX_LOCK(&(p)->Lock); |
| #define UNLOCK_AR6K(p) A_MUTEX_UNLOCK(&(p)->Lock); |
| #define REF_IRQ_STATUS_RECHECK(p) (p)->RecheckIRQStatusCnt = 1 /* note: no need to lock this, it only gets set */ |
| |
| int DevSetup(struct ar6k_device *pDev); |
| void DevCleanup(struct ar6k_device *pDev); |
| int DevUnmaskInterrupts(struct ar6k_device *pDev); |
| int DevMaskInterrupts(struct ar6k_device *pDev); |
| int DevPollMboxMsgRecv(struct ar6k_device *pDev, |
| u32 *pLookAhead, |
| int TimeoutMS); |
| int DevRWCompletionHandler(void *context, int status); |
| int DevDsrHandler(void *context); |
| int DevCheckPendingRecvMsgsAsync(void *context); |
| void DevAsyncIrqProcessComplete(struct ar6k_device *pDev); |
| void DevDumpRegisters(struct ar6k_device *pDev, |
| struct ar6k_irq_proc_registers *pIrqProcRegs, |
| struct ar6k_irq_enable_registers *pIrqEnableRegs); |
| |
| #define DEV_STOP_RECV_ASYNC true |
| #define DEV_STOP_RECV_SYNC false |
| #define DEV_ENABLE_RECV_ASYNC true |
| #define DEV_ENABLE_RECV_SYNC false |
| int DevStopRecv(struct ar6k_device *pDev, bool ASyncMode); |
| int DevEnableRecv(struct ar6k_device *pDev, bool ASyncMode); |
| int DevEnableInterrupts(struct ar6k_device *pDev); |
| int DevDisableInterrupts(struct ar6k_device *pDev); |
| int DevWaitForPendingRecv(struct ar6k_device *pDev,u32 TimeoutInMs,bool *pbIsRecvPending); |
| |
| #define DEV_CALC_RECV_PADDED_LEN(pDev, length) (((length) + (pDev)->BlockMask) & (~((pDev)->BlockMask))) |
| #define DEV_CALC_SEND_PADDED_LEN(pDev, length) DEV_CALC_RECV_PADDED_LEN(pDev,length) |
| #define DEV_IS_LEN_BLOCK_ALIGNED(pDev, length) (((length) % (pDev)->BlockSize) == 0) |
| |
| static INLINE int DevSendPacket(struct ar6k_device *pDev, HTC_PACKET *pPacket, u32 SendLength) { |
| u32 paddedLength; |
| bool sync = (pPacket->Completion == NULL) ? true : false; |
| int status; |
| |
| /* adjust the length to be a multiple of block size if appropriate */ |
| paddedLength = DEV_CALC_SEND_PADDED_LEN(pDev, SendLength); |
| |
| #if 0 |
| if (paddedLength > pPacket->BufferLength) { |
| A_ASSERT(false); |
| if (pPacket->Completion != NULL) { |
| COMPLETE_HTC_PACKET(pPacket,A_EINVAL); |
| return 0; |
| } |
| return A_EINVAL; |
| } |
| #endif |
| |
| AR_DEBUG_PRINTF(ATH_DEBUG_SEND, |
| ("DevSendPacket, Padded Length: %d Mbox:0x%X (mode:%s)\n", |
| paddedLength, |
| pDev->MailBoxInfo.MboxAddresses[HTC_MAILBOX], |
| sync ? "SYNC" : "ASYNC")); |
| |
| status = HIFReadWrite(pDev->HIFDevice, |
| pDev->MailBoxInfo.MboxAddresses[HTC_MAILBOX], |
| pPacket->pBuffer, |
| paddedLength, /* the padded length */ |
| sync ? HIF_WR_SYNC_BLOCK_INC : HIF_WR_ASYNC_BLOCK_INC, |
| sync ? NULL : pPacket); /* pass the packet as the context to the HIF request */ |
| |
| if (sync) { |
| pPacket->Status = status; |
| } else { |
| if (status == A_PENDING) { |
| status = 0; |
| } |
| } |
| |
| return status; |
| } |
| |
| static INLINE int DevRecvPacket(struct ar6k_device *pDev, HTC_PACKET *pPacket, u32 RecvLength) { |
| u32 paddedLength; |
| int status; |
| bool sync = (pPacket->Completion == NULL) ? true : false; |
| |
| /* adjust the length to be a multiple of block size if appropriate */ |
| paddedLength = DEV_CALC_RECV_PADDED_LEN(pDev, RecvLength); |
| |
| if (paddedLength > pPacket->BufferLength) { |
| A_ASSERT(false); |
| AR_DEBUG_PRINTF(ATH_DEBUG_ERR, |
| ("DevRecvPacket, Not enough space for padlen:%d recvlen:%d bufferlen:%d \n", |
| paddedLength,RecvLength,pPacket->BufferLength)); |
| if (pPacket->Completion != NULL) { |
| COMPLETE_HTC_PACKET(pPacket,A_EINVAL); |
| return 0; |
| } |
| return A_EINVAL; |
| } |
| |
| AR_DEBUG_PRINTF(ATH_DEBUG_RECV, |
| ("DevRecvPacket (0x%lX : hdr:0x%X) Padded Length: %d Mbox:0x%X (mode:%s)\n", |
| (unsigned long)pPacket, pPacket->PktInfo.AsRx.ExpectedHdr, |
| paddedLength, |
| pDev->MailBoxInfo.MboxAddresses[HTC_MAILBOX], |
| sync ? "SYNC" : "ASYNC")); |
| |
| status = HIFReadWrite(pDev->HIFDevice, |
| pDev->MailBoxInfo.MboxAddresses[HTC_MAILBOX], |
| pPacket->pBuffer, |
| paddedLength, |
| sync ? HIF_RD_SYNC_BLOCK_FIX : HIF_RD_ASYNC_BLOCK_FIX, |
| sync ? NULL : pPacket); /* pass the packet as the context to the HIF request */ |
| |
| if (sync) { |
| pPacket->Status = status; |
| } |
| |
| return status; |
| } |
| |
| #define DEV_CHECK_RECV_YIELD(pDev) \ |
| ((pDev)->CurrentDSRRecvCount >= (pDev)->HifIRQYieldParams.RecvPacketYieldCount) |
| |
| #define IS_DEV_IRQ_PROC_SYNC_MODE(pDev) (HIF_DEVICE_IRQ_SYNC_ONLY == (pDev)->HifIRQProcessingMode) |
| #define IS_DEV_IRQ_PROCESSING_ASYNC_ALLOWED(pDev) ((pDev)->HifIRQProcessingMode != HIF_DEVICE_IRQ_SYNC_ONLY) |
| |
| /**************************************************/ |
| /****** Scatter Function and Definitions |
| * |
| * |
| */ |
| |
| int DevCopyScatterListToFromDMABuffer(HIF_SCATTER_REQ *pReq, bool FromDMA); |
| |
| /* copy any READ data back into scatter list */ |
| #define DEV_FINISH_SCATTER_OPERATION(pR) \ |
| do { \ |
| if (!((pR)->CompletionStatus) && \ |
| !((pR)->Request & HIF_WRITE) && \ |
| ((pR)->ScatterMethod == HIF_SCATTER_DMA_BOUNCE)) { \ |
| (pR)->CompletionStatus = \ |
| DevCopyScatterListToFromDMABuffer((pR), \ |
| FROM_DMA_BUFFER); \ |
| } \ |
| } while (0) |
| |
| /* copy any WRITE data to bounce buffer */ |
| static INLINE int DEV_PREPARE_SCATTER_OPERATION(HIF_SCATTER_REQ *pReq) { |
| if ((pReq->Request & HIF_WRITE) && (pReq->ScatterMethod == HIF_SCATTER_DMA_BOUNCE)) { |
| return DevCopyScatterListToFromDMABuffer(pReq,TO_DMA_BUFFER); |
| } else { |
| return 0; |
| } |
| } |
| |
| |
| int DevSetupMsgBundling(struct ar6k_device *pDev, int MaxMsgsPerTransfer); |
| |
| int DevCleanupMsgBundling(struct ar6k_device *pDev); |
| |
| #define DEV_GET_MAX_MSG_PER_BUNDLE(pDev) (pDev)->HifScatterInfo.MaxScatterEntries |
| #define DEV_GET_MAX_BUNDLE_LENGTH(pDev) (pDev)->HifScatterInfo.MaxTransferSizePerScatterReq |
| #define DEV_ALLOC_SCATTER_REQ(pDev) \ |
| (pDev)->HifScatterInfo.pAllocateReqFunc((pDev)->ScatterIsVirtual ? (pDev) : (pDev)->HIFDevice) |
| |
| #define DEV_FREE_SCATTER_REQ(pDev,pR) \ |
| (pDev)->HifScatterInfo.pFreeReqFunc((pDev)->ScatterIsVirtual ? (pDev) : (pDev)->HIFDevice,(pR)) |
| |
| #define DEV_GET_MAX_BUNDLE_RECV_LENGTH(pDev) (pDev)->MaxRecvBundleSize |
| #define DEV_GET_MAX_BUNDLE_SEND_LENGTH(pDev) (pDev)->MaxSendBundleSize |
| |
| #define DEV_SCATTER_READ true |
| #define DEV_SCATTER_WRITE false |
| #define DEV_SCATTER_ASYNC true |
| #define DEV_SCATTER_SYNC false |
| int DevSubmitScatterRequest(struct ar6k_device *pDev, HIF_SCATTER_REQ *pScatterReq, bool Read, bool Async); |
| |
| #ifdef MBOXHW_UNIT_TEST |
| int DoMboxHWTest(struct ar6k_device *pDev); |
| #endif |
| |
| /* completely virtual */ |
| struct dev_scatter_dma_virtual_info { |
| u8 *pVirtDmaBuffer; /* dma-able buffer - CPU accessible address */ |
| u8 DataArea[1]; /* start of data area */ |
| }; |
| |
| |
| |
| void DumpAR6KDevState(struct ar6k_device *pDev); |
| |
| /**************************************************/ |
| /****** GMBOX functions and definitions |
| * |
| * |
| */ |
| |
| #ifdef ATH_AR6K_ENABLE_GMBOX |
| |
| void DevCleanupGMbox(struct ar6k_device *pDev); |
| int DevSetupGMbox(struct ar6k_device *pDev); |
| int DevCheckGMboxInterrupts(struct ar6k_device *pDev); |
| void DevNotifyGMboxTargetFailure(struct ar6k_device *pDev); |
| |
| #else |
| |
| /* compiled out */ |
| #define DevCleanupGMbox(p) |
| #define DevCheckGMboxInterrupts(p) 0 |
| #define DevNotifyGMboxTargetFailure(p) |
| |
| static INLINE int DevSetupGMbox(struct ar6k_device *pDev) { |
| pDev->GMboxEnabled = false; |
| return 0; |
| } |
| |
| #endif |
| |
| #ifdef ATH_AR6K_ENABLE_GMBOX |
| |
| /* GMBOX protocol modules must expose each of these internal APIs */ |
| HCI_TRANSPORT_HANDLE GMboxAttachProtocol(struct ar6k_device *pDev, struct hci_transport_config_info *pInfo); |
| int GMboxProtocolInstall(struct ar6k_device *pDev); |
| void GMboxProtocolUninstall(struct ar6k_device *pDev); |
| |
| /* API used by GMBOX protocol modules */ |
| struct ar6k_device *HTCGetAR6KDevice(void *HTCHandle); |
| #define DEV_GMBOX_SET_PROTOCOL(pDev,recv_callback,credits_pending,failure,statedump,context) \ |
| { \ |
| (pDev)->GMboxInfo.pProtocolContext = (context); \ |
| (pDev)->GMboxInfo.pMessagePendingCallBack = (recv_callback); \ |
| (pDev)->GMboxInfo.pCreditsPendingCallback = (credits_pending); \ |
| (pDev)->GMboxInfo.pTargetFailureCallback = (failure); \ |
| (pDev)->GMboxInfo.pStateDumpCallback = (statedump); \ |
| } |
| |
| #define DEV_GMBOX_GET_PROTOCOL(pDev) (pDev)->GMboxInfo.pProtocolContext |
| |
| int DevGMboxWrite(struct ar6k_device *pDev, HTC_PACKET *pPacket, u32 WriteLength); |
| int DevGMboxRead(struct ar6k_device *pDev, HTC_PACKET *pPacket, u32 ReadLength); |
| |
| #define PROC_IO_ASYNC true |
| #define PROC_IO_SYNC false |
| typedef enum GMBOX_IRQ_ACTION_TYPE { |
| GMBOX_ACTION_NONE = 0, |
| GMBOX_DISABLE_ALL, |
| GMBOX_ERRORS_IRQ_ENABLE, |
| GMBOX_RECV_IRQ_ENABLE, |
| GMBOX_RECV_IRQ_DISABLE, |
| GMBOX_CREDIT_IRQ_ENABLE, |
| GMBOX_CREDIT_IRQ_DISABLE, |
| } GMBOX_IRQ_ACTION_TYPE; |
| |
| int DevGMboxIRQAction(struct ar6k_device *pDev, GMBOX_IRQ_ACTION_TYPE, bool AsyncMode); |
| int DevGMboxReadCreditCounter(struct ar6k_device *pDev, bool AsyncMode, int *pCredits); |
| int DevGMboxReadCreditSize(struct ar6k_device *pDev, int *pCreditSize); |
| int DevGMboxRecvLookAheadPeek(struct ar6k_device *pDev, u8 *pLookAheadBuffer, int *pLookAheadBytes); |
| int DevGMboxSetTargetInterrupt(struct ar6k_device *pDev, int SignalNumber, int AckTimeoutMS); |
| |
| #endif |
| |
| #endif /*AR6K_H_*/ |