/*
 * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
 *
 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
 *
 *
 * 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.
 */

/*
 * This file was originally distributed by Qualcomm Atheros, Inc.
 * under proprietary terms before Copyright ownership was assigned
 * to the Linux Foundation.
 */

//==============================================================================
// HIF specific declarations and prototypes
//
// Author(s): ="Atheros"
//==============================================================================
#ifndef _HIF_H_
#define _HIF_H_

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/* Header files */
//#include "a_config.h"
#include "athdefs.h"
#include "a_types.h"
#include "osapi_linux.h"
#include "dl_list.h"

#define ENABLE_MBOX_DUMMY_SPACE_FEATURE 1

typedef struct htc_callbacks HTC_CALLBACKS;
typedef struct hif_device HIF_DEVICE;
typedef void __iomem *A_target_id_t;

#define HIF_TYPE_AR6002 2
#define HIF_TYPE_AR6003 3
#define HIF_TYPE_AR6004 5
#define HIF_TYPE_AR9888 6
#define HIF_TYPE_AR6320 7
#define HIF_TYPE_AR6320V2 8
/* For attaching Peregrine 2.0 board host_reg_tbl only */
#define HIF_TYPE_AR9888V2 8

/*
 * direction - Direction of transfer (HIF_READ/HIF_WRITE).
 */
#define HIF_READ                    0x00000001
#define HIF_WRITE                   0x00000002
#define HIF_DIR_MASK                (HIF_READ | HIF_WRITE)

/*
 *     type - An interface may support different kind of read/write commands.
 *            For example: SDIO supports CMD52/CMD53s. In case of MSIO it
 *            translates to using different kinds of TPCs. The command type
 *            is thus divided into a basic and an extended command and can
 *            be specified using HIF_BASIC_IO/HIF_EXTENDED_IO.
 */
#define HIF_BASIC_IO                0x00000004
#define HIF_EXTENDED_IO             0x00000008
#define HIF_TYPE_MASK               (HIF_BASIC_IO | HIF_EXTENDED_IO)

/*
 *     emode - This indicates the whether the command is to be executed in a
 *             blocking or non-blocking fashion (HIF_SYNCHRONOUS/
 *             HIF_ASYNCHRONOUS). The read/write data paths in HTC have been
 *             implemented using the asynchronous mode allowing the the bus
 *             driver to indicate the completion of operation through the
 *             registered callback routine. The requirement primarily comes
 *             from the contexts these operations get called from (a driver's
 *             transmit context or the ISR context in case of receive).
 *             Support for both of these modes is essential.
 */
#define HIF_SYNCHRONOUS             0x00000010
#define HIF_ASYNCHRONOUS            0x00000020
#define HIF_EMODE_MASK              (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS)

/*
 *     dmode - An interface may support different kinds of commands based on
 *             the tradeoff between the amount of data it can carry and the
 *             setup time. Byte and Block modes are supported (HIF_BYTE_BASIS/
 *             HIF_BLOCK_BASIS). In case of latter, the data is rounded off
 *             to the nearest block size by padding. The size of the block is
 *             configurable at compile time using the HIF_BLOCK_SIZE and is
 *             negotiated with the target during initialization after the
 *             AR6000 interrupts are enabled.
 */
#define HIF_BYTE_BASIS              0x00000040
#define HIF_BLOCK_BASIS             0x00000080
#define HIF_DMODE_MASK              (HIF_BYTE_BASIS | HIF_BLOCK_BASIS)

/*
 *     amode - This indicates if the address has to be incremented on AR6000
 *             after every read/write operation (HIF?FIXED_ADDRESS/
 *             HIF_INCREMENTAL_ADDRESS).
 */
#define HIF_FIXED_ADDRESS           0x00000100
#define HIF_INCREMENTAL_ADDRESS     0x00000200
#define HIF_AMODE_MASK              (HIF_FIXED_ADDRESS | HIF_INCREMENTAL_ADDRESS)

/*
 *      dummy - data written into the dummy space will not put into the final mbox FIFO
 */
#define HIF_DUMMY_SPACE_MASK              0xFFFF0000


#define HIF_WR_ASYNC_BYTE_FIX   \
    (HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
#define HIF_WR_ASYNC_BYTE_INC   \
    (HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
#define HIF_WR_ASYNC_BLOCK_INC  \
    (HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
#define HIF_WR_SYNC_BYTE_FIX    \
    (HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
#define HIF_WR_SYNC_BYTE_INC    \
    (HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
#define HIF_WR_SYNC_BLOCK_INC  \
    (HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
#define HIF_WR_ASYNC_BLOCK_FIX \
    (HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS)
#define HIF_WR_SYNC_BLOCK_FIX  \
    (HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS)
#define HIF_RD_SYNC_BYTE_INC    \
    (HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
#define HIF_RD_SYNC_BYTE_FIX    \
    (HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
#define HIF_RD_ASYNC_BYTE_FIX   \
    (HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
#define HIF_RD_ASYNC_BLOCK_FIX  \
    (HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS)
#define HIF_RD_ASYNC_BYTE_INC   \
    (HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
#define HIF_RD_ASYNC_BLOCK_INC  \
    (HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
#define HIF_RD_SYNC_BLOCK_INC  \
    (HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
#define HIF_RD_SYNC_BLOCK_FIX  \
    (HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS)

typedef enum {
    HIF_DEVICE_POWER_STATE = 0,
    HIF_DEVICE_GET_MBOX_BLOCK_SIZE,
    HIF_DEVICE_GET_MBOX_ADDR,
    HIF_DEVICE_GET_PENDING_EVENTS_FUNC,
    HIF_DEVICE_GET_IRQ_PROC_MODE,
    HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC,
    HIF_DEVICE_POWER_STATE_CHANGE,
    HIF_DEVICE_GET_IRQ_YIELD_PARAMS,
    HIF_CONFIGURE_QUERY_SCATTER_REQUEST_SUPPORT,
    HIF_DEVICE_GET_OS_DEVICE,
    HIF_DEVICE_DEBUG_BUS_STATE,
    HIF_BMI_DONE,
    HIF_DEVICE_SET_TARGET_TYPE,
    HIF_DEVICE_SET_HTC_CONTEXT,
    HIF_DEVICE_GET_HTC_CONTEXT,
} HIF_DEVICE_CONFIG_OPCODE;

/*
 * HIF CONFIGURE definitions:
 *
 *   HIF_DEVICE_GET_MBOX_BLOCK_SIZE
 *   input : none
 *   output : array of 4 u_int32_ts
 *   notes: block size is returned for each mailbox (4)
 *
 *   HIF_DEVICE_GET_MBOX_ADDR
 *   input : none
 *   output : HIF_DEVICE_MBOX_INFO
 *   notes:
 *
 *   HIF_DEVICE_GET_PENDING_EVENTS_FUNC
 *   input : none
 *   output: HIF_PENDING_EVENTS_FUNC function pointer
 *   notes: this is optional for the HIF layer, if the request is
 *          not handled then it indicates that the upper layer can use
 *          the standard device methods to get pending events (IRQs, mailbox messages etc..)
 *          otherwise it can call the function pointer to check pending events.
 *
 *   HIF_DEVICE_GET_IRQ_PROC_MODE
 *   input : none
 *   output : HIF_DEVICE_IRQ_PROCESSING_MODE (interrupt processing mode)
 *   note: the hif layer interfaces with the underlying OS-specific bus driver. The HIF
 *         layer can report whether IRQ processing is requires synchronous behavior or
 *         can be processed using asynchronous bus requests (typically faster).
 *
 *   HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC
 *   input :
 *   output : HIF_MASK_UNMASK_RECV_EVENT function pointer
 *   notes: this is optional for the HIF layer.  The HIF layer may require a special mechanism
 *          to mask receive message events.  The upper layer can call this pointer when it needs
 *          to mask/unmask receive events (in case it runs out of buffers).
 *
 *   HIF_DEVICE_POWER_STATE_CHANGE
 *
 *   input : HIF_DEVICE_POWER_CHANGE_TYPE
 *   output : none
 *   note: this is optional for the HIF layer.  The HIF layer can handle power on/off state change
 *         requests in an interconnect specific way.  This is highly OS and bus driver dependent.
 *         The caller must guarantee that no HIF read/write requests will be made after the device
 *         is powered down.
 *
 *   HIF_DEVICE_GET_IRQ_YIELD_PARAMS
 *
 *   input : none
 *   output : HIF_DEVICE_IRQ_YIELD_PARAMS
 *   note: This query checks if the HIF layer wishes to impose a processing yield count for the DSR handler.
 *   The DSR callback handler will exit after a fixed number of RX packets or events are processed.
 *   This query is only made if the device reports an IRQ processing mode of HIF_DEVICE_IRQ_SYNC_ONLY.
 *   The HIF implementation can ignore this command if it does not desire the DSR callback to yield.
 *   The HIF layer can indicate the maximum number of IRQ processing units (RX packets) before the
 *   DSR handler callback must yield and return control back to the HIF layer.  When a yield limit is
 *   used the DSR callback will not call HIFAckInterrupts() as it would normally do before returning.
 *   The HIF implementation that requires a yield count must call HIFAckInterrupt() when it is prepared
 *   to process interrupts again.
 *
 *   HIF_CONFIGURE_QUERY_SCATTER_REQUEST_SUPPORT
 *   input : none
 *   output : HIF_DEVICE_SCATTER_SUPPORT_INFO
 *   note:  This query checks if the HIF layer implements the SCATTER request interface.  Scatter requests
 *   allows upper layers to submit mailbox I/O operations using a list of buffers.  This is useful for
 *   multi-message transfers that can better utilize the bus interconnect.
 *
 *
 *   HIF_DEVICE_GET_OS_DEVICE
 *   intput : none
 *   output : HIF_DEVICE_OS_DEVICE_INFO;
 *   note: On some operating systems, the HIF layer has a parent device object for the bus.  This object
 *         may be required to register certain types of logical devices.
 *
 *   HIF_DEVICE_DEBUG_BUS_STATE
 *   input : none
 *   output : none
 *   note: This configure option triggers the HIF interface to dump as much bus interface state.  This
 *   configuration request is optional (No-OP on some HIF implementations)
 *
 *   HIF_DEVICE_SET_TARGET_TYPE
 *   input : TARGET_TYPE_*
 *   output : none
 *   note: Some HIF implementations may need to know TargetType in order to access
 *   Target registers or Host Interest Area.  (No-OP on some HIF implementations)
 */

typedef struct {
    u_int32_t    ExtendedAddress;  /* extended address for larger writes */
    u_int32_t    ExtendedSize;
} HIF_MBOX_PROPERTIES;

#define HIF_MBOX_FLAG_NO_BUNDLING   (1 << 0)   /* do not allow bundling over the mailbox */

typedef struct {
    u_int32_t MboxAddresses[4];  /* must be first element for legacy HIFs that return the address in
                                   and ARRAY of 32-bit words */

        /* the following describe extended mailbox properties */
    HIF_MBOX_PROPERTIES MboxProp[4];
        /* if the HIF supports the GMbox extended address region it can report it
         * here, some interfaces cannot support the GMBOX address range and not set this */
    u_int32_t GMboxAddress;
    u_int32_t GMboxSize;
    u_int32_t Flags;             /* flags to describe mbox behavior or usage */
} HIF_DEVICE_MBOX_INFO;

typedef enum {
    HIF_DEVICE_IRQ_SYNC_ONLY,   /* for HIF implementations that require the DSR to process all
                                   interrupts before returning */
    HIF_DEVICE_IRQ_ASYNC_SYNC,  /* for HIF implementations that allow DSR to process interrupts
                                   using ASYNC I/O (that is HIFAckInterrupt can be called at a
                                   later time */
} HIF_DEVICE_IRQ_PROCESSING_MODE;

typedef enum {
    HIF_DEVICE_POWER_UP,    /* HIF layer should power up interface and/or module */
    HIF_DEVICE_POWER_DOWN,  /* HIF layer should initiate bus-specific measures to minimize power */
    HIF_DEVICE_POWER_CUT    /* HIF layer should initiate bus-specific AND/OR platform-specific measures
                               to completely power-off the module and associated hardware (i.e. cut power supplies)
                            */
} HIF_DEVICE_POWER_CHANGE_TYPE;

typedef enum {
    HIF_DEVICE_STATE_ON,
    HIF_DEVICE_STATE_DEEPSLEEP,
    HIF_DEVICE_STATE_CUTPOWER,
    HIF_DEVICE_STATE_WOW
} HIF_DEVICE_STATE;

typedef struct {
    int     RecvPacketYieldCount; /* max number of packets to force DSR to return */
} HIF_DEVICE_IRQ_YIELD_PARAMS;


typedef struct _HIF_SCATTER_ITEM {
    u_int8_t     *pBuffer;             /* CPU accessible address of buffer */
    int          Length;              /* length of transfer to/from this buffer */
    void        *pCallerContexts[2];  /* space for caller to insert a context associated with this item */
} HIF_SCATTER_ITEM;

struct _HIF_SCATTER_REQ;

typedef void ( *HIF_SCATTER_COMP_CB)(struct _HIF_SCATTER_REQ *);

typedef enum _HIF_SCATTER_METHOD {
    HIF_SCATTER_NONE = 0,
    HIF_SCATTER_DMA_REAL,              /* Real SG support no restrictions */
    HIF_SCATTER_DMA_BOUNCE,            /* Uses SG DMA but HIF layer uses an internal bounce buffer */
} HIF_SCATTER_METHOD;

typedef struct _HIF_SCATTER_REQ {
    DL_LIST             ListLink;           /* link management */
    u_int32_t            Address;            /* address for the read/write operation */
    u_int32_t            Request;            /* request flags */
    u_int32_t            TotalLength;        /* total length of entire transfer */
    u_int32_t            CallerFlags;        /* caller specific flags can be stored here */
    HIF_SCATTER_COMP_CB CompletionRoutine;  /* completion routine set by caller */
    int            CompletionStatus;   /* status of completion */
    void                *Context;           /* caller context for this request */
    int                 ValidScatterEntries;  /* number of valid entries set by caller */
    HIF_SCATTER_METHOD  ScatterMethod;        /* scatter method handled by HIF */
    void                *HIFPrivate[4];     /* HIF private area */
    u_int8_t             *pScatterBounceBuffer;  /* bounce buffer for upper layers to copy to/from */
    HIF_SCATTER_ITEM    ScatterList[1];     /* start of scatter list */
} HIF_SCATTER_REQ;

typedef HIF_SCATTER_REQ * ( *HIF_ALLOCATE_SCATTER_REQUEST)(HIF_DEVICE *device);
typedef void ( *HIF_FREE_SCATTER_REQUEST)(HIF_DEVICE *device, HIF_SCATTER_REQ *request);
typedef int ( *HIF_READWRITE_SCATTER)(HIF_DEVICE *device, HIF_SCATTER_REQ *request);

typedef struct _HIF_DEVICE_SCATTER_SUPPORT_INFO {
        /* information returned from HIF layer */
    HIF_ALLOCATE_SCATTER_REQUEST    pAllocateReqFunc;
    HIF_FREE_SCATTER_REQUEST        pFreeReqFunc;
    HIF_READWRITE_SCATTER           pReadWriteScatterFunc;
    int                             MaxScatterEntries;
    int                             MaxTransferSizePerScatterReq;
} HIF_DEVICE_SCATTER_SUPPORT_INFO;

typedef struct {
    void    *pOSDevice;
} HIF_DEVICE_OS_DEVICE_INFO;

#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG
typedef struct _HID_ACCESS_LOG {
    A_UINT32     seqnum;
    bool         is_write;
    void         *addr;
    A_UINT32     value;
}HIF_ACCESS_LOG;
#endif

#define HIF_MAX_DEVICES                 1

struct htc_callbacks {
    void      *context;     /* context to pass to the dsrhandler
                               note : rwCompletionHandler is provided the context passed to HIFReadWrite  */
    int (* rwCompletionHandler)(void *rwContext, int status);
    int (* dsrHandler)(void *context);
};

typedef struct osdrv_callbacks {
    void      *context;     /* context to pass for all callbacks except deviceRemovedHandler
                               the deviceRemovedHandler is only called if the device is claimed */
    int (* deviceInsertedHandler)(void *context, void *hif_handle);
    int (* deviceRemovedHandler)(void *claimedContext, void *hif_handle);
    int (* deviceSuspendHandler)(void *context);
    int (* deviceResumeHandler)(void *context);
    int (* deviceWakeupHandler)(void *context);
    int (* devicePowerChangeHandler)(void *context, HIF_DEVICE_POWER_CHANGE_TYPE config);
} OSDRV_CALLBACKS;

#define HIF_OTHER_EVENTS     (1 << 0)   /* other interrupts (non-Recv) are pending, host
                                           needs to read the register table to figure out what */
#define HIF_RECV_MSG_AVAIL   (1 << 1)   /* pending recv packet */

typedef struct _HIF_PENDING_EVENTS_INFO {
    u_int32_t Events;
    u_int32_t LookAhead;
    u_int32_t AvailableRecvBytes;
} HIF_PENDING_EVENTS_INFO;

    /* function to get pending events , some HIF modules use special mechanisms
     * to detect packet available and other interrupts */
typedef int ( *HIF_PENDING_EVENTS_FUNC)(HIF_DEVICE              *device,
                                             HIF_PENDING_EVENTS_INFO *pEvents,
                                             void                    *AsyncContext);

#define HIF_MASK_RECV    TRUE
#define HIF_UNMASK_RECV  FALSE
    /* function to mask recv events */
typedef int ( *HIF_MASK_UNMASK_RECV_EVENT)(HIF_DEVICE  *device,
                                                bool    Mask,
                                                void   *AsyncContext);

#ifdef HIF_MBOX_SLEEP_WAR
/* This API is used to update the target sleep state */
void
HIFSetMboxSleep(HIF_DEVICE *device, bool sleep, bool wait, bool cache);
#endif
/*
 * This API is used to perform any global initialization of the HIF layer
 * and to set OS driver callbacks (i.e. insertion/removal) to the HIF layer
 *
 */
int HIFInit(OSDRV_CALLBACKS *callbacks);

/* This API claims the HIF device and provides a context for handling removal.
 * The device removal callback is only called when the OSDRV layer claims
 * a device.  The claimed context must be non-NULL */
void HIFClaimDevice(HIF_DEVICE *device, void *claimedContext);
/* release the claimed device */
void HIFReleaseDevice(HIF_DEVICE *device);

/* This API allows the HTC layer to attach to the HIF device */
int HIFAttachHTC(HIF_DEVICE *device, HTC_CALLBACKS *callbacks);
/* This API detaches the HTC layer from the HIF device */
void     HIFDetachHTC(HIF_DEVICE *device);

A_STATUS
HIFSyncRead(HIF_DEVICE *device,
               A_UINT32 address,
               A_UCHAR *buffer,
               A_UINT32 length,
               A_UINT32 request,
               void *context);

/*
 * This API is used to provide the read/write interface over the specific bus
 * interface.
 * address - Starting address in the AR6000's address space. For mailbox
 *           writes, it refers to the start of the mbox boundary. It should
 *           be ensured that the last byte falls on the mailbox's EOM. For
 *           mailbox reads, it refers to the end of the mbox boundary.
 * buffer - Pointer to the buffer containg the data to be transmitted or
 *          received.
 * length - Amount of data to be transmitted or received.
 * request - Characterizes the attributes of the command.
 */
int
HIFReadWrite(HIF_DEVICE    *device,
             u_int32_t      address,
             u_char        *buffer,
             u_int32_t      length,
             u_int32_t      request,
             void          *context);

/*
 * This can be initiated from the unload driver context when the OSDRV layer has no more use for
 * the device.
 */
void HIFShutDownDevice(HIF_DEVICE *device);
void HIFSurpriseRemoved(HIF_DEVICE *device);

/*
 * This should translate to an acknowledgment to the bus driver indicating that
 * the previous interrupt request has been serviced and the all the relevant
 * sources have been cleared. HTC is ready to process more interrupts.
 * This should prevent the bus driver from raising an interrupt unless the
 * previous one has been serviced and acknowledged using the previous API.
 */
void HIFAckInterrupt(HIF_DEVICE *device);

void HIFMaskInterrupt(HIF_DEVICE *device);

void HIFUnMaskInterrupt(HIF_DEVICE *device);

int
HIFConfigureDevice(HIF_DEVICE *device, HIF_DEVICE_CONFIG_OPCODE opcode,
                   void *config, u_int32_t configLen);

/*
 * This API wait for the remaining MBOX messages to be drained
 * This should be moved to HTC AR6K layer
 */
int hifWaitForPendingRecv(HIF_DEVICE *device);

/****************************************************************/
/* BMI and Diag window abstraction                              */
/****************************************************************/

#define HIF_BMI_EXCHANGE_NO_TIMEOUT  ((u_int32_t)(0))

#define DIAG_TRANSFER_LIMIT 2048U /* maximum number of bytes that can be
                                    handled atomically by DiagRead/DiagWrite */

    /* API to handle HIF-specific BMI message exchanges, this API is synchronous
     * and only allowed to be called from a context that can block (sleep) */
int HIFExchangeBMIMsg(HIF_DEVICE *device,
                           u_int8_t    *pSendMessage,
                           u_int32_t   Length,
                           u_int8_t    *pResponseMessage,
                           u_int32_t   *pResponseLength,
                           u_int32_t   TimeoutMS);



    /*
     * APIs to handle HIF specific diagnostic read accesses. These APIs are
     * synchronous and only allowed to be called from a context that can block (sleep).
     * They are not high performance APIs.
     *
     * HIFDiagReadAccess reads a 4 Byte aligned/length value from a Target register
     * or memory word.
     *
     * HIFDiagReadMem reads an arbitrary length of arbitrarily aligned memory.
     */
int HIFDiagReadAccess(HIF_DEVICE *hifDevice, A_UINT32 address, A_UINT32 *data);
int HIFDiagReadMem(HIF_DEVICE *hif_device, A_UINT32 address, A_UINT8 *data, int nbytes);
void HIFDumpTargetMemory(HIF_DEVICE *hif_device, void *ramdump_base,
                           u_int32_t address, u_int32_t size);
    /*
     * APIs to handle HIF specific diagnostic write accesses. These APIs are
     * synchronous and only allowed to be called from a context that can block (sleep).
     * They are not high performance APIs.
     *
     * HIFDiagWriteAccess writes a 4 Byte aligned/length value to a Target register
     * or memory word.
     *
     * HIFDiagWriteMem writes an arbitrary length of arbitrarily aligned memory.
     */
int HIFDiagWriteAccess(HIF_DEVICE *hifDevice, A_UINT32 address, A_UINT32 data);
int HIFDiagWriteMem(HIF_DEVICE *hif_device, A_UINT32 address, A_UINT8 *data, int nbytes);
#if defined(HIF_PCI) && ! defined(A_SIMOS_DEVHOST)
/*
 * This API allows the Host to access Target registers of a given
 * A_target_id_t directly and relatively efficiently over PCIe.
 * This allows the Host to avoid extra overhead associated with
 * sending a message to firmware and waiting for a response message
 * from firmware, as is done on other interconnects.
 *
 * Yet there is some complexity with direct accesses because the
 * Target's power state is not known a priori. The Host must issue
 * special PCIe reads/writes in order to explicitly wake the Target
 * and to verify that it is awake and will remain awake.
 *
 * NB: Host endianness conversion is left for the caller to handle.
 *     These interfaces handle access; not interpretation.
 *
 * Usage:
 *   During initialization, use A_TARGET_ID to obtain an 'target ID'
 *   for use with these interfaces.
 *
 *   Use A_TARGET_READ and A_TARGET_WRITE to access Target space.
 *   These calls must be bracketed by A_TARGET_ACCESS_BEGIN and
 *   A_TARGET_ACCESS_END.  A single BEGIN/END pair is adequate for
 *   multiple READ/WRITE operations.
 *
 *   Use A_TARGET_ACCESS_BEGIN to put the Target in a state in
 *   which it is legal for the Host to directly access it. This
 *   may involve waking the Target from a low power state, which
 *   may take up to 2Ms!
 *
 *   Use A_TARGET_ACCESS_END to tell the Target that as far as
 *   this code path is concerned, it no longer needs to remain
 *   directly accessible.  BEGIN/END is under a reference counter;
 *   multiple code paths may issue BEGIN/END on a single targid.
 *
 *   For added efficiency, the Host may use A_TARGET_ACCESS_LIKELY.
 *   The LIKELY interface works just like A_TARGET_ACCESS_BEGIN,
 *   except that it may return before the Target is actually
 *   available. It's a vague indication that some Target accesses
 *   are expected "soon".  When the LIKELY API is used,
 *   A_TARGET_ACCESS_BEGIN must be used before any access.
 *
 *   There are several uses for the LIKELY/UNLIKELY API:
 *     -If there is some potential time before Target accesses
 *      and we want to get a head start on waking the Target
 *      (e.g. to overlap Target wake with Host-side malloc)
 *     -High-level code knows that it will call low-level
 *      functions that will use BEGIN/END, and we don't want
 *      to allow the Target to sleep until the entire sequence
 *      has completed.
 *
 *   A_TARGET_ACCESS_OK verifies that the Target can be
 *   accessed. In general, this should not be needed, but it
 *   may be useful for debugging or for special uses.
 *
 *   Note that there must be a matching END for each BEGIN
 *       AND   there must be a matching UNLIKELY for each LIKELY!
 *
 *   NB: This API is designed to allow some flexibility in tradeoffs
 *   between Target power utilization and Host efficiency and
 *   system performance.
 */

/*
 * For maximum performance and no power management, set this to 1.
 * For power management at the cost of performance, set this to 0.
 */
#define CONFIG_ATH_PCIE_MAX_PERF 0

/*
 * For keeping the target awake till the driver is
 * loaded, set this to 1
 */
#define CONFIG_ATH_PCIE_AWAKE_WHILE_DRIVER_LOAD 1

/*
 * When CONFIG_ATH_PCIE_MAX_PERF is 0:
 * To use LIKELY hints, set this to 1 (slightly better performance, more power)
 * To ignore "LIKELY" hints, set this to 0 (slightly worse performance, less power)
 */
#if defined(CONFIG_ATH_PCIE_MAX_PERF)
#define CONFIG_ATH_PCIE_ACCESS_LIKELY 0
#else
#define CONFIG_ATH_PCIE_ACCESS_LIKELY 1
#endif

/*
 * Enable/disable CDC max performance workaround
 * For max-performace set this to 0
 * To allow SoC to enter sleep set this to 1
 */
#define CONFIG_DISABLE_CDC_MAX_PERF_WAR 0

/*
 * PCI-E L1 ASPPM sub-states
 * To enable clock gating in L1 state, set this to 1. (less power, slightly more wakeup latency)
 * To disable clock gating in L1 state, set this to 0. (slighly more power)
 */
#define CONFIG_PCIE_ENABLE_L1_CLOCK_GATE 1

/*
 * PCIE_ACCESS_LOG_NUM specifies the number of
 * read/write records to store
 */
#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG
#define PCIE_ACCESS_LOG_NUM 500
#endif

/* 64-bit MSI support */
#define CONFIG_PCIE_64BIT_MSI 0

/* BAR0 ready checking for AR6320v2 */
#define PCIE_BAR0_READY_CHECKING 0

/* AXI gating when L1, L2 to reduce power consumption */
#define CONFIG_PCIE_ENABLE_AXI_CLK_GATE 0

extern A_target_id_t HIFGetTargetId(HIF_DEVICE *hifDevice);
extern int HIFTargetSleepStateAdjust(A_target_id_t targid, A_BOOL sleep_ok, A_BOOL wait_for_it);
extern void
HIFSetTargetSleep(HIF_DEVICE *hif_device, A_BOOL sleep_ok, A_BOOL wait_for_it);
extern A_BOOL HIFTargetForcedAwake(A_target_id_t targid);
extern void
HIFCancelDeferredTargetSleep(HIF_DEVICE *hif_device);

#define A_TARGET_ID(hifDevice)                HIFGetTargetId(hifDevice)

#if CONFIG_ATH_PCIE_MAX_PERF
#define A_TARGET_ACCESS_BEGIN(targid) \
        do {A_target_id_t unused = (A_target_id_t)(targid); unused = unused;} while(0)

#define A_TARGET_ACCESS_END(targid) \
        do {A_target_id_t unused = (A_target_id_t)(targid); unused = unused;} while(0)

#define A_TARGET_ACCESS_OK(targid) 1

#define A_TARGET_ACCESS_LIKELY(targid) \
        do {A_target_id_t unused = (A_target_id_t)(targid); unused = unused;} while(0)

#define A_TARGET_ACCESS_UNLIKELY(targid) \
        do {A_target_id_t unused = (A_target_id_t)(targid); unused = unused;} while(0)

#define A_TARGET_READ(targid, offset) \
        A_PCI_READ32(TARGID_TO_PCI_ADDR(targid)+(offset))

#if 0
#define A_TARGET_WRITE(targid, offset, value) \
        A_PCI_WRITE32(TARGID_TO_PCI_ADDR(targid)+(offset), (value))
#else /* WORKAROUND */
void WAR_PCI_WRITE32(char *addr, u32 offset, u32 value);
#define A_TARGET_WRITE(targid, offset, value) \
        WAR_PCI_WRITE32(TARGID_TO_PCI_ADDR(targid), (offset), (value))
#endif
#define A_TARGET_ACCESS_BEGIN_RET(targid) \
        do {A_target_id_t unused = (A_target_id_t)(targid); unused = unused;} while(0)

#define A_TARGET_ACCESS_BEGIN_RET_EXT(targid, val) \
        do {A_target_id_t unused = (A_target_id_t)(targid); unused = unused;} while(0)

#define A_TARGET_ACCESS_BEGIN_RET_PTR(targid) \
        do {A_target_id_t unused = (A_target_id_t)(targid); unused = unused;} while(0)

#define A_TARGET_ACCESS_END_RET(targid) \
        do {A_target_id_t unused = (A_target_id_t)(targid); unused = unused;} while(0)

#define A_TARGET_ACCESS_END_RET_EXT(targid, val) \
        do {A_target_id_t unused = (A_target_id_t)(targid); unused = unused;} while(0)

#define A_TARGET_ACCESS_END_RET_PTR(targid) \
        do {A_target_id_t unused = (A_target_id_t)(targid); unused = unused;} while(0)

#else /* CONFIG_ATH_PCIE_MAX_PERF */

void WAR_PCI_WRITE32(char *addr, u32 offset, u32 value);

#define A_TARGET_ACCESS_BEGIN_RET_EXT(targid, val) \
        if (!WLAN_IS_EPPING_ENABLED(vos_get_conparam()) && Q_TARGET_ACCESS_BEGIN(targid) < 0 ) \
             val = -1;

#define A_TARGET_ACCESS_BEGIN_RET(targid) \
        if (!WLAN_IS_EPPING_ENABLED(vos_get_conparam()) && Q_TARGET_ACCESS_BEGIN(targid) < 0) \
            return -1;

#define A_TARGET_ACCESS_BEGIN_RET_PTR(targid) \
        if (!WLAN_IS_EPPING_ENABLED(vos_get_conparam()) && Q_TARGET_ACCESS_BEGIN(targid) < 0) \
            return NULL;

#define A_TARGET_ACCESS_BEGIN(targid) \
        if(Q_TARGET_ACCESS_BEGIN(targid) < 0) \
            return;

#define Q_TARGET_ACCESS_BEGIN(targid) \
        HIFTargetSleepStateAdjust((targid), FALSE, TRUE)

#define A_TARGET_ACCESS_END_RET(targid) \
        if (!WLAN_IS_EPPING_ENABLED(vos_get_conparam()) && Q_TARGET_ACCESS_END(targid) < 0) \
            return -1;

#define A_TARGET_ACCESS_END_RET_EXT(targid, val) \
        if (!WLAN_IS_EPPING_ENABLED(vos_get_conparam()) && Q_TARGET_ACCESS_END(targid) < 0) \
           val = -1;

#define A_TARGET_ACCESS_END_RET_PTR(targid) \
        if (!WLAN_IS_EPPING_ENABLED(vos_get_conparam()) && Q_TARGET_ACCESS_END(targid) < 0) \
            return NULL;

#define A_TARGET_ACCESS_END(targid) \
        if (Q_TARGET_ACCESS_END(targid) < 0) \
            return;

#define Q_TARGET_ACCESS_END(targid) \
        HIFTargetSleepStateAdjust((targid), TRUE, FALSE)

#define A_TARGET_ACCESS_OK(targid)            HIFTargetForcedAwake(targid)

#if CONFIG_ATH_PCIE_ACCESS_LIKELY
#define A_TARGET_ACCESS_LIKELY(targid)        HIFTargetSleepStateAdjust((targid), FALSE, FALSE)
#define A_TARGET_ACCESS_UNLIKELY(targid)      HIFTargetSleepStateAdjust((targid), TRUE, FALSE)
#else /* CONFIG_ATH_PCIE_ACCESS_LIKELY */
#define A_TARGET_ACCESS_LIKELY(targid) \
        do {unsigned long unused = (unsigned long)(targid); unused = unused;} while(0)

#define A_TARGET_ACCESS_UNLIKELY(targid) \
        do {unsigned long unused = (unsigned long)(targid); unused = unused;} while(0)
#endif /* CONFIG_ATH_PCIE_ACCESS_LIKELY */

#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG
extern A_UINT32 HIFTargetReadChecked(A_target_id_t targid, A_UINT32 offset);
extern void HIFTargetWriteChecked(A_target_id_t targid, A_UINT32 offset, A_UINT32 value);
#define A_TARGET_READ(targid, offset)         HIFTargetReadChecked((targid), (offset))
#define A_TARGET_WRITE(targid, offset, value) HIFTargetWriteChecked((targid), (offset), (value))
#else /* CONFIG_ATH_PCIE_ACCESS_DEBUG */
#define A_TARGET_READ(targid, offset)         A_PCI_READ32(TARGID_TO_PCI_ADDR(targid)+(offset))
#if 0
#define A_TARGET_WRITE(targid, offset, value) \
        A_PCI_WRITE32(TARGID_TO_PCI_ADDR(targid)+(offset), (value))
#else /* WORKAROUND */
#define A_TARGET_WRITE(targid, offset, value) \
        WAR_PCI_WRITE32(TARGID_TO_PCI_ADDR(targid), (offset), (value))
#endif
#endif

#endif /* CONFIG_ATH_PCIE_MAX_PERF */

/*Macro to increment the HIF layer packet error count*/
#define OL_ATH_HIF_PKT_ERROR_COUNT_INCR(_hif_state,_hif_ecode);\
{\
  if(_hif_ecode==HIF_PIPE_NO_RESOURCE)(_hif_state->sc->ol_sc->pkt_stats.hif_pipe_no_resrc_count)+=1;\
}
/*
 * This macro implementation is exposed for efficiency only.
 * The implementation may change and callers should
 * consider the targid to be a completely opaque handle.
 */
#define TARGID_TO_PCI_ADDR(targid) (*((A_target_id_t *)(targid)))

void *HIFDeviceToOsDevice(HIF_DEVICE *hif_device);

#elif defined(A_SIMOS_DEVHOST)

struct ol_softc;

u_int32_t sim_target_register_read(struct ol_softc *scn, u_int32_t addr);
void sim_target_register_write(struct ol_softc *scn, u_int32_t addr, u_int32_t val);

#define A_TARGET_ID(hifDevice) 0
#define A_TARGET_READ(ar, addr) sim_target_register_read(ar, addr)
#define A_TARGET_WRITE(ar, addr, val) sim_target_register_write(ar, addr, val)
#define A_TARGET_ACCESS_BEGIN(targid)
#define A_TARGET_ACCESS_END(targid)

#define HIFDeviceToOsDevice(hif_device) NULL

#else

#define HIFDeviceToOsDevice(hif_device) NULL

#endif

#ifdef IPA_UC_OFFLOAD
/*
 * IPA micro controller data path offload feature enabled,
 * HIF should release copy engine related resource information to IPA UC
 * IPA UC will access hardware resource with released information
 */
void HIFIpaGetCEResource(HIF_DEVICE *hif_device,
                          A_UINT32 *ce_sr_base_paddr,
                          A_UINT32 *ce_sr_ring_size,
                          A_UINT32 *ce_reg_paddr);
#endif /* IPA_UC_OFFLOAD */

void HIFSetMailboxSwap(HIF_DEVICE  *device);

int hif_register_driver(void);
void hif_unregister_driver(void);
/* The API's check if FW can be suspended as part of cfg80211 suspend.
 * This is done for SDIO drivers, for other bus types it's NO OP, they
 * enable/disable wow in bus suspend callback.
 * In SDIO driver bus suspend host will configure 4 bit sdio mode to
 * 1 bit sdio mode and set the appropriate host flags.
 */
bool hif_is_80211_fw_wow_required(void);

#ifdef FEATURE_PBM_MAGIC_WOW
void hif_bus_suspend_nonos(void);
void hif_bus_resume_nonos(void);
#endif

#ifdef FEATURE_RUNTIME_PM
/* Runtime power management API of HIF to control
 * runtime pm. During Runtime Suspend the get API
 * return -EAGAIN. The caller can queue the cmd or return.
 * The put API decrements the usage count.
 * The get API increments the usage count.
 * The API's are exposed to HTT and WMI Services only.
 */
int hif_pm_runtime_get(HIF_DEVICE *);
int hif_pm_runtime_put(HIF_DEVICE *);
void *hif_runtime_pm_prevent_suspend_init(const char *);
void hif_runtime_pm_prevent_suspend_deinit(void *data);
int hif_pm_runtime_prevent_suspend(void *ol_sc, void *data);
int hif_pm_runtime_allow_suspend(void *ol_sc, void *data);
int hif_pm_runtime_prevent_suspend_timeout(void *ol_sc, void *data,
						unsigned int delay);
void hif_request_runtime_pm_resume(void *ol_sc);
#else
static inline int hif_pm_runtime_get(HIF_DEVICE *device) { return 0; }
static inline int hif_pm_runtime_put(HIF_DEVICE *device) { return 0; }
static inline int
hif_pm_runtime_prevent_suspend(void *ol_sc, void *context) { return 0; }
static inline int
hif_pm_runtime_allow_suspend(void *ol_sc, void *context) { return 0; }
static inline int
hif_pm_runtime_prevent_suspend_timeout(void *ol_sc, void *context,
						unsigned int msec)
{
	return 0;
}
static inline void *
hif_runtime_pm_prevent_suspend_init(const char *name) { return NULL; }
static inline void
hif_runtime_pm_prevent_suspend_deinit(void *context) { }
static inline void hif_request_runtime_pm_resume(void *ol_sc)
{ }
#endif
#ifdef __cplusplus
}
#endif

A_BOOL HIFIsMailBoxSwapped(HIF_DEVICE *hd);

#ifdef HIF_PCI
int hif_addr_in_boundary(HIF_DEVICE *hif_device, A_UINT32 offset);
#else
static inline int hif_addr_in_boundary(HIF_DEVICE *hif_device, A_UINT32 offset)
{
	return 0;
}
#endif
#endif /* _HIF_H_ */
