Logo Search packages:      
Sourcecode: kfreebsd-7 version File versions  Download package

xgehal-device.c

/*-
 * Copyright (c) 2002-2007 Neterion, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: src/sys/dev/nxge/xgehal/xgehal-device.c,v 1.1.2.1 2007/11/02 00:52:33 rwatson Exp $
 */

#include <dev/nxge/include/xgehal-device.h>
#include <dev/nxge/include/xgehal-channel.h>
#include <dev/nxge/include/xgehal-fifo.h>
#include <dev/nxge/include/xgehal-ring.h>
#include <dev/nxge/include/xgehal-driver.h>
#include <dev/nxge/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);
      }
#if 0  // Removing temporarily as FreeBSD is seeing lower performance 
         // attributable to this fix. 
      /* SXE-2-010 */
      if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
          /* Turn off the ECC error reporting for RLDRAM interface */
          if ((status = xge_hal_fix_rldram_ecc_error(hldev)) != XGE_HAL_OK)
              return status;
      }
#endif 
      __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)
#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) {
              /*  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 : xge_hal_device_reset(hldev);
      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) {
          xge_hal_device_reset(hldev);
          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) {
          xge_hal_device_reset(hldev);
          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 : xge_hal_device_reset(hldev);
      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) {
          xge_hal_device_reset(hldev);
          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) {
          xge_hal_device_reset(hldev);
          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.
           */
          __hal_device_intr_mgmt(hldev, XGE_HAL_ALL_INTRS, 0);
      } 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;

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

      for (i=1; i<XGE_HAL_MAX_MAC_ADDRESSES; i++) {
          macaddr_t macaddr;
          (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 == 0))  {
          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_strcpy((char *) hldev->vpd_data.product_name,
                  "10 Gigabit Ethernet Adapter");
      xge_os_strcpy((char *) hldev->vpd_data.serial_num, "not available");

      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)) {
                      memset(hldev->vpd_data.serial_num, 0, XGE_HAL_VPD_LENGTH);
                      memcpy(hldev->vpd_data.serial_num, &vpd_data[count + 3],
                          vpd_data[count + 2]);
                      break;
              }
          }

          if (vpd_data[1] < XGE_HAL_VPD_LENGTH) {
              memset(hldev->vpd_data.product_name, 0, vpd_data[1]);
              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.fifo.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.ring.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
 * fields 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;
}

Generated by  Doxygen 1.6.0   Back to index