root/usr/src/uts/common/io/bnx/570x/driver/common/lmdev/lm5706.h
/*
 * Copyright 2014-2017 Cavium, Inc.
 * The contents of this file are subject to the terms of the Common Development
 * and Distribution License, v.1,  (the "License").
 *
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the License at available
 * at http://opensource.org/licenses/CDDL-1.0
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _LM5706_H
#define _LM5706_H


#include "bcmtype.h"
#include "debug.h"
#include "5706_reg.h"
#include "l2_defs.h"
#include "l5_defs.h"
#ifndef EXCLUDE_KQE_SUPPORT
#include "l4_kqe.h"
#endif
#ifndef L2_ONLY
#include "status_code.h"
#endif
#include "shmem.h"
#include "lm_desc.h"
#include "listq.h"
#include "lm.h"
#include "mm.h"
#ifndef L2_ONLY
#include "toe_ctx.h"
#endif
#ifdef UEFI
#include "5706_efi.h"
#endif
#ifdef SOLARIS
#include <sys/ddi.h>
#include <sys/sunddi.h>
#endif

#ifdef LINUX /*lediag*/
#include "../../mpd_driver_hybrid/pal2.h"
#endif

typedef struct fw_version
{
    u8_t    name[11];
    u8_t    namez;
    u32_t   version;
} fw_version_t;

#ifndef PRIVATE_HSI_HEADER
#include "rxp_hsi.h"
#include "com_hsi.h"
#include "cp_hsi.h"
#include "txp_hsi.h"
#include "tpat_hsi.h"
#else
#include "hsi.h"
#endif

/*******************************************************************************
 * Constants.
 ******************************************************************************/

#define MAX_TX_CHAIN                12
#define MAX_RX_CHAIN                12
#define FIRST_RSS_RXQ               4

#ifndef NUM_RX_CHAIN
#define NUM_RX_CHAIN                1
#endif

#ifndef NUM_TX_CHAIN
#define NUM_TX_CHAIN                1
#endif

#if NUM_TX_CHAIN > MAX_TX_CHAIN
#error Exceeded maximum number of tx chains.
#endif

#if NUM_RX_CHAIN > MAX_RX_CHAIN
#error Exceeded maximum number of rx chains.
#endif

/* Number of bits must be 10 to 25. */
#ifndef LM_PAGE_BITS
#define LM_PAGE_BITS                            12  /* 4K page. */
#endif

#define LM_PAGE_SIZE                            (1 << LM_PAGE_BITS)
#define LM_PAGE_MASK                            (LM_PAGE_SIZE - 1)


#ifndef CACHE_LINE_SIZE_MASK
#define CACHE_LINE_SIZE_MASK        0x3f
#endif


/* Number of packets per indication in calls to mm_indicate_rx/tx. */
#ifndef MAX_PACKETS_PER_INDICATION
#define MAX_PACKETS_PER_INDICATION  50
#endif


#ifndef MAX_FRAG_CNT
#define MAX_FRAG_CNT                33
#endif

/* The maximum is actually 0xffff which can be described by a BD. */
#define MAX_FRAGMENT_SIZE           0xf000


/* Context size. */
#define CTX_SHIFT                   7
#define CTX_SIZE                    (1 << CTX_SHIFT)
#define CTX_MASK                    (CTX_SIZE - 1)
#define GET_CID_ADDR(_cid)          ((_cid) << CTX_SHIFT)
#define GET_CID(_cid_addr)          ((_cid_addr) >> CTX_SHIFT)

#define PHY_CTX_SHIFT               6
#define PHY_CTX_SIZE                (1 << PHY_CTX_SHIFT)
#define PHY_CTX_MASK                (PHY_CTX_SIZE - 1)
#define GET_PCID_ADDR(_pcid)        ((_pcid) << PHY_CTX_SHIFT)
#define GET_PCID(_pcid_addr)        ((_pcid_addr) >> PHY_CTX_SHIFT)

#define MB_KERNEL_CTX_SHIFT         8
#define MB_KERNEL_CTX_SIZE          (1 << MB_KERNEL_CTX_SHIFT)
#define MB_KERNEL_CTX_MASK          (MB_KERNEL_CTX_SIZE - 1)
/* #define MB_GET_CID_ADDR(_cid)       (0x10000 + ((_cid) << MB_KERNEL_CTX_SHIFT)) */
#define MB_GET_CID_ADDR(_p, _c)     lm_mb_get_cid_addr(_p, _c)

#define MAX_CID_CNT                 0x4000
#define MAX_CID_ADDR                (GET_CID_ADDR(MAX_CID_CNT))
#define INVALID_CID_ADDR            0xffffffff


/* The size of the GRC window that appears in 32k-64k. */
#define GRC_WINDOW_BASE             0x8000
#define GRC_WINDOW_SIZE             0x8000


/* L2 rx frame header size. */
#define L2RX_FRAME_HDR_LEN          (sizeof(l2_fhdr_t)+2)


/* The number of bd's per page including the last bd which is used as
 * a pointer to the next bd page. */
#define BD_PER_PAGE                 (LM_PAGE_SIZE/sizeof(tx_bd_t))

/* The number of useable bd's per page.  This number does not include
 * the last bd at the end of the page. */
#define MAX_BD_PER_PAGE             ((u32_t) (BD_PER_PAGE-1))


/* Buffer size of the statistics block. */
#define CHIP_STATS_BUFFER_SIZE      ((sizeof(statistics_block_t) + \
                                        CACHE_LINE_SIZE_MASK) & \
                                        ~CACHE_LINE_SIZE_MASK)

/* Buffer size of the status block. */
#define STATUS_BLOCK_BUFFER_SIZE    ((sizeof(status_blk_combined_t) + \
                                        CACHE_LINE_SIZE_MASK) & \
                                        ~CACHE_LINE_SIZE_MASK)


#define RSS_INDIRECTION_TABLE_SIZE  0x80    /* Maximum indirection table. */
#define RSS_HASH_KEY_SIZE           0x40    /* Maximum key size. */
#ifndef RSS_LOOKUP_TABLE_WA
#define RSS_LOOKUP_TABLE_WA         (4*12*256)  /* 0 to disable workaround. */
#endif


/* Quick context assigments. */
#define L2RX_CID_BASE               0       /* 0-15 */
#define L2TX_CID_BASE               16      /* 16-23 */
#define KWQ_CID                     24
#define KCQ_CID                     25
#define HCOPY_CID                   26      /* 26-27 */
#define GEN_CHAIN_CID               29

/* Xinan definitions. */
#define L2TX_TSS_CID_BASE           32      /* 32-43 */

/* MSIX definitions. */
#define IRQ_MODE_UNKNOWN            0
#define IRQ_MODE_LINE_BASED         1
#define IRQ_MODE_SIMD               2
#define IRQ_MODE_MSI_BASED          3
#define IRQ_MODE_MSIX_BASED         4
#define MAX_MSIX_HW_VEC             9
#define PCI_GRC_WINDOW2_BASE        0xc000
#define PCI_GRC_WINDOW3_BASE        0xe000
#define MSIX_TABLE_ADDR             0x318000
#define MSIX_PBA_ADDR               0x31c000

/*******************************************************************************
 * Macros.
 ******************************************************************************/

/* These macros have been moved to bcmtype.h. */
#if 0
/* Signed subtraction macros with no sign extending.  */
#define S64_SUB(_a, _b)     ((s64_t) ((s64_t) (_a) - (s64_t) (_b)))
#define u64_SUB(_a, _b)     ((u64_t) ((s64_t) (_a) - (s64_t) (_b)))
#define S32_SUB(_a, _b)     ((s32_t) ((s32_t) (_a) - (s32_t) (_b)))
#define uS32_SUB(_a, _b)    ((u32_t) ((s32_t) (_a) - (s32_t) (_b)))
#define S16_SUB(_a, _b)     ((s16_t) ((s16_t) (_a) - (s16_t) (_b)))
#define u16_SUB(_a, _b)     ((u16_t) ((s16_t) (_a) - (s16_t) (_b)))
#define PTR_SUB(_a, _b)     ((u8_t *) (_a) - (u8_t *) (_b))
#endif

#ifndef OFFSETOF
#define OFFSETOF(_s, _m)    ((u32_t) PTR_SUB(&((_s *) 0)->_m, (u8_t *) 0))
#endif
#define WORD_ALIGNED_OFFSETOF(_s, _m)       (OFFSETOF(_s, _m) & ~0x03)


/* STATIC void
 * get_attn_chng_bits(
 *     lm_device_t *pdev,
 *     u32_t *asserted_attns,
 *     u32_t *deasserted_attns); */
#define GET_ATTN_CHNG_BITS(_pdev, _asserted_attns_ptr, _deasserted_attns_ptr) \
    {                                                                         \
        u32_t attn_chng;                                                      \
        u32_t attn_bits;                                                      \
        u32_t attn_ack;                                                       \
                                                                              \
        attn_bits = (_pdev)->vars.status_virt->deflt.status_attn_bits;        \
        attn_ack = (_pdev)->vars.status_virt->deflt.status_attn_bits_ack;     \
                                                                              \
        attn_chng = attn_bits ^ attn_ack;                                     \
                                                                              \
        *(_asserted_attns_ptr) = attn_bits & attn_chng;                       \
        *(_deasserted_attns_ptr) = ~attn_bits & attn_chng;                    \
    }



/*******************************************************************************
 * Statistics.
 ******************************************************************************/

typedef struct _lm_tx_statistics_t
{
    lm_u64_t ipv4_lso_frames;
    lm_u64_t ipv6_lso_frames;
    lm_u64_t ip_cso_frames;
    lm_u64_t ipv4_tcp_udp_cso_frames;
    lm_u64_t ipv6_tcp_udp_cso_frames;
    u32_t aborted;
    u32_t no_bd;
    u32_t no_desc;
    u32_t no_coalesce_buf;
    u32_t no_map_reg;
} lm_tx_stats_t;


typedef struct _lm_rx_statistics_t
{
    u32_t aborted;
    u32_t err;
    u32_t crc;
    u32_t phy_err;
    u32_t alignment;
    u32_t short_packet;
    u32_t giant_packet;
} lm_rx_stats_t;



/*******************************************************************************
 * Packet descriptor.
 ******************************************************************************/
#if defined(LM_NON_LEGACY_MODE_SUPPORT)
typedef struct _lm_packet_t
{
    /* Must be the first entry in this structure. */
    s_list_entry_t link;

    lm_status_t status;

    union _lm_pkt_info_t
    {
        struct _tx_pkt_info_t
        {
            lm_pkt_tx_info_t *tx_pkt_info;
            u16_t next_bd_idx;
            u16_t bd_used;
            u8_t span_pages;
            u8_t  pad;
            u16_t pad1;
            u32_t size;
            #if DBG
            tx_bd_t *dbg_start_bd;
            u16_t dbg_start_bd_idx;
            u16_t dbg_frag_cnt;
            #endif
        } tx;

        struct _rx_pkt_info_t
        {
            lm_pkt_rx_info_t *rx_pkt_info;
            u16_t next_bd_idx;
            u16_t pad;
            u32_t hash_value;           /* RSS hash value. */
            #if DBG
            rx_bd_t *dbg_bd;
            rx_bd_t *dbg_bd1; /* when vmq header split is enabled */
            #endif
        } rx;
    } u1;
} lm_packet_t;
#else
typedef struct _lm_packet_t
{
    /* Must be the first entry in this structure. */
    s_list_entry_t link;

    lm_status_t status;
    u32_t size;

    union _lm_pkt_info_t
    {
        struct _lm_tx_pkt_info_t
        {
            lm_tx_flag_t flags;

            u16_t vlan_tag;
            u16_t next_bd_idx;
            u16_t bd_used;
            u8_t span_pages;
            u8_t _pad;

            u16_t lso_mss;
            u16_t _pad2;

            u16_t lso_ip_hdr_len;
            u16_t lso_tcp_hdr_len;

            #if DBG
            tx_bd_t *dbg_start_bd;
            u16_t dbg_start_bd_idx;
            u16_t dbg_frag_cnt;
            #endif
        } tx;

        struct _lm_rx_pkt_info_t
        {
            lm_rx_flag_t flags;

            u16_t vlan_tag;
            u16_t ip_cksum;
            u16_t tcp_or_udp_cksum;
            u16_t next_bd_idx;

            u8_t *mem_virt;
            lm_address_t mem_phy;
            u32_t buf_size;

            u32_t hash_value;           /* RSS hash value. */

            #if DBG
            rx_bd_t *dbg_bd;
            #endif
        } rx;
    } u1;
} lm_packet_t;
#endif

DECLARE_FRAG_LIST_BUFFER_TYPE(lm_packet_frag_list_t, MAX_FRAG_CNT);



/*******************************************************************************
 * Configurable parameters for the hardware dependent module.
 ******************************************************************************/

typedef struct _lm_params_t
{
    /* This value is used by the upper module to inform the protocol
     * of the maximum transmit/receive packet size.  Packet size
     * ranges from 1514-9014 bytes.  This value does not include CRC32 and
     * VLAN tag. */
    u32_t mtu;
    /* Current node address.  The MAC address is initially set to the
     * hardware address.  This entry can be modified to allow the driver
     * to override the default MAC address.  The new MAC address takes
     * effect after a driver reset. */
    u8_t mac_addr[8];

    u32_t l2_rx_desc_cnt[MAX_RX_CHAIN];
    u32_t l2_tx_bd_page_cnt[MAX_TX_CHAIN];
    u32_t l2_rx_bd_page_cnt[MAX_RX_CHAIN];

    u32_t l4_tx_bd_page_cnt;
    u32_t limit_l4_tx_bd_cnt;
    u32_t l4_rx_bd_page_cnt;
    u32_t limit_l4_rx_bd_cnt;

    #ifndef EXCLUDE_KQE_SUPPORT
    u32_t kwq_page_cnt;
    u32_t kcq_page_cnt;
    u32_t kcq_history_size;
    u32_t con_kcqe_history_size;
    u32_t con_kwqe_history_size;
    #endif

    u32_t gen_bd_page_cnt;
    u32_t max_gen_buf_cnt;
    u32_t gen_buf_per_alloc;

    /* This parameter controls whether the buffered data (generic buffers)
     * should be copied to a staging buffer for indication. */
    u32_t copy_buffered_data;

    /* All the L2 receive buffers start at a cache line size aligned
     * address.  This value determines the location of the L2 frame header
     * from the beginning of the receive buffer.  The value must be a
     * multiple of 4. */
    u32_t rcv_buffer_offset;

    /* Enable a separate receive queue for receiving packets with
     * TCP SYN bit set. */
    u32_t enable_syn_rcvq;

    /* Buffer of hcopy descriptor to allocate for a connection.  When
     * this value is 0, hcopy is disabled. */
    u32_t hcopy_desc_cnt;

    /* Number of pages used for the hcopy bd chain. */
    u32_t hcopy_bd_page_cnt;

    /* This parameter is only valid when enable_hcopy is enabled.
     * When enable_hcopy is enabled, a given connection will not
     * be able to process subsequent kcqe's after the copy_gen kcqe
     * until the hcopy request (for the copy_gen) has completed.
     * The subsequent kcqe's will be copied to a per-connection kcq
     * buffer.  The parameter controls the size of this buffer. */
    u32_t buffered_kcqe_cnt;

    /* Size of the deferred kcqe queue. */
    u32_t deferred_kcqe_cnt;

    /* Various test/debug modes.  Any validation failure will cause the
     * driver to write to misc.swap_diag0 with the corresponding flag.
     * The intention is to trigger the bus analyzer. */
    u32_t test_mode;
    #define TEST_MODE_DISABLED                  0x00
    #define TEST_MODE_OBSOLETE_0                0x01    /* was TEST_MODE_IKOS */
    #define TEST_MODE_OBSOLETE_1                0x02    /* was TEST_MODE_FPGA */
    #define TEST_MODE_VERIFY_RX_CRC             0x10
    #define TEST_MODE_RX_BD_TAGGING             0x20
    #define TEST_MODE_TX_BD_TAGGING             0x40
    #define TEST_MODE_LOG_REG_ACCESS            0x80
    #define TEST_MODE_SAVE_DUMMY_DMA_DATA       0x0100
    #define TEST_MODE_INIT_GEN_BUF_DATA         0x0200
    #define TEST_MODE_DRIVER_PULSE_ALWAYS_ALIVE 0x0400
    #define TEST_MODE_IGNORE_SHMEM_SIGNATURE    0x0800
    #define TEST_MODE_XDIAG_ISCSI               0x1000

    lm_offload_t ofld_cap;
    lm_wake_up_mode_t wol_cap;
    lm_flow_control_t flow_ctrl_cap;
    lm_medium_t req_medium;

    u32_t selective_autoneg;
    #define SELECTIVE_AUTONEG_OFF                   0
    #define SELECTIVE_AUTONEG_SINGLE_SPEED          1
    #define SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS  2

    u32_t wire_speed;                           /* Not valid on SERDES. */
    u32_t phy_addr;                             /* PHY address. */

    /* Ways for the MAC to determine a link change. */
    u32_t phy_int_mode;
    #define PHY_INT_MODE_AUTO                   0
    #define PHY_INT_MODE_MI_INTERRUPT           1
    #define PHY_INT_MODE_LINK_READY             2
    #define PHY_INT_MODE_AUTO_POLLING           3

    /* Ways for the driver to get the link change event. */
    u32_t link_chng_mode;
    #define LINK_CHNG_MODE_AUTO                 0
    #define LINK_CHNG_MODE_USE_STATUS_REG       1
    #define LINK_CHNG_MODE_USE_STATUS_BLOCK     2

    /* Coalescing paramers. */
    u32_t hc_timer_mode;
    #define HC_COLLECT_MODE                     0x0000
    #define HC_RX_TIMER_MODE                    0x0001
    #define HC_TX_TIMER_MODE                    0x0002
    #define HC_COM_TIMER_MODE                   0x0004
    #define HC_CMD_TIMER_MODE                   0x0008
    #define HC_TIMER_MODE                       0x000f

    u32_t ind_comp_limit;
    u32_t tx_quick_cons_trip;
    u32_t tx_quick_cons_trip_int;
    u32_t rx_quick_cons_trip;
    u32_t rx_quick_cons_trip_int;
    u32_t comp_prod_trip;
    u32_t comp_prod_trip_int;
    u32_t tx_ticks;
    u32_t tx_ticks_int;
    u32_t com_ticks;
    u32_t com_ticks_int;
    u32_t cmd_ticks;
    u32_t cmd_ticks_int;
    u32_t rx_ticks;
    u32_t rx_ticks_int;
    u32_t stats_ticks;

    /* Xinan per-processor HC configuration. */
    u32_t psb_tx_cons_trip;
    u32_t psb_tx_ticks;
    u32_t psb_rx_cons_trip;
    u32_t psb_rx_ticks;
    u32_t psb_comp_prod_trip;
    u32_t psb_com_ticks;
    u32_t psb_cmd_ticks;
    u32_t psb_period_ticks;

    u32_t enable_fir;
    u32_t num_rchans;
    u32_t num_wchans;
    u32_t one_tdma;
    u32_t ping_pong_dma;
    u32_t serdes_pre_emphasis;
    u32_t tmr_reload_value1;

    u32_t keep_vlan_tag;

    u32_t enable_remote_phy;
    u32_t rphy_req_medium;
    u32_t rphy_flow_ctrl_cap;
    u32_t rphy_selective_autoneg;
    u32_t rphy_wire_speed;

    u32_t bin_mq_mode;
    u32_t validate_l4_data;

    /* disable PCIe non-FATAL error reporting */
    u32_t disable_pcie_nfr;

    // setting for L2 flow control 0 for disable 1 for enable:
    u32_t fw_flow_control;
    // This parameter dictates how long to wait before dropping L2 packet
    // due to insufficient posted buffers
    // 0 mean no waiting before dropping, 0xFFFF means maximum wait
    u32_t fw_flow_control_wait;
    // 8 lsb represents watermark for flow control, 0 is disable
    u32_t fw_flow_control_watermarks;

    u32_t ena_large_grc_timeout;

    /* 0 causes the driver to report the current flow control configuration.
     * 1 causes the driver to report the flow control autoneg result. */
    u32_t flow_control_reporting_mode;
} lm_params_t;



/*******************************************************************************
 * Device NVM info -- The native strapping does not support the new parts, the
 *                    software needs to reconfigure for them.
 ******************************************************************************/

typedef struct _flash_spec_t
{
    u32_t buffered;
    u32_t shift_bits;
    u32_t page_size;
    u32_t addr_mask;
    u32_t total_size;
} flash_spec_t;


/*******************************************************************************
 * Device info.
 ******************************************************************************/

typedef struct _lm_hardware_info_t
{
    /* PCI info. */
    u16_t vid;
    u16_t did;
    u16_t ssid;
    u16_t svid;

    u8_t irq;
    u8_t int_pin;
    u8_t latency_timer;
    u8_t cache_line_size;
    u8_t rev_id;
    u8_t _pad[3];

    u8_t mac_id;            /* 5709 function 0 or 1. */
    u8_t bin_size;          /* 5709 bin size in term of context pages. */
    u16_t first_l4_l5_bin;  /* 5709 first bin. */

    lm_address_t mem_base;
    u32_t bar_size;

    /* Device info. */
    u32_t phy_id;               /* (phy_reg2 << 16) | phy_reg3 */
    u8_t mac_addr[8];           /* Hardware MAC address. */
    u8_t iscsi_mac_addr[8];     /* Hardware MAC address for iSCSI. */

    u32_t shmem_base;           /* Firmware share memory base addr. */

    u32_t chip_id;      /* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */
    #define CHIP_NUM(_p)                (((_p)->hw_info.chip_id) & 0xffff0000)
    #define CHIP_NUM_5706               0x57060000
    #define CHIP_NUM_5708               0x57080000
    #define CHIP_NUM_5709               0x57090000
    #define CHIP_NUM_57728              0x00000000

    #define CHIP_REV(_p)                (((_p)->hw_info.chip_id) & 0x0000f000)
    #define CHIP_REV_Ax                 0x00000000
    #define CHIP_REV_Bx                 0x00001000
    #define CHIP_REV_Cx                 0x00002000
    #define CHIP_REV_FPGA               0x0000f000
    #define CHIP_REV_IKOS               0x0000e000

    #define CHIP_METAL(_p)              (((_p)->hw_info.chip_id) & 0x00000ff0)
    #define CHIP_BONDING(_p)            (((_p)->hw_info.chip_id) & 0x0000000f)

    #define CHIP_ID(_p)                 (((_p)->hw_info.chip_id) & 0xfffffff0)
    #define CHIP_ID_5706_A0             0x57060000
    #define CHIP_ID_5706_A1             0x57060010
    #define CHIP_ID_5706_FPGA           0x5706f000
    #define CHIP_ID_5706_IKOS           0x5706e000
    #define CHIP_ID_5708_A0             0x57080000
    #define CHIP_ID_5708_B0             0x57081000
    #define CHIP_ID_5708_B1             0x57081010
    #define CHIP_ID_5708_FPGA           0x5708f000
    #define CHIP_ID_5708_IKOS           0x5708e000
    #define CHIP_ID_5709_A0             0x57090000
    #define CHIP_ID_5709_A1             0x57090010
    #define CHIP_ID_5709_B0             0x57091000
    #define CHIP_ID_5709_B1             0x57091010
    #define CHIP_ID_5709_B2             0x57091020
    #define CHIP_ID_5709_FPGA           0x5709f000
    #define CHIP_ID_5709_IKOS           0x5709e000

    #define CHIP_BOND_ID(_p)            (((_p)->hw_info.chip_id) & 0xf)

    /* A serdes chip will have the first bit of the bond id set. */
    #define CHIP_BOND_ID_SERDES_BIT     0x01

    /* HW config from nvram. */
    u32_t nvm_hw_config;

    u32_t max_toe_conn;
    u32_t max_iscsi_conn;
    u32_t max_iscsi_pending_tasks;

    /* Bus info. */
    u8_t bus_mode;
    #define BUS_MODE_PCI                0
    #define BUS_MODE_PCIX               1
    #define BUS_MODE_PCIE               2

    u8_t bus_width;
    #define BUS_WIDTH_32_BIT            32
    #define BUS_WIDTH_64_BIT            64

    u16_t bus_speed;
    #define BUS_SPEED_33_MHZ            33
    #define BUS_SPEED_50_MHZ            50
    #define BUS_SPEED_66_MHZ            66
    #define BUS_SPEED_100_MHZ           100
    #define BUS_SPEED_133_MHZ           133

    /* EPB info.  Only valid for 5708. */
    u8_t pcie_bus_num;

    u8_t pcie_max_width;
    u8_t pcie_width;
    #define PCIE_WIDTH_1                1
    #define PCIE_WIDTH_2                2
    #define PCIE_WIDTH_4                4
    #define PCIE_WIDTH_8                8
    #define PCIE_WIDTH_16               16
    #define PCIE_WIDTH_32               32

    u8_t _unused_;

    u16_t pcie_max_speed;
    u16_t pcie_speed;
    #define PCIE_SPEED_2_5_G            25
    #define PCIE_SPEED_5_G              50

    /* Flash info. */
    flash_spec_t flash_spec;
} lm_hardware_info_t;



/*******************************************************************************
 * Device state variables.
 ******************************************************************************/

typedef struct _phy_mem_block_t
{
    lm_address_t start_phy;
    u8_t *start;
    u32_t size;
} phy_mem_block_t;


typedef struct _lm_variables_t
{
#ifdef SOLARIS
        ddi_acc_handle_t dmaRegAccHandle;
#endif
    volatile reg_space_t *regview;

    volatile status_blk_combined_t *status_virt;
    lm_address_t status_phy;

    lm_status_t link_status;
    lm_medium_t medium;
    lm_flow_control_t flow_control;

    /* remote phy status. */
    u8_t rphy_status;
    #define RPHY_STATUS_ACTIVE          0x01
    #define RPHY_STATUS_MODULE_PRESENT  0x02

    u8_t enable_cu_rate_limiter;

    u16_t bcm5706s_tx_drv_cur;

    volatile statistics_block_t *stats_virt;
    lm_address_t stats_phy;

    u16_t fw_wr_seq;
    u8_t fw_timed_out;

    /* Serdes autonegotiation fallback.  For a serdes medium,
     * if we cannot get link via autonegotiation, we'll force
     * the speed to get link. */
    u8_t serdes_fallback_select;
    u8_t serdes_fallback_status;
    #define SERDES_FALLBACK_NONE            0
    #define SERDES_FALLBACK_1G              1
    #define SERDES_FALLBACK_2_5G            2

    /* This flag is set if the cable is attached when there
     * is no link.  The upper module could check this flag to
     * determine if there is a need to wait for link. */
    u8_t cable_is_attached;

    /* Write sequence for driver pulse. */
    u16_t drv_pulse_wr_seq;

    /* 5708 pre-emphasis. */
    u32_t serdes_pre_emphasis;

    u32_t interrupt_mode;

    u32_t cu_mbuf_cnt; /*5709 only */

    u32_t hw_filter_ctx_offset;
    /* 5709 backing store context memory. */
    #ifndef MAX_CTX
    #define MAX_CTX                         (16 * 1024)
    #endif
    #define ONE_CTX_SIZE                    0x80
    #define NUM_CTX_MBLKS                   16
    #define CTX_MBLK_SIZE                   (128 * 1024)
    phy_mem_block_t ctx_mem[NUM_CTX_MBLKS];
} lm_variables_t;



/*******************************************************************************
 * Transmit info.
 ******************************************************************************/

typedef struct _lm_tx_chain_t
{
    u32_t idx;
    #define TX_CHAIN_IDX0                       0
    #define TX_CHAIN_IDX1                       1
    #define TX_CHAIN_IDX2                       2
    #define TX_CHAIN_IDX3                       3
    #define TX_CHAIN_IDX4                       4
    #define TX_CHAIN_IDX5                       5
    #define TX_CHAIN_IDX6                       6
    #define TX_CHAIN_IDX7                       7
    #define TX_CHAIN_IDX8                       8
    #define TX_CHAIN_IDX9                       9
    #define TX_CHAIN_IDX10                      10
    #define TX_CHAIN_IDX11                      11

    u8_t  cpu_num;
    u8_t  cpu_num_valid;
    u16_t reserve2;
    /* This is a contiguous memory block of params.l2_tx_bd_page_cnt pages
     * used for L2 tx_bd chain.  The BD chain is arranged as a circular
     * chain where the last BD entry of a page points to the next page,
     * and the last BD entry of the last page points to the first. */
    tx_bd_t *bd_chain_virt;
    lm_address_t bd_chain_phy;

    u32_t cid_addr;
    u16_t prod_idx;
    u16_t con_idx;
    tx_bd_t *prod_bd;
    u32_t prod_bseq;
    volatile u16_t *hw_con_idx_ptr;
    u16_t bd_left;

    s_list_t active_descq;
} lm_tx_chain_t;


typedef struct _lm_tx_info_t
{
    lm_tx_chain_t chain[MAX_TX_CHAIN];

    u32_t num_txq;
    u32_t cu_idx;

    lm_tx_stats_t stats;
} lm_tx_info_t;



/*******************************************************************************
 * Receive info.
 ******************************************************************************/

typedef struct _lm_rx_chain_t
{
    u32_t idx;
    #define RX_CHAIN_IDX0                       0
    #define RX_CHAIN_IDX1                       1
    #define RX_CHAIN_IDX2                       2
    #define RX_CHAIN_IDX3                       3
    #define RX_CHAIN_IDX4                       4
    #define RX_CHAIN_IDX5                       5
    #define RX_CHAIN_IDX6                       6
    #define RX_CHAIN_IDX7                       7
    #define RX_CHAIN_IDX8                       8
    #define RX_CHAIN_IDX9                       9
    #define RX_CHAIN_IDX10                      10
    #define RX_CHAIN_IDX11                      11
    #define RX_CHAIN_IDX12                      12
    #define RX_CHAIN_IDX13                      13
    #define RX_CHAIN_IDX14                      14
    #define RX_CHAIN_IDX15                      15

    u8_t  cpu_num;  /* place holder for cpu affinity(msix) */
    u8_t  cpu_num_valid;
    u16_t max_pkt_len;
    /* This is a contiguous memory block of params.l2_rx_bd_page_cnt pages
     * used for rx completion.  The BD chain is arranged as a circular
     * chain where the last BD entry of a page points to the next page,
     * and the last BD entry of the last page points to the first. */
    rx_bd_t *bd_chain_virt;
    lm_address_t bd_chain_phy;

    u32_t cid_addr;
    u16_t prod_idx;
    u16_t con_idx;
    u16_t hw_con_idx;
    u16_t _pad;

    rx_bd_t *prod_bd;
    u32_t prod_bseq;
    volatile u16_t *hw_con_idx_ptr;
    u16_t bd_left;

    u32_t vmq_lookahead_size;
    s_list_t free_descq; /* legacy mode variable */
    s_list_t active_descq;
} lm_rx_chain_t;


typedef struct _lm_rx_info_t
{
    lm_rx_chain_t chain[MAX_RX_CHAIN];

    u32_t num_rxq;

    #define RX_FILTER_USER_IDX0         0
    #define RX_FILTER_USER_IDX1         1
    #define RX_FILTER_USER_IDX2         2
    #define RX_FILTER_USER_IDX3         3
    #define MAX_RX_FILTER_USER_CNT      4
    lm_rx_mask_t mask[MAX_RX_FILTER_USER_CNT];

    lm_rx_stats_t stats;

    #ifndef EXCLUDE_RSS_SUPPORT
    u32_t rss_tbl_size;
    u8_t *rss_ind_table_virt;
    lm_address_t rss_ind_table_phy;
    #endif
} lm_rx_info_t;



#ifndef EXCLUDE_KQE_SUPPORT
/*******************************************************************************
 * Kernel work and completion queue info.
 ******************************************************************************/

typedef struct _lm_kq_info_t
{
    u32_t kwq_cid_addr;
    u32_t kcq_cid_addr;

    kwqe_t *kwq_virt;
    kwqe_t *kwq_prod_qe;
    kwqe_t *kwq_con_qe;
    kwqe_t *kwq_last_qe;
    u16_t kwq_prod_idx;
    u16_t kwq_con_idx;
    u32_t kwqe_left;

    kcqe_t *kcq_virt;
    kcqe_t *kcq_con_qe;
    kcqe_t *kcq_last_qe;
    u16_t kcq_con_idx;
    u16_t history_kcq_con_idx;
    kcqe_t *history_kcq_con_qe;

    void *kwq_pgtbl_virt;
    lm_address_t kwq_pgtbl_phy;
    lm_address_t kwq_phy;

    void *kcq_pgtbl_virt;
    lm_address_t kcq_pgtbl_phy;
    lm_address_t kcq_phy;

    /* Statistics. */
    u32_t no_kwq_bd_left;
} lm_kq_info_t;
#endif /* EXCLUDE_KQE_SUPPORT */



/*******************************************************************************
 * Include the l4 offload header file.
 ******************************************************************************/

#if INCLUDE_OFLD_SUPPORT
#include "lm_ofld.h"
#else
/* This structure is only used as a placed holder and it is not referenced. */
typedef struct _lm_offload_info_t
{
    void *unused;
} lm_offload_info_t;
#endif



/*******************************************************************************
 * Main device block.
 ******************************************************************************/

typedef enum
{
    OS_TYPE_UNKNOWN = 0,
    OS_TYPE_W2K     = 1,
    OS_TYPE_WXP     = 2,
    OS_TYPE_W2K3    = 3,
    OS_TYPE_VISTA   = 4,
    OS_TYPE_W2K8    = 5,
    OS_TYPE_WIN7    = 6,
    OS_TYPE_WIN8    = 7,
} lm_os_type_t;


typedef struct _lm_device_t
{
    d_list_entry_t link;        /* Link for the device list. */

    u32_t ver_num;              /* major:8 minor:8 rel:8 fix:8 */
    u8_t ver_str[32];           /* null terminated version string. */

    lm_os_type_t os_type;

    lm_variables_t vars;
    lm_tx_info_t tx_info;
    lm_rx_info_t rx_info;
    #ifndef EXCLUDE_KQE_SUPPORT
    lm_kq_info_t kq_info;
    #endif
    lm_offload_info_t ofld;
    lm_hardware_info_t hw_info;
    lm_params_t params;
    lm_mc_table_t mc_table;
    lm_nwuf_list_t nwuf_list;

    #ifdef UEFI
    EFI_PCI_IO_PROTOCOL *PciIoFuncs;
    #endif

    /* Statistics. */
    u32_t chip_reset_cnt;
    u32_t fw_timed_out_cnt;
} lm_device_t;



/*******************************************************************************
 * Functions exported between file modules.
 ******************************************************************************/

lm_status_t
lm_mwrite(
    lm_device_t *pdev,
    u32_t phy_addr,
    u32_t phy_reg,
    u32_t val);

lm_status_t
lm_mread(
    lm_device_t *pdev,
    u32_t phy_addr,
    u32_t phy_reg,
    u32_t *ret_val);

u32_t
lm_nvram_query(
    lm_device_t *pdev,
    u8_t reset_flash_block,
    u8_t no_hw_mod);

void
lm_nvram_init(
    lm_device_t *pdev,
    u8_t reset_flash_block);

lm_status_t
lm_nvram_read(
    lm_device_t *pdev,
    u32_t offset,
    u32_t *ret_buf,
    u32_t buf_size);        /* Must be a multiple of 4. */

lm_status_t
lm_nvram_write(
    lm_device_t *pdev,
    u32_t offset,
    u32_t *data_buf,
    u32_t buf_size);        /* Must be a multiple of 4. */

void
lm_init_cpus(
    lm_device_t *pdev,
    u32_t cpu_mask);
#define CPU_RV2P_1          0x00000001
#define CPU_RV2P_2          0x00000002
#define CPU_RXP             0x00000004
#define CPU_TXP             0x00000008
#define CPU_TPAT            0x00000010
#define CPU_COM             0x00000020
#define CPU_CP              0x00000040
#define CPU_ALL             0xffffffff

void
lm_reg_rd_ind(
    lm_device_t *pdev,
    u32_t offset,
    u32_t *ret);

void
lm_reg_wr_ind(
    lm_device_t *pdev,
    u32_t offset,
    u32_t val);

void
lm_ctx_wr(
    lm_device_t *pdev,
    u32_t cid_addr,
    u32_t offset,
    u32_t val);

u32_t
lm_ctx_rd(
    lm_device_t *pdev,
    u32_t cid_addr,
    u32_t offset);

void
lm_setup_bd_chain_ring(
    u8_t *mem_virt,
    lm_address_t mem_phy,
    u32_t page_cnt);

lm_status_t
lm_init_remote_phy(
    lm_device_t *pdev,
    lm_link_settings_t *local_link,
    lm_link_settings_t *rphy_link);

lm_status_t
lm_init_mac_link(
    lm_device_t *pdev);

#ifndef EXCLUDE_KQE_SUPPORT
u32_t
lm_submit_kernel_wqes(
    lm_device_t *pdev,
    kwqe_t *wqes[],
    u32_t num_wqes);

u32_t
lm_get_kernel_cqes(
    lm_device_t *pdev,
    kcqe_t *cqe_ptr[],
    u32_t ptr_cnt);

u8_t
lm_ack_kernel_cqes(
    lm_device_t *pdev,
    u32_t num_cqes);

void
lm_ack_completed_wqes(
    lm_device_t *pdev);
#endif /* EXCLUDE_KQE_SUPPORT */

u8_t
fw_reset_sync(
    lm_device_t *pdev,
    lm_reason_t reason,
    u32_t msg_data,
    u32_t fw_ack_timeout_us);   /* timeout in microseconds. */

void
lm_reg_rd_blk(
    lm_device_t *pdev,
    u32_t reg_offset,
    u32_t *buf_ptr,
    u32_t u32t_cnt);

void
lm_reg_rd_blk_ind(
    lm_device_t *pdev,
    u32_t reg_offset,
    u32_t *buf_ptr,
    u32_t u32t_cnt);

void
lm_reg_wr_blk(
    lm_device_t *pdev,
    u32_t reg_offset,
    u32_t *data_ptr,
    u32_t u32t_cnt);

void
lm_reg_wr_blk_ind(
    lm_device_t *pdev,
    u32_t reg_offset,
    u32_t *data_ptr,
    u32_t u32t_cnt);

lm_status_t
lm_submit_fw_cmd(
    lm_device_t *pdev,
    u32_t drv_msg);

lm_status_t
lm_last_fw_cmd_status(
    lm_device_t *pdev);

#ifndef EXCLUDE_RSS_SUPPORT

#if defined(LM_NON_LEGACY_MODE_SUPPORT)
lm_status_t
lm_enable_rss(
    lm_device_t *pdev,
    lm_rss_hash_t hash_type,
    PROCESSOR_NUMBER *indirection_table,
    u32_t table_size,
    u8_t *hash_key,
    u32_t key_size,
    u8_t *cpu_tbl,
    u8_t *rss_qidx_tbl);
#else
lm_status_t
lm_enable_rss(
    lm_device_t *pdev,
    lm_rss_hash_t hash_type,
    u8_t *indirection_table,
    u32_t table_size,
    u8_t *hash_key,
    u32_t key_size);
#endif

lm_status_t
lm_disable_rss(
    lm_device_t *pdev);
#endif /* EXCLUDE_RSS_SUPPORT */

lm_medium_t
lm_get_medium(
    lm_device_t *pdev);

u32_t
lm_mb_get_cid_addr(
    lm_device_t *pdev,
    u32_t cid);

u32_t
lm_mb_get_bypass_addr(
    lm_device_t *pdev,
    u32_t cid);

void
lm_set_pcie_nfe_report(
    lm_device_t *pdev);

void
lm_clear_coalescing_ticks(
    lm_device_t *pdev);

void
lm_post_rx_bd(
    lm_device_t *pdev,
    lm_rx_chain_t *rxq
    );

void
lm_create_q_group(
    lm_device_t *pdev,
    u32_t q_group_id,
    u32_t lookahead_sz
    );

lm_status_t
lm_destroy_q_group(
    lm_device_t *pdev,
    u32_t q_group_id,
    u32_t num_queues
    );

void
lm_update_defq_filter_ctx(
    lm_device_t *pdev,
    u8_t valid
    );

lm_status_t
lm_chng_q_group_filter(
    lm_device_t *pdev,
    u32_t q_group_id,
    u8_t  *dest_mac,
    u16_t *vlan_ptr,
    u32_t filter_id
    );

#ifndef EXCLUDE_KQE_SUPPORT
u32_t
lm_service_l2_kcqes(
    struct _lm_device_t *pdev,
    kcqe_t *cqe_ptr[],
    u32_t num_cqes);
#endif

/*******************************************************************************
 * Register access macros.
 ******************************************************************************/

#if DBG && LOG_REG_ACCESS

#define LOG_REG_RD(_pdev, _offset, _val) \
    if((_pdev)->params.test_mode & TEST_MODE_LOG_REG_ACCESS) \
    { \
        DbgMessage2(_pdev, INFORM, "rd 0x%04x = 0x%08x\n", _offset, _val); \
    }

#define LOG_REG_WR(_pdev, _offset, _val) \
    if((_pdev)->params.test_mode & TEST_MODE_LOG_REG_ACCESS) \
    { \
        DbgMessage2(_pdev, INFORM, "wr 0x%04x 0x%08x\n", _offset, _val); \
    }

#define LOG_MBQ_WR32(_pdev, _cid, _offset, _val) \
    if((_pdev)->params.test_mode & TEST_MODE_LOG_REG_ACCESS) \
    { \
        DbgMessage3(_pdev, INFORM, "mbq_wr32 (0x%04x,0x%02x) = 0x%08x\n", \
            _cid, _offset, _val); \
    }

#define LOG_MBQ_WR32(_pdev, _cid, _offset, _val) \
    if((_pdev)->params.test_mode & TEST_MODE_LOG_REG_ACCESS) \
    { \
        DbgMessage3(_pdev, INFORM, "mbq_wr32 (0x%04x,0x%02x) = 0x%08x\n", \
            _cid, _offset, _val); \
    }

#define LOG_MBQ_WR16(_pdev, _cid, _offset, _val) \
    if((_pdev)->params.test_mode & TEST_MODE_LOG_REG_ACCESS) \
    { \
        DbgMessage3(_pdev, INFORM, "mbq_wr16 (0x%04x,0x%02x) = 0x%04x\n", \
            _cid, _offset, _val); \
    }

#define LOG_MBQ_WR8(_pdev, _cid, _offset, _val) \
    if((_pdev)->params.test_mode & TEST_MODE_LOG_REG_ACCESS) \
    { \
        DbgMessage3(_pdev, INFORM, "mbq_wr8 (0x%04x,0x%02x) = 0x%02x\n", \
            _cid, _offset, _val); \
    }

#else
#define LOG_REG_RD(_pdev, _offset, _val)
#define LOG_REG_WR(_pdev, _offset, _val)
#define LOG_MBQ_WR32(_pdev, _cid, _offset, _val)
#define LOG_MBQ_WR16(_pdev, _cid, _offset, _val)
#define LOG_MBQ_WR8(_pdev, _cid, _offset, _val)
#endif

/* Indirect register access. */
#define REG_RD_IND(_pdev, _offset, _ret)    lm_reg_rd_ind(_pdev, _offset, _ret)
#define REG_WR_IND(_pdev, _offset, _val)    lm_reg_wr_ind(_pdev, _offset, _val)

#ifdef CONFIG_PPC64

/* Register access via register name. */
#define REG_RD(_pdev, _name, _ret) \
    mm_read_barrier(); \
    *(_ret) = pal_readl(&((_pdev)->vars.regview->_name)); \
    LOG_REG_RD( \
        _pdev, \
        OFFSETOF(reg_space_t, _name), \
        (_pdev)->vars.regview->_name)

#define REG_WR(_pdev, _name, _val) \
    LOG_REG_WR(_pdev, OFFSETOF(reg_space_t, _name), _val); \
    pal_writel((_val), &((_pdev)->vars.regview->_name)); \
    mm_write_barrier()


/* Register access via register offset. */
#define REG_RD_OFFSET(_pdev, _offset, _ret) \
    mm_read_barrier(); \
    *(_ret) = pal_readl((volatile u32_t *) ((u8_t *) (_pdev)->vars.regview + (_offset))); \
    LOG_REG_RD( \
        _pdev, \
        _offset, \
        *((volatile u32_t *) ((u8_t *) (_pdev)->vars.regview + (_offset))))

#define REG_WR_OFFSET(_pdev, _offset, _val) \
    LOG_REG_WR(_pdev, _offset, _val); \
    pal_writel((_val), (volatile u32_t *) ((u8_t *) (_pdev)->vars.regview + (_offset))); \
    mm_write_barrier()


/* Context write via mailbox queue. */
#define MBQ_WR32(_pdev, _cid, _offset, _val) \
    LOG_MBQ_WR32(_pdev, _cid, _offset, _val); \
    pal_writel((_val), (volatile u32_t *) ((u8_t *) (_pdev)->vars.regview + \
                    MB_GET_CID_ADDR(_pdev, _cid) + (_offset))); \
    mm_write_barrier(); \
    if(CHIP_REV(_pdev) == CHIP_REV_IKOS) \
    { \
        mm_wait(_pdev, 1); \
    }

#define MBQ_WR16(_pdev, _cid, _offset, _val) \
    LOG_MBQ_WR16(_pdev, _cid, _offset, _val); \
    pal_writew((_val), (volatile u16_t *) ((u8_t *) (_pdev)->vars.regview + \
                    MB_GET_CID_ADDR(_pdev, _cid) + (_offset))); \
    mm_write_barrier(); \
    if(CHIP_REV(_pdev) == CHIP_REV_IKOS) \
    { \
        mm_wait(_pdev, 1); \
    }

#define MBQ_WR8(_pdev, _cid, _offset, _val) \
    LOG_MBQ_WR8(_pdev, _cid, _offset, _val); \
    pal_writeb((_val), (volatile u8_t *) ((u8_t *) (_pdev)->vars.regview + \
                    MB_GET_CID_ADDR(_pdev, _cid) + (_offset))); \
    mm_write_barrier(); \
    if(CHIP_REV(_pdev) == CHIP_REV_IKOS) \
    { \
        mm_wait(_pdev, 1); \
    }

#else /* CONFIG_PPC64 */

#ifdef SOLARIS

/* Register access via register name. */
#define REG_RD(_pdev, _name, _ret)                             \
    mm_read_barrier();                                         \
    if ((OFFSETOF(reg_space_t, _name) % 4) == 0)               \
    {                                                          \
        *(_ret) =                                              \
            ddi_get32((_pdev)->vars.dmaRegAccHandle,           \
                      (u32_t *)&(_pdev)->vars.regview->_name); \
    }                                                          \
    else                                                       \
    {                                                          \
        *(_ret) =                                              \
            ddi_get16((_pdev)->vars.dmaRegAccHandle,           \
                      (u16_t *)&(_pdev)->vars.regview->_name); \
    }                                                          \
    LOG_REG_RD(_pdev, OFFSETOF(reg_space_t, _name), *(_ret))

#define REG_WR(_pdev, _name, _val)                         \
    LOG_REG_WR(_pdev, OFFSETOF(reg_space_t, _name), _val); \
    if ((OFFSETOF(reg_space_t, _name) % 4) == 0)           \
    {                                                      \
        ddi_put32((_pdev)->vars.dmaRegAccHandle,           \
                  (u32_t *)&(_pdev)->vars.regview->_name,  \
                  (_val));                                 \
    }                                                      \
    else                                                   \
    {                                                      \
        ddi_put16((_pdev)->vars.dmaRegAccHandle,           \
                  (u16_t *)&(_pdev)->vars.regview->_name,  \
                  (u16_t)(_val));                          \
    }                                                      \
    mm_write_barrier()

/* Register access via register offset. */
#define REG_RD_OFFSET(_pdev, _offset, _ret)                                    \
    mm_read_barrier();                                                         \
    *(_ret) = ddi_get32((_pdev)->vars.dmaRegAccHandle,                         \
                        (u32_t *)((u8_t *)(_pdev)->vars.regview + (_offset))); \
    LOG_REG_RD(_pdev, _offset, *(_ret))

#define REG_WR_OFFSET(_pdev, _offset, _val)                         \
    LOG_REG_WR(_pdev, _offset, _val);                               \
    ddi_put32((_pdev)->vars.dmaRegAccHandle,                        \
              (u32_t *)((u8_t *)(_pdev)->vars.regview + (_offset)), \
              (_val));                                              \
    mm_write_barrier()

/* Context write via mailbox queue. */
#define MBQ_WR32(_pdev, _cid, _offset, _val)                       \
    LOG_MBQ_WR32(_pdev, _cid, _offset, _val);                      \
    ddi_put32((_pdev)->vars.dmaRegAccHandle,                       \
              (u32_t *)((u8_t *)(_pdev)->vars.regview +            \
                        MB_GET_CID_ADDR(_pdev, _cid) + (_offset)), \
              (_val));                                             \
    mm_write_barrier();                                            \
    if(CHIP_REV(_pdev) == CHIP_REV_IKOS)                           \
    {                                                              \
        mm_wait(_pdev, 1);                                         \
    }

#define MBQ_WR16(_pdev, _cid, _offset, _val)                       \
    LOG_MBQ_WR16(_pdev, _cid, _offset, _val);                      \
    ddi_put16((_pdev)->vars.dmaRegAccHandle,                       \
              (u16_t *)((u8_t *)(_pdev)->vars.regview +            \
                        MB_GET_CID_ADDR(_pdev, _cid) + (_offset)), \
              (u16_t)(_val));                                      \
    mm_write_barrier();                                            \
    if(CHIP_REV(_pdev) == CHIP_REV_IKOS)                           \
    {                                                              \
        mm_wait(_pdev, 1);                                         \
    }

#define MBQ_WR8(_pdev, _cid, _offset, _val)                      \
    LOG_MBQ_WR8(_pdev, _cid, _offset, _val);                     \
    ddi_put8((_pdev)->vars.dmaRegAccHandle,                      \
             (u8_t *)((u8_t *)(_pdev)->vars.regview +            \
                      MB_GET_CID_ADDR(_pdev, _cid) + (_offset)), \
             (u8_t)(_val));                                      \
    mm_write_barrier();                                          \
    if(CHIP_REV(_pdev) == CHIP_REV_IKOS)                         \
    {                                                            \
        mm_wait(_pdev, 1);                                       \
    }

#elif !defined(UEFI)

/* Register access via register name. */
#define REG_RD(_pdev, _name, _ret) \
    mm_read_barrier(); \
    *(_ret) = ((_pdev)->vars.regview->_name); \
    LOG_REG_RD( \
        _pdev, \
        OFFSETOF(reg_space_t, _name), \
        (_pdev)->vars.regview->_name)

#define REG_WR(_pdev, _name, _val) \
    LOG_REG_WR(_pdev, OFFSETOF(reg_space_t, _name), _val); \
    (_pdev)->vars.regview->_name = (_val); \
    mm_write_barrier()


/* Register access via register offset. */
#define REG_RD_OFFSET(_pdev, _offset, _ret) \
    mm_read_barrier(); \
    *(_ret) = *((volatile u32_t *) ((u8_t *) (_pdev)->vars.regview+(_offset)));\
    LOG_REG_RD( \
        _pdev, \
        _offset, \
        *((volatile u32_t *) ((u8_t *) (_pdev)->vars.regview + (_offset))))

#define REG_WR_OFFSET(_pdev, _offset, _val) \
    LOG_REG_WR(_pdev, _offset, _val); \
    *((volatile u32_t *) ((u8_t *) (_pdev)->vars.regview+(_offset)))=(_val); \
    mm_write_barrier()


/* Context write via mailbox queue. */
#define MBQ_WR32(_pdev, _cid, _offset, _val) \
    LOG_MBQ_WR32(_pdev, _cid, _offset, _val); \
    *((volatile u32_t *) (((u8_t *) (_pdev)->vars.regview) + \
        MB_GET_CID_ADDR(_pdev, _cid) + (_offset))) = (_val); \
    mm_write_barrier(); \
    if(CHIP_REV(_pdev) == CHIP_REV_IKOS) \
    { \
        mm_wait(_pdev, 1); \
    }

#define MBQ_WR16(_pdev, _cid, _offset, _val) \
    LOG_MBQ_WR16(_pdev, _cid, _offset, _val); \
    *((volatile u16_t *) (((u8_t *) (_pdev)->vars.regview) + \
        MB_GET_CID_ADDR(_pdev, _cid) + (_offset))) = (u16_t) (_val); \
    mm_write_barrier(); \
    if(CHIP_REV(_pdev) == CHIP_REV_IKOS) \
    { \
        mm_wait(_pdev, 1); \
    }

#define MBQ_WR8(_pdev, _cid, _offset, _val) \
    LOG_MBQ_WR8(_pdev, _cid, _offset, _val); \
    *((volatile u8_t *) (((u8_t *) (_pdev)->vars.regview) + \
        MB_GET_CID_ADDR(_pdev, _cid) + (_offset))) = (u8_t) (_val); \
    mm_write_barrier(); \
    if(CHIP_REV(_pdev) == CHIP_REV_IKOS) \
    { \
        mm_wait(_pdev, 1); \
    }

#else   //UEFI

/* Register access via register name. */
#define REG_RD(_pdev, _name, _ret) \
    if ((OFFSETOF(reg_space_t, _name) % 4) == 0) \
    { \
        (_pdev)->PciIoFuncs->Mem.Read( \
                (_pdev)->PciIoFuncs, \
                EfiPciIoWidthUint32, \
                0, \
                (UINT64)(OFFSETOF(reg_space_t, _name)), \
                1, \
                _ret); \
    } \
    else \
    { \
        (_pdev)->PciIoFuncs->Mem.Read( \
                (_pdev)->PciIoFuncs, \
                EfiPciIoWidthUint16, \
                0, \
                (UINT64)(OFFSETOF(reg_space_t, _name)), \
                1, \
                _ret); \
    }

#define REG_WR(_pdev, _name, _val) \
    if ((OFFSETOF(reg_space_t, _name) % 4) == 0) \
    { \
        { \
            u32_t w_val; \
            w_val = _val; \
            (_pdev)->PciIoFuncs->Mem.Write( \
                    (_pdev)->PciIoFuncs, \
                    EfiPciIoWidthUint32, \
                    0, \
                    (UINT64)(OFFSETOF(reg_space_t, _name)), \
                    1, \
                    &w_val); \
        } \
    } \
    else \
    { \
        { \
            u16_t w_val; \
            w_val = (u16_t)_val; \
            (_pdev)->PciIoFuncs->Mem.Write( \
                    (_pdev)->PciIoFuncs, \
                    EfiPciIoWidthUint16, \
                    0, \
                    (UINT64)(OFFSETOF(reg_space_t, _name)), \
                    1, \
                    &w_val); \
        } \
    }


/* Register access via register offset. */
#define REG_RD_OFFSET(_pdev, _offset, _ret) \
    (_pdev)->PciIoFuncs->Mem.Read( \
            (_pdev)->PciIoFuncs, \
            EfiPciIoWidthUint32, \
            0, \
            (UINT64)(_offset), \
            1, \
            _ret)

#define REG_WR_OFFSET(_pdev, _offset, _val) \
    { \
        u32_t w_val; \
        w_val = _val; \
        (_pdev)->PciIoFuncs->Mem.Write( \
                (_pdev)->PciIoFuncs, \
                EfiPciIoWidthUint32, \
                0, \
                (UINT64)(_offset), \
                1, \
                &w_val); \
    }


/* Context write via mailbox queue. */
#define MBQ_WR32(_pdev, _cid, _offset, _val) \
    { \
        u32_t w_val; \
        w_val = _val; \
        (_pdev)->PciIoFuncs->Mem.Write( \
                (_pdev)->PciIoFuncs, \
                EfiPciIoWidthUint32, \
                0, \
                (UINT64)(MB_GET_CID_ADDR(_pdev, _cid) + (_offset)), \
                1, \
                &w_val); \
        if(CHIP_REV(_pdev) == CHIP_REV_IKOS) \
        { \
            mm_wait(_pdev, 1); \
        } \
    }

#define MBQ_WR16(_pdev, _cid, _offset, _val) \
    { \
        u16_t w_val; \
        w_val = _val; \
        (_pdev)->PciIoFuncs->Mem.Write( \
                (_pdev)->PciIoFuncs, \
                EfiPciIoWidthUint16, \
                0, \
                (UINT64)(MB_GET_CID_ADDR(_pdev, _cid) + (_offset)), \
                1, \
                &w_val); \
        if(CHIP_REV(_pdev) == CHIP_REV_IKOS) \
        { \
            mm_wait(_pdev, 1); \
        } \
    }

#define MBQ_WR8(_pdev, _cid, _offset, _val) \
    { \
        u8_t w_val; \
        w_val = _val; \
        (_pdev)->PciIoFuncs->Mem.Write( \
                (_pdev)->PciIoFuncs, \
                EfiPciIoWidthUint8, \
                0, \
                (UINT64)(MB_GET_CID_ADDR(_pdev, _cid) + (_offset)), \
                1, \
                &w_val); \
        if(CHIP_REV(_pdev) == CHIP_REV_IKOS) \
        { \
            mm_wait(_pdev, 1); \
        } \
    }

#endif  //!UEFI

#endif /* CONFIG_PPC64 */

/* Indirect context access.  Unlike the MBQ_WR, these macros will not
 * trigger a chip event. */
#define CTX_WR(_pdev, _cid_addr, _offset, _val) \
    lm_ctx_wr(_pdev, _cid_addr, _offset, _val)

#define CTX_RD(_pdev, _cid_addr, _offset) \
    lm_ctx_rd(_pdev, _cid_addr, _offset)


/* Away to trigger the bus analyzer. */
#define TRIGGER(_pdev, _val)        REG_WR(_pdev, misc.misc_id, _val)



#endif /* _LM5706_H */