root/usr/src/uts/common/io/xge/hal/xgehal/xgehal-device.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 * Copyright (c) 2002-2006 Neterion, Inc.
 */

/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include "xgehal-device.h"
#include "xgehal-channel.h"
#include "xgehal-fifo.h"
#include "xgehal-ring.h"
#include "xgehal-driver.h"
#include "xgehal-mgmt.h"

#define SWITCH_SIGN     0xA5A5A5A5A5A5A5A5ULL
#define END_SIGN        0x0

#ifdef XGE_HAL_HERC_EMULATION
#undef XGE_HAL_PROCESS_LINK_INT_IN_ISR
#endif

/*
 * Jenkins hash key length(in bytes)
 */
#define XGE_HAL_JHASH_MSG_LEN 50

/*
 * mix(a,b,c) used in Jenkins hash algorithm
 */
#define mix(a,b,c) { \
        a -= b; a -= c; a ^= (c>>13); \
        b -= c; b -= a; b ^= (a<<8);  \
        c -= a; c -= b; c ^= (b>>13); \
        a -= b; a -= c; a ^= (c>>12); \
        b -= c; b -= a; b ^= (a<<16); \
        c -= a; c -= b; c ^= (b>>5);  \
        a -= b; a -= c; a ^= (c>>3);  \
        b -= c; b -= a; b ^= (a<<10); \
        c -= a; c -= b; c ^= (b>>15); \
}


/*
 * __hal_device_event_queued
 * @data: pointer to xge_hal_device_t structure
 *
 * Will be called when new event succesfully queued.
 */
void
__hal_device_event_queued(void *data, int event_type)
{
        xge_assert(((xge_hal_device_t*)data)->magic == XGE_HAL_MAGIC);
        if (g_xge_hal_driver->uld_callbacks.event_queued) {
                g_xge_hal_driver->uld_callbacks.event_queued(data, event_type);
        }
}

/*
 * __hal_pio_mem_write32_upper
 *
 * Endiann-aware implementation of xge_os_pio_mem_write32().
 * Since Xframe has 64bit registers, we differintiate uppper and lower
 * parts.
 */
void
__hal_pio_mem_write32_upper(pci_dev_h pdev, pci_reg_h regh, u32 val, void *addr)
{
#if defined(XGE_OS_HOST_BIG_ENDIAN) && !defined(XGE_OS_PIO_LITTLE_ENDIAN)
        xge_os_pio_mem_write32(pdev, regh, val, addr);
#else
        xge_os_pio_mem_write32(pdev, regh, val, (void *)((char *)addr + 4));
#endif
}

/*
 * __hal_pio_mem_write32_upper
 *
 * Endiann-aware implementation of xge_os_pio_mem_write32().
 * Since Xframe has 64bit registers, we differintiate uppper and lower
 * parts.
 */
void
__hal_pio_mem_write32_lower(pci_dev_h pdev, pci_reg_h regh, u32 val,
                            void *addr)
{
#if defined(XGE_OS_HOST_BIG_ENDIAN) && !defined(XGE_OS_PIO_LITTLE_ENDIAN)
        xge_os_pio_mem_write32(pdev, regh, val,
                               (void *) ((char *)addr + 4));
#else
        xge_os_pio_mem_write32(pdev, regh, val, addr);
#endif
}

/*
 * __hal_device_register_poll
 * @hldev: pointer to xge_hal_device_t structure
 * @reg: register to poll for
 * @op: 0 - bit reset, 1 - bit set
 * @mask: mask for logical "and" condition based on %op
 * @max_millis: maximum time to try to poll in milliseconds
 *
 * Will poll certain register for specified amount of time.
 * Will poll until masked bit is not cleared.
 */
xge_hal_status_e
__hal_device_register_poll(xge_hal_device_t *hldev, u64 *reg,
                           int op, u64 mask, int max_millis)
{
        u64 val64;
        int i = 0;
        xge_hal_status_e ret = XGE_HAL_FAIL;

        xge_os_udelay(10);

        do {
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0, reg);
                if (op == 0 && !(val64 & mask))
                        return XGE_HAL_OK;
                else if (op == 1 && (val64 & mask) == mask)
                        return XGE_HAL_OK;
                xge_os_udelay(100);
        } while (++i <= 9);

        do {
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0, reg);
                if (op == 0 && !(val64 & mask))
                        return XGE_HAL_OK;
                else if (op == 1 && (val64 & mask) == mask)
                        return XGE_HAL_OK;
                xge_os_udelay(1000);
        } while (++i < max_millis);

        return ret;
}

/*
 * __hal_device_wait_quiescent
 * @hldev: the device
 * @hw_status: hw_status in case of error
 *
 * Will wait until device is quiescent for some blocks.
 */
static xge_hal_status_e
__hal_device_wait_quiescent(xge_hal_device_t *hldev, u64 *hw_status)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;

        /* poll and wait first */
#ifdef XGE_HAL_HERC_EMULATION
        (void) __hal_device_register_poll(hldev, &bar0->adapter_status, 1,
                        (XGE_HAL_ADAPTER_STATUS_TDMA_READY |
                         XGE_HAL_ADAPTER_STATUS_RDMA_READY |
                         XGE_HAL_ADAPTER_STATUS_PFC_READY |
                         XGE_HAL_ADAPTER_STATUS_TMAC_BUF_EMPTY |
                         XGE_HAL_ADAPTER_STATUS_PIC_QUIESCENT |
                         XGE_HAL_ADAPTER_STATUS_MC_DRAM_READY |
                         XGE_HAL_ADAPTER_STATUS_MC_QUEUES_READY |
                         XGE_HAL_ADAPTER_STATUS_M_PLL_LOCK),
                         XGE_HAL_DEVICE_QUIESCENT_WAIT_MAX_MILLIS);
#else
        (void) __hal_device_register_poll(hldev, &bar0->adapter_status, 1,
                        (XGE_HAL_ADAPTER_STATUS_TDMA_READY |
                         XGE_HAL_ADAPTER_STATUS_RDMA_READY |
                         XGE_HAL_ADAPTER_STATUS_PFC_READY |
                         XGE_HAL_ADAPTER_STATUS_TMAC_BUF_EMPTY |
                         XGE_HAL_ADAPTER_STATUS_PIC_QUIESCENT |
                         XGE_HAL_ADAPTER_STATUS_MC_DRAM_READY |
                         XGE_HAL_ADAPTER_STATUS_MC_QUEUES_READY |
                         XGE_HAL_ADAPTER_STATUS_M_PLL_LOCK |
                         XGE_HAL_ADAPTER_STATUS_P_PLL_LOCK),
                         XGE_HAL_DEVICE_QUIESCENT_WAIT_MAX_MILLIS);
#endif

        return xge_hal_device_status(hldev, hw_status);
}

/**
 * xge_hal_device_is_slot_freeze
 * @devh: the device
 *
 * Returns non-zero if the slot is freezed.
 * The determination is made based on the adapter_status
 * register which will never give all FFs, unless PCI read
 * cannot go through.
 */
int
xge_hal_device_is_slot_freeze(xge_hal_device_h devh)
{
        xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u16 device_id;
        u64 adapter_status =
                xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                      &bar0->adapter_status);
        xge_os_pci_read16(hldev->pdev,hldev->cfgh,
                        xge_offsetof(xge_hal_pci_config_le_t, device_id),
                        &device_id);
#ifdef TX_DEBUG
        if (adapter_status == XGE_HAL_ALL_FOXES)
        {
                u64 dummy;
                dummy = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                                &bar0->pcc_enable);
                printf(">>> Slot is frozen!\n");
                brkpoint(0);
        }
#endif
        return((adapter_status == XGE_HAL_ALL_FOXES) || (device_id == 0xffff));
}


/*
 * __hal_device_led_actifity_fix
 * @hldev: pointer to xge_hal_device_t structure
 *
 * SXE-002: Configure link and activity LED to turn it off
 */
static void
__hal_device_led_actifity_fix(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u16 subid;
        u64 val64;

        xge_os_pci_read16(hldev->pdev, hldev->cfgh,
                xge_offsetof(xge_hal_pci_config_le_t, subsystem_id), &subid);

        /*
         *  In the case of Herc, there is a new register named beacon control
         *  is added which was not present in Xena.
         *  Beacon control register in Herc is at the same offset as
         *  gpio control register in Xena.  It means they are one and same in
         *  the case of Xena. Also, gpio control register offset in Herc and
         *  Xena is different.
         *  The current register map represents Herc(It means we have
         *  both beacon  and gpio control registers in register map).
         *  WRT transition from Xena to Herc, all the code in Xena which was
         *  using  gpio control register for LED handling would  have to
         *  use beacon control register in Herc and the rest of the code
         *  which uses gpio control in Xena  would use the same register
         *  in Herc.
         *  WRT LED handling(following code), In the case of Herc, beacon
         *  control register has to be used. This is applicable for Xena also,
         *  since it represents the gpio control register in Xena.
         */
        if ((subid & 0xFF) >= 0x07) {
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                            &bar0->beacon_control);
                val64 |= 0x0000800000000000ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                     val64, &bar0->beacon_control);
                val64 = 0x0411040400000000ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                                    (void *) ((u8 *)bar0 + 0x2700));
        }
}

/* Constants for Fixing the MacAddress problem seen mostly on
 * Alpha machines.
 */
static u64 xena_fix_mac[] = {
        0x0060000000000000ULL, 0x0060600000000000ULL,
        0x0040600000000000ULL, 0x0000600000000000ULL,
        0x0020600000000000ULL, 0x0060600000000000ULL,
        0x0020600000000000ULL, 0x0060600000000000ULL,
        0x0020600000000000ULL, 0x0060600000000000ULL,
        0x0020600000000000ULL, 0x0060600000000000ULL,
        0x0020600000000000ULL, 0x0060600000000000ULL,
        0x0020600000000000ULL, 0x0060600000000000ULL,
        0x0020600000000000ULL, 0x0060600000000000ULL,
        0x0020600000000000ULL, 0x0060600000000000ULL,
        0x0020600000000000ULL, 0x0060600000000000ULL,
        0x0020600000000000ULL, 0x0060600000000000ULL,
        0x0020600000000000ULL, 0x0000600000000000ULL,
        0x0040600000000000ULL, 0x0060600000000000ULL,
        END_SIGN
};

/*
 * __hal_device_fix_mac
 * @hldev: HAL device handle.
 *
 * Fix for all "FFs" MAC address problems observed on Alpha platforms.
 */
static void
__hal_device_xena_fix_mac(xge_hal_device_t *hldev)
{
        int i = 0;
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;

        /*
         *  In the case of Herc, there is a new register named beacon control
         *  is added which was not present in Xena.
         *  Beacon control register in Herc is at the same offset as
         *  gpio control register in Xena.  It means they are one and same in
         *  the case of Xena. Also, gpio control register offset in Herc and
         *  Xena is different.
         *  The current register map represents Herc(It means we have
         *  both beacon  and gpio control registers in register map).
         *  WRT transition from Xena to Herc, all the code in Xena which was
         *  using  gpio control register for LED handling would  have to
         *  use beacon control register in Herc and the rest of the code
         *  which uses gpio control in Xena  would use the same register
         *  in Herc.
         *  In the following code(xena_fix_mac), beacon control register has
         *  to be used in the case of Xena, since it represents gpio control
         *  register. In the case of Herc, there is no change required.
         */
        while (xena_fix_mac[i] != END_SIGN) {
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                xena_fix_mac[i++], &bar0->beacon_control);
                xge_os_mdelay(1);
        }
}

/*
 * xge_hal_device_bcast_enable
 * @hldev: HAL device handle.
 *
 * Enable receiving broadcasts.
 * The host must first write RMAC_CFG_KEY "key"
 * register, and then - MAC_CFG register.
 */
void
xge_hal_device_bcast_enable(xge_hal_device_h devh)
{
        xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
        &bar0->mac_cfg);
                val64 |= XGE_HAL_MAC_RMAC_BCAST_ENABLE;

        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                XGE_HAL_RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);

    __hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0,
                (u32)(val64 >> 32), &bar0->mac_cfg);

        xge_debug_device(XGE_TRACE, "mac_cfg 0x"XGE_OS_LLXFMT": broadcast %s",
                (unsigned long long)val64,
                hldev->config.mac.rmac_bcast_en ? "enabled" : "disabled");
}

/*
 * xge_hal_device_bcast_disable
 * @hldev: HAL device handle.
 *
 * Disable receiving broadcasts.
 * The host must first write RMAC_CFG_KEY "key"
 * register, and then - MAC_CFG register.
 */
void
xge_hal_device_bcast_disable(xge_hal_device_h devh)
{
        xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
        &bar0->mac_cfg);

        val64 &= ~(XGE_HAL_MAC_RMAC_BCAST_ENABLE);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                     XGE_HAL_RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);

        __hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0,
                    (u32)(val64 >> 32), &bar0->mac_cfg);

        xge_debug_device(XGE_TRACE, "mac_cfg 0x"XGE_OS_LLXFMT": broadcast %s",
                (unsigned long long)val64,
                hldev->config.mac.rmac_bcast_en ? "enabled" : "disabled");
}

/*
 * __hal_device_shared_splits_configure
 * @hldev: HAL device handle.
 *
 * TxDMA will stop Read request if the number of read split had exceeded
 * the limit set by shared_splits
 */
static void
__hal_device_shared_splits_configure(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                    &bar0->pic_control);
        val64 |=
        XGE_HAL_PIC_CNTL_SHARED_SPLITS(hldev->config.shared_splits);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                             &bar0->pic_control);
        xge_debug_device(XGE_TRACE, "%s", "shared splits configured");
}

/*
 * __hal_device_rmac_padding_configure
 * @hldev: HAL device handle.
 *
 * Configure RMAC frame padding. Depends on configuration, it
 * can be send to host or removed by MAC.
 */
static void
__hal_device_rmac_padding_configure(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;

        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                    XGE_HAL_RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
        &bar0->mac_cfg);
        val64 &= ( ~XGE_HAL_MAC_RMAC_ALL_ADDR_ENABLE );
        val64 &= ( ~XGE_HAL_MAC_CFG_RMAC_PROM_ENABLE );
        val64 |= XGE_HAL_MAC_CFG_TMAC_APPEND_PAD;

        /*
         * If the RTH enable bit is not set, strip the FCS
         */
        if (!hldev->config.rth_en ||
            !(xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                           &bar0->rts_rth_cfg) & XGE_HAL_RTS_RTH_EN)) {
                val64 |= XGE_HAL_MAC_CFG_RMAC_STRIP_FCS;
        }

        val64 &= ( ~XGE_HAL_MAC_CFG_RMAC_STRIP_PAD );
        val64 |= XGE_HAL_MAC_RMAC_DISCARD_PFRM;

        __hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0,
                    (u32)(val64 >> 32), (char*)&bar0->mac_cfg);
        xge_os_mdelay(1);

        xge_debug_device(XGE_TRACE,
                  "mac_cfg 0x"XGE_OS_LLXFMT": frame padding configured",
                  (unsigned long long)val64);
}

/*
 * __hal_device_pause_frames_configure
 * @hldev: HAL device handle.
 *
 * Set Pause threshold.
 *
 * Pause frame is generated if the amount of data outstanding
 * on any queue exceeded the ratio of
 * (mac_control.mc_pause_threshold_q0q3 or q4q7)/256
 */
static void
__hal_device_pause_frames_configure(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        int i;
        u64 val64;

        switch (hldev->config.mac.media) {
                case XGE_HAL_MEDIA_SR:
                case XGE_HAL_MEDIA_SW:
                        val64=0xfffbfffbfffbfffbULL;
                        break;
                case XGE_HAL_MEDIA_LR:
                case XGE_HAL_MEDIA_LW:
                        val64=0xffbbffbbffbbffbbULL;
                        break;
                case XGE_HAL_MEDIA_ER:
                case XGE_HAL_MEDIA_EW:
                default:
                        val64=0xffbbffbbffbbffbbULL;
                        break;
        }

        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                        val64, &bar0->mc_pause_thresh_q0q3);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                        val64, &bar0->mc_pause_thresh_q4q7);

        /* Set the time value  to be inserted in the pause frame generated
         * by Xframe */
        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                    &bar0->rmac_pause_cfg);
        if (hldev->config.mac.rmac_pause_gen_en)
                val64 |= XGE_HAL_RMAC_PAUSE_GEN_EN;
        else
                val64 &= ~(XGE_HAL_RMAC_PAUSE_GEN_EN);
        if (hldev->config.mac.rmac_pause_rcv_en)
                val64 |= XGE_HAL_RMAC_PAUSE_RCV_EN;
        else
                val64 &= ~(XGE_HAL_RMAC_PAUSE_RCV_EN);
        val64 &= ~(XGE_HAL_RMAC_PAUSE_HG_PTIME(0xffff));
        val64 |= XGE_HAL_RMAC_PAUSE_HG_PTIME(hldev->config.mac.rmac_pause_time);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                             &bar0->rmac_pause_cfg);

        val64 = 0;
        for (i = 0; i<4; i++) {
                val64 |=
                     (((u64)0xFF00|hldev->config.mac.mc_pause_threshold_q0q3)
                                                        <<(i*2*8));
        }
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                             &bar0->mc_pause_thresh_q0q3);

        val64 = 0;
        for (i = 0; i<4; i++) {
                val64 |=
                     (((u64)0xFF00|hldev->config.mac.mc_pause_threshold_q4q7)
                                                        <<(i*2*8));
        }
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                             &bar0->mc_pause_thresh_q4q7);
        xge_debug_device(XGE_TRACE, "%s", "pause frames configured");
}

/*
 * Herc's clock rate doubled, unless the slot is 33MHz.
 */
unsigned int __hal_fix_time_ival_herc(xge_hal_device_t *hldev,
                                      unsigned int time_ival)
{
        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA)
                return time_ival;

        xge_assert(xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC);

        if (hldev->bus_frequency != XGE_HAL_PCI_BUS_FREQUENCY_UNKNOWN &&
            hldev->bus_frequency != XGE_HAL_PCI_BUS_FREQUENCY_33MHZ)
                time_ival *= 2;

        return time_ival;
}


/*
 * __hal_device_bus_master_disable
 * @hldev: HAL device handle.
 *
 * Disable bus mastership.
 */
static void
__hal_device_bus_master_disable (xge_hal_device_t *hldev)
{
        u16 cmd;
        u16 bus_master = 4;

        xge_os_pci_read16(hldev->pdev, hldev->cfgh,
                        xge_offsetof(xge_hal_pci_config_le_t, command), &cmd);
        cmd &= ~bus_master;
        xge_os_pci_write16(hldev->pdev, hldev->cfgh,
                         xge_offsetof(xge_hal_pci_config_le_t, command), cmd);
}

/*
 * __hal_device_bus_master_enable
 * @hldev: HAL device handle.
 *
 * Disable bus mastership.
 */
static void
__hal_device_bus_master_enable (xge_hal_device_t *hldev)
{
        u16 cmd;
        u16 bus_master = 4;

        xge_os_pci_read16(hldev->pdev, hldev->cfgh,
                        xge_offsetof(xge_hal_pci_config_le_t, command), &cmd);

        /* already enabled? do nothing */
        if (cmd & bus_master)
                return;

        cmd |= bus_master;
        xge_os_pci_write16(hldev->pdev, hldev->cfgh,
                         xge_offsetof(xge_hal_pci_config_le_t, command), cmd);
}
/*
 * __hal_device_intr_mgmt
 * @hldev: HAL device handle.
 * @mask: mask indicating which Intr block must be modified.
 * @flag: if true - enable, otherwise - disable interrupts.
 *
 * Disable or enable device interrupts. Mask is used to specify
 * which hardware blocks should produce interrupts. For details
 * please refer to Xframe User Guide.
 */
static void
__hal_device_intr_mgmt(xge_hal_device_t *hldev, u64 mask, int flag)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64 = 0, temp64 = 0;
        u64 gim, gim_saved;

        gim_saved = gim = xge_os_pio_mem_read64(hldev->pdev,
                              hldev->regh0, &bar0->general_int_mask);

        /* Top level interrupt classification */
        /* PIC Interrupts */
        if ((mask & (XGE_HAL_TX_PIC_INTR/* | XGE_HAL_RX_PIC_INTR*/))) {
                /* Enable PIC Intrs in the general intr mask register */
                val64 = XGE_HAL_TXPIC_INT_M/* | XGE_HAL_PIC_RX_INT_M*/;
                if (flag) {
                        gim &= ~((u64) val64);
                        temp64 = xge_os_pio_mem_read64(hldev->pdev,
                                        hldev->regh0, &bar0->pic_int_mask);

                        temp64 &= ~XGE_HAL_PIC_INT_TX;
#ifdef  XGE_HAL_PROCESS_LINK_INT_IN_ISR
                        if (xge_hal_device_check_id(hldev) ==
                                                        XGE_HAL_CARD_HERC) {
                                temp64 &= ~XGE_HAL_PIC_INT_MISC;
                        }
#endif
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                             temp64, &bar0->pic_int_mask);
#ifdef  XGE_HAL_PROCESS_LINK_INT_IN_ISR
                        if (xge_hal_device_check_id(hldev) ==
                                                        XGE_HAL_CARD_HERC) {
                                /*
                                 * Unmask only Link Up interrupt
                                 */
                                temp64 = xge_os_pio_mem_read64(hldev->pdev,
                                        hldev->regh0, &bar0->misc_int_mask);
                                temp64 &= ~XGE_HAL_MISC_INT_REG_LINK_UP_INT;
                                xge_os_pio_mem_write64(hldev->pdev,
                                              hldev->regh0, temp64,
                                              &bar0->misc_int_mask);
                                xge_debug_device(XGE_TRACE,
                                        "unmask link up flag "XGE_OS_LLXFMT,
                                        (unsigned long long)temp64);
                        }
#endif
                } else { /* flag == 0 */

#ifdef  XGE_HAL_PROCESS_LINK_INT_IN_ISR
                        if (xge_hal_device_check_id(hldev) ==
                                                        XGE_HAL_CARD_HERC) {
                                /*
                                 * Mask both Link Up and Down interrupts
                                 */
                                temp64 = xge_os_pio_mem_read64(hldev->pdev,
                                        hldev->regh0, &bar0->misc_int_mask);
                                temp64 |= XGE_HAL_MISC_INT_REG_LINK_UP_INT;
                                temp64 |= XGE_HAL_MISC_INT_REG_LINK_DOWN_INT;
                                xge_os_pio_mem_write64(hldev->pdev,
                                              hldev->regh0, temp64,
                                              &bar0->misc_int_mask);
                                xge_debug_device(XGE_TRACE,
                                        "mask link up/down flag "XGE_OS_LLXFMT,
                                        (unsigned long long)temp64);
                        }
#endif
                        /* Disable PIC Intrs in the general intr mask
                         * register */
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                             XGE_HAL_ALL_INTRS_DIS,
                                             &bar0->pic_int_mask);
                        gim |= val64;
                }
        }

        /*  DMA Interrupts */
        /*  Enabling/Disabling Tx DMA interrupts */
        if (mask & XGE_HAL_TX_DMA_INTR) {
                /*  Enable TxDMA Intrs in the general intr mask register */
                val64 = XGE_HAL_TXDMA_INT_M;
                if (flag) {
                        gim &= ~((u64) val64);
                        /* Enable all TxDMA interrupts */
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                             0x0, &bar0->txdma_int_mask);
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                             0x0, &bar0->pfc_err_mask);
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                             0x0, &bar0->tda_err_mask);
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                             0x0, &bar0->pcc_err_mask);
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                             0x0, &bar0->tti_err_mask);
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                             0x0, &bar0->lso_err_mask);
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                             0x0, &bar0->tpa_err_mask);
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                             0x0, &bar0->sm_err_mask);

                } else { /* flag == 0 */

                        /*  Disable TxDMA Intrs in the general intr mask
                         *  register */
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                             XGE_HAL_ALL_INTRS_DIS,
                                             &bar0->txdma_int_mask);
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                             XGE_HAL_ALL_INTRS_DIS,
                                             &bar0->pfc_err_mask);

                        gim |= val64;
                }
        }

        /*  Enabling/Disabling Rx DMA interrupts */
        if (mask & XGE_HAL_RX_DMA_INTR) {
                /*  Enable RxDMA Intrs in the general intr mask register */
                val64 = XGE_HAL_RXDMA_INT_M;
                if (flag) {

                        gim &= ~((u64) val64);
                        /* All RxDMA block interrupts are disabled for now
                         * TODO */
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                             XGE_HAL_ALL_INTRS_DIS,
                                             &bar0->rxdma_int_mask);

                } else { /* flag == 0 */

                        /*  Disable RxDMA Intrs in the general intr mask
                         *  register */
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                             XGE_HAL_ALL_INTRS_DIS,
                                             &bar0->rxdma_int_mask);

                        gim |= val64;
                }
        }

        /*  MAC Interrupts */
        /*  Enabling/Disabling MAC interrupts */
        if (mask & (XGE_HAL_TX_MAC_INTR | XGE_HAL_RX_MAC_INTR)) {
                val64 = XGE_HAL_TXMAC_INT_M | XGE_HAL_RXMAC_INT_M;
                if (flag) {

                        gim &= ~((u64) val64);

                        /* All MAC block error inter. are disabled for now. */
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                             XGE_HAL_ALL_INTRS_DIS, &bar0->mac_int_mask);
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                             XGE_HAL_ALL_INTRS_DIS, &bar0->mac_rmac_err_mask);

                } else { /* flag == 0 */

                        /* Disable MAC Intrs in the general intr mask
                         * register */
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                             XGE_HAL_ALL_INTRS_DIS, &bar0->mac_int_mask);
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                             XGE_HAL_ALL_INTRS_DIS, &bar0->mac_rmac_err_mask);

                        gim |= val64;
                }
        }

        /*  XGXS Interrupts */
        if (mask & (XGE_HAL_TX_XGXS_INTR | XGE_HAL_RX_XGXS_INTR)) {
                val64 = XGE_HAL_TXXGXS_INT_M | XGE_HAL_RXXGXS_INT_M;
                if (flag) {

                        gim &= ~((u64) val64);
                        /* All XGXS block error interrupts are disabled for now
                         * TODO */
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                             XGE_HAL_ALL_INTRS_DIS, &bar0->xgxs_int_mask);

                } else { /* flag == 0 */

                        /* Disable MC Intrs in the general intr mask register */
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                XGE_HAL_ALL_INTRS_DIS, &bar0->xgxs_int_mask);

                        gim |= val64;
                }
        }

        /*  Memory Controller(MC) interrupts */
        if (mask & XGE_HAL_MC_INTR) {
                val64 = XGE_HAL_MC_INT_M;
                if (flag) {

                        gim &= ~((u64) val64);

                        /* Enable all MC blocks error interrupts */
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                     0x0ULL, &bar0->mc_int_mask);

                } else { /* flag == 0 */

                        /* Disable MC Intrs in the general intr mask
                         * register */
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                     XGE_HAL_ALL_INTRS_DIS, &bar0->mc_int_mask);

                        gim |= val64;
                }
        }


        /*  Tx traffic interrupts */
        if (mask & XGE_HAL_TX_TRAFFIC_INTR) {
                val64 = XGE_HAL_TXTRAFFIC_INT_M;
                if (flag) {

                        gim &= ~((u64) val64);

                        /* Enable all the Tx side interrupts */
                        /* '0' Enables all 64 TX interrupt levels. */
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, 0x0,
                                            &bar0->tx_traffic_mask);

                } else { /* flag == 0 */

                        /* Disable Tx Traffic Intrs in the general intr mask
                         * register. */
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                             XGE_HAL_ALL_INTRS_DIS,
                                             &bar0->tx_traffic_mask);
                        gim |= val64;
                }
        }

        /*  Rx traffic interrupts */
        if (mask & XGE_HAL_RX_TRAFFIC_INTR) {
                val64 = XGE_HAL_RXTRAFFIC_INT_M;
                if (flag) {
                        gim &= ~((u64) val64);
                        /* '0' Enables all 8 RX interrupt levels. */
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, 0x0,
                                            &bar0->rx_traffic_mask);

                } else { /* flag == 0 */

                        /* Disable Rx Traffic Intrs in the general intr mask
                         * register.
                         */
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                             XGE_HAL_ALL_INTRS_DIS,
                                             &bar0->rx_traffic_mask);

                        gim |= val64;
                }
        }

        /* Sched Timer interrupt */
        if (mask & XGE_HAL_SCHED_INTR) {
                if (flag) {
                        temp64 = xge_os_pio_mem_read64(hldev->pdev,
                                        hldev->regh0, &bar0->txpic_int_mask);
                        temp64 &= ~XGE_HAL_TXPIC_INT_SCHED_INTR;
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                        temp64, &bar0->txpic_int_mask);

                        xge_hal_device_sched_timer(hldev,
                                        hldev->config.sched_timer_us,
                                        hldev->config.sched_timer_one_shot);
                } else {
                        temp64 = xge_os_pio_mem_read64(hldev->pdev,
                                        hldev->regh0, &bar0->txpic_int_mask);
                        temp64 |= XGE_HAL_TXPIC_INT_SCHED_INTR;

                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                        temp64, &bar0->txpic_int_mask);

                        xge_hal_device_sched_timer(hldev,
                                        XGE_HAL_SCHED_TIMER_DISABLED,
                                        XGE_HAL_SCHED_TIMER_ON_SHOT_ENABLE);
                }
        }

        if (gim != gim_saved) {
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, gim,
                        &bar0->general_int_mask);
                xge_debug_device(XGE_TRACE, "general_int_mask updated "
                         XGE_OS_LLXFMT" => "XGE_OS_LLXFMT,
                        (unsigned long long)gim_saved, (unsigned long long)gim);
        }
}

/*
 * __hal_device_bimodal_configure
 * @hldev: HAL device handle.
 *
 * Bimodal parameters initialization.
 */
static void
__hal_device_bimodal_configure(xge_hal_device_t *hldev)
{
        int i;

        for (i=0; i<XGE_HAL_MAX_RING_NUM; i++) {
                xge_hal_tti_config_t *tti;
                xge_hal_rti_config_t *rti;

                if (!hldev->config.ring.queue[i].configured)
                        continue;
                rti = &hldev->config.ring.queue[i].rti;
                tti = &hldev->bimodal_tti[i];

                tti->enabled = 1;
                tti->urange_a = hldev->bimodal_urange_a_en * 10;
                tti->urange_b = 20;
                tti->urange_c = 30;
                tti->ufc_a = hldev->bimodal_urange_a_en * 8;
                tti->ufc_b = 16;
                tti->ufc_c = 32;
                tti->ufc_d = 64;
                tti->timer_val_us = hldev->bimodal_timer_val_us;
                tti->timer_ac_en = 1;
                tti->timer_ci_en = 0;

                rti->urange_a = 10;
                rti->urange_b = 20;
                rti->urange_c = 30;
                rti->ufc_a = 1; /* <= for netpipe type of tests */
                rti->ufc_b = 4;
                rti->ufc_c = 4;
                rti->ufc_d = 4; /* <= 99% of a bandwidth traffic counts here */
                rti->timer_ac_en = 1;
                rti->timer_val_us = 5; /* for optimal bus efficiency usage */
        }
}

/*
 * __hal_device_tti_apply
 * @hldev: HAL device handle.
 *
 * apply TTI configuration.
 */
static xge_hal_status_e
__hal_device_tti_apply(xge_hal_device_t *hldev, xge_hal_tti_config_t *tti,
                       int num, int runtime)
{
        u64 val64, data1 = 0, data2 = 0;
        xge_hal_pci_bar0_t *bar0;

        if (runtime)
                bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
        else
                bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;

        if (tti->timer_val_us) {
                unsigned int tx_interval;

                if (hldev->config.pci_freq_mherz) {
                        tx_interval = hldev->config.pci_freq_mherz *
                                        tti->timer_val_us / 64;
                        tx_interval =
                                __hal_fix_time_ival_herc(hldev,
                                                         tx_interval);
                } else {
                        tx_interval = tti->timer_val_us;
                }
                data1 |= XGE_HAL_TTI_DATA1_MEM_TX_TIMER_VAL(tx_interval);
                if (tti->timer_ac_en) {
                        data1 |= XGE_HAL_TTI_DATA1_MEM_TX_TIMER_AC_EN;
                }
                if (tti->timer_ci_en) {
                        data1 |= XGE_HAL_TTI_DATA1_MEM_TX_TIMER_CI_EN;
                }

                if (!runtime) {
                        xge_debug_device(XGE_TRACE, "TTI[%d] timer enabled to %d, ci %s",
                                  num, tx_interval, tti->timer_ci_en ?
                                  "enabled": "disabled");
                }
        }

        if (tti->urange_a ||
            tti->urange_b ||
            tti->urange_c ||
            tti->ufc_a ||
            tti->ufc_b ||
            tti->ufc_c ||
            tti->ufc_d ) {
                data1 |= XGE_HAL_TTI_DATA1_MEM_TX_URNG_A(tti->urange_a) |
                         XGE_HAL_TTI_DATA1_MEM_TX_URNG_B(tti->urange_b) |
                         XGE_HAL_TTI_DATA1_MEM_TX_URNG_C(tti->urange_c);

                data2 |= XGE_HAL_TTI_DATA2_MEM_TX_UFC_A(tti->ufc_a) |
                         XGE_HAL_TTI_DATA2_MEM_TX_UFC_B(tti->ufc_b) |
                         XGE_HAL_TTI_DATA2_MEM_TX_UFC_C(tti->ufc_c) |
                         XGE_HAL_TTI_DATA2_MEM_TX_UFC_D(tti->ufc_d);
        }

        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
            data1, &bar0->tti_data1_mem);
        (void)xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
            &bar0->tti_data1_mem);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
            data2, &bar0->tti_data2_mem);
        (void)xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
            &bar0->tti_data2_mem);
        xge_os_wmb();

        val64 = XGE_HAL_TTI_CMD_MEM_WE | XGE_HAL_TTI_CMD_MEM_STROBE_NEW_CMD |
              XGE_HAL_TTI_CMD_MEM_OFFSET(num);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                &bar0->tti_command_mem);

        if (!runtime && __hal_device_register_poll(hldev, &bar0->tti_command_mem,
                   0, XGE_HAL_TTI_CMD_MEM_STROBE_NEW_CMD,
                   XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
                /* upper layer may require to repeat */
                return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
        }

        if (!runtime) {
                xge_debug_device(XGE_TRACE, "TTI[%d] configured: tti_data1_mem 0x"
                   XGE_OS_LLXFMT, num,
                   (unsigned long long)xge_os_pio_mem_read64(hldev->pdev,
                   hldev->regh0, &bar0->tti_data1_mem));
        }

        return XGE_HAL_OK;
}

/*
 * __hal_device_tti_configure
 * @hldev: HAL device handle.
 *
 * TTI Initialization.
 * Initialize Transmit Traffic Interrupt Scheme.
 */
static xge_hal_status_e
__hal_device_tti_configure(xge_hal_device_t *hldev, int runtime)
{
        int i;

        for (i=0; i<XGE_HAL_MAX_FIFO_NUM; i++) {
                int j;

                if (!hldev->config.fifo.queue[i].configured)
                        continue;

                for (j=0; j<XGE_HAL_MAX_FIFO_TTI_NUM; j++) {
                        xge_hal_status_e status;

                        if (!hldev->config.fifo.queue[i].tti[j].enabled)
                                continue;

                        /* at least some TTI enabled. Record it. */
                        hldev->tti_enabled = 1;

                        status = __hal_device_tti_apply(hldev,
                                &hldev->config.fifo.queue[i].tti[j],
                                i * XGE_HAL_MAX_FIFO_TTI_NUM + j, runtime);
                        if (status != XGE_HAL_OK)
                                return status;
                }
        }

        /* processing bimodal TTIs */
        for (i=0; i<XGE_HAL_MAX_RING_NUM; i++) {
                xge_hal_status_e status;

                if (!hldev->bimodal_tti[i].enabled)
                        continue;

                /* at least some bimodal TTI enabled. Record it. */
                hldev->tti_enabled = 1;

                status = __hal_device_tti_apply(hldev, &hldev->bimodal_tti[i],
                                XGE_HAL_MAX_FIFO_TTI_RING_0 + i, runtime);
                if (status != XGE_HAL_OK)
                        return status;

        }

        return XGE_HAL_OK;
}

/*
 * __hal_device_rti_configure
 * @hldev: HAL device handle.
 *
 * RTI Initialization.
 * Initialize Receive Traffic Interrupt Scheme.
 */
xge_hal_status_e
__hal_device_rti_configure(xge_hal_device_t *hldev, int runtime)
{
        xge_hal_pci_bar0_t *bar0;
        u64 val64, data1 = 0, data2 = 0;
        int i;

        if (runtime) {
                /*
                 * we don't want to re-configure RTI in case when
                 * bimodal interrupts are in use. Instead reconfigure TTI
                 * with new RTI values.
                 */
                if (hldev->config.bimodal_interrupts) {
                        __hal_device_bimodal_configure(hldev);
                        return __hal_device_tti_configure(hldev, 1);
                }
                bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
        } else
                bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;

        for (i=0; i<XGE_HAL_MAX_RING_NUM; i++) {
                xge_hal_rti_config_t *rti = &hldev->config.ring.queue[i].rti;

                if (!hldev->config.ring.queue[i].configured)
                        continue;

                if (rti->timer_val_us) {
                        unsigned int rx_interval;

                        if (hldev->config.pci_freq_mherz) {
                                rx_interval = hldev->config.pci_freq_mherz *
                                                rti->timer_val_us / 8;
                                rx_interval =
                                        __hal_fix_time_ival_herc(hldev,
                                                                 rx_interval);
                        } else {
                                rx_interval = rti->timer_val_us;
                        }
                        data1 |=XGE_HAL_RTI_DATA1_MEM_RX_TIMER_VAL(rx_interval);
                        if (rti->timer_ac_en) {
                                data1 |= XGE_HAL_RTI_DATA1_MEM_RX_TIMER_AC_EN;
                        }
                        data1 |= XGE_HAL_RTI_DATA1_MEM_RX_TIMER_CI_EN;
                }

                if (rti->urange_a ||
                    rti->urange_b ||
                    rti->urange_c ||
                    rti->ufc_a ||
                    rti->ufc_b ||
                    rti->ufc_c ||
                    rti->ufc_d) {
                        data1 |=XGE_HAL_RTI_DATA1_MEM_RX_URNG_A(rti->urange_a) |
                                XGE_HAL_RTI_DATA1_MEM_RX_URNG_B(rti->urange_b) |
                                XGE_HAL_RTI_DATA1_MEM_RX_URNG_C(rti->urange_c);

                        data2 |= XGE_HAL_RTI_DATA2_MEM_RX_UFC_A(rti->ufc_a) |
                                 XGE_HAL_RTI_DATA2_MEM_RX_UFC_B(rti->ufc_b) |
                                 XGE_HAL_RTI_DATA2_MEM_RX_UFC_C(rti->ufc_c) |
                                 XGE_HAL_RTI_DATA2_MEM_RX_UFC_D(rti->ufc_d);
                }

                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                    data1, &bar0->rti_data1_mem);
                (void)xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                    &bar0->rti_data1_mem);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                    data2, &bar0->rti_data2_mem);
                (void)xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                    &bar0->rti_data2_mem);

                xge_os_wmb();

                val64 = XGE_HAL_RTI_CMD_MEM_WE |
                XGE_HAL_RTI_CMD_MEM_STROBE_NEW_CMD;
                val64 |= XGE_HAL_RTI_CMD_MEM_OFFSET(i);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                                    &bar0->rti_command_mem);

                if (!runtime && __hal_device_register_poll(hldev,
                        &bar0->rti_command_mem, 0,
                        XGE_HAL_RTI_CMD_MEM_STROBE_NEW_CMD,
                        XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
                        /* upper layer may require to repeat */
                        return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
                }

                if (!runtime) {
                        xge_debug_device(XGE_TRACE,
                          "RTI[%d] configured: rti_data1_mem 0x"XGE_OS_LLXFMT,
                          i,
                          (unsigned long long)xge_os_pio_mem_read64(hldev->pdev,
                                          hldev->regh0, &bar0->rti_data1_mem));
                }
        }

        return XGE_HAL_OK;
}


/* Constants to be programmed into the Xena's registers to configure
 * the XAUI. */
static u64 default_xena_mdio_cfg[] = {
        /* Reset PMA PLL */
        0xC001010000000000ULL, 0xC0010100000000E0ULL,
        0xC0010100008000E4ULL,
        /* Remove Reset from PMA PLL */
        0xC001010000000000ULL, 0xC0010100000000E0ULL,
        0xC0010100000000E4ULL,
        END_SIGN
};

static u64 default_herc_mdio_cfg[] = {
        END_SIGN
};

static u64 default_xena_dtx_cfg[] = {
        0x8000051500000000ULL, 0x80000515000000E0ULL,
        0x80000515D93500E4ULL, 0x8001051500000000ULL,
        0x80010515000000E0ULL, 0x80010515001E00E4ULL,
        0x8002051500000000ULL, 0x80020515000000E0ULL,
        0x80020515F21000E4ULL,
        /* Set PADLOOPBACKN */
        0x8002051500000000ULL, 0x80020515000000E0ULL,
        0x80020515B20000E4ULL, 0x8003051500000000ULL,
        0x80030515000000E0ULL, 0x80030515B20000E4ULL,
        0x8004051500000000ULL, 0x80040515000000E0ULL,
        0x80040515B20000E4ULL, 0x8005051500000000ULL,
        0x80050515000000E0ULL, 0x80050515B20000E4ULL,
        SWITCH_SIGN,
        /* Remove PADLOOPBACKN */
        0x8002051500000000ULL, 0x80020515000000E0ULL,
        0x80020515F20000E4ULL, 0x8003051500000000ULL,
        0x80030515000000E0ULL, 0x80030515F20000E4ULL,
        0x8004051500000000ULL, 0x80040515000000E0ULL,
        0x80040515F20000E4ULL, 0x8005051500000000ULL,
        0x80050515000000E0ULL, 0x80050515F20000E4ULL,
        END_SIGN
};

/*
static u64 default_herc_dtx_cfg[] = {
        0x80000515BA750000ULL, 0x80000515BA7500E0ULL,
        0x80000515BA750004ULL, 0x80000515BA7500E4ULL,
        0x80010515003F0000ULL, 0x80010515003F00E0ULL,
        0x80010515003F0004ULL, 0x80010515003F00E4ULL,
        0x80020515F2100000ULL, 0x80020515F21000E0ULL,
        0x80020515F2100004ULL, 0x80020515F21000E4ULL,
        END_SIGN
};
*/

static u64 default_herc_dtx_cfg[] = {
    0x8000051536750000ULL, 0x80000515367500E0ULL,
    0x8000051536750004ULL, 0x80000515367500E4ULL,

    0x80010515003F0000ULL, 0x80010515003F00E0ULL,
    0x80010515003F0004ULL, 0x80010515003F00E4ULL,

    0x801205150D440000ULL, 0x801205150D4400E0ULL,
    0x801205150D440004ULL, 0x801205150D4400E4ULL,

    0x80020515F2100000ULL, 0x80020515F21000E0ULL,
    0x80020515F2100004ULL, 0x80020515F21000E4ULL,
    END_SIGN
};


void
__hal_serial_mem_write64(xge_hal_device_t *hldev, u64 value, u64 *reg)
{
        __hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0,
                    (u32)(value>>32), reg);
        xge_os_wmb();
        __hal_pio_mem_write32_lower(hldev->pdev, hldev->regh0,
                    (u32)value, reg);
        xge_os_wmb();
        xge_os_mdelay(1);
}

u64
__hal_serial_mem_read64(xge_hal_device_t *hldev, u64 *reg)
{
        u64 val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                        reg);
        xge_os_mdelay(1);
        return val64;
}

/*
 * __hal_device_xaui_configure
 * @hldev: HAL device handle.
 *
 * Configure XAUI Interface of Xena.
 *
 * To Configure the Xena's XAUI, one has to write a series
 * of 64 bit values into two registers in a particular
 * sequence. Hence a macro 'SWITCH_SIGN' has been defined
 * which will be defined in the array of configuration values
 * (default_dtx_cfg & default_mdio_cfg) at appropriate places
 * to switch writing from one regsiter to another. We continue
 * writing these values until we encounter the 'END_SIGN' macro.
 * For example, After making a series of 21 writes into
 * dtx_control register the 'SWITCH_SIGN' appears and hence we
 * start writing into mdio_control until we encounter END_SIGN.
 */
static void
__hal_device_xaui_configure(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        int mdio_cnt = 0, dtx_cnt = 0;
        u64 *default_dtx_cfg = NULL, *default_mdio_cfg = NULL;

        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA) {
                default_dtx_cfg = default_xena_dtx_cfg;
                default_mdio_cfg = default_xena_mdio_cfg;
        } else if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
                default_dtx_cfg = default_herc_dtx_cfg;
                default_mdio_cfg = default_herc_mdio_cfg;
        } else {
                xge_assert(default_dtx_cfg);
    return;
  }

        do {
            dtx_cfg:
                while (default_dtx_cfg[dtx_cnt] != END_SIGN) {
                        if (default_dtx_cfg[dtx_cnt] == SWITCH_SIGN) {
                                dtx_cnt++;
                                goto mdio_cfg;
                        }
                        __hal_serial_mem_write64(hldev, default_dtx_cfg[dtx_cnt],
                                               &bar0->dtx_control);
                        dtx_cnt++;
                }
            mdio_cfg:
                while (default_mdio_cfg[mdio_cnt] != END_SIGN) {
                        if (default_mdio_cfg[mdio_cnt] == SWITCH_SIGN) {
                                mdio_cnt++;
                                goto dtx_cfg;
                        }
                        __hal_serial_mem_write64(hldev, default_mdio_cfg[mdio_cnt],
                                &bar0->mdio_control);
                        mdio_cnt++;
                }
        } while ( !((default_dtx_cfg[dtx_cnt] == END_SIGN) &&
                    (default_mdio_cfg[mdio_cnt] == END_SIGN)) );

        xge_debug_device(XGE_TRACE, "%s", "XAUI interface configured");
}

/*
 * __hal_device_mac_link_util_set
 * @hldev: HAL device handle.
 *
 * Set sampling rate to calculate link utilization.
 */
static void
__hal_device_mac_link_util_set(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;

        val64 = XGE_HAL_MAC_TX_LINK_UTIL_VAL(
                        hldev->config.mac.tmac_util_period) |
                XGE_HAL_MAC_RX_LINK_UTIL_VAL(
                        hldev->config.mac.rmac_util_period);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                             &bar0->mac_link_util);
        xge_debug_device(XGE_TRACE, "%s",
                          "bandwidth link utilization configured");
}

/*
 * __hal_device_set_swapper
 * @hldev: HAL device handle.
 *
 * Set the Xframe's byte "swapper" in accordance with
 * endianness of the host.
 */
xge_hal_status_e
__hal_device_set_swapper(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;

        /*
         * from 32bit errarta:
         *
         * The SWAPPER_CONTROL register determines how the adapter accesses
         * host memory as well as how it responds to read and write requests
         * from the host system. Writes to this register should be performed
         * carefully, since the byte swappers could reverse the order of bytes.
         * When configuring this register keep in mind that writes to the PIF
         * read and write swappers could reverse the order of the upper and
         * lower 32-bit words. This means that the driver may have to write
         * to the upper 32 bits of the SWAPPER_CONTROL twice in order to
         * configure the entire register. */

        /*
         * The device by default set to a big endian format, so a big endian
         * driver need not set anything.
         */

#if defined(XGE_HAL_CUSTOM_HW_SWAPPER)

        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                        0xffffffffffffffffULL, &bar0->swapper_ctrl);

        val64 = XGE_HAL_CUSTOM_HW_SWAPPER;

        xge_os_wmb();
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                             &bar0->swapper_ctrl);

        xge_debug_device(XGE_TRACE, "using custom HW swapper 0x"XGE_OS_LLXFMT,
                        (unsigned long long)val64);

#elif !defined(XGE_OS_HOST_BIG_ENDIAN)

        /*
         * Initially we enable all bits to make it accessible by the driver,
         * then we selectively enable only those bits that we want to set.
         * i.e. force swapper to swap for the first time since second write
         * will overwrite with the final settings.
         *
         * Use only for little endian platforms.
         */
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                        0xffffffffffffffffULL, &bar0->swapper_ctrl);
        xge_os_wmb();
        val64 = (XGE_HAL_SWAPPER_CTRL_PIF_R_FE |
                 XGE_HAL_SWAPPER_CTRL_PIF_R_SE |
                 XGE_HAL_SWAPPER_CTRL_PIF_W_FE |
                 XGE_HAL_SWAPPER_CTRL_PIF_W_SE |
                 XGE_HAL_SWAPPER_CTRL_RTH_FE |
                 XGE_HAL_SWAPPER_CTRL_RTH_SE |
                 XGE_HAL_SWAPPER_CTRL_TXP_FE |
                 XGE_HAL_SWAPPER_CTRL_TXP_SE |
                 XGE_HAL_SWAPPER_CTRL_TXD_R_FE |
                 XGE_HAL_SWAPPER_CTRL_TXD_R_SE |
                 XGE_HAL_SWAPPER_CTRL_TXD_W_FE |
                 XGE_HAL_SWAPPER_CTRL_TXD_W_SE |
                 XGE_HAL_SWAPPER_CTRL_TXF_R_FE |
                 XGE_HAL_SWAPPER_CTRL_RXD_R_FE |
                 XGE_HAL_SWAPPER_CTRL_RXD_R_SE |
                 XGE_HAL_SWAPPER_CTRL_RXD_W_FE |
                 XGE_HAL_SWAPPER_CTRL_RXD_W_SE |
                 XGE_HAL_SWAPPER_CTRL_RXF_W_FE |
                 XGE_HAL_SWAPPER_CTRL_XMSI_FE |
                 XGE_HAL_SWAPPER_CTRL_STATS_FE | XGE_HAL_SWAPPER_CTRL_STATS_SE);

        /*
        if (hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSIX) {
                 val64 |= XGE_HAL_SWAPPER_CTRL_XMSI_SE;
        } */
        __hal_pio_mem_write32_lower(hldev->pdev, hldev->regh0, (u32)val64,
                             &bar0->swapper_ctrl);
        xge_os_wmb();
        __hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0, (u32)(val64>>32),
                             &bar0->swapper_ctrl);
        xge_os_wmb();
        __hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0, (u32)(val64>>32),
                             &bar0->swapper_ctrl);
        xge_debug_device(XGE_TRACE, "%s", "using little endian set");
#endif

        /*  Verifying if endian settings are accurate by reading a feedback
         *  register.  */
        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                    &bar0->pif_rd_swapper_fb);
        if (val64 != XGE_HAL_IF_RD_SWAPPER_FB) {
                xge_debug_device(XGE_ERR, "pif_rd_swapper_fb read "XGE_OS_LLXFMT,
                          (unsigned long long) val64);
                return XGE_HAL_ERR_SWAPPER_CTRL;
        }

        xge_debug_device(XGE_TRACE, "%s", "be/le swapper enabled");

        return XGE_HAL_OK;
}

/*
 * __hal_device_rts_mac_configure - Configure RTS steering based on
 * destination mac address.
 * @hldev: HAL device handle.
 *
 */
xge_hal_status_e
__hal_device_rts_mac_configure(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;

        if (!hldev->config.rts_mac_en) {
                return XGE_HAL_OK;
        }

        /*
        * Set the receive traffic steering mode from default(classic)
        * to enhanced.
        */
        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                        &bar0->rts_ctrl);
        val64 |=  XGE_HAL_RTS_CTRL_ENHANCED_MODE;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                val64, &bar0->rts_ctrl);
        return XGE_HAL_OK;
}

/*
 * __hal_device_rts_port_configure - Configure RTS steering based on
 * destination or source port number.
 * @hldev: HAL device handle.
 *
 */
xge_hal_status_e
__hal_device_rts_port_configure(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;
        int rnum;

        if (!hldev->config.rts_port_en) {
                return XGE_HAL_OK;
        }

        /*
         * Set the receive traffic steering mode from default(classic)
         * to enhanced.
         */
        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                        &bar0->rts_ctrl);
        val64 |=  XGE_HAL_RTS_CTRL_ENHANCED_MODE;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                val64, &bar0->rts_ctrl);

        /*
         * Initiate port steering according to per-ring configuration
         */
        for (rnum = 0; rnum < XGE_HAL_MAX_RING_NUM; rnum++) {
                int pnum;
                xge_hal_ring_queue_t *queue = &hldev->config.ring.queue[rnum];

                if (!queue->configured || queue->rts_port_en)
                        continue;

                for (pnum = 0; pnum < XGE_HAL_MAX_STEERABLE_PORTS; pnum++) {
                        xge_hal_rts_port_t *port = &queue->rts_ports[pnum];

                        /*
                         * Skip and clear empty ports
                         */
                        if (!port->num) {
                                /*
                                 * Clear CAM memory
                                 */
                                xge_os_pio_mem_write64(hldev->pdev,
                                       hldev->regh0, 0ULL,
                                       &bar0->rts_pn_cam_data);

                                val64 = BIT(7) | BIT(15);
                        } else {
                                /*
                                 * Assign new Port values according
                                 * to configuration
                                 */
                                val64 = vBIT(port->num,8,16) |
                                        vBIT(rnum,37,3) | BIT(63);
                                if (port->src)
                                        val64 = BIT(47);
                                if (!port->udp)
                                        val64 = BIT(7);
                                xge_os_pio_mem_write64(hldev->pdev,
                                               hldev->regh0, val64,
                                               &bar0->rts_pn_cam_data);

                                val64 = BIT(7) | BIT(15) | vBIT(pnum,24,8);
                        }

                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                               val64, &bar0->rts_pn_cam_ctrl);

                        /* poll until done */
                        if (__hal_device_register_poll(hldev,
                               &bar0->rts_pn_cam_ctrl, 0,
                               XGE_HAL_RTS_PN_CAM_CTRL_STROBE_BEING_EXECUTED,
                               XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) !=
                                                                XGE_HAL_OK) {
                                /* upper layer may require to repeat */
                                return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
                        }
                }
        }
        return XGE_HAL_OK;
}

/*
 * __hal_device_rts_qos_configure - Configure RTS steering based on
 * qos.
 * @hldev: HAL device handle.
 *
 */
xge_hal_status_e
__hal_device_rts_qos_configure(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;
        int j, rx_ring_num;

        if (!hldev->config.rts_qos_en) {
                return XGE_HAL_OK;
        }

        /* First clear the RTS_DS_MEM_DATA */
        val64 = 0;
        for (j = 0; j < 64; j++ )
        {
                /* First clear the value */
                val64 = XGE_HAL_RTS_DS_MEM_DATA(0);

                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                                       &bar0->rts_ds_mem_data);

                val64 = XGE_HAL_RTS_DS_MEM_CTRL_WE |
                        XGE_HAL_RTS_DS_MEM_CTRL_STROBE_NEW_CMD |
                        XGE_HAL_RTS_DS_MEM_CTRL_OFFSET ( j );

                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                                       &bar0->rts_ds_mem_ctrl);


                /* poll until done */
                if (__hal_device_register_poll(hldev,
                       &bar0->rts_ds_mem_ctrl, 0,
                       XGE_HAL_RTS_DS_MEM_CTRL_STROBE_CMD_BEING_EXECUTED,
                       XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
                        /* upper layer may require to repeat */
                        return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
                }

        }

        rx_ring_num = 0;
        for (j = 0; j < XGE_HAL_MAX_RING_NUM; j++) {
                if (hldev->config.ring.queue[j].configured)
                        rx_ring_num++;
        }

        switch (rx_ring_num) {
        case 1:
                val64 = 0x0;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_0);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_1);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_2);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_3);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_4);
                break;
        case 2:
                val64 = 0x0001000100010001ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_0);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_1);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_2);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_3);
                val64 = 0x0001000100000000ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_4);
                break;
        case 3:
                val64 = 0x0001020001020001ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_0);
                val64 = 0x0200010200010200ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_1);
                val64 = 0x0102000102000102ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_2);
                val64 = 0x0001020001020001ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_3);
                val64 = 0x0200010200000000ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_4);
                break;
        case 4:
                val64 = 0x0001020300010203ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_0);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_1);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_2);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_3);
                val64 = 0x0001020300000000ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_4);
                break;
        case 5:
                val64 = 0x0001020304000102ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_0);
                val64 = 0x0304000102030400ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_1);
                val64 = 0x0102030400010203ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_2);
                val64 = 0x0400010203040001ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_3);
                val64 = 0x0203040000000000ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_4);
                break;
        case 6:
                val64 = 0x0001020304050001ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_0);
                val64 = 0x0203040500010203ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_1);
                val64 = 0x0405000102030405ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_2);
                val64 = 0x0001020304050001ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_3);
                val64 = 0x0203040500000000ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_4);
                break;
        case 7:
                val64 = 0x0001020304050600ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_0);
                val64 = 0x0102030405060001ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_1);
                val64 = 0x0203040506000102ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_2);
                val64 = 0x0304050600010203ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_3);
                val64 = 0x0405060000000000ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_4);
                break;
        case 8:
                val64 = 0x0001020304050607ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_0);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_1);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_2);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_3);
                val64 = 0x0001020300000000ULL;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_4);
                break;
        }

        return XGE_HAL_OK;
}

/*
 * xge__hal_device_rts_mac_enable
 *
 * @devh: HAL device handle.
 * @index: index number where the MAC addr will be stored
 * @macaddr: MAC address
 *
 * - Enable RTS steering for the given MAC address. This function has to be
 * called with lock acquired.
 *
 * NOTE:
 * 1. ULD has to call this function with the index value which
 *    statisfies the following condition:
 *      ring_num = (index % 8)
 * 2.ULD also needs to make sure that the index is not
 *   occupied by any MAC address. If that index has any MAC address
 *   it will be overwritten and HAL will not check for it.
 *
 */
xge_hal_status_e
xge_hal_device_rts_mac_enable(xge_hal_device_h devh, int index, macaddr_t macaddr)
{
        int max_addr = XGE_HAL_MAX_MAC_ADDRESSES;
        xge_hal_status_e status;

        xge_hal_device_t *hldev = (xge_hal_device_t *)devh;

        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC)
                max_addr = XGE_HAL_MAX_MAC_ADDRESSES_HERC;

        if ( index >= max_addr )
                return XGE_HAL_ERR_OUT_OF_MAC_ADDRESSES;

        /*
         * Set the MAC address at the given location marked by index.
         */
        status = xge_hal_device_macaddr_set(hldev, index, macaddr);
        if (status != XGE_HAL_OK) {
                xge_debug_device(XGE_ERR, "%s",
                        "Not able to set the mac addr");
                return status;
        }

        return xge_hal_device_rts_section_enable(hldev, index);
}

/*
 * xge__hal_device_rts_mac_disable
 * @hldev: HAL device handle.
 * @index: index number where to disable the MAC addr
 *
 * Disable RTS Steering based on the MAC address.
 * This function should be called with lock acquired.
 *
 */
xge_hal_status_e
xge_hal_device_rts_mac_disable(xge_hal_device_h devh, int index)
{
        xge_hal_status_e status;
        u8 macaddr[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
        int max_addr = XGE_HAL_MAX_MAC_ADDRESSES;

        xge_hal_device_t *hldev = (xge_hal_device_t *)devh;

        xge_debug_ll(XGE_TRACE, "the index value is %d ", index);

        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC)
                max_addr = XGE_HAL_MAX_MAC_ADDRESSES_HERC;

        if ( index >= max_addr )
                return XGE_HAL_ERR_OUT_OF_MAC_ADDRESSES;

        /*
         * Disable MAC address @ given index location
         */
        status = xge_hal_device_macaddr_set(hldev, index, macaddr);
        if (status != XGE_HAL_OK) {
                xge_debug_device(XGE_ERR, "%s",
                        "Not able to set the mac addr");
                return status;
        }

        return XGE_HAL_OK;
}


/*
 * __hal_device_rth_configure - Configure RTH for the device
 * @hldev: HAL device handle.
 *
 * Using IT (Indirection Table).
 */
xge_hal_status_e
__hal_device_rth_it_configure(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;
        int rings[XGE_HAL_MAX_RING_NUM]={0};
        int rnum;
        int rmax;
        int buckets_num;
        int bucket;

        if (!hldev->config.rth_en) {
                return XGE_HAL_OK;
        }

        /*
         * Set the receive traffic steering mode from default(classic)
         * to enhanced.
         */
        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                      &bar0->rts_ctrl);
        val64 |=  XGE_HAL_RTS_CTRL_ENHANCED_MODE;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                               val64, &bar0->rts_ctrl);

        buckets_num = (1 << hldev->config.rth_bucket_size);

        rmax=0;
        for (rnum = 0; rnum < XGE_HAL_MAX_RING_NUM; rnum++) {
                if (hldev->config.ring.queue[rnum].configured &&
                                hldev->config.ring.queue[rnum].rth_en)
                                rings[rmax++] = rnum;
        }

        rnum = 0;
        /* for starters: fill in all the buckets with rings "equally" */
        for (bucket = 0; bucket < buckets_num; bucket++) {

            if (rnum == rmax)
           rnum = 0;

                /* write data */
                val64 = XGE_HAL_RTS_RTH_MAP_MEM_DATA_ENTRY_EN |
                        XGE_HAL_RTS_RTH_MAP_MEM_DATA(rings[rnum]);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                                     &bar0->rts_rth_map_mem_data);

                /* execute */
                val64 = XGE_HAL_RTS_RTH_MAP_MEM_CTRL_WE |
                        XGE_HAL_RTS_RTH_MAP_MEM_CTRL_STROBE |
                        XGE_HAL_RTS_RTH_MAP_MEM_CTRL_OFFSET(bucket);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                                     &bar0->rts_rth_map_mem_ctrl);

                /* poll until done */
                if (__hal_device_register_poll(hldev,
                        &bar0->rts_rth_map_mem_ctrl, 0,
                        XGE_HAL_RTS_RTH_MAP_MEM_CTRL_STROBE,
                        XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
                        return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
                }

        rnum++;
        }

        val64 = XGE_HAL_RTS_RTH_EN;
        val64 |= XGE_HAL_RTS_RTH_BUCKET_SIZE(hldev->config.rth_bucket_size);
        val64 |= XGE_HAL_RTS_RTH_TCP_IPV4_EN | XGE_HAL_RTS_RTH_UDP_IPV4_EN | XGE_HAL_RTS_RTH_IPV4_EN |
                         XGE_HAL_RTS_RTH_TCP_IPV6_EN |XGE_HAL_RTS_RTH_UDP_IPV6_EN | XGE_HAL_RTS_RTH_IPV6_EN |
                         XGE_HAL_RTS_RTH_TCP_IPV6_EX_EN | XGE_HAL_RTS_RTH_UDP_IPV6_EX_EN | XGE_HAL_RTS_RTH_IPV6_EX_EN;

        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                             &bar0->rts_rth_cfg);

        xge_debug_device(XGE_TRACE, "RTH configured, bucket_size %d",
                          hldev->config.rth_bucket_size);

        return XGE_HAL_OK;
}


/*
 * __hal_spdm_entry_add - Add a new entry to the SPDM table.
 *
 * Add a new entry to the SPDM table
 *
 * This function add a new entry to the SPDM table.
 *
 * Note:
 *   This function should be called with spdm_lock.
 *
 * See also: xge_hal_spdm_entry_add , xge_hal_spdm_entry_remove.
 */
static xge_hal_status_e
__hal_spdm_entry_add(xge_hal_device_t *hldev, xge_hal_ipaddr_t *src_ip,
                xge_hal_ipaddr_t *dst_ip, u16 l4_sp, u16 l4_dp, u8 is_tcp,
                u8 is_ipv4, u8 tgt_queue, u32 jhash_value, u16 spdm_entry)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;
        u64 spdm_line_arr[8];
        u8 line_no;

        /*
         * Clear the SPDM READY bit
         */
        val64 = XGE_HAL_RX_PIC_INT_REG_SPDM_READY;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                               &bar0->rxpic_int_reg);

        xge_debug_device(XGE_TRACE,
                        "L4 SP %x:DP %x: hash %x tgt_queue %d ",
                        l4_sp, l4_dp, jhash_value, tgt_queue);

        xge_os_memzero(&spdm_line_arr, sizeof(spdm_line_arr));

        /*
         * Construct the SPDM entry.
         */
        spdm_line_arr[0] = vBIT(l4_sp,0,16) |
                           vBIT(l4_dp,16,32) |
                           vBIT(tgt_queue,53,3) |
                           vBIT(is_tcp,59,1) |
                           vBIT(is_ipv4,63,1);


        if (is_ipv4) {
                spdm_line_arr[1] = vBIT(src_ip->ipv4.addr,0,32) |
                                   vBIT(dst_ip->ipv4.addr,32,32);

        } else {
                xge_os_memcpy(&spdm_line_arr[1], &src_ip->ipv6.addr[0], 8);
                xge_os_memcpy(&spdm_line_arr[2], &src_ip->ipv6.addr[1], 8);
                xge_os_memcpy(&spdm_line_arr[3], &dst_ip->ipv6.addr[0], 8);
                xge_os_memcpy(&spdm_line_arr[4], &dst_ip->ipv6.addr[1], 8);
        }

        spdm_line_arr[7] = vBIT(jhash_value,0,32) |
                                BIT(63);  /* entry enable bit */

        /*
         * Add the entry to the SPDM table
         */
        for(line_no = 0; line_no < 8; line_no++) {
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                spdm_line_arr[line_no],
                                (void *)((char *)hldev->spdm_mem_base +
                                                (spdm_entry * 64) +
                                                (line_no * 8)));
        }

        /*
         * Wait for the operation to be completed.
         */
        if (__hal_device_register_poll(hldev, &bar0->rxpic_int_reg, 1,
                        XGE_HAL_RX_PIC_INT_REG_SPDM_READY,
                        XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
                return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
        }

        /*
         * Add this information to a local SPDM table. The purpose of
         * maintaining a local SPDM table is to avoid a search in the
         * adapter SPDM table for spdm entry lookup which is very costly
         * in terms of time.
         */
        hldev->spdm_table[spdm_entry]->in_use = 1;
        xge_os_memcpy(&hldev->spdm_table[spdm_entry]->src_ip, src_ip,
                    sizeof(xge_hal_ipaddr_t));
        xge_os_memcpy(&hldev->spdm_table[spdm_entry]->dst_ip, dst_ip,
                    sizeof(xge_hal_ipaddr_t));
        hldev->spdm_table[spdm_entry]->l4_sp = l4_sp;
        hldev->spdm_table[spdm_entry]->l4_dp = l4_dp;
        hldev->spdm_table[spdm_entry]->is_tcp = is_tcp;
        hldev->spdm_table[spdm_entry]->is_ipv4 = is_ipv4;
        hldev->spdm_table[spdm_entry]->tgt_queue = tgt_queue;
        hldev->spdm_table[spdm_entry]->jhash_value = jhash_value;
        hldev->spdm_table[spdm_entry]->spdm_entry = spdm_entry;

        return XGE_HAL_OK;
}

/*
 * __hal_device_rth_spdm_configure - Configure RTH for the device
 * @hldev: HAL device handle.
 *
 * Using SPDM (Socket-Pair Direct Match).
 */
xge_hal_status_e
__hal_device_rth_spdm_configure(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)hldev->bar0;
        u64 val64;
        u8 spdm_bar_num;
        u32 spdm_bar_offset;
        int spdm_table_size;
        int i;

        if (!hldev->config.rth_spdm_en) {
                return XGE_HAL_OK;
        }

        /*
         * Retrieve the base address of SPDM Table.
         */
        val64 = xge_os_pio_mem_read64(hldev->pdev,
                        hldev->regh0, &bar0->spdm_bir_offset);

        spdm_bar_num    = XGE_HAL_SPDM_PCI_BAR_NUM(val64);
        spdm_bar_offset = XGE_HAL_SPDM_PCI_BAR_OFFSET(val64);


        /*
         * spdm_bar_num specifies the PCI bar num register used to
         * address the memory space. spdm_bar_offset specifies the offset
         * of the SPDM memory with in the bar num memory space.
         */
        switch (spdm_bar_num) {
                case 0:
                {
                        hldev->spdm_mem_base = (char *)bar0 +
                                                (spdm_bar_offset * 8);
                        break;
                }
                case 1:
                {
                        char *bar1 = (char *)hldev->bar1;
                        hldev->spdm_mem_base = bar1 + (spdm_bar_offset * 8);
                        break;
                }
                default:
                        xge_assert(((spdm_bar_num != 0) && (spdm_bar_num != 1)));
        }

        /*
         * Retrieve the size of SPDM table(number of entries).
         */
        val64 = xge_os_pio_mem_read64(hldev->pdev,
                        hldev->regh0, &bar0->spdm_structure);
        hldev->spdm_max_entries = XGE_HAL_SPDM_MAX_ENTRIES(val64);


        spdm_table_size = hldev->spdm_max_entries *
                                        sizeof(xge_hal_spdm_entry_t);
        if (hldev->spdm_table == NULL) {
                void *mem;

                /*
                 * Allocate memory to hold the copy of SPDM table.
                 */
                if ((hldev->spdm_table = (xge_hal_spdm_entry_t **)
                                        xge_os_malloc(
                                         hldev->pdev,
                                         (sizeof(xge_hal_spdm_entry_t *) *
                                         hldev->spdm_max_entries))) == NULL) {
                        return XGE_HAL_ERR_OUT_OF_MEMORY;
                }

                if ((mem = xge_os_malloc(hldev->pdev, spdm_table_size)) == NULL)
                {
                        xge_os_free(hldev->pdev, hldev->spdm_table,
                                  (sizeof(xge_hal_spdm_entry_t *) *
                                         hldev->spdm_max_entries));
                        return XGE_HAL_ERR_OUT_OF_MEMORY;
                }

                xge_os_memzero(mem, spdm_table_size);
                for (i = 0; i < hldev->spdm_max_entries; i++) {
                        hldev->spdm_table[i] = (xge_hal_spdm_entry_t *)
                                        ((char *)mem +
                                         i * sizeof(xge_hal_spdm_entry_t));
                }
                xge_os_spin_lock_init(&hldev->spdm_lock, hldev->pdev);
        } else {
                /*
                 * We are here because the host driver tries to
                 * do a soft reset on the device.
                 * Since the device soft reset clears the SPDM table, copy
                 * the entries from the local SPDM table to the actual one.
                 */
                xge_os_spin_lock(&hldev->spdm_lock);
                for (i = 0; i < hldev->spdm_max_entries; i++) {
                        xge_hal_spdm_entry_t *spdm_entry = hldev->spdm_table[i];

                        if (spdm_entry->in_use) {
                                if (__hal_spdm_entry_add(hldev,
                                                         &spdm_entry->src_ip,
                                                         &spdm_entry->dst_ip,
                                                         spdm_entry->l4_sp,
                                                         spdm_entry->l4_dp,
                                                         spdm_entry->is_tcp,
                                                         spdm_entry->is_ipv4,
                                                         spdm_entry->tgt_queue,
                                                         spdm_entry->jhash_value,
                                                         spdm_entry->spdm_entry)
                                                != XGE_HAL_OK) {
                                        /* Log an warning */
                                        xge_debug_device(XGE_ERR,
                                                "SPDM table update from local"
                                                " memory failed");
                                }
                        }
                }
                xge_os_spin_unlock(&hldev->spdm_lock);
        }

        /*
         * Set the receive traffic steering mode from default(classic)
         * to enhanced.
         */
        val64 = xge_os_pio_mem_read64(hldev->pdev,
                                    hldev->regh0, &bar0->rts_ctrl);
        val64 |=  XGE_HAL_RTS_CTRL_ENHANCED_MODE;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                             val64, &bar0->rts_ctrl);

        /*
         * We may not need to configure rts_rth_jhash_cfg register as the
         * default values are good enough to calculate the hash.
         */

        /*
         * As of now, set all the rth mask registers to zero. TODO.
         */
        for(i = 0; i < 5; i++) {
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                     0, &bar0->rts_rth_hash_mask[i]);
        }

        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                             0, &bar0->rts_rth_hash_mask_5);

        if (hldev->config.rth_spdm_use_l4) {
                val64 = XGE_HAL_RTH_STATUS_SPDM_USE_L4;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                     val64, &bar0->rts_rth_status);
        }

        val64 = XGE_HAL_RTS_RTH_EN;
        val64 |= XGE_HAL_RTS_RTH_IPV4_EN | XGE_HAL_RTS_RTH_TCP_IPV4_EN;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                             &bar0->rts_rth_cfg);


        return XGE_HAL_OK;
}

/*
 * __hal_device_pci_init
 * @hldev: HAL device handle.
 *
 * Initialize certain PCI/PCI-X configuration registers
 * with recommended values. Save config space for future hw resets.
 */
static void
__hal_device_pci_init(xge_hal_device_t *hldev)
{
        int i, pcisize = 0;
        u16 cmd = 0;
        u8  val;

        /* Store PCI device ID and revision for future references where in we
         * decide Xena revision using PCI sub system ID */
        xge_os_pci_read16(hldev->pdev,hldev->cfgh,
                        xge_offsetof(xge_hal_pci_config_le_t, device_id),
                        &hldev->device_id);
        xge_os_pci_read8(hldev->pdev,hldev->cfgh,
                        xge_offsetof(xge_hal_pci_config_le_t, revision),
                        &hldev->revision);

        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC)
                pcisize = XGE_HAL_PCISIZE_HERC;
        else if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA)
                pcisize = XGE_HAL_PCISIZE_XENA;

        /* save original PCI config space to restore it on device_terminate() */
        for (i = 0; i < pcisize; i++) {
                xge_os_pci_read32(hldev->pdev, hldev->cfgh, i*4,
                                (u32*)&hldev->pci_config_space_bios + i);
        }

        /* Set the PErr Repconse bit and SERR in PCI command register. */
        xge_os_pci_read16(hldev->pdev, hldev->cfgh,
                        xge_offsetof(xge_hal_pci_config_le_t, command), &cmd);
        cmd |= 0x140;
        xge_os_pci_write16(hldev->pdev, hldev->cfgh,
                         xge_offsetof(xge_hal_pci_config_le_t, command), cmd);

        /* Set user spcecified value for the PCI Latency Timer */
        if (hldev->config.latency_timer &&
            hldev->config.latency_timer != XGE_HAL_USE_BIOS_DEFAULT_LATENCY) {
                xge_os_pci_write8(hldev->pdev, hldev->cfgh,
                         xge_offsetof(xge_hal_pci_config_le_t,
                         latency_timer),
                         (u8)hldev->config.latency_timer);
        }
        /* Read back latency timer to reflect it into user level */
        xge_os_pci_read8(hldev->pdev, hldev->cfgh,
                xge_offsetof(xge_hal_pci_config_le_t, latency_timer), &val);
        hldev->config.latency_timer = val;

        /* Enable Data Parity Error Recovery in PCI-X command register. */
        xge_os_pci_read16(hldev->pdev, hldev->cfgh,
                xge_offsetof(xge_hal_pci_config_le_t, pcix_command), &cmd);
        cmd |= 1;
        xge_os_pci_write16(hldev->pdev, hldev->cfgh,
                 xge_offsetof(xge_hal_pci_config_le_t, pcix_command), cmd);

        /* Set MMRB count in PCI-X command register. */
        if (hldev->config.mmrb_count != XGE_HAL_DEFAULT_BIOS_MMRB_COUNT) {
                cmd &= 0xFFF3;
                cmd |= hldev->config.mmrb_count << 2;
                xge_os_pci_write16(hldev->pdev, hldev->cfgh,
                       xge_offsetof(xge_hal_pci_config_le_t, pcix_command),
                       cmd);
        }
        /* Read back MMRB count to reflect it into user level */
        xge_os_pci_read16(hldev->pdev, hldev->cfgh,
                        xge_offsetof(xge_hal_pci_config_le_t, pcix_command),
                        &cmd);
        cmd &= 0x000C;
        hldev->config.mmrb_count = cmd>>2;

        /*  Setting Maximum outstanding splits based on system type. */
        if (hldev->config.max_splits_trans != XGE_HAL_USE_BIOS_DEFAULT_SPLITS)  {
                xge_os_pci_read16(hldev->pdev, hldev->cfgh,
                        xge_offsetof(xge_hal_pci_config_le_t, pcix_command),
                        &cmd);
                cmd &= 0xFF8F;
                cmd |= hldev->config.max_splits_trans << 4;
                xge_os_pci_write16(hldev->pdev, hldev->cfgh,
                        xge_offsetof(xge_hal_pci_config_le_t, pcix_command),
                        cmd);
        }

        /* Read back max split trans to reflect it into user level */
        xge_os_pci_read16(hldev->pdev, hldev->cfgh,
                xge_offsetof(xge_hal_pci_config_le_t, pcix_command), &cmd);
        cmd &= 0x0070;
        hldev->config.max_splits_trans = cmd>>4;

        /* Forcibly disabling relaxed ordering capability of the card. */
        xge_os_pci_read16(hldev->pdev, hldev->cfgh,
                xge_offsetof(xge_hal_pci_config_le_t, pcix_command), &cmd);
        cmd &= 0xFFFD;
        xge_os_pci_write16(hldev->pdev, hldev->cfgh,
                 xge_offsetof(xge_hal_pci_config_le_t, pcix_command), cmd);

        /* save PCI config space for future resets */
        for (i = 0; i < pcisize; i++) {
                xge_os_pci_read32(hldev->pdev, hldev->cfgh, i*4,
                                (u32*)&hldev->pci_config_space + i);
        }
}

/*
 * __hal_device_pci_info_get - Get PCI bus informations such as width, frequency
 *                               and mode.
 * @devh: HAL device handle.
 * @pci_mode:           pointer to a variable of enumerated type
 *                      xge_hal_pci_mode_e{}.
 * @bus_frequency:      pointer to a variable of enumerated type
 *                      xge_hal_pci_bus_frequency_e{}.
 * @bus_width:          pointer to a variable of enumerated type
 *                      xge_hal_pci_bus_width_e{}.
 *
 * Get pci mode, frequency, and PCI bus width.
 *
 * Returns: one of the xge_hal_status_e{} enumerated types.
 * XGE_HAL_OK                   - for success.
 * XGE_HAL_ERR_INVALID_PCI_INFO - for invalid PCI information from the card.
 * XGE_HAL_ERR_BAD_DEVICE_ID    - for invalid card.
 *
 * See Also: xge_hal_pci_mode_e, xge_hal_pci_mode_e, xge_hal_pci_width_e.
 */
static xge_hal_status_e
__hal_device_pci_info_get(xge_hal_device_h devh, xge_hal_pci_mode_e *pci_mode,
                xge_hal_pci_bus_frequency_e *bus_frequency,
                xge_hal_pci_bus_width_e *bus_width)
{
        xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
        xge_hal_status_e rc_status = XGE_HAL_OK;
        xge_hal_card_e card_id     = xge_hal_device_check_id (devh);

#ifdef XGE_HAL_HERC_EMULATION
        hldev->config.pci_freq_mherz =
                XGE_HAL_PCI_BUS_FREQUENCY_66MHZ;
        *bus_frequency  =
                XGE_HAL_PCI_BUS_FREQUENCY_66MHZ;
        *pci_mode = XGE_HAL_PCI_66MHZ_MODE;
#else
        if (card_id == XGE_HAL_CARD_HERC) {
                xge_hal_pci_bar0_t *bar0 =
                (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
                u64 pci_info = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                    &bar0->pci_info);
                if (XGE_HAL_PCI_32_BIT & pci_info)
                        *bus_width = XGE_HAL_PCI_BUS_WIDTH_32BIT;
                else
                        *bus_width = XGE_HAL_PCI_BUS_WIDTH_64BIT;
                switch((pci_info & XGE_HAL_PCI_INFO)>>60)
                {
                        case XGE_HAL_PCI_33MHZ_MODE:
                                 *bus_frequency =
                                         XGE_HAL_PCI_BUS_FREQUENCY_33MHZ;
                                 *pci_mode = XGE_HAL_PCI_33MHZ_MODE;
                                 break;
                        case XGE_HAL_PCI_66MHZ_MODE:
                                 *bus_frequency =
                                         XGE_HAL_PCI_BUS_FREQUENCY_66MHZ;
                                 *pci_mode = XGE_HAL_PCI_66MHZ_MODE;
                                 break;
                        case XGE_HAL_PCIX_M1_66MHZ_MODE:
                                 *bus_frequency =
                                         XGE_HAL_PCI_BUS_FREQUENCY_66MHZ;
                                 *pci_mode = XGE_HAL_PCIX_M1_66MHZ_MODE;
                                 break;
                        case XGE_HAL_PCIX_M1_100MHZ_MODE:
                                 *bus_frequency =
                                         XGE_HAL_PCI_BUS_FREQUENCY_100MHZ;
                                 *pci_mode = XGE_HAL_PCIX_M1_100MHZ_MODE;
                                 break;
                        case XGE_HAL_PCIX_M1_133MHZ_MODE:
                                 *bus_frequency =
                                         XGE_HAL_PCI_BUS_FREQUENCY_133MHZ;
                                 *pci_mode = XGE_HAL_PCIX_M1_133MHZ_MODE;
                                 break;
                        case XGE_HAL_PCIX_M2_66MHZ_MODE:
                                 *bus_frequency =
                                         XGE_HAL_PCI_BUS_FREQUENCY_133MHZ;
                                 *pci_mode = XGE_HAL_PCIX_M2_66MHZ_MODE;
                                 break;
                        case XGE_HAL_PCIX_M2_100MHZ_MODE:
                                 *bus_frequency =
                                         XGE_HAL_PCI_BUS_FREQUENCY_200MHZ;
                                 *pci_mode = XGE_HAL_PCIX_M2_100MHZ_MODE;
                                 break;
                        case XGE_HAL_PCIX_M2_133MHZ_MODE:
                                 *bus_frequency =
                                         XGE_HAL_PCI_BUS_FREQUENCY_266MHZ;
                                 *pci_mode = XGE_HAL_PCIX_M2_133MHZ_MODE;
                                  break;
                        case XGE_HAL_PCIX_M1_RESERVED:
                        case XGE_HAL_PCIX_M1_66MHZ_NS:
                        case XGE_HAL_PCIX_M1_100MHZ_NS:
                        case XGE_HAL_PCIX_M1_133MHZ_NS:
                        case XGE_HAL_PCIX_M2_RESERVED:
                        case XGE_HAL_PCIX_533_RESERVED:
                        default:
                                 rc_status = XGE_HAL_ERR_INVALID_PCI_INFO;
                                 xge_debug_device(XGE_ERR,
                                          "invalid pci info "XGE_OS_LLXFMT,
                                         (unsigned long long)pci_info);
                                 break;
                }
                if (rc_status != XGE_HAL_ERR_INVALID_PCI_INFO)
                        xge_debug_device(XGE_TRACE, "PCI info: mode %d width "
                                "%d frequency %d", *pci_mode, *bus_width,
                                *bus_frequency);
                if (hldev->config.pci_freq_mherz ==
                                XGE_HAL_DEFAULT_USE_HARDCODE) {
                        hldev->config.pci_freq_mherz = *bus_frequency;
                }
        }
        /* for XENA, we report PCI mode, only. PCI bus frequency, and bus width
         * are set to unknown */
        else if (card_id == XGE_HAL_CARD_XENA) {
                u32 pcix_status;
                u8 dev_num, bus_num;
                /* initialize defaults for XENA */
                *bus_frequency  = XGE_HAL_PCI_BUS_FREQUENCY_UNKNOWN;
                *bus_width      = XGE_HAL_PCI_BUS_WIDTH_UNKNOWN;
                xge_os_pci_read32(hldev->pdev, hldev->cfgh,
                        xge_offsetof(xge_hal_pci_config_le_t, pcix_status),
                        &pcix_status);
                dev_num = (u8)((pcix_status & 0xF8) >> 3);
                bus_num = (u8)((pcix_status & 0xFF00) >> 8);
                if (dev_num == 0 && bus_num == 0)
                        *pci_mode = XGE_HAL_PCI_BASIC_MODE;
                else
                        *pci_mode = XGE_HAL_PCIX_BASIC_MODE;
                xge_debug_device(XGE_TRACE, "PCI info: mode %d", *pci_mode);
                if (hldev->config.pci_freq_mherz ==
                                XGE_HAL_DEFAULT_USE_HARDCODE) {
                        /*
                         * There is no way to detect BUS frequency on Xena,
                         * so, in case of automatic configuration we hopelessly
                         * assume 133MHZ.
                         */
                        hldev->config.pci_freq_mherz =
                                XGE_HAL_PCI_BUS_FREQUENCY_133MHZ;
                }
        } else if (card_id == XGE_HAL_CARD_TITAN) {
                *bus_width = XGE_HAL_PCI_BUS_WIDTH_64BIT;
                *bus_frequency  = XGE_HAL_PCI_BUS_FREQUENCY_250MHZ;
                if (hldev->config.pci_freq_mherz ==
                                XGE_HAL_DEFAULT_USE_HARDCODE) {
                        hldev->config.pci_freq_mherz = *bus_frequency;
                }
        } else{
                rc_status =  XGE_HAL_ERR_BAD_DEVICE_ID;
                xge_debug_device(XGE_ERR, "invalid device id %d", card_id);
        }
#endif

        return rc_status;
}

/*
 * __hal_device_handle_link_up_ind
 * @hldev: HAL device handle.
 *
 * Link up indication handler. The function is invoked by HAL when
 * Xframe indicates that the link is up for programmable amount of time.
 */
static int
__hal_device_handle_link_up_ind(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;

        /*
         * If the previous link state is not down, return.
         */
        if (hldev->link_state == XGE_HAL_LINK_UP) {
#ifdef XGE_HAL_PROCESS_LINK_INT_IN_ISR
                if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC){
                        val64 = xge_os_pio_mem_read64(
                                hldev->pdev, hldev->regh0,
                                &bar0->misc_int_mask);
                        val64 |= XGE_HAL_MISC_INT_REG_LINK_UP_INT;
                        val64 &= ~XGE_HAL_MISC_INT_REG_LINK_DOWN_INT;
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                val64, &bar0->misc_int_mask);
                }
#endif
                xge_debug_device(XGE_TRACE,
                        "link up indication while link is up, ignoring..");
                return 0;
        }

        /* Now re-enable it as due to noise, hardware turned it off */
        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                     &bar0->adapter_control);
        val64 |= XGE_HAL_ADAPTER_CNTL_EN;
        val64 = val64 & (~XGE_HAL_ADAPTER_ECC_EN); /* ECC enable */
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                             &bar0->adapter_control);

        /* Turn on the Laser */
        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                    &bar0->adapter_control);
        val64 = val64|(XGE_HAL_ADAPTER_EOI_TX_ON |
                        XGE_HAL_ADAPTER_LED_ON);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                             &bar0->adapter_control);

#ifdef XGE_HAL_PROCESS_LINK_INT_IN_ISR
        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                              &bar0->adapter_status);
                if (val64 & (XGE_HAL_ADAPTER_STATUS_RMAC_REMOTE_FAULT |
                             XGE_HAL_ADAPTER_STATUS_RMAC_LOCAL_FAULT)) {
                        xge_debug_device(XGE_TRACE, "%s",
                                          "fail to transition link to up...");
                        return 0;
                }
                else {
                        /*
                         * Mask the Link Up interrupt and unmask the Link Down
                         * interrupt.
                         */
                        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                                      &bar0->misc_int_mask);
                        val64 |= XGE_HAL_MISC_INT_REG_LINK_UP_INT;
                        val64 &= ~XGE_HAL_MISC_INT_REG_LINK_DOWN_INT;
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                                               &bar0->misc_int_mask);
                        xge_debug_device(XGE_TRACE, "calling link up..");
                        hldev->link_state = XGE_HAL_LINK_UP;

                        /* notify ULD */
                        if (g_xge_hal_driver->uld_callbacks.link_up) {
                                g_xge_hal_driver->uld_callbacks.link_up(
                                                hldev->upper_layer_info);
                        }
                        return 1;
                }
        }
#endif
        xge_os_mdelay(1);
        if (__hal_device_register_poll(hldev, &bar0->adapter_status, 0,
                        (XGE_HAL_ADAPTER_STATUS_RMAC_REMOTE_FAULT |
                        XGE_HAL_ADAPTER_STATUS_RMAC_LOCAL_FAULT),
                        XGE_HAL_DEVICE_FAULT_WAIT_MAX_MILLIS) == XGE_HAL_OK) {

                /* notify ULD */
                (void) xge_queue_produce_context(hldev->queueh,
                                                 XGE_HAL_EVENT_LINK_IS_UP, hldev);
                /* link is up after been enabled */
                return 1;
        } else {
                xge_debug_device(XGE_TRACE, "%s",
                                  "fail to transition link to up...");
                return 0;
        }
}

/*
 * __hal_device_handle_link_down_ind
 * @hldev: HAL device handle.
 *
 * Link down indication handler. The function is invoked by HAL when
 * Xframe indicates that the link is down.
 */
static int
__hal_device_handle_link_down_ind(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;

        /*
         * If the previous link state is not up, return.
         */
        if (hldev->link_state == XGE_HAL_LINK_DOWN) {
#ifdef  XGE_HAL_PROCESS_LINK_INT_IN_ISR
                if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC){
                        val64 = xge_os_pio_mem_read64(
                                hldev->pdev, hldev->regh0,
                                &bar0->misc_int_mask);
                        val64 |= XGE_HAL_MISC_INT_REG_LINK_DOWN_INT;
                        val64 &= ~XGE_HAL_MISC_INT_REG_LINK_UP_INT;
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                val64, &bar0->misc_int_mask);
                }
#endif
                xge_debug_device(XGE_TRACE,
                        "link down indication while link is down, ignoring..");
                return 0;
        }
        xge_os_mdelay(1);

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                      &bar0->adapter_control);

        /* try to debounce the link only if the adapter is enabled. */
        if (val64 & XGE_HAL_ADAPTER_CNTL_EN) {
                if (__hal_device_register_poll(hldev, &bar0->adapter_status, 0,
                        (XGE_HAL_ADAPTER_STATUS_RMAC_REMOTE_FAULT |
                        XGE_HAL_ADAPTER_STATUS_RMAC_LOCAL_FAULT),
                        XGE_HAL_DEVICE_FAULT_WAIT_MAX_MILLIS) == XGE_HAL_OK) {
                        xge_debug_device(XGE_TRACE,
                                "link is actually up (possible noisy link?), ignoring.");
                        return(0);
                }
        }

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                    &bar0->adapter_control);
        /* turn off LED */
        val64 = val64 & (~XGE_HAL_ADAPTER_LED_ON);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                               &bar0->adapter_control);

#ifdef  XGE_HAL_PROCESS_LINK_INT_IN_ISR
        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
                /*
                 * Mask the Link Down interrupt and unmask the Link up
                 * interrupt
                 */
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                              &bar0->misc_int_mask);
                val64 |= XGE_HAL_MISC_INT_REG_LINK_DOWN_INT;
                val64 &= ~XGE_HAL_MISC_INT_REG_LINK_UP_INT;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                                       &bar0->misc_int_mask);

                /* link is down */
                xge_debug_device(XGE_TRACE, "calling link down..");
                hldev->link_state = XGE_HAL_LINK_DOWN;

                /* notify ULD */
                if (g_xge_hal_driver->uld_callbacks.link_down) {
                                g_xge_hal_driver->uld_callbacks.link_down(
                                        hldev->upper_layer_info);
                }
                return 1;
        }
#endif
        /* notify ULD */
        (void) xge_queue_produce_context(hldev->queueh,
                                         XGE_HAL_EVENT_LINK_IS_DOWN, hldev);
        /* link is down */
        return 1;
}
/*
 * __hal_device_handle_link_state_change
 * @hldev: HAL device handle.
 *
 * Link state change handler. The function is invoked by HAL when
 * Xframe indicates link state change condition. The code here makes sure to
 * 1) ignore redundant state change indications;
 * 2) execute link-up sequence, and handle the failure to bring the link up;
 * 3) generate XGE_HAL_LINK_UP/DOWN event for the subsequent handling by
 *    upper-layer driver (ULD).
 */
static int
__hal_device_handle_link_state_change(xge_hal_device_t *hldev)
{
        u64 hw_status;
        int hw_link_state;
        int retcode;
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;
        int i = 0;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                        &bar0->adapter_control);

        /* If the adapter is not enabled but the hal thinks we are in the up
         * state then transition to the down state.
         */
        if ( !(val64 & XGE_HAL_ADAPTER_CNTL_EN) &&
             (hldev->link_state == XGE_HAL_LINK_UP) ) {
                return(__hal_device_handle_link_down_ind(hldev));
        }

        do {
                xge_os_mdelay(1);
                (void) xge_hal_device_status(hldev, &hw_status);
                hw_link_state = (hw_status &
                        (XGE_HAL_ADAPTER_STATUS_RMAC_REMOTE_FAULT |
                                XGE_HAL_ADAPTER_STATUS_RMAC_LOCAL_FAULT)) ?
                                XGE_HAL_LINK_DOWN : XGE_HAL_LINK_UP;

                /* check if the current link state is still considered
                 * to be changed. This way we will make sure that this is
                 * not a noise which needs to be filtered out */
                if (hldev->link_state == hw_link_state)
                        break;
        } while (i++ < hldev->config.link_valid_cnt);

        /* If the current link state is same as previous, just return */
        if (hldev->link_state == hw_link_state)
                retcode = 0;
        /* detected state change */
        else if (hw_link_state == XGE_HAL_LINK_UP)
                retcode = __hal_device_handle_link_up_ind(hldev);
        else
                retcode = __hal_device_handle_link_down_ind(hldev);
        return retcode;
}

/*
 *
 */
static void
__hal_device_handle_serr(xge_hal_device_t *hldev, char *reg, u64 value)
{
        hldev->stats.sw_dev_err_stats.serr_cnt++;
        if (hldev->config.dump_on_serr) {
#ifdef XGE_HAL_USE_MGMT_AUX
                (void) xge_hal_aux_device_dump(hldev);
#endif
        }

        (void) xge_queue_produce(hldev->queueh, XGE_HAL_EVENT_SERR, hldev,
                           1, sizeof(u64), (void *)&value);

        xge_debug_device(XGE_ERR, "%s: read "XGE_OS_LLXFMT, reg,
                                  (unsigned long long) value);
}

/*
 *
 */
static void
__hal_device_handle_eccerr(xge_hal_device_t *hldev, char *reg, u64 value)
{
        if (hldev->config.dump_on_eccerr) {
#ifdef XGE_HAL_USE_MGMT_AUX
                (void) xge_hal_aux_device_dump(hldev);
#endif
        }

        /* Herc smart enough to recover on its own! */
        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA) {
                (void) xge_queue_produce(hldev->queueh,
                        XGE_HAL_EVENT_ECCERR, hldev,
                        1, sizeof(u64), (void *)&value);
        }

        xge_debug_device(XGE_ERR, "%s: read "XGE_OS_LLXFMT, reg,
                                  (unsigned long long) value);
}

/*
 *
 */
static void
__hal_device_handle_parityerr(xge_hal_device_t *hldev, char *reg, u64 value)
{
        if (hldev->config.dump_on_parityerr) {
#ifdef XGE_HAL_USE_MGMT_AUX
                (void) xge_hal_aux_device_dump(hldev);
#endif
        }
        (void) xge_queue_produce_context(hldev->queueh,
                        XGE_HAL_EVENT_PARITYERR, hldev);

        xge_debug_device(XGE_ERR, "%s: read "XGE_OS_LLXFMT, reg,
                                  (unsigned long long) value);
}

/*
 *
 */
static void
__hal_device_handle_targetabort(xge_hal_device_t *hldev)
{
        (void) xge_queue_produce_context(hldev->queueh,
                        XGE_HAL_EVENT_TARGETABORT, hldev);
}


/*
 * __hal_device_hw_initialize
 * @hldev: HAL device handle.
 *
 * Initialize Xframe hardware.
 */
static xge_hal_status_e
__hal_device_hw_initialize(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        xge_hal_status_e status;
        u64 val64;

        /* Set proper endian settings and verify the same by reading the PIF
         * Feed-back register. */
        status = __hal_device_set_swapper(hldev);
        if (status != XGE_HAL_OK) {
                return status;
        }

        /* update the pci mode, frequency, and width */
        if (__hal_device_pci_info_get(hldev, &hldev->pci_mode,
                &hldev->bus_frequency, &hldev->bus_width) != XGE_HAL_OK){
                hldev->pci_mode = XGE_HAL_PCI_INVALID_MODE;
                hldev->bus_frequency = XGE_HAL_PCI_BUS_FREQUENCY_UNKNOWN;
                hldev->bus_width = XGE_HAL_PCI_BUS_WIDTH_UNKNOWN;
                /*
                 * FIXME: this cannot happen.
                 * But if it happens we cannot continue just like that
                 */
                xge_debug_device(XGE_ERR, "unable to get pci info");
        }

        if ((hldev->pci_mode == XGE_HAL_PCI_33MHZ_MODE) ||
                (hldev->pci_mode == XGE_HAL_PCI_66MHZ_MODE) ||
                (hldev->pci_mode == XGE_HAL_PCI_BASIC_MODE)) {
                /* PCI optimization: set TxReqTimeOut
                 * register (0x800+0x120) to 0x1ff or
                 * something close to this.
                 * Note: not to be used for PCI-X! */

                val64 = XGE_HAL_TXREQTO_VAL(0x1FF);
                val64 |= XGE_HAL_TXREQTO_EN;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                                     &bar0->txreqtimeout);

                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, 0ULL,
                                     &bar0->read_retry_delay);

                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, 0ULL,
                                     &bar0->write_retry_delay);

                xge_debug_device(XGE_TRACE, "%s", "optimizing for PCI mode");
        }

        if (hldev->bus_frequency == XGE_HAL_PCI_BUS_FREQUENCY_266MHZ ||
            hldev->bus_frequency == XGE_HAL_PCI_BUS_FREQUENCY_250MHZ) {

                /* Optimizing for PCI-X 266/250 */

                val64 = XGE_HAL_TXREQTO_VAL(0x7F);
                val64 |= XGE_HAL_TXREQTO_EN;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                                     &bar0->txreqtimeout);

                xge_debug_device(XGE_TRACE, "%s", "optimizing for PCI-X 266/250 modes");
        }

        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, 0x4000000000000ULL,
                                     &bar0->read_retry_delay);

                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, 0x4000000000000ULL,
                                     &bar0->write_retry_delay);
        }

        /* added this to set the no of bytes used to update lso_bytes_sent
           returned TxD0 */
        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                      &bar0->pic_control_2);
        val64 &= ~XGE_HAL_TXD_WRITE_BC(0x2);
        val64 |= XGE_HAL_TXD_WRITE_BC(0x4);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                               &bar0->pic_control_2);
        /* added this to clear the EOI_RESET field while leaving XGXS_RESET
         * in reset, then a 1-second delay */
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                        XGE_HAL_SW_RESET_XGXS, &bar0->sw_reset);
        xge_os_mdelay(1000);

        /* Clear the XGXS_RESET field of the SW_RESET register in order to
         * release the XGXS from reset. Its reset value is 0xA5; write 0x00
         * to activate the XGXS. The core requires a minimum 500 us reset.*/
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, 0, &bar0->sw_reset);
        (void) xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &bar0->sw_reset);
        xge_os_mdelay(1);

        /* read registers in all blocks */
        (void) xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                   &bar0->mac_int_mask);
        (void) xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                   &bar0->mc_int_mask);
        (void) xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                   &bar0->xgxs_int_mask);

        /* set default MTU and steer based on length*/
        __hal_ring_mtu_set(hldev, hldev->config.mtu+22); // Alway set 22 bytes extra for steering to work

        if (hldev->config.mac.rmac_bcast_en) {
        xge_hal_device_bcast_enable(hldev);
        } else {
            xge_hal_device_bcast_disable(hldev);
        }

#ifndef XGE_HAL_HERC_EMULATION
        __hal_device_xaui_configure(hldev);
#endif
        __hal_device_mac_link_util_set(hldev);

        __hal_device_mac_link_util_set(hldev);

        /*
         * Keep its PCI REQ# line asserted during a write
         * transaction up to the end of the transaction
         */
        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &bar0->misc_control);

        val64 |= XGE_HAL_MISC_CONTROL_EXT_REQ_EN;

        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                val64, &bar0->misc_control);

        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                        &bar0->misc_control);

                val64 |= XGE_HAL_MISC_CONTROL_LINK_FAULT;

                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                        val64, &bar0->misc_control);
        }

        /*
         * bimodal interrupts is when all Rx traffic interrupts
         * will go to TTI, so we need to adjust RTI settings and
         * use adaptive TTI timer. We need to make sure RTI is
         * properly configured to sane value which will not
         * distrupt bimodal behavior.
         */
        if (hldev->config.bimodal_interrupts) {
                int i;

                /* force polling_cnt to be "0", otherwise
                 * IRQ workload statistics will be screwed. This could
                 * be worked out in TXPIC handler later. */
                hldev->config.isr_polling_cnt = 0;
                hldev->config.sched_timer_us = 10000;

                /* disable all TTI < 56 */
                for (i=0; i<XGE_HAL_MAX_FIFO_NUM; i++) {
                        int j;
                        if (!hldev->config.fifo.queue[i].configured)
                                continue;
                        for (j=0; j<XGE_HAL_MAX_FIFO_TTI_NUM; j++) {
                            if (hldev->config.fifo.queue[i].tti[j].enabled)
                                hldev->config.fifo.queue[i].tti[j].enabled = 0;
                        }
                }

                /* now configure bimodal interrupts */
                __hal_device_bimodal_configure(hldev);
        }

        status = __hal_device_tti_configure(hldev, 0);
        if (status != XGE_HAL_OK)
                return status;

        status = __hal_device_rti_configure(hldev, 0);
        if (status != XGE_HAL_OK)
                return status;

        status = __hal_device_rth_it_configure(hldev);
        if (status != XGE_HAL_OK)
                return status;

        status = __hal_device_rth_spdm_configure(hldev);
        if (status != XGE_HAL_OK)
                return status;

        status = __hal_device_rts_mac_configure(hldev);
        if (status != XGE_HAL_OK) {
                xge_debug_device(XGE_ERR, "__hal_device_rts_mac_configure Failed ");
                return status;
        }

        status = __hal_device_rts_port_configure(hldev);
        if (status != XGE_HAL_OK) {
                xge_debug_device(XGE_ERR, "__hal_device_rts_port_configure Failed ");
                return status;
        }

        status = __hal_device_rts_qos_configure(hldev);
        if (status != XGE_HAL_OK) {
                xge_debug_device(XGE_ERR, "__hal_device_rts_qos_configure Failed ");
                return status;
        }

        __hal_device_pause_frames_configure(hldev);
        __hal_device_rmac_padding_configure(hldev);
        __hal_device_shared_splits_configure(hldev);

        /* make sure all interrupts going to be disabled at the moment */
        __hal_device_intr_mgmt(hldev, XGE_HAL_ALL_INTRS, 0);

        /* SXE-008 Transmit DMA arbitration issue */
        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA &&
            hldev->revision < 4) {
                xge_os_pio_mem_write64(hldev->pdev,hldev->regh0,
                                XGE_HAL_ADAPTER_PCC_ENABLE_FOUR,
                                &bar0->pcc_enable);
        }
        __hal_fifo_hw_initialize(hldev);
        __hal_ring_hw_initialize(hldev);

        if (__hal_device_wait_quiescent(hldev, &val64)) {
                return XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT;
        }

        if (__hal_device_register_poll(hldev, &bar0->adapter_status, 1,
                XGE_HAL_ADAPTER_STATUS_RC_PRC_QUIESCENT,
                 XGE_HAL_DEVICE_QUIESCENT_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
                xge_debug_device(XGE_TRACE, "%s", "PRC is not QUIESCENT!");
                return XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT;
        }

        xge_debug_device(XGE_TRACE, "device 0x"XGE_OS_LLXFMT" is quiescent",
                          (unsigned long long)(ulong_t)hldev);

        if (hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSIX ||
            hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSI) {
                /*
                 * If MSI is enabled, ensure that One Shot for MSI in PCI_CTRL
                 * is disabled.
                 */
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                            &bar0->pic_control);
                val64 &= ~(XGE_HAL_PIC_CNTL_ONE_SHOT_TINT);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                                            &bar0->pic_control);
        }

        hldev->hw_is_initialized = 1;
        hldev->terminating = 0;
        return XGE_HAL_OK;
}

/*
 * __hal_device_reset - Reset device only.
 * @hldev: HAL device handle.
 *
 * Reset the device, and subsequently restore
 * the previously saved PCI configuration space.
 */
#define XGE_HAL_MAX_PCI_CONFIG_SPACE_REINIT 50
static xge_hal_status_e
__hal_device_reset(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        int i, j, swap_done, pcisize = 0;
        u64 val64, rawval = 0ULL;

        if (hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSIX) {
                if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
                        if ( hldev->bar2 ) {
                            u64 *msix_vetor_table = (u64 *)hldev->bar2;

                            // 2 64bit words for each entry
                            for (i = 0; i < XGE_HAL_MAX_MSIX_MESSAGES * 2;
                                 i++) {
                                  hldev->msix_vector_table[i] =
                                       xge_os_pio_mem_read64(hldev->pdev,
                                          hldev->regh2, &msix_vetor_table[i]);
                            }
                        }
                }
        }
        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                    &bar0->pif_rd_swapper_fb);
        swap_done = (val64 == XGE_HAL_IF_RD_SWAPPER_FB);

        if (swap_done) {
                __hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0,
                     (u32)(XGE_HAL_SW_RESET_ALL>>32), (char *)&bar0->sw_reset);
        } else {
                u32 val = (u32)(XGE_HAL_SW_RESET_ALL >> 32);
#if defined(XGE_OS_HOST_LITTLE_ENDIAN) || defined(XGE_OS_PIO_LITTLE_ENDIAN)
                /* swap it */
                val = (((val & (u32)0x000000ffUL) << 24) |
                       ((val & (u32)0x0000ff00UL) <<  8) |
                       ((val & (u32)0x00ff0000UL) >>  8) |
                       ((val & (u32)0xff000000UL) >> 24));
#endif
                xge_os_pio_mem_write32(hldev->pdev, hldev->regh0, val,
                                     &bar0->sw_reset);
        }

        pcisize = (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC)?
                           XGE_HAL_PCISIZE_HERC : XGE_HAL_PCISIZE_XENA;

        xge_os_mdelay(20); /* Wait for 20 ms after reset */

        {
                /* Poll for no more than 1 second */
                for (i = 0; i < XGE_HAL_MAX_PCI_CONFIG_SPACE_REINIT; i++)
                {
                        for (j = 0; j < pcisize; j++) {
                                xge_os_pci_write32(hldev->pdev, hldev->cfgh, j * 4,
                                        *((u32*)&hldev->pci_config_space + j));
                        }

                        xge_os_pci_read16(hldev->pdev,hldev->cfgh,
                                xge_offsetof(xge_hal_pci_config_le_t, device_id),
                                &hldev->device_id);

                        if (xge_hal_device_check_id(hldev) != XGE_HAL_CARD_UNKNOWN)
                                break;
                        xge_os_mdelay(20);
                }
        }

        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_UNKNOWN)
        {
                xge_debug_device(XGE_ERR, "device reset failed");
                        return XGE_HAL_ERR_RESET_FAILED;
        }

        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
                int cnt = 0;

                rawval = XGE_HAL_SW_RESET_RAW_VAL_HERC;
                pcisize = XGE_HAL_PCISIZE_HERC;
                xge_os_mdelay(1);
                do {
                        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &bar0->sw_reset);
                        if (val64 != rawval) {
                                break;
                        }
                        cnt++;
                        xge_os_mdelay(1); /* Wait for 1ms before retry */
                } while(cnt < 20);
        } else if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA) {
                rawval = XGE_HAL_SW_RESET_RAW_VAL_XENA;
                pcisize = XGE_HAL_PCISIZE_XENA;
                xge_os_mdelay(XGE_HAL_DEVICE_RESET_WAIT_MAX_MILLIS);
        }

        /* Restore MSI-X vector table */
        if (hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSIX) {
                if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
                        if ( hldev->bar2 ) {
                            /*
                             * 94: MSIXTable 00000004  ( BIR:4  Offset:0x0 )
                             * 98: PBATable  00000404  ( BIR:4  Offset:0x400 )
                             */
                             u64 *msix_vetor_table = (u64 *)hldev->bar2;

                             /* 2 64bit words for each entry */
                             for (i = 0; i < XGE_HAL_MAX_MSIX_MESSAGES * 2;
                                  i++) {
                                 xge_os_pio_mem_write64(hldev->pdev,
                                        hldev->regh2,
                                        hldev->msix_vector_table[i],
                                        &msix_vetor_table[i]);
                             }
                        }
                }
        }

        hldev->link_state = XGE_HAL_LINK_DOWN;
        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                      &bar0->sw_reset);

        if (val64 != rawval) {
                xge_debug_device(XGE_ERR, "device has not been reset "
                        "got 0x"XGE_OS_LLXFMT", expected 0x"XGE_OS_LLXFMT,
                        (unsigned long long)val64, (unsigned long long)rawval);
                return XGE_HAL_ERR_RESET_FAILED;
        }

        hldev->hw_is_initialized = 0;
        return XGE_HAL_OK;
}

/*
 * __hal_device_poll - General private routine to poll the device.
 * @hldev: HAL device handle.
 *
 * Returns: one of the xge_hal_status_e{} enumerated types.
 * XGE_HAL_OK                   - for success.
 * XGE_HAL_ERR_CRITICAL         - when encounters critical error.
 */
static xge_hal_status_e
__hal_device_poll(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0;
        u64 err_reg;

        bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;

        /* Handling SERR errors by forcing a H/W reset. */
        err_reg = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                      &bar0->serr_source);
        if (err_reg & XGE_HAL_SERR_SOURCE_ANY) {
                __hal_device_handle_serr(hldev, "serr_source", err_reg);
                return XGE_HAL_ERR_CRITICAL;
        }

        err_reg = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                        &bar0->misc_int_reg);

        if (err_reg & XGE_HAL_MISC_INT_REG_DP_ERR_INT) {
                hldev->stats.sw_dev_err_stats.parity_err_cnt++;
                __hal_device_handle_parityerr(hldev, "misc_int_reg", err_reg);
                return XGE_HAL_ERR_CRITICAL;
        }

#ifdef  XGE_HAL_PROCESS_LINK_INT_IN_ISR
        if ((xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA) ||
                (hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSIX))
#endif
        {

                /* Handling link status change error Intr */
                err_reg = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                                &bar0->mac_rmac_err_reg);
                if (__hal_device_handle_link_state_change(hldev))
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                       err_reg, &bar0->mac_rmac_err_reg);
        }

        if (hldev->inject_serr != 0) {
                err_reg = hldev->inject_serr;
                hldev->inject_serr = 0;
                __hal_device_handle_serr(hldev, "inject_serr", err_reg);
                return XGE_HAL_ERR_CRITICAL;
        }

        if (hldev->inject_ecc != 0) {
                err_reg = hldev->inject_ecc;
                hldev->inject_ecc = 0;
                hldev->stats.sw_dev_err_stats.ecc_err_cnt++;
                __hal_device_handle_eccerr(hldev, "inject_ecc", err_reg);
                return XGE_HAL_ERR_CRITICAL;
        }

        if (hldev->inject_bad_tcode != 0) {
                u8 t_code = hldev->inject_bad_tcode;
                xge_hal_channel_t channel;
                xge_hal_fifo_txd_t txd;
                xge_hal_ring_rxd_1_t rxd;

                channel.devh =  hldev;

                if (hldev->inject_bad_tcode_for_chan_type ==
                                                XGE_HAL_CHANNEL_TYPE_FIFO) {
                        channel.type = XGE_HAL_CHANNEL_TYPE_FIFO;

                } else {
                        channel.type = XGE_HAL_CHANNEL_TYPE_RING;
                }

                hldev->inject_bad_tcode = 0;

                if (channel.type == XGE_HAL_CHANNEL_TYPE_FIFO)
                        return xge_hal_device_handle_tcode(&channel, &txd,
                                                           t_code);
                else
                        return xge_hal_device_handle_tcode(&channel, &rxd,
                                                           t_code);
        }

        return XGE_HAL_OK;
}

/*
 * __hal_verify_pcc_idle - Verify All Enbled PCC are IDLE or not
 * @hldev: HAL device handle.
 * @adp_status: Adapter Status value
 * Usage: See xge_hal_device_enable{}.
 */
xge_hal_status_e
__hal_verify_pcc_idle(xge_hal_device_t *hldev, u64 adp_status)
{
        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA &&
            hldev->revision < 4) {
                /*
                 * For Xena 1,2,3 we enable only 4 PCCs Due to
                 * SXE-008 (Transmit DMA arbitration issue)
                 */
                if ((adp_status & XGE_HAL_ADAPTER_STATUS_RMAC_PCC_4_IDLE)
                        != XGE_HAL_ADAPTER_STATUS_RMAC_PCC_4_IDLE) {
                        xge_debug_device(XGE_TRACE, "%s",
                            "PCC is not IDLE after adapter enabled!");
                        return XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT;
                }
        } else {
                if ((adp_status & XGE_HAL_ADAPTER_STATUS_RMAC_PCC_IDLE) !=
                        XGE_HAL_ADAPTER_STATUS_RMAC_PCC_IDLE) {
                        xge_debug_device(XGE_TRACE, "%s",
                        "PCC is not IDLE after adapter enabled!");
                        return XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT;
                }
        }
        return XGE_HAL_OK;
}

static void
__hal_update_bimodal(xge_hal_device_t *hldev, int ring_no)
{
        int tval, d, iwl_avg, len_avg, bytes_avg, bytes_hist, d_hist;
        int iwl_rxcnt, iwl_txcnt, iwl_txavg, len_rxavg, iwl_rxavg, len_txavg;
        int iwl_cnt, i;

#define _HIST_SIZE      50 /* 0.5 sec history */
#define _HIST_ADJ_TIMER 1
#define _STEP           2

        static int bytes_avg_history[_HIST_SIZE] = {0};
        static int d_avg_history[_HIST_SIZE] = {0};
        static int history_idx = 0;
        static int pstep = 1;
        static int hist_adj_timer = 0;

        /*
         * tval - current value of this bimodal timer
         */
        tval = hldev->bimodal_tti[ring_no].timer_val_us;

        /*
         * d - how many interrupts we were getting since last
         *     bimodal timer tick.
         */
        d = hldev->stats.sw_dev_info_stats.tx_traffic_intr_cnt -
                hldev->bimodal_intr_cnt;

        /* advance bimodal interrupt counter */
        hldev->bimodal_intr_cnt =
                hldev->stats.sw_dev_info_stats.tx_traffic_intr_cnt;

        /*
         * iwl_cnt - how many interrupts we've got since last
         *           bimodal timer tick.
         */
        iwl_rxcnt = (hldev->irq_workload_rxcnt[ring_no] ?
                     hldev->irq_workload_rxcnt[ring_no] : 1);
        iwl_txcnt = (hldev->irq_workload_txcnt[ring_no] ?
                     hldev->irq_workload_txcnt[ring_no] : 1);
        iwl_cnt = iwl_rxcnt + iwl_txcnt;
        iwl_cnt = iwl_cnt; /* just to remove the lint warning */

        /*
         * we need to take hldev->config.isr_polling_cnt into account
         * but for some reason this line causing GCC to produce wrong
         * code on Solaris. As of now, if bimodal_interrupts is configured
         * hldev->config.isr_polling_cnt is forced to be "0".
         *
         * iwl_cnt = iwl_cnt / (hldev->config.isr_polling_cnt + 1); */

        /*
         * iwl_avg - how many RXDs on avarage been processed since
         *           last bimodal timer tick. This indirectly includes
         *           CPU utilizations.
         */
        iwl_rxavg = hldev->irq_workload_rxd[ring_no] / iwl_rxcnt;
        iwl_txavg = hldev->irq_workload_txd[ring_no] / iwl_txcnt;
        iwl_avg = iwl_rxavg + iwl_txavg;
        iwl_avg = iwl_avg == 0 ? 1 : iwl_avg;

        /*
         * len_avg - how many bytes on avarage been processed since
         *           last bimodal timer tick. i.e. avarage frame size.
         */
        len_rxavg = 1 + hldev->irq_workload_rxlen[ring_no] /
                       (hldev->irq_workload_rxd[ring_no] ?
                        hldev->irq_workload_rxd[ring_no] : 1);
        len_txavg = 1 + hldev->irq_workload_txlen[ring_no] /
                       (hldev->irq_workload_txd[ring_no] ?
                        hldev->irq_workload_txd[ring_no] : 1);
        len_avg = len_rxavg + len_txavg;
        if (len_avg < 60)
                len_avg = 60;

        /* align on low boundary */
        if ((tval -_STEP) < hldev->config.bimodal_timer_lo_us)
                tval = hldev->config.bimodal_timer_lo_us;

        /* reset faster */
        if (iwl_avg == 1) {
                tval = hldev->config.bimodal_timer_lo_us;
                /* reset history */
                for (i = 0; i < _HIST_SIZE; i++)
                        bytes_avg_history[i] = d_avg_history[i] = 0;
                history_idx = 0;
                pstep = 1;
                hist_adj_timer = 0;
        }

        /* always try to ajust timer to the best throughput value */
        bytes_avg = iwl_avg * len_avg;
        history_idx %= _HIST_SIZE;
        bytes_avg_history[history_idx] = bytes_avg;
        d_avg_history[history_idx] = d;
        history_idx++;
        d_hist = bytes_hist = 0;
        for (i = 0; i < _HIST_SIZE; i++) {
                /* do not re-configure until history is gathered */
                if (!bytes_avg_history[i]) {
                        tval = hldev->config.bimodal_timer_lo_us;
                        goto _end;
                }
                bytes_hist += bytes_avg_history[i];
                d_hist += d_avg_history[i];
        }
        bytes_hist /= _HIST_SIZE;
        d_hist /= _HIST_SIZE;

//      xge_os_printf("d %d iwl_avg %d len_avg %d:%d:%d tval %d avg %d hist %d pstep %d",
//                    d, iwl_avg, len_txavg, len_rxavg, len_avg, tval, d*bytes_avg,
//                    d_hist*bytes_hist, pstep);

        /* make an adaptive step */
        if (d * bytes_avg < d_hist * bytes_hist && hist_adj_timer++ > _HIST_ADJ_TIMER) {
                pstep = !pstep;
                hist_adj_timer = 0;
        }

        if (pstep &&
            (tval + _STEP) <= hldev->config.bimodal_timer_hi_us) {
                tval += _STEP;
                hldev->stats.sw_dev_info_stats.bimodal_hi_adjust_cnt++;
        } else if ((tval - _STEP) >= hldev->config.bimodal_timer_lo_us) {
                tval -= _STEP;
                hldev->stats.sw_dev_info_stats.bimodal_lo_adjust_cnt++;
        }

        /* enable TTI range A for better latencies */
        hldev->bimodal_urange_a_en = 0;
        if (tval <= hldev->config.bimodal_timer_lo_us && iwl_avg > 2)
                hldev->bimodal_urange_a_en = 1;

_end:
        /* reset workload statistics counters */
        hldev->irq_workload_rxcnt[ring_no] = 0;
        hldev->irq_workload_rxd[ring_no] = 0;
        hldev->irq_workload_rxlen[ring_no] = 0;
        hldev->irq_workload_txcnt[ring_no] = 0;
        hldev->irq_workload_txd[ring_no] = 0;
        hldev->irq_workload_txlen[ring_no] = 0;

        /* reconfigure TTI56 + ring_no with new timer value */
        hldev->bimodal_timer_val_us = tval;
        (void) __hal_device_rti_configure(hldev, 1);
}

static void
__hal_update_rxufca(xge_hal_device_t *hldev, int ring_no)
{
        int ufc, ic, i;

        ufc = hldev->config.ring.queue[ring_no].rti.ufc_a;
        ic = hldev->stats.sw_dev_info_stats.rx_traffic_intr_cnt;

        /* urange_a adaptive coalescing */
        if (hldev->rxufca_lbolt > hldev->rxufca_lbolt_time) {
                if (ic > hldev->rxufca_intr_thres) {
                        if (ufc < hldev->config.rxufca_hi_lim) {
                                ufc += 1;
                                for (i=0; i<XGE_HAL_MAX_RING_NUM; i++)
                                   hldev->config.ring.queue[i].rti.ufc_a = ufc;
                                (void) __hal_device_rti_configure(hldev, 1);
                                hldev->stats.sw_dev_info_stats.rxufca_hi_adjust_cnt++;
                        }
                        hldev->rxufca_intr_thres = ic +
                                hldev->config.rxufca_intr_thres; /* def: 30 */
                } else {
                        if (ufc > hldev->config.rxufca_lo_lim) {
                                ufc -= 1;
                                for (i=0; i<XGE_HAL_MAX_RING_NUM; i++)
                                   hldev->config.ring.queue[i].rti.ufc_a = ufc;
                                (void) __hal_device_rti_configure(hldev, 1);
                                hldev->stats.sw_dev_info_stats.rxufca_lo_adjust_cnt++;
                        }
                }
                hldev->rxufca_lbolt_time = hldev->rxufca_lbolt +
                        hldev->config.rxufca_lbolt_period;
        }
        hldev->rxufca_lbolt++;
}

/*
 * __hal_device_handle_mc - Handle MC interrupt reason
 * @hldev: HAL device handle.
 * @reason: interrupt reason
 */
xge_hal_status_e
__hal_device_handle_mc(xge_hal_device_t *hldev, u64 reason)
{
        xge_hal_pci_bar0_t *isrbar0 =
                (xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
        u64 val64;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->mc_int_status);
        if (!(val64 & XGE_HAL_MC_INT_STATUS_MC_INT))
                return XGE_HAL_OK;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->mc_err_reg);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                val64, &isrbar0->mc_err_reg);

        if (val64 & XGE_HAL_MC_ERR_REG_ETQ_ECC_SG_ERR_L ||
            val64 & XGE_HAL_MC_ERR_REG_ETQ_ECC_SG_ERR_U ||
            val64 & XGE_HAL_MC_ERR_REG_MIRI_ECC_SG_ERR_0 ||
            val64 & XGE_HAL_MC_ERR_REG_MIRI_ECC_SG_ERR_1 ||
            (xge_hal_device_check_id(hldev) != XGE_HAL_CARD_XENA &&
             (val64 & XGE_HAL_MC_ERR_REG_ITQ_ECC_SG_ERR_L ||
              val64 & XGE_HAL_MC_ERR_REG_ITQ_ECC_SG_ERR_U ||
              val64 & XGE_HAL_MC_ERR_REG_RLD_ECC_SG_ERR_L ||
              val64 & XGE_HAL_MC_ERR_REG_RLD_ECC_SG_ERR_U))) {
                hldev->stats.sw_dev_err_stats.single_ecc_err_cnt++;
                hldev->stats.sw_dev_err_stats.ecc_err_cnt++;
        }

        if (val64 & XGE_HAL_MC_ERR_REG_ETQ_ECC_DB_ERR_L ||
            val64 & XGE_HAL_MC_ERR_REG_ETQ_ECC_DB_ERR_U ||
            val64 & XGE_HAL_MC_ERR_REG_MIRI_ECC_DB_ERR_0 ||
            val64 & XGE_HAL_MC_ERR_REG_MIRI_ECC_DB_ERR_1 ||
            (xge_hal_device_check_id(hldev) != XGE_HAL_CARD_XENA &&
             (val64 & XGE_HAL_MC_ERR_REG_ITQ_ECC_DB_ERR_L ||
              val64 & XGE_HAL_MC_ERR_REG_ITQ_ECC_DB_ERR_U ||
              val64 & XGE_HAL_MC_ERR_REG_RLD_ECC_DB_ERR_L ||
              val64 & XGE_HAL_MC_ERR_REG_RLD_ECC_DB_ERR_U))) {
                hldev->stats.sw_dev_err_stats.double_ecc_err_cnt++;
                hldev->stats.sw_dev_err_stats.ecc_err_cnt++;
        }

        if (val64 & XGE_HAL_MC_ERR_REG_SM_ERR) {
                hldev->stats.sw_dev_err_stats.sm_err_cnt++;
        }

        /* those two should result in device reset */
        if (val64 & XGE_HAL_MC_ERR_REG_MIRI_ECC_DB_ERR_0 ||
            val64 & XGE_HAL_MC_ERR_REG_MIRI_ECC_DB_ERR_1) {
                __hal_device_handle_eccerr(hldev, "mc_err_reg", val64);
                return XGE_HAL_ERR_CRITICAL;
        }

        return XGE_HAL_OK;
}

/*
 * __hal_device_handle_pic - Handle non-traffic PIC interrupt reason
 * @hldev: HAL device handle.
 * @reason: interrupt reason
 */
xge_hal_status_e
__hal_device_handle_pic(xge_hal_device_t *hldev, u64 reason)
{
        xge_hal_pci_bar0_t *isrbar0 =
                (xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
        u64 val64;

        if (reason & XGE_HAL_PIC_INT_FLSH) {
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                        &isrbar0->flsh_int_reg);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                       val64, &isrbar0->flsh_int_reg);
                /* FIXME: handle register */
        }
        if (reason & XGE_HAL_PIC_INT_MDIO) {
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                        &isrbar0->mdio_int_reg);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                       val64, &isrbar0->mdio_int_reg);
                /* FIXME: handle register */
        }
        if (reason & XGE_HAL_PIC_INT_IIC) {
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                        &isrbar0->iic_int_reg);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                       val64, &isrbar0->iic_int_reg);
                /* FIXME: handle register */
        }
        if (reason & XGE_HAL_PIC_INT_MISC) {
                val64 = xge_os_pio_mem_read64(hldev->pdev,
                                hldev->regh0, &isrbar0->misc_int_reg);
#ifdef XGE_HAL_PROCESS_LINK_INT_IN_ISR
                if ((xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) &&
                        (hldev->config.intr_mode != XGE_HAL_INTR_MODE_MSIX)) {
                        /*  Check for Link interrupts. If both Link Up/Down
                         *  bits are set, clear both and check adapter status
                         */
                        if ((val64 & XGE_HAL_MISC_INT_REG_LINK_UP_INT) &&
                            (val64 & XGE_HAL_MISC_INT_REG_LINK_DOWN_INT)) {
                                u64 temp64;

                                xge_debug_device(XGE_TRACE,
                                "both link up and link down detected "XGE_OS_LLXFMT,
                                (unsigned long long)val64);

                                temp64 = (XGE_HAL_MISC_INT_REG_LINK_DOWN_INT |
                                          XGE_HAL_MISC_INT_REG_LINK_UP_INT);
                                xge_os_pio_mem_write64(hldev->pdev,
                                                       hldev->regh0, temp64,
                                                       &isrbar0->misc_int_reg);
                        }
                        else if (val64 & XGE_HAL_MISC_INT_REG_LINK_UP_INT) {
                                xge_debug_device(XGE_TRACE,
                                        "link up call request, misc_int "XGE_OS_LLXFMT,
                                        (unsigned long long)val64);
                                __hal_device_handle_link_up_ind(hldev);
                        }
                        else if (val64 & XGE_HAL_MISC_INT_REG_LINK_DOWN_INT){
                                xge_debug_device(XGE_TRACE,
                                        "link down request, misc_int "XGE_OS_LLXFMT,
                                        (unsigned long long)val64);
                                __hal_device_handle_link_down_ind(hldev);
                        }
                } else
#endif
                {
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                       val64, &isrbar0->misc_int_reg);
                }
        }

        return XGE_HAL_OK;
}

/*
 * __hal_device_handle_txpic - Handle TxPIC interrupt reason
 * @hldev: HAL device handle.
 * @reason: interrupt reason
 */
xge_hal_status_e
__hal_device_handle_txpic(xge_hal_device_t *hldev, u64 reason)
{
        xge_hal_status_e status = XGE_HAL_OK;
        xge_hal_pci_bar0_t *isrbar0 =
                (xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
        volatile u64 val64;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->pic_int_status);
        if ( val64 & (XGE_HAL_PIC_INT_FLSH |
                      XGE_HAL_PIC_INT_MDIO |
                      XGE_HAL_PIC_INT_IIC |
                      XGE_HAL_PIC_INT_MISC) ) {
                status =  __hal_device_handle_pic(hldev, val64);
                xge_os_wmb();
        }

        if (!(val64 & XGE_HAL_PIC_INT_TX))
                return status;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->txpic_int_reg);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                               val64, &isrbar0->txpic_int_reg);
        xge_os_wmb();

        if (val64 & XGE_HAL_TXPIC_INT_SCHED_INTR) {
                int i;

                if (g_xge_hal_driver->uld_callbacks.sched_timer != NULL)
                        g_xge_hal_driver->uld_callbacks.sched_timer(
                                          hldev, hldev->upper_layer_info);
                /*
                 * This feature implements adaptive receive interrupt
                 * coalecing. It is disabled by default. To enable it
                 * set hldev->config.rxufca_lo_lim to be not equal to
                 * hldev->config.rxufca_hi_lim.
                 *
                 * We are using HW timer for this feature, so
                 * use needs to configure hldev->config.rxufca_lbolt_period
                 * which is essentially a time slice of timer.
                 *
                 * For those who familiar with Linux, lbolt means jiffies
                 * of this timer. I.e. timer tick.
                 */
                if (hldev->config.rxufca_lo_lim !=
                                hldev->config.rxufca_hi_lim &&
                    hldev->config.rxufca_lo_lim != 0) {
                        for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++) {
                                if (!hldev->config.ring.queue[i].configured)
                                        continue;
                                if (hldev->config.ring.queue[i].rti.urange_a)
                                        __hal_update_rxufca(hldev, i);
                        }
                }

                /*
                 * This feature implements adaptive TTI timer re-calculation
                 * based on host utilization, number of interrupt processed,
                 * number of RXD per tick and avarage length of packets per
                 * tick.
                 */
                if (hldev->config.bimodal_interrupts) {
                        for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++) {
                                if (!hldev->config.ring.queue[i].configured)
                                        continue;
                                if (hldev->bimodal_tti[i].enabled)
                                        __hal_update_bimodal(hldev, i);
                        }
                }
        }

        return XGE_HAL_OK;
}

/*
 * __hal_device_handle_txdma - Handle TxDMA interrupt reason
 * @hldev: HAL device handle.
 * @reason: interrupt reason
 */
xge_hal_status_e
__hal_device_handle_txdma(xge_hal_device_t *hldev, u64 reason)
{
        xge_hal_pci_bar0_t *isrbar0 =
                (xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
        u64 val64, temp64, err;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->txdma_int_status);
        if (val64 & XGE_HAL_TXDMA_PFC_INT) {
                err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->pfc_err_reg);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                err, &isrbar0->pfc_err_reg);
                hldev->stats.sw_dev_info_stats.pfc_err_cnt++;
                temp64 = XGE_HAL_PFC_ECC_DB_ERR|XGE_HAL_PFC_SM_ERR_ALARM
                        |XGE_HAL_PFC_MISC_0_ERR|XGE_HAL_PFC_MISC_1_ERR
                        |XGE_HAL_PFC_PCIX_ERR;
                if (val64 & temp64)
                        goto reset;
        }
        if (val64 & XGE_HAL_TXDMA_TDA_INT) {
                err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->tda_err_reg);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                err, &isrbar0->tda_err_reg);
                hldev->stats.sw_dev_info_stats.tda_err_cnt++;
                temp64 = XGE_HAL_TDA_Fn_ECC_DB_ERR|XGE_HAL_TDA_SM0_ERR_ALARM
                        |XGE_HAL_TDA_SM1_ERR_ALARM;
                if (val64 & temp64)
                        goto reset;
        }
        if (val64 & XGE_HAL_TXDMA_PCC_INT) {
                err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->pcc_err_reg);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                err, &isrbar0->pcc_err_reg);
                hldev->stats.sw_dev_info_stats.pcc_err_cnt++;
                temp64 = XGE_HAL_PCC_FB_ECC_DB_ERR|XGE_HAL_PCC_TXB_ECC_DB_ERR
                        |XGE_HAL_PCC_SM_ERR_ALARM|XGE_HAL_PCC_WR_ERR_ALARM
                        |XGE_HAL_PCC_N_SERR|XGE_HAL_PCC_6_COF_OV_ERR
                        |XGE_HAL_PCC_7_COF_OV_ERR|XGE_HAL_PCC_6_LSO_OV_ERR
                        |XGE_HAL_PCC_7_LSO_OV_ERR;
                if (val64 & temp64)
                        goto reset;
        }
        if (val64 & XGE_HAL_TXDMA_TTI_INT) {
                err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->tti_err_reg);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                err, &isrbar0->tti_err_reg);
                hldev->stats.sw_dev_info_stats.tti_err_cnt++;
                temp64 = XGE_HAL_TTI_SM_ERR_ALARM;
                if (val64 & temp64)
                        goto reset;
        }
        if (val64 & XGE_HAL_TXDMA_LSO_INT) {
                err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->lso_err_reg);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                err, &isrbar0->lso_err_reg);
                hldev->stats.sw_dev_info_stats.lso_err_cnt++;
                temp64 = XGE_HAL_LSO6_ABORT|XGE_HAL_LSO7_ABORT
                        |XGE_HAL_LSO6_SM_ERR_ALARM|XGE_HAL_LSO7_SM_ERR_ALARM;
                if (val64 & temp64)
                        goto reset;
        }
        if (val64 & XGE_HAL_TXDMA_TPA_INT) {
                err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->tpa_err_reg);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                err, &isrbar0->tpa_err_reg);
                hldev->stats.sw_dev_info_stats.tpa_err_cnt++;
                temp64 = XGE_HAL_TPA_SM_ERR_ALARM;
                if (val64 & temp64)
                        goto reset;
        }
        if (val64 & XGE_HAL_TXDMA_SM_INT) {
                err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->sm_err_reg);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                err, &isrbar0->sm_err_reg);
                hldev->stats.sw_dev_info_stats.sm_err_cnt++;
                temp64 = XGE_HAL_SM_SM_ERR_ALARM;
                if (val64 & temp64)
                        goto reset;
        }

        return XGE_HAL_OK;

reset : (void) xge_hal_device_reset(hldev);
        (void) xge_hal_device_enable(hldev);
        xge_hal_device_intr_enable(hldev);
        return XGE_HAL_OK;
}

/*
 * __hal_device_handle_txmac - Handle TxMAC interrupt reason
 * @hldev: HAL device handle.
 * @reason: interrupt reason
 */
xge_hal_status_e
__hal_device_handle_txmac(xge_hal_device_t *hldev, u64 reason)
{
        xge_hal_pci_bar0_t *isrbar0 =
                (xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
        u64 val64, temp64;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->mac_int_status);
        if (!(val64 & XGE_HAL_MAC_INT_STATUS_TMAC_INT))
                return XGE_HAL_OK;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->mac_tmac_err_reg);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                val64, &isrbar0->mac_tmac_err_reg);
        hldev->stats.sw_dev_info_stats.mac_tmac_err_cnt++;
        temp64 = XGE_HAL_TMAC_TX_BUF_OVRN|XGE_HAL_TMAC_TX_SM_ERR;
        if (val64 & temp64) {
                (void) xge_hal_device_reset(hldev);
                (void) xge_hal_device_enable(hldev);
                xge_hal_device_intr_enable(hldev);
        }

        return XGE_HAL_OK;
}

/*
 * __hal_device_handle_txxgxs - Handle TxXGXS interrupt reason
 * @hldev: HAL device handle.
 * @reason: interrupt reason
 */
xge_hal_status_e
__hal_device_handle_txxgxs(xge_hal_device_t *hldev, u64 reason)
{
        xge_hal_pci_bar0_t *isrbar0 =
                (xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
        u64 val64, temp64;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->xgxs_int_status);
        if (!(val64 & XGE_HAL_XGXS_INT_STATUS_TXGXS))
                return XGE_HAL_OK;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->xgxs_txgxs_err_reg);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                val64, &isrbar0->xgxs_txgxs_err_reg);
        hldev->stats.sw_dev_info_stats.xgxs_txgxs_err_cnt++;
        temp64 = XGE_HAL_TXGXS_ESTORE_UFLOW|XGE_HAL_TXGXS_TX_SM_ERR;
        if (val64 & temp64) {
                (void) xge_hal_device_reset(hldev);
                (void) xge_hal_device_enable(hldev);
                xge_hal_device_intr_enable(hldev);
        }

        return XGE_HAL_OK;
}

/*
 * __hal_device_handle_rxpic - Handle RxPIC interrupt reason
 * @hldev: HAL device handle.
 * @reason: interrupt reason
 */
xge_hal_status_e
__hal_device_handle_rxpic(xge_hal_device_t *hldev, u64 reason)
{
        /* FIXME: handle register */

        return XGE_HAL_OK;
}

/*
 * __hal_device_handle_rxdma - Handle RxDMA interrupt reason
 * @hldev: HAL device handle.
 * @reason: interrupt reason
 */
xge_hal_status_e
__hal_device_handle_rxdma(xge_hal_device_t *hldev, u64 reason)
{
        xge_hal_pci_bar0_t *isrbar0 =
                (xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
        u64 val64, err, temp64;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->rxdma_int_status);
        if (val64 & XGE_HAL_RXDMA_RC_INT) {
                err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->rc_err_reg);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                err, &isrbar0->rc_err_reg);
                hldev->stats.sw_dev_info_stats.rc_err_cnt++;
                temp64 = XGE_HAL_RC_PRCn_ECC_DB_ERR|XGE_HAL_RC_FTC_ECC_DB_ERR
                        |XGE_HAL_RC_PRCn_SM_ERR_ALARM
                        |XGE_HAL_RC_FTC_SM_ERR_ALARM;
                if (val64 & temp64)
                        goto reset;
        }
        if (val64 & XGE_HAL_RXDMA_RPA_INT) {
                err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->rpa_err_reg);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                err, &isrbar0->rpa_err_reg);
                hldev->stats.sw_dev_info_stats.rpa_err_cnt++;
                temp64 = XGE_HAL_RPA_SM_ERR_ALARM|XGE_HAL_RPA_CREDIT_ERR;
                if (val64 & temp64)
                        goto reset;
        }
        if (val64 & XGE_HAL_RXDMA_RDA_INT) {
                err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->rda_err_reg);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                err, &isrbar0->rda_err_reg);
                hldev->stats.sw_dev_info_stats.rda_err_cnt++;
                temp64 = XGE_HAL_RDA_RXDn_ECC_DB_ERR
                        |XGE_HAL_RDA_FRM_ECC_DB_N_AERR
                        |XGE_HAL_RDA_SM1_ERR_ALARM|XGE_HAL_RDA_SM0_ERR_ALARM
                        |XGE_HAL_RDA_RXD_ECC_DB_SERR;
                if (val64 & temp64)
                        goto reset;
        }
        if (val64 & XGE_HAL_RXDMA_RTI_INT) {
                err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->rti_err_reg);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                err, &isrbar0->rti_err_reg);
                hldev->stats.sw_dev_info_stats.rti_err_cnt++;
                temp64 = XGE_HAL_RTI_SM_ERR_ALARM;
                if (val64 & temp64)
                        goto reset;
        }

        return XGE_HAL_OK;

reset : (void) xge_hal_device_reset(hldev);
        (void) xge_hal_device_enable(hldev);
        xge_hal_device_intr_enable(hldev);
        return XGE_HAL_OK;
}

/*
 * __hal_device_handle_rxmac - Handle RxMAC interrupt reason
 * @hldev: HAL device handle.
 * @reason: interrupt reason
 */
xge_hal_status_e
__hal_device_handle_rxmac(xge_hal_device_t *hldev, u64 reason)
{
        xge_hal_pci_bar0_t *isrbar0 =
                (xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
        u64 val64, temp64;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->mac_int_status);
        if (!(val64 & XGE_HAL_MAC_INT_STATUS_RMAC_INT))
                return XGE_HAL_OK;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->mac_rmac_err_reg);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                val64, &isrbar0->mac_rmac_err_reg);
        hldev->stats.sw_dev_info_stats.mac_rmac_err_cnt++;
        temp64 = XGE_HAL_RMAC_RX_BUFF_OVRN|XGE_HAL_RMAC_RX_SM_ERR;
        if (val64 & temp64) {
                (void) xge_hal_device_reset(hldev);
                (void) xge_hal_device_enable(hldev);
                xge_hal_device_intr_enable(hldev);
        }

        return XGE_HAL_OK;
}

/*
 * __hal_device_handle_rxxgxs - Handle RxXGXS interrupt reason
 * @hldev: HAL device handle.
 * @reason: interrupt reason
 */
xge_hal_status_e
__hal_device_handle_rxxgxs(xge_hal_device_t *hldev, u64 reason)
{
        xge_hal_pci_bar0_t *isrbar0 =
                (xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
        u64 val64, temp64;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->xgxs_int_status);
        if (!(val64 & XGE_HAL_XGXS_INT_STATUS_RXGXS))
                return XGE_HAL_OK;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &isrbar0->xgxs_rxgxs_err_reg);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                val64, &isrbar0->xgxs_rxgxs_err_reg);
        hldev->stats.sw_dev_info_stats.xgxs_rxgxs_err_cnt++;
        temp64 = XGE_HAL_RXGXS_ESTORE_OFLOW|XGE_HAL_RXGXS_RX_SM_ERR;
        if (val64 & temp64) {
                (void) xge_hal_device_reset(hldev);
                (void) xge_hal_device_enable(hldev);
                xge_hal_device_intr_enable(hldev);
        }

        return XGE_HAL_OK;
}

/**
 * xge_hal_device_enable - Enable device.
 * @hldev: HAL device handle.
 *
 * Enable the specified device: bring up the link/interface.
 * Returns:  XGE_HAL_OK - success.
 * XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT - Failed to restore the device
 * to a "quiescent" state.
 *
 * See also: xge_hal_status_e{}.
 *
 * Usage: See ex_open{}.
 */
xge_hal_status_e
xge_hal_device_enable(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;
        u64 adp_status;
        int i, j;

        if (!hldev->hw_is_initialized) {
                xge_hal_status_e status;

                status = __hal_device_hw_initialize(hldev);
                if (status != XGE_HAL_OK) {
                        return status;
                }
        }

        /*
         * Not needed in most cases, i.e.
         * when device_disable() is followed by reset -
         * the latter copies back PCI config space, along with
         * the bus mastership - see __hal_device_reset().
         * However, there are/may-in-future be other cases, and
         * does not hurt.
         */
        __hal_device_bus_master_enable(hldev);

        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
                /*
                 * Configure the link stability period.
                 */
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                              &bar0->misc_control);
                if (hldev->config.link_stability_period !=
                                XGE_HAL_DEFAULT_USE_HARDCODE) {

                        val64 |= XGE_HAL_MISC_CONTROL_LINK_STABILITY_PERIOD(
                                        hldev->config.link_stability_period);
                } else {
                        /*
                         * Use the link stability period 1 ms as default
                         */
                        val64 |= XGE_HAL_MISC_CONTROL_LINK_STABILITY_PERIOD(
                                        XGE_HAL_DEFAULT_LINK_STABILITY_PERIOD);
                }
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                       val64, &bar0->misc_control);

                /*
                 * Clearing any possible Link up/down interrupts that
                 * could have popped up just before Enabling the card.
                 */
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                              &bar0->misc_int_reg);
                if (val64) {
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                               val64, &bar0->misc_int_reg);
                        xge_debug_device(XGE_TRACE, "%s","link state cleared");
                }
        } else if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA) {
                /*
                 * Clearing any possible Link state change interrupts that
                 * could have popped up just before Enabling the card.
                 */
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                        &bar0->mac_rmac_err_reg);
                if (val64) {
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                               val64, &bar0->mac_rmac_err_reg);
                        xge_debug_device(XGE_TRACE, "%s", "link state cleared");
                }
        }

        if (__hal_device_wait_quiescent(hldev, &val64)) {
                return XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT;
        }

        /* Enabling Laser. */
        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                    &bar0->adapter_control);
        val64 |= XGE_HAL_ADAPTER_EOI_TX_ON;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                             &bar0->adapter_control);

        /* let link establish */
        xge_os_mdelay(1);

        /* set link down untill poll() routine will set it up (maybe) */
        hldev->link_state = XGE_HAL_LINK_DOWN;

        /* If link is UP (adpter is connected) then enable the adapter */
        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                    &bar0->adapter_status);
        if( val64 & (XGE_HAL_ADAPTER_STATUS_RMAC_REMOTE_FAULT |
                     XGE_HAL_ADAPTER_STATUS_RMAC_LOCAL_FAULT) ) {
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                        &bar0->adapter_control);
                val64 = val64 & (~XGE_HAL_ADAPTER_LED_ON);
        } else {
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                           &bar0->adapter_control);
                val64 = val64 | ( XGE_HAL_ADAPTER_EOI_TX_ON |
                                  XGE_HAL_ADAPTER_LED_ON );
        }

        val64 = val64 | XGE_HAL_ADAPTER_CNTL_EN;   /* adapter enable */
        val64 = val64 & (~XGE_HAL_ADAPTER_ECC_EN); /* ECC enable */
        xge_os_pio_mem_write64 (hldev->pdev, hldev->regh0, val64,
                              &bar0->adapter_control);

        /* We spin here waiting for the Link to come up.
         * This is the fix for the Link being unstable after the reset. */
        i = 0;
        j = 0;
        do
        {
                adp_status = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                                &bar0->adapter_status);

                /* Read the adapter control register for Adapter_enable bit */
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                           &bar0->adapter_control);
                if (!(adp_status & (XGE_HAL_ADAPTER_STATUS_RMAC_REMOTE_FAULT |
                                    XGE_HAL_ADAPTER_STATUS_RMAC_LOCAL_FAULT)) &&
                    (val64 & XGE_HAL_ADAPTER_CNTL_EN)) {
                        j++;
                        if (j >= hldev->config.link_valid_cnt) {
                                if (xge_hal_device_status(hldev, &adp_status) ==
                                                        XGE_HAL_OK) {
                                        if (__hal_verify_pcc_idle(hldev,
                                                  adp_status) != XGE_HAL_OK) {
                                           return
                                            XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT;
                                        }
                                        xge_debug_device(XGE_TRACE,
                                              "adp_status: "XGE_OS_LLXFMT
                                              ", link is up on "
                                              "adapter enable!",
                                              (unsigned long long)adp_status);
                                        val64 = xge_os_pio_mem_read64(
                                                        hldev->pdev,
                                                        hldev->regh0,
                                                        &bar0->adapter_control);
                                        val64 = val64|
                                                (XGE_HAL_ADAPTER_EOI_TX_ON |
                                                 XGE_HAL_ADAPTER_LED_ON );
                                        xge_os_pio_mem_write64(hldev->pdev,
                                                        hldev->regh0, val64,
                                                        &bar0->adapter_control);
                                        xge_os_mdelay(1);

                                        val64 = xge_os_pio_mem_read64(
                                                        hldev->pdev,
                                                        hldev->regh0,
                                                        &bar0->adapter_control);
                                        break;    /* out of for loop */
                                } else {
                                       return
                                           XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT;
                                }
                        }
                } else {
                        j = 0;  /* Reset the count */
                        /* Turn on the Laser */
                        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                        &bar0->adapter_control);
                        val64 = val64 | XGE_HAL_ADAPTER_EOI_TX_ON;
                        xge_os_pio_mem_write64 (hldev->pdev, hldev->regh0,
                                                val64, &bar0->adapter_control);

                        xge_os_mdelay(1);

                        /* Now re-enable it as due to noise, hardware
                         * turned it off */
                        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                                    &bar0->adapter_control);
                        val64 |= XGE_HAL_ADAPTER_CNTL_EN;
                        val64 = val64 & (~XGE_HAL_ADAPTER_ECC_EN);/*ECC enable*/
                        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                                            &bar0->adapter_control);
                }
                xge_os_mdelay(1); /* Sleep for 1 msec */
                i++;
        } while (i < hldev->config.link_retry_cnt);

        __hal_device_led_actifity_fix(hldev);

#ifndef  XGE_HAL_PROCESS_LINK_INT_IN_ISR
        /* Here we are performing soft reset on XGXS to force link down.
         * Since link is already up, we will get link state change
         * poll notificatoin after adapter is enabled */

        __hal_serial_mem_write64(hldev, 0x80010515001E0000ULL,
                                 &bar0->dtx_control);
        (void) __hal_serial_mem_read64(hldev, &bar0->dtx_control);

        __hal_serial_mem_write64(hldev, 0x80010515001E00E0ULL,
                                 &bar0->dtx_control);
        (void) __hal_serial_mem_read64(hldev, &bar0->dtx_control);

        __hal_serial_mem_write64(hldev, 0x80070515001F00E4ULL,
                                 &bar0->dtx_control);
        (void) __hal_serial_mem_read64(hldev, &bar0->dtx_control);

        xge_os_mdelay(100); /* Sleep for 500 msec */
#else
        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA)
#endif
        {
                /*
                 * With some switches the link state change interrupt does not
                 * occur even though the xgxs reset is done as per SPN-006. So,
                 * poll the adapter status register and check if the link state
                 * is ok.
                 */
                adp_status = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                                   &bar0->adapter_status);
                if (!(adp_status & (XGE_HAL_ADAPTER_STATUS_RMAC_REMOTE_FAULT |
                      XGE_HAL_ADAPTER_STATUS_RMAC_LOCAL_FAULT)))
                {
                        xge_debug_device(XGE_TRACE, "%s",
                             "enable device causing link state change ind..");
                        (void) __hal_device_handle_link_state_change(hldev);
                }
        }

        if (hldev->config.stats_refresh_time_sec !=
            XGE_HAL_STATS_REFRESH_DISABLE)
                __hal_stats_enable(&hldev->stats);

        return XGE_HAL_OK;
}

/**
 * xge_hal_device_disable - Disable Xframe adapter.
 * @hldev: Device handle.
 *
 * Disable this device. To gracefully reset the adapter, the host should:
 *
 *      - call xge_hal_device_disable();
 *
 *      - call xge_hal_device_intr_disable();
 *
 *      - close all opened channels and clean up outstanding resources;
 *
 *      - do some work (error recovery, change mtu, reset, etc);
 *
 *      - call xge_hal_device_enable();
 *
 *      - open channels, replenish RxDs, etc.
 *
 *      - call xge_hal_device_intr_enable().
 *
 * Note: Disabling the device does _not_ include disabling of interrupts.
 * After disabling the device stops receiving new frames but those frames
 * that were already in the pipe will keep coming for some few milliseconds.
 *
 * Returns:  XGE_HAL_OK - success.
 * XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT - Failed to restore the device to
 * a "quiescent" state.
 *
 * See also: xge_hal_status_e{}.
 */
xge_hal_status_e
xge_hal_device_disable(xge_hal_device_t *hldev)
{
        xge_hal_status_e status = XGE_HAL_OK;
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;

        xge_debug_device(XGE_TRACE, "%s", "turn off laser, cleanup hardware");

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                    &bar0->adapter_control);
        val64 = val64 & (~XGE_HAL_ADAPTER_CNTL_EN);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                             &bar0->adapter_control);

        if (__hal_device_wait_quiescent(hldev, &val64) != XGE_HAL_OK) {
                status = XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT;
        }

        if (__hal_device_register_poll(hldev, &bar0->adapter_status, 1,
                 XGE_HAL_ADAPTER_STATUS_RC_PRC_QUIESCENT,
                 XGE_HAL_DEVICE_QUIESCENT_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
                xge_debug_device(XGE_TRACE, "%s", "PRC is not QUIESCENT!");
                status = XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT;
        }

        if (hldev->config.stats_refresh_time_sec !=
            XGE_HAL_STATS_REFRESH_DISABLE)
                __hal_stats_disable(&hldev->stats);
#ifdef XGE_DEBUG_ASSERT
        else
                xge_assert(!hldev->stats.is_enabled);
#endif

#ifndef XGE_HAL_DONT_DISABLE_BUS_MASTER_ON_STOP
        __hal_device_bus_master_disable(hldev);
#endif

        return status;
}

/**
 * xge_hal_device_reset - Reset device.
 * @hldev: HAL device handle.
 *
 * Soft-reset the device, reset the device stats except reset_cnt.
 *
 * After reset is done, will try to re-initialize HW.
 *
 * Returns:  XGE_HAL_OK - success.
 * XGE_HAL_ERR_DEVICE_NOT_INITIALIZED - Device is not initialized.
 * XGE_HAL_ERR_RESET_FAILED - Reset failed.
 *
 * See also: xge_hal_status_e{}.
 */
xge_hal_status_e
xge_hal_device_reset(xge_hal_device_t *hldev)
{
        xge_hal_status_e status;

        /* increment the soft reset counter */
        u32 reset_cnt = hldev->stats.sw_dev_info_stats.soft_reset_cnt;

        xge_debug_device(XGE_TRACE, "%s (%d)", "resetting the device", reset_cnt);

        if (!hldev->is_initialized)
                return XGE_HAL_ERR_DEVICE_NOT_INITIALIZED;

        /* actual "soft" reset of the adapter */
        status = __hal_device_reset(hldev);

        /* reset all stats including saved */
        __hal_stats_soft_reset(hldev, 1);

        /* increment reset counter */
        hldev->stats.sw_dev_info_stats.soft_reset_cnt = reset_cnt + 1;

        /* re-initialize rxufca_intr_thres */
        hldev->rxufca_intr_thres = hldev->config.rxufca_intr_thres;

        hldev->reset_needed_after_close = 0;

        return status;
}

/**
 * xge_hal_device_status - Check whether Xframe hardware is ready for
 * operation.
 * @hldev: HAL device handle.
 * @hw_status: Xframe status register. Returned by HAL.
 *
 * Check whether Xframe hardware is ready for operation.
 * The checking includes TDMA, RDMA, PFC, PIC, MC_DRAM, and the rest
 * hardware functional blocks.
 *
 * Returns: XGE_HAL_OK if the device is ready for operation. Otherwise
 * returns XGE_HAL_FAIL. Also, fills in  adapter status (in @hw_status).
 *
 * See also: xge_hal_status_e{}.
 * Usage: See ex_open{}.
 */
xge_hal_status_e
xge_hal_device_status(xge_hal_device_t *hldev, u64 *hw_status)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 tmp64;

        tmp64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                    &bar0->adapter_status);

        *hw_status = tmp64;

        if (!(tmp64 & XGE_HAL_ADAPTER_STATUS_TDMA_READY)) {
                xge_debug_device(XGE_TRACE, "%s", "TDMA is not ready!");
                return XGE_HAL_FAIL;
        }
        if (!(tmp64 & XGE_HAL_ADAPTER_STATUS_RDMA_READY)) {
                xge_debug_device(XGE_TRACE, "%s", "RDMA is not ready!");
                return XGE_HAL_FAIL;
        }
        if (!(tmp64 & XGE_HAL_ADAPTER_STATUS_PFC_READY)) {
                xge_debug_device(XGE_TRACE, "%s", "PFC is not ready!");
                return XGE_HAL_FAIL;
        }
        if (!(tmp64 & XGE_HAL_ADAPTER_STATUS_TMAC_BUF_EMPTY)) {
                xge_debug_device(XGE_TRACE, "%s", "TMAC BUF is not empty!");
                return XGE_HAL_FAIL;
        }
        if (!(tmp64 & XGE_HAL_ADAPTER_STATUS_PIC_QUIESCENT)) {
                xge_debug_device(XGE_TRACE, "%s", "PIC is not QUIESCENT!");
                return XGE_HAL_FAIL;
        }
        if (!(tmp64 & XGE_HAL_ADAPTER_STATUS_MC_DRAM_READY)) {
                xge_debug_device(XGE_TRACE, "%s", "MC_DRAM is not ready!");
                return XGE_HAL_FAIL;
        }
        if (!(tmp64 & XGE_HAL_ADAPTER_STATUS_MC_QUEUES_READY)) {
                xge_debug_device(XGE_TRACE, "%s", "MC_QUEUES is not ready!");
                return XGE_HAL_FAIL;
        }
        if (!(tmp64 & XGE_HAL_ADAPTER_STATUS_M_PLL_LOCK)) {
                xge_debug_device(XGE_TRACE, "%s", "M_PLL is not locked!");
                return XGE_HAL_FAIL;
        }
#ifndef XGE_HAL_HERC_EMULATION
        /*
         * Andrew: in PCI 33 mode, the P_PLL is not used, and therefore,
         * the the P_PLL_LOCK bit in the adapter_status register will
         * not be asserted.
         */
        if (!(tmp64 & XGE_HAL_ADAPTER_STATUS_P_PLL_LOCK) &&
             xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC &&
             hldev->pci_mode != XGE_HAL_PCI_33MHZ_MODE) {
                xge_debug_device(XGE_TRACE, "%s", "P_PLL is not locked!");
                return XGE_HAL_FAIL;
        }
#endif

        return XGE_HAL_OK;
}

void
__hal_device_msi_intr_endis(xge_hal_device_t *hldev, int flag)
{
        u16 msi_control_reg;

        xge_os_pci_read16(hldev->pdev, hldev->cfgh,
             xge_offsetof(xge_hal_pci_config_le_t,
                          msi_control), &msi_control_reg);

        if (flag)
                msi_control_reg |= 0x1;
        else
                msi_control_reg &= ~0x1;

        xge_os_pci_write16(hldev->pdev, hldev->cfgh,
             xge_offsetof(xge_hal_pci_config_le_t,
                             msi_control), msi_control_reg);
}

void
__hal_device_msix_intr_endis(xge_hal_device_t *hldev,
                              xge_hal_channel_t *channel, int flag)
{
        u64 val64;
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)hldev->bar0;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                &bar0->xmsi_mask_reg);

        if (flag)
                val64 &= ~(1LL << ( 63 - channel->msix_idx ));
        else
                val64 |= (1LL << ( 63 - channel->msix_idx ));
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                &bar0->xmsi_mask_reg);
}

/**
 * xge_hal_device_intr_enable - Enable Xframe interrupts.
 * @hldev: HAL device handle.
 * @op: One of the xge_hal_device_intr_e enumerated values specifying
 *      the type(s) of interrupts to enable.
 *
 * Enable Xframe interrupts. The function is to be executed the last in
 * Xframe initialization sequence.
 *
 * See also: xge_hal_device_intr_disable()
 */
void
xge_hal_device_intr_enable(xge_hal_device_t *hldev)
{
        xge_list_t *item;
        u64 val64;

        /* PRC initialization and configuration */
        xge_list_for_each(item, &hldev->ring_channels) {
                xge_hal_channel_h channel;
                channel = xge_container_of(item, xge_hal_channel_t, item);
                __hal_ring_prc_enable(channel);
        }

        /* enable traffic only interrupts */
        if (hldev->config.intr_mode != XGE_HAL_INTR_MODE_IRQLINE) {
                /*
                 * make sure all interrupts going to be disabled if MSI
                 * is enabled.
                 */
#ifdef XGE_HAL_PROCESS_LINK_INT_IN_ISR
                __hal_device_intr_mgmt(hldev, XGE_HAL_TX_PIC_INTR, 1);
#else
                __hal_device_intr_mgmt(hldev, XGE_HAL_ALL_INTRS, 0);
#endif
        } else {
                /*
                 * Enable the Tx traffic interrupts only if the TTI feature is
                 * enabled.
                 */
                val64 = 0;
                if (hldev->tti_enabled)
                        val64 = XGE_HAL_TX_TRAFFIC_INTR;

                if (!hldev->config.bimodal_interrupts)
                        val64 |= XGE_HAL_RX_TRAFFIC_INTR;

                if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA)
                        val64 |= XGE_HAL_RX_TRAFFIC_INTR;

                val64 |=XGE_HAL_TX_PIC_INTR |
                        XGE_HAL_MC_INTR |
                        XGE_HAL_TX_DMA_INTR |
                        (hldev->config.sched_timer_us !=
                         XGE_HAL_SCHED_TIMER_DISABLED ? XGE_HAL_SCHED_INTR : 0);
                __hal_device_intr_mgmt(hldev, val64, 1);
        }

        /*
         * Enable MSI-X interrupts
         */
        if (hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSIX) {

                if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
                        /*
                         * To enable MSI-X, MSI also needs to be enabled,
                         * due to a bug in the herc NIC.
                         */
                        __hal_device_msi_intr_endis(hldev, 1);
                }


                /* Enable the MSI-X interrupt for each configured channel */
                xge_list_for_each(item, &hldev->fifo_channels) {
                        xge_hal_channel_t *channel;

                        channel = xge_container_of(item,
                                           xge_hal_channel_t, item);

                        /* 0 vector is reserved for alarms */
                        if (!channel->msix_idx)
                                continue;

                        __hal_device_msix_intr_endis(hldev, channel, 1);
                }

                xge_list_for_each(item, &hldev->ring_channels) {
                        xge_hal_channel_t *channel;

                        channel = xge_container_of(item,
                                           xge_hal_channel_t, item);

                        /* 0 vector is reserved for alarms */
                        if (!channel->msix_idx)
                                continue;

                        __hal_device_msix_intr_endis(hldev, channel, 1);
                }
        }

        xge_debug_device(XGE_TRACE, "%s", "interrupts are enabled");
}


/**
 * xge_hal_device_intr_disable - Disable Xframe interrupts.
 * @hldev: HAL device handle.
 * @op: One of the xge_hal_device_intr_e enumerated values specifying
 *      the type(s) of interrupts to disable.
 *
 * Disable Xframe interrupts.
 *
 * See also: xge_hal_device_intr_enable()
 */
void
xge_hal_device_intr_disable(xge_hal_device_t *hldev)
{
        xge_list_t *item;
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;

        if (hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSIX) {

                if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
                        /*
                         * To disable MSI-X, MSI also needs to be disabled,
                         * due to a bug in the herc NIC.
                         */
                        __hal_device_msi_intr_endis(hldev, 0);
                }

                /* Disable the MSI-X interrupt for each configured channel */
                xge_list_for_each(item, &hldev->fifo_channels) {
                        xge_hal_channel_t *channel;

                        channel = xge_container_of(item,
                                           xge_hal_channel_t, item);

                        /* 0 vector is reserved for alarms */
                        if (!channel->msix_idx)
                                continue;

                        __hal_device_msix_intr_endis(hldev, channel, 0);

                }

                xge_os_pio_mem_write64(hldev->pdev,
                        hldev->regh0, 0xFFFFFFFFFFFFFFFFULL,
                        &bar0->tx_traffic_mask);

                xge_list_for_each(item, &hldev->ring_channels) {
                        xge_hal_channel_t *channel;

                        channel = xge_container_of(item,
                                           xge_hal_channel_t, item);

                        /* 0 vector is reserved for alarms */
                        if (!channel->msix_idx)
                                continue;

                        __hal_device_msix_intr_endis(hldev, channel, 0);
                }

                xge_os_pio_mem_write64(hldev->pdev,
                        hldev->regh0, 0xFFFFFFFFFFFFFFFFULL,
                        &bar0->rx_traffic_mask);
        }

        /*
         * Disable traffic only interrupts.
         * Tx traffic interrupts are used only if the TTI feature is
         * enabled.
         */
        val64 = 0;
        if (hldev->tti_enabled)
                val64 = XGE_HAL_TX_TRAFFIC_INTR;

        val64 |= XGE_HAL_RX_TRAFFIC_INTR |
                 XGE_HAL_TX_PIC_INTR |
                 XGE_HAL_MC_INTR |
                 (hldev->config.sched_timer_us != XGE_HAL_SCHED_TIMER_DISABLED ?
                                                XGE_HAL_SCHED_INTR : 0);
        __hal_device_intr_mgmt(hldev, val64, 0);

        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                             0xFFFFFFFFFFFFFFFFULL,
                             &bar0->general_int_mask);


        /* disable all configured PRCs */
        xge_list_for_each(item, &hldev->ring_channels) {
                xge_hal_channel_h channel;
                channel = xge_container_of(item, xge_hal_channel_t, item);
                __hal_ring_prc_disable(channel);
        }

        xge_debug_device(XGE_TRACE, "%s", "interrupts are disabled");
}


/**
 * xge_hal_device_mcast_enable - Enable Xframe multicast addresses.
 * @hldev: HAL device handle.
 *
 * Enable Xframe multicast addresses.
 * Returns: XGE_HAL_OK on success.
 * XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING - Failed to enable mcast
 * feature within the time(timeout).
 *
 * See also: xge_hal_device_mcast_disable(), xge_hal_status_e{}.
 */
xge_hal_status_e
xge_hal_device_mcast_enable(xge_hal_device_t *hldev)
{
        u64 val64;
        xge_hal_pci_bar0_t *bar0;
        int mc_offset = XGE_HAL_MAC_MC_ALL_MC_ADDR_OFFSET;

        if (hldev == NULL)
                return XGE_HAL_ERR_INVALID_DEVICE;

        if (hldev->mcast_refcnt)
                return XGE_HAL_OK;

        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC)
                mc_offset = XGE_HAL_MAC_MC_ALL_MC_ADDR_OFFSET_HERC;

        hldev->mcast_refcnt = 1;

        bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;

        /*  Enable all Multicast addresses */
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
              XGE_HAL_RMAC_ADDR_DATA0_MEM_ADDR(0x010203040506ULL),
              &bar0->rmac_addr_data0_mem);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
              XGE_HAL_RMAC_ADDR_DATA1_MEM_MASK(0xfeffffffffffULL),
              &bar0->rmac_addr_data1_mem);
        val64 = XGE_HAL_RMAC_ADDR_CMD_MEM_WE |
                XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
                XGE_HAL_RMAC_ADDR_CMD_MEM_OFFSET(mc_offset);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                            &bar0->rmac_addr_cmd_mem);

        if (__hal_device_register_poll(hldev,
                &bar0->rmac_addr_cmd_mem, 0,
                XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
                XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
                /* upper layer may require to repeat */
                return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
        }

        return XGE_HAL_OK;
}

/**
 * xge_hal_device_mcast_disable - Disable Xframe multicast addresses.
 * @hldev: HAL device handle.
 *
 * Disable Xframe multicast addresses.
 * Returns: XGE_HAL_OK - success.
 * XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING - Failed to disable mcast
 * feature within the time(timeout).
 *
 * See also: xge_hal_device_mcast_enable(), xge_hal_status_e{}.
 */
xge_hal_status_e
xge_hal_device_mcast_disable(xge_hal_device_t *hldev)
{
        u64 val64;
        xge_hal_pci_bar0_t *bar0;
        int mc_offset = XGE_HAL_MAC_MC_ALL_MC_ADDR_OFFSET;

        if (hldev == NULL)
                return XGE_HAL_ERR_INVALID_DEVICE;

        if (hldev->mcast_refcnt == 0)
                return XGE_HAL_OK;

        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC)
                mc_offset = XGE_HAL_MAC_MC_ALL_MC_ADDR_OFFSET_HERC;

        hldev->mcast_refcnt = 0;

        bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;

        /*  Disable all Multicast addresses */
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
               XGE_HAL_RMAC_ADDR_DATA0_MEM_ADDR(0xffffffffffffULL),
                       &bar0->rmac_addr_data0_mem);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
               XGE_HAL_RMAC_ADDR_DATA1_MEM_MASK(0),
                       &bar0->rmac_addr_data1_mem);

        val64 = XGE_HAL_RMAC_ADDR_CMD_MEM_WE |
                XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
                XGE_HAL_RMAC_ADDR_CMD_MEM_OFFSET(mc_offset);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                            &bar0->rmac_addr_cmd_mem);

        if (__hal_device_register_poll(hldev,
                &bar0->rmac_addr_cmd_mem, 0,
                XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
                XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
                /* upper layer may require to repeat */
                return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
        }

        return XGE_HAL_OK;
}

/**
 * xge_hal_device_promisc_enable - Enable promiscuous mode.
 * @hldev: HAL device handle.
 *
 * Enable promiscuous mode of Xframe operation.
 *
 * See also: xge_hal_device_promisc_disable().
 */
void
xge_hal_device_promisc_enable(xge_hal_device_t *hldev)
{
        u64 val64;
        xge_hal_pci_bar0_t *bar0;

        xge_assert(hldev);

        bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;

        if (!hldev->is_promisc) {
                /*  Put the NIC into promiscuous mode */
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                            &bar0->mac_cfg);
                val64 |= XGE_HAL_MAC_CFG_RMAC_PROM_ENABLE;

                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                               XGE_HAL_RMAC_CFG_KEY(0x4C0D),
                               &bar0->rmac_cfg_key);

                __hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0,
                                      (u32)(val64 >> 32),
                                      &bar0->mac_cfg);

                hldev->is_promisc = 1;
                xge_debug_device(XGE_TRACE,
                        "mac_cfg 0x"XGE_OS_LLXFMT": promisc enabled",
                        (unsigned long long)val64);
        }
}

/**
 * xge_hal_device_promisc_disable - Disable promiscuous mode.
 * @hldev: HAL device handle.
 *
 * Disable promiscuous mode of Xframe operation.
 *
 * See also: xge_hal_device_promisc_enable().
 */
void
xge_hal_device_promisc_disable(xge_hal_device_t *hldev)
{
        u64 val64;
        xge_hal_pci_bar0_t *bar0;

        xge_assert(hldev);

        bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;

        if (hldev->is_promisc) {
                /*  Remove the NIC from promiscuous mode */
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                            &bar0->mac_cfg);
                val64 &= ~XGE_HAL_MAC_CFG_RMAC_PROM_ENABLE;

                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                               XGE_HAL_RMAC_CFG_KEY(0x4C0D),
                               &bar0->rmac_cfg_key);

                __hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0,
                                      (u32)(val64 >> 32),
                                      &bar0->mac_cfg);

                hldev->is_promisc = 0;
                xge_debug_device(XGE_TRACE,
                        "mac_cfg 0x"XGE_OS_LLXFMT": promisc disabled",
                        (unsigned long long)val64);
        }
}

/**
 * xge_hal_device_macaddr_get - Get MAC addresses.
 * @hldev: HAL device handle.
 * @index: MAC address index, in the range from 0 to
 * XGE_HAL_MAX_MAC_ADDRESSES.
 * @macaddr: MAC address. Returned by HAL.
 *
 * Retrieve one of the stored MAC addresses by reading non-volatile
 * memory on the chip.
 *
 * Up to %XGE_HAL_MAX_MAC_ADDRESSES addresses is supported.
 *
 * Returns: XGE_HAL_OK - success.
 * XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING - Failed to retrieve the mac
 * address within the time(timeout).
 * XGE_HAL_ERR_OUT_OF_MAC_ADDRESSES - Invalid MAC address index.
 *
 * See also: xge_hal_device_macaddr_set(), xge_hal_status_e{}.
 */
xge_hal_status_e
xge_hal_device_macaddr_get(xge_hal_device_t *hldev, int index,
                        macaddr_t *macaddr)
{
        xge_hal_pci_bar0_t *bar0;
        u64 val64;
        int i;

        if (hldev == NULL) {
                return XGE_HAL_ERR_INVALID_DEVICE;
        }

        bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;

        if ( index >= XGE_HAL_MAX_MAC_ADDRESSES ) {
                return XGE_HAL_ERR_OUT_OF_MAC_ADDRESSES;
        }

#ifdef XGE_HAL_HERC_EMULATION
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,0x0000010000000000,
                                    &bar0->rmac_addr_data0_mem);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,0x0000000000000000,
                                    &bar0->rmac_addr_data1_mem);
    val64 = XGE_HAL_RMAC_ADDR_CMD_MEM_RD |
                                 XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
                                 XGE_HAL_RMAC_ADDR_CMD_MEM_OFFSET((index));
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                             &bar0->rmac_addr_cmd_mem);

                /* poll until done */
        __hal_device_register_poll(hldev,
                       &bar0->rmac_addr_cmd_mem, 0,
                       XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD,
                       XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS);

#endif

        val64 = ( XGE_HAL_RMAC_ADDR_CMD_MEM_RD |
                  XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
                  XGE_HAL_RMAC_ADDR_CMD_MEM_OFFSET((index)) );
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                             &bar0->rmac_addr_cmd_mem);

        if (__hal_device_register_poll(hldev, &bar0->rmac_addr_cmd_mem, 0,
                   XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
                   XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
                /* upper layer may require to repeat */
                return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
        }

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                    &bar0->rmac_addr_data0_mem);
        for (i=0; i < XGE_HAL_ETH_ALEN; i++) {
                (*macaddr)[i] = (u8)(val64 >> ((64 - 8) - (i * 8)));
        }

#ifdef XGE_HAL_HERC_EMULATION
        for (i=0; i < XGE_HAL_ETH_ALEN; i++) {
                (*macaddr)[i] = (u8)0;
        }
        (*macaddr)[1] = (u8)1;

#endif

        return XGE_HAL_OK;
}

/**
 * xge_hal_device_macaddr_set - Set MAC address.
 * @hldev: HAL device handle.
 * @index: MAC address index, in the range from 0 to
 * XGE_HAL_MAX_MAC_ADDRESSES.
 * @macaddr: New MAC address to configure.
 *
 * Configure one of the available MAC address "slots".
 *
 * Up to %XGE_HAL_MAX_MAC_ADDRESSES addresses is supported.
 *
 * Returns: XGE_HAL_OK - success.
 * XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING - Failed to set the new mac
 * address within the time(timeout).
 * XGE_HAL_ERR_OUT_OF_MAC_ADDRESSES - Invalid MAC address index.
 *
 * See also: xge_hal_device_macaddr_get(), xge_hal_status_e{}.
 */
xge_hal_status_e
xge_hal_device_macaddr_set(xge_hal_device_t *hldev, int index,
                        macaddr_t macaddr)
{
        xge_hal_pci_bar0_t *bar0 =
                (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64, temp64;
        int i;

        if ( index >= XGE_HAL_MAX_MAC_ADDRESSES )
                return XGE_HAL_ERR_OUT_OF_MAC_ADDRESSES;

        temp64 = 0;
        for (i=0; i < XGE_HAL_ETH_ALEN; i++) {
                temp64 |= macaddr[i];
                temp64 <<= 8;
        }
        temp64 >>= 8;

        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                        XGE_HAL_RMAC_ADDR_DATA0_MEM_ADDR(temp64),
                        &bar0->rmac_addr_data0_mem);

        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                        XGE_HAL_RMAC_ADDR_DATA1_MEM_MASK(0ULL),
                        &bar0->rmac_addr_data1_mem);

        val64 = ( XGE_HAL_RMAC_ADDR_CMD_MEM_WE |
                  XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
                  XGE_HAL_RMAC_ADDR_CMD_MEM_OFFSET((index)) );

        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                             &bar0->rmac_addr_cmd_mem);

        if (__hal_device_register_poll(hldev, &bar0->rmac_addr_cmd_mem, 0,
                   XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
                   XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
                /* upper layer may require to repeat */
                return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
        }

        return XGE_HAL_OK;
}

/**
 * xge_hal_device_macaddr_clear - Set MAC address.
 * @hldev: HAL device handle.
 * @index: MAC address index, in the range from 0 to
 * XGE_HAL_MAX_MAC_ADDRESSES.
 *
 * Clear one of the available MAC address "slots".
 *
 * Returns: XGE_HAL_OK - success.
 * XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING - Failed to set the new mac
 * address within the time(timeout).
 * XGE_HAL_ERR_OUT_OF_MAC_ADDRESSES - Invalid MAC address index.
 *
 * See also: xge_hal_device_macaddr_set(), xge_hal_status_e{}.
 */
xge_hal_status_e
xge_hal_device_macaddr_clear(xge_hal_device_t *hldev, int index)
{
        xge_hal_status_e status;
        u8 macaddr[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

        status = xge_hal_device_macaddr_set(hldev, index, macaddr);
        if (status != XGE_HAL_OK) {
                xge_debug_device(XGE_ERR, "%s",
                        "Not able to set the mac addr");
                return status;
        }

        return XGE_HAL_OK;
}

/**
 * xge_hal_device_macaddr_find - Finds index in the rmac table.
 * @hldev: HAL device handle.
 * @wanted: Wanted MAC address.
 *
 * See also: xge_hal_device_macaddr_set().
 */
int
xge_hal_device_macaddr_find(xge_hal_device_t *hldev, macaddr_t wanted)
{
        int i;
        macaddr_t macaddr;

        if (hldev == NULL) {
                return XGE_HAL_ERR_INVALID_DEVICE;
        }

        for (i=0; i<XGE_HAL_MAX_MAC_ADDRESSES; i++) {
                (void) xge_hal_device_macaddr_get(hldev, i, &macaddr);
                if (!xge_os_memcmp(macaddr, wanted, sizeof(macaddr_t))) {
                        return i;
                }
        }

        return -1;
}

/**
 * xge_hal_device_mtu_set - Set MTU.
 * @hldev: HAL device handle.
 * @new_mtu: New MTU size to configure.
 *
 * Set new MTU value. Example, to use jumbo frames:
 * xge_hal_device_mtu_set(my_device, my_channel, 9600);
 *
 * Returns: XGE_HAL_OK on success.
 * XGE_HAL_ERR_SWAPPER_CTRL - Failed to configure swapper control
 * register.
 * XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING - Failed to initialize TTI/RTI
 * schemes.
 * XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT - Failed to restore the device to
 * a "quiescent" state.
 */
xge_hal_status_e
xge_hal_device_mtu_set(xge_hal_device_t *hldev, int new_mtu)
{
        xge_hal_status_e status;

        /*
         * reset needed if 1) new MTU differs, and
         * 2a) device was closed or
         * 2b) device is being upped for first time.
         */
        if (hldev->config.mtu != new_mtu) {
                if (hldev->reset_needed_after_close ||
                        !hldev->mtu_first_time_set) {
                        status = xge_hal_device_reset(hldev);
                        if (status != XGE_HAL_OK) {
                                xge_debug_device(XGE_TRACE, "%s",
                                          "fatal: can not reset the device");
                                return status;
                        }
                }
                /* store the new MTU in device, reset will use it */
                hldev->config.mtu = new_mtu;
                xge_debug_device(XGE_TRACE, "new MTU %d applied",
                                 new_mtu);
        }

        if (!hldev->mtu_first_time_set)
                hldev->mtu_first_time_set = 1;

        return XGE_HAL_OK;
}

/**
 * xge_hal_device_initialize - Initialize Xframe device.
 * @hldev: HAL device handle.
 * @attr: pointer to xge_hal_device_attr_t structure
 * @device_config: Configuration to be _applied_ to the device,
 *                 For the Xframe configuration "knobs" please
 *                 refer to xge_hal_device_config_t and Xframe
 *                 User Guide.
 *
 * Initialize Xframe device. Note that all the arguments of this public API
 * are 'IN', including @hldev. Upper-layer driver (ULD) cooperates with
 * OS to find new Xframe device, locate its PCI and memory spaces.
 *
 * When done, the ULD allocates sizeof(xge_hal_device_t) bytes for HAL
 * to enable the latter to perform Xframe hardware initialization.
 *
 * Returns: XGE_HAL_OK - success.
 * XGE_HAL_ERR_DRIVER_NOT_INITIALIZED - Driver is not initialized.
 * XGE_HAL_ERR_BAD_DEVICE_CONFIG - Device configuration params are not
 * valid.
 * XGE_HAL_ERR_OUT_OF_MEMORY - Memory allocation failed.
 * XGE_HAL_ERR_BAD_SUBSYSTEM_ID - Device subsystem id is invalid.
 * XGE_HAL_ERR_INVALID_MAC_ADDRESS - Device mac address in not valid.
 * XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING - Failed to retrieve the mac
 * address within the time(timeout) or TTI/RTI initialization failed.
 * XGE_HAL_ERR_SWAPPER_CTRL - Failed to configure swapper control.
 * XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT -Device is not queiscent.
 *
 * See also: xge_hal_device_terminate(), xge_hal_status_e{}
 * xge_hal_device_attr_t{}.
 */
xge_hal_status_e
xge_hal_device_initialize(xge_hal_device_t *hldev, xge_hal_device_attr_t *attr,
                xge_hal_device_config_t *device_config)
{
        int i;
        xge_hal_status_e status;
        xge_hal_channel_t *channel;
        u16 subsys_device;
        u16 subsys_vendor;
        int total_dram_size, ring_auto_dram_cfg, left_dram_size;
        int total_dram_size_max = 0;

        xge_debug_device(XGE_TRACE, "device 0x"XGE_OS_LLXFMT" is initializing",
                         (unsigned long long)(ulong_t)hldev);

        /* sanity check */
        if (g_xge_hal_driver == NULL ||
            !g_xge_hal_driver->is_initialized) {
                return XGE_HAL_ERR_DRIVER_NOT_INITIALIZED;
        }

        xge_os_memzero(hldev, sizeof(xge_hal_device_t));

        /*
         * validate a common part of Xframe-I/II configuration
         * (and run check_card() later, once PCI inited - see below)
         */
        status = __hal_device_config_check_common(device_config);
        if (status != XGE_HAL_OK)
                return status;

        /* apply config */
        xge_os_memcpy(&hldev->config, device_config,
                      sizeof(xge_hal_device_config_t));

        /* save original attr */
        xge_os_memcpy(&hldev->orig_attr, attr,
                      sizeof(xge_hal_device_attr_t));

        /* initialize rxufca_intr_thres */
        hldev->rxufca_intr_thres = hldev->config.rxufca_intr_thres;

        hldev->regh0 = attr->regh0;
        hldev->regh1 = attr->regh1;
        hldev->regh2 = attr->regh2;
        hldev->isrbar0 = hldev->bar0 = attr->bar0;
        hldev->bar1 = attr->bar1;
        hldev->bar2 = attr->bar2;
        hldev->pdev = attr->pdev;
        hldev->irqh = attr->irqh;
        hldev->cfgh = attr->cfgh;

        /* set initial bimodal timer for bimodal adaptive schema */
        hldev->bimodal_timer_val_us = hldev->config.bimodal_timer_lo_us;

        hldev->queueh = xge_queue_create(hldev->pdev, hldev->irqh,
                                  g_xge_hal_driver->config.queue_size_initial,
                                  g_xge_hal_driver->config.queue_size_max,
                                  __hal_device_event_queued, hldev);
        if (hldev->queueh == NULL)
                return XGE_HAL_ERR_OUT_OF_MEMORY;

        hldev->magic = XGE_HAL_MAGIC;

        xge_assert(hldev->regh0);
        xge_assert(hldev->regh1);
        xge_assert(hldev->bar0);
        xge_assert(hldev->bar1);
        xge_assert(hldev->pdev);
        xge_assert(hldev->irqh);
        xge_assert(hldev->cfgh);

        /* initialize some PCI/PCI-X fields of this PCI device. */
        __hal_device_pci_init(hldev);

        /*
         * initlialize lists to properly handling a potential
         * terminate request
         */
        xge_list_init(&hldev->free_channels);
        xge_list_init(&hldev->fifo_channels);
        xge_list_init(&hldev->ring_channels);

        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA) {
                /* fixups for xena */
                hldev->config.rth_en = 0;
                hldev->config.rth_spdm_en = 0;
                hldev->config.rts_mac_en = 0;
                total_dram_size_max = XGE_HAL_MAX_RING_QUEUE_SIZE_XENA;

                status = __hal_device_config_check_xena(device_config);
                if (status != XGE_HAL_OK) {
                        xge_hal_device_terminate(hldev);
                        return status;
                }
                if (hldev->config.bimodal_interrupts == 1) {
                        xge_hal_device_terminate(hldev);
                        return XGE_HAL_BADCFG_BIMODAL_XENA_NOT_ALLOWED;
                } else if (hldev->config.bimodal_interrupts ==
                    XGE_HAL_DEFAULT_USE_HARDCODE)
                        hldev->config.bimodal_interrupts = 0;
        } else if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
                /* fixups for herc */
                total_dram_size_max = XGE_HAL_MAX_RING_QUEUE_SIZE_HERC;
                status = __hal_device_config_check_herc(device_config);
                if (status != XGE_HAL_OK) {
                        xge_hal_device_terminate(hldev);
                        return status;
                }
                if (hldev->config.bimodal_interrupts ==
                    XGE_HAL_DEFAULT_USE_HARDCODE)
                        hldev->config.bimodal_interrupts = 1;
        } else {
                xge_debug_device(XGE_ERR,
                          "detected unknown device_id 0x%x", hldev->device_id);
                xge_hal_device_terminate(hldev);
                return XGE_HAL_ERR_BAD_DEVICE_ID;
        }


        /* allocate and initialize FIFO types of channels according to
         * configuration */
        for (i = 0; i < XGE_HAL_MAX_FIFO_NUM; i++) {
                if (!device_config->fifo.queue[i].configured)
                        continue;

                channel = __hal_channel_allocate(hldev, i,
                                                 XGE_HAL_CHANNEL_TYPE_FIFO);
                if (channel == NULL) {
                        xge_debug_device(XGE_ERR,
                                "fifo: __hal_channel_allocate failed");
                        xge_hal_device_terminate(hldev);
                        return XGE_HAL_ERR_OUT_OF_MEMORY;
                }
                /* add new channel to the device */
                xge_list_insert(&channel->item, &hldev->free_channels);
        }

        /*
         * automatic DRAM adjustment
         */
        total_dram_size = 0;
        ring_auto_dram_cfg = 0;
        for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++) {
                if (!device_config->ring.queue[i].configured)
                        continue;
                if (device_config->ring.queue[i].dram_size_mb ==
                    XGE_HAL_DEFAULT_USE_HARDCODE) {
                        ring_auto_dram_cfg++;
                        continue;
                }
                total_dram_size += device_config->ring.queue[i].dram_size_mb;
        }
        left_dram_size = total_dram_size_max - total_dram_size;
        if (left_dram_size < 0 ||
            (ring_auto_dram_cfg && left_dram_size < ring_auto_dram_cfg))  {
                xge_debug_device(XGE_ERR,
                         "ring config: exceeded DRAM size %d MB",
                         total_dram_size_max);
                xge_hal_device_terminate(hldev);
                return XGE_HAL_BADCFG_RING_QUEUE_SIZE;
        }

        /*
         * allocate and initialize RING types of channels according to
         * configuration
         */
        for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++) {
                if (!device_config->ring.queue[i].configured)
                        continue;

                if (device_config->ring.queue[i].dram_size_mb ==
                    XGE_HAL_DEFAULT_USE_HARDCODE) {
                        hldev->config.ring.queue[i].dram_size_mb =
                                device_config->ring.queue[i].dram_size_mb =
                                        left_dram_size / ring_auto_dram_cfg;
                }

                channel = __hal_channel_allocate(hldev, i,
                                                 XGE_HAL_CHANNEL_TYPE_RING);
                if (channel == NULL) {
                        xge_debug_device(XGE_ERR,
                                "ring: __hal_channel_allocate failed");
                        xge_hal_device_terminate(hldev);
                        return XGE_HAL_ERR_OUT_OF_MEMORY;
                }
                /* add new channel to the device */
                xge_list_insert(&channel->item, &hldev->free_channels);
        }

        /* get subsystem IDs */
        xge_os_pci_read16(hldev->pdev, hldev->cfgh,
                xge_offsetof(xge_hal_pci_config_le_t, subsystem_id),
                &subsys_device);
        xge_os_pci_read16(hldev->pdev, hldev->cfgh,
                xge_offsetof(xge_hal_pci_config_le_t, subsystem_vendor_id),
                &subsys_vendor);
        xge_debug_device(XGE_TRACE,
                         "subsystem_id %04x:%04x",
                         subsys_vendor, subsys_device);

        /* reset device initially */
        (void) __hal_device_reset(hldev);

        /* set host endian before, to assure proper action */
        status = __hal_device_set_swapper(hldev);
        if (status != XGE_HAL_OK) {
                xge_debug_device(XGE_ERR,
                        "__hal_device_set_swapper failed");
                xge_hal_device_terminate(hldev);
                (void) __hal_device_reset(hldev);
                return status;
        }

#ifndef XGE_HAL_HERC_EMULATION
        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA)
                __hal_device_xena_fix_mac(hldev);
#endif

        /*  MAC address initialization.
         *  For now only one mac address will be read and used.  */
        status = xge_hal_device_macaddr_get(hldev, 0, &hldev->macaddr[0]);
        if (status != XGE_HAL_OK) {
                xge_debug_device(XGE_ERR,
                        "xge_hal_device_macaddr_get failed");
                xge_hal_device_terminate(hldev);
                return status;
        }

        if (hldev->macaddr[0][0] == 0xFF &&
            hldev->macaddr[0][1] == 0xFF &&
            hldev->macaddr[0][2] == 0xFF &&
            hldev->macaddr[0][3] == 0xFF &&
            hldev->macaddr[0][4] == 0xFF &&
            hldev->macaddr[0][5] == 0xFF) {
                xge_debug_device(XGE_ERR,
                        "xge_hal_device_macaddr_get returns all FFs");
                xge_hal_device_terminate(hldev);
                return XGE_HAL_ERR_INVALID_MAC_ADDRESS;
        }

        xge_debug_device(XGE_TRACE,
                          "default macaddr: 0x%02x-%02x-%02x-%02x-%02x-%02x",
                          hldev->macaddr[0][0], hldev->macaddr[0][1],
                          hldev->macaddr[0][2], hldev->macaddr[0][3],
                          hldev->macaddr[0][4], hldev->macaddr[0][5]);

        status = __hal_stats_initialize(&hldev->stats, hldev);
        if (status != XGE_HAL_OK) {
                xge_debug_device(XGE_ERR,
                        "__hal_stats_initialize failed");
                xge_hal_device_terminate(hldev);
                return status;
        }

        status = __hal_device_hw_initialize(hldev);
        if (status != XGE_HAL_OK) {
                xge_debug_device(XGE_ERR,
                        "__hal_device_hw_initialize failed");
                xge_hal_device_terminate(hldev);
                return status;
        }
        hldev->dump_buf=(char*)xge_os_malloc(hldev->pdev, XGE_HAL_DUMP_BUF_SIZE);
        if (hldev->dump_buf == NULL)  {
                xge_debug_device(XGE_ERR,
                        "__hal_device_hw_initialize failed");
                xge_hal_device_terminate(hldev);
                return XGE_HAL_ERR_OUT_OF_MEMORY;
        }


        /* Xena-only: need to serialize fifo posts across all device fifos */
#if defined(XGE_HAL_TX_MULTI_POST)
        xge_os_spin_lock_init(&hldev->xena_post_lock, hldev->pdev);
#elif defined(XGE_HAL_TX_MULTI_POST_IRQ)
        xge_os_spin_lock_init_irq(&hldev->xena_post_lock, hldev->irqh);
#endif
         /* Getting VPD data */
        __hal_device_get_vpd_data(hldev);

        hldev->is_initialized = 1;

        return XGE_HAL_OK;
}

/**
 * xge_hal_device_terminating - Mark the device as 'terminating'.
 * @devh: HAL device handle.
 *
 * Mark the device as 'terminating', going to terminate. Can be used
 * to serialize termination with other running processes/contexts.
 *
 * See also: xge_hal_device_terminate().
 */
void
xge_hal_device_terminating(xge_hal_device_h devh)
{
        xge_hal_device_t *hldev = (xge_hal_device_t*)devh;
        xge_list_t *item;
        xge_hal_channel_t *channel;
#if defined(XGE_HAL_TX_MULTI_RESERVE_IRQ)
        unsigned long flags = 0;
#endif

        /*
         * go through each opened tx channel and aquire
         * lock, so it will serialize with HAL termination flag
         */
        xge_list_for_each(item, &hldev->fifo_channels) {
                channel = xge_container_of(item, xge_hal_channel_t, item);
#if defined(XGE_HAL_TX_MULTI_RESERVE)
        xge_os_spin_lock(&channel->reserve_lock);
#elif defined(XGE_HAL_TX_MULTI_RESERVE_IRQ)
        xge_os_spin_lock_irq(&channel->reserve_lock, flags);
#endif

        channel->terminating = 1;

#if defined(XGE_HAL_TX_MULTI_RESERVE)
        xge_os_spin_unlock(&channel->reserve_lock);
#elif defined(XGE_HAL_TX_MULTI_RESERVE_IRQ)
        xge_os_spin_unlock_irq(&channel->reserve_lock, flags);
#endif
        }

        hldev->terminating = 1;
}

/**
 * xge_hal_device_terminate - Terminate Xframe device.
 * @hldev: HAL device handle.
 *
 * Terminate HAL device.
 *
 * See also: xge_hal_device_initialize().
 */
void
xge_hal_device_terminate(xge_hal_device_t *hldev)
{
        xge_assert(g_xge_hal_driver != NULL);
        xge_assert(hldev != NULL);
        xge_assert(hldev->magic == XGE_HAL_MAGIC);

        xge_queue_flush(hldev->queueh);

        hldev->terminating = 1;
        hldev->is_initialized = 0;
        hldev->in_poll = 0;
        hldev->magic = XGE_HAL_DEAD;

#if defined(XGE_HAL_TX_MULTI_POST)
        xge_os_spin_lock_destroy(&hldev->xena_post_lock, hldev->pdev);
#elif defined(XGE_HAL_TX_MULTI_POST_IRQ)
        xge_os_spin_lock_destroy_irq(&hldev->xena_post_lock, hldev->pdev);
#endif

        xge_debug_device(XGE_TRACE, "device "XGE_OS_LLXFMT" is terminating",
                                (unsigned long long)(ulong_t)hldev);

        xge_assert(xge_list_is_empty(&hldev->fifo_channels));
        xge_assert(xge_list_is_empty(&hldev->ring_channels));

        if (hldev->stats.is_initialized) {
                __hal_stats_terminate(&hldev->stats);
        }

        /* close if open and free all channels */
        while (!xge_list_is_empty(&hldev->free_channels)) {
                xge_hal_channel_t *channel = (xge_hal_channel_t*)
                                        hldev->free_channels.next;

                xge_assert(!channel->is_open);
                xge_list_remove(&channel->item);
                __hal_channel_free(channel);
        }

        if (hldev->queueh) {
                xge_queue_destroy(hldev->queueh);
        }

        if (hldev->spdm_table) {
                xge_os_free(hldev->pdev,
                          hldev->spdm_table[0],
                          (sizeof(xge_hal_spdm_entry_t) *
                                hldev->spdm_max_entries));
                xge_os_free(hldev->pdev,
                          hldev->spdm_table,
                          (sizeof(xge_hal_spdm_entry_t *) *
                                hldev->spdm_max_entries));
                xge_os_spin_lock_destroy(&hldev->spdm_lock, hldev->pdev);
                hldev->spdm_table = NULL;
        }

        if (hldev->dump_buf)  {
                xge_os_free(hldev->pdev, hldev->dump_buf,
                            XGE_HAL_DUMP_BUF_SIZE);
                hldev->dump_buf = NULL;
        }

        if (hldev->device_id != 0) {
                int j, pcisize;

                pcisize = (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC)?
                                   XGE_HAL_PCISIZE_HERC : XGE_HAL_PCISIZE_XENA;
                for (j = 0; j < pcisize; j++) {
                        xge_os_pci_write32(hldev->pdev, hldev->cfgh, j * 4,
                                *((u32*)&hldev->pci_config_space_bios + j));
                }
        }
}
/**
 * __hal_device_get_vpd_data - Getting vpd_data.
 *
 *   @hldev: HAL device handle.
 *
 *   Getting  product name and serial number from vpd capabilites structure
 *
 */
void
__hal_device_get_vpd_data(xge_hal_device_t *hldev)
{
    u8 * vpd_data;
    u8   data;
    int  index = 0, count, fail = 0;
    u8   vpd_addr = XGE_HAL_CARD_XENA_VPD_ADDR;
    if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC)
        vpd_addr = XGE_HAL_CARD_HERC_VPD_ADDR;

    xge_os_strlcpy((char *) hldev->vpd_data.product_name,
                "10 Gigabit Ethernet Adapter",
                sizeof(hldev->vpd_data.product_name));

    xge_os_strlcpy((char *) hldev->vpd_data.serial_num,
                "not available",
                sizeof(hldev->vpd_data.serial_num));

    vpd_data = ( u8*) xge_os_malloc(hldev->pdev, XGE_HAL_VPD_BUFFER_SIZE + 16);
    if ( vpd_data == 0 )
        return;

    for (index = 0; index < XGE_HAL_VPD_BUFFER_SIZE; index +=4 ) {
        xge_os_pci_write8(hldev->pdev, hldev->cfgh, (vpd_addr + 2), (u8)index);
        xge_os_pci_read8(hldev->pdev, hldev->cfgh,(vpd_addr + 2), &data);
        xge_os_pci_write8(hldev->pdev, hldev->cfgh, (vpd_addr + 3), 0);
        for (count = 0; count < 5; count++ ) {
            xge_os_mdelay(2);
            xge_os_pci_read8(hldev->pdev, hldev->cfgh,(vpd_addr + 3), &data);
            if (data == XGE_HAL_VPD_READ_COMPLETE)
                break;
        }

        if (count >= 5) {
            xge_os_printf("ERR, Reading VPD data failed");
            fail = 1;
            break;
        }

        xge_os_pci_read32(hldev->pdev, hldev->cfgh,(vpd_addr + 4),
                (u32 *)&vpd_data[index]);
    }

    if(!fail) {

        /* read serial number of adapter */
        for (count = 0; count < XGE_HAL_VPD_BUFFER_SIZE; count++) {
            if ((vpd_data[count] == 'S')     &&
                (vpd_data[count + 1] == 'N') &&
                (vpd_data[count + 2] < XGE_HAL_VPD_LENGTH)) {
                    (void) memset(hldev->vpd_data.serial_num, 0, XGE_HAL_VPD_LENGTH);
                    (void) memcpy(hldev->vpd_data.serial_num, &vpd_data[count + 3],
                        vpd_data[count + 2]);
                    break;
            }
        }

        if (vpd_data[1] < XGE_HAL_VPD_LENGTH) {
            (void) memset(hldev->vpd_data.product_name, 0, vpd_data[1]);
            (void) memcpy(hldev->vpd_data.product_name, &vpd_data[3], vpd_data[1]);
        }

    }

    xge_os_free(hldev->pdev, vpd_data, XGE_HAL_VPD_BUFFER_SIZE + 16);
}


/**
 * xge_hal_device_handle_tcode - Handle transfer code.
 * @channelh: Channel handle.
 * @dtrh: Descriptor handle.
 * @t_code: One of the enumerated (and documented in the Xframe user guide)
 *          "transfer codes".
 *
 * Handle descriptor's transfer code. The latter comes with each completed
 * descriptor, see xge_hal_fifo_dtr_next_completed() and
 * xge_hal_ring_dtr_next_completed().
 * Transfer codes are enumerated in xgehal-fifo.h and xgehal-ring.h.
 *
 * Returns: one of the xge_hal_status_e{} enumerated types.
 * XGE_HAL_OK                   - for success.
 * XGE_HAL_ERR_CRITICAL         - when encounters critical error.
 */
xge_hal_status_e
xge_hal_device_handle_tcode (xge_hal_channel_h channelh,
                             xge_hal_dtr_h dtrh, u8 t_code)
{
        xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
        xge_hal_device_t *hldev = (xge_hal_device_t *)channel->devh;

        if (t_code > 15) {
                xge_os_printf("invalid t_code %d", t_code);
                return XGE_HAL_OK;
        }

        if (channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) {
                hldev->stats.sw_dev_err_stats.txd_t_code_err_cnt[t_code]++;

#if defined(XGE_HAL_DEBUG_BAD_TCODE)
        xge_hal_fifo_txd_t *txdp = (xge_hal_fifo_txd_t *)dtrh;
        xge_os_printf(""XGE_OS_LLXFMT":"XGE_OS_LLXFMT":"
                XGE_OS_LLXFMT":"XGE_OS_LLXFMT,
                txdp->control_1, txdp->control_2, txdp->buffer_pointer,
                txdp->host_control);
#endif

                /* handle link "down" immediately without going through
                 * xge_hal_device_poll() routine. */
                if (t_code == XGE_HAL_TXD_T_CODE_LOSS_OF_LINK) {
                        /* link is down */
                        if (hldev->link_state != XGE_HAL_LINK_DOWN) {
                                xge_hal_pci_bar0_t *bar0 =
                                (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
                                u64 val64;

                                hldev->link_state = XGE_HAL_LINK_DOWN;

                                val64 = xge_os_pio_mem_read64(hldev->pdev,
                                    hldev->regh0, &bar0->adapter_control);

                                /* turn off LED */
                                val64 = val64 & (~XGE_HAL_ADAPTER_LED_ON);
                                xge_os_pio_mem_write64(hldev->pdev,
                                                hldev->regh0, val64,
                                                &bar0->adapter_control);

                                g_xge_hal_driver->uld_callbacks.link_down(
                                                hldev->upper_layer_info);
                        }
                } else if (t_code == XGE_HAL_TXD_T_CODE_ABORT_BUFFER ||
                           t_code == XGE_HAL_TXD_T_CODE_ABORT_DTOR) {
                        __hal_device_handle_targetabort(hldev);
                        return XGE_HAL_ERR_CRITICAL;
                }
                return XGE_HAL_ERR_PKT_DROP;
        } else if (channel->type == XGE_HAL_CHANNEL_TYPE_RING) {
                hldev->stats.sw_dev_err_stats.rxd_t_code_err_cnt[t_code]++;

#if defined(XGE_HAL_DEBUG_BAD_TCODE)
                xge_hal_ring_rxd_1_t *rxdp = (xge_hal_ring_rxd_1_t *)dtrh;
                xge_os_printf(""XGE_OS_LLXFMT":"XGE_OS_LLXFMT":"XGE_OS_LLXFMT
                        ":"XGE_OS_LLXFMT, rxdp->control_1,
                        rxdp->control_2, rxdp->buffer0_ptr,
                        rxdp->host_control);
#endif
                if (t_code == XGE_HAL_RXD_T_CODE_BAD_ECC) {
                        hldev->stats.sw_dev_err_stats.ecc_err_cnt++;
                        __hal_device_handle_eccerr(hldev, "rxd_t_code",
                                                   (u64)t_code);
                        return XGE_HAL_ERR_CRITICAL;
                } else if (t_code == XGE_HAL_RXD_T_CODE_PARITY ||
                           t_code == XGE_HAL_RXD_T_CODE_PARITY_ABORT) {
                        hldev->stats.sw_dev_err_stats.parity_err_cnt++;
                        __hal_device_handle_parityerr(hldev, "rxd_t_code",
                                                      (u64)t_code);
                        return XGE_HAL_ERR_CRITICAL;
                /* do not drop if detected unknown IPv6 extension */
                } else if (t_code != XGE_HAL_RXD_T_CODE_UNKNOWN_PROTO) {
                        return XGE_HAL_ERR_PKT_DROP;
                }
        }
        return XGE_HAL_OK;
}

/**
 * xge_hal_device_link_state - Get link state.
 * @devh: HAL device handle.
 * @ls: Link state, see xge_hal_device_link_state_e{}.
 *
 * Get link state.
 * Returns: XGE_HAL_OK.
 * See also: xge_hal_device_link_state_e{}.
 */
xge_hal_status_e xge_hal_device_link_state(xge_hal_device_h devh,
                        xge_hal_device_link_state_e *ls)
{
        xge_hal_device_t *hldev = (xge_hal_device_t *)devh;

        xge_assert(ls != NULL);
        *ls = hldev->link_state;
        return XGE_HAL_OK;
}

/**
 * xge_hal_device_sched_timer - Configure scheduled device interrupt.
 * @devh: HAL device handle.
 * @interval_us: Time interval, in miscoseconds.
 *            Unlike transmit and receive interrupts,
 *            the scheduled interrupt is generated independently of
 *            traffic, but purely based on time.
 * @one_shot: 1 - generate scheduled interrupt only once.
 *            0 - generate scheduled interrupt periodically at the specified
 *            @interval_us interval.
 *
 * (Re-)configure scheduled interrupt. Can be called at runtime to change
 * the setting, generate one-shot interrupts based on the resource and/or
 * traffic conditions, other purposes.
 * See also: xge_hal_device_config_t{}.
 */
void xge_hal_device_sched_timer(xge_hal_device_h devh, int interval_us,
                        int one_shot)
{
        u64 val64;
        xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
        xge_hal_pci_bar0_t *bar0 =
                (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        unsigned int interval = hldev->config.pci_freq_mherz * interval_us;

        interval = __hal_fix_time_ival_herc(hldev, interval);

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                    &bar0->scheduled_int_ctrl);
        if (interval) {
                val64 &= XGE_HAL_SCHED_INT_PERIOD_MASK;
                val64 |= XGE_HAL_SCHED_INT_PERIOD(interval);
                if (one_shot) {
                        val64 |= XGE_HAL_SCHED_INT_CTRL_ONE_SHOT;
                }
                val64 |= XGE_HAL_SCHED_INT_CTRL_TIMER_EN;
        } else {
                val64 &= ~XGE_HAL_SCHED_INT_CTRL_TIMER_EN;
        }

        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                             val64, &bar0->scheduled_int_ctrl);

        xge_debug_device(XGE_TRACE, "sched_timer 0x"XGE_OS_LLXFMT": %s",
                          (unsigned long long)val64,
                          interval ? "enabled" : "disabled");
}

/**
 * xge_hal_device_check_id - Verify device ID.
 * @devh: HAL device handle.
 *
 * Verify device ID.
 * Returns: one of the xge_hal_card_e{} enumerated types.
 * See also: xge_hal_card_e{}.
 */
xge_hal_card_e
xge_hal_device_check_id(xge_hal_device_h devh)
{
        xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
        switch (hldev->device_id) {
        case XGE_PCI_DEVICE_ID_XENA_1:
        case XGE_PCI_DEVICE_ID_XENA_2:
                return XGE_HAL_CARD_XENA;
        case XGE_PCI_DEVICE_ID_HERC_1:
        case XGE_PCI_DEVICE_ID_HERC_2:
                return XGE_HAL_CARD_HERC;
        case XGE_PCI_DEVICE_ID_TITAN_1:
        case XGE_PCI_DEVICE_ID_TITAN_2:
                return XGE_HAL_CARD_TITAN;
        default:
                return XGE_HAL_CARD_UNKNOWN;
        }
}

/**
 * xge_hal_device_pci_info_get - Get PCI bus informations such as width,
 *                       frequency, and mode from previously stored values.
 * @devh:               HAL device handle.
 * @pci_mode:           pointer to a variable of enumerated type
 *                      xge_hal_pci_mode_e{}.
 * @bus_frequency:      pointer to a variable of enumerated type
 *                      xge_hal_pci_bus_frequency_e{}.
 * @bus_width:          pointer to a variable of enumerated type
 *                      xge_hal_pci_bus_width_e{}.
 *
 * Get pci mode, frequency, and PCI bus width.
 * Returns: one of the xge_hal_status_e{} enumerated types.
 * XGE_HAL_OK                   - for success.
 * XGE_HAL_ERR_INVALID_DEVICE   - for invalid device handle.
 * See Also: xge_hal_pci_mode_e, xge_hal_pci_mode_e, xge_hal_pci_width_e.
 */
xge_hal_status_e
xge_hal_device_pci_info_get(xge_hal_device_h devh, xge_hal_pci_mode_e *pci_mode,
                xge_hal_pci_bus_frequency_e *bus_frequency,
                xge_hal_pci_bus_width_e *bus_width)
{
        xge_hal_status_e rc_status;
        xge_hal_device_t *hldev = (xge_hal_device_t *)devh;

        if (!hldev || !hldev->is_initialized || hldev->magic != XGE_HAL_MAGIC) {
                rc_status =  XGE_HAL_ERR_INVALID_DEVICE;
                xge_debug_device(XGE_ERR,
                        "xge_hal_device_pci_info_get error, rc %d for device %p",
                        rc_status, hldev);

                return rc_status;
        }

        *pci_mode       = hldev->pci_mode;
        *bus_frequency  = hldev->bus_frequency;
        *bus_width      = hldev->bus_width;
        rc_status       = XGE_HAL_OK;
        return rc_status;
}

/**
 * xge_hal_reinitialize_hw
 * @hldev: private member of the device structure.
 *
 * This function will soft reset the NIC and re-initalize all the
 * I/O registers to the values they had after it's inital initialization
 * through the probe function.
 */
int xge_hal_reinitialize_hw(xge_hal_device_t * hldev)
{
        (void) xge_hal_device_reset(hldev);
        if (__hal_device_hw_initialize(hldev) != XGE_HAL_OK) {
                xge_hal_device_terminate(hldev);
                (void) __hal_device_reset(hldev);
                return 1;
        }
        return 0;
}


/*
 * __hal_read_spdm_entry_line
 * @hldev: pointer to xge_hal_device_t structure
 * @spdm_line: spdm line in the spdm entry to be read.
 * @spdm_entry: spdm entry of the spdm_line in the SPDM table.
 * @spdm_line_val: Contains the value stored in the spdm line.
 *
 * SPDM table contains upto a maximum of 256 spdm entries.
 * Each spdm entry contains 8 lines and each line stores 8 bytes.
 * This function reads the spdm line(addressed by @spdm_line)
 * of the spdm entry(addressed by @spdm_entry) in
 * the SPDM table.
 */
xge_hal_status_e
__hal_read_spdm_entry_line(xge_hal_device_t *hldev, u8 spdm_line,
                        u16 spdm_entry, u64 *spdm_line_val)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;

        val64 = XGE_HAL_RTS_RTH_SPDM_MEM_CTRL_STROBE |
                XGE_HAL_RTS_RTH_SPDM_MEM_CTRL_LINE_SEL(spdm_line) |
                XGE_HAL_RTS_RTH_SPDM_MEM_CTRL_OFFSET(spdm_entry);

        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                        &bar0->rts_rth_spdm_mem_ctrl);

        /* poll until done */
        if (__hal_device_register_poll(hldev,
                &bar0->rts_rth_spdm_mem_ctrl, 0,
                XGE_HAL_RTS_RTH_SPDM_MEM_CTRL_STROBE,
                XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {

                return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
        }

        *spdm_line_val = xge_os_pio_mem_read64(hldev->pdev,
                                hldev->regh0, &bar0->rts_rth_spdm_mem_data);
        return XGE_HAL_OK;
}


/*
 * __hal_get_free_spdm_entry
 * @hldev: pointer to xge_hal_device_t structure
 * @spdm_entry: Contains an index to the unused spdm entry in the SPDM table.
 *
 * This function returns an index of unused spdm entry in the SPDM
 * table.
 */
static xge_hal_status_e
__hal_get_free_spdm_entry(xge_hal_device_t *hldev, u16 *spdm_entry)
{
        xge_hal_status_e status;
        u64 spdm_line_val=0;

        /*
         * Search in the local SPDM table for a free slot.
         */
        *spdm_entry = 0;
        for(; *spdm_entry < hldev->spdm_max_entries; (*spdm_entry)++) {
                if (hldev->spdm_table[*spdm_entry]->in_use) {
                        break;
                }
        }

        if (*spdm_entry >= hldev->spdm_max_entries) {
                return XGE_HAL_ERR_SPDM_TABLE_FULL;
        }

        /*
         * Make sure that the corresponding spdm entry in the SPDM
         * table is free.
         * Seventh line of the spdm entry contains information about
         * whether the entry is free or not.
         */
        if ((status = __hal_read_spdm_entry_line(hldev, 7, *spdm_entry,
                                        &spdm_line_val)) != XGE_HAL_OK) {
                return status;
        }

        /* BIT(63) in spdm_line 7 corresponds to entry_enable bit */
        if ((spdm_line_val & BIT(63))) {
                /*
                 * Log a warning
                 */
                xge_debug_device(XGE_ERR, "Local SPDM table is not "
                          "consistent with the actual one for the spdm "
                          "entry %d", *spdm_entry);
                return XGE_HAL_ERR_SPDM_TABLE_DATA_INCONSISTENT;
        }

        return XGE_HAL_OK;
}


/*
 * __hal_calc_jhash - Calculate Jenkins hash.
 * @msg: Jenkins hash algorithm key.
 * @length: Length of the key.
 * @golden_ratio: Jenkins hash golden ratio.
 * @init_value: Jenkins hash initial value.
 *
 * This function implements the Jenkins based algorithm used for the
 * calculation of the RTH hash.
 * Returns:  Jenkins hash value.
 *
 */
static u32
__hal_calc_jhash(u8 *msg, u32 length, u32 golden_ratio, u32 init_value)
{

        register u32 a,b,c,len;

        /*
         * Set up the internal state
         */
        len = length;
        a = b = golden_ratio;  /* the golden ratio; an arbitrary value */
        c = init_value;         /* the previous hash value */

        /*  handle most of the key */
        while (len >= 12)
        {
                a += (msg[0] + ((u32)msg[1]<<8) + ((u32)msg[2]<<16)
                                                 + ((u32)msg[3]<<24));
                b += (msg[4] + ((u32)msg[5]<<8) + ((u32)msg[6]<<16)
                                                 + ((u32)msg[7]<<24));
                c += (msg[8] + ((u32)msg[9]<<8) + ((u32)msg[10]<<16)
                                                 + ((u32)msg[11]<<24));
                mix(a,b,c);
                msg += 12; len -= 12;
        }

        /*  handle the last 11 bytes */
        c += length;
        switch(len)  /* all the case statements fall through */
        {
                case 11: c+= ((u32)msg[10]<<24);
                         break;
                case 10: c+= ((u32)msg[9]<<16);
                         break;
                case 9 : c+= ((u32)msg[8]<<8);
                         break;
                /* the first byte of c is reserved for the length */
                case 8 : b+= ((u32)msg[7]<<24);
                         break;
                case 7 : b+= ((u32)msg[6]<<16);
                         break;
                case 6 : b+= ((u32)msg[5]<<8);
                         break;
                case 5 : b+= msg[4];
                         break;
                case 4 : a+= ((u32)msg[3]<<24);
                         break;
                case 3 : a+= ((u32)msg[2]<<16);
                         break;
                case 2 : a+= ((u32)msg[1]<<8);
                         break;
                case 1 : a+= msg[0];
                         break;
                /* case 0: nothing left to add */
        }

        mix(a,b,c);

        /* report the result */
        return c;
}


/**
 * xge_hal_spdm_entry_add - Add a new entry to the SPDM table.
 * @devh: HAL device handle.
 * @src_ip: Source ip address(IPv4/IPv6).
 * @dst_ip: Destination ip address(IPv4/IPv6).
 * @l4_sp: L4 source port.
 * @l4_dp: L4 destination port.
 * @is_tcp: Set to 1, if the protocol is TCP.
 *                 0, if the protocol is UDP.
 * @is_ipv4: Set to 1, if the protocol is IPv4.
 *                 0, if the protocol is IPv6.
 * @tgt_queue: Target queue to route the receive packet.
 *
 * This function add a new entry to the SPDM table.
 *
 * Returns:  XGE_HAL_OK - success.
 * XGE_HAL_ERR_SPDM_NOT_ENABLED -  SPDM support is not enabled.
 * XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING - Failed to add a new entry with in
 *                                      the time(timeout).
 * XGE_HAL_ERR_SPDM_TABLE_FULL - SPDM table is full.
 * XGE_HAL_ERR_SPDM_INVALID_ENTRY - Invalid SPDM entry.
 *
 * See also: xge_hal_spdm_entry_remove{}.
 */
xge_hal_status_e
xge_hal_spdm_entry_add(xge_hal_device_h devh, xge_hal_ipaddr_t *src_ip,
                xge_hal_ipaddr_t *dst_ip, u16 l4_sp, u16 l4_dp,
                u8 is_tcp, u8 is_ipv4, u8 tgt_queue)
{

        xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u32 jhash_value;
        u32 jhash_init_val;
        u32 jhash_golden_ratio;
        u64 val64;
        int off;
        u16 spdm_entry;
        u8  msg[XGE_HAL_JHASH_MSG_LEN];
        int ipaddr_len;
        xge_hal_status_e status;


        if (!hldev->config.rth_spdm_en) {
                return XGE_HAL_ERR_SPDM_NOT_ENABLED;
        }

        if ((tgt_queue <  XGE_HAL_MIN_RING_NUM) ||
                (tgt_queue  >  XGE_HAL_MAX_RING_NUM)) {
                return XGE_HAL_ERR_SPDM_INVALID_ENTRY;
        }


        /*
         * Calculate the jenkins hash.
         */
        /*
         * Create the Jenkins hash algorithm key.
         * key = {L3SA, L3DA, L4SP, L4DP}, if SPDM is configured to
         * use L4 information. Otherwize key = {L3SA, L3DA}.
         */

        if (is_ipv4) {
                ipaddr_len = 4;   // In bytes
        } else {
                ipaddr_len = 16;
        }

        /*
         * Jenkins hash algorithm expects the key in the big endian
         * format. Since key is the byte array, memcpy won't work in the
         * case of little endian. So, the current code extracts each
         * byte starting from MSB and store it in the key.
         */
        if (is_ipv4) {
                for (off = 0; off < ipaddr_len; off++) {
                        u32 mask = vBIT32(0xff,(off*8),8);
                        int shift = 32-(off+1)*8;
                        msg[off] = (u8)((src_ip->ipv4.addr & mask) >> shift);
                        msg[off+ipaddr_len] =
                                (u8)((dst_ip->ipv4.addr & mask) >> shift);
                }
        } else {
                for (off = 0; off < ipaddr_len; off++) {
                        int loc = off % 8;
                        u64 mask = vBIT(0xff,(loc*8),8);
                        int shift = 64-(loc+1)*8;

                        msg[off] = (u8)((src_ip->ipv6.addr[off/8] & mask)
                                                >> shift);
                        msg[off+ipaddr_len] = (u8)((dst_ip->ipv6.addr[off/8]
                                                    & mask) >> shift);
                }
        }

        off = (2*ipaddr_len);

        if (hldev->config.rth_spdm_use_l4) {
                msg[off] = (u8)((l4_sp & 0xff00) >> 8);
                msg[off + 1] = (u8)(l4_sp & 0xff);
                msg[off + 2] = (u8)((l4_dp & 0xff00) >> 8);
                msg[off + 3] = (u8)(l4_dp & 0xff);
                off += 4;
        }

        /*
         * Calculate jenkins hash for this configuration
         */
        val64 = xge_os_pio_mem_read64(hldev->pdev,
                                    hldev->regh0,
                                    &bar0->rts_rth_jhash_cfg);
        jhash_golden_ratio = (u32)(val64 >> 32);
        jhash_init_val = (u32)(val64 & 0xffffffff);

        jhash_value = __hal_calc_jhash(msg, off,
                                       jhash_golden_ratio,
                                       jhash_init_val);

        xge_os_spin_lock(&hldev->spdm_lock);

        /*
         * Locate a free slot in the SPDM table. To avoid a seach in the
         * actual SPDM table, which is very expensive in terms of time,
         * we are maintaining a local copy of  the table and the search for
         * the free entry is performed in the local table.
         */
        if ((status = __hal_get_free_spdm_entry(hldev,&spdm_entry))
                        != XGE_HAL_OK) {
                xge_os_spin_unlock(&hldev->spdm_lock);
                return status;
        }

        /*
         * Add this entry to the SPDM table
         */
        status =  __hal_spdm_entry_add(hldev, src_ip, dst_ip, l4_sp, l4_dp,
                                     is_tcp, is_ipv4, tgt_queue,
                                     jhash_value, /* calculated jhash */
                                     spdm_entry);

        xge_os_spin_unlock(&hldev->spdm_lock);

        return status;
}

/**
 * xge_hal_spdm_entry_remove - Remove an entry from the SPDM table.
 * @devh: HAL device handle.
 * @src_ip: Source ip address(IPv4/IPv6).
 * @dst_ip: Destination ip address(IPv4/IPv6).
 * @l4_sp: L4 source port.
 * @l4_dp: L4 destination port.
 * @is_tcp: Set to 1, if the protocol is TCP.
 *                 0, if the protocol os UDP.
 * @is_ipv4: Set to 1, if the protocol is IPv4.
 *                 0, if the protocol is IPv6.
 *
 * This function remove an entry from the SPDM table.
 *
 * Returns:  XGE_HAL_OK - success.
 * XGE_HAL_ERR_SPDM_NOT_ENABLED -  SPDM support is not enabled.
 * XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING - Failed to remove an entry with in
 *                                      the time(timeout).
 * XGE_HAL_ERR_SPDM_ENTRY_NOT_FOUND - Unable to locate the entry in the SPDM
 *                                      table.
 *
 * See also: xge_hal_spdm_entry_add{}.
 */
xge_hal_status_e
xge_hal_spdm_entry_remove(xge_hal_device_h devh, xge_hal_ipaddr_t *src_ip,
                xge_hal_ipaddr_t *dst_ip, u16 l4_sp, u16 l4_dp,
                u8 is_tcp, u8 is_ipv4)
{

        xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;
        u16 spdm_entry;
        xge_hal_status_e status;
        u64 spdm_line_arr[8];
        u8 line_no;
        u8 spdm_is_tcp;
        u8 spdm_is_ipv4;
        u16 spdm_l4_sp;
        u16 spdm_l4_dp;

        if (!hldev->config.rth_spdm_en) {
                return XGE_HAL_ERR_SPDM_NOT_ENABLED;
        }

        xge_os_spin_lock(&hldev->spdm_lock);

        /*
         * Poll the rxpic_int_reg register until spdm ready bit is set or
         * timeout happens.
         */
        if (__hal_device_register_poll(hldev, &bar0->rxpic_int_reg, 1,
                        XGE_HAL_RX_PIC_INT_REG_SPDM_READY,
                        XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {

                /* upper layer may require to repeat */
                xge_os_spin_unlock(&hldev->spdm_lock);
                return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
        }

        /*
         * Clear the SPDM READY bit.
         */
        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                               &bar0->rxpic_int_reg);
        val64 &= ~XGE_HAL_RX_PIC_INT_REG_SPDM_READY;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                      &bar0->rxpic_int_reg);

        /*
         * Search in the local SPDM table to get the index of the
         * corresponding entry in the SPDM table.
         */
        spdm_entry = 0;
        for (;spdm_entry < hldev->spdm_max_entries; spdm_entry++) {
                if ((!hldev->spdm_table[spdm_entry]->in_use) ||
                    (hldev->spdm_table[spdm_entry]->is_tcp != is_tcp) ||
                    (hldev->spdm_table[spdm_entry]->l4_sp != l4_sp) ||
                    (hldev->spdm_table[spdm_entry]->l4_dp != l4_dp) ||
                    (hldev->spdm_table[spdm_entry]->is_ipv4 != is_ipv4)) {
                        continue;
                }

                /*
                 * Compare the src/dst IP addresses of source and target
                 */
                if (is_ipv4) {
                        if ((hldev->spdm_table[spdm_entry]->src_ip.ipv4.addr
                             != src_ip->ipv4.addr) ||
                            (hldev->spdm_table[spdm_entry]->dst_ip.ipv4.addr
                             != dst_ip->ipv4.addr)) {
                                continue;
                        }
                } else {
                        if ((hldev->spdm_table[spdm_entry]->src_ip.ipv6.addr[0]
                             != src_ip->ipv6.addr[0]) ||
                            (hldev->spdm_table[spdm_entry]->src_ip.ipv6.addr[1]
                             != src_ip->ipv6.addr[1]) ||
                            (hldev->spdm_table[spdm_entry]->dst_ip.ipv6.addr[0]
                             != dst_ip->ipv6.addr[0]) ||
                            (hldev->spdm_table[spdm_entry]->dst_ip.ipv6.addr[1]
                             != dst_ip->ipv6.addr[1])) {
                                continue;
                        }
                }
                break;
        }

        if (spdm_entry >= hldev->spdm_max_entries) {
                xge_os_spin_unlock(&hldev->spdm_lock);
                return XGE_HAL_ERR_SPDM_ENTRY_NOT_FOUND;
        }

        /*
         * Retrieve the corresponding entry from the SPDM table and
         * make sure that the data is consistent.
         */
        for(line_no = 0; line_no < 8; line_no++) {

                /*
                 *  SPDM line 2,3,4 are valid only for IPv6 entry.
                 *  SPDM line 5 & 6 are reserved. We don't have to
                 *  read these entries in the above cases.
                 */
                if (((is_ipv4) &&
                        ((line_no == 2)||(line_no == 3)||(line_no == 4))) ||
                     (line_no == 5) ||
                     (line_no == 6)) {
                        continue;
                }

                if ((status = __hal_read_spdm_entry_line(
                                        hldev,
                                        line_no,
                                        spdm_entry,
                                        &spdm_line_arr[line_no]))
                                                        != XGE_HAL_OK) {
                        xge_os_spin_unlock(&hldev->spdm_lock);
                        return status;
                }
        }

        /*
         * Seventh line of the spdm entry contains the entry_enable
         * bit. Make sure that the entry_enable bit of this spdm entry
         * is set.
         * To remove an entry from the SPDM table, reset this
         * bit.
         */
        if (!(spdm_line_arr[7] & BIT(63))) {
                /*
                 * Log a warning
                 */
                xge_debug_device(XGE_ERR, "Local SPDM table is not "
                        "consistent with the actual one for the spdm "
                        "entry %d ", spdm_entry);
                goto err_exit;
        }

        /*
         *  Retreive the L4 SP/DP, src/dst ip addresses from the SPDM
         *  table and do a comparision.
         */
        spdm_is_tcp = (u8)((spdm_line_arr[0] & BIT(59)) >> 4);
        spdm_is_ipv4 = (u8)(spdm_line_arr[0] & BIT(63));
        spdm_l4_sp = (u16)(spdm_line_arr[0] >> 48);
        spdm_l4_dp = (u16)((spdm_line_arr[0] >> 32) & 0xffff);


        if ((spdm_is_tcp != is_tcp) ||
            (spdm_is_ipv4 != is_ipv4) ||
            (spdm_l4_sp != l4_sp) ||
            (spdm_l4_dp != l4_dp)) {
                /*
                 * Log a warning
                 */
                xge_debug_device(XGE_ERR, "Local SPDM table is not "
                        "consistent with the actual one for the spdm "
                        "entry %d ", spdm_entry);
                goto err_exit;
        }

        if (is_ipv4) {
                /* Upper 32 bits of spdm_line(64 bit) contains the
                 * src IPv4 address. Lower 32 bits of spdm_line
                 * contains the destination IPv4 address.
                 */
                u32 temp_src_ip = (u32)(spdm_line_arr[1] >> 32);
                u32 temp_dst_ip = (u32)(spdm_line_arr[1] & 0xffffffff);

                if ((temp_src_ip != src_ip->ipv4.addr) ||
                    (temp_dst_ip != dst_ip->ipv4.addr)) {
                        xge_debug_device(XGE_ERR, "Local SPDM table is not "
                                "consistent with the actual one for the spdm "
                                "entry %d ", spdm_entry);
                        goto err_exit;
                }

        } else {
                /*
                 * SPDM line 1 & 2 contains the src IPv6 address.
                 * SPDM line 3 & 4 contains the dst IPv6 address.
                 */
                if ((spdm_line_arr[1] != src_ip->ipv6.addr[0]) ||
                    (spdm_line_arr[2] != src_ip->ipv6.addr[1]) ||
                    (spdm_line_arr[3] != dst_ip->ipv6.addr[0]) ||
                    (spdm_line_arr[4] != dst_ip->ipv6.addr[1])) {

                        /*
                         * Log a warning
                         */
                        xge_debug_device(XGE_ERR, "Local SPDM table is not "
                                "consistent with the actual one for the spdm "
                                "entry %d ", spdm_entry);
                        goto err_exit;
                }
        }

        /*
         * Reset the entry_enable bit to zero
         */
        spdm_line_arr[7] &= ~BIT(63);

        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                spdm_line_arr[7],
                (void *)((char *)hldev->spdm_mem_base +
                (spdm_entry * 64) + (7 * 8)));

        /*
         * Wait for the operation to be completed.
         */
        if (__hal_device_register_poll(hldev,
                &bar0->rxpic_int_reg, 1,
                XGE_HAL_RX_PIC_INT_REG_SPDM_READY,
                XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
                xge_os_spin_unlock(&hldev->spdm_lock);
                return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
        }

        /*
         * Make the corresponding spdm entry in the local SPDM table
         * available for future use.
         */
        hldev->spdm_table[spdm_entry]->in_use = 0;
        xge_os_spin_unlock(&hldev->spdm_lock);

        return XGE_HAL_OK;

err_exit:
        xge_os_spin_unlock(&hldev->spdm_lock);
        return XGE_HAL_ERR_SPDM_TABLE_DATA_INCONSISTENT;
}

/*
 * __hal_device_rti_set
 * @ring: The post_qid of the ring.
 * @channel: HAL channel of the ring.
 *
 * This function stores the RTI value associated for the MSI and
 * also unmasks this particular RTI in the rti_mask register.
 */
static void __hal_device_rti_set(int ring_qid, xge_hal_channel_t *channel)
{
        xge_hal_device_t *hldev = (xge_hal_device_t*)channel->devh;
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)hldev->bar0;
        u64 val64;

        if (hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSI ||
            hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSIX)
                channel->rti = (u8)ring_qid;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                            &bar0->rx_traffic_mask);
        val64 &= ~BIT(ring_qid);
        xge_os_pio_mem_write64(hldev->pdev,
                            hldev->regh0, val64,
                            &bar0->rx_traffic_mask);
}

/*
 * __hal_device_tti_set
 * @ring: The post_qid of the FIFO.
 * @channel: HAL channel the FIFO.
 *
 * This function stores the TTI value associated for the MSI and
 * also unmasks this particular TTI in the tti_mask register.
 */
static void __hal_device_tti_set(int fifo_qid, xge_hal_channel_t *channel)
{
        xge_hal_device_t *hldev = (xge_hal_device_t*)channel->devh;
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)hldev->bar0;
        u64 val64;

        if (hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSI ||
            hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSIX)
                channel->tti = (u8)fifo_qid;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                            &bar0->tx_traffic_mask);
        val64 &= ~BIT(fifo_qid);
        xge_os_pio_mem_write64(hldev->pdev,
                            hldev->regh0, val64,
                            &bar0->tx_traffic_mask);
}

/**
 * xge_hal_channel_msi_set - Associate a RTI with a ring or TTI with a
 * FIFO for a given MSI.
 * @channelh: HAL channel handle.
 * @msi: MSI Number associated with the channel.
 * @msi_msg: The MSI message associated with the MSI number above.
 *
 * This API will associate a given channel (either Ring or FIFO) with the
 * given MSI number. It will alo program the Tx_Mat/Rx_Mat tables in the
 * hardware to indicate this association to the hardware.
 */
xge_hal_status_e
xge_hal_channel_msi_set(xge_hal_channel_h channelh, int msi, u32 msi_msg)
{
        xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
        xge_hal_device_t *hldev = (xge_hal_device_t*)channel->devh;
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)hldev->bar0;
        u64 val64;

        channel->msi_msg = msi_msg;
        if (channel->type == XGE_HAL_CHANNEL_TYPE_RING) {
                int ring = channel->post_qid;
                xge_debug_osdep(XGE_TRACE, "MSI Data: 0x%4x, Ring: %d,"
                                " MSI: %d", channel->msi_msg, ring, msi);
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                        &bar0->rx_mat);
                val64 |= XGE_HAL_SET_RX_MAT(ring, msi);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                        &bar0->rx_mat);
                __hal_device_rti_set(ring, channel);
        } else {
                int fifo = channel->post_qid;
                xge_debug_osdep(XGE_TRACE, "MSI Data: 0x%4x, Fifo: %d,"
                                " MSI: %d", channel->msi_msg, fifo, msi);
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                        &bar0->tx_mat[0]);
                val64 |= XGE_HAL_SET_TX_MAT(fifo, msi);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                        &bar0->tx_mat[0]);
                __hal_device_tti_set(fifo, channel);
        }

         return XGE_HAL_OK;
}

/**
 * xge_hal_mask_msix - Begin IRQ processing.
 * @hldev: HAL device handle.
 * @msi_id:  MSI ID
 *
 * The function masks the msix interrupt for the given msi_id
 *
 * Note:
 *
 * Returns: 0,
 * Otherwise, XGE_HAL_ERR_WRONG_IRQ if the msix index is out of range
 * status.
 * See also:
 */
xge_hal_status_e
xge_hal_mask_msix(xge_hal_device_h devh, int msi_id)
{
        xge_hal_status_e  status = XGE_HAL_OK;
        xge_hal_device_t *hldev  = (xge_hal_device_t *)devh;
        u32              *bar2   = (u32 *)hldev->bar2;
        u32               val32;

        xge_assert(msi_id < XGE_HAL_MAX_MSIX_MESSAGES);

        val32 = xge_os_pio_mem_read32(hldev->pdev, hldev->regh2, &bar2[msi_id*4+3]);
        val32 |= 1;
        xge_os_pio_mem_write32(hldev->pdev, hldev->regh2, val32, &bar2[msi_id*4+3]);
        return status;
}

/**
 * xge_hal_mask_msix - Begin IRQ processing.
 * @hldev: HAL device handle.
 * @msi_id:  MSI ID
 *
 * The function masks the msix interrupt for the given msi_id
 *
 * Note:
 *
 * Returns: 0,
 * Otherwise, XGE_HAL_ERR_WRONG_IRQ if the msix index is out of range
 * status.
 * See also:
 */
xge_hal_status_e
xge_hal_unmask_msix(xge_hal_device_h devh, int msi_id)
{
        xge_hal_status_e  status = XGE_HAL_OK;
        xge_hal_device_t *hldev  = (xge_hal_device_t *)devh;
        u32              *bar2   = (u32 *)hldev->bar2;
        u32               val32;

        xge_assert(msi_id < XGE_HAL_MAX_MSIX_MESSAGES);

        val32 = xge_os_pio_mem_read32(hldev->pdev, hldev->regh2, &bar2[msi_id*4+3]);
        val32 &= ~1;
        xge_os_pio_mem_write32(hldev->pdev, hldev->regh2, val32, &bar2[msi_id*4+3]);
        return status;
}

/*
 * __hal_set_msix_vals
 * @devh: HAL device handle.
 * @msix_value: 32bit MSI-X value transferred across PCI to @msix_address.
 *              Filled in by this function.
 * @msix_address: 32bit MSI-X DMA address.
 *              Filled in by this function.
 * @msix_idx: index that corresponds to the (@msix_value, @msix_address)
 *            entry in the table of MSI-X (value, address) pairs.
 *
 * This function will program the hardware associating the given
 * address/value cobination to the specified msi number.
 */
static void __hal_set_msix_vals (xge_hal_device_h devh,
                                 u32 *msix_value,
                                 u64 *msix_addr,
                                 int msix_idx)
{
        int cnt = 0;

        xge_hal_device_t *hldev = (xge_hal_device_t*)devh;
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)hldev->bar0;
        u64 val64;

        val64 = XGE_HAL_XMSI_NO(msix_idx) | XGE_HAL_XMSI_STROBE;
        __hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0,
                        (u32)(val64 >> 32), &bar0->xmsi_access);
        __hal_pio_mem_write32_lower(hldev->pdev, hldev->regh0,
                                   (u32)(val64), &bar0->xmsi_access);
        do {
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                            &bar0->xmsi_access);
                if (val64 & XGE_HAL_XMSI_STROBE)
                        break;
                cnt++;
                xge_os_mdelay(20);
        } while(cnt < 5);
        *msix_value = (u32)(xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                             &bar0->xmsi_data));
        *msix_addr = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                             &bar0->xmsi_address);
}

/**
 * xge_hal_channel_msix_set - Associate MSI-X with a channel.
 * @channelh: HAL channel handle.
 * @msix_idx: index that corresponds to a particular (@msix_value,
 *            @msix_address) entry in the MSI-X table.
 *
 * This API associates a given channel (either Ring or FIFO) with the
 * given MSI-X number. It programs the Xframe's Tx_Mat/Rx_Mat tables
 * to indicate this association.
 */
xge_hal_status_e
xge_hal_channel_msix_set(xge_hal_channel_h channelh, int msix_idx)
{
        xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
        xge_hal_device_t *hldev = (xge_hal_device_t*)channel->devh;
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)hldev->bar0;
        u64 val64;

         if (channel->type == XGE_HAL_CHANNEL_TYPE_RING) {
                 /* Currently Ring and RTI is one on one. */
                int ring = channel->post_qid;
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                        &bar0->rx_mat);
                val64 |= XGE_HAL_SET_RX_MAT(ring, msix_idx);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                        &bar0->rx_mat);
                __hal_device_rti_set(ring, channel);
                hldev->config.ring.queue[channel->post_qid].intr_vector =
                                                                msix_idx;
         } else if (channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) {
                int fifo = channel->post_qid;
                val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                        &bar0->tx_mat[0]);
                val64 |= XGE_HAL_SET_TX_MAT(fifo, msix_idx);
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                        &bar0->tx_mat[0]);
                __hal_device_tti_set(fifo, channel);
                hldev->config.fifo.queue[channel->post_qid].intr_vector =
                                                                msix_idx;
        }
         channel->msix_idx = msix_idx;
        __hal_set_msix_vals(hldev, &channel->msix_data,
                            &channel->msix_address,
                            channel->msix_idx);

         return XGE_HAL_OK;
}

#if defined(XGE_HAL_CONFIG_LRO)
/**
 * xge_hal_lro_terminate - Terminate lro resources.
 * @lro_scale: Amount of  lro memory.
 * @hldev: Hal device structure.
 *
 */
void
xge_hal_lro_terminate(u32 lro_scale,
                    xge_hal_device_t *hldev)
{
}

/**
 * xge_hal_lro_init - Initiate lro resources.
 * @lro_scale: Amount of  lro memory.
 * @hldev: Hal device structure.
 * Note: For time being I am using only one LRO per device. Later on size
 * will be increased.
 */

xge_hal_status_e
xge_hal_lro_init(u32 lro_scale,
               xge_hal_device_t *hldev)
{
        int i;

        if (hldev->config.lro_sg_size == XGE_HAL_DEFAULT_USE_HARDCODE)
                hldev->config.lro_sg_size = XGE_HAL_LRO_DEFAULT_SG_SIZE;

        if (hldev->config.lro_frm_len == XGE_HAL_DEFAULT_USE_HARDCODE)
                hldev->config.lro_frm_len = XGE_HAL_LRO_DEFAULT_FRM_LEN;

        for (i=0; i < XGE_HAL_MAX_RING_NUM; i++)
        {
                xge_os_memzero(hldev->lro_desc[i].lro_pool,
                               sizeof(lro_t) * XGE_HAL_LRO_MAX_BUCKETS);

                hldev->lro_desc[i].lro_next_idx = 0;
                hldev->lro_desc[i].lro_recent = NULL;
        }

        return XGE_HAL_OK;
}
#endif


/**
 * xge_hal_device_poll - HAL device "polling" entry point.
 * @devh: HAL device.
 *
 * HAL "polling" entry point. Note that this is part of HAL public API.
 * Upper-Layer driver _must_ periodically poll HAL via
 * xge_hal_device_poll().
 *
 * HAL uses caller's execution context to serially process accumulated
 * slow-path events, such as link state changes and hardware error
 * indications.
 *
 * The rate of polling could be somewhere between 500us to 10ms,
 * depending on requirements (e.g., the requirement to support fail-over
 * could mean that 500us or even 100us polling interval need to be used).
 *
 * The need and motivation for external polling includes
 *
 *   - remove the error-checking "burden" from the HAL interrupt handler
 *     (see xge_hal_device_handle_irq());
 *
 *   - remove the potential source of portability issues by _not_
 *     implementing separate polling thread within HAL itself.
 *
 * See also: xge_hal_event_e{}, xge_hal_driver_config_t{}.
 * Usage: See ex_slow_path{}.
 */
void
xge_hal_device_poll(xge_hal_device_h devh)
{
        unsigned char item_buf[sizeof(xge_queue_item_t) +
                                XGE_DEFAULT_EVENT_MAX_DATA_SIZE];
        xge_queue_item_t *item = (xge_queue_item_t *)(void *)item_buf;
        xge_queue_status_e qstatus;
        xge_hal_status_e hstatus;
        int i = 0;
        int queue_has_critical_event = 0;
        xge_hal_device_t *hldev = (xge_hal_device_t*)devh;

  xge_os_memzero(item_buf, (sizeof(xge_queue_item_t) +
                             XGE_DEFAULT_EVENT_MAX_DATA_SIZE));

_again:
        if (!hldev->is_initialized ||
            hldev->terminating ||
            hldev->magic != XGE_HAL_MAGIC)
                return;

        if(hldev->stats.sw_dev_err_stats.xpak_counter.tick_period < 72000)
        {
                /*
                 * Wait for an Hour
                 */
                hldev->stats.sw_dev_err_stats.xpak_counter.tick_period++;
        } else {
                /*
                 * Logging Error messages in the excess temperature,
                 * Bias current, laser ouput for three cycle
                 */
                __hal_updt_stats_xpak(hldev);
                hldev->stats.sw_dev_err_stats.xpak_counter.tick_period = 0;
        }

        if (!queue_has_critical_event)
                queue_has_critical_event =
                        __queue_get_reset_critical(hldev->queueh);

        hldev->in_poll = 1;
        while (i++ < XGE_HAL_DRIVER_QUEUE_CONSUME_MAX || queue_has_critical_event) {

                qstatus = xge_queue_consume(hldev->queueh,
                                    XGE_DEFAULT_EVENT_MAX_DATA_SIZE,
                                    item);
                if (qstatus == XGE_QUEUE_IS_EMPTY)
                        break;

                xge_debug_queue(XGE_TRACE,
                         "queueh 0x"XGE_OS_LLXFMT" consumed event: %d ctxt 0x"
                         XGE_OS_LLXFMT, (u64)(ulong_t)hldev->queueh, item->event_type,
                         (u64)(ulong_t)item->context);

                if (!hldev->is_initialized ||
                    hldev->magic != XGE_HAL_MAGIC) {
                        hldev->in_poll = 0;
                        return;
                }

                switch (item->event_type) {
                case XGE_HAL_EVENT_LINK_IS_UP: {
                        if (!queue_has_critical_event &&
                            g_xge_hal_driver->uld_callbacks.link_up) {
                                g_xge_hal_driver->uld_callbacks.link_up(
                                        hldev->upper_layer_info);
                                hldev->link_state = XGE_HAL_LINK_UP;
                        }
                } break;
                case XGE_HAL_EVENT_LINK_IS_DOWN: {
                        if (!queue_has_critical_event &&
                            g_xge_hal_driver->uld_callbacks.link_down) {
                                g_xge_hal_driver->uld_callbacks.link_down(
                                        hldev->upper_layer_info);
                                hldev->link_state = XGE_HAL_LINK_DOWN;
                        }
                } break;
                case XGE_HAL_EVENT_SERR:
                case XGE_HAL_EVENT_ECCERR:
                case XGE_HAL_EVENT_PARITYERR:
                case XGE_HAL_EVENT_TARGETABORT:
                case XGE_HAL_EVENT_SLOT_FREEZE: {
                        void *item_data = xge_queue_item_data(item);
                        xge_hal_event_e event_type = item->event_type;
                        u64 val64 = *((u64*)item_data);

                        if (event_type != XGE_HAL_EVENT_SLOT_FREEZE)
                                if (xge_hal_device_is_slot_freeze(hldev))
                                        event_type = XGE_HAL_EVENT_SLOT_FREEZE;
                        if (g_xge_hal_driver->uld_callbacks.crit_err) {
                            g_xge_hal_driver->uld_callbacks.crit_err(
                                        hldev->upper_layer_info,
                                        event_type,
                                        val64);
                                /* handle one critical event per poll cycle */
                                hldev->in_poll = 0;
                                return;
                        }
                } break;
                default: {
                        xge_debug_queue(XGE_TRACE,
                                "got non-HAL event %d",
                                item->event_type);
                } break;
                }

                /* broadcast this event */
                if (g_xge_hal_driver->uld_callbacks.event)
                        g_xge_hal_driver->uld_callbacks.event(item);
        }

        if (g_xge_hal_driver->uld_callbacks.before_device_poll) {
                if (g_xge_hal_driver->uld_callbacks.before_device_poll(
                                             hldev) != 0) {
                        hldev->in_poll = 0;
                        return;
                }
        }

        hstatus = __hal_device_poll(hldev);
        if (g_xge_hal_driver->uld_callbacks.after_device_poll)
            g_xge_hal_driver->uld_callbacks.after_device_poll(hldev);

        /*
         * handle critical error right away:
         * - walk the device queue again
         * - drop non-critical events, if any
         * - look for the 1st critical
         */
        if (hstatus == XGE_HAL_ERR_CRITICAL) {
                queue_has_critical_event = 1;
                goto _again;
        }

        hldev->in_poll = 0;
}

/**
 * xge_hal_rts_rth_init - Set enhanced mode for  RTS hashing.
 * @hldev: HAL device handle.
 *
 * This function is used to set the adapter to enhanced mode.
 *
 * See also: xge_hal_rts_rth_clr(), xge_hal_rts_rth_set().
 */
void
xge_hal_rts_rth_init(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;

        /*
         * Set the receive traffic steering mode from default(classic)
         * to enhanced.
         */
        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                      &bar0->rts_ctrl);
        val64 |= XGE_HAL_RTS_CTRL_ENHANCED_MODE;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                               val64, &bar0->rts_ctrl);
}

/**
 * xge_hal_rts_rth_clr - Clear RTS hashing.
 * @hldev: HAL device handle.
 *
 * This function is used to clear all RTS hashing related stuff.
 * It brings the adapter out from enhanced mode to classic mode.
 * It also clears RTS_RTH_CFG register i.e clears hash type, function etc.
 *
 * See also: xge_hal_rts_rth_set(), xge_hal_rts_rth_itable_set().
 */
void
xge_hal_rts_rth_clr(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;

        /*
         * Set the receive traffic steering mode from default(classic)
         * to enhanced.
         */
        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                      &bar0->rts_ctrl);
        val64 &=  ~XGE_HAL_RTS_CTRL_ENHANCED_MODE;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                               val64, &bar0->rts_ctrl);
        val64 = 0;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                               &bar0->rts_rth_cfg);
}

/**
 * xge_hal_rts_rth_set - Set/configure RTS hashing.
 * @hldev: HAL device handle.
 * @def_q: default queue
 * @hash_type: hash type i.e TcpIpV4, TcpIpV6 etc.
 * @bucket_size: no of least significant bits to be used for hashing.
 *
 * Used to set/configure all RTS hashing related stuff.
 * - set the steering mode to enhanced.
 * - set hash function i.e algo selection.
 * - set the default queue.
 *
 * See also: xge_hal_rts_rth_clr(), xge_hal_rts_rth_itable_set().
 */
void
xge_hal_rts_rth_set(xge_hal_device_t *hldev, u8 def_q, u64 hash_type,
                    u16 bucket_size)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;

        val64 = XGE_HAL_RTS_DEFAULT_Q(def_q);
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                               &bar0->rts_default_q);

        val64 = hash_type;
        val64 |= XGE_HAL_RTS_RTH_EN;
        val64 |= XGE_HAL_RTS_RTH_BUCKET_SIZE(bucket_size);
        val64 |= XGE_HAL_RTS_RTH_ALG_SEL_MS;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                               &bar0->rts_rth_cfg);
}

/**
 * xge_hal_rts_rth_start - Start RTS hashing.
 * @hldev: HAL device handle.
 *
 * Used to Start RTS hashing .
 *
 * See also: xge_hal_rts_rth_clr(), xge_hal_rts_rth_itable_set(), xge_hal_rts_rth_start.
 */
void
xge_hal_rts_rth_start(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;


        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                      &bar0->rts_rth_cfg);
        val64 |= XGE_HAL_RTS_RTH_EN;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                               &bar0->rts_rth_cfg);
}

/**
 * xge_hal_rts_rth_stop - Stop the RTS hashing.
 * @hldev: HAL device handle.
 *
 * Used to Staop RTS hashing .
 *
 * See also: xge_hal_rts_rth_clr(), xge_hal_rts_rth_itable_set(), xge_hal_rts_rth_start.
 */
void
xge_hal_rts_rth_stop(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
        u64 val64;

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                      &bar0->rts_rth_cfg);
        val64 &=  ~XGE_HAL_RTS_RTH_EN;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                               &bar0->rts_rth_cfg);
}

/**
 * xge_hal_rts_rth_itable_set - Set/configure indirection table (IT).
 * @hldev: HAL device handle.
 * @itable: Pointer to the indirection table
 * @itable_size: no of least significant bits to be used for hashing
 *
 * Used to set/configure indirection table.
 * It enables the required no of entries in the IT.
 * It adds entries to the IT.
 *
 * See also: xge_hal_rts_rth_clr(), xge_hal_rts_rth_set().
 */
xge_hal_status_e
xge_hal_rts_rth_itable_set(xge_hal_device_t *hldev, u8 *itable, u32 itable_size)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void  *)hldev->bar0;
        u64 val64;
        u32 idx;

        for (idx = 0; idx < itable_size; idx++) {
                val64 = XGE_HAL_RTS_RTH_MAP_MEM_DATA_ENTRY_EN |
                        XGE_HAL_RTS_RTH_MAP_MEM_DATA(itable[idx]);

                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                                       &bar0->rts_rth_map_mem_data);

                /* execute */
                val64 = (XGE_HAL_RTS_RTH_MAP_MEM_CTRL_WE |
                         XGE_HAL_RTS_RTH_MAP_MEM_CTRL_STROBE |
                         XGE_HAL_RTS_RTH_MAP_MEM_CTRL_OFFSET(idx));
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                                       &bar0->rts_rth_map_mem_ctrl);

                /* poll until done */
                if (__hal_device_register_poll(hldev,
                       &bar0->rts_rth_map_mem_ctrl, 0,
                       XGE_HAL_RTS_RTH_MAP_MEM_CTRL_STROBE,
                       XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
                        /* upper layer may require to repeat */
                        return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
                }
        }

        return XGE_HAL_OK;
}


/**
 * xge_hal_device_rts_rth_key_set - Configure 40byte secret for hash calc.
 *
 * @hldev: HAL device handle.
 * @KeySize: Number of 64-bit words
 * @Key: upto 40-byte array of 8-bit values
 * This function configures the 40-byte secret which is used for hash
 * calculation.
 *
 * See also: xge_hal_rts_rth_clr(), xge_hal_rts_rth_set().
 */
void
xge_hal_device_rts_rth_key_set(xge_hal_device_t *hldev, u8 KeySize, u8 *Key)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *) hldev->bar0;
        u64 val64;
        u32 entry, nreg, i;

        entry = 0;
        nreg = 0;

        while( KeySize ) {
                val64 = 0;
                for ( i = 0; i < 8 ; i++) {
                        /* Prepare 64-bit word for 'nreg' containing 8 keys. */
                        if (i)
                                val64 <<= 8;
                        val64 |= Key[entry++];
                }

                KeySize--;

                /* temp64 = XGE_HAL_RTH_HASH_MASK_n(val64, (n<<3), (n<<3)+7);*/
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                                       &bar0->rts_rth_hash_mask[nreg++]);
        }

        while( nreg < 5 ) {
                /* Clear the rest if key is less than 40 bytes */
                val64 = 0;
                xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
                                       &bar0->rts_rth_hash_mask[nreg++]);
        }
}


/**
 * xge_hal_device_is_closed - Device is closed
 *
 * @devh: HAL device handle.
 */
int
xge_hal_device_is_closed(xge_hal_device_h devh)
{
        xge_hal_device_t *hldev = (xge_hal_device_t *)devh;

        if (xge_list_is_empty(&hldev->fifo_channels) &&
            xge_list_is_empty(&hldev->ring_channels))
                return 1;

        return 0;
}

xge_hal_status_e
xge_hal_device_rts_section_enable(xge_hal_device_h devh, int index)
{
        u64 val64;
        int section;
        int max_addr = XGE_HAL_MAX_MAC_ADDRESSES;

        xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;

        if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC)
                max_addr = XGE_HAL_MAX_MAC_ADDRESSES_HERC;

        if ( index >= max_addr )
                return XGE_HAL_ERR_OUT_OF_MAC_ADDRESSES;

        /*
         * Calculate the section value
         */
        section = index / 32;

        xge_debug_device(XGE_TRACE, "the Section value is %d ", section);

        val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
                                &bar0->rts_mac_cfg);
        switch(section)
        {
                case 0:
                        val64 |=  XGE_HAL_RTS_MAC_SECT0_EN;
                        break;
                case 1:
                        val64 |=  XGE_HAL_RTS_MAC_SECT1_EN;
                        break;
                case 2:
                        val64 |=  XGE_HAL_RTS_MAC_SECT2_EN;
                        break;
                case 3:
                        val64 |=  XGE_HAL_RTS_MAC_SECT3_EN;
                        break;
                case 4:
                        val64 |=  XGE_HAL_RTS_MAC_SECT4_EN;
                        break;
                case 5:
                        val64 |=  XGE_HAL_RTS_MAC_SECT5_EN;
                        break;
                case 6:
                        val64 |=  XGE_HAL_RTS_MAC_SECT6_EN;
                        break;
                case 7:
                        val64 |=  XGE_HAL_RTS_MAC_SECT7_EN;
                        break;
                default:
                        xge_debug_device(XGE_ERR, "Invalid Section value %d "
                                        , section);
        }

        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
                                val64, &bar0->rts_mac_cfg);
        return XGE_HAL_OK;
}

/*
 * xge_hal_fix_rldram_ecc_error
 * @hldev: private member of the device structure.
 *
 * SXE-02-010. This function will turn OFF the ECC error reporting for the
 * interface bet'n external Micron RLDRAM II device and memory controller.
 * The error would have been reported in RLD_ECC_DB_ERR_L and RLD_ECC_DB_ERR_U
 * fileds of MC_ERR_REG register. Issue reported by HP-Unix folks during the
 * qualification of Herc.
 */
xge_hal_status_e
xge_hal_fix_rldram_ecc_error(xge_hal_device_t *hldev)
{
        xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)hldev->bar0;
        u64 val64;

        // Enter Test Mode.
        val64 = XGE_HAL_MC_RLDRAM_TEST_MODE;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
            &bar0->mc_rldram_test_ctrl);

        // Enable fg/bg tests.
        val64 = 0x0100000000000000ULL;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
            &bar0->mc_driver);

        // Enable RLDRAM configuration.
        val64 = 0x0000000000017B00ULL;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
            &bar0->mc_rldram_mrs);

        // Enable RLDRAM queues.
        val64 = 0x0000000001017B00ULL;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
            &bar0->mc_rldram_mrs);

        // Setup test ranges.
        val64 = 0x00000000001E0100ULL;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
            &bar0->mc_rldram_test_add);

        val64 = 0x00000100001F0100ULL;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
            &bar0->mc_rldram_test_add_bkg);

        // Start Reads.
        val64 = 0x0001000000010000ULL;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
            &bar0->mc_rldram_test_ctrl);

        if (__hal_device_register_poll(hldev, &bar0->mc_rldram_test_ctrl, 1,
            XGE_HAL_MC_RLDRAM_TEST_DONE,
            XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
                return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
        }

        // Exit test mode.
        val64 = 0x0000000000000000ULL;
        xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
            &bar0->mc_rldram_test_ctrl);

        return XGE_HAL_OK;
}

/*
 * xge_hal_device_quiesce
 * @hldev: HAL device object
 * @devh : HAL device handle
 *
 * This is called by xge_quiesce to quiesce the device.
 */
void
xge_hal_device_quiesce(xge_hal_device_t *hldev, xge_hal_device_h devh)
{
        /* Turn off debugging */
        g_xge_hal_driver->debug_level = XGE_NONE;
        g_level = &(g_xge_hal_driver->debug_level);

        /* Disable device */
        (void) xge_hal_device_disable(devh);

        /* Disable Xframe interrupts */
        xge_hal_device_intr_disable(devh);
}