]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
add hxge-1.3.3 driver
authorMaxim Uvarov <maxim.uvarov@oracle.com>
Tue, 27 Mar 2012 22:07:54 +0000 (15:07 -0700)
committerMaxim Uvarov <maxim.uvarov@oracle.com>
Mon, 2 Apr 2012 17:48:27 +0000 (10:48 -0700)
Signed-off-by: Maxim Uvarov <maxim.uvarov@oracle.com>
41 files changed:
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/hxge/Kconfig [new file with mode: 0644]
drivers/net/hxge/Makefile [new file with mode: 0644]
drivers/net/hxge/hpi/hpi.c [new file with mode: 0644]
drivers/net/hxge/hpi/hpi.h [new file with mode: 0644]
drivers/net/hxge/hpi/hpi_pfc.c [new file with mode: 0644]
drivers/net/hxge/hpi/hpi_pfc.h [new file with mode: 0644]
drivers/net/hxge/hpi/hpi_rxdma.c [new file with mode: 0644]
drivers/net/hxge/hpi/hpi_rxdma.h [new file with mode: 0644]
drivers/net/hxge/hpi/hpi_txdma.c [new file with mode: 0644]
drivers/net/hxge/hpi/hpi_txdma.h [new file with mode: 0644]
drivers/net/hxge/hpi/hpi_vir.c [new file with mode: 0644]
drivers/net/hxge/hpi/hpi_vir.h [new file with mode: 0644]
drivers/net/hxge/hpi/hpi_vmac.c [new file with mode: 0644]
drivers/net/hxge/hpi/hpi_vmac.h [new file with mode: 0644]
drivers/net/hxge/hxge.h [new file with mode: 0644]
drivers/net/hxge/hxge_classify.h [new file with mode: 0644]
drivers/net/hxge/hxge_defs.h [new file with mode: 0644]
drivers/net/hxge/hxge_ethtool.c [new file with mode: 0644]
drivers/net/hxge/hxge_intr.c [new file with mode: 0644]
drivers/net/hxge/hxge_main.c [new file with mode: 0644]
drivers/net/hxge/hxge_other.c [new file with mode: 0644]
drivers/net/hxge/hxge_param.c [new file with mode: 0644]
drivers/net/hxge/hxge_peu_hw.h [new file with mode: 0644]
drivers/net/hxge/hxge_pfc.c [new file with mode: 0644]
drivers/net/hxge/hxge_pfc.h [new file with mode: 0644]
drivers/net/hxge/hxge_pfc_hw.h [new file with mode: 0644]
drivers/net/hxge/hxge_rdc_hw.h [new file with mode: 0644]
drivers/net/hxge/hxge_rxdma.c [new file with mode: 0644]
drivers/net/hxge/hxge_rxdma.h [new file with mode: 0644]
drivers/net/hxge/hxge_stats.c [new file with mode: 0644]
drivers/net/hxge/hxge_sysfs.c [new file with mode: 0644]
drivers/net/hxge/hxge_tdc_hw.h [new file with mode: 0644]
drivers/net/hxge/hxge_txdma.c [new file with mode: 0644]
drivers/net/hxge/hxge_txdma.h [new file with mode: 0644]
drivers/net/hxge/hxge_txdma_hw.h [new file with mode: 0644]
drivers/net/hxge/hxge_vmac.c [new file with mode: 0644]
drivers/net/hxge/hxge_vmac.h [new file with mode: 0644]
drivers/net/hxge/hxge_vmac_hw.h [new file with mode: 0644]
uek-rpm/ol6/config-generic

index 93359fab240e13f95e61b8a94f8045b61bf13f01..003116b8bb2ff5c974843cd8dcf772fd2c5f4a9a 100644 (file)
@@ -2927,6 +2927,8 @@ source "drivers/net/sfc/Kconfig"
 
 source "drivers/net/benet/Kconfig"
 
+source "drivers/net/hxge/Kconfig"
+
 endif # NETDEV_10000
 
 source "drivers/net/tokenring/Kconfig"
index d5ce0115e065bbd5572252ef3ed672c01bd393e1..5add04207dd1f5ecd4d2671584fc75304047ce12 100644 (file)
@@ -38,7 +38,7 @@ obj-$(CONFIG_JME) += jme.o
 obj-$(CONFIG_BE2NET) += benet/
 obj-$(CONFIG_VMXNET3) += vmxnet3/
 obj-$(CONFIG_BNA) += bna/
-
+obj-$(CONFIG_HXGE) += hxge/
 gianfar_driver-objs := gianfar.o \
                gianfar_ethtool.o \
                gianfar_sysfs.o
diff --git a/drivers/net/hxge/Kconfig b/drivers/net/hxge/Kconfig
new file mode 100644 (file)
index 0000000..1b77e56
--- /dev/null
@@ -0,0 +1,24 @@
+config HXGE 
+        tristate "Sun Microsystems 10Gb Ethernet Adapter "
+        depends on PCI
+        ---help---
+          This driver supports the Hydra 10Gb Ethernet driver.  
+
+
+config HXGE_NAPI
+        bool "Use Rx Polling (NAPI)"
+        depends on HXGE
+        help
+          NAPI is a new driver API designed to reduce CPU and interrupt load
+          when the driver is receiving lots of packets from the card. It is
+          still somewhat experimental and thus not yet enabled by default.
+
+          If your estimated Rx load is 10kpps or more, or if the card will be
+          deployed on potentially unfriendly networks (e.g. in a firewall),
+          then say Y here.
+
+          See <file:Documentation/networking/NAPI_HOWTO.txt> for more
+          information.
+
+          If in doubt, say N.
+
diff --git a/drivers/net/hxge/Makefile b/drivers/net/hxge/Makefile
new file mode 100644 (file)
index 0000000..6bed51d
--- /dev/null
@@ -0,0 +1,18 @@
+# Makefile for the Sun Microsystems 10Gb ethernet driver
+#
+
+#EXTRA_CFLAGS += -DCONFIG_HXGE_NAPI 
+EXTRA_CFLAGS += -DCONFIG_SKB_SHARED -DUSE_PIO 
+
+ifeq ($(ERRINJECT),1)
+EXTRA_CFLAGS += -DCONFIG_ERRINJECT
+endif
+
+
+obj-$(CONFIG_HXGE) += hxge.o
+hxge-objs := hxge_other.o hxge_ethtool.o hxge_main.o hxge_stats.o hxge_vmac.o hxge_param.o hxge_pfc.o hxge_txdma.o hxge_rxdma.o hxge_intr.o 
+ifeq ($(ERRINJECT),1)
+hxge-objs += hxge_sysfs.o
+endif
+hxge-objs += hpi/hpi.o hpi/hpi_rxdma.o hpi/hpi_txdma.o hpi/hpi_pfc.o
+hxge-objs += hpi/hpi_vir.o hpi/hpi_vmac.o
diff --git a/drivers/net/hxge/hpi/hpi.c b/drivers/net/hxge/hpi/hpi.c
new file mode 100644 (file)
index 0000000..6b53a73
--- /dev/null
@@ -0,0 +1,75 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#include "linux/version.h"
+#include "hpi.h"
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+#include <asm/semaphore.h>
+#else
+#include <linux/semaphore.h>
+#endif
+
+DECLARE_MUTEX(hpidebuglock);
+int hpi_debug_init = 0;
+uint64_t hpi_debug_level = 0;
+
+void
+hpi_debug_msg(uint64_t level, char *fmt, ...)
+{
+       char msg_buffer[1024];
+       va_list ap;
+
+       if ((level & hpi_debug_level) ||
+           (level & HPI_REG_CTL) || (level & HPI_ERR_CTL)) {
+
+                va_start(ap, fmt);
+                (void) vsprintf(msg_buffer, fmt, ap);
+                va_end(ap);
+
+               HPI_DEBUG("%s",msg_buffer);
+       }
+}
+
+void
+hpi_rtrace_buf_init(rtrace_t *rt)
+{
+       int i;
+
+       rt->next_idx = 0;
+       rt->last_idx = MAX_RTRACE_ENTRIES - 1;
+       rt->wrapped = FALSE;
+       for (i = 0; i < MAX_RTRACE_ENTRIES; i++) {
+               rt->buf[i].ctl_addr = TRACE_CTL_INVALID;
+               rt->buf[i].val_l32 = 0;
+               rt->buf[i].val_h32 = 0;
+       }
+}
+
+void
+hpi_rtrace_update(boolean_t wr, rtrace_t *rt,
+                   uint32_t addr, uint64_t val)
+{
+}
diff --git a/drivers/net/hxge/hpi/hpi.h b/drivers/net/hxge/hpi/hpi.h
new file mode 100644 (file)
index 0000000..92090b8
--- /dev/null
@@ -0,0 +1,220 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#ifndef _HPI_H
+#define        _HPI_H
+
+#include "../hxge_defs.h"
+
+typedef        uint32_t hpi_status_t;
+typedef void * hpi_handle_t;
+
+/* Common Block ID */
+#define        VMAC_BLK_ID                     0x1
+#define        TXDMA_BLK_ID                    0x2
+#define        RXDMA_BLK_ID                    0x3
+#define        PFC_BLK_ID                      0x4
+#define        VIR_BLK_ID                      0x5
+#define        PEU_BLK_ID                      0x6
+
+/* Common HW error code */
+/* HW unable to exit from reset state. */
+#define        RESET_FAILED                    0x81
+
+/* Write operation failed on indirect write. */
+#define        WRITE_FAILED                    0x82
+/* Read operation failed on indirect read.      */
+#define        READ_FAILED                     0x83
+
+/* Error code boundary */
+
+#define        COMMON_SW_ERR_START             0x40
+#define        COMMON_SW_ERR_END               0x4f
+#define        BLK_SPEC_SW_ERR_START           0x50
+#define        BLK_SPEC_SW_ERR_END             0x7f
+#define        COMMON_HW_ERR_START             0x80
+#define        COMMON_HW_ERR_END               0x8f
+#define        BLK_SPEC_HW_ERR_START           0x90
+#define        BLK_SPEC_HW_ERR_END             0xbf
+
+#define        IS_PORT                         0x00100000
+#define        IS_CHAN                         0x00200000
+
+/* Common SW errors code */
+
+#define        PORT_INVALID                    0x41    /* Invalid port number */
+#define        CHANNEL_INVALID                 0x42    /* Invalid dma channel number */
+#define        OPCODE_INVALID                  0x43    /* Invalid opcode */
+#define        REGISTER_INVALID                0x44    /* Invalid register number */
+#define        COUNTER_INVALID                 0x45    /* Invalid counter number */
+#define        CONFIG_INVALID                  0x46    /* Invalid config input */
+#define        LOGICAL_PAGE_INVALID            0x47    /* Invalid logical page # */
+#define        VLAN_INVALID                    0x48    /* Invalid Vlan ID */
+#define        RDC_TAB_INVALID                 0x49    /* Invalid RDC Group Number */
+#define        LOCATION_INVALID                0x4a    /* Invalid Entry Location */
+
+#define        HPI_SUCCESS                     0               /* Operation succeed */
+#define        HPI_FAILURE                     0x80000000      /* Operation failed */
+
+#define        HPI_CNT_CLR_VAL                 0
+
+/*
+ * Block identifier starts at bit 8.
+ */
+#define        HPI_BLOCK_ID_SHIFT              8
+
+/*
+ * Port, channel and misc. information starts at bit 12.
+ */
+#define        HPI_PORT_CHAN_SHIFT                     12
+
+/*
+ * Software Block specific error codes start at 0x50.
+ */
+#define        HPI_BK_ERROR_START              0x50
+
+/*
+ * Hardware block specific error codes start at 0x90.
+ */
+#define        HPI_BK_HW_ER_START              0x90
+
+/* Structures for register tracing */
+
+typedef struct _rt_buf {
+       uint32_t        ctl_addr;
+       uint32_t        val_l32;
+       uint32_t        val_h32;
+} rt_buf_t;
+
+/*
+ * Control Address field format
+ *
+ * Bit 0 - 23: Address
+ * Bit 24 - 25: Function Number
+ * Bit 26 - 29: Instance Number
+ * Bit 30: Read/Write Direction bit
+ * Bit 31: Invalid bit
+ */
+
+#define        MAX_RTRACE_ENTRIES      1024
+#define        MAX_RTRACE_IOC_ENTRIES  64
+#define        TRACE_ADDR_MASK         0x00FFFFFF
+#define        TRACE_FUNC_MASK         0x03000000
+#define        TRACE_INST_MASK         0x3C000000
+#define        TRACE_CTL_WR            0x40000000
+#define        TRACE_CTL_INVALID       0x80000000
+#define        TRACE_FUNC_SHIFT        24
+#define        TRACE_INST_SHIFT        26
+#define        MSG_BUF_SIZE            1024
+
+
+typedef struct _rtrace {
+       uint16_t        next_idx;
+       uint16_t        last_idx;
+       boolean_t       wrapped;
+       rt_buf_t        buf[MAX_RTRACE_ENTRIES];
+} rtrace_t;
+
+typedef struct _err_inject {
+       uint8_t         blk_id;
+       uint8_t         chan;
+       uint32_t        err_id;
+       uint32_t        control;
+} err_inject_t;
+
+/* Configuration options */
+typedef enum config_op {
+       DISABLE = 0,
+       ENABLE,
+       INIT
+} config_op_t;
+
+/* I/O options */
+typedef enum io_op {
+       OP_SET = 0,
+       OP_GET,
+       OP_UPDATE,
+       OP_CLEAR
+} io_op_t;
+
+/* Counter options */
+typedef enum counter_op {
+       SNAP_STICKY = 0,
+       SNAP_ACCUMULATE,
+       CLEAR
+} counter_op_t;
+
+/* HPI attribute */
+typedef struct _hpi_attr_t {
+       uint32_t type;
+       uint32_t idata[16];
+       uint32_t odata[16];
+} hpi_attr_t;
+
+/* HPI Counter */
+typedef struct _hpi_counter_t {
+       uint32_t id;
+       char *name;
+       uint32_t val;
+} hpi_counter_t;
+
+/*
+ * Commmon definitions for HPI RXDMA and TXDMA functions.
+ */
+typedef struct _dma_log_page {
+       uint8_t                 page_num;
+       boolean_t               valid;
+       uint8_t                 func_num;
+       uint64_t                mask;
+       uint64_t                value;
+       uint64_t                reloc;
+} dma_log_page_t, *p_dma_log_page_t;
+
+extern rtrace_t hpi_rtracebuf;
+void hpi_rtrace_buf_init(rtrace_t *rt);
+void hpi_rtrace_update(boolean_t wr, rtrace_t *rt,
+                       uint32_t addr, uint64_t val);
+void hpi_rtrace_buf_init(rtrace_t *rt);
+
+void hpi_debug_msg(uint64_t level, char *fmt, ...);
+
+#ifdef DBG     
+#define        HPI_DEBUG_MSG(params) hpi_debug_msg params
+#else
+#define        HPI_DEBUG_MSG(params)
+#endif
+
+#define        HPI_ERROR_MSG(params) hpi_debug_msg params
+#define        HPI_REG_DUMP_MSG(params) hpi_debug_msg params
+
+#ifdef DBG
+#define HPI_DEBUG(args...) printk(KERN_DEBUG "hpi: " __FUNCTION__ , ##args)
+#else
+#define HPI_DEBUG(args...)
+#endif
+
+#define HPI_ERR(args...) printk(KERN_ERR "hpi: " __FUNCTION__ , ##args)
+
+#endif /* _HPI_H */
diff --git a/drivers/net/hxge/hpi/hpi_pfc.c b/drivers/net/hxge/hpi/hpi_pfc.c
new file mode 100644 (file)
index 0000000..ed7bcc6
--- /dev/null
@@ -0,0 +1,873 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include "hpi_vir.h"
+#include "hpi_pfc.h"
+
+#define        TCAM_COMPLETION_TRY_COUNT       10
+
+uint64_t pfc_reg_offset[] = {
+       PFC_VLAN_TABLE, PFC_VLAN_CTRL,
+       PFC_MAC_ADDR, PFC_MAC_ADDR_MASK,
+       PFC_HASH_TABLE,
+       PFC_L2_CLASS_CONFIG, PFC_L3_CLASS_CONFIG,
+       PFC_TCAM_KEY0, PFC_TCAM_KEY1, PFC_TCAM_MASK0, PFC_TCAM_MASK1,
+       PFC_TCAM_CTRL,
+       PFC_CONFIG, TCP_CTRL_MASK, SRC_HASH_VAL,
+       PFC_INT_STATUS, PFC_DBG_INT_STATUS, PFC_INT_MASK,
+       PFC_DROP_LOG, PFC_DROP_LOG_MASK,
+       PFC_VLAN_PAR_ERR_LOG, PFC_TCAM_PAR_ERR_LOG,
+       PFC_BAD_CS_COUNTER, PFC_DROP_COUNTER, PFC_AUTO_INIT
+};
+
+const char *pfc_reg_name[] = {
+       "PFC_VLAN_TABLE", "PFC_VLAN_CTRL",
+       "PFC_MAC_ADDR", "PFC_MAC_ADDR_MASK",
+       "PFC_HASH_TABLE",
+       "PFC_L2_CLASS_CONFIG", "PFC_L3_CLASS_CONFIG",
+       "PFC_TCAM_KEY0", "PFC_TCAM_KEY1", "PFC_TCAM_MASK0", "PFC_TCAM_MASK1",
+       "PFC_TCAM_CTRL",
+       "PFC_CONFIG", "TCP_CTRL_MASK", "SRC_HASH_VAL",
+       "PFC_INT_STATUS", "PFC_DBG_INT_STATUS", "PFC_INT_MASK",
+       "PFC_DROP_LOG", "PFC_DROP_LOG_MASK",
+       "PFC_VLAN_PAR_ERR_LOG", "PFC_TCAM_PAR_ERR_LOG",
+       "PFC_BAD_CS_COUNTER", "PFC_DROP_COUNTER", "PFC_AUTO_INIT"
+};
+
+hpi_status_t
+hpi_pfc_dump_regs(hpi_handle_t handle)
+{
+       uint64_t        value;
+       int             num_regs, i;
+
+       num_regs = sizeof (pfc_reg_offset) / sizeof (uint64_t);
+       HPI_REG_DUMP_MSG(( HPI_REG_CTL,
+               "\nPFC Register Dump \n"));
+
+       for (i = 0; i < num_regs; i++) {
+               REG_PIO_READ64(handle, pfc_reg_offset[i], &value);
+               HPI_REG_DUMP_MSG(( HPI_REG_CTL,
+                       " %08llx %s\t %016llx \n",
+                       pfc_reg_offset[i], pfc_reg_name[i], value));
+       }
+
+       HPI_REG_DUMP_MSG(( HPI_REG_CTL,
+           "\n PFC Register Dump done\n"));
+
+       return (HPI_SUCCESS);
+}
+
+static uint64_t
+hpi_pfc_tcam_check_completion(hpi_handle_t handle, tcam_op_t op_type)
+{
+       uint32_t try_counter, tcam_delay = 10;
+       pfc_tcam_ctrl_t tctl;
+
+       try_counter = TCAM_COMPLETION_TRY_COUNT;
+
+       switch (op_type) {
+       case TCAM_RWC_STAT:
+               READ_TCAM_REG_CTL(handle, &tctl.value);
+               while ((try_counter) &&
+                   (tctl.bits.status != TCAM_CTL_RWC_RWC_STAT)) {
+                       try_counter--;
+                       HXGE_DELAY(tcam_delay);
+                       READ_TCAM_REG_CTL(handle, &tctl.value);
+               }
+
+               if (!try_counter) {
+                       HPI_ERROR_MSG(( HPI_ERR_CTL,
+                           " TCAM RWC_STAT operation"
+                           " failed to complete \n"));
+                       return (HPI_PFC_TCAM_HW_ERROR);
+               }
+
+               tctl.value = 0;
+               break;
+       case TCAM_RWC_MATCH:
+               READ_TCAM_REG_CTL(handle, &tctl.value);
+
+               while ((try_counter) &&
+                   (tctl.bits.match != TCAM_CTL_RWC_RWC_MATCH)) {
+                       try_counter--;
+                       HXGE_DELAY(tcam_delay);
+                       READ_TCAM_REG_CTL(handle, &tctl.value);
+               }
+
+               if (!try_counter) {
+                       HPI_ERROR_MSG(( HPI_ERR_CTL,
+                           " TCAM Match operationfailed to find match \n"));
+               }
+
+               break;
+       default:
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " Invalid TCAM completion Request \n"));
+               return (HPI_PFC_ERROR | HPI_TCAM_ERROR | OPCODE_INVALID);
+       }
+
+       return (tctl.value);
+}
+
+hpi_status_t
+hpi_pfc_tcam_entry_read(hpi_handle_t handle, uint32_t location,
+    hxge_tcam_entry_t *tcam_ptr)
+{
+       pfc_tcam_ctrl_t tctl;
+       pfc_tcam_ctrl_t tctl_rv;
+
+       /*
+        * Hydra doesn't allow to read TCAM entries. Use compare instead.
+        */
+       WRITE_TCAM_REG_MASK0(handle, tcam_ptr->mask0);
+       WRITE_TCAM_REG_MASK1(handle, tcam_ptr->mask1);
+
+       WRITE_TCAM_REG_KEY0(handle, tcam_ptr->key0);
+       WRITE_TCAM_REG_KEY1(handle, tcam_ptr->key1);
+
+       tctl.value = 0;
+       tctl.bits.addr = location;
+       tctl.bits.cmd = TCAM_CTL_RWC_TCAM_CMP;
+
+       WRITE_TCAM_REG_CTL(handle, tctl.value);
+
+       tctl_rv.value = hpi_pfc_tcam_check_completion(handle, TCAM_RWC_MATCH);
+
+       if (tctl_rv.bits.match)
+               return (HPI_SUCCESS);
+       else
+               return (HPI_FAILURE);
+}
+
+hpi_status_t
+hpi_pfc_tcam_asc_ram_entry_write(hpi_handle_t handle, uint32_t location,
+    uint64_t ram_data)
+{
+       uint64_t tcam_stat = 0;
+       pfc_tcam_ctrl_t tctl;
+
+       WRITE_TCAM_REG_KEY0(handle, ram_data);
+
+       tctl.value = 0;
+       tctl.bits.addr = location;
+       tctl.bits.cmd = TCAM_CTL_RWC_RAM_WR;
+
+       HPI_DEBUG_MSG(( HPI_PFC_CTL,
+           " tcam ascr write: location %x data %llx ctl value %llx \n",
+           location, ram_data, tctl.value));
+       WRITE_TCAM_REG_CTL(handle, tctl.value);
+       tcam_stat = hpi_pfc_tcam_check_completion(handle, TCAM_RWC_STAT);
+
+       if (tcam_stat & HPI_FAILURE) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   "TCAM RAM write failed loc %d \n", location));
+               return (HPI_PFC_ASC_RAM_WR_ERROR);
+       }
+
+       return (HPI_SUCCESS);
+}
+
+static hpi_status_t
+hpi_pfc_set_config(hpi_handle_t handle, pfc_config_t config)
+{
+       uint64_t offset;
+
+       offset = PFC_CONFIG;
+       REG_PIO_WRITE64(handle, offset, config.value);
+
+       return (HPI_SUCCESS);
+}
+
+static hpi_status_t
+hpi_pfc_get_config(hpi_handle_t handle, pfc_config_t *configp)
+{
+       uint64_t offset;
+
+       offset = PFC_CONFIG;
+       REG_PIO_READ64(handle, offset, &configp->value);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_set_tcam_enable(hpi_handle_t handle, boolean_t tcam)
+{
+       pfc_config_t    config;
+
+       /*
+        * Read the register first.
+        */
+       (void) hpi_pfc_get_config(handle, &config);
+
+       if (tcam)
+               config.bits.tcam_en = 1;
+       else
+               config.bits.tcam_en = 0;
+
+       return (hpi_pfc_set_config(handle, config));
+}
+
+hpi_status_t
+hpi_pfc_set_l2_hash(hpi_handle_t handle, boolean_t l2_hash)
+{
+       pfc_config_t    config;
+
+       /*
+        * Read the register first.
+        */
+       (void) hpi_pfc_get_config(handle, &config);
+
+       if (l2_hash)
+               config.bits.l2_hash_en = 1;
+       else
+               config.bits.l2_hash_en = 0;
+
+       return (hpi_pfc_set_config(handle, config));
+}
+
+hpi_status_t
+hpi_pfc_set_tcp_cksum(hpi_handle_t handle, boolean_t cksum)
+{
+       pfc_config_t    config;
+
+       /*
+        * Read the register first.
+        */
+       (void) hpi_pfc_get_config(handle, &config);
+
+       if (cksum)
+               config.bits.tcp_cs_en = 1;
+       else
+               config.bits.tcp_cs_en = 0;
+
+       return (hpi_pfc_set_config(handle, config));
+}
+
+hpi_status_t
+hpi_pfc_set_default_dma(hpi_handle_t handle, uint32_t dma_channel_no)
+{
+       pfc_config_t    config;
+
+       (void) hpi_pfc_get_config(handle, &config);
+
+       if (dma_channel_no > PFC_MAX_DMA_CHANNELS)
+               return (HPI_FAILURE);
+
+       config.bits.default_dma = dma_channel_no;
+
+       return (hpi_pfc_set_config(handle, config));
+}
+
+hpi_status_t
+hpi_pfc_mac_addr_enable(hpi_handle_t handle, uint32_t slot)
+{
+       pfc_config_t    config;
+       uint32_t        bit;
+
+       if (slot >= PFC_N_MAC_ADDRESSES) {
+               return (HPI_FAILURE);
+       }
+
+       (void) hpi_pfc_get_config(handle, &config);
+
+       bit = 1 << slot;
+       config.bits.mac_addr_en = config.bits.mac_addr_en | bit;
+
+       return (hpi_pfc_set_config(handle, config));
+}
+
+hpi_status_t
+hpi_pfc_mac_addr_disable(hpi_handle_t handle, uint32_t slot)
+{
+       pfc_config_t    config;
+       uint32_t        bit;
+
+       if (slot >= PFC_N_MAC_ADDRESSES) {
+               return (HPI_FAILURE);
+       }
+
+       (void) hpi_pfc_get_config(handle, &config);
+
+       bit = 1 << slot;
+       config.bits.mac_addr_en = config.bits.mac_addr_en & ~bit;
+
+       return (hpi_pfc_set_config(handle, config));
+}
+
+hpi_status_t
+hpi_pfc_set_force_csum(hpi_handle_t handle, boolean_t force)
+{
+       pfc_config_t    config;
+
+       (void) hpi_pfc_get_config(handle, &config);
+
+       if (force)
+               config.bits.force_cs_en = 1;
+       else
+               config.bits.force_cs_en = 0;
+
+       return (hpi_pfc_set_config(handle, config));
+}
+
+hpi_status_t
+hpi_pfc_cfg_vlan_table_dump(hpi_handle_t handle)
+{
+       int                     i;
+       int                     offset;
+       int                     step = 8;
+       pfc_vlan_table_t        table_entry;
+
+       printk(KERN_DEBUG "Vlan table dump\n");
+       for (i = 0; i < 128; i++) {
+               table_entry.value = 0;
+               offset = PFC_VLAN_TABLE + i * step;
+               REG_PIO_READ64(handle, offset, &table_entry.value);
+
+               printk(KERN_DEBUG "%08x ", (unsigned int)table_entry.bits.member);
+               if ((i % 8) == 0)
+                       printk(KERN_DEBUG "\n");
+       }
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_cfg_vlan_table_clear(hpi_handle_t handle)
+{
+       int                     i;
+       int                     offset;
+       int                     step = 8;
+       pfc_vlan_table_t        table_entry;
+
+       table_entry.value = 0;
+       for (i = 0; i < 128; i++) {
+               table_entry.bits.member = 0;
+               offset = PFC_VLAN_TABLE + i * step;
+               REG_PIO_WRITE64(handle, offset, table_entry.value);
+       }
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_cfg_vlan_table_entry_clear(hpi_handle_t handle, vlan_id_t vlan_id)
+{
+       uint64_t offset;
+       pfc_vlan_table_t  vlan_tbl_entry;
+       uint64_t bit;
+
+       /*
+        * Assumes that the hardware will generate the new parity
+        * data.
+        */
+       offset = PFC_VLAN_REG_OFFSET(vlan_id);
+       REG_PIO_READ64(handle, offset, (uint64_t *)&vlan_tbl_entry.value);
+
+       bit = PFC_VLAN_BIT_OFFSET(vlan_id);
+       bit = 1 << bit;
+       vlan_tbl_entry.bits.member = vlan_tbl_entry.bits.member & ~bit;
+
+       REG_PIO_WRITE64(handle, offset, vlan_tbl_entry.value);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_cfg_vlan_table_entry_set(hpi_handle_t handle, vlan_id_t vlan_id)
+{
+       uint64_t                offset;
+       pfc_vlan_table_t        vlan_tbl_entry;
+       uint64_t                bit;
+
+       /*
+        * Assumes that the hardware will generate the new parity
+        * data.
+        */
+       offset = PFC_VLAN_REG_OFFSET(vlan_id);
+       REG_PIO_READ64(handle, offset, (uint64_t *)&vlan_tbl_entry.value);
+
+       bit = PFC_VLAN_BIT_OFFSET(vlan_id);
+       bit = 1 << bit;
+       vlan_tbl_entry.bits.member = vlan_tbl_entry.bits.member | bit;
+
+       REG_PIO_WRITE64(handle, offset, vlan_tbl_entry.value);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_cfg_vlan_control_set(hpi_handle_t handle, boolean_t parity,
+       boolean_t valid, vlan_id_t vlan_id)
+{
+       pfc_vlan_ctrl_t vlan_control;
+
+       vlan_control.value = 0;
+
+       if (parity)
+               vlan_control.bits.par_en = 1;
+       else
+               vlan_control.bits.par_en = 0;
+
+       if (valid)
+               vlan_control.bits.valid = 1;
+       else
+               vlan_control.bits.valid = 0;
+
+       vlan_control.bits.id = vlan_id;
+
+       REG_PIO_WRITE64(handle, PFC_VLAN_CTRL, vlan_control.value);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_get_vlan_parity_log(hpi_handle_t handle, pfc_vlan_par_err_log_t *logp)
+{
+       uint64_t offset;
+
+       offset = PFC_VLAN_PAR_ERR_LOG;
+       REG_PIO_READ64(handle, offset, &logp->value);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_set_mac_address(hpi_handle_t handle, uint32_t slot, uint64_t address)
+{
+       uint64_t offset;
+       uint64_t moffset;
+       pfc_mac_addr_mask_t mask;
+       pfc_mac_addr_t addr;
+
+       if (slot >= PFC_N_MAC_ADDRESSES)
+               return (HPI_FAILURE);
+
+       offset = PFC_MAC_ADDRESS(slot);
+       moffset = PFC_MAC_ADDRESS_MASK(slot);
+
+       addr.bits.addr = address;
+       mask.bits.mask = 0x0;
+
+       REG_PIO_WRITE64(handle, offset, addr.value);
+       REG_PIO_WRITE64(handle, moffset, mask.value);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_get_mac_address(hpi_handle_t handle, int slot, uint8_t *data)
+{
+       pfc_mac_addr_t addr;
+       uint64_t offset;
+
+        if (slot >= PFC_N_MAC_ADDRESSES)
+                return (HPI_FAILURE);
+
+        offset = PFC_MAC_ADDRESS(slot);
+       REG_PIO_READ64(handle, offset,  &addr.value);
+
+       data[0] = addr.byte[5];
+       data[1] = addr.byte[4];
+       data[2] = addr.byte[3];
+       data[3] = addr.byte[2];
+       data[4] = addr.byte[1];
+       data[5] = addr.byte[0];
+       
+       return HPI_SUCCESS;
+}
+
+
+hpi_status_t
+hpi_pfc_clear_mac_address(hpi_handle_t handle, uint32_t slot)
+{
+       uint64_t offset, moffset;
+       uint64_t zaddr = 0x0ULL;
+       uint64_t zmask = 0x0ULL;
+
+       if (slot >= PFC_N_MAC_ADDRESSES)
+               return (HPI_FAILURE);
+
+       (void) hpi_pfc_mac_addr_disable(handle, slot);
+
+       offset = PFC_MAC_ADDRESS(slot);
+       moffset = PFC_MAC_ADDRESS_MASK(slot);
+
+       REG_PIO_WRITE64(handle, offset, zaddr);
+       REG_PIO_WRITE64(handle, moffset, zmask);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_clear_multicast_hash_table(hpi_handle_t handle, uint32_t slot)
+{
+       uint64_t offset;
+
+       offset = PFC_HASH_ADDR(slot);
+       REG_PIO_WRITE64(handle, offset, 0ULL);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_set_multicast_hash_table(hpi_handle_t handle, uint32_t slot,
+       uint64_t address)
+{
+       uint64_t offset;
+
+       offset = PFC_HASH_ADDR(slot);
+       REG_PIO_WRITE64(handle, offset, address);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_set_l2_class_slot(hpi_handle_t handle, uint16_t etype, boolean_t valid,
+       int slot)
+{
+       pfc_l2_class_config_t   l2_config;
+       uint64_t                offset;
+
+       l2_config.value = 0;
+
+       if (valid)
+               l2_config.bits.valid = 1;
+       else
+               l2_config.bits.valid = 0;
+
+       l2_config.bits.etype = etype;
+       l2_config.bits.rsrvd = 0;
+
+       offset = PFC_L2_CONFIG(slot);
+       REG_PIO_WRITE64(handle, offset, l2_config.value);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_set_l3_class_config(hpi_handle_t handle, tcam_class_t slot,
+       tcam_key_cfg_t cfg)
+{
+       pfc_l3_class_config_t   l3_config;
+       uint64_t                offset;
+
+       l3_config.value = 0;
+
+       if (cfg.lookup_enable)
+               l3_config.bits.tsel = 1;
+       else
+               l3_config.bits.tsel = 0;
+
+       if (cfg.discard)
+               l3_config.bits.discard = 1;
+       else
+               l3_config.bits.discard = 0;
+
+       offset = PFC_L3_CONFIG(slot);
+       REG_PIO_WRITE64(handle, offset, l3_config.value);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_get_l3_class_config(hpi_handle_t handle, tcam_class_t slot,
+    tcam_key_cfg_t *cfg)
+{
+       pfc_l3_class_config_t   l3_config;
+       uint64_t                offset;
+
+       offset = PFC_L3_CONFIG(slot);
+       REG_PIO_READ64(handle, offset, &l3_config.value);
+
+       if (l3_config.bits.tsel)
+               cfg->lookup_enable = 1;
+       else
+               cfg->lookup_enable = 0;
+
+       if (l3_config.bits.discard)
+               cfg->discard = 1;
+       else
+               cfg->discard = 0;
+
+       return (HPI_SUCCESS);
+}
+
+static hpi_status_t
+hpi_pfc_set_tcam_control(hpi_handle_t handle, pfc_tcam_ctrl_t *tcontrolp)
+{
+       uint64_t offset;
+
+       offset = PFC_TCAM_CTRL;
+       REG_PIO_WRITE64(handle, offset, tcontrolp->value);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_tcam_entry_invalidate(hpi_handle_t handle, uint32_t location)
+{
+       hxge_tcam_entry_t       tcam_ptr;
+
+       memset(&tcam_ptr, 0, sizeof (hxge_tcam_entry_t));
+       hpi_pfc_tcam_entry_write(handle, location, &tcam_ptr);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_tcam_invalidate_all(hpi_handle_t handle)
+{
+       int             i;
+       pfc_tcam_ctrl_t tcontrol;
+
+       tcontrol.value = 0;
+       for (i = 0; i < PFC_N_TCAM_ENTRIES; i++) {
+               (void) hpi_pfc_set_tcam_control(handle, &tcontrol);
+               (void) hpi_pfc_tcam_entry_invalidate(handle, i);
+       }
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_tcam_entry_write(hpi_handle_t handle, uint32_t location,
+       hxge_tcam_entry_t *tcam_ptr)
+{
+       uint64_t        tcam_stat;
+       pfc_tcam_ctrl_t tctl;
+
+       WRITE_TCAM_REG_MASK0(handle, tcam_ptr->mask0);
+       WRITE_TCAM_REG_MASK1(handle, tcam_ptr->mask1);
+
+       WRITE_TCAM_REG_KEY0(handle, tcam_ptr->key0);
+       WRITE_TCAM_REG_KEY1(handle, tcam_ptr->key1);
+
+       HPI_DEBUG_MSG(( HPI_PFC_CTL,
+           " tcam write: location %x\n key:  %llx %llx\n mask: %llx %llx\n",
+           location, tcam_ptr->key0, tcam_ptr->key1,
+           tcam_ptr->mask0, tcam_ptr->mask1));
+
+       tctl.value = 0;
+       tctl.bits.addr = location;
+       tctl.bits.cmd = TCAM_CTL_RWC_TCAM_WR;
+
+       HPI_DEBUG_MSG(( HPI_PFC_CTL,
+           " tcam write: ctl value %llx \n", tctl.value));
+
+       WRITE_TCAM_REG_CTL(handle, tctl.value);
+
+       tcam_stat = hpi_pfc_tcam_check_completion(handle, TCAM_RWC_STAT);
+
+       if (tcam_stat & HPI_FAILURE) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   "TCAM Write failed loc %d \n", location));
+               return (HPI_PFC_TCAM_WR_ERROR);
+       }
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_get_tcam_parity_log(hpi_handle_t handle, pfc_tcam_par_err_log_t *logp)
+{
+       uint64_t offset;
+
+       offset = PFC_TCAM_PAR_ERR_LOG;
+       REG_PIO_READ64(handle, offset, &logp->value);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_set_hash_seed_value(hpi_handle_t handle, uint32_t seed)
+{
+       uint64_t        offset;
+       src_hash_val_t  src_hash_seed;
+
+       src_hash_seed.value = 0;
+       src_hash_seed.bits.seed = seed;
+
+       offset = SRC_HASH_VAL;
+       REG_PIO_WRITE64(handle, offset, src_hash_seed.value);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_get_interrupt_status(hpi_handle_t handle, pfc_int_status_t *statusp)
+{
+       uint64_t offset;
+
+       offset = PFC_INT_STATUS;
+       REG_PIO_READ64(handle, offset, &statusp->value);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_clear_interrupt_status(hpi_handle_t handle)
+{
+       uint64_t offset;
+       uint64_t value = ~0ULL; /* force a match to occur */
+
+       offset = PFC_INT_STATUS;
+       REG_PIO_WRITE64(handle, offset, value);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_set_interrupt_mask(hpi_handle_t handle, boolean_t drop,
+       boolean_t tcam_parity_error, boolean_t vlan_parity_error)
+{
+       pfc_int_mask_t  mask;
+       uint64_t        offset;
+
+       mask.value = 0;
+
+       if (drop)
+               mask.bits.pkt_drop_mask = 1;
+       else
+               mask.bits.pkt_drop_mask = 0;
+
+       if (tcam_parity_error)
+               mask.bits.tcam_parity_err_mask = 1;
+       else
+               mask.bits.tcam_parity_err_mask = 0;
+
+       if (vlan_parity_error)
+               mask.bits.vlan_parity_err_mask = 1;
+       else
+               mask.bits.vlan_parity_err_mask = 0;
+
+       offset = PFC_INT_MASK;
+       REG_PIO_WRITE64(handle, offset, mask.value);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_get_drop_log(hpi_handle_t handle, pfc_drop_log_t *logp)
+{
+       uint64_t offset;
+
+       offset = PFC_DROP_LOG;
+       REG_PIO_READ64(handle, offset, &logp->value);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_set_drop_log_mask(hpi_handle_t handle, boolean_t vlan_drop,
+       boolean_t tcam_drop, boolean_t class_code_drop, boolean_t l2_addr_drop,
+       boolean_t tcp_ctrl_drop)
+{
+       uint64_t                offset;
+       pfc_drop_log_mask_t     log;
+
+       log.value = 0;
+
+       if (vlan_drop)
+               log.bits.vlan_drop_mask = 1;
+       if (tcam_drop)
+               log.bits.tcam_drop_mask = 1;
+       if (class_code_drop)
+               log.bits.class_code_drop_mask = 1;
+       if (l2_addr_drop)
+               log.bits.l2_addr_drop_mask = 1;
+       if (tcp_ctrl_drop)
+               log.bits.tcp_ctrl_drop_mask = 1;
+
+       offset = PFC_DROP_LOG_MASK;
+       REG_PIO_WRITE64(handle, offset, log.value);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_get_bad_csum_counter(hpi_handle_t handle, uint64_t *countp)
+{
+       uint64_t offset;
+
+       offset = PFC_BAD_CS_COUNTER;
+       REG_PIO_READ64(handle, offset, countp);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_pfc_get_drop_counter(hpi_handle_t handle, uint64_t *countp)
+{
+       uint64_t offset;
+
+       offset = PFC_DROP_COUNTER;
+       REG_PIO_READ64(handle, offset, countp);
+
+       return (HPI_SUCCESS);
+}
+
+/* This routine reads the MAC address from the SPROM programmed HCR
+ * region. This routine is used as part of programming the MAC addresses
+ * into the PFC for use
+ */
+hpi_status_t
+hpi_hcr_mac_addr_get(hpi_handle_t handle, int index, uint8_t *data)
+{
+       uint64_t step = sizeof (uint64_t);
+       uint32_t addr_hi = 0, addr_lo = 0;
+       peu_debug_training_vec_t blade;
+       uint32_t mac_offset;
+
+       HXGE_REG_RD32(handle, PEU_DEBUG_TRAINING_VEC, &blade.value);
+
+       printk(KERN_DEBUG "hpi_hcr_mac_addr_get: Blade ID %d\n", blade.bits.bld_num_upper);
+       if (!blade.bits.bld_num_upper) { /* for blade ID zero */
+               mac_offset = 0x8; /* CR 6687755 blade/port 0 is different */
+       } else {
+               mac_offset = 0xC;
+       }
+               
+       /*
+        * Read the static MAC address out of the HCR.  Note: these HCR
+       * MAC address(es) are initialized by NEM/SP from SPROM.
+        */
+       HXGE_REG_RD32(handle, HCR_REG + mac_offset   + index * step, &addr_lo);
+       HXGE_REG_RD32(handle, HCR_REG + mac_offset+4 + index * step, &addr_hi);
+
+       /* Note that the MAC address in the SPROM is stored in big-endian 
+        * format. So, do the transformation to little-endian for PFC 
+        * and driver 
+        */
+       data[0] = (addr_hi & 0x000000ff);
+       data[1] = (addr_hi & 0x0000ff00) >> 8;
+       data[2] = (addr_lo & 0xff000000) >> 24;
+       data[3] = (addr_lo & 0x00ff0000) >> 16;
+       data[4] = (addr_lo & 0x0000ff00) >> 8;
+       data[5] = addr_lo & 0x000000ff;
+
+       return (HPI_SUCCESS);  
+}
diff --git a/drivers/net/hxge/hpi/hpi_pfc.h b/drivers/net/hxge/hpi/hpi_pfc.h
new file mode 100644 (file)
index 0000000..2fe3638
--- /dev/null
@@ -0,0 +1,208 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#ifndef _HPI_PFC_H
+#define        _HPI_PFC_H
+
+#include "hpi.h"
+#include "../hxge_pfc_hw.h"
+#include "../hxge_pfc.h"
+
+typedef enum _tcam_op {
+       TCAM_RWC_STAT   = 0x1,
+       TCAM_RWC_MATCH  = 0x2
+} tcam_op_t;
+
+#define        HPI_TCAM_COMP_NO_MATCH  0x8000000000000ULL
+
+/*
+ * HPI PFC ERROR Codes
+ */
+#define        HPI_PFC_BLK_CODE        PFC_BLK_ID << 8
+#define        HPI_PFC_ERROR           (HPI_FAILURE | HPI_PFC_BLK_CODE)
+#define        HPI_TCAM_ERROR          0x10
+#define        HPI_FCRAM_ERROR         0x20
+#define        HPI_GEN_PFC             0x30
+#define        HPI_PFC_SW_PARAM_ERROR  0x40
+#define        HPI_PFC_HW_ERROR        0x80
+
+#define        HPI_PFC_RESET_ERROR     (HPI_PFC_ERROR | HPI_GEN_PFC | RESET_FAILED)
+#define        HPI_PFC_RDC_TABLE_INVALID       (HPI_PFC_ERROR | RDC_TAB_INVALID)
+#define        HPI_PFC_VLAN_INVALID            (HPI_PFC_ERROR | VLAN_INVALID)
+#define        HPI_PFC_PORT_INVALID            (HPI_PFC_ERROR | PORT_INVALID)
+#define        HPI_PFC_TCAM_RD_ERROR           \
+       (HPI_PFC_ERROR | HPI_TCAM_ERROR | READ_FAILED)
+#define        HPI_PFC_TCAM_WR_ERROR           \
+       (HPI_PFC_ERROR | HPI_TCAM_ERROR | WRITE_FAILED)
+#define        HPI_PFC_TCAM_LOC_INVALID        \
+       (HPI_PFC_ERROR | HPI_TCAM_ERROR | LOCATION_INVALID)
+#define        HPI_PFC_ASC_RAM_RD_ERROR        \
+       (HPI_PFC_ERROR | HPI_TCAM_ERROR | READ_FAILED)
+#define        HPI_PFC_ASC_RAM_WR_ERROR        \
+       (HPI_PFC_ERROR | HPI_TCAM_ERROR | WRITE_FAILED)
+#define        HPI_PFC_FCRAM_READ_ERROR        \
+       (HPI_PFC_ERROR | HPI_FCRAM_ERROR | READ_FAILED)
+#define        HPI_PFC_FCRAM_WR_ERROR          \
+       (HPI_PFC_ERROR | HPI_FCRAM_ERROR | WRITE_FAILED)
+#define        HPI_PFC_FCRAM_PART_INVALID      \
+       (HPI_PFC_ERROR | HPI_FCRAM_ERROR | RDC_TAB_INVALID)
+#define        HPI_PFC_FCRAM_LOC_INVALID       \
+       (HPI_PFC_ERROR | HPI_FCRAM_ERROR | LOCATION_INVALID)
+
+#define        TCAM_CLASS_INVALID              \
+       (HPI_PFC_SW_PARAM_ERROR | 0xb)
+/* have only 0xc, 0xd, 0xe and 0xf left for sw error codes */
+#define        HPI_PFC_TCAM_CLASS_INVALID      \
+       (HPI_PFC_ERROR | HPI_TCAM_ERROR | TCAM_CLASS_INVALID)
+#define        HPI_PFC_TCAM_HW_ERROR           \
+       (HPI_PFC_ERROR | HPI_PFC_HW_ERROR | HPI_TCAM_ERROR)
+#define        HPI_PFC_FCRAM_HW_ERROR          \
+       (HPI_PFC_ERROR | HPI_PFC_HW_ERROR | HPI_FCRAM_ERROR)
+
+#define        PFC_N_VLAN_REGISTERS            0x80
+#define        PFC_N_VLAN_MEMBERS              0x20
+
+#define        PFC_N_MAC_ADDRESSES             16
+#define        PFC_MAX_DMA_CHANNELS            4
+#define        PFC_MAC_ADDR_STEP               8
+
+#define        PFC_HASH_TABLE_SIZE             16
+#define        PFC_HASH_STEP                   0x08
+
+#define        PFC_L2_CLASS_CONFIG_STEP        0x08
+
+#define        PFC_L3_CLASS_SLOTS              0x08
+#define        PFC_L3_CLASS_CONFIG_STEP        0x08
+
+#define        PFC_N_TCAM_ENTRIES              42
+
+#define        PFC_VLAN_REG_OFFSET(vlan_id) \
+       ((((vlan_id_t)(vlan_id / PFC_N_VLAN_MEMBERS)) * 8) + PFC_VLAN_TABLE)
+#define        PFC_VLAN_BIT_OFFSET(vlan_id) \
+       (vlan_id % PFC_N_VLAN_MEMBERS)
+#define        PFC_MAC_ADDRESS(slot) \
+       ((slot * PFC_MAC_ADDR_STEP) + PFC_MAC_ADDR)
+#define        PFC_MAC_ADDRESS_MASK(slot) \
+       ((slot * PFC_MAC_ADDR_STEP) + PFC_MAC_ADDR_MASK)
+#define        PFC_HASH_ADDR(slot) \
+       ((slot * PFC_HASH_STEP) + PFC_HASH_TABLE)
+
+#define        PFC_L2_CONFIG(slot) \
+       ((slot * PFC_L2_CLASS_CONFIG_STEP) + PFC_L2_CLASS_CONFIG)
+#define        PFC_L3_CONFIG(slot) \
+       (((slot - TCAM_CLASS_TCP_IPV4) * PFC_L3_CLASS_CONFIG_STEP) + \
+       PFC_L3_CLASS_CONFIG)
+
+typedef uint16_t vlan_id_t;
+
+hpi_status_t hpi_pfc_dump_regs(hpi_handle_t handle);
+
+/*
+ * PFC Control Register Functions
+ */
+hpi_status_t hpi_pfc_set_tcam_enable(hpi_handle_t, boolean_t);
+hpi_status_t hpi_pfc_set_l2_hash(hpi_handle_t, boolean_t);
+hpi_status_t hpi_pfc_set_tcp_cksum(hpi_handle_t, boolean_t);
+hpi_status_t hpi_pfc_set_default_dma(hpi_handle_t, uint32_t);
+hpi_status_t hpi_pfc_mac_addr_enable(hpi_handle_t, uint32_t);
+hpi_status_t hpi_pfc_mac_addr_disable(hpi_handle_t, uint32_t);
+hpi_status_t hpi_pfc_set_force_csum(hpi_handle_t, boolean_t);
+
+/*
+ * PFC vlan Functions
+ */
+hpi_status_t hpi_pfc_cfg_vlan_table_dump(hpi_handle_t handle);
+hpi_status_t hpi_pfc_cfg_vlan_table_clear(hpi_handle_t);
+hpi_status_t hpi_pfc_cfg_vlan_table_entry_clear(hpi_handle_t, vlan_id_t);
+hpi_status_t hpi_pfc_cfg_vlan_table_entry_set(hpi_handle_t, vlan_id_t);
+hpi_status_t hpi_pfc_cfg_vlan_control_set(hpi_handle_t, boolean_t,
+       boolean_t, vlan_id_t);
+hpi_status_t   hpi_pfc_get_vlan_parity_log(hpi_handle_t,
+       pfc_vlan_par_err_log_t *);
+
+/*
+ * PFC Mac Address Functions
+ */
+hpi_status_t hpi_pfc_set_mac_address(hpi_handle_t, uint32_t, uint64_t);
+hpi_status_t hpi_pfc_clear_mac_address(hpi_handle_t, uint32_t);
+hpi_status_t hpi_pfc_clear_multicast_hash_table(hpi_handle_t, uint32_t);
+hpi_status_t hpi_pfc_set_multicast_hash_table(hpi_handle_t, uint32_t,
+       uint64_t);
+
+/*
+ * PFC L2 and L3 Config Functions.
+ */
+hpi_status_t hpi_pfc_set_l2_class_slot(hpi_handle_t, uint16_t, boolean_t,
+    int);
+hpi_status_t hpi_pfc_get_l3_class_config(hpi_handle_t handle, tcam_class_t slot,
+    tcam_key_cfg_t *cfg);
+hpi_status_t hpi_pfc_set_l3_class_config(hpi_handle_t handle, tcam_class_t slot,
+    tcam_key_cfg_t cfg);
+
+/*
+ * PFC TCAM Functions
+ */
+hpi_status_t   hpi_pfc_tcam_invalidate_all(hpi_handle_t);
+hpi_status_t   hpi_pfc_tcam_entry_invalidate(hpi_handle_t, uint32_t);
+hpi_status_t   hpi_pfc_tcam_entry_write(hpi_handle_t, uint32_t,
+       hxge_tcam_entry_t *);
+hpi_status_t   hpi_pfc_tcam_entry_read(hpi_handle_t, uint32_t,
+       hxge_tcam_entry_t *);
+hpi_status_t hpi_pfc_tcam_asc_ram_entry_read(hpi_handle_t handle,
+       uint32_t location, uint64_t *ram_data);
+hpi_status_t hpi_pfc_tcam_asc_ram_entry_write(hpi_handle_t handle,
+       uint32_t location, uint64_t ram_data);
+hpi_status_t   hpi_pfc_get_tcam_parity_log(hpi_handle_t,
+       pfc_tcam_par_err_log_t *);
+hpi_status_t   hpi_pfc_get_tcam_auto_init(hpi_handle_t,
+       pfc_auto_init_t *);
+
+/*
+ * PFC Hash Seed Value
+ */
+hpi_status_t   hpi_pfc_set_hash_seed_value(hpi_handle_t, uint32_t);
+
+/*
+ * PFC Interrupt Management Functions
+ */
+hpi_status_t   hpi_pfc_get_interrupt_status(hpi_handle_t, pfc_int_status_t *);
+hpi_status_t   hpi_pfc_clear_interrupt_status(hpi_handle_t);
+hpi_status_t   hpi_pfc_set_interrupt_mask(hpi_handle_t, boolean_t,
+       boolean_t, boolean_t);
+
+/*
+ * PFC Packet Logs
+ */
+hpi_status_t   hpi_pfc_get_drop_log(hpi_handle_t, pfc_drop_log_t *);
+hpi_status_t   hpi_pfc_set_drop_log_mask(hpi_handle_t, boolean_t,
+       boolean_t, boolean_t, boolean_t, boolean_t);
+hpi_status_t   hpi_pfc_get_bad_csum_counter(hpi_handle_t, uint64_t *);
+hpi_status_t   hpi_pfc_get_drop_counter(hpi_handle_t, uint64_t *);
+
+hpi_status_t hpi_pfc_get_mac_address(hpi_handle_t handle, int i, uint8_t *data);
+hpi_status_t hpi_hcr_mac_addr_get(hpi_handle_t handle, int i, uint8_t *data);
+hpi_status_t hpi_pfc_num_macs_get(hpi_handle_t handle, uint8_t *data);
+
+#endif /* !_HPI_PFC_H */
diff --git a/drivers/net/hxge/hpi/hpi_rxdma.c b/drivers/net/hxge/hpi/hpi_rxdma.c
new file mode 100644 (file)
index 0000000..92fa0a5
--- /dev/null
@@ -0,0 +1,834 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#include "hpi_rxdma.h"
+
+/* The state bit indicates the value that you want the qst bit to be */
+hpi_status_t
+hpi_rxdma_cfg_rdc_wait_for_qst(hpi_handle_t handle, uint8_t rdc,
+                       rdc_rx_cfg1_t *cfg, int state )
+{
+       uint32_t count = RXDMA_RESET_TRY_COUNT;
+       uint32_t delay_time = RXDMA_RESET_DELAY;
+
+       RXDMA_REG_READ64(handle, RDC_RX_CFG1, rdc, &cfg->value);
+       while ((count--) && (cfg->bits.qst == (1-state)))
+       {
+               HXGE_DELAY(delay_time);
+               RXDMA_REG_READ64(handle, RDC_RX_CFG1, rdc, &cfg->value);
+       }
+
+       if (!count) {
+               printk(KERN_DEBUG "hpi_rxdma_cfg_rdc_wait_for_qst not set to %d\n",state);
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                   " hpi_rxdma_cfg_rdc_ctl"
+                   " RXDMA_OP_DISABLE Failed for RDC %d \n",
+                   rdc));
+               return (HPI_RXDMA_ERROR_ENCODE(HPI_RXDMA_RESET_ERR, rdc));
+       }
+
+       return (HPI_SUCCESS);
+}
+
+/* RX DMA functions */
+hpi_status_t 
+hpi_rxdma_cfg_rdc_ctl(hpi_handle_t handle, uint8_t rdc, uint8_t op)
+{
+       rdc_rx_cfg1_t cfg;
+       uint32_t err = HPI_SUCCESS;
+
+       if (!RXDMA_CHANNEL_VALID(rdc)) {
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                   "hpi_rxdma_cfg_rdc_ctl Illegal RDC number %d \n", rdc));
+               return (HPI_RXDMA_RDC_INVALID);
+       }
+
+       switch (op) {
+               case RXDMA_OP_ENABLE:
+                       RXDMA_REG_READ64(handle, RDC_RX_CFG1, rdc, &cfg.value);
+                       cfg.bits.enable = 1;
+                       RXDMA_REG_WRITE64(handle, RDC_RX_CFG1, rdc, cfg.value);
+                       err = hpi_rxdma_cfg_rdc_wait_for_qst(handle, rdc, &cfg, 0);
+                       break;
+
+               case RXDMA_OP_DISABLE:
+                       RXDMA_REG_READ64(handle, RDC_RX_CFG1, rdc, &cfg.value);
+                       cfg.bits.enable = 0;
+                       RXDMA_REG_WRITE64(handle, RDC_RX_CFG1, rdc, cfg.value);
+                       err = hpi_rxdma_cfg_rdc_wait_for_qst(handle, rdc, &cfg, 1);
+                       break;
+
+               case RXDMA_OP_RESET:
+                       cfg.value = 0;
+                       cfg.bits.reset = 1;
+                       RXDMA_REG_WRITE64(handle, RDC_RX_CFG1, rdc, cfg.value);
+                       err = hpi_rxdma_cfg_rdc_wait_for_qst(handle, rdc, &cfg,1);
+                       break;
+
+               default:
+                       err = HPI_RXDMA_SW_PARAM_ERROR;
+                       break;
+       }
+
+       if (err !=  HPI_SUCCESS)
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                           " hpi_rxdma_cfg_rdc_ctl"
+                           " Reset Failed for RDC %d \n", rdc));
+       return (err);
+
+
+}
+
+hpi_status_t
+hpi_rxdma_cfg_rdc_rcr_ctl(hpi_handle_t handle, uint8_t rdc, uint8_t op, 
+                          uint16_t param)
+{
+       rdc_rcr_cfg_b_t rcr_cfgb;
+
+       if (!RXDMA_CHANNEL_VALID(rdc)) {
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                   "rxdma_cfg_rdc_rcr_ctl Illegal RDC number %d \n", rdc));
+               return (HPI_RXDMA_RDC_INVALID);
+       }
+
+       RXDMA_REG_READ64(handle, RDC_RCR_CFG_B, rdc, &rcr_cfgb.value);
+
+       switch (op) {
+               case RCR_TIMEOUT_ENABLE:
+                       rcr_cfgb.bits.timeout = (uint8_t)param;
+                       rcr_cfgb.bits.entout = 1;
+                       break;
+
+               case RCR_THRESHOLD:
+                       rcr_cfgb.bits.pthres = param;
+                       break;
+
+               case RCR_TIMEOUT_DISABLE:
+                       rcr_cfgb.bits.entout = 0;
+                       break;
+
+               default:
+                       HPI_ERROR_MSG((HPI_ERR_CTL,
+                           "rxdma_cfg_rdc_rcr_ctl Illegal opcode %x \n", op));
+               return (HPI_RXDMA_OPCODE_INVALID(rdc));
+       }
+
+       RXDMA_REG_WRITE64(handle, RDC_RCR_CFG_B, rdc, rcr_cfgb.value);
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_rxdma_cfg_rdc_rcr_timeout_disable(hpi_handle_t handle, uint8_t rdc)
+{
+       return (hpi_rxdma_cfg_rdc_rcr_ctl(handle, rdc, RCR_TIMEOUT_DISABLE, 0));
+}
+
+
+hpi_status_t
+hpi_rxdma_cfg_rdc_enable(hpi_handle_t handle, uint8_t rdc)
+{
+       return (hpi_rxdma_cfg_rdc_ctl(handle, rdc, RXDMA_OP_ENABLE));
+}
+
+hpi_status_t
+hpi_rxdma_cfg_rdc_disable(hpi_handle_t handle, uint8_t rdc)
+{
+       return (hpi_rxdma_cfg_rdc_ctl(handle, rdc, RXDMA_OP_DISABLE));
+}
+
+hpi_status_t
+hpi_rxdma_cfg_rdc_reset(hpi_handle_t handle, uint8_t rdc)
+{
+       return (hpi_rxdma_cfg_rdc_ctl(handle, rdc, RXDMA_OP_RESET));
+}
+
+
+hpi_status_t
+hpi_rxdma_cfg_rdc_rcr_timeout(hpi_handle_t handle, uint8_t rdc,
+    uint16_t rcr_timeout)
+{
+       return (hpi_rxdma_cfg_rdc_rcr_ctl(handle, rdc,
+           RCR_TIMEOUT_ENABLE, rcr_timeout));
+}
+
+/*
+ * hpi_rxdma_cfg_rdc_ring()
+ * Configure The RDC channel Rcv Buffer Ring
+ *
+ * Inputs:
+ *     rdc:            RX DMA Channel number
+ *     rdc_params:     RDC confiuration parameters
+ *
+ * Return:
+ * HPI_SUCCESS
+ * HPI_FAILURE
+ * HPI_SW_ERR
+ * HPI_HW_ERR
+ *
+ */
+hpi_status_t
+hpi_rxdma_cfg_rdc_ring(hpi_handle_t handle, uint8_t rdc,
+    rdc_desc_cfg_t *rdc_desc_cfg)
+{
+       rdc_rbr_cfg_a_t cfga;
+       rdc_rbr_cfg_b_t cfgb;
+       rdc_rx_cfg1_t cfg1;
+       rdc_rx_cfg2_t cfg2;
+       rdc_rcr_cfg_a_t rcr_cfga;
+       rdc_rcr_cfg_b_t rcr_cfgb;
+       rdc_page_handle_t page_handle;
+
+       if (!RXDMA_CHANNEL_VALID(rdc)) {
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                   "rxdma_cfg_rdc_ring Illegal RDC number %d \n", rdc));
+               return (HPI_RXDMA_RDC_INVALID);
+       }
+
+       cfga.value = 0;
+       cfgb.value = 0;
+       cfg1.value = 0;
+       cfg2.value = 0;
+       page_handle.value = 0;
+
+       if (rdc_desc_cfg->mbox_enable == 1) {
+               cfg1.bits.mbaddr_h = (rdc_desc_cfg->mbox_addr >> 32) & 0xfff;
+               cfg2.bits.mbaddr_l = ((rdc_desc_cfg->mbox_addr &
+                   RXDMA_CFIG2_MBADDR_L_MASK) >> RXDMA_CFIG2_MBADDR_L_SHIFT);
+
+               /*
+                * Only after all the configurations are set, then
+                * enable the RDC or else configuration fatal error
+                * will be returned (especially if the Hypervisor
+                * set up the logical pages with non-zero values.
+                * This HPI function only sets up the configuration.
+                * Call the enable function to enable the RDMC!
+                */
+       }
+
+       if (rdc_desc_cfg->full_hdr == 1)
+               cfg2.bits.full_hdr = 1;
+
+       if (RXDMA_BUFF_OFFSET_VALID(rdc_desc_cfg->offset)) {
+               cfg2.bits.offset = rdc_desc_cfg->offset;
+       } else {
+               cfg2.bits.offset = SW_OFFSET_NO_OFFSET;
+       }
+
+       /* rbr config */
+       cfga.value = (rdc_desc_cfg->rbr_addr &
+           (RBR_CFIG_A_STDADDR_MASK | RBR_CFIG_A_STDADDR_BASE_MASK));
+
+       /* The remaining 20 bits in the DMA address form the handle */
+       page_handle.bits.handle = (rdc_desc_cfg->rbr_addr >> 44) && 0xfffff;
+
+       /*
+        * Hydra:
+        * The RBR ring size must be multiple of 64.
+        */
+       if ((rdc_desc_cfg->rbr_len < RBR_DEFAULT_MIN_LEN) ||
+           (rdc_desc_cfg->rbr_len > RBR_DEFAULT_MAX_LEN) ||
+           (rdc_desc_cfg->rbr_len % 64)) {
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                   "hpi_rxdma_cfg_rdc_ring Illegal RBR Queue Length %d \n",
+                   rdc_desc_cfg->rbr_len));
+               return (HPI_RXDMA_ERROR_ENCODE(HPI_RXDMA_RBRSZIE_INVALID, rdc));
+       }
+
+       /*
+        * Hydra:
+        * The lower 6 bits are hardcoded to 0 and the higher 10 bits are
+        * stored in len.
+        */
+       cfga.bits.len = rdc_desc_cfg->rbr_len >> 6;
+       HPI_DEBUG_MSG((HPI_RDC_CTL,
+           "hpi_rxdma_cfg_rdc_ring CFGA 0x%llx len %d (RBR LEN %d)\n",
+           cfga.value, cfga.bits.len, rdc_desc_cfg->rbr_len));
+
+       /*
+        * Hydra: bksize is 1 bit, Neptune: bksize is 2 bits
+        * Buffer Block Size. b0 - 4K; b1 - 8K.
+        */
+       if (rdc_desc_cfg->page_size == SIZE_4KB)
+               cfgb.bits.bksize = RBR_BKSIZE_4K;
+       else if (rdc_desc_cfg->page_size == SIZE_8KB)
+               cfgb.bits.bksize = RBR_BKSIZE_8K;
+       else {
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                   "rxdma_cfg_rdc_ring blksize: Illegal buffer size %d \n",
+                   rdc_desc_cfg->page_size));
+               return (HPI_RXDMA_BUFSZIE_INVALID);
+       }
+
+       /*
+        * Hydra:
+        * Size 0 of packet buffer. b00 - 256; b01 - 512; b10 - 1K; b11 - resvd.
+        */
+       if (rdc_desc_cfg->valid0) {
+               if (rdc_desc_cfg->size0 == SIZE_256B)
+                       cfgb.bits.bufsz0 = RBR_BUFSZ0_256B;
+               else if (rdc_desc_cfg->size0 == SIZE_512B)
+                       cfgb.bits.bufsz0 = RBR_BUFSZ0_512B;
+               else if (rdc_desc_cfg->size0 == SIZE_1KB)
+                       cfgb.bits.bufsz0 = RBR_BUFSZ0_1K;
+               else {
+                       HPI_ERROR_MSG((HPI_ERR_CTL,
+                           " rxdma_cfg_rdc_ring"
+                           " blksize0: Illegal buffer size %x \n",
+                           rdc_desc_cfg->size0));
+                       return (HPI_RXDMA_BUFSZIE_INVALID);
+               }
+               cfgb.bits.vld0 = 1;
+       } else {
+               cfgb.bits.vld0 = 0;
+       }
+
+       /*
+        * Hydra:
+        * Size 1 of packet buffer. b0 - 1K; b1 - 2K.
+        */
+       if (rdc_desc_cfg->valid1) {
+               if (rdc_desc_cfg->size1 == SIZE_1KB)
+                       cfgb.bits.bufsz1 = RBR_BUFSZ1_1K;
+               else if (rdc_desc_cfg->size1 == SIZE_2KB)
+                       cfgb.bits.bufsz1 = RBR_BUFSZ1_2K;
+               else {
+                       HPI_ERROR_MSG((HPI_ERR_CTL,
+                           " rxdma_cfg_rdc_ring"
+                           " blksize1: Illegal buffer size %x \n",
+                           rdc_desc_cfg->size1));
+                       return (HPI_RXDMA_BUFSZIE_INVALID);
+               }
+               cfgb.bits.vld1 = 1;
+       } else {
+               cfgb.bits.vld1 = 0;
+       }
+
+       /*
+        * Hydra:
+        * Size 2 of packet buffer. b0 - 2K; b1 - 4K.
+        */
+       if (rdc_desc_cfg->valid2) {
+               if (rdc_desc_cfg->size2 == SIZE_2KB)
+                       cfgb.bits.bufsz2 = RBR_BUFSZ2_2K;
+               else if (rdc_desc_cfg->size2 == SIZE_4KB)
+                       cfgb.bits.bufsz2 = RBR_BUFSZ2_4K;
+               else {
+                       HPI_ERROR_MSG((HPI_ERR_CTL,
+                           " rxdma_cfg_rdc_ring"
+                           " blksize2: Illegal buffer size %x \n",
+                           rdc_desc_cfg->size2));
+                       return (HPI_RXDMA_BUFSZIE_INVALID);
+               }
+               cfgb.bits.vld2 = 1;
+       } else {
+               cfgb.bits.vld2 = 0;
+       }
+
+       rcr_cfga.value = (rdc_desc_cfg->rcr_addr &
+           (RCRCFIG_A_STADDR_MASK | RCRCFIG_A_STADDR_BASE_MASK));
+
+       /*
+        * Hydra:
+        * The rcr len must be multiple of 32.
+        */
+       if ((rdc_desc_cfg->rcr_len < RCR_DEFAULT_MIN_LEN) ||
+           (rdc_desc_cfg->rcr_len > HXGE_RCR_MAX) ||
+           (rdc_desc_cfg->rcr_len % 32)) {
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                   " rxdma_cfg_rdc_ring Illegal RCR Queue Length %d \n",
+                   rdc_desc_cfg->rcr_len));
+               return (HPI_RXDMA_ERROR_ENCODE(HPI_RXDMA_RCRSZIE_INVALID, rdc));
+       }
+
+       /*
+        * Hydra:
+        * Bits 15:5 of the maximum number of 8B entries in RCR.  Bits 4:0 are
+        * hard-coded to zero.  The maximum size is 2^16 - 32.
+        */
+       rcr_cfga.bits.len = rdc_desc_cfg->rcr_len >> 5;
+
+       rcr_cfgb.value = 0;
+       if (rdc_desc_cfg->rcr_timeout_enable == 1) {
+               /* check if the rcr timeout value is valid */
+
+               if (RXDMA_RCR_TO_VALID(rdc_desc_cfg->rcr_timeout)) {
+                       rcr_cfgb.bits.timeout = rdc_desc_cfg->rcr_timeout;
+                       rcr_cfgb.bits.entout = 1;
+               } else {
+                       HPI_ERROR_MSG((HPI_ERR_CTL,
+                           " rxdma_cfg_rdc_ring"
+                           " Illegal RCR Timeout value %d \n",
+                           rdc_desc_cfg->rcr_timeout));
+                       rcr_cfgb.bits.entout = 0;
+               }
+       } else {
+               rcr_cfgb.bits.entout = 0;
+       }
+
+       rcr_cfgb.bits.pthres = rdc_desc_cfg->rcr_threshold;
+
+       /* now do the actual HW configuration */
+       RXDMA_REG_WRITE64(handle, RDC_RX_CFG1, rdc, cfg1.value);
+       RXDMA_REG_WRITE64(handle, RDC_RX_CFG2, rdc, cfg2.value);
+
+       RXDMA_REG_WRITE64(handle, RDC_RBR_CFG_A, rdc, cfga.value);
+       RXDMA_REG_WRITE64(handle, RDC_RBR_CFG_B, rdc, cfgb.value);
+
+       RXDMA_REG_WRITE64(handle, RDC_RCR_CFG_A, rdc, rcr_cfga.value);
+       RXDMA_REG_WRITE64(handle, RDC_RCR_CFG_B, rdc, rcr_cfgb.value);
+
+       RXDMA_REG_WRITE64(handle, RDC_PAGE_HANDLE, rdc, page_handle.value);
+
+       return (HPI_SUCCESS);
+}
+
+/* system wide conf functions */
+
+hpi_status_t
+hpi_rxdma_cfg_clock_div_set(hpi_handle_t handle, uint16_t count)
+{
+       uint64_t offset;
+       rdc_clock_div_t clk_div;
+
+       offset = RDC_CLOCK_DIV;
+
+       clk_div.value = 0;
+       clk_div.bits.count = count;
+       HPI_DEBUG_MSG((HPI_RDC_CTL,
+           " hpi_rxdma_cfg_clock_div_set: value 0x%llx",
+           clk_div.value));
+
+       HXGE_REG_WR64(handle, offset, clk_div.value);
+
+       return (HPI_SUCCESS);
+}
+
+
+hpi_status_t
+hpi_rxdma_rdc_rbr_qlen_get(hpi_handle_t handle, uint8_t rdc,
+    rdc_rbr_qlen_t *rbr_qlen)
+{
+       if (!RXDMA_CHANNEL_VALID(rdc)) {
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                   " rxdma_rdc_rbr_qlen_get Illegal RDC Number %d \n", rdc));
+               return (HPI_RXDMA_RDC_INVALID);
+       }
+
+       RXDMA_REG_READ64(handle, RDC_RBR_QLEN, rdc, &rbr_qlen->value);
+       return (HPI_SUCCESS);
+}
+
+
+hpi_status_t
+hpi_rxdma_rdc_rcr_qlen_get(hpi_handle_t handle, uint8_t rdc,
+    uint16_t *rcr_qlen)
+{
+       rdc_rcr_qlen_t stats;
+
+       if (!RXDMA_CHANNEL_VALID(rdc)) {
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                   " rxdma_rdc_rcr_qlen_get Illegal RDC Number %d \n", rdc));
+               return (HPI_RXDMA_RDC_INVALID);
+       }
+
+       RXDMA_REG_READ64(handle, RDC_RCR_QLEN, rdc, &stats.value);
+       *rcr_qlen =  stats.bits.qlen;
+       HPI_DEBUG_MSG((HPI_RDC_CTL,
+           " rxdma_rdc_rcr_qlen_get RDC %d qlen %x qlen %x\n",
+           rdc, *rcr_qlen, stats.bits.qlen));
+       return (HPI_SUCCESS);
+}
+
+
+hpi_status_t
+hpi_rxdma_rdc_rcr_tail_get(hpi_handle_t handle, uint8_t rdc,
+       uint32_t *rcr_tail)
+{
+       rdc_rcr_tail_t tail;
+
+        if (!RXDMA_CHANNEL_VALID(rdc)) {
+                HPI_ERROR_MSG((HPI_ERR_CTL,
+                    " rxdma_rdc_rcr_tail_get Illegal RDC Number %d \n", rdc));
+                return (HPI_RXDMA_RDC_INVALID);
+        }
+        RXDMA_REG_READ64(handle, RDC_RCR_TAIL, rdc, &tail.value);
+        *rcr_tail =  tail.bits.tail;
+        HPI_DEBUG_MSG((HPI_RDC_CTL,
+            " rxdma_rdc_rcr_qlen_get RDC %d qlen %x \n",
+            rdc, *rcr_tail));
+        return (HPI_SUCCESS);
+}
+
+
+
+hpi_status_t
+hpi_rxdma_rdc_rcr_read_update(hpi_handle_t handle, uint8_t channel,
+       uint16_t pkts_read, uint16_t bufs_read)
+{
+       rdc_stat_t      cs;
+
+       if (!RXDMA_CHANNEL_VALID(channel)) {
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                   " hpi_rxdma_rdc_rcr_read_update ", " channel %d", channel));
+               return (HPI_FAILURE | HPI_RXDMA_CHANNEL_INVALID(channel));
+       }
+
+       HPI_DEBUG_MSG((HPI_RDC_CTL,
+           " hpi_rxdma_rdc_rcr_read_update bufs read %d pkt read %d",
+           bufs_read, pkts_read));
+
+       cs.value = 0; /* do not modify any other bits */
+       cs.bits.pktread = pkts_read;
+       cs.bits.ptrread = bufs_read;
+
+       RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value);
+
+       return (HPI_SUCCESS);
+}
+
+/*
+ * hpi_rxdma_channel_mex_set():
+ *     This function is called to arm the DMA channel with
+ *     mailbox updating capability. Software needs to rearm
+ *     for each update by writing to the control and status register.
+ *
+ * Parameters:
+ *     handle          - HPI handle (virtualization flag must be defined).
+ *     channel         - logical RXDMA channel from 0 to 23.
+ *                       (If virtualization flag is not set, then
+ *                        logical channel is the same as the hardware
+ *                        channel number).
+ *
+ * Return:
+ *     HPI_SUCCESS             - If enable channel with mailbox update
+ *                               is complete successfully.
+ *
+ *     Error:
+ *     HPI_FAILURE     -
+ *             HPI_RXDMA_CHANNEL_INVALID -
+ */
+hpi_status_t
+hpi_rxdma_channel_mex_set(hpi_handle_t handle, uint8_t channel)
+{
+       return (hpi_rxdma_channel_control(handle, RXDMA_MEX_SET, channel));
+}
+
+hpi_status_t
+hpi_rxdma_channel_cs_clear_all(hpi_handle_t handle, uint8_t channel)
+{
+       return (hpi_rxdma_channel_control(handle, RXDMA_CS_CLEAR_ALL, channel));
+}
+
+/*
+ * hpi_rxdma_channel_control():
+ *     This function is called to control a receive DMA channel
+ *     for arming the channel with mailbox updates, resetting
+ *     various event status bits (control and status register).
+ *
+ * Parameters:
+ *     handle          - HPI handle (virtualization flag must be defined).
+ *     control         - HPI defined control type supported:
+ *                             - RXDMA_MEX_SET
+ *                             - RXDMA_RCRTO_CLEAR
+ *                             - RXDMA_RCR_SFULL_CLEAR
+ *                             - RXDMA_RCR_FULL_CLEAR
+ *                             - RXDMA_RBR_PRE_EMPTY_CLEAR
+ *                             - RXDMA_RBR_EMPTY_CLEAR
+ *     channel         - logical RXDMA channel from 0 to 23.
+ *                       (If virtualization flag is not set, then
+ *                        logical channel is the same as the hardware.
+ * Return:
+ *     HPI_SUCCESS
+ *
+ *     Error:
+ *     HPI_FAILURE             -
+ *             HPI_TXDMA_OPCODE_INVALID        -
+ *             HPI_TXDMA_CHANNEL_INVALID       -
+ */
+hpi_status_t
+hpi_rxdma_channel_control(hpi_handle_t handle, rxdma_cs_cntl_t control,
+       uint8_t channel)
+{
+       rdc_stat_t      cs;
+
+       if (!RXDMA_CHANNEL_VALID(channel)) {
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                   " hpi_rxdma_channel_control", " channel", channel));
+               return (HPI_FAILURE | HPI_RXDMA_CHANNEL_INVALID(channel));
+       }
+
+       cs.value = 0; // do not modify other bits
+       switch (control) {
+       case RXDMA_MEX_SET:
+               cs.bits.mex = 1;
+               RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value);
+               break;
+
+       case RXDMA_RCRTO_CLEAR:
+               cs.bits.rcr_to = 1;
+               RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value);
+               break;
+
+       case RXDMA_RCR_SFULL_CLEAR:
+               cs.bits.rcr_shadow_full = 1;
+               RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value);
+               break;
+
+       case RXDMA_RCR_FULL_CLEAR:
+               cs.bits.rcr_full = 1;
+               RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value);
+               break;
+
+       case RXDMA_RBR_PRE_EMPTY_CLEAR:
+               cs.bits.rbr_pre_empty = 1;
+               RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value);
+               break;
+
+       case RXDMA_RBR_EMPTY_CLEAR:
+               cs.bits.rbr_empty = 1;
+               RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value);
+               break;
+
+       case RXDMA_CS_CLEAR_ALL:
+               cs.value = ~0ULL;
+               RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs.value);
+               break;
+
+       default:
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                   "hpi_rxdma_channel_control", "control", control));
+               return (HPI_FAILURE | HPI_RXDMA_OPCODE_INVALID(channel));
+       }
+
+       return (HPI_SUCCESS);
+}
+
+/*
+ * hpi_rxdma_control_status():
+ *     This function is called to operate on the control
+ *     and status register.
+ *
+ * Parameters:
+ *     handle          - HPI handle
+ *     op_mode         - OP_GET: get hardware control and status
+ *                       OP_SET: set hardware control and status
+ *                       OP_UPDATE: update hardware control and status.
+ *                       OP_CLEAR: clear control and status register to 0s.
+ *     channel         - hardware RXDMA channel from 0 to 23.
+ *     cs_p            - pointer to hardware defined control and status
+ *                       structure.
+ * Return:
+ *     HPI_SUCCESS
+ *
+ *     Error:
+ *     HPI_FAILURE             -
+ *             HPI_RXDMA_OPCODE_INVALID        -
+ *             HPI_RXDMA_CHANNEL_INVALID       -
+ */
+hpi_status_t
+hpi_rxdma_control_status(hpi_handle_t handle, io_op_t op_mode, uint8_t channel,
+    rdc_stat_t *cs_p)
+{
+       int             status = HPI_SUCCESS;
+       rdc_stat_t      cs;
+
+       if (!RXDMA_CHANNEL_VALID(channel)) {
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                   "hpi_rxdma_control_status", "channel", channel));
+               return (HPI_FAILURE | HPI_RXDMA_CHANNEL_INVALID(channel));
+       }
+
+       switch (op_mode) {
+       case OP_GET:
+               RXDMA_REG_READ64(handle, RDC_STAT, channel, &cs_p->value);
+               break;
+
+       case OP_SET:
+               RXDMA_REG_WRITE64(handle, RDC_STAT, channel, cs_p->value);
+               break;
+
+       case OP_UPDATE:
+               RXDMA_REG_READ64(handle, RDC_STAT, channel, &cs.value);
+               RXDMA_REG_WRITE64(handle, RDC_STAT, channel,
+                   cs_p->value | cs.value);
+               break;
+
+       default:
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                   "hpi_rxdma_control_status", "control", op_mode));
+               return (HPI_FAILURE | HPI_RXDMA_OPCODE_INVALID(channel));
+       }
+
+       return (status);
+}
+
+/*
+ * hpi_rxdma_event_mask():
+ *     This function is called to operate on the event mask
+ *     register which is used for generating interrupts.
+ *
+ * Parameters:
+ *     handle          - HPI handle
+ *     op_mode         - OP_GET: get hardware event mask
+ *                       OP_SET: set hardware interrupt event masks
+ *                       OP_CLEAR: clear control and status register to 0s.
+ *     channel         - hardware RXDMA channel from 0 to 23.
+ *     mask_p          - pointer to hardware defined event mask
+ *                       structure.
+ * Return:
+ *     HPI_SUCCESS             - If set is complete successfully.
+ *
+ *     Error:
+ *     HPI_FAILURE             -
+ *             HPI_RXDMA_OPCODE_INVALID        -
+ *             HPI_RXDMA_CHANNEL_INVALID       -
+ */
+
+
+hpi_status_t
+hpi_rxdma_event_mask(hpi_handle_t handle, io_op_t op_mode, uint8_t channel,
+    rdc_int_mask_t *mask_p)
+{
+       int             status = HPI_SUCCESS;
+       rdc_int_mask_t  mask;
+
+       if (!RXDMA_CHANNEL_VALID(channel)) {
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                   "hpi_rxdma_event_mask", "channel", channel));
+               return (HPI_FAILURE | HPI_RXDMA_CHANNEL_INVALID(channel));
+       }
+
+       switch (op_mode) {
+       case OP_GET:
+               RXDMA_REG_READ64(handle, RDC_INT_MASK, channel, &mask_p->value);
+               break;
+
+       case OP_SET:
+               RXDMA_REG_WRITE64(handle, RDC_INT_MASK, channel, mask_p->value);
+               break;
+
+       case OP_UPDATE:
+               RXDMA_REG_READ64(handle, RDC_INT_MASK, channel, &mask.value);
+               RXDMA_REG_WRITE64(handle, RDC_INT_MASK, channel,
+                   mask_p->value | mask.value);
+               break;
+
+       default:
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                   "hpi_rxdma_event_mask", "eventmask", op_mode));
+               return (HPI_FAILURE | HPI_RXDMA_OPCODE_INVALID(channel));
+       }
+
+       return (status);
+}
+
+/*
+ * hpi_rx_fifo_status():
+ *     This function is called to operate on the RX Fifo Error Status
+ *     register.
+ *
+ * Parameters:
+ *     handle          - HPI handle
+ *     op_mode         - OP_GET: get hardware control and status
+ *                       OP_SET: set hardware control and status
+ *     cs_p            - pointer to hardware defined fifo status structure.
+ *
+ * Return:
+ *     HPI_SUCCESS
+ *
+ *     Error:
+ *     HPI_FAILURE             -
+ *             HPI_RXDMA_OPCODE_INVALID        -
+ *             HPI_RXDMA_CHANNEL_INVALID       -
+ */
+hpi_status_t
+hpi_rx_fifo_status(hpi_handle_t handle, io_op_t op_mode,
+                  rdc_fifo_err_stat_t *cs_p)
+{
+       int             status = HPI_SUCCESS;
+
+       switch (op_mode) {
+       case OP_GET:
+               HXGE_REG_RD64(handle, RDC_FIFO_ERR_STAT, &cs_p->value);
+               break;
+
+       case OP_SET:
+               HXGE_REG_WR64(handle, RDC_FIFO_ERR_STAT, cs_p->value);
+               break;
+
+       default:
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                   "hpi_rx_fifo_status", "control", op_mode));
+               return (HPI_FAILURE | HPI_RXDMA_OPCODE_INVALID(0));
+       }
+
+       return (status);
+}
+
+/*
+ * hpi_rx_fifo_mask():
+ *     This function is called to operate on the fifo error mask
+ *     register which is used for generating interrupts.
+ *
+ * Parameters:
+ *     handle          - HPI handle
+ *     op_mode         - OP_GET: get hardware event mask
+ *                       OP_SET: set hardware interrupt event masks
+ *     mask_p          - pointer to hardware defined event mask
+ *                       structure.
+ * Return:
+ *     HPI_SUCCESS             - If set is complete successfully.
+ *
+ *     Error:
+ *     HPI_FAILURE             -
+ *             HPI_RXDMA_OPCODE_INVALID        -
+ *             HPI_RXDMA_CHANNEL_INVALID       -
+ */
+
+
+hpi_status_t
+hpi_rx_fifo_mask(hpi_handle_t handle, io_op_t op_mode,
+                rdc_fifo_err_mask_t *mask_p)
+{
+       int             status = HPI_SUCCESS;
+
+       switch (op_mode) {
+       case OP_GET:
+               HXGE_REG_RD64(handle, RDC_FIFO_ERR_MASK, &mask_p->value);
+               break;
+
+       case OP_SET:
+               HXGE_REG_WR64(handle, RDC_FIFO_ERR_MASK, mask_p->value);
+               break;
+
+       default:
+               HPI_ERROR_MSG((HPI_ERR_CTL,
+                   "hpi_rx_fifo_mask", "interrupt-mask", op_mode));
+               return (HPI_FAILURE | HPI_RXDMA_OPCODE_INVALID(0));
+       }
+
+       return (status);
+}
diff --git a/drivers/net/hxge/hpi/hpi_rxdma.h b/drivers/net/hxge/hpi/hpi_rxdma.h
new file mode 100644 (file)
index 0000000..f1bfc84
--- /dev/null
@@ -0,0 +1,266 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#ifndef _HPI_RXDMA_H
+#define        _HPI_RXDMA_H
+
+#include "hpi.h"
+#include "../hxge_defs.h"
+#include "../hxge_rdc_hw.h"
+
+#define        RXDMA_CFIG2_MBADDR_L_SHIFT      6       /* bit 31:6 */
+#define        RXDMA_CFIG2_MBADDR_L_MASK       0x00000000ffffffc0ULL
+
+#define        RBR_CFIG_A_STDADDR_MASK         0x000000000003ffc0ULL
+#define        RBR_CFIG_A_STDADDR_BASE_MASK    0x00000ffffffc0000ULL
+
+#define        RCRCFIG_A_STADDR_SHIFT          6       /* bit 18:6 */
+#define        RCRCFIG_A_STADDR_MASK           0x000000000007FFC0ULL
+#define        RCRCFIG_A_STADDR_BASE_SHIF      19      /* bit 43:19 */
+#define        RCRCFIG_A_STADDR_BASE_MASK      0x00000FFFFFF80000ULL
+#define        RCRCFIG_A_LEN_SHIF              48      /* bit 63:48 */
+#define        RCRCFIG_A_LEN_MASK              0xFFFF000000000000ULL
+
+#define        RCR_FLSH_SHIFT                  0       /* RW, bit 0:0 */
+#define        RCR_FLSH_SET                    0x0000000000000001ULL
+#define        RCR_FLSH_MASK                   0x0000000000000001ULL
+
+#define        RBR_CFIG_A_LEN_SHIFT            48      /* bits 63:48 */
+#define        RBR_CFIG_A_LEN_MASK             0xFFFF000000000000ULL
+
+#define  RXDMA_RESET_TRY_COUNT  5
+#define  RXDMA_RESET_DELAY      5
+
+#define  RXDMA_OP_DISABLE       0
+#define  RXDMA_OP_ENABLE        1
+#define  RXDMA_OP_RESET         2
+
+#define  RCR_TIMEOUT_ENABLE     1
+#define  RCR_TIMEOUT_DISABLE    2
+#define  RCR_THRESHOLD          4
+
+
+/*
+ * Buffer block descriptor
+ */
+typedef struct _rx_desc_t {
+       uint32_t        block_addr;
+} rx_desc_t, *p_rx_desc_t;
+
+/*
+ * RXDMA HPI defined control types.
+ */
+typedef        enum _rxdma_cs_cntl_e {
+       RXDMA_CS_CLEAR_ALL              = 0x1,
+       RXDMA_MEX_SET                   = 0x2,
+       RXDMA_RCRTO_CLEAR               = 0x4,
+       RXDMA_RCR_SFULL_CLEAR           = 0x8,
+       RXDMA_RCR_FULL_CLEAR            = 0x10,
+       RXDMA_RBR_PRE_EMPTY_CLEAR       = 0x20,
+       RXDMA_RBR_EMPTY_CLEAR           = 0x40
+} rxdma_cs_cntl_t;
+
+typedef union _rcr_addr44 {
+       uint64_t        addr;
+       struct {
+#if defined(_BIG_ENDIAN)
+               uint32_t rsrvd:20;
+               uint32_t hdw:25;
+               uint32_t ldw:19;
+#else
+               uint32_t ldw:19;
+               uint32_t hdw:25;
+               uint32_t rsrvd:20;
+#endif
+       } bits;
+} rcr_addr44_t;
+
+typedef union _rbr_addr44 {
+       uint64_t        addr;
+       struct {
+#if defined(_BIG_ENDIAN)
+               uint32_t rsrvd:20;
+               uint32_t hdw:26;
+               uint32_t ldw:18;
+#else
+               uint32_t ldw:18;
+               uint32_t hdw:26;
+               uint32_t rsrvd:20;
+#endif
+       } bits;
+} rbr_addr44_t;
+
+typedef enum _bsize {
+       SIZE_0B = 0x0,
+       SIZE_64B = 64,
+       SIZE_128B = 128,
+       SIZE_192B = 192,
+       SIZE_256B = 256,
+       SIZE_512B = 512,
+       SIZE_1KB = 1024,
+       SIZE_2KB = 2048,
+       SIZE_4KB = 4096,
+       SIZE_8KB = 8192,
+       SIZE_16KB = 16384,
+       SIZE_32KB = 32668
+} bsize_t;
+
+typedef struct _rdc_desc_cfg_t {
+       uint8_t mbox_enable;            /* Enable full (18b) header */
+       uint8_t full_hdr;               /* Enable full (18b) header */
+       uint8_t offset;                 /* 64 byte offsets */
+       uint8_t valid2;                 /* size 2 is valid */
+       bsize_t size2;                  /* Size 2 length */
+       uint8_t valid1;                 /* size 1 is valid */
+       bsize_t size1;                  /* Size 1 length */
+       uint8_t valid0;                 /* size 0 is valid */
+       bsize_t size0;                  /* Size 1 length */
+       bsize_t page_size;              /* Page or buffer Size */
+       uint8_t rcr_timeout_enable;
+       uint8_t rcr_timeout;
+       uint16_t rcr_threshold;
+       uint16_t rcr_len;               /* RBR Descriptor size (entries) */
+       uint16_t rbr_len;               /* RBR Descriptor size (entries) */
+       uint64_t mbox_addr;             /* Mailbox Address */
+       uint64_t rcr_addr;              /* RCR Address */
+       uint64_t rbr_addr;              /* RBB Address */
+} rdc_desc_cfg_t;
+
+
+/*
+ * Register offset (0x800 bytes for each channel) for receive ring registers.
+ */
+#define        HXGE_RXDMA_OFFSET(x, v, channel) (x + \
+               (!v ? DMC_OFFSET(channel) : \
+                   RDMC_PIOVADDR_OFFSET(channel)))
+
+#define        RXDMA_REG_READ64(handle, reg, channel, data_p) \
+do {\
+       HXGE_REG_RD64(handle, (HXGE_RXDMA_OFFSET(reg, 0,\
+               channel)), (data_p));\
+} while(0)
+
+#define        RXDMA_REG_READ32(handle, reg, channel, data_p) \
+       HXGE_REG_RD32(handle, (HXGE_RXDMA_OFFSET(reg, 0,\
+               channel)), (data_p))
+
+#define        RXDMA_REG_WRITE64(handle, reg, channel, data)\
+do {\
+       HXGE_REG_WR64(handle, (HXGE_RXDMA_OFFSET(reg, 0,\
+               channel)), (data));\
+} while(0)
+
+/*
+ * RX HPI error codes
+ */
+#define        RXDMA_ER_ST                     (RXDMA_BLK_ID << HPI_BLOCK_ID_SHIFT)
+#define        RXDMA_ID_SHIFT(n)               (n << HPI_PORT_CHAN_SHIFT)
+
+#define        HPI_RXDMA_ERROR                 RXDMA_ER_ST
+
+#define        HPI_RXDMA_SW_PARAM_ERROR        (HPI_RXDMA_ERROR | 0x40)
+#define        HPI_RXDMA_HW_ERROR              (HPI_RXDMA_ERROR | 0x80)
+
+#define        HPI_RXDMA_RDC_INVALID           (HPI_RXDMA_ERROR | CHANNEL_INVALID)
+#define        HPI_RXDMA_PAGE_INVALID          (HPI_RXDMA_ERROR | LOGICAL_PAGE_INVALID)
+#define        HPI_RXDMA_RESET_ERR             (HPI_RXDMA_HW_ERROR | RESET_FAILED)
+#define        HPI_RXDMA_DISABLE_ERR           (HPI_RXDMA_HW_ERROR | 0x0000a)
+#define        HPI_RXDMA_ENABLE_ERR            (HPI_RXDMA_HW_ERROR | 0x0000b)
+#define        HPI_RXDMA_FUNC_INVALID          (HPI_RXDMA_SW_PARAM_ERROR | 0x0000a)
+#define        HPI_RXDMA_BUFSZIE_INVALID       (HPI_RXDMA_SW_PARAM_ERROR | 0x0000b)
+#define        HPI_RXDMA_RBRSZIE_INVALID       (HPI_RXDMA_SW_PARAM_ERROR | 0x0000c)
+#define        HPI_RXDMA_RCRSZIE_INVALID       (HPI_RXDMA_SW_PARAM_ERROR | 0x0000d)
+#define        HPI_RXDMA_PORT_INVALID          (HPI_RXDMA_ERROR | PORT_INVALID)
+#define        HPI_RXDMA_TABLE_INVALID         (HPI_RXDMA_ERROR | RDC_TAB_INVALID)
+
+#define        HPI_RXDMA_CHANNEL_INVALID(n)    (RXDMA_ID_SHIFT(n) |    \
+                                       HPI_RXDMA_ERROR | CHANNEL_INVALID)
+#define        HPI_RXDMA_OPCODE_INVALID(n)     (RXDMA_ID_SHIFT(n) |    \
+                                       HPI_RXDMA_ERROR | OPCODE_INVALID)
+
+#define        HPI_RXDMA_ERROR_ENCODE(err, rdc)        \
+       (RXDMA_ID_SHIFT(rdc) | RXDMA_ER_ST | err)
+
+#define        RXDMA_CHANNEL_VALID(rdc) \
+       ((rdc < HXGE_MAX_RDCS))
+
+#define        RXDMA_PAGE_VALID(page) \
+       ((page == 0) || (page == 1))
+
+#define        RXDMA_BUFF_OFFSET_VALID(offset) \
+       ((offset == SW_OFFSET_NO_OFFSET) || \
+           (offset == SW_OFFSET_64) || \
+           (offset == SW_OFFSET_128))
+
+#define        RXDMA_RCR_TO_VALID(tov) ((tov) && (tov < 64))
+#define        RXDMA_RCR_THRESH_VALID(thresh) ((thresh < 65536))
+
+#define        hpi_rxdma_rdc_rbr_kick(handle, rdc, num_buffers) \
+       RXDMA_REG_WRITE64(handle, RDC_RBR_KICK, rdc, num_buffers)
+
+hpi_status_t hpi_rxdma_cfg_rdc_ring(hpi_handle_t handle, uint8_t rdc,
+    rdc_desc_cfg_t *rdc_desc_params);
+hpi_status_t hpi_rxdma_cfg_clock_div_set(hpi_handle_t handle, uint16_t count);
+hpi_status_t hpi_rxdma_cfg_logical_page_handle(hpi_handle_t handle, uint8_t rdc,
+    uint64_t pg_handle);
+
+hpi_status_t hpi_rxdma_rdc_rcr_read_update(hpi_handle_t handle, uint8_t channel,
+    uint16_t num_pkts, uint16_t bufs_read);
+hpi_status_t hpi_rxdma_rdc_rbr_qlen_get(hpi_handle_t handle, uint8_t rdc,
+    rdc_rbr_qlen_t *rbr_stat);
+hpi_status_t hpi_rxdma_cfg_rdc_reset(hpi_handle_t handle, uint8_t rdc);
+hpi_status_t hpi_rxdma_cfg_rdc_enable(hpi_handle_t handle, uint8_t rdc);
+hpi_status_t hpi_rxdma_cfg_rdc_disable(hpi_handle_t handle, uint8_t rdc);
+hpi_status_t hpi_rxdma_cfg_rdc_rcr_timeout(hpi_handle_t handle, uint8_t rdc,
+    uint16_t rcr_timeout);
+
+hpi_status_t hpi_rxdma_cfg_rdc_rcr_threshold(hpi_handle_t handle, uint8_t rdc,
+    uint16_t rcr_threshold);
+hpi_status_t hpi_rxdma_cfg_rdc_rcr_timeout_disable(hpi_handle_t handle,
+    uint8_t rdc);
+hpi_status_t hpi_rxdma_cfg_rdc_rcr_ctl(hpi_handle_t handle, uint8_t rdc,
+                        uint8_t op, uint16_t rcr_timeout);
+hpi_status_t hpi_rxdma_rdc_rcr_qlen_get(hpi_handle_t handle,
+    uint8_t rdc,  uint16_t *qlen);
+hpi_status_t hpi_rxdma_channel_mex_set(hpi_handle_t handle, uint8_t channel);
+hpi_status_t hpi_rxdma_channel_control(hpi_handle_t handle,
+    rxdma_cs_cntl_t control, uint8_t channel);
+hpi_status_t hpi_rxdma_control_status(hpi_handle_t handle, io_op_t op_mode,
+    uint8_t channel, rdc_stat_t *cs_p);
+hpi_status_t hpi_rxdma_event_mask(hpi_handle_t handle, io_op_t op_mode,
+    uint8_t channel, rdc_int_mask_t *mask_p);
+hpi_status_t hpi_rxdma_channel_cs_clear_all(hpi_handle_t handle, 
+       uint8_t channel);
+hpi_status_t hpi_rx_fifo_status(hpi_handle_t handle, io_op_t op_mode,
+       rdc_fifo_err_stat_t *stat);
+hpi_status_t hpi_rx_fifo_mask(hpi_handle_t handle, io_op_t op_mode,
+       rdc_fifo_err_mask_t *stat);
+hpi_status_t hpi_rxdma_rdc_rcr_tail_get(hpi_handle_t handle, uint8_t channel, 
+       uint32_t *rcr_tail);
+hpi_status_t hpi_rxdma_cfg_rdc_wait_for_qst(hpi_handle_t handle, uint8_t rdc,
+                       rdc_rx_cfg1_t *cfg, int state);
+
+
+#endif /* _HPI_RXDMA_H */
diff --git a/drivers/net/hxge/hpi/hpi_txdma.c b/drivers/net/hxge/hpi/hpi_txdma.c
new file mode 100644 (file)
index 0000000..4952333
--- /dev/null
@@ -0,0 +1,903 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#include       "hpi_txdma.h"
+
+#define        TXDMA_WAIT_LOOP         10000
+#define        TXDMA_WAIT_USEC         5
+
+uint64_t tdc_dmc_offset[] = {
+       TDC_PAGE_HANDLE,
+       TDC_TDR_CFG,
+       TDC_TDR_HEAD,
+       TDC_TDR_PRE_HEAD,
+       TDC_TDR_KICK,
+       TDC_INT_MASK,
+       TDC_STAT,
+       TDC_MBH,
+       TDC_MBL,
+       TDC_BYTE_CNT,
+       TDC_TDR_QLEN,
+       TDC_DROP_CNT,
+       TDC_PREF_PAR_LOG,
+       TDC_STAT_INT_DBG,
+       TDC_PKT_REQ_TID_TAG,
+       TDC_SOP_PREF_DESC_LOG,
+       TDC_PREF_DESC_LOG,
+};
+
+const char *tdc_dmc_name[] = {
+       "TDC_PAGE_HANDLE",
+       "TDC_TDR_CFG",
+       "TDC_TDR_HEAD",
+       "TDC_TDR_PRE_HEAD",
+       "TDC_TDR_KICK",
+       "TDC_INT_MASK",
+       "TDC_STAT",
+       "TDC_MBH",
+       "TDC_MBL",
+       "TDC_BYTE_CNT",
+       "TDC_TDR_QLEN",
+       "TDC_DROP_CNT",
+       "TDC_PREF_PAR_LOG",
+       "TDC_STAT_INT_DBG",
+       "TDC_PKT_REQ_TID_TAG",
+       "TDC_SOP_PREF_DESC_LOG",
+       "TDC_PREF_DESC_LOG",
+};
+
+uint64_t tdc_reg_offset[] = {
+       TDC_RTAB_PTR,
+       TDC_LAST_PKT_RBUF_PTRS,
+       TDC_PREF_CMD,
+       TDC_PREF_DATA,
+       TDC_PREF_PAR_DATA,
+       TDC_REORD_BUF_CMD,
+       TDC_REORD_BUF_DATA,
+       TDC_REORD_BUF_ECC_DATA,
+       TDC_REORD_TBL_CMD,
+       TDC_REORD_TBL_DATA_LO,
+       TDC_REORD_TBL_DATA_HI,
+       TDC_REORD_BUF_ECC_LOG,
+       TDC_REORD_TBL_PAR_LOG,
+       TDC_FIFO_ERR_MASK,
+       TDC_FIFO_ERR_STAT,
+       TDC_FIFO_ERR_INT_DBG,
+       TDC_PEU_TXN_LOG,
+       TDC_DBG_TRAINING_VEC,
+       TDC_DBG_GRP_SEL,
+};
+
+const char *tdc_reg_name[] = {
+       "TDC_RTAB_PTR",
+       "TDC_LAST_PKT_RBUF_PTRS",
+       "TDC_PREF_CMD",
+       "TDC_PREF_DATA",
+       "TDC_PREF_PAR_DATA",
+       "TDC_REORD_BUF_CMD",
+       "TDC_REORD_BUF_DATA",
+       "TDC_REORD_BUF_ECC_DATA",
+       "TDC_REORD_TBL_CMD",
+       "TDC_REORD_TBL_DATA_LO",
+       "TDC_REORD_TBL_DATA_HI",
+       "TDC_REORD_BUF_ECC_LOG",
+       "TDC_REORD_TBL_PAR_LOG",
+       "TDC_FIFO_ERR_MASK",
+       "TDC_FIFO_ERR_STAT",
+       "TDC_FIFO_ERR_INT_DBG",
+       "TDC_PEU_TXN_LOG",
+       "TDC_DBG_TRAINING_VEC",
+       "TDC_DBG_GRP_SEL",
+};
+
+hpi_status_t
+hpi_txdma_dump_tdc_regs(hpi_handle_t handle, uint8_t tdc)
+{
+       uint64_t value, offset;
+       int num_regs, i;
+
+       if (!TXDMA_CHANNEL_VALID(tdc)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   "hpi_txdma_dump_tdc_regs Invalid TDC number %d \n", tdc));
+
+               return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(tdc));
+       }
+
+       HPI_REG_DUMP_MSG(( HPI_REG_CTL,
+           "\nTXDMA Register Dump for Channel %d\n", tdc));
+
+       num_regs = sizeof (tdc_dmc_offset) / sizeof (uint64_t);
+       for (i = 0; i < num_regs; i++) {
+               TXDMA_REG_READ64(handle, tdc_dmc_offset[i], tdc, &value);
+               offset = HXGE_TXDMA_OFFSET(tdc_dmc_offset[i], 0,
+                   tdc);
+               HPI_REG_DUMP_MSG(( HPI_REG_CTL, "0x%08llx "
+                   "%s\t 0x%016llx \n", offset, tdc_dmc_name[i], value));
+       }
+
+       HPI_REG_DUMP_MSG(( HPI_REG_CTL,
+           "\nTXDMA Register Dump for Channel %d done\n", tdc));
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_txdma_dump_tdc_common_regs(hpi_handle_t handle)
+{
+       uint64_t value, offset;
+       int num_regs, i;
+
+       HPI_REG_DUMP_MSG(( HPI_REG_CTL,
+           "\nTXDMA Common Register Dump\n"));
+
+       num_regs = sizeof (tdc_reg_offset) / sizeof (uint64_t);
+       for (i = 0; i < num_regs; i++) {
+               offset = tdc_reg_offset[i];
+               HXGE_REG_RD64(handle, offset, &value);
+               HPI_REG_DUMP_MSG(( HPI_REG_CTL, "0x%08llx "
+                   "%s\t %016llx \n", offset, tdc_reg_name[i], value));
+       }
+
+       HPI_REG_DUMP_MSG(( HPI_REG_CTL,
+           "\nTXDMA Common Register Dump done\n"));
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_txdma_log_page_handle_set(hpi_handle_t handle, uint8_t channel,
+       tdc_page_handle_t *hdl_p)
+{
+       int status = HPI_SUCCESS;
+
+       if (!TXDMA_CHANNEL_VALID(channel)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_log_page_handle_set"
+                   " Invalid Input: channel <0x%x>", channel));
+               return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
+       }
+
+       TXDMA_REG_WRITE64(handle, TDC_PAGE_HANDLE, channel, hdl_p->value);
+
+       return (status);
+}
+
+hpi_status_t
+hpi_txdma_channel_reset(hpi_handle_t handle, uint8_t channel)
+{
+       HPI_DEBUG_MSG(( HPI_TDC_CTL,
+           " hpi_txdma_channel_reset" " RESETTING", channel));
+       return (hpi_txdma_channel_control(handle, TXDMA_RESET, channel));
+}
+
+hpi_status_t
+hpi_txdma_channel_init_enable(hpi_handle_t handle, uint8_t channel)
+{
+       return (hpi_txdma_channel_control(handle, TXDMA_INIT_START, channel));
+}
+
+hpi_status_t
+hpi_txdma_channel_enable(hpi_handle_t handle, uint8_t channel)
+{
+       return (hpi_txdma_channel_control(handle, TXDMA_START, channel));
+}
+
+hpi_status_t
+hpi_txdma_channel_disable(hpi_handle_t handle, uint8_t channel)
+{
+       return (hpi_txdma_channel_control(handle, TXDMA_STOP, channel));
+}
+
+hpi_status_t
+hpi_txdma_channel_mbox_enable(hpi_handle_t handle, uint8_t channel)
+{
+       return (hpi_txdma_channel_control(handle, TXDMA_MBOX_ENABLE, channel));
+}
+
+hpi_status_t
+hpi_txdma_channel_control(hpi_handle_t handle, txdma_cs_cntl_t control,
+       uint8_t channel)
+{
+       hpi_status_t status = HPI_SUCCESS;
+       tdc_stat_t cs;
+       tdc_tdr_cfg_t cfg;
+
+       if (!TXDMA_CHANNEL_VALID(channel)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_channel_control"
+                   " Invalid Input: channel <0x%x>", channel));
+               return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
+       }
+
+       switch (control) {
+       case TXDMA_INIT_RESET:
+               cfg.value = 0;
+               TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, &cfg.value);
+               cfg.bits.reset = 1;
+               TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, cfg.value);
+               return (hpi_txdma_control_reset_wait(handle, channel));
+
+       case TXDMA_INIT_START:
+               cfg.value = 0;
+               TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, &cfg.value);
+               cfg.bits.enable = 1;
+               TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, cfg.value);
+               break;
+
+       case TXDMA_RESET:
+               /*
+                * Sets reset bit only (Hardware will reset all the RW bits but
+                * leave the RO bits alone.
+                */
+               cfg.value = 0;
+               cfg.bits.reset = 1;
+               TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, cfg.value);
+               return (hpi_txdma_control_reset_wait(handle, channel));
+
+       case TXDMA_START:
+               /* Enable the DMA channel */
+               TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, &cfg.value);
+               cfg.bits.enable = 1;
+               TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, cfg.value);
+               break;
+
+       case TXDMA_STOP:
+               /* Disable the DMA channel */
+               TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, &cfg.value);
+               cfg.bits.enable = 0;
+               TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, cfg.value);
+               status = hpi_txdma_control_stop_wait(handle, channel);
+               if (status) {
+                       HPI_ERROR_MSG(( HPI_ERR_CTL,
+                           "Cannot stop channel %d (TXC hung!)", channel));
+               }
+               break;
+
+       case TXDMA_MBOX_ENABLE:
+               /*
+                * Write 1 to MB bit to enable mailbox update (cleared to 0 by
+                * hardware after update).
+                */
+               TXDMA_REG_READ64(handle, TDC_STAT, channel, &cs.value);
+               cs.bits.mb = 1;
+               TXDMA_REG_WRITE64(handle, TDC_STAT, channel, cs.value);
+               break;
+
+       default:
+               status = (HPI_FAILURE | HPI_TXDMA_OPCODE_INVALID(channel));
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_channel_control"
+                   " Invalid Input: control <0x%x>", control));
+       }
+
+       return (status);
+}
+
+hpi_status_t
+hpi_txdma_control_status(hpi_handle_t handle, io_op_t op_mode, uint8_t channel,
+       tdc_stat_t *cs_p)
+{
+       int status = HPI_SUCCESS;
+       tdc_stat_t txcs;
+
+       if (!TXDMA_CHANNEL_VALID(channel)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_control_status"
+                   " Invalid Input: channel <0x%x>", channel));
+               return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
+       }
+       switch (op_mode) {
+       case OP_GET:
+               TXDMA_REG_READ64(handle, TDC_STAT, channel, &cs_p->value);
+               break;
+
+       case OP_SET:
+               TXDMA_REG_WRITE64(handle, TDC_STAT, channel, cs_p->value);
+               break;
+
+       case OP_UPDATE:
+               TXDMA_REG_READ64(handle, TDC_STAT, channel, &txcs.value);
+               TXDMA_REG_WRITE64(handle, TDC_STAT, channel,
+                   cs_p->value | txcs.value);
+               break;
+
+       default:
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_control_status"
+                   " Invalid Input: control <0x%x>", op_mode));
+               return (HPI_FAILURE | HPI_TXDMA_OPCODE_INVALID(channel));
+       }
+
+       return (status);
+}
+
+hpi_status_t
+hpi_txdma_event_mask(hpi_handle_t handle, io_op_t op_mode, uint8_t channel,
+       tdc_int_mask_t *mask_p)
+{
+       int status = HPI_SUCCESS;
+       tdc_int_mask_t mask;
+
+       if (!TXDMA_CHANNEL_VALID(channel)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_event_mask Invalid Input: channel <0x%x>",
+                   channel));
+               return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
+       }
+       switch (op_mode) {
+       case OP_GET:
+               TXDMA_REG_READ64(handle, TDC_INT_MASK, channel, &mask_p->value);
+               break;
+
+       case OP_SET:
+               TXDMA_REG_WRITE64(handle, TDC_INT_MASK, channel, mask_p->value);
+               break;
+
+       case OP_UPDATE:
+               TXDMA_REG_READ64(handle, TDC_INT_MASK, channel, &mask.value);
+               TXDMA_REG_WRITE64(handle, TDC_INT_MASK, channel,
+                   mask_p->value | mask.value);
+               break;
+
+       default:
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_event_mask Invalid Input: eventmask <0x%x>",
+                   op_mode));
+               return (HPI_FAILURE | HPI_TXDMA_OPCODE_INVALID(channel));
+       }
+
+       return (status);
+}
+
+hpi_status_t
+hpi_tx_fifo_status(hpi_handle_t handle, io_op_t op_mode,
+                     tdc_fifo_err_stat_t *cs_p)
+{
+       int status = HPI_SUCCESS;
+
+       switch (op_mode) {
+       case OP_GET:
+               HXGE_REG_RD64(handle, TDC_FIFO_ERR_STAT, &cs_p->value);
+               break;
+
+       case OP_SET:
+               HXGE_REG_WR64(handle, TDC_FIFO_ERR_STAT, cs_p->value);
+               break;
+
+       default:
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_tx_fifo_status:"
+                   " Invalid Input: control <0x%x>", op_mode));
+               return (HPI_FAILURE | HPI_TXDMA_OPCODE_INVALID(0));
+       }
+
+       return (status);
+}
+
+hpi_status_t
+hpi_tx_fifo_mask(hpi_handle_t handle, io_op_t op_mode, 
+                   tdc_fifo_err_mask_t *mask_p)
+{
+       int status = HPI_SUCCESS;
+
+       switch (op_mode) {
+       case OP_GET:
+               HXGE_REG_RD64(handle, TDC_FIFO_ERR_MASK, &mask_p->value);
+               break;
+
+       case OP_SET:
+               HXGE_REG_WR64(handle, TDC_FIFO_ERR_MASK, mask_p->value);
+               break;
+
+       default:
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_tx_fifo_mask: Invalid Input: eventmask <0x%x>",
+                   op_mode));
+               return (HPI_FAILURE | HPI_TXDMA_OPCODE_INVALID(0));
+       }
+
+       return (status);
+}
+
+/*
+ * This function is called to mask out the packet transmit marked event.
+ */
+hpi_status_t
+hpi_txdma_event_mask_mk_out(hpi_handle_t handle, uint8_t channel)
+{
+       tdc_int_mask_t event_mask;
+       int status = HPI_SUCCESS;
+
+       if (!TXDMA_CHANNEL_VALID(channel)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_event_mask_mk_out"
+                   " Invalid Input: channel <0x%x>", channel));
+               return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
+       }
+       TXDMA_REG_READ64(handle, TDC_INT_MASK, channel, &event_mask.value);
+       TXDMA_REG_WRITE64(handle, TDC_INT_MASK, channel,
+           (event_mask.value & ~TDC_INT_MASK_MK_MASK));
+
+       return (status);
+}
+
+/*
+ * This function is called to set the mask for the the packet marked event.
+ */
+hpi_status_t
+hpi_txdma_event_mask_mk_in(hpi_handle_t handle, uint8_t channel)
+{
+       tdc_int_mask_t event_mask;
+       int status = HPI_SUCCESS;
+
+       if (!TXDMA_CHANNEL_VALID(channel)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_event_mask_mk_in"
+                   " Invalid Input: channel <0x%x>", channel));
+               return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
+       }
+       TXDMA_REG_READ64(handle, TDC_INT_MASK, channel, &event_mask.value);
+       TXDMA_REG_WRITE64(handle, TDC_INT_MASK, channel,
+           (event_mask.value | TDC_INT_MASK_MK_MASK));
+
+       return (status);
+}
+
+/*
+ * This function is called to configure the transmit descriptor
+ * ring address and its size.
+ */
+hpi_status_t
+hpi_txdma_ring_addr_set(hpi_handle_t handle, uint8_t channel,
+       uint64_t start_addr, uint32_t len)
+{
+       int status = HPI_SUCCESS;
+       tdc_tdr_cfg_t cfg;
+
+       if (!TXDMA_CHANNEL_VALID(channel)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_ring_addr_set"
+                   " Invalid Input: channel <0x%x>", channel));
+               return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
+       }
+       cfg.value = ((start_addr & TDC_TDR_CFG_ADDR_MASK) |
+           (((uint64_t)len) << TDC_TDR_CFG_LEN_SHIFT));
+       TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, cfg.value);
+
+       return (status);
+}
+
+hpi_status_t
+hpi_txdma_ring_config(hpi_handle_t handle, io_op_t op_mode,
+       uint8_t channel, uint64_t *reg_data)
+{
+       int status = HPI_SUCCESS;
+
+       if (!TXDMA_CHANNEL_VALID(channel)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_ring_config"
+                   " Invalid Input: channel <0x%x>", channel));
+               return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
+       }
+       switch (op_mode) {
+       case OP_GET:
+               TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, reg_data);
+               break;
+
+       case OP_SET:
+               TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, *reg_data);
+               break;
+
+       default:
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_ring_config"
+                   " Invalid Input: ring_config <0x%x>", op_mode));
+               return (HPI_FAILURE | HPI_TXDMA_OPCODE_INVALID(channel));
+       }
+
+       return (status);
+}
+
+hpi_status_t
+hpi_txdma_mbox_config(hpi_handle_t handle, io_op_t op_mode,
+       uint8_t channel, uint64_t *mbox_addr)
+{
+       int status = HPI_SUCCESS;
+       tdc_mbh_t mh;
+       tdc_mbl_t ml;
+
+       if (!TXDMA_CHANNEL_VALID(channel)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_mbox_config Invalid Input: channel <0x%x>",
+                   channel));
+               return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
+       }
+
+       mh.value = ml.value = 0;
+
+       switch (op_mode) {
+       case OP_GET:
+               TXDMA_REG_READ64(handle, TDC_MBH, channel, &mh.value);
+               TXDMA_REG_READ64(handle, TDC_MBL, channel, &ml.value);
+               *mbox_addr = ml.value;
+               *mbox_addr |= (mh.value << TDC_MBH_ADDR_SHIFT);
+
+               break;
+
+       case OP_SET:
+               ml.bits.mbaddr = ((*mbox_addr & TDC_MBL_MASK) >> TDC_MBL_SHIFT);
+               TXDMA_REG_WRITE64(handle, TDC_MBL, channel, ml.value);
+               mh.bits.mbaddr = ((*mbox_addr >> TDC_MBH_ADDR_SHIFT) &
+                   TDC_MBH_MASK);
+               TXDMA_REG_WRITE64(handle, TDC_MBH, channel, mh.value);
+               break;
+
+       default:
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_mbox_config Invalid Input: mbox <0x%x>",
+                   op_mode));
+               return (HPI_FAILURE | HPI_TXDMA_OPCODE_INVALID(channel));
+       }
+
+       return (status);
+}
+
+/*
+ * This function is called to set up a transmit descriptor entry.
+ */
+hpi_status_t
+hpi_txdma_desc_gather_set(hpi_handle_t handle, p_tx_desc_t desc_p,
+       uint8_t gather_index, boolean_t mark, uint8_t ngathers,
+       uint64_t dma_ioaddr, uint32_t transfer_len)
+{
+       hpi_status_t status;
+
+       status = HPI_TXDMA_GATHER_INDEX(gather_index);
+       if (status) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_desc_gather_set"
+                   " Invalid Input: gather_index <0x%x>", gather_index));
+               return (status);
+       }
+       if (transfer_len > TX_MAX_TRANSFER_LENGTH) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_desc_gather_set"
+                   " Invalid Input: tr_len <0x%x>", transfer_len));
+               return (HPI_FAILURE | HPI_TXDMA_XFER_LEN_INVALID);
+       }
+       if (gather_index == 0) {
+               desc_p->bits.sop = 1;
+               desc_p->bits.mark = mark;
+               desc_p->bits.num_ptr = ngathers;
+               HPI_DEBUG_MSG(( HPI_TDC_CTL,
+                   "hpi_txdma_gather_set: SOP len %d (%d)",
+                   desc_p->bits.tr_len, transfer_len));
+       }
+       desc_p->bits.tr_len = transfer_len;
+       desc_p->bits.sad = dma_ioaddr;
+
+       HPI_DEBUG_MSG(( HPI_TDC_CTL,
+           "hpi_txdma_gather_set: xfer len %d to set (%d)",
+           desc_p->bits.tr_len, transfer_len));
+
+       HXGE_MEM_PIO_WRITE64(handle, desc_p->value);
+
+       return (status);
+}
+
+/*
+ * This function is called to set up the first gather entry.
+ */
+hpi_status_t
+hpi_txdma_desc_gather_sop_set(hpi_handle_t handle, p_tx_desc_t desc_p,
+       boolean_t mark_mode, uint8_t ngathers)
+{
+       hpi_status_t status = HPI_SUCCESS;
+
+       desc_p->bits.sop = 1;
+       desc_p->bits.mark = mark_mode;
+       desc_p->bits.num_ptr = ngathers;
+
+       HXGE_MEM_PIO_WRITE64(handle, desc_p->value);
+
+       return (status);
+}
+
+hpi_status_t
+hpi_txdma_desc_gather_sop_set_1(hpi_handle_t handle, p_tx_desc_t desc_p,
+       boolean_t mark_mode, uint8_t ngathers, uint32_t extra)
+{
+       int status = HPI_SUCCESS;
+
+       desc_p->bits.sop = 1;
+       desc_p->bits.mark = mark_mode;
+       desc_p->bits.num_ptr = ngathers;
+       desc_p->bits.tr_len += extra;
+
+       HXGE_MEM_PIO_WRITE64(handle, desc_p->value);
+
+       return (status);
+}
+
+hpi_status_t
+hpi_txdma_desc_set_xfer_len(hpi_handle_t handle, p_tx_desc_t desc_p,
+       uint32_t transfer_len)
+{
+       int status = HPI_SUCCESS;
+
+       desc_p->bits.tr_len = transfer_len;
+
+       HPI_DEBUG_MSG(( HPI_TDC_CTL,
+           "hpi_set_xfer_len: len %d (%d)",
+           desc_p->bits.tr_len, transfer_len));
+
+       HXGE_MEM_PIO_WRITE64(handle, desc_p->value);
+
+       return (status);
+}
+
+hpi_status_t
+hpi_txdma_desc_set_zero(hpi_handle_t handle, uint16_t entries)
+{
+       uint32_t offset;
+       int i;
+
+       /*
+        * Assume no wrapped around.
+        */
+       offset = 0;
+       for (i = 0; i < entries; i++) {
+               HXGE_REG_WR64(handle, offset, 0);
+               offset += (i * (sizeof (tx_desc_t)));
+       }
+
+       return (HPI_SUCCESS);
+}
+
+
+hpi_status_t
+hpi_txdma_desc_mem_get(hpi_handle_t handle, uint16_t index,
+       p_tx_desc_t desc_p)
+{
+       int status = HPI_SUCCESS;
+
+       hpi_txdma_dump_desc_one(handle, desc_p, index);
+
+       return (status);
+}
+
+/*
+ * This function is called to kick the transmit  to start transmission.
+ */
+hpi_status_t
+hpi_txdma_desc_kick_reg_set(hpi_handle_t handle, uint8_t channel,
+       uint16_t tail_index, boolean_t wrap)
+{
+       int status = HPI_SUCCESS;
+       tdc_tdr_kick_t kick;
+
+       if (!TXDMA_CHANNEL_VALID(channel)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_desc_kick_reg_set"
+                   " Invalid Input: channel <0x%x>", channel));
+               return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
+       }
+       HPI_DEBUG_MSG(( HPI_TDC_CTL,
+           " hpi_txdma_desc_kick_reg_set: KICKING channel %d", channel));
+
+       /* Toggle the wrap around bit */
+       kick.value = 0;
+       kick.bits.wrap = wrap;
+       kick.bits.tail = tail_index;
+
+       /* Kick start the Transmit kick register */
+       TXDMA_REG_WRITE64(handle, TDC_TDR_KICK, channel, kick.value);
+
+       return (status);
+}
+
+/*
+ * This function is called to kick the transmit  to start transmission.
+ */
+hpi_status_t
+hpi_txdma_desc_kick_reg_get(hpi_handle_t handle, uint8_t channel,
+       tdc_tdr_kick_t *kick_p)
+{
+       int status = HPI_SUCCESS;
+
+       if (!TXDMA_CHANNEL_VALID(channel)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_desc_kick_reg_get"
+                   " Invalid Input: channel <0x%x>", channel));
+               return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
+       }
+       TXDMA_REG_READ64(handle, TDC_TDR_KICK, channel, &kick_p->value);
+
+       return (status);
+}
+
+/*
+ * This function is called to get the transmit ring head index.
+ */
+hpi_status_t
+hpi_txdma_ring_head_get(hpi_handle_t handle, uint8_t channel,
+       tdc_tdr_head_t *hdl_p)
+{
+       int status = HPI_SUCCESS;
+
+       if (!TXDMA_CHANNEL_VALID(channel)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_ring_head_get"
+                   " Invalid Input: channel <0x%x>", channel));
+               return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
+       }
+       TXDMA_REG_READ64(handle, TDC_TDR_HEAD, channel, &hdl_p->value);
+
+       return (status);
+}
+
+/*ARGSUSED*/
+hpi_status_t
+hpi_txdma_channel_mbox_get(hpi_handle_t handle, uint8_t channel,
+       p_txdma_mailbox_t mbox_p)
+{
+       int status = HPI_SUCCESS;
+
+       return (status);
+}
+
+hpi_status_t
+hpi_txdma_channel_pre_state_get(hpi_handle_t handle, uint8_t channel,
+       tdc_tdr_pre_head_t *prep)
+{
+       int status = HPI_SUCCESS;
+
+       if (!TXDMA_CHANNEL_VALID(channel)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_txdma_channel_pre_state_get"
+                   " Invalid Input: channel <0x%x>", channel));
+               return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
+       }
+       TXDMA_REG_READ64(handle, TDC_TDR_PRE_HEAD, channel, &prep->value);
+
+       return (status);
+}
+
+/*
+ * Dumps the contents of transmit descriptors.
+ */
+/*ARGSUSED*/
+void
+hpi_txdma_dump_desc_one(hpi_handle_t handle, p_tx_desc_t desc_p, int desc_index)
+{
+       tx_desc_t desc, *desp;
+
+#ifdef HXGE_DEBUG
+       uint64_t sad;
+       int xfer_len;
+#endif
+
+       HPI_DEBUG_MSG(( HPI_TDC_CTL,
+           "\n==> hpi_txdma_dump_desc_one: dump "
+           " desc_p $%p descriptor entry %d\n", desc_p, desc_index));
+       desc.value = 0;
+       desp = ((desc_p != NULL) ? desc_p : (p_tx_desc_t)&desc);
+       desp->value = HXGE_MEM_PIO_READ64(handle);
+#ifdef HXGE_DEBUG
+       sad = desp->bits.sad;
+       xfer_len = desp->bits.tr_len;
+#endif
+       HPI_DEBUG_MSG(( HPI_TDC_CTL, "\n\t: value 0x%llx\n"
+           "\t\tsad $%p\ttr_len %d len %d\tnptrs %d\tmark %d sop %d\n",
+           desp->value, sad, desp->bits.hdw.tr_len, xfer_len,
+           desp->bits.hdw.num_ptr, desp->bits.hdw.mark, desp->bits.hdw.sop));
+
+       HPI_DEBUG_MSG(( HPI_TDC_CTL,
+           "\n<== hpi_txdma_dump_desc_one: Done \n"));
+}
+
+/*ARGSUSED*/
+void
+hpi_txdma_dump_hdr(hpi_handle_t handle, p_tx_pkt_header_t hdrp)
+{
+       HPI_DEBUG_MSG(( HPI_TDC_CTL,
+           "\n==> hpi_txdma_dump_hdr: dump\n"));
+       HPI_DEBUG_MSG(( HPI_TDC_CTL,
+           "\n\t: value 0x%llx\n"
+           "\t\tpkttype 0x%x\tip_ver %d\tllc %d\tvlan %d \tihl %d\n"
+           "\t\tl3start %d\tl4start %d\tl4stuff %d\n"
+           "\t\txferlen %d\tpad %d\n",
+           hdrp->value,
+           hdrp->bits.hdw.cksum_en_pkt_type,
+           hdrp->bits.hdw.ip_ver,
+           hdrp->bits.hdw.llc,
+           hdrp->bits.hdw.vlan,
+           hdrp->bits.hdw.ihl,
+           hdrp->bits.hdw.l3start,
+           hdrp->bits.hdw.l4start,
+           hdrp->bits.hdw.l4stuff,
+           hdrp->bits.ldw.tot_xfer_len,
+           hdrp->bits.ldw.pad));
+
+       HPI_DEBUG_MSG(( HPI_TDC_CTL,
+           "\n<== hpi_txdma_dump_hdr: Done \n"));
+}
+
+/*
+ * Static functions start here.
+ */
+hpi_status_t
+hpi_txdma_control_reset_wait(hpi_handle_t handle, uint8_t channel)
+{
+       tdc_tdr_cfg_t txcs;
+       int loop = 0;
+
+       txcs.value = 0;
+       do {
+               TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, &txcs.value);
+
+               /*
+                * Reset completes when this bit is set to 1 by hw
+                */
+               if (txcs.bits.qst) {
+                       return (HPI_SUCCESS);
+               }
+               HXGE_DELAY(TXDMA_WAIT_USEC);
+               loop++;
+       } while (loop < TXDMA_WAIT_LOOP);
+
+       if (loop == TXDMA_WAIT_LOOP) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   "hpi_txdma_control_reset_wait: RST bit not "
+                   "cleared to 0 txcs.bits 0x%llx", txcs.value));
+               return (HPI_FAILURE | HPI_TXDMA_RESET_FAILED);
+       }
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_txdma_control_stop_wait(hpi_handle_t handle, uint8_t channel)
+{
+       tdc_tdr_cfg_t txcs;
+       int loop = 0;
+
+       do {
+               txcs.value = 0;
+               TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, &txcs.value);
+               if (txcs.bits.qst) {
+                       return (HPI_SUCCESS);
+               }
+               HXGE_DELAY(TXDMA_WAIT_USEC);
+               loop++;
+       } while (loop < TXDMA_WAIT_LOOP);
+
+       if (loop == TXDMA_WAIT_LOOP) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   "hpi_txdma_control_stop_wait: SNG_STATE not "
+                   "set to 1 txcs.bits 0x%llx", txcs.value));
+               return (HPI_FAILURE | HPI_TXDMA_STOP_FAILED);
+       }
+       return (HPI_SUCCESS);
+}
diff --git a/drivers/net/hxge/hpi/hpi_txdma.h b/drivers/net/hxge/hpi/hpi_txdma.h
new file mode 100644 (file)
index 0000000..c08fbaa
--- /dev/null
@@ -0,0 +1,166 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#ifndef _HPI_TXDMA_H
+#define        _HPI_TXDMA_H
+
+#include "hpi.h"
+#include "../hxge_defs.h"
+#include "../hxge_txdma_hw.h"
+#include "../hxge_tdc_hw.h"
+
+typedef        enum _txdma_cs_cntl_e {
+       TXDMA_INIT_RESET        = 0x1,
+       TXDMA_INIT_START        = 0x2,
+       TXDMA_START             = 0x3,
+       TXDMA_RESET             = 0x4,
+       TXDMA_STOP              = 0x5,
+       TXDMA_MBOX_ENABLE       = 0x6
+} txdma_cs_cntl_t;
+
+#define        HXGE_TXDMA_OFFSET(x, v, channel) (x + \
+               (!v ? DMC_OFFSET(channel) : TDMC_PIOVADDR_OFFSET(channel)))
+/*
+ * PIO macros to read and write the transmit registers.
+ */
+#define        TXDMA_REG_READ64(handle, reg, channel, val_p)   \
+               HXGE_REG_RD64(handle, \
+               (HXGE_TXDMA_OFFSET(reg, 0, channel)), val_p)
+
+#define        TXDMA_REG_WRITE64(handle, reg, channel, data)   \
+               HXGE_REG_WR64(handle, \
+               HXGE_TXDMA_OFFSET(reg, 0, channel), data)
+
+#define        HPI_TXDMA_GATHER_INDEX(index)   \
+               ((index <= TX_MAX_GATHER_POINTERS)) ? HPI_SUCCESS : \
+               (HPI_TXDMA_GATHER_INVALID)
+
+/*
+ * Transmit HPI error codes
+ */
+#define        TXDMA_ER_ST                     (TXDMA_BLK_ID << HPI_BLOCK_ID_SHIFT)
+#define        TXDMA_ID_SHIFT(n)               (n << HPI_PORT_CHAN_SHIFT)
+
+#define        TXDMA_HW_STOP_FAILED            (HPI_BK_HW_ER_START | 0x1)
+#define        TXDMA_HW_RESUME_FAILED          (HPI_BK_HW_ER_START | 0x2)
+
+#define        TXDMA_GATHER_INVALID            (HPI_BK_ERROR_START | 0x1)
+#define        TXDMA_XFER_LEN_INVALID          (HPI_BK_ERROR_START | 0x2)
+
+#define        HPI_TXDMA_OPCODE_INVALID(n)     (TXDMA_ID_SHIFT(n) |    \
+                                       TXDMA_ER_ST | OPCODE_INVALID)
+
+#define        HPI_TXDMA_FUNC_INVALID(n)       (TXDMA_ID_SHIFT(n) |    \
+                                       TXDMA_ER_ST | PORT_INVALID)
+#define        HPI_TXDMA_CHANNEL_INVALID(n)    (TXDMA_ID_SHIFT(n) |    \
+                                       TXDMA_ER_ST | CHANNEL_INVALID)
+
+#define        HPI_TXDMA_PAGE_INVALID(n)       (TXDMA_ID_SHIFT(n) |    \
+                                       TXDMA_ER_ST | LOGICAL_PAGE_INVALID)
+
+#define        HPI_TXDMA_REGISTER_INVALID      (TXDMA_ER_ST | REGISTER_INVALID)
+#define        HPI_TXDMA_COUNTER_INVALID       (TXDMA_ER_ST | COUNTER_INVALID)
+#define        HPI_TXDMA_CONFIG_INVALID        (TXDMA_ER_ST | CONFIG_INVALID)
+
+
+#define        HPI_TXDMA_GATHER_INVALID        (TXDMA_ER_ST | TXDMA_GATHER_INVALID)
+#define        HPI_TXDMA_XFER_LEN_INVALID      (TXDMA_ER_ST | TXDMA_XFER_LEN_INVALID)
+
+#define        HPI_TXDMA_RESET_FAILED          (TXDMA_ER_ST | RESET_FAILED)
+#define        HPI_TXDMA_STOP_FAILED           (TXDMA_ER_ST | TXDMA_HW_STOP_FAILED)
+#define        HPI_TXDMA_RESUME_FAILED         (TXDMA_ER_ST | TXDMA_HW_RESUME_FAILED)
+
+/*
+ * Transmit DMA Channel HPI Prototypes.
+ */
+hpi_status_t hpi_txdma_log_page_handle_set(hpi_handle_t handle,
+       uint8_t channel, tdc_page_handle_t *hdl_p);
+hpi_status_t hpi_txdma_channel_reset(hpi_handle_t handle, uint8_t channel);
+hpi_status_t hpi_txdma_channel_init_enable(hpi_handle_t handle,
+               uint8_t channel);
+hpi_status_t hpi_txdma_channel_enable(hpi_handle_t handle, uint8_t channel);
+hpi_status_t hpi_txdma_channel_disable(hpi_handle_t handle, uint8_t channel);
+hpi_status_t hpi_txdma_channel_mbox_enable(hpi_handle_t handle,
+               uint8_t channel);
+hpi_status_t hpi_txdma_channel_control(hpi_handle_t handle,
+               txdma_cs_cntl_t control, uint8_t channel);
+hpi_status_t hpi_txdma_control_status(hpi_handle_t handle, io_op_t op_mode,
+               uint8_t channel, tdc_stat_t *cs_p);
+
+hpi_status_t hpi_txdma_event_mask(hpi_handle_t handle, io_op_t op_mode,
+               uint8_t channel, tdc_int_mask_t *mask_p);
+hpi_status_t hpi_tx_fifo_status(hpi_handle_t handle, io_op_t op_mode,
+                     tdc_fifo_err_stat_t *cs_p);
+hpi_status_t hpi_tx_fifo_mask(hpi_handle_t handle, io_op_t op_mode, 
+                   tdc_fifo_err_mask_t *mask_p);
+
+hpi_status_t hpi_txdma_event_mask_mk_out(hpi_handle_t handle, uint8_t channel);
+hpi_status_t hpi_txdma_event_mask_mk_in(hpi_handle_t handle, uint8_t channel);
+
+hpi_status_t hpi_txdma_ring_addr_set(hpi_handle_t handle, uint8_t channel,
+               uint64_t start_addr, uint32_t len);
+hpi_status_t hpi_txdma_ring_config(hpi_handle_t handle, io_op_t op_mode,
+               uint8_t channel, uint64_t *reg_data);
+hpi_status_t hpi_txdma_mbox_config(hpi_handle_t handle, io_op_t op_mode,
+               uint8_t channel, uint64_t *mbox_addr);
+hpi_status_t hpi_txdma_desc_gather_set(hpi_handle_t handle,
+               p_tx_desc_t desc_p, uint8_t gather_index,
+               boolean_t mark, uint8_t ngathers,
+               uint64_t dma_ioaddr, uint32_t transfer_len);
+
+hpi_status_t hpi_txdma_desc_gather_sop_set(hpi_handle_t handle,
+               p_tx_desc_t desc_p, boolean_t mark_mode, uint8_t ngathers);
+
+hpi_status_t hpi_txdma_desc_gather_sop_set_1(hpi_handle_t handle,
+               p_tx_desc_t desc_p, boolean_t mark_mode, uint8_t ngathers,
+               uint32_t transfer_len);
+
+hpi_status_t hpi_txdma_desc_set_xfer_len(hpi_handle_t handle,
+               p_tx_desc_t desc_p, uint32_t transfer_len);
+
+hpi_status_t hpi_txdma_desc_set_zero(hpi_handle_t handle, uint16_t entries);
+hpi_status_t hpi_txdma_desc_mem_get(hpi_handle_t handle, uint16_t index,
+               p_tx_desc_t desc_p);
+hpi_status_t hpi_txdma_desc_kick_reg_set(hpi_handle_t handle, uint8_t channel,
+               uint16_t tail_index, boolean_t wrap);
+hpi_status_t hpi_txdma_desc_kick_reg_get(hpi_handle_t handle, uint8_t channel,
+               tdc_tdr_kick_t *kick_p);
+hpi_status_t hpi_txdma_ring_head_get(hpi_handle_t handle, uint8_t channel,
+               tdc_tdr_head_t *hdl_p);
+hpi_status_t hpi_txdma_channel_mbox_get(hpi_handle_t handle, uint8_t channel,
+               p_txdma_mailbox_t mbox_p);
+hpi_status_t hpi_txdma_channel_pre_state_get(hpi_handle_t handle,
+               uint8_t channel, tdc_tdr_pre_head_t *prep);
+void hpi_txdma_dump_desc_one(hpi_handle_t handle, p_tx_desc_t desc_p,
+       int desc_index);
+hpi_status_t hpi_txdma_dump_tdc_regs(hpi_handle_t handle, uint8_t tdc);
+hpi_status_t hpi_txdma_dump_tdc_common_regs(hpi_handle_t handle);
+hpi_status_t hpi_txdma_control_reset_wait(hpi_handle_t handle,
+        uint8_t channel);
+hpi_status_t hpi_txdma_control_stop_wait(hpi_handle_t handle,
+       uint8_t channel);
+
+
+#endif /* _HPI_TXDMA_H */
diff --git a/drivers/net/hxge/hpi/hpi_vir.c b/drivers/net/hxge/hpi/hpi_vir.c
new file mode 100644 (file)
index 0000000..a3c61a1
--- /dev/null
@@ -0,0 +1,309 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#include       "hpi_vir.h"
+
+/* One register only */
+uint32_t fzc_pio_offset[] = {
+       LD_INTR_TIM_RES
+};
+
+const char *fzc_pio_name[] = {
+       "LD_INTR_TIM_RES"
+};
+
+/* 32 logical devices */
+uint32_t fzc_pio_ldgnum_offset[] = {
+       LD_GRP_CTRL
+};
+
+const char *fzc_pio_ldgnum_name[] = {
+       "LD_GRP_CTRL"
+};
+
+/* PIO_LDSV, 32 sets by 8192 bytes */
+uint32_t pio_ldsv_offset[] = {
+       LDSV0,
+       LDSV1,
+       LD_INTR_MGMT
+};
+const char *pio_ldsv_name[] = {
+       "LDSV0",
+       "LDSV1",
+       "LD_INTR_MGMT"
+};
+
+/* PIO_IMASK0: 32 by 8192 */
+uint32_t pio_imask0_offset[] = {
+       LD_INTR_MASK,
+};
+
+const char *pio_imask0_name[] = {
+       "LD_INTR_MASK",
+};
+
+/*
+ * Set up a logical group number that a logical device belongs to.
+ */
+hpi_status_t
+hpi_fzc_ldg_num_set(hpi_handle_t handle, uint8_t ld, uint8_t ldg)
+{
+       ld_grp_ctrl_t   gnum;
+
+       if (!LD_VALID(ld)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_fzc_ldg_num_set ld <0x%x>", ld));
+               return (HPI_FAILURE | HPI_VIR_LD_INVALID(ld));
+       }
+
+       if (!LDG_VALID(ldg)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_fzc_ldg_num_set ldg <0x%x>", ldg));
+               return (HPI_FAILURE | HPI_VIR_LDG_INVALID(ld));
+       }
+
+       gnum.value = 0;
+       gnum.bits.num = ldg;
+
+       HXGE_REG_WR32(handle, LD_GRP_CTRL + LD_NUM_OFFSET(ld), gnum.value);
+
+       return (HPI_SUCCESS);
+}
+
+/*
+ * Get device state vectors.
+ */
+hpi_status_t
+hpi_ldsv_ldfs_get(hpi_handle_t handle, uint8_t ldg, uint32_t *vector0_p,
+       uint32_t *vector1_p)
+{
+       hpi_status_t status;
+
+       if ((status = hpi_ldsv_get(handle, ldg, VECTOR0, vector0_p))) {
+               return (status);
+       }
+       if ((status = hpi_ldsv_get(handle, ldg, VECTOR1, vector1_p))) {
+               return (status);
+       }
+
+       return (HPI_SUCCESS);
+}
+
+/*
+ * Get device state vectors.
+ */
+hpi_status_t
+hpi_ldsv_get(hpi_handle_t handle, uint8_t ldg, ldsv_type_t vector,
+       uint32_t *ldf_p)
+{
+       uint32_t        offset;
+
+       if (!LDG_VALID(ldg)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_ldsv_get Invalid Input ldg <0x%x>", ldg));
+               return (HPI_FAILURE | HPI_VIR_LDG_INVALID(ldg));
+       }
+
+       switch (vector) {
+       case VECTOR0:
+               offset = LDSV0 + LDSV_OFFSET(ldg);
+               break;
+
+       case VECTOR1:
+               offset = LDSV1 + LDSV_OFFSET(ldg);
+               break;
+
+       default:
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_ldsv_get Invalid Input: ldsv type <0x%x>", vector));
+               return (HPI_FAILURE | HPI_VIR_LDSV_INVALID(vector));
+       }
+
+       HXGE_REG_RD32(handle, offset, ldf_p);
+
+       return (HPI_SUCCESS);
+}
+
+/*
+ * Set the mask bits for both ldf0 and ldf1.
+ */
+hpi_status_t
+hpi_intr_mask_set(hpi_handle_t handle, uint8_t ld, uint8_t ldf_mask)
+{
+       uint32_t        offset;
+
+       if (!LD_VALID(ld)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_intr_mask_set ld", ld));
+               return (HPI_FAILURE | HPI_VIR_LD_INVALID(ld));
+       }
+
+       ldf_mask &= LD_IM_MASK;
+       offset = LDSV_OFFSET_MASK(ld);
+
+       HPI_DEBUG_MSG(( HPI_VIR_CTL,
+           "hpi_intr_mask_set: ld %d offset 0x%0x mask 0x%x",
+           ld, offset, ldf_mask));
+
+       HXGE_REG_WR32(handle, offset, (uint32_t)ldf_mask);
+
+       return (HPI_SUCCESS);
+}
+
+/*
+ * Set interrupt timer and arm bit.
+ */
+hpi_status_t
+hpi_intr_ldg_mgmt_set(hpi_handle_t handle, uint8_t ldg, boolean_t arm,
+       uint8_t timer)
+{
+       ld_intr_mgmt_t  mgm;
+
+       if (!LDG_VALID(ldg)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_intr_ldg_mgmt_set Invalid Input: ldg <0x%x>", ldg));
+               return (HPI_FAILURE | HPI_VIR_LDG_INVALID(ldg));
+       }
+
+       if (!LD_INTTIMER_VALID(timer)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_intr_ldg_mgmt_set Invalid Input"
+                   " timer <0x%x>", timer));
+               return (HPI_FAILURE | HPI_VIR_INTM_TM_INVALID(ldg));
+       }
+
+       if (arm) {
+               mgm.bits.arm = 1;
+       } else {
+               HXGE_REG_RD32(handle, LD_INTR_MGMT + LDSV_OFFSET(ldg),
+                   &mgm.value);
+       }
+
+       mgm.bits.timer = timer;
+       HXGE_REG_WR32(handle, LD_INTR_MGMT + LDSV_OFFSET(ldg), mgm.value);
+
+       HPI_DEBUG_MSG(( HPI_VIR_CTL,
+           " hpi_intr_ldg_mgmt_set: ldg %d reg offset 0x%x",
+           ldg, LD_INTR_MGMT + LDSV_OFFSET(ldg)));
+
+       return (HPI_SUCCESS);
+}
+
+/*
+ * Arm the group.
+ */
+hpi_status_t
+hpi_intr_ldg_mgmt_arm(hpi_handle_t handle, uint8_t ldg)
+{
+       ld_intr_mgmt_t  mgm;
+
+       if (!LDG_VALID(ldg)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_intr_ldg_mgmt_arm Invalid Input: ldg <0x%x>", ldg));
+               return (HPI_FAILURE | HPI_VIR_LDG_INVALID(ldg));
+       }
+
+       HXGE_REG_RD32(handle, (LD_INTR_MGMT + LDSV_OFFSET(ldg)), &mgm.value);
+       mgm.bits.arm = 1;
+
+       HXGE_REG_WR32(handle, LD_INTR_MGMT + LDSV_OFFSET(ldg), mgm.value);
+       HPI_DEBUG_MSG(( HPI_VIR_CTL,
+           " hpi_intr_ldg_mgmt_arm: ldg %d reg offset 0x%x",
+           ldg, LD_INTR_MGMT + LDSV_OFFSET(ldg)));
+
+       return (HPI_SUCCESS);
+}
+
+/*
+ * Set the timer resolution.
+ */
+hpi_status_t
+hpi_fzc_ldg_timer_res_set(hpi_handle_t handle, uint32_t res)
+{
+       ld_intr_tim_res_t       tm;
+
+       if (res > LDGTITMRES_RES_MASK) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_fzc_ldg_timer_res_set Invalid Input: res <0x%x>",
+                   res));
+               return (HPI_FAILURE | HPI_VIR_TM_RES_INVALID);
+       }
+
+       tm.value = 0;
+       tm.bits.res = res;
+
+       HXGE_REG_WR32(handle, LD_INTR_TIM_RES, tm.value);
+
+       return (HPI_SUCCESS);
+}
+
+/*
+ * Set the system interrupt data.
+ */
+hpi_status_t
+hpi_fzc_sid_set(hpi_handle_t handle, fzc_sid_t sid)
+{
+       sid_t   sd;
+
+       if (!LDG_VALID(sid.ldg)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_fzc_sid_set Invalid Input: ldg <0x%x>", sid.ldg));
+               return (HPI_FAILURE | HPI_VIR_LDG_INVALID(sid.ldg));
+       }
+
+       if (!SID_VECTOR_VALID(sid.vector)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_fzc_sid_set Invalid Input: vector <0x%x>",
+                   sid.vector));
+
+#if defined(SOLARIS) && defined(_KERNEL) && defined(HPI_DEBUG)
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " invalid VECTOR: hpi_fzc_sid_set(%d)", sid.vector));
+#endif
+               return (HPI_FAILURE | HPI_VIR_SID_VEC_INVALID(sid.vector));
+       }
+
+       sd.value = 0;
+       sd.bits.data = sid.vector;
+
+#if defined(SOLARIS) && defined(_KERNEL) && defined(HPI_DEBUG)
+       HPI_ERROR_MSG(( HPI_ERR_CTL,
+           " hpi_fzc_sid_set: group %d 0x%x", sid.ldg, sd.value));
+#endif
+
+       HXGE_REG_WR32(handle,  SID + LDG_SID_OFFSET(sid.ldg), sd.value);
+
+       return (HPI_SUCCESS);
+}
+
+/*
+ * Get the system error stats.
+ */
+hpi_status_t
+hpi_fzc_sys_err_stat_get(hpi_handle_t handle, dev_err_stat_t *statp)
+{
+       HXGE_REG_RD32(handle,  DEV_ERR_STAT, &statp->value);
+       return (HPI_SUCCESS);
+}
diff --git a/drivers/net/hxge/hpi/hpi_vir.h b/drivers/net/hxge/hpi/hpi_vir.h
new file mode 100644 (file)
index 0000000..e45d2bf
--- /dev/null
@@ -0,0 +1,118 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#ifndef _HPI_VIR_H
+#define        _HPI_VIR_H
+
+#include "hpi.h"
+#include "../hxge_peu_hw.h"
+
+/*
+ * Virtualization and Logical devices HPI error codes
+ */
+#define        VIR_ERR_ST              (VIR_BLK_ID << HPI_BLOCK_ID_SHIFT)
+#define        VIR_ID_SHIFT(n)         (n << HPI_PORT_CHAN_SHIFT)
+
+#define        VIR_LD_INVALID          (HPI_BK_ERROR_START | 0x30)
+#define        VIR_LDG_INVALID         (HPI_BK_ERROR_START | 0x31)
+#define        VIR_LDSV_INVALID        (HPI_BK_ERROR_START | 0x32)
+
+#define        VIR_INTM_TM_INVALID     (HPI_BK_ERROR_START | 0x33)
+#define        VIR_TM_RES_INVALID      (HPI_BK_ERROR_START | 0x34)
+#define        VIR_SID_VEC_INVALID     (HPI_BK_ERROR_START | 0x35)
+
+/*
+ * Error codes of logical devices and groups functions.
+ */
+#define        HPI_VIR_LD_INVALID(n)   (VIR_ID_SHIFT(n) | VIR_ERR_ST | VIR_LD_INVALID)
+#define        HPI_VIR_LDG_INVALID(n)  (VIR_ID_SHIFT(n) | VIR_ERR_ST | VIR_LDG_INVALID)
+#define        HPI_VIR_LDSV_INVALID(n) (VIR_ID_SHIFT(n) | \
+                                       VIR_ERR_ST | VIR_LDSV_INVALID)
+#define        HPI_VIR_INTM_TM_INVALID(n)      (VIR_ID_SHIFT(n) | \
+                                       VIR_ERR_ST | VIR_INTM_TM_INVALID)
+#define        HPI_VIR_TM_RES_INVALID          (VIR_ERR_ST | VIR_TM_RES_INVALID)
+#define        HPI_VIR_SID_VEC_INVALID(n)      (VIR_ID_SHIFT(n) | \
+                                               VIR_ERR_ST | VIR_TM_RES_INVALID)
+
+/*
+ * Logical device definitions.
+ */
+#define        LDG_NUM_STEP            4
+#define        LD_NUM_OFFSET(ld)       (ld * LDG_NUM_STEP)
+
+#define        LDSV_STEP               8192
+#define        LDSVG_OFFSET(ldg)       (ldg * LDSV_STEP)
+#define        LDSV_OFFSET(ldv)        (ldv * LDSV_STEP)
+#define        LDSV_OFFSET_MASK(ld)    (LD_INTR_MASK + LDSV_OFFSET(ld))
+
+#define        LDG_SID_STEP            8192
+#define        LDG_SID_OFFSET(ldg)     (ldg * LDG_SID_STEP)
+
+typedef enum {
+       VECTOR0,
+       VECTOR1,
+} ldsv_type_t;
+
+/*
+ * Definitions for the system interrupt data.
+ */
+typedef struct _fzc_sid {
+       uint8_t         ldg;
+       uint8_t         vector;
+} fzc_sid_t, *p_fzc_sid_t;
+
+/*
+ * Virtualization and Interrupt Prototypes.
+ */
+hpi_status_t hpi_fzc_ldg_num_set(hpi_handle_t handle, uint8_t ld, uint8_t ldg);
+hpi_status_t hpi_fzc_ldg_num_get(hpi_handle_t handle, uint8_t ld,
+       uint8_t *ldg_p);
+hpi_status_t hpi_ldsv_ldfs_get(hpi_handle_t handle, uint8_t ldg,
+       uint32_t *vector0_p, uint32_t *vecto1_p);
+hpi_status_t hpi_ldsv_get(hpi_handle_t handle, uint8_t ldg, ldsv_type_t vector,
+       uint32_t *ldf_p);
+hpi_status_t hpi_intr_mask_set(hpi_handle_t handle, uint8_t ld,
+       uint8_t ldf_mask);
+hpi_status_t hpi_intr_mask_get(hpi_handle_t handle, uint8_t ld,
+       uint8_t *ldf_mask_p);
+hpi_status_t hpi_intr_ldg_mgmt_set(hpi_handle_t handle, uint8_t ldg,
+       boolean_t arm, uint8_t timer);
+hpi_status_t hpi_intr_ldg_mgmt_timer_get(hpi_handle_t handle, uint8_t ldg,
+       uint8_t *timer_p);
+hpi_status_t hpi_intr_ldg_mgmt_arm(hpi_handle_t handle, uint8_t ldg);
+hpi_status_t hpi_fzc_ldg_timer_res_set(hpi_handle_t handle, uint32_t res);
+hpi_status_t hpi_fzc_ldg_timer_res_get(hpi_handle_t handle, uint8_t *res_p);
+hpi_status_t hpi_fzc_sid_set(hpi_handle_t handle, fzc_sid_t sid);
+hpi_status_t hpi_fzc_sid_get(hpi_handle_t handle, p_fzc_sid_t sid_p);
+hpi_status_t hpi_fzc_sys_err_mask_set(hpi_handle_t handle, uint32_t mask);
+hpi_status_t hpi_fzc_sys_err_stat_get(hpi_handle_t handle,
+                                               dev_err_stat_t *statp);
+hpi_status_t hpi_vir_dump_pio_fzc_regs_one(hpi_handle_t handle);
+hpi_status_t hpi_vir_dump_ldgnum(hpi_handle_t handle);
+hpi_status_t hpi_vir_dump_ldsv(hpi_handle_t handle);
+hpi_status_t hpi_vir_dump_imask0(hpi_handle_t handle);
+hpi_status_t hpi_vir_dump_sid(hpi_handle_t handle);
+
+#endif /* _HPI_VIR_H */
diff --git a/drivers/net/hxge/hpi/hpi_vmac.c b/drivers/net/hxge/hpi/hpi_vmac.c
new file mode 100644 (file)
index 0000000..2447b8f
--- /dev/null
@@ -0,0 +1,370 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#include "hpi_vmac.h"
+
+uint64_t vmac_offset[] = {
+       VMAC_RST,
+       VMAC_TX_CFG,
+       VMAC_RX_CFG,
+       VMAC_TX_STAT,
+       VMAC_TX_MSK,
+       VMAC_RX_STAT,
+       VMAC_RX_MSK,
+       VMAC_TX_STAT_MIRROR,
+       VMAC_RX_STAT_MIRROR,
+       VMAC_TX_FRAME_CNT,
+       VMAC_TX_BYTE_CNT,
+       VMAC_RX_FRAME_CNT,
+       VMAC_RX_BYTE_CNT,
+       VMAC_RX_DROP_FR_CNT,
+       VMAC_RX_DROP_BYTE_CNT,
+       VMAC_RX_CRC_CNT,
+       VMAC_RX_PAUSE_CNT,
+       VMAC_RX_BCAST_FR_CNT,
+       VMAC_RX_MCAST_FR_CNT
+};
+
+const char *vmac_name[] = {
+       "VMAC_RST",
+       "VMAC_TX_CFG",
+       "VMAC_RX_CFG",
+       "VMAC_TX_STAT",
+       "VMAC_TX_MSK",
+       "VMAC_RX_STAT",
+       "VMAC_RX_MSK",
+       "VMAC_TX_STAT_MIRROR",
+       "VMAC_RX_STAT_MIRROR",
+       "VMAC_TX_FRAME_CNT",
+       "VMAC_TX_BYTE_CNT",
+       "VMAC_RX_FRAME_CNT",
+       "VMAC_RX_BYTE_CNT",
+       "VMAC_RX_DROP_FR_CNT",
+       "VMAC_RX_DROP_BYTE_CNT",
+       "VMAC_RX_CRC_CNT",
+       "VMAC_RX_PAUSE_CNT",
+       "VMAC_RX_BCAST_FR_CNT",
+       "VMAC_RX_MCAST_FR_CNT"
+};
+
+
+hpi_status_t
+hpi_vmac_dump_regs(hpi_handle_t handle)
+{
+       uint64_t value;
+       int num_regs, i;
+
+       num_regs = sizeof (vmac_offset) / sizeof (uint64_t);
+       HPI_REG_DUMP_MSG(( HPI_REG_CTL,
+           "\nVMAC Register Dump\n"));
+
+       for (i = 0; i < num_regs; i++) {
+               HXGE_REG_RD64(handle, vmac_offset[i], &value);
+               HPI_REG_DUMP_MSG(( HPI_REG_CTL,
+                       "%08llx %s\t %016llx \n",
+                       vmac_offset[i], vmac_name[i], value));
+       }
+
+       HPI_REG_DUMP_MSG(( HPI_REG_CTL,
+           "\n VMAC Register Dump done\n"));
+
+       return (HPI_SUCCESS);
+}
+
+
+hpi_status_t
+hpi_tx_vmac_reset(hpi_handle_t handle)
+{
+       vmac_rst_t      reset;
+
+       HXGE_REG_RD64(handle, VMAC_RST, &(reset.value));
+
+       reset.bits.tx_reset = 1;
+
+       HXGE_REG_WR64(handle, VMAC_RST, reset.value);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_vmac_tx_ints(hpi_handle_t handle, int enable)
+{
+       uint64_t mask = 0;
+       if (!enable)
+               mask = ~0ULL;
+        HXGE_REG_WR64(handle, VMAC_TX_MSK, mask);
+       return (HPI_SUCCESS);
+}
+
+
+hpi_status_t
+hpi_tx_vmac_clear_regs(hpi_handle_t handle)
+{
+       uint64_t val;
+
+       HXGE_REG_WR64(handle, VMAC_TX_STAT, ~0ULL); /* RW1C */
+       HXGE_REG_WR64(handle, VMAC_TX_MSK, ~0ULL); /* disable everything */
+       HXGE_REG_RD64(handle, VMAC_TX_FRAME_CNT, &val);
+       HXGE_REG_RD64(handle, VMAC_TX_BYTE_CNT, &val);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_vmac_rx_ints(hpi_handle_t handle, int enable)
+{
+       uint64_t mask = 0;
+       if (!enable)
+               mask = ~0ULL;
+       HXGE_REG_WR64(handle, VMAC_RX_MSK, mask);
+       return (HPI_SUCCESS);
+}
+
+
+
+hpi_status_t
+hpi_rx_vmac_reset(hpi_handle_t handle)
+{
+       vmac_rst_t      reset;
+
+       HXGE_REG_RD64(handle, VMAC_RST, &(reset.value));
+
+       reset.bits.rx_reset = 1;
+
+       HXGE_REG_WR64(handle, VMAC_RST, reset.value);
+       
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_rx_vmac_clear_regs(hpi_handle_t handle)
+{
+       uint64_t val;
+
+       /* Clear off the Rx registers */
+       HXGE_REG_WR64(handle, VMAC_RX_STAT, ~0ULL); /* RW1C */
+       HXGE_REG_WR64(handle, VMAC_RX_MSK, ~0ULL); /* disable everything */
+       HXGE_REG_WR64(handle, VMAC_RX_STAT_MIRROR, 0);
+       HXGE_REG_RD64(handle, VMAC_RX_FRAME_CNT, &val); /* RORC */
+       HXGE_REG_RD64(handle, VMAC_RX_BYTE_CNT, &val); /* RORC */
+       HXGE_REG_RD64(handle, VMAC_RX_DROP_FR_CNT, &val); /* RORC */
+       HXGE_REG_RD64(handle, VMAC_RX_DROP_BYTE_CNT, &val); /* RORC */
+       HXGE_REG_RD64(handle, VMAC_RX_CRC_CNT, &val); /* RORC */
+       HXGE_REG_RD64(handle, VMAC_RX_PAUSE_CNT, &val); /* RORC */
+       HXGE_REG_RD64(handle, VMAC_RX_BCAST_FR_CNT, &val);/*  RORC */
+       HXGE_REG_RD64(handle, VMAC_RX_MCAST_FR_CNT, &val); /* RORC */
+
+       return (HPI_SUCCESS);
+
+}
+
+
+hpi_status_t
+hpi_vmac_tx_config(hpi_handle_t handle, config_op_t op, uint64_t config,
+    uint16_t max_frame_length)
+{
+       vmac_tx_cfg_t   cfg;
+       hpi_status_t err = HPI_SUCCESS;
+
+       if (config == 0) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_vmac_tx_config Invalid Input: config <0x%x>",
+                   config));
+               return (HPI_FAILURE);
+       }
+
+       HXGE_REG_RD64(handle, VMAC_TX_CFG, &cfg.value);
+
+       switch (op) {
+       case ENABLE:
+               if (config & CFG_VMAC_TX_EN)
+                       cfg.bits.tx_en = 1;
+               if (config & CFG_VMAC_TX_CRC_INSERT)
+                       cfg.bits.crc_insert = 1;
+               if (config & CFG_VMAC_TX_PAD)
+                       cfg.bits.tx_pad = 1;
+
+               /* If a bad MTU was passed, then leave the old value as is
+                * and return a failure so that "ifconfig mtu" can fail 
+                */
+               if (max_frame_length  > MAX_JUMBO_FRAME_SIZE) {
+                        HPI_ERROR_MSG(( HPI_ERR_CTL,
+                 " hpi_vmac_tx_config Invalid Input: max_frame_length <0x%x>",
+                    max_frame_length));
+                   err = HPI_FAILURE;
+               }
+               else if (max_frame_length)
+                       cfg.bits.tx_max_frame_length = max_frame_length;
+               break;
+       case DISABLE:
+               if (config & CFG_VMAC_TX_EN)
+                       cfg.bits.tx_en = 0;
+               if (config & CFG_VMAC_TX_CRC_INSERT)
+                       cfg.bits.crc_insert = 0;
+               if (config & CFG_VMAC_TX_PAD)
+                       cfg.bits.tx_pad = 0;
+               break;
+       case INIT:
+               if (config & CFG_VMAC_TX_EN)
+                       cfg.bits.tx_en = 1;
+               else
+                       cfg.bits.tx_en = 0;
+
+               if (config & CFG_VMAC_TX_CRC_INSERT)
+                       cfg.bits.crc_insert = 1;
+               else
+                       cfg.bits.crc_insert = 0;
+
+               if (config & CFG_VMAC_TX_PAD)
+                       cfg.bits.tx_pad = 1;
+               else
+                       cfg.bits.tx_pad = 0;
+
+               if (max_frame_length  > MAX_JUMBO_FRAME_SIZE) {
+                        HPI_ERROR_MSG(( HPI_ERR_CTL,
+                 " hpi_vmac_tx_config Invalid Input: max_frame_length <0x%x>",
+                    max_frame_length));
+                err = HPI_FAILURE;
+               }
+               else if (max_frame_length)
+                       cfg.bits.tx_max_frame_length = max_frame_length;
+
+               break;
+       default:
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_vmac_tx_config Invalid Input: op <0x%x>", op));
+               return (HPI_FAILURE);
+       }
+
+       HXGE_REG_WR64(handle, VMAC_TX_CFG, cfg.value);
+
+       return (err);
+}
+
+hpi_status_t
+hpi_vmac_rx_config(hpi_handle_t handle, config_op_t op, uint64_t config,
+       uint16_t max_frame_length)
+{
+       vmac_rx_cfg_t cfg;
+
+       if (!config && (op != INIT)) {
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_vmac_rx_config Invalid Input: config <0x%x>",
+                   config));
+               return (HPI_FAILURE);
+       }
+
+       HXGE_REG_RD64(handle, VMAC_RX_CFG, &cfg.value);
+
+       switch (op) {
+       case ENABLE:
+               if (config & CFG_VMAC_RX_EN)
+                       cfg.bits.rx_en = 1;
+               if (config & CFG_VMAC_RX_CRC_CHECK_DISABLE)
+                       cfg.bits.crc_check_disable = 1;
+               if (config & CFG_VMAC_RX_STRIP_CRC)
+                       cfg.bits.strip_crc = 1;
+               if (config & CFG_VMAC_RX_PASS_FLOW_CTRL_FR)
+                       cfg.bits.pass_flow_ctrl_fr = 1;
+               if (config & CFG_VMAC_RX_PROMISCUOUS_GROUP)
+                       cfg.bits.promiscuous_group = 1;
+               if (config & CFG_VMAC_RX_PROMISCUOUS_MODE)
+                       cfg.bits.promiscuous_mode = 1;
+               if (config & CFG_VMAC_RX_LOOP_BACK)
+                       cfg.bits.loopback = 1;
+               break;
+       case DISABLE:
+               if (config & CFG_VMAC_RX_EN)
+                       cfg.bits.rx_en = 0;
+               if (config & CFG_VMAC_RX_CRC_CHECK_DISABLE)
+                       cfg.bits.crc_check_disable = 0;
+               if (config & CFG_VMAC_RX_STRIP_CRC)
+                       cfg.bits.strip_crc = 0;
+               if (config & CFG_VMAC_RX_PASS_FLOW_CTRL_FR)
+                       cfg.bits.pass_flow_ctrl_fr = 0;
+               if (config & CFG_VMAC_RX_PROMISCUOUS_GROUP)
+                       cfg.bits.promiscuous_group = 0;
+               if (config & CFG_VMAC_RX_PROMISCUOUS_MODE)
+                       cfg.bits.promiscuous_mode = 0;
+               if (config & CFG_VMAC_RX_LOOP_BACK)
+                       cfg.bits.loopback = 0;
+               break;
+       case INIT:
+               if (config & CFG_VMAC_RX_EN)
+                       cfg.bits.rx_en = 1;
+               else
+                       cfg.bits.rx_en = 0;
+               if (config & CFG_VMAC_RX_CRC_CHECK_DISABLE)
+                       cfg.bits.crc_check_disable = 1;
+               else
+                       cfg.bits.crc_check_disable = 0;
+               if (config & CFG_VMAC_RX_STRIP_CRC)
+                       cfg.bits.strip_crc = 1;
+               else
+                       cfg.bits.strip_crc = 0;
+               if (config & CFG_VMAC_RX_PASS_FLOW_CTRL_FR)
+                       cfg.bits.pass_flow_ctrl_fr = 1;
+               else
+                       cfg.bits.pass_flow_ctrl_fr = 0;
+               if (config & CFG_VMAC_RX_PROMISCUOUS_GROUP)
+                       cfg.bits.promiscuous_group = 1;
+               else
+                       cfg.bits.promiscuous_group = 0;
+               if (config & CFG_VMAC_RX_PROMISCUOUS_MODE)
+                       cfg.bits.promiscuous_mode = 1;
+               else
+                       cfg.bits.promiscuous_mode = 0;
+               if (config & CFG_VMAC_RX_LOOP_BACK)
+                       cfg.bits.loopback = 1;
+               else
+                       cfg.bits.loopback = 0;
+
+               break;
+       default:
+               HPI_ERROR_MSG(( HPI_ERR_CTL,
+                   " hpi_vmac_rx_config Invalid Input: op <0x%x>", op));
+               return (HPI_FAILURE);
+       }
+       if (max_frame_length  > MAX_JUMBO_FRAME_SIZE) {
+                HPI_ERROR_MSG(( HPI_ERR_CTL,
+                    " hpi_vmac_rx_config Invalid Input: max_frame_length <0x%x>",
+                    max_frame_length));
+                return (HPI_FAILURE);
+       }
+               
+       if (max_frame_length > 0)
+               cfg.bits.rx_max_frame_length = max_frame_length;
+
+       HXGE_REG_WR64(handle, VMAC_RX_CFG, cfg.value);
+
+       return (HPI_SUCCESS);
+}
+
+hpi_status_t
+hpi_vmac_rx_set_framesize(hpi_handle_t handle, uint16_t max_frame_length)
+{
+       return(hpi_vmac_rx_config(handle, ENABLE, 0, max_frame_length));
+}
diff --git a/drivers/net/hxge/hpi/hpi_vmac.h b/drivers/net/hxge/hpi/hpi_vmac.h
new file mode 100644 (file)
index 0000000..41a2aa9
--- /dev/null
@@ -0,0 +1,59 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#ifndef _HPI_MAC_H
+#define        _HPI_MAC_H
+
+#include "hpi.h"
+#include "../hxge_vmac_hw.h"
+
+hpi_status_t hpi_tx_vmac_reset(hpi_handle_t handle);
+hpi_status_t hpi_rx_vmac_reset(hpi_handle_t handle);
+hpi_status_t hpi_vmac_rx_ints(hpi_handle_t handle, int enable);
+hpi_status_t hpi_vmac_tx_ints(hpi_handle_t handle, int enable);
+hpi_status_t hpi_tx_vmac_clear_regs(hpi_handle_t handle);
+hpi_status_t hpi_rx_vmac_clear_regs(hpi_handle_t handle);
+hpi_status_t hpi_vmac_dump_regs(hpi_handle_t handle);
+hpi_status_t hpi_vmac_tx_config(hpi_handle_t handle, config_op_t op,
+       uint64_t config, uint16_t max_frame_length);
+hpi_status_t hpi_vmac_rx_config(hpi_handle_t handle, config_op_t op,
+       uint64_t config, uint16_t max_frame_length);
+hpi_status_t hpi_vmac_rx_set_framesize(hpi_handle_t handle, 
+       uint16_t max_frame_length);
+
+
+#define        CFG_VMAC_TX_EN                  0x00000001
+#define        CFG_VMAC_TX_CRC_INSERT          0x00000002
+#define        CFG_VMAC_TX_PAD                 0x00000004
+
+#define        CFG_VMAC_RX_EN                  0x00000001
+#define        CFG_VMAC_RX_CRC_CHECK_DISABLE   0x00000002
+#define        CFG_VMAC_RX_STRIP_CRC           0x00000004
+#define        CFG_VMAC_RX_PASS_FLOW_CTRL_FR   0x00000008
+#define        CFG_VMAC_RX_PROMISCUOUS_GROUP   0x00000010
+#define        CFG_VMAC_RX_PROMISCUOUS_MODE    0x00000020
+#define        CFG_VMAC_RX_LOOP_BACK           0x00000040
+
+#endif /* _HPI_MAC_H */
diff --git a/drivers/net/hxge/hxge.h b/drivers/net/hxge/hxge.h
new file mode 100644 (file)
index 0000000..0d8efa9
--- /dev/null
@@ -0,0 +1,482 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+/* Linux Hydra 10GBe Driver main header file */
+
+#ifndef _HXGE_H_
+#define _HXGE_H_
+
+#include <linux/version.h>
+#include <linux/stddef.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/pagemap.h>
+#include <linux/dma-mapping.h>
+#include <linux/bitops.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/capability.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <net/pkt_sched.h>
+#include <linux/list.h>
+#include <linux/reboot.h>
+#ifdef NETIF_F_TSO
+#include <net/checksum.h>
+#endif
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/version.h>
+
+#include "hxge_defs.h"
+#include "hxge_pfc_hw.h"
+#include "hxge_peu_hw.h"
+#include "hxge_rxdma.h"
+#include "hxge_txdma.h"
+#include "hxge_vmac.h"
+#include "hxge_pfc.h"
+#include "hxge_classify.h"
+
+#define BAR_0          0
+#define BAR_1          1
+#define BAR_5          5
+
+#define ETHERADDRL ETH_ALEN
+#define PCI_DEVICE_ID_SUN_HYDRA 0xAAAA
+
+#define SUN_ETHERNET_DEVICE(device_id) {\
+       PCI_DEVICE(PCI_VENDOR_ID_SUN, device_id)}
+
+#define MUTEX_INIT(lock, nm, tp, arg)   spin_lock_init((lock))
+#define MUTEX_ENTER(lock)               spin_lock((lock))
+#define MUTEX_TRY_ENTER(lock)           spin_trylock((lock))
+#define MUTEX_EXIT(lock)                spin_unlock((lock))
+#define MUTEX_ENTER_INT(lock, flags)    spin_lock_irqsave(lock, flags)
+#define MUTEX_EXIT_INT(lock, flags)     spin_unlock_irqrestore(lock, flags)
+#define MUTEX_DESTROY(lock)
+
+/* forward declaration of hxge_adapter structure */
+struct hxge_adapter;
+/* declarations required for debug */
+#define HXGE_DRIVER_NAME "hxge"
+#define PFX "hxge: "
+#define DPRINTK(adapter, nlevel, klevel, fmt, args...) \
+       do{\
+       (void)((adapter) &&\
+       (NETIF_MSG_##nlevel & ((struct hxge_adapter *)adapter)->msg_enable)&&\
+       printk(KERN_##klevel PFX "%s: %s: " fmt "\n",\
+       ((struct hxge_adapter *)adapter)->netdev->name, __FUNCTION__ , ##args));\
+       } while (0)
+/* Only two functions defined, can be extended */
+#define HXGE_ERR(adapter, fmt, args...) DPRINTK(adapter, HW, ERR, fmt, ##args)
+#define HXGE_DBG(adapter, fmt, args...) DPRINTK(adapter, DRV, DEBUG, fmt, ##args)
+
+/* This is for where the adapter is not defined in context */
+#define HPRINTK(klevel, fmt, args...) \
+       do{\
+       printk(KERN_##klevel PFX "%s: " fmt "\n", __FUNCTION__ , ##args);\
+       } while (0)
+#define HXGE_ERR_PRINT(fmt, args...) HPRINTK(ERR, fmt, ##args)
+#define HXGE_DBG_PRINT(fmt, args...) HPRINTK(DEBUG, fmt, ##args)
+
+/* Hydra can address up to 44-bits of DMA memory */
+#define HXGE_MAX_ADDRESS_BITS_MASK 0x00000FFFFFFFFFFFULL
+#define HXGE_MAX_ADDRESS_BITS 44
+
+/* Timeout for Transmit before declaring it hung */
+#define HXGE_TX_TIMEOUT (5*HZ)
+
+/* Periodic timeout for monitoring link state */
+#define HXGE_LINK_TIMEOUT (2*HZ)
+
+/* Device hardware error threshold/limits before taking hxge down
+ *  THRESHOLD   Initial count before invoking rate limit
+ *  RATELIMIT   Event count per day ("rate") before taking device "down".
+ *
+ * Example:  THRESHOLD 4 & RATELIMIT 1 says allow 3 errors; on fourth
+ *           error, impose the rate/limit of 1 per day.  In other words,
+ *           allow a burst of up to three errors "immediately", but if
+ *           the long term average exceeds one per day (after any initial
+ *           burst), take the hxge down; 300 errors would be OK if you've
+ *           been up for a year.
+ */
+       
+#define HARD_ERROR_THRESHOLD   4
+#define HARD_ERROR_RATELIMIT   1
+#define SOFT_ERROR_THRESHOLD   100
+#define SOFT_ERROR_RATELIMIT   20
+#define LINE_ERROR_THRESHOLD   1000
+#define LINE_ERROR_RATELIMIT   500
+
+typedef enum {
+        HXGE_DEVICE_TESTING = 0,
+        HXGE_DEVICE_RESETTING,
+       HXGE_DEVICE_INITIALIZED, /* Device available; hxge_probe() complete */
+       HXGE_DEVICE_OPENING,    /* Opening ('UP'ing) device; hxge_open() */
+       HXGE_DEVICE_ALLOCATED,  /* I/O Buffers allocated; hxge_open() */
+       HXGE_DEVICE_UP,         /* In 'UP' state, active & running */
+       HXGE_DEVICE_CLOSING,    /* Closing/shutting down; hxge_close() */
+       HXGE_DRIVER_REMOVING,
+       HXGE_DEVICE_SHUTTINGDOWN, /* Shutting down (on fatal error) */
+       HXGE_DEVICE_FATAL       /* Fatal error in open, close & abort */
+} hxge_state_t;
+
+typedef enum {
+        LINK_MONITOR_DISABLED = 0,
+        LINK_MONITOR_ENABLED,
+}link_monitor_state_t;
+
+typedef enum {
+       LINK_MONITOR_START,
+       LINK_MONITOR_STOP
+} link_monitor_t;
+
+typedef enum {
+       LINK_MODE_INTR,
+       LINK_MODE_POLL
+} link_monitor_mode_t;
+
+
+struct hxge_hw {
+       uint8_t         *hw_addr;
+};
+
+
+typedef struct _hxge_stats_t {
+       hxge_vmac_stats_t       vmac_stats;
+       hxge_pfc_stats_t        pfc_stats;
+       uint32_t                link_monitor_cnt;
+       uint32_t                hard_errors; /* Hard device errors */
+       uint32_t                soft_errors; /* Soft device errors */
+       uint32_t                line_errors; /* Line (non-device) errors */
+       uint32_t                accum_hard_errors; /* Accumulated ... */
+       uint32_t                accum_soft_errors; /* Accumulated ... */
+       uint32_t                accum_line_errors; /* Accumulated ... */
+       /* Device Error status/statistics
+        * PEU_INTR_STAT Generic/other/high-level device errors */
+       uint32_t                peu_errors; /* Accumulated non-"i/o" errors */
+       uint32_t                peu_spc_acc_err; /* PEU_INTR_STAT[20] */
+       uint32_t                peu_pioacc_err; /* PEU_INTR_STAT[19:16] */
+       uint32_t                peu_pcie_parerr; /* PEU_INTR_STAT[9:2] */
+       uint32_t                peu_hcr_msix_parerr; /* PEU_INTR_STAT[1:0] */
+       /* Device Error status/statistics
+        * RDC_FIFO_ERR_STAT Receive subsystem device errors */
+       uint32_t                rx_ierrors; /* Generic/accumulated "i" errors */
+       uint32_t                rx_ctrl_sec; /* RX Ctrl RAM SEC */
+       uint32_t                rx_ctrl_ded; /* RX Ctrl RAM DED */
+       uint32_t                rx_data_sec; /* RX Data RAM SEC */
+       uint32_t                rx_data_ded; /* RX Data RAM DED */
+       /* Device Error status/statistics
+        * TDC_FIFO_ERR_STAT Transmit subsystem device errors */
+       uint32_t                tx_oerrors; /* Generic/accumulated "o" errors */
+       uint32_t                tx_timeout_cnt;
+       uint32_t                tx_reorder_sec; /* TX Reorder buffer SEC */
+       uint32_t                tx_reorder_ded; /* TX Reorder buffer DED */
+       uint32_t                tx_rtab_parerr; /* TX Reorder table parity */
+} hxge_stats_t, *p_hxge_stats_t;
+
+#define LDV_RXDMA      1       
+#define LDV_TXDMA      2
+#define LDV_VMAC       4
+#define LDV_PFC                8
+#define LDV_DEVERR     16
+#define LDV_ALL                0xFF
+
+#define INTx_TYPE      0
+#define MSI_TYPE       1
+#define MSIX_TYPE      2
+#define POLLING_TYPE   3
+
+struct ldv_array {
+       uint16_t        type;
+       uint16_t        dev_no;
+};
+struct hxge_ldv {        
+       uint16_t                ldv; /* logical device number */ 
+       uint16_t                dev_type; /* rxdma,txdma,vmac,syserr,pfc */ 
+       boolean_t               use_timer; 
+       uint16_t                ldv_flags; 
+       uint8_t                 ldf_masks; 
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+       irqreturn_t             (*intr_handler)(int, void *, struct pt_regs *);
+#else
+       irqreturn_t             (*intr_handler)(int, void *);
+#endif
+
+       struct hxge_ldg         *ldgp;
+       uint64_t                data;  /* device specific data */
+       struct list_head        ldg_list;
+       struct list_head        list; 
+}; 
+
+#define HXGE_MAX_IRQNAME       16
+struct hxge_ldg { 
+       uint16_t                ldg;/* logical group number */ 
+        uint16_t                       vldg_index; 
+        uint16_t                       vector; 
+        uint16_t                       nldvs; 
+        struct hxge_adapter    *hxgep; 
+       uint32_t                timer;
+       boolean_t               arm;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+        irqreturn_t            (*intr_handler)(int, void *, struct pt_regs *);
+#else
+        irqreturn_t            (*intr_handler)(int, void *);
+#endif
+
+       char                    irq_name[HXGE_MAX_IRQNAME]; /* dyn. allocated */
+        struct list_head       ldv_list; 
+       struct list_head        list; 
+}; 
+
+
+struct hxge_ldgv { 
+       uint8_t                 nldvs; 
+       uint8_t                 nldgs;
+       uint8_t                 max_ldgs; 
+       uint8_t                 max_ldvs; 
+       uint32_t                tmres; 
+       struct list_head        ldgp; 
+       struct list_head        ldvp;   
+};
+
+
+typedef enum {
+       RESET_TX_CHANNEL_0,
+       RESET_TX_CHANNEL_1,
+       RESET_TX_CHANNEL_2,
+       RESET_TX_CHANNEL_3,
+       RESET_RX_CHANNEL_0 = HXGE_MAX_TDCS,
+       RESET_RX_CHANNEL_1,
+       RESET_RX_CHANNEL_2,
+       RESET_RX_CHANNEL_3,
+       RESET_ADAPTER = HXGE_MAX_RDCS + HXGE_MAX_TDCS,
+       RESET_TDC,
+       RESET_RDC,
+       RESET_PFC,
+       RESET_VMAC,
+       SHUTDOWN_ADAPTER,
+       MAX_CMD
+} hxge_command_t;
+
+
+/*
+ *  * VLAN table configuration
+ *   */
+typedef struct hxge_mv_cfg {
+        uint8_t         flag;                   /* 0:unconfigure 1:configured */
+} hxge_mv_cfg_t, *p_hxge_mv_cfg_t;
+
+
+
+/* classification configuration */
+typedef struct hxge_class_pt_cfg {
+        /* VLAN table */
+        hxge_mv_cfg_t   vlan_tbl[VLAN_ID_MAX + 1];
+        /* class config value */
+        uint32_t        init_hash;
+        uint32_t        class_cfg[TCAM_CLASS_MAX];
+} hxge_class_pt_cfg_t, *p_hxge_class_pt_cfg_t;
+
+
+/* Adapter flags */
+#define HXGE_RX_CHKSUM_ENABLED 0x1
+#define HXGE_TX_CHKSUM_ENABLED 0x2
+#define HXGE_VLAN_ENABLED   0x4
+#define HXGE_TCAM_ENABLED   0x8
+
+#define HXGE_CHKSUM_ENABLED (HXGE_RX_CHKSUM_ENABLED | HXGE_TX_CHKSUM_ENABLED)
+
+/* board specific private data structure */
+
+struct hxge_adapter {
+#ifdef CONFIG_HXGE_NAPI
+       struct net_device       *polling_netdev;  /* One per active queue */
+#endif
+       /* OS defined structs */
+       struct net_device       *netdev;
+       struct pci_dev          *pdev;
+       struct net_device_stats net_stats;
+       unsigned long           state;
+       int                     num_openers;
+       int                     rbrs_to_kick; /* workaround for CR 6671220 */
+       unsigned int            tx_mark_ints;
+       unsigned long           ifup_time; /* "ifconfig up" time */
+       /* Flags */
+       uint32_t                flags;
+       unsigned long           err_flags;
+
+       /* Used during suspend and resume to save and restore PCI configuration
+           space */
+       uint32_t                *config_space;
+       uint32_t                msg_enable;
+       uint32_t                bd_number;
+        struct hxge_hw                 hw;
+       struct hxge_work_queue_t {
+               unsigned long command;
+       } work_q;
+        struct work_struct     work_to_do;
+       uint32_t                rx_buffer_len;
+       
+       /* Locks */
+       spinlock_t              lock;
+       spinlock_t              stats_lock;
+       spinlock_t              tcam_lock;
+       rwlock_t                wtd_lock;
+
+       /* Interrupt */
+       unsigned int            intr_type;
+#ifdef CONFIG_PCI_MSI
+       struct msix_entry       *msix;
+#endif
+        atomic_t               irq_sem;
+       struct hxge_ldgv        *ldgvp;
+
+       /* link management */
+       link_monitor_t          link_monitor_state;
+       link_monitor_mode_t     link_mode;
+       int                     prev_link_status;
+       struct timer_list       wd_timer;
+
+       /* Transmit and Receive */
+       uint32_t                max_tdcs;
+       uint32_t                max_rdcs;
+       uint32_t                default_block_size;
+
+        /* threshold of packets when queued up will force an interrupt */
+       uint16_t                rcr_threshold;
+        /* Max number of packets that are processed before giving the 
+           interrupt handling a breather */
+       uint16_t                max_rx_pkts;
+        /* Timeout value after which interrupt will be forced (if timeout is 
+           enabled and interrupt is armed */
+       uint32_t                rcr_timeout;
+       uint64_t                rcr_cfgb_cpy;
+       /* Enable adaptive tuning of Rx interrupt rate */
+       uint32_t                adaptive_rx;
+
+       /* Transmit */
+       struct tx_ring_t        *tx_ring;
+
+       /* Receive */
+       struct rx_ring_t        *rx_ring;
+
+       /* Statistics */
+       p_hxge_stats_t  statsp;
+
+       /* Parameter array */
+       void            *param; 
+
+       /* VMAC block */
+       hxge_vmac_t     vmac;
+
+       /* VLAN/TCAM/PFC */
+       hxge_classify_t         classifier;
+       hxge_class_pt_cfg_t     class_config;
+       pfc_vlan_table_t        vlan_table[VLAN_MAX_ENTRIES];
+       struct vlan_group       *vlangrp;
+       int                     vlan_id;
+
+       /* Multicast Filter Table */
+       uint16_t                mcast_hash_tbl[MAC_MAX_HASH_ENTRY];
+};
+
+#define LB_IOC (SIOCDEVPRIVATE + 15)
+#define GET_INFO_SIZE 1
+#define GET_INFO      2
+#define GET_LB_MODE   3
+#define SET_LB_MODE   4
+
+struct lb_size_info {
+       int      cmd;
+       uint32_t size;
+};
+
+typedef enum {
+       normal,
+       internal,
+       external
+} lb_type_t;
+
+typedef enum {
+        hxge_lb_normal,
+        hxge_lb_ext10g,
+} hxge_lb_t;
+
+
+typedef struct lb_property_s {
+        lb_type_t lb_type;
+        char key[16];
+        uint32_t value;
+} lb_property_t;
+
+/* Error injection flags */
+
+#define KMEM_FAILURE           0x1
+#define SKB_FAILURE            0x2
+#define ALLOC_PAGES_FAILURE    0x4
+#define CHKSUM_FAILURE         0x8
+#define PCIMAP_FAILURE         0x10
+
+/*  hxge_ethtool.c  */
+extern void hxge_set_ethtool_ops(struct net_device *netdev);
+
+/*  hxge_param.c  */
+extern void hxge_check_options(struct hxge_adapter *adapter);
+extern int hxge_get_option(const char *str, int *val);
+
+/* hxge_intr.c */
+extern void hxge_disable_rx_ints(struct hxge_adapter *hxgep, struct hxge_ldg *ldgp, int channel);
+extern void hxge_enable_rx_ints(struct hxge_adapter *hxgep, struct hxge_ldg *ldgp, int channel);
+extern void hxge_enable_tx_ints(struct hxge_adapter *hxgep, struct hxge_ldg *ldgp);
+extern void hxge_disable_tx_ints(struct hxge_adapter *hxgep);
+extern void get_ldf_flags(struct hxge_ldv *ldvp, int *ldf0, int *ldf1);
+extern int valid_alignment(uint64_t addr, uint64_t size, int);
+extern int hxge_debug;
+
+
+#endif /* _HXGE_H_ */
diff --git a/drivers/net/hxge/hxge_classify.h b/drivers/net/hxge/hxge_classify.h
new file mode 100644 (file)
index 0000000..71e4fca
--- /dev/null
@@ -0,0 +1,82 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#ifndef _HXGE_CLASSIFY_H
+#define        _HXGE_CLASSIFY_H
+
+/*
+ * The following are the user configurable ether types. Refer to
+ * /usr/include/sys/ethernet.h
+ *
+ * ETHERTYPE_PUP       (0x0200)
+ * ETHERTYPE_802_MIN   (0x0600)
+ * ETHERTYPE_IP                (0x0800)
+ * ETHERTYPE_ARP       (0x0806)
+ * ETHERTYPE_REVARP    (0x8035)
+ * ETHERTYPE_AT                (0x809b)
+ * ETHERTYPE_AARP      (0x80f3)
+ * ETHERTYPE_IPV6      (0x86dd)
+ * ETHERTYPE_SLOW      (0x8809)
+ * ETHERTYPE_PPPOED    (0x8863)
+ * ETHERTYPE_PPPOES    (0x8864)
+ * ETHERTYPE_MAX       (0xffff)
+ */
+
+/*
+ * Used for ip class tcam key config
+ */
+#define        HXGE_CLASS_TCAM_LOOKUP          0x10000
+#define        HXGE_CLASS_DISCARD              0x20000
+#define        HXGE_CLASS_VALID                0x40000
+#define        HXGE_CLASS_ETHER_TYPE_MASK      0x0FFFF
+
+typedef struct _tcam_flow_spec {
+       hxge_tcam_entry_t tce;
+       uint64_t flags;
+       uint64_t user_info;
+} tcam_flow_spec_t, *p_tcam_flow_spec_t;
+
+typedef struct {
+       uint16_t        ether_type;
+       int             count;  /* How many TCAM entries using this class. */
+} hxge_class_usage_t;
+
+#define HXGE_PFC_HW_UNINIT     0x0
+#define        HXGE_PFC_HW_RESET       0x1
+#define        HXGE_PFC_HW_INIT        0x2
+#define        HXGE_PFC_SW_INIT        0x4
+
+typedef struct _hxge_classify {
+       uint32_t                tcam_size;
+       uint32_t                n_used;
+       uint32_t                state;
+       p_hxge_pfc_stats_t      pfc_stats;
+
+       tcam_flow_spec_t        *tcam_entries;
+       uint8_t                 tcam_location;
+       hxge_class_usage_t      class_usage[TCAM_CLASS_MAX];
+} hxge_classify_t, *p_hxge_classify_t;
+
+#endif /* _HXGE_CLASSIFY_H */
diff --git a/drivers/net/hxge/hxge_defs.h b/drivers/net/hxge/hxge_defs.h
new file mode 100644 (file)
index 0000000..5c99bf8
--- /dev/null
@@ -0,0 +1,516 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#ifndef        _HXGE_HXGE_DEFS_H
+#define        _HXGE_HXGE_DEFS_H
+
+#include <linux/delay.h>
+#include <asm/io.h>
+
+typedef enum {
+    FALSE = 0,
+    TRUE = 1
+} boolean_t;
+
+
+#define         NO_DEBUG        0x0000000000000000ULL
+#define         RX_CTL          0x0000000000000002ULL
+#define         TX_CTL          0x0000000000000004ULL
+#define         OBP_CTL         0x0000000000000008ULL
+
+#define         VPD_CTL         0x0000000000000010ULL
+#define         DDI_CTL         0x0000000000000020ULL
+#define         MEM_CTL         0x0000000000000040ULL
+
+#define         IOC_CTL         0x0000000000000100ULL
+#define         MOD_CTL         0x0000000000000200ULL
+#define         DMA_CTL         0x0000000000000400ULL
+#define         STR_CTL         0x0000000000000800ULL
+
+#define         INT_CTL         0x0000000000001000ULL
+#define         SYSERR_CTL      0x0000000000002000ULL
+#define         KST_CTL         0x0000000000004000ULL
+
+#define         FCRAM_CTL       0x0000000000040000ULL
+#define         MAC_CTL         0x0000000000080000ULL
+
+#define         DMA2_CTL        0x0000000000200000ULL
+#define         RX2_CTL         0x0000000000400000ULL
+#define         TX2_CTL         0x0000000000800000ULL
+
+#define         MEM2_CTL        0x0000000001000000ULL
+#define         MEM3_CTL        0x0000000002000000ULL
+#define         NEMO_CTL        0x0000000004000000ULL
+#define         NDD_CTL         0x0000000008000000ULL
+#define         NDD2_CTL        0x0000000010000000ULL
+
+#define         TCAM_CTL        0x0000000020000000ULL
+#define         CFG_CTL         0x0000000040000000ULL
+#define         CFG2_CTL        0x0000000080000000ULL
+
+#define         PFC_CTL         TCAM_CTL
+
+#define         VIR_CTL         0x0000000100000000ULL
+#define         VIR2_CTL        0x0000000200000000ULL
+
+#define         HXGE_NOTE       0x0000001000000000ULL
+#define         HXGE_ERR_CTL    0x0000002000000000ULL
+
+#define         DUMP_ALWAYS     0x2000000000000000ULL
+
+
+/************************************************************************
+ * Special Hydra handling for 32-bit access architecture
+ *
+ * Hydra CR xxxxxxxx
+ *
+ * If on a 32-bit architecture (e.g., i686 vs x86_64), we must perform
+ * two consecutive 32-bit PIOs to gain access to any 64-bit Hydra
+ * register. The Hydra PEU (PCI Execution Unit) will internally "buffer"
+ * the two separate 32-bit reads, do a SINGLE 64-bit (atomic) register
+ * read, and then return the two 32-bit values.  The Hydra read does
+ * ***NOT*** occur until the second 32-bit PIO read arrives (the first
+ * 32-bit read is simply "held" or buffered pending arrival of the
+ * "other half of the read" operation).  Similarly for write operations,
+ * the Hydra buffers and then coalesces two distinct 32-bit write PIOs
+ * into a single (atomic) 64-bit internal register write.
+ *
+ * Now, this is cool (gives us 64-bit "atomic/coherent") register access
+ * on a 32-bit machine.
+ *
+ * The Issue (there is debate over this being a "bug" or a "feature") is
+ * that ABSOLUTELY NO INTERVENING PCI PIO access can occur between the
+ * two consecutive 32-bit PIO accesses for a 64-bit register.  If a
+ * PIO access comes in that is NOT consecutive (e.g., is NOT for address
+ * and address+4), the held/buffered PIO is discarded, and an entirely
+ * new register access is started, either a 32-bit register access that
+ * will run normally to completion, or a NEW 64-bit access, for which 
+ * this is the "first half", and which will be held until the "second half"
+ * (address+4) arrives, triggering completion of the 64-bit access.
+ *
+ * As such, *ALL* Hydra PCI PIO read/writes must be locked with exclusive
+ * PCI bus access (guaranteed consecutive & sequential).    Actually, the
+ * only thing we MUST guarantee is that the PIO *requests* are consecutive
+ * and sequential delivered to the Hydra; for reads we really don't care
+ * in which order Hydra sends the upper/lower halves back to us...
+ *
+ * Bear in mind we can have a dozen different CPUs concurrently executing
+ * Hydra driver code all trying to execute 64-bit PIO register access!
+ *
+ */
+
+#if BITS_PER_LONG == 32                /* Special Hydra handling for 32bit arch */
+
+struct hxge_adapter;
+
+extern spinlock_t hxge_lock;
+
+static inline u64 __hxge_readq(void __iomem *addr)
+{
+//     /* Use 'MMX' 64-bit mov available on i386/i686 architecture */
+//
+// Unfortunately, needs to save FPU status, not just %%mm0
+// Deferred for future investigation...should be faster than spin_lock!
+//
+//     u64 var = 0, tmp = 0;
+//     __asm__ __volatile__ (
+//             "movq %%mm0, %[t]\n\t"
+//             "movl %[a], %%eax\n\t"
+//             "movq (%%eax), %%mm0\n\t"
+//             "movq %%mm0, %[r]\n\t"
+//             "movq %[t], %%mm0\n\t"
+//             :[r] "=m"(var), [t]"+m"(tmp)
+//             :[a] "r"(addr)
+//             :"%eax"
+//     );
+//     smp_rmb();
+//     return var;
+
+       uint64_t val;
+
+       unsigned long flags;
+
+       spin_lock_irqsave (&hxge_lock, flags);
+
+#if defined(__BIG_ENDIAN)
+       val = (uint64_t)(readl(addr)) << 32;
+       val |= (uint64_t)(readl(addr+4) & 0xFFFFFFFF);
+#else
+       val = (uint64_t)(readl(addr) & 0xFFFFFFFF);
+       val |= (uint64_t)(readl(addr+4)) << 32;
+#endif
+
+       spin_unlock_irqrestore (&hxge_lock, flags);
+
+       return val;
+}
+
+static inline void __hxge_writeq(uint64_t val, void *addr)
+{
+//     /* Use 'MMX' 64-bit mov available on i386/i686 architecture */
+//
+// Unfortunately, needs to save FPU status, not just %%mm0
+// Deferred for future investigation...should be faster than spin_lock!
+//
+//     u64 tmp = 0;
+//     __asm__ __volatile__ (
+//             "movq %%mm0, %[t]\n\t"
+//             "movq %[d], %%mm0\n\t"
+//             "movl %[a], %%eax\n\t"
+//             "movq %%mm0, (%%eax)\n\t"
+//             "movq %[t], %%mm0\n\t"
+//             :[t] "+m"(tmp)
+//             :[a] "r"(addr), [d] "m"(val)
+//             :"%eax"
+//     );
+//     smp_wmb();
+//     return;
+
+       unsigned long flags;
+
+       spin_lock_irqsave (&hxge_lock, flags);
+
+#if defined(__BIG_ENDIAN)
+       writel ((uint32_t)(val >> 32), addr);
+       writel ((uint32_t)(val), addr+4);
+#else
+       writel ((uint32_t)(val), addr);
+       writel ((uint32_t)(val >> 32), addr+4);
+#endif /* defined (__BIG_ENDIAN) */
+
+       spin_unlock_irqrestore (&hxge_lock, flags);
+
+       return;
+}
+
+static inline u32 __hxge_readl(void __iomem *addr)
+{
+       uint32_t val;
+       unsigned long flags;
+
+       spin_lock_irqsave (&hxge_lock, flags);
+
+       val = readl(addr);
+
+       spin_unlock_irqrestore (&hxge_lock, flags);
+
+       return val;
+}
+
+static inline void __hxge_writel(u32 val, void *addr)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave (&hxge_lock, flags);
+
+       writel (val, addr);
+
+       spin_unlock_irqrestore (&hxge_lock, flags);
+
+       return;
+}
+
+#define hxge_readq(addr)\
+({\
+       u64 v; v = __hxge_readq(addr); v;\
+})
+
+#define hxge_writeq(v, addr)\
+do{\
+       __hxge_writeq(v, addr);\
+} while(0)
+
+#define hxge_readl(addr)\
+({\
+       u32 v; v = __hxge_readl(addr); v;\
+})
+
+#define hxge_writel(v, addr)\
+do{\
+       __hxge_writel(v, addr);\
+} while(0)
+
+#else  /* 64-bit BITS_PER_LONG -- the normal, easy case */
+
+#define hxge_readq(addr)               readq(addr)
+#define hxge_writeq(val, addr)         writeq(val, addr)
+
+#define hxge_readl(addr)       readl(addr)
+#define hxge_writel(val, addr) writel(val, addr)
+
+#endif /* BITS_PER_LONG */
+
+
+/* HXGE specific definitions (uses the above ones) */
+#define HXGE_REG_RD64(handle, offset, val_p)\
+do{\
+        *(val_p) = hxge_readq((handle + offset));\
+} while (0)
+
+#define HXGE_REG_RD32(handle, offset, val_p)\
+do{\
+        *(val_p) = hxge_readl((handle + offset));\
+} while (0)
+
+#define HXGE_REG_WR64(handle, offset, val)\
+do{\
+        hxge_writeq( (val), (handle + (offset)));\
+} while (0)
+
+#define HXGE_REG_WR32(handle, offset, val)\
+do{\
+        hxge_writel((val), (handle +(offset)));\
+} while (0)
+
+#define HXGE_MEM_PIO_READ64(handle)\
+({\
+       u64 v;\
+       v = hxge_readq(handle);\
+       v;\
+})
+
+#define HXGE_MEM_PIO_WRITE32(handle, data)\
+do{\
+       hxge_writel((val), handle);\
+} while (0)
+
+#define HXGE_MEM_PIO_WRITE64(handle, data)\
+do{\
+       hxge_writeq((data), handle);\
+} while (0)
+
+
+/* RDC/TDC CSR size */
+#define        DMA_CSR_SIZE            2048
+
+/*
+ * Define the Default RBR, RCR
+ */
+#define        RBR_DEFAULT_MAX_BLKS    4096    /* each entry (16 blockaddr/64B) */
+#define        RBR_NBLK_PER_LINE       16      /* 16 block addresses per 64 B line */
+#define        RBR_DEFAULT_MAX_LEN     65472   /* 2^16 - 64 */
+#define        RBR_DEFAULT_MIN_LEN     64      /* multiple of 64 */
+
+#define        SW_OFFSET_NO_OFFSET     0
+#define        SW_OFFSET_64            1       /* 64 bytes */
+#define        SW_OFFSET_128           2       /* 128 bytes */
+#define        SW_OFFSET_INVALID       3
+
+/*
+ * RBR block descriptor is 32 bits (bits [43:12]
+ */
+#define        RBR_BKADDR_SHIFT        12
+#define        RCR_DEFAULT_MAX_BLKS    4096    /* each entry (8 blockaddr/64B) */
+#define        RCR_NBLK_PER_LINE       8       /* 8 block addresses per 64 B line */
+#define        RCR_DEFAULT_MAX_LEN     (RCR_DEFAULT_MAX_BLKS)
+#define        RCR_DEFAULT_MIN_LEN     32
+
+/*  DMA Channels.  */
+#define        HXGE_MAX_DMCS           (HXGE_MAX_RDCS + HXGE_MAX_TDCS)
+#define HXGE_MIN_RDCS          1
+#define        HXGE_MAX_RDCS           4
+#define HXGE_MIN_TDCS          1
+#define        HXGE_MAX_TDCS           4
+
+#define        VLAN_ETHERTYPE                  (0x8100)
+
+/* 256 total, each blade gets 42 */
+#define        TCAM_HXGE_TCAM_MAX_ENTRY        42
+
+/*
+ * Locate the DMA channel start offset (PIO_VADDR)
+ * (DMA virtual address space of the PIO block)
+ */
+/* TX_RNG_CFIG is not used since we are not using VADDR. */
+#define        TX_RNG_CFIG                     0x1000000
+#define        TDMC_PIOVADDR_OFFSET(channel)   (2 * DMA_CSR_SIZE * channel)
+#define        RDMC_PIOVADDR_OFFSET(channel)   (TDMC_OFFSET(channel) + DMA_CSR_SIZE)
+
+/*
+ * PIO access using the DMC block directly (DMC)
+ */
+#define        DMC_OFFSET(channel)             (DMA_CSR_SIZE * channel)
+#define        TDMC_OFFSET(channel)            (TX_RNG_CFIG + DMA_CSR_SIZE * channel)
+
+/*
+ * The following macros expect unsigned input values.
+ */
+#define        TXDMA_CHANNEL_VALID(cn)         (cn < HXGE_MAX_TDCS)
+
+/*
+ * Logical device definitions.
+ */
+#define        HXGE_INT_MAX_LD         32
+#define        HXGE_INT_MAX_LDG        32
+
+#define        HXGE_RDMA_LD_START      0       /* 0 - 3 with 4 - 7 reserved */
+#define        HXGE_TDMA_LD_START      8       /* 8 - 11 with 12 - 15 reserved */
+#define        HXGE_VMAC_LD            16
+#define        HXGE_PFC_LD             17
+#define        HXGE_NMAC_LD            18
+#define        HXGE_MBOX_LD_START      20      /* 20 - 23  for SW Mbox */
+#define        HXGE_SYS_ERROR_LD       31
+
+#define        LDG_VALID(n)            (n < HXGE_INT_MAX_LDG)
+#define        LD_VALID(n)             (n < HXGE_INT_MAX_LD)
+#define        LD_RXDMA_LD_VALID(n)    (n < HXGE_MAX_RDCS)
+#define        LD_TXDMA_LD_VALID(n)    (n >= HXGE_MAX_RDCS && \
+                                       ((n - HXGE_MAX_RDCS) < HXGE_MAX_TDCS)))
+
+#define        LD_TIMER_MAX            0x3f
+#define        LD_INTTIMER_VALID(n)    (n <= LD_TIMER_MAX)
+
+/* System Interrupt Data */
+#define        SID_VECTOR_MAX          0x1f
+#define        SID_VECTOR_VALID(n)     (n <= SID_VECTOR_MAX)
+
+#define        LD_IM_MASK              0x00000003ULL
+#define        LDGTITMRES_RES_MASK     0x000FFFFFULL
+
+#define        STD_FRAME_SIZE          1522            /* 1518 + 4 = 5EE + 4 */
+
+#define HXGE_DMA_START  B_TRUE
+#define HXGE_DMA_STOP   B_FALSE
+
+/* The timer resolution is 4 microsec per tick (250MHz clock). So, we set it 
+   to be 8 microsecs */
+#define HXGE_TIMER_RESO 8
+/* Number of ticks to count down before timer goes off. It is set to be 
+   16 microsecs */
+#define HXGE_TIMER_LDG  8
+
+/*
+ * Receive and Transmit DMA definitions
+ */
+#ifdef  _DMA_USES_VIRTADDR
+#define HXGE_DMA_BLOCK          1
+#else
+#define HXGE_DMA_BLOCK          (64 * 64)
+#endif
+
+#define HXGE_RBR_RBB_MIN        (64)
+#define HXGE_RBR_RBB_MAX        (65536-64)
+#define HXGE_RBR_RBB_DEFAULT    (2048) /* CR 6779304 */
+#define HXGE_RBR_SPARE          0
+#define HXGE_RCR_MIN            (HXGE_RBR_RBB_MIN * 2)
+#define HXGE_RCR_MAX            (32768) /* 2^15 (CR 6779304) */
+
+#define HXGE_RCR_CLK_RESO      25000
+#define HXGE_RCR_TIMEOUT        1
+#define HXGE_RCR_TIMEOUT_MIN   0 /* 0 => disable timeout */
+#define HXGE_RCR_TIMEOUT_MAX   63
+
+#define HXGE_RCR_THRESHOLD     1
+#define HXGE_RCR_THRESHOLD_MIN 0
+#define HXGE_RCR_THRESHOLD_MAX 65535
+
+#define HXGE_MAX_RX_PKTS_MIN   10
+#define HXGE_MAX_RX_PKTS_MAX   65535
+/* Maximum number of Rx packets that can be processed before the interrupt
+   handler lets go and handles the rest later. The limit is imposed by the
+   quota and budget in the NAPI case but in the non-NAPI case, this is the 
+   only way to limit processing at one time */
+#define HXGE_MAX_RX_PKTS       512
+
+/* Assume the smallest buffer size of 256B. So, we can have
+ * 16 256B packets in a 4K page
+ */
+#define HXGE_RCR_DEFAULT        (HXGE_RBR_RBB_DEFAULT * 16)
+
+#define HXGE_TX_RING_DEFAULT    (1024)
+#define HXGE_TX_RING_MAX        (64 * 128 - 1)
+
+#define RBR_BKSIZE_4K                   0
+#define RBR_BKSIZE_8K                   1
+#define RBR_BKSIZE_4K_BYTES             (4 * 1024)
+
+#define RBR_BUFSZ2_2K                   0
+#define RBR_BUFSZ2_4K                   1
+#define RBR_BUFSZ2_2K_BYTES             (2 * 1024)
+#define RBR_BUFSZ2_4K_BYTES             (4 * 1024)
+
+#define RBR_BUFSZ1_1K                   0
+#define RBR_BUFSZ1_2K                   1
+#define RBR_BUFSZ1_1K_BYTES             1024
+#define RBR_BUFSZ1_2K_BYTES             (2 * 1024)
+
+#define RBR_BUFSZ0_256B                 0
+#define RBR_BUFSZ0_512B                 1
+#define RBR_BUFSZ0_1K                   2
+#define RBR_BUFSZ0_256_BYTES            256
+#define RBR_BUFSZ0_512B_BYTES           512
+#define RBR_BUFSZ0_1K_BYTES             (1024)
+
+#define HXGE_MAX_MAC_ADDRS             16
+
+/* HPI Debug and Error defines */
+#define         HPI_RDC_CTL     0x0000000000000001ULL
+#define         HPI_TDC_CTL     0x0000000000000002ULL
+
+#define         HPI_XPCS_CTL    0x0000000000000010ULL
+#define         HPI_PCS_CTL     0x0000000000000020ULL
+#define         HPI_ESR_CTL     0x0000000000000040ULL
+#define         HPI_BMAC_CTL    0x0000000000000080ULL
+#define         HPI_XMAC_CTL    0x0000000000000100ULL
+#define         HPI_MAC_CTL     HPI_BMAC_CTL | HPI_XMAC_CTL
+
+#define         HPI_TCAM_CTL    0x0000000000000400ULL
+#define         HPI_FCRAM_CTL   0x0000000000000800ULL
+#define         HPI_FFLP_CTL    HPI_TCAM_CTL | HPI_FCRAM_CTL
+
+#define         HPI_VIR_CTL     0x0000000000001000ULL
+#define         HPI_PIO_CTL     0x0000000000002000ULL
+#define         HPI_VIO_CTL     0x0000000000004000ULL
+
+#define         HPI_REG_CTL     0x0000000040000000ULL
+#define         HPI_CTL         0x0000000080000000ULL
+#define         HPI_ERR_CTL     0x0000000080000000ULL
+
+#define HXGE_DELAY(microseconds)   (udelay(microseconds))
+
+/* The sizes (in bytes) of a ethernet packet */
+#define ENET_HEADER_SIZE             14
+#define MAXIMUM_ETHERNET_FRAME_SIZE  1518 /* With checksum */
+#define MINIMUM_ETHERNET_FRAME_SIZE  64   /* With checksum */
+#define ETHERNET_CSUM_SIZE            4 
+#define MAXIMUM_ETHERNET_PACKET_SIZE \
+    (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_CSUM_SIZE)
+#define MINIMUM_ETHERNET_PACKET_SIZE \
+    (MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_CSUM_SIZE)
+#define CRC_LENGTH                   ETHERNET_CSUM_SIZE
+#define MAX_JUMBO_FRAME_SIZE         9216 /* Standard Jumbo frame */
+#define MAXIMUM_ETHERNET_VLAN_SIZE   MAXIMUM_ETHERNET_FRAME_SIZE+4 /* VLAN tagging included */
+
+#define HASH_TABLE_SIZE 1024
+
+typedef enum {                 /* Represents bit numbers */
+        RING_INIT = 1,
+        RING_ENABLED,
+        RING_RESET,
+       RING_RECLAIM
+} ring_state_t;
+
+
+#endif /* _HXGE_HXGE_DEFS_H */
diff --git a/drivers/net/hxge/hxge_ethtool.c b/drivers/net/hxge/hxge_ethtool.c
new file mode 100644 (file)
index 0000000..f08d838
--- /dev/null
@@ -0,0 +1,1060 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#include "hpi/hpi_vmac.h"
+#include "hpi/hpi_txdma.h"
+#include "hpi/hpi_rxdma.h"
+#include "hxge.h"
+
+/************************************************************************
+* How to add new diagnostic (loopback) tests 
+*
+*
+*   1. Add a new entry to the loopback_params array with new test parameters.
+*   2. Add a corresponding new entry to hxge_gstrings_test array indicating 
+*      a default of "NOTRUN"
+*
+*   Currently, the test will bail after the first failure. Also, the hydra
+*   should be in loopback mode. I have been testing with the loopback module
+*   plugged into the port. If there is no loopback module, then configure the 
+*   VMAC RX in loopback mode
+*
+*************************************************************************/
+       
+
+
+extern const char hxge_driver_version[];
+extern int hxge_reset_tx_channel(struct hxge_adapter *hxgep, int i);
+extern int hxge_reset_rx_channel(struct hxge_adapter *hxgep, int i);
+extern hpi_status_t hpi_txdma_desc_mem_get(hpi_handle_t handle, uint16_t index,
+               p_tx_desc_t desc_p);
+extern hpi_status_t hpi_vmac_rx_config(hpi_handle_t handle, config_op_t op, 
+       uint64_t config, uint16_t max_frame_length);
+extern hpi_status_t hpi_txdma_desc_kick_reg_set(hpi_handle_t handle, 
+       uint8_t channel, uint16_t tail_index, boolean_t wrap);
+extern hpi_status_t hpi_rxdma_cfg_rdc_reset(hpi_handle_t handle, uint8_t rdc);
+extern hpi_status_t hpi_txdma_channel_reset(hpi_handle_t handle, 
+       uint8_t channel);
+extern int hxge_process_packets(struct hxge_adapter *hxgep,
+#ifdef CONFIG_HXGE_NAPI
+                                               int work_to_do,
+#endif
+                                       int channel, struct sk_buff **skb);
+#define PATT_LEN 8
+uint8_t pattern[PATT_LEN] = {0xAA, 0xBB, 0xCC, 0xDD, 0xDE, 0xAD, 0xBE, 0xEF};
+
+extern int hxge_alloc_tx(struct hxge_adapter *hxgep);
+extern int hxge_alloc_rx(struct hxge_adapter *hxgep);
+extern void hxge_enable_adapter(struct hxge_adapter *hxgep);
+extern void hxge_disable_adapter(struct hxge_adapter *hxgep);
+extern int hxge_free_tx(struct hxge_adapter *hxgep);
+extern int hxge_free_rx(struct hxge_adapter *hxgep);
+extern int hxge_set_option(const char *parm, int val);
+extern int hxge_block_reset(struct hxge_adapter *hxgep, int device);
+extern int hxge_start_xmit(struct sk_buff *skb, struct net_device *netdev);
+extern int hxge_setup_interrupt(struct net_device *netdev);
+extern int hxge_teardown_interrupt(struct hxge_adapter *hxgep);
+extern int hxge_peu_get_link_status(struct hxge_adapter *hxgep);
+
+
+typedef struct hxge_loopback_params {
+       int intr_type;   /* interrupt type - INTx, MSI, MSIX, polling */
+       int pkt_len; /* packet size in bytes */
+       int num_pkts;    /* # of pkts to send */
+       int tx_channels; /* # of tx channels */
+       int rx_channels; /* # of rx channels */
+       int tx_descs;    /* # of tx descriptors */
+       int rcr_entries; /* # of RCR entries */
+       int rbr_entries; /* # of RBR entries */
+       int rcr_threshold;
+       int rcr_timeout;
+       int bad_len;     /* force a bad pkt_hdr formation */
+} loopback_params_t;
+       
+
+loopback_params_t loopback_params[] = 
+{ 
+        /* 1 Packet sent from 1 channel */
+       {
+         INTx_TYPE,
+         64,
+         32,
+         1,
+         1,
+         HXGE_TX_DESCS_MIN,
+         HXGE_RCR_MIN,
+         HXGE_RBR_RBB_MIN,
+         1,
+         0,
+         1,
+        },
+       /* 1 Packet sent from 1 channel, using INTx */
+       {
+         INTx_TYPE,
+         64,
+         32,
+         1,
+         1,
+         HXGE_TX_DESCS_MIN,
+         HXGE_RCR_MIN,
+         HXGE_RBR_RBB_MIN,
+         1,
+         0,
+         1
+       },
+       /* 1 Packet sent from 1 channel, threshold but no timeout. Sending
+       * 2 packets because 1 packet with threshold does not work */
+       {
+         INTx_TYPE,
+         64,
+         2,
+         1,
+         1,
+         HXGE_TX_DESCS_MIN,
+         HXGE_RCR_MIN,
+         HXGE_RBR_RBB_MIN,
+         1,
+         0,
+         0
+       },
+       /* 1024-byte packet */
+       { 
+         INTx_TYPE, 
+         1024, 
+         2, 
+         1, 
+         1, 
+         HXGE_TX_DESCS_MIN,
+         HXGE_RCR_MIN,
+         HXGE_RBR_RBB_MIN,
+         1,
+         0,
+        0
+       },
+        /* 1 Packet sent from 1 channel */
+       { 
+         POLLING_TYPE,
+         64, 
+         2, 
+         1,
+         1,
+         HXGE_TX_DESCS_MIN,
+         HXGE_RCR_MIN, 
+         HXGE_RBR_RBB_MIN,
+         1,
+         0,
+         0
+        },
+       /* 2 Tx channels, 2 Tx channels, 1 packet each */
+       { POLLING_TYPE, 
+         64, 
+         1, 
+         2,
+         2,
+         HXGE_TX_DESCS_MIN,
+         HXGE_RCR_MIN, 
+         HXGE_RBR_RBB_MIN,
+         1,
+         0,
+         0
+        },
+       /* 1 Tx channel, Tx descriptor number of packets */
+       { POLLING_TYPE,
+         64,
+         -1,
+         1,
+         1,
+         HXGE_TX_DESCS_MIN,
+         HXGE_RCR_MIN,
+         HXGE_RBR_RBB_MIN,
+         1,
+         0,
+         0
+        },
+};
+
+#define HXGE_TEST_LEN sizeof(hxge_gstrings_test) / ETH_GSTRING_LEN
+
+static char hxge_gstrings_test[][ETH_GSTRING_LEN] = {
+        "Loopback Test 1 = NOTRUN", 
+        "Loopback Test 2 = NOTRUN", 
+        "Loopback Test 3 = NOTRUN", 
+        "Loopback Test 4 = NOTRUN", 
+        "Loopback Test 5 = NOTRUN", 
+        "Loopback Test 6 = NOTRUN", 
+        "Loopback Test 7 = NOTRUN", 
+};
+
+struct hxge_stats_struct {
+       char name[ETH_GSTRING_LEN];
+       uint64_t offset;
+};
+
+#define STAT_OFFSET(name) offsetof(hxge_stats_t, name)
+#define RX_STAT_OFFSET(name) offsetof(struct rx_ring_stats_t, name)
+
+static struct hxge_stats_struct hxge_rdc_stats[] = {
+       {"Rx Channel #", 0},
+       {"  Rx Packets", RX_STAT_OFFSET(ipackets)},
+       {"  Rx Bytes", RX_STAT_OFFSET(ibytes)},
+       {"  Rx Errors", RX_STAT_OFFSET(ierrors)},
+       {"  Jumbo Packets", RX_STAT_OFFSET(jumbo_pkts)},
+       {"  ECC Errors", RX_STAT_OFFSET(ecc_errors)},
+       {"  RBR Completion Timeout", RX_STAT_OFFSET(rbr_cpl_tmout)},
+       {"  PEU Response Error", RX_STAT_OFFSET(peu_resp_err)},
+       {"  RCR Shadow Parity", RX_STAT_OFFSET(rcr_shadow_parity)},
+       {"  RCR Prefetch Parity", RX_STAT_OFFSET(rcr_prefetch_parity)},
+       {"  RCR Shadow Full", RX_STAT_OFFSET(rcr_shadow_full)},
+       {"  RCR Full", RX_STAT_OFFSET(rcr_full)},
+       {"  RBR Empty", RX_STAT_OFFSET(rbr_empty)},
+        {"  RBR Empty Handled", RX_STAT_OFFSET(rbr_empty_handled)},
+        {"  RBR Empty Buffers Posted", RX_STAT_OFFSET(rbr_empty_posted)},
+       {"  RBR Full", RX_STAT_OFFSET(rbr_full)},
+       {"  RCR Timeouts", RX_STAT_OFFSET(rcr_to)},
+       {"  RCR Thresholds", RX_STAT_OFFSET(rcr_thres)},
+       {"  Packet Too Long Errors", RX_STAT_OFFSET(pkt_too_long)},
+       {"  No RBR available", RX_STAT_OFFSET(no_rbr_avail)},
+       {"  No Memory Drops", RX_STAT_OFFSET(nomem_drop)},
+       {"  RVM Errors", RX_STAT_OFFSET(rvm_errors)},
+       {"  Frame Errors", RX_STAT_OFFSET(frame_errors)},
+       {"  RAM Errors", RX_STAT_OFFSET(ram_errors)},
+       {"  CRC Errors", RX_STAT_OFFSET(crc_errors)}
+};
+#define HXGE_RDC_STATS_CNT (sizeof(hxge_rdc_stats)/sizeof(struct hxge_stats_struct))
+
+
+#define TX_STAT_OFFSET(name) offsetof(struct tx_ring_stats_t, name)
+static struct hxge_stats_struct hxge_tdc_stats[] = {
+       {"Tx Channel #", 0},
+       {"  Tx Packets", TX_STAT_OFFSET(opackets)},
+       {"  Tx Bytes", TX_STAT_OFFSET(obytes)},
+       {"  Tx Errors", TX_STAT_OFFSET(oerrors)},
+       {"  Tx Desc Used [0]", TX_STAT_OFFSET(descs_used[0])},
+       {"  Tx Desc Used [1]", TX_STAT_OFFSET(descs_used[1])},
+       {"  Tx Desc Used [2]", TX_STAT_OFFSET(descs_used[2])},
+       {"  Tx Desc Used [3]", TX_STAT_OFFSET(descs_used[3])},
+       {"  Tx Desc Used [4]", TX_STAT_OFFSET(descs_used[4])},
+       {"  Tx Desc Used [5]", TX_STAT_OFFSET(descs_used[5])},
+       {"  Tx Desc Used [6]", TX_STAT_OFFSET(descs_used[6])},
+       {"  Tx Desc Used [7]", TX_STAT_OFFSET(descs_used[7])},
+       {"  Tx Desc Used [8]", TX_STAT_OFFSET(descs_used[8])},
+       {"  Tx Desc Used [9]", TX_STAT_OFFSET(descs_used[9])},
+       {"  Tx Desc Used [10]", TX_STAT_OFFSET(descs_used[10])},
+       {"  Tx Desc Used [11]", TX_STAT_OFFSET(descs_used[11])},
+       {"  Tx Desc Used [12]", TX_STAT_OFFSET(descs_used[12])},
+       {"  Tx Desc Used [13]", TX_STAT_OFFSET(descs_used[13])},
+       {"  Tx Desc Used [14]", TX_STAT_OFFSET(descs_used[14])},
+       {"  Tx Desc Used [15]", TX_STAT_OFFSET(descs_used[15])},
+        {"  Tx Lock Failed", TX_STAT_OFFSET(txlock_acquire_failed)},
+       {"  Marked Ints", TX_STAT_OFFSET(marked)},
+       {"  PEU Response Error Ints", TX_STAT_OFFSET(peu_resp_err)},
+       {"  Packet Hdr Size Err Ints", TX_STAT_OFFSET(pkt_size_hdr_err)},
+       {"  Runt Packet Drop Ints", TX_STAT_OFFSET(runt_pkt_drop_err)},
+       {"  Ring Overflow Ints", TX_STAT_OFFSET(tx_rng_oflow)},
+       {"  Prefetch Parity Error Ints", TX_STAT_OFFSET(pref_par_err)},
+       {"  Prefetch Compl Timeout Ints", TX_STAT_OFFSET(tdr_pref_cpl_to)},
+       {"  Packet Completion Timeout Ints", TX_STAT_OFFSET(pkt_cpl_to)},
+       {"  Invalid SOP Ints", TX_STAT_OFFSET(invalid_sop)},
+       {"  Unexpected SOP Ints", TX_STAT_OFFSET(unexpected_sop)},
+       {"  Header Error Count", TX_STAT_OFFSET(hdr_error_cnt)},
+       {"  Abort Count", TX_STAT_OFFSET(abort_cnt)},
+       {"  Runt Count", TX_STAT_OFFSET(runt_cnt)}
+};
+#define HXGE_TDC_STATS_CNT (sizeof(hxge_tdc_stats)/sizeof(struct hxge_stats_struct))
+
+#define PFC_STAT_OFFSET(name) offsetof(hxge_pfc_stats_t, name)
+static struct hxge_stats_struct hxge_pfc_stats[] = {
+       {"PFC ", 0},
+       {"  Packets dropped", PFC_STAT_OFFSET(pkt_drop)},
+       {"  TCAM Parity Errors", PFC_STAT_OFFSET(tcam_parity_err)},
+       {"  VLAN Parity Errors", PFC_STAT_OFFSET(tcam_parity_err)},
+       {"  Bad TCP/UDP Checksum Count ", PFC_STAT_OFFSET(bad_cs_count)},
+       {"  Drop Counter ", PFC_STAT_OFFSET(drop_count)},
+       {"  TCP Control Drop Cnt", PFC_STAT_OFFSET(errlog.tcp_ctrl_drop)},
+       {"  L2 Addr Drop Cnt", PFC_STAT_OFFSET(errlog.l2_addr_drop)},
+       {"  Class Code Drop Cnt", PFC_STAT_OFFSET(errlog.class_code_drop)},
+       {"  TCAM Drop Cnt", PFC_STAT_OFFSET(errlog.tcam_drop)},
+       {"  VLAN Drop Cnt", PFC_STAT_OFFSET(errlog.vlan_drop)},
+       {"  VLAN Parity Error Address", PFC_STAT_OFFSET(errlog.vlan_par_err_log)},
+       {"  TCAM Parity Error Address", PFC_STAT_OFFSET(errlog.tcam_par_err_log)},
+};
+#define HXGE_PFC_STATS_CNT (sizeof(hxge_pfc_stats)/sizeof(struct hxge_stats_struct))
+
+
+#define VMAC_STAT_OFFSET(name) offsetof(hxge_vmac_stats_t, name)
+static struct hxge_stats_struct hxge_vmac_stats[] = {
+       {"VMAC", 0},
+       {"  Tx Byte Cnt Overflow Ints", VMAC_STAT_OFFSET(tx_byte_cnt_overflow)},
+       {"  Tx Frame Count Overflow Ints", VMAC_STAT_OFFSET(tx_frame_cnt_overflow)},
+       {"  Tx Frame Ints", VMAC_STAT_OFFSET(frame_tx)},
+       {"  Broadcast Cnt Overflowed", VMAC_STAT_OFFSET(bcast_cnt_overflow)},
+       {"  Multicast Cnt Overflowed", VMAC_STAT_OFFSET(mcast_cnt_overflow)},
+       {"  Pause Cnt Overflowed", VMAC_STAT_OFFSET(pause_cnt_overflow)},
+       {"  CRC Error Cnt Overflowed", VMAC_STAT_OFFSET(pause_cnt_overflow)},
+       {"  Rx Drop Byte Cnt Overflowed", VMAC_STAT_OFFSET(rx_drop_byte_cnt_overflow)},
+       {"  Rx Drop Frame Cnt Overflowed", VMAC_STAT_OFFSET(rx_drop_frame_cnt_overflow)},
+       {"  Rx Frame Ints ", VMAC_STAT_OFFSET(frame_rx)},
+       {"  # Frames Transmitted", VMAC_STAT_OFFSET(tx_frame_cnt)},
+       {"  # Bytes Transmitted", VMAC_STAT_OFFSET(tx_byte_cnt)},
+       {"  # Frames Received", VMAC_STAT_OFFSET(rx_frame_cnt)},
+       {"  # Bytes Received", VMAC_STAT_OFFSET(rx_byte_cnt)},
+       {"  # Rx Frames Dropped", VMAC_STAT_OFFSET(rx_drop_frame_cnt)},
+       {"  # Rx Bytes Dropped", VMAC_STAT_OFFSET(rx_drop_byte_cnt)},
+       {"  # Rx CRC Error Frames", VMAC_STAT_OFFSET(rx_crc_cnt)},
+       {"  # Rx Pause Frames", VMAC_STAT_OFFSET(rx_pause_cnt)},
+       {"  # Rx Broadcast Frames", VMAC_STAT_OFFSET(rx_bcast_fr_cnt)},
+       {"  # Rx Multicast Frames", VMAC_STAT_OFFSET(rx_mcast_fr_cnt)}
+};
+#define HXGE_VMAC_STATS_CNT (sizeof(hxge_vmac_stats)/sizeof(struct hxge_stats_struct))
+
+wait_queue_head_t ethtool_evnt;
+volatile int ethtool_cond = 0;
+struct sk_buff *ethtool_skb;
+
+
+static int 
+hxge_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
+{
+       cmd->supported  = SUPPORTED_FIBRE;
+       cmd->advertising = ADVERTISED_FIBRE;
+       cmd->port       = PORT_FIBRE;
+       cmd->transceiver = XCVR_EXTERNAL;
+       cmd->speed = SPEED_10000;
+       cmd->duplex = DUPLEX_FULL;
+
+       return 0;
+}
+
+
+static void
+hxge_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
+{
+       struct hxge_adapter *hxgep = netdev_priv(netdev);
+       
+       strncpy(info->driver, HXGE_DRIVER_NAME, strlen(HXGE_DRIVER_NAME));
+       strncpy(info->version, hxge_driver_version, strlen(hxge_driver_version));
+       strncpy(info->fw_version, "N/A", strlen("N/A"));
+       strncpy(info->bus_info, pci_name(hxgep->pdev), strlen(pci_name(hxgep->pdev)));
+       info->testinfo_len =  HXGE_TEST_LEN;
+}
+
+
+static struct sk_buff *create_lb_frame(loopback_params_t *p, int buffer_size)
+{
+       int i;
+       struct sk_buff *skb;
+       uint8_t *ptr;
+       int pkt_len = p->pkt_len;
+
+       skb = dev_alloc_skb(pkt_len);
+       if (!skb) {
+               HXGE_DBG_PRINT("Failed to allocate skb");
+               return NULL;
+       }
+
+       /* Abusing the priority field for my own devious ends.. */
+       skb->priority = p->bad_len;
+       memset(skb_put(skb, pkt_len), 0xFF, pkt_len);
+
+       ptr = skb->data;
+       for (i = 0; i < PATT_LEN; i++)
+               ptr[i] = pattern[i];
+
+       return skb;
+}
+
+static int good_pkt(struct sk_buff *skb, int pkt_len)
+{
+       uint8_t *data = (uint8_t *)skb->data;
+       int i;
+
+       for (i = 0; i < PATT_LEN; i++)
+               if (data[i] != pattern[i])
+                       return 0;
+
+       while (i < pkt_len)
+               if (data[i++] != 0xFF) {
+                       HXGE_DBG_PRINT("failed at byte %d",i);
+                       return 0;       
+               }
+
+       return 1;
+}
+
+static int hxge_send_lb_pkts(struct hxge_adapter *hxgep, 
+                       loopback_params_t *param)
+{
+       struct tx_ring_t *tx_ring;
+       int i, j, buffer_size;
+       int num_pkts_sent = 0;
+       int pkts_to_send;
+       struct sk_buff *skb;
+
+       pkts_to_send = param->num_pkts;
+       for (i = 0; i < hxgep->max_tdcs; i++)  {
+               tx_ring = &hxgep->tx_ring[i];
+               if (pkts_to_send <= 0)
+                       pkts_to_send = tx_ring->num_tdrs;       
+               buffer_size = tx_ring->tx_buffer_size;
+               for (j = 0; j < pkts_to_send; j++)  {
+                       skb = create_lb_frame(param, buffer_size);
+                       if (!skb) 
+                               return -1;
+                       hxge_start_xmit(skb, hxgep->netdev);
+                       num_pkts_sent++;
+               }
+       }
+       HXGE_DBG(hxgep, "hxge_send_lb_pkts: %d Packets sent", num_pkts_sent);
+       return num_pkts_sent;
+               
+}
+
+
+/* Process packets that are received. Instead of sending them to the linux 
+   network stack, hxge_process_packets link up the skb's and sends it to us.
+   We free the skb's after validating the packet
+*/
+static int hxge_receive_and_validate_lb_pkts(struct hxge_adapter *hxgep,                                       loopback_params_t *param)
+{
+       int i;
+       int pkts_rcvd, tot_pkts_rcvd = 0;
+       struct sk_buff *ptr, *skb;
+       int failed = 0;
+       int pkts_freed=0;
+       int retval;
+       int mismatch = 0;
+
+
+       /* If polling, then we have to explicity call the receive function
+           to collect the packets. In interrupt case, we will get an event
+          signalling packets have arrived */
+
+       if (param->intr_type != POLLING_TYPE) {
+               HXGE_DBG(hxgep, "Waiting to receive packet..%d", ethtool_cond);
+               retval = wait_event_interruptible_timeout(ethtool_evnt, 
+                                       !ethtool_cond, 5000);
+               if (!retval) {
+                       HXGE_DBG(hxgep, "Timeout out waiting for pkt");
+               }
+               else if (retval < 0) {
+                       HXGE_DBG(hxgep, "Got interrupted - failing");
+               }
+               else  {
+                       HXGE_DBG(hxgep, "Received all packet");
+               }
+
+               if (ethtool_cond)  {
+                       HXGE_DBG(hxgep, "Did not get all the pkts");
+                       failed = -1;
+               }
+       } else {
+               for (i = 0; i < hxgep->max_rdcs; i++) {
+                       while ((pkts_rcvd = hxge_process_packets(hxgep,
+#ifdef CONFIG_HXGE_NAPI
+                                       param->tx_descs,
+#endif
+                                       i, &ethtool_skb)) > 0)
+                               tot_pkts_rcvd += pkts_rcvd;
+                       if (pkts_rcvd < 0) {
+                               HXGE_DBG(hxgep, "hxge_process_packets failed");
+                               return -1;
+                       }
+                       else if (!tot_pkts_rcvd)
+                       {
+                               HXGE_DBG(hxgep, "No packets received. Problem with sending?");
+                               return -1;
+                       }
+                       else 
+                               HXGE_DBG(hxgep, "%d packets received",tot_pkts_rcvd);
+               }
+       }
+
+       skb = ethtool_skb;
+       while (skb != NULL)  {
+               if (!good_pkt(skb, param->pkt_len))
+                       mismatch = 1;
+               ptr = skb;
+               skb = skb->next;
+               dev_kfree_skb_any(ptr);
+               pkts_freed++;
+       }
+
+       HXGE_DBG(hxgep, "%d Packets Freed",pkts_freed);
+       if (!param->bad_len && failed) {
+               if (mismatch) {
+                       HXGE_DBG(hxgep, "Packet(s) did not match! Failing test");
+               } else {
+                       HXGE_DBG(hxgep, "Receive failed");
+               }
+       } else if (param->bad_len)
+               failed = 0;
+
+       return failed;
+}
+
+static int hxge_setup_descs(struct hxge_adapter *hxgep, loopback_params_t *p)
+{
+
+       /* Allocate Tx and Rx descriptors */
+       if (hxge_alloc_tx(hxgep)) {
+               HXGE_DBG(hxgep, "hxge_setup_descs: Failed hxge_alloc_tx");
+               return -1;
+       }
+
+       if (hxge_alloc_rx(hxgep)) {
+               HXGE_DBG(hxgep, "hxge_setup_descs: Failed hxge_alloc_rx");
+               return -1;
+       }
+
+       /* Setup interrupts if needed */
+       if (hxge_setup_interrupt(hxgep->netdev)) {
+               HXGE_DBG(hxgep, "hxge_setup_interrupt failed");
+               return -1;
+       }
+
+       init_waitqueue_head(&ethtool_evnt);
+
+       hxge_enable_adapter(hxgep);
+
+       return 0;
+}
+
+int hxge_free_descs(struct hxge_adapter *hxgep, loopback_params_t *p)
+{
+
+       hxge_disable_adapter(hxgep);
+
+       hxge_teardown_interrupt(hxgep);
+
+       hxge_free_tx(hxgep);
+       hxge_free_rx(hxgep);
+
+       return 0;
+}
+               
+
+static int hxge_run_loopback_test(struct hxge_adapter *hxgep, 
+               loopback_params_t *param)
+{
+       int pkts_sent;
+
+       ethtool_cond = param->num_pkts * param->tx_channels;
+       ethtool_skb = NULL;     
+
+       /* Setup the Tx descriptor packets */
+       if ((pkts_sent = hxge_send_lb_pkts(hxgep, param)) <= 0) {
+               HXGE_DBG(hxgep, "hxge_send_lb_pkts failed. Packets not sent.");
+               return -1;
+       }
+
+       HXGE_DBG(hxgep, "Sleeping for 1 second  before processing RX...");
+       msleep(1000); /* sleep for 2 ms before processing Rx */
+
+       /* Receive the lb packets and validate them */
+       if (hxge_receive_and_validate_lb_pkts(hxgep, param)) {
+               HXGE_DBG(hxgep, "hxge_receive_and_validate_lb_pkts failed");
+               return -1;
+       }
+               
+       return 0;
+}
+
+
+/* Reset the adapter without involving any OS structures */
+static void hxge_reset(struct hxge_adapter *hxgep)
+{
+       int i;
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+
+
+       hxge_block_reset(hxgep, (LDV_RXDMA | LDV_TXDMA | LDV_VMAC));
+       for ( i = 0; i < hxgep->max_rdcs; i++) 
+               hpi_rxdma_cfg_rdc_reset(handle, i);
+       for (i = 0; i < hxgep->max_tdcs; i++)
+               hpi_txdma_channel_reset(handle, i);
+       hpi_tx_vmac_reset(handle);
+       hpi_rx_vmac_reset(handle);
+}
+
+
+
+int configure_driver_and_card(struct hxge_adapter *hxgep,
+                               loopback_params_t *param)
+{
+       uint64_t config = 0;
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+
+        if ((hxge_set_option("intr_type", param->intr_type) < 0) ||
+            (hxge_set_option("num_tx_descs", param->tx_descs) < 0) ||
+            (hxge_set_option("tx_dma_channels", param->tx_channels) < 0) ||
+            (hxge_set_option("rx_dma_channels", param->rx_channels) < 0) ||
+            (hxge_set_option("rcr_entries", param->rcr_entries) < 0) ||
+            (hxge_set_option("rbr_entries", param->rbr_entries) < 0) ||
+           (hxge_set_option("rcr_threshold", param->rcr_threshold) < 0) ||
+            (hxge_set_option("rcr_timeout", param->rcr_timeout) < 0))
+                return -1;
+
+        hxge_reset(hxgep);
+
+       /* Set up descriptors. Going to poll for Rx packets; no interrupts
+           enabled here */
+       if (hxge_setup_descs(hxgep,param)) {
+               HXGE_DBG(hxgep, "configure_driver_and_card: Setting up descs failed");
+               return -1;
+       }
+
+       /* Set the adapter in loopback mode now. Make sure that the STRIP_CRC
+           is disabled due to a HW bug */
+        config = CFG_VMAC_RX_PROMISCUOUS_MODE | CFG_VMAC_RX_EN |
+                       CFG_VMAC_RX_PROMISCUOUS_GROUP | CFG_VMAC_RX_LOOP_BACK;
+       if (hpi_vmac_rx_config(handle, INIT, config, 0) == HPI_FAILURE) {
+               HXGE_DBG(hxgep, "configure_driver_and_card: Could not configure VMAC Rx");
+               goto free_descs;
+       }
+
+       config = CFG_VMAC_TX_EN | CFG_VMAC_TX_CRC_INSERT;
+       if (hpi_vmac_tx_config(handle, INIT, config, 0) == HPI_FAILURE) {
+               HXGE_DBG(hxgep, "configure_driver_and_card: Could not configure VMAC Tx");
+               goto free_descs;
+       }
+
+       return 0;
+
+free_descs:
+       hxge_free_descs(hxgep,param);
+       return -1;
+}
+
+static int deconfigure_driver_and_card(struct hxge_adapter *hxgep,
+                       loopback_params_t *p)
+{
+       uint64_t config = 0;
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+
+       flush_scheduled_work();
+
+       config = 0;
+       hpi_vmac_rx_config(handle, INIT, config, 0);
+
+       hxge_free_descs(hxgep,p);
+
+       return 0;
+}
+
+static int hxge_loopback_test(struct hxge_adapter *hxgep, loopback_params_t *p)
+{
+       int failed = 0;
+
+       if (configure_driver_and_card(hxgep, p)) {
+               HXGE_DBG(hxgep, "hxge_loopback_test: failed to configure device");                      return -1;
+       }
+
+       if (hxge_run_loopback_test(hxgep, p)) {
+               HXGE_DBG(hxgep, "hxge_loopback_test: Loopback Test failed");
+               failed = -1;
+       }
+
+       deconfigure_driver_and_card(hxgep, p);
+
+       return failed;
+}
+
+static void hxge_diag_test(struct net_device *netdev, 
+               struct ethtool_test *eth_test, uint64_t *data)
+{
+       struct hxge_adapter *hxgep = netdev_priv(netdev);
+       boolean_t if_running = netif_running(netdev);
+       int link_up = hxge_peu_get_link_status(hxgep);
+       int i;
+       loopback_params_t *param;
+       loopback_params_t orig_params;
+       char *str;
+       int num_tests;
+                       
+       num_tests = sizeof(loopback_params)/sizeof(loopback_params_t);
+       for (i = 0, param = loopback_params; i < num_tests; i++)
+       {
+               str = strstr(hxge_gstrings_test[i], "=");
+               if (!str) {
+                       HXGE_ERR(hxgep, "Error in test strings construct");
+                       return;
+               }
+               str += 2; /* skip = and a space */
+               strncpy(str, "NOTRUN", strlen("NOTRUN"));
+       }
+
+       for (i = 0; i < num_tests; i++) 
+               data[i] = 0;
+
+       /* These are offline tests */
+       if (eth_test->flags == ETH_TEST_FL_OFFLINE) 
+               HXGE_DBG(hxgep, "hxge_diag_test: Offline test starting");
+
+       set_bit(HXGE_DEVICE_TESTING, &hxgep->state);
+
+       /* Close the device before running this offline test */
+       if (if_running) {
+               HXGE_ERR(hxgep, "hxge_diag_test: Cannot run offline test on a running  interface. Bring interface down before attempting offline tests!");
+               eth_test->flags |= ETH_TEST_FL_FAILED;
+               return;
+       }
+
+       if (link_up) {
+               HXGE_ERR(hxgep, "hxge_diag_test: Link should be down for offline tests");
+               eth_test->flags |= ETH_TEST_FL_FAILED;
+               return;
+       }
+
+
+       if ((hxge_get_option("intr_type", &orig_params.intr_type) < 0) ||
+           (hxge_get_option("num_tx_descs",&orig_params.tx_descs) < 0) ||
+           (hxge_get_option("tx_dma_channels", &orig_params.tx_channels) < 0) ||
+           (hxge_get_option("rx_dma_channels", &orig_params.rx_channels) < 0) ||
+           (hxge_get_option("rcr_entries", &orig_params.rcr_entries) < 0) ||
+           (hxge_get_option("rbr_entries", &orig_params.rbr_entries) < 0) ||
+           (hxge_get_option("rcr_threshold", &orig_params.rcr_threshold) < 0) ||
+           (hxge_get_option("rcr_timeout", &orig_params.rcr_timeout) < 0))
+       {
+               eth_test->flags |= ETH_TEST_FL_FAILED;
+               return;
+       }
+
+
+
+       for (i = 0, param = loopback_params; i < num_tests; i++)
+       {
+               str = strstr(hxge_gstrings_test[i], "=");
+               if (!str) {
+                       HXGE_ERR(hxgep, "Error in test strings construct");
+                       return;
+               }
+               str += 2; /* skip = and a space */
+               HXGE_DBG(hxgep, "*** LOOPBACK TEST %d", i);
+               if (hxge_loopback_test(hxgep, &param[i])) {
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+                       strncpy(str, "FAILED", strlen("FAILED"));
+                       break;
+               }
+               /* Replace FAILED with PASSED */
+               strncpy(str, "PASSED", strlen("PASSED"));
+               data[i] = 1;
+       }
+
+        /* restore parameters to original value */
+        hxge_set_option("rbr_entries", orig_params.rbr_entries);
+        hxge_set_option("rcr_entries", orig_params.rcr_entries);
+        hxge_set_option("rx_dma_channels", orig_params.rx_channels);
+        hxge_set_option("tx_dma_channels", orig_params.tx_channels);
+        hxge_set_option("num_tx_descs", orig_params.tx_descs);
+       hxge_set_option("intr_type", orig_params.intr_type);
+       hxge_set_option("rcr_threshold", orig_params.rcr_threshold);
+       hxge_set_option("rcr_timeout", orig_params.rcr_timeout);
+
+       clear_bit(HXGE_DEVICE_TESTING, &hxgep->state);
+}
+
+static void
+hxge_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data)
+{
+       struct hxge_adapter *hxgep = netdev_priv(netdev);
+       int i, j, offset = 0;
+
+       switch (stringset) {
+       case ETH_SS_TEST:
+               memcpy(data, hxge_gstrings_test, 
+                       HXGE_TEST_LEN*ETH_GSTRING_LEN);
+               break;
+       case ETH_SS_STATS:
+               for (i = 0; i < hxgep->max_rdcs; i++)
+                       for (j = 0; j < HXGE_RDC_STATS_CNT; j++)  {
+                               memcpy(&data[offset], 
+                                      hxge_rdc_stats[j].name, ETH_GSTRING_LEN);
+                               offset += ETH_GSTRING_LEN;
+               }
+               for (i = 0; i < hxgep->max_tdcs; i++)
+                       for (j = 0; j < HXGE_TDC_STATS_CNT; j++)  {
+                               memcpy(&data[offset], 
+                                      hxge_tdc_stats[j].name, ETH_GSTRING_LEN);
+                               offset += ETH_GSTRING_LEN;
+               }
+               for (j = 0; j < HXGE_PFC_STATS_CNT; j++) {
+                       memcpy(&data[offset], 
+                              hxge_pfc_stats[j].name, ETH_GSTRING_LEN);
+                       offset += ETH_GSTRING_LEN;
+               }
+               for (j = 0; j < HXGE_VMAC_STATS_CNT; j++) {
+                       memcpy(&data[offset], 
+                              hxge_vmac_stats[j].name, ETH_GSTRING_LEN);
+                       offset += ETH_GSTRING_LEN;
+               }
+               break;
+       default: HXGE_ERR(hxgep, "hxge_get_strings: Unsupported type");
+                break;
+
+       }
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)
+static int 
+hxge_diag_test_count(struct net_device *netdev)
+{
+       return HXGE_TEST_LEN;
+}
+#endif
+
+static u32 hxge_get_tx_csum(struct net_device *netdev)
+{
+       struct hxge_adapter *hxgep = netdev_priv(netdev);
+       return ((hxgep->flags & HXGE_TX_CHKSUM_ENABLED) != 0);
+}
+
+static int hxge_set_tx_csum (struct net_device *netdev, u32 data)
+{
+        struct hxge_adapter *hxgep = netdev_priv(netdev);
+       int i;
+
+        if (data) 
+       {
+               if (hxgep->flags & HXGE_TX_CHKSUM_ENABLED)
+                       return 0;
+
+               hxgep->flags |= HXGE_TX_CHKSUM_ENABLED;
+                netdev->features |= NETIF_F_IP_CSUM;
+       } 
+       else 
+       {
+               if (!(hxgep->flags & HXGE_TX_CHKSUM_ENABLED))
+                       return 0;
+                       
+               hxgep->flags &= ~HXGE_TX_CHKSUM_ENABLED;
+               /* Both chksum flags need to disabled for HW to be disabled */
+               if (!(hxgep->flags & HXGE_CHKSUM_ENABLED))
+                       netdev->features &= ~NETIF_F_IP_CSUM;
+       }
+
+       for (i = 0; i < hxgep->max_tdcs; i++)
+               hxge_reset_tx_channel(hxgep, i);
+        return 0;
+}
+
+static u32 hxge_get_rx_csum(struct net_device *netdev)
+{
+        struct hxge_adapter *hxgep = netdev_priv(netdev);
+       return ((hxgep->flags & HXGE_RX_CHKSUM_ENABLED) != 0);
+}
+
+
+static int hxge_set_rx_csum(struct net_device *netdev, u32 data)
+{
+        struct hxge_adapter *hxgep = netdev_priv(netdev);
+       int i;
+
+       if (data)
+       {
+               if (hxgep->flags & HXGE_RX_CHKSUM_ENABLED)
+                       return 0;
+
+               hxgep->flags |= HXGE_RX_CHKSUM_ENABLED;
+                netdev->features |= NETIF_F_IP_CSUM;
+       }
+       else 
+       {
+               if (!(hxgep->flags & HXGE_RX_CHKSUM_ENABLED))
+                       return 0;
+
+               hxgep->flags &= ~HXGE_RX_CHKSUM_ENABLED;
+               netdev->features &= ~NETIF_F_IP_CSUM;
+       }
+
+       for (i = 0; i < hxgep->max_rdcs; i++)
+               hxge_reset_rx_channel(hxgep, i);
+
+       return 0;
+}
+
+static int hxge_get_stats_count(struct net_device *netdev)
+{
+        struct hxge_adapter *hxgep = netdev_priv(netdev);
+       int stats_count;
+
+       stats_count = (hxgep->max_rdcs * HXGE_RDC_STATS_CNT);
+       stats_count += (hxgep->max_tdcs * HXGE_TDC_STATS_CNT);
+       stats_count += HXGE_PFC_STATS_CNT;
+       stats_count += HXGE_VMAC_STATS_CNT;
+       return (stats_count);
+}
+
+
+static void hxge_get_ethtool_stats(struct net_device *netdev, 
+               struct ethtool_stats *stats, uint64_t *data)
+{
+        struct hxge_adapter *hxgep = netdev_priv(netdev);
+       struct rx_ring_t *rx_ring;
+       struct tx_ring_t *tx_ring;
+       int i, j, offset = 0;
+       uint32_t stat;
+       p_hxge_stats_t  statsp = hxgep->statsp;
+       p_hxge_pfc_stats_t pfc_statsp;
+       p_hxge_vmac_stats_t vmac_statsp;
+
+       /* None of the data structures are allocated yet; so, nothing to
+          show yet */
+       if (!test_bit(HXGE_DEVICE_ALLOCATED, &hxgep->state)) {
+               memset(data, 0, hxge_get_stats_count(netdev)*sizeof(uint64_t));
+               return;
+       }
+
+       for (i = 0; i < hxgep->max_rdcs;  i++) {
+               rx_ring = &hxgep->rx_ring[i];
+               data[offset++] = rx_ring->rdc;
+               for (j = 1; j < HXGE_RDC_STATS_CNT; j++)
+                       data[offset++] = *(uint64_t *)((char *)&rx_ring->stats + hxge_rdc_stats[j].offset);
+       }
+
+       for (i = 0; i < hxgep->max_tdcs;  i++) {
+               tx_ring = &hxgep->tx_ring[i];
+               data[offset++] = tx_ring->tdc;
+               for (j = 1; j < HXGE_TDC_STATS_CNT; j++)
+                       data[offset++] = *(uint64_t *)((char *)&tx_ring->stats + hxge_tdc_stats[j].offset);
+       }
+
+       pfc_statsp = &statsp->pfc_stats;
+       data[offset++] = 0;
+       for (j = 1; j < HXGE_PFC_STATS_CNT; j++) {
+               stat = *(uint32_t *)((char *)pfc_statsp + hxge_pfc_stats[j].offset);
+               data[offset++] = (uint64_t)stat;
+       }
+
+       vmac_statsp = &statsp->vmac_stats;
+       data[offset++] = 0;
+       for (j = 1; j < HXGE_VMAC_STATS_CNT; j++) 
+               data[offset++]= *(uint64_t *)((char *)vmac_statsp + hxge_vmac_stats[j].offset);
+}
+
+static uint32_t hxge_get_msglevel(struct net_device *netdev)
+{
+       struct hxge_adapter *hxgep = netdev_priv(netdev);
+       return (hxgep->msg_enable);
+}
+
+static void hxge_set_msglevel(struct net_device *netdev, uint32_t data)
+{
+       struct hxge_adapter *hxgep = netdev_priv(netdev);
+       hxgep->msg_enable = data;
+}
+
+static int
+hxge_get_coalesce_intr(struct net_device *dev,
+                                           struct  ethtool_coalesce *intr_param)
+{
+        struct hxge_adapter *hxgep = netdev_priv(dev);
+
+       /* 250MHz clock that is divided down by HXGE_RCR_CLK_RESO value. So,
+          1 tick = 0.004 usec */
+
+        intr_param->rx_coalesce_usecs =        /* 32-bit safe integer expression */
+               hxgep->rcr_timeout * ((4 * HXGE_RCR_CLK_RESO)/1000);
+        intr_param->rx_max_coalesced_frames = hxgep->rcr_threshold;
+        intr_param->rx_max_coalesced_frames_irq = hxgep->max_rx_pkts;
+       intr_param->use_adaptive_rx_coalesce = hxgep->adaptive_rx;
+        return 0;
+}
+
+static int
+hxge_set_coalesce_intr(struct net_device *dev,
+                                           struct  ethtool_coalesce *intr_param)
+{
+        struct hxge_adapter *hxgep = netdev_priv(dev);
+       int i;
+
+       /* Illegal to have both set to zero as this would disable both the
+           threshold and timeout mechanisms resulting in no Rx interrupt
+          generation */
+        if ((intr_param->rx_max_coalesced_frames == 0) &&
+                (intr_param->rx_coalesce_usecs == 0)) {
+                return (1);
+        }
+        if ((intr_param->rx_max_coalesced_frames_irq < HXGE_MAX_RX_PKTS_MIN) ||
+           (intr_param->rx_max_coalesced_frames_irq > HXGE_MAX_RX_PKTS_MAX))
+                return (1);
+
+       if (intr_param->rx_max_coalesced_frames > HXGE_RCR_THRESHOLD_MAX)
+               return (1);
+
+       spin_lock(&hxgep->lock);
+
+       hxgep->adaptive_rx = intr_param->use_adaptive_rx_coalesce;
+        if (intr_param->rx_coalesce_usecs) {
+               hxgep->rcr_timeout =    /* 32-bit safe arithmetic */
+                       (uint32_t)(intr_param->rx_coalesce_usecs
+                                  / ((4 * HXGE_RCR_CLK_RESO)/1000));
+                hxgep->rcr_cfgb_cpy = RCR_CFGB_ENABLE_TIMEOUT | hxgep->rcr_timeout;
+        } else {
+                hxgep->rcr_timeout= 0;
+               hxgep->rcr_cfgb_cpy = 0;
+        }
+
+        hxgep->rcr_threshold =  intr_param->rx_max_coalesced_frames;
+        hxgep->max_rx_pkts =  intr_param->rx_max_coalesced_frames_irq;
+
+       for (i = 0; i < hxgep->max_rdcs; i++) {
+               struct rx_ring_t *rx_ring = &hxgep->rx_ring[i];
+               if (test_bit(RING_ENABLED, &rx_ring->state))
+                       RXDMA_REG_WRITE64(hxgep->hw.hw_addr, RDC_RCR_CFG_B, i, hxgep->rcr_threshold << 16 | hxgep->rcr_cfgb_cpy);
+       }
+
+       spin_unlock(&hxgep->lock);
+        return 0;
+}
+
+static struct ethtool_ops hxge_ethtool_ops = {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)
+       .self_test_count        = hxge_diag_test_count,
+       .get_stats_count        = hxge_get_stats_count,
+#endif
+       .get_drvinfo            = hxge_get_drvinfo,
+       .get_settings           = hxge_get_settings,
+       .self_test              = hxge_diag_test,
+       .get_strings            = hxge_get_strings,
+        .get_tx_csum            = hxge_get_tx_csum,
+        .set_tx_csum            = hxge_set_tx_csum,
+       .get_rx_csum            = hxge_get_rx_csum,
+       .set_rx_csum            = hxge_set_rx_csum,
+       .get_ethtool_stats      = hxge_get_ethtool_stats,
+       .get_msglevel           = hxge_get_msglevel,
+       .set_msglevel           = hxge_set_msglevel,
+       .get_tso                = ethtool_op_get_tso,
+       .set_tso                = ethtool_op_set_tso,
+        .get_coalesce           = hxge_get_coalesce_intr,
+        .set_coalesce           = hxge_set_coalesce_intr,
+       .get_link               = ethtool_op_get_link
+};
+
+
+void hxge_set_ethtool_ops(struct net_device *netdev)
+{
+               SET_ETHTOOL_OPS(netdev, &hxge_ethtool_ops);
+
+}
diff --git a/drivers/net/hxge/hxge_intr.c b/drivers/net/hxge/hxge_intr.c
new file mode 100644 (file)
index 0000000..29e0c86
--- /dev/null
@@ -0,0 +1,851 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#include "hpi/hpi_vir.h"
+#include "hpi/hpi_rxdma.h"
+#include "hxge.h"
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+extern irqreturn_t hxge_pfc_intr(int irq, void *data, struct pt_regs *regs);
+extern irqreturn_t hxge_vmac_intr(int irq, void *data, struct pt_regs *regs);
+extern irqreturn_t hxge_rx_intr(int irq, void *data, struct pt_regs *regs);
+extern irqreturn_t hxge_rx_deverr_intr(int irq, void *data, struct pt_regs *regs);
+extern irqreturn_t hxge_tx_intr(int irq, void *data, struct pt_regs *regs);
+extern irqreturn_t hxge_tx_deverr_intr(int irq, void *data, struct pt_regs *regs);
+extern irqreturn_t hxge_peu_deverr_intr(int irq, void *data, struct pt_regs *regs);
+#else
+extern irqreturn_t hxge_pfc_intr(int irq, void *data);
+extern irqreturn_t hxge_vmac_intr(int irq, void *data);
+extern irqreturn_t hxge_rx_intr(int irq, void *data);
+extern irqreturn_t hxge_rx_deverr_intr(int irq, void *data);
+extern irqreturn_t hxge_tx_intr(int irq, void *data);
+extern irqreturn_t hxge_tx_deverr_intr(int irq, void *data);
+extern irqreturn_t hxge_peu_deverr_intr(int irq, void *data);
+#endif
+
+extern int hxge_get_option(const char *str, int *val);
+
+static void hxge_dump_ints(struct hxge_adapter *hxgep);
+static void hxge_enable_ldg_ints(struct hxge_ldg *ldgp);
+void hxge_teardown_interrupt(struct hxge_adapter *hxgep);
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+static irqreturn_t hxge_deverr_intr (int irq, void *data, struct pt_regs *regs)
+#else
+static irqreturn_t hxge_deverr_intr (int irq, void *data)
+#endif
+{
+       struct hxge_ldv *ldvp = (struct hxge_ldv *)data;
+       struct hxge_adapter *hxgep = ldvp->ldgp->hxgep;
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+       dev_err_stat_t dsts;
+       hpi_status_t hsts;
+
+       dsts.value = 0;
+       hsts = hpi_fzc_sys_err_stat_get(handle, &dsts);
+       if (hsts != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hxge_deverr_intr: Can't read DEV_ERR_STAT register");
+               /* Not clear what to do now...probably go down in flames...
+                * fake up a DEV_ERR_STAT with lotsa bits set, and see if
+                * the individual handlers have anything to report.  We
+                * should probably down/reset the whole device.
+                */
+               dsts.value = 0xF; /* TDC/RDC/PEU/VMAC "errors" */
+       }
+
+       if (!dsts.value) {
+               HXGE_ERR(hxgep, "hxge_deverr_intr: DEV_ERR_STAT register empty:");
+               return (IRQ_NONE);
+       }
+
+       HXGE_DBG(hxgep, "hxge_deverr_intr: Device Error Interrupt! (0x%8.8x)",
+                dsts.value);
+
+       /* Look for TX, RX, or general (VMAC/PEU) and "dispatch" */
+
+       if (dsts.bits.tdc_err0 || dsts.bits.tdc_err1) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+               hxge_tx_deverr_intr(irq, ldvp, regs);
+#else
+               hxge_tx_deverr_intr(irq, ldvp);
+#endif
+               dsts.bits.tdc_err0 = 0;
+               dsts.bits.tdc_err1 = 0;
+       }
+
+       if (dsts.bits.rdc_err0 || dsts.bits.rdc_err1) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+               hxge_rx_deverr_intr(irq, ldvp, regs);
+#else
+               hxge_rx_deverr_intr(irq, ldvp);
+#endif
+               dsts.bits.rdc_err0 = 0;
+               dsts.bits.rdc_err1 = 0;
+       }
+
+       if (dsts.bits.vnm_pio_err1 || dsts.bits.peu_err1) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+               hxge_peu_deverr_intr(irq, ldvp, regs);
+#else
+               hxge_peu_deverr_intr(irq, ldvp);
+#endif
+               dsts.bits.vnm_pio_err1 = 0;
+               dsts.bits.peu_err1 = 0;
+       }
+
+       if (dsts.value) {
+               HXGE_ERR(hxgep, "hxge_deverr_intr: Unexpected/unknown DEV_ERR_STAT flags: %8.8x", dsts.value);
+       }
+
+       return (IRQ_HANDLED);
+}
+
+/**
+ * hxge_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ * @pt_regs: CPU registers structure
+ **/
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+static irqreturn_t
+hxge_intr(int irq, void *data, struct pt_regs *regs)
+#else
+static irqreturn_t
+hxge_intr(int irq, void *data)
+#endif
+{
+       struct hxge_ldg *ldgp = (struct hxge_ldg *)data;
+       struct hxge_ldv *ldvp;
+       irqreturn_t status = IRQ_NONE;
+       int ldf0, ldf1;
+
+
+       list_for_each_entry(ldvp, &ldgp->ldv_list, ldg_list) {
+
+               /* Check if there is an interrupt for this device */
+               get_ldf_flags(ldvp, &ldf0, &ldf1);
+               if (!ldf0 && !ldf1)
+                       continue;
+
+               /* We're banking on the fact that IRQ_NONE is zero; otherwise
+                  this neat trick won't work! */
+               switch (ldvp->dev_type) {
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+               case LDV_TXDMA :
+                       status |= hxge_tx_intr(irq, ldvp, regs);
+                       break;
+               case LDV_VMAC :
+                       status |= hxge_vmac_intr(irq, ldvp, regs);
+                       break;
+               case LDV_PFC :
+                       status |= hxge_pfc_intr(irq, ldvp, regs);
+                       break;
+               case LDV_DEVERR :
+                       status |= hxge_deverr_intr(irq, ldvp, regs);
+                       break;
+               case LDV_RXDMA :
+                       status |= hxge_rx_intr(irq, ldvp, regs);
+                       break;
+#else
+               case LDV_TXDMA :
+                       status |= hxge_tx_intr(irq, ldvp);
+                       break;
+               case LDV_VMAC :
+                       status |= hxge_vmac_intr(irq, ldvp);
+                       break;
+               case LDV_PFC :
+                       status |= hxge_pfc_intr(irq, ldvp);
+                       break;
+               case LDV_DEVERR :
+                       status |= hxge_deverr_intr(irq, ldvp);
+                       break;
+               case LDV_RXDMA :
+                       status |= hxge_rx_intr(irq, ldvp);
+                       break;
+#endif
+
+               default : HXGE_ERR_PRINT("hxge_intr: Unknown device %d", ldvp->ldv);
+                       status = IRQ_HANDLED;
+               }
+       }
+
+       /* Enable interrutps for this logical device group */
+       if (status == IRQ_HANDLED)
+               hxge_enable_ldg_ints(ldgp);
+
+        return status;
+}
+
+
+
+/* Basic utility routine that enables or disables interrupts for the 
+   devices (blocks) within hydra that are supported */
+static int hxge_interrupt_mgmt(struct hxge_adapter *hxgep, int enable_int,
+                               int mask_int, int dev_type, 
+                               struct hxge_ldg *dev, int channel)
+{
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+       struct hxge_ldv *ldvp;
+       struct hxge_ldg *ldgp;
+       int status;
+       int arm = FALSE;
+       uint8_t masks = (uint8_t)LD_IM_MASK;
+
+
+       if (hxgep->intr_type == POLLING_TYPE)
+               return 0;
+
+       /* If interrutps are enabled, then
+               a) arm the logical device groups
+               b) Enable the timer as well
+       */
+       if (enable_int) 
+               arm = TRUE;
+
+       /* If mask_int is not true, then clear the LDF masks for the devices */
+       if (!mask_int)
+               masks = 0;
+
+       list_for_each_entry(ldgp, &hxgep->ldgvp->ldgp, list) {
+               if (dev && (dev != ldgp))
+                       continue;
+               if (mask_int >= 0) {
+                       list_for_each_entry(ldvp, &ldgp->ldv_list, ldg_list) {
+                               if (ldvp->dev_type & dev_type) {
+                                       if (channel >= 0) {
+                                          if (dev_type == LDV_RXDMA)
+                                             channel += HXGE_RDMA_LD_START;
+                                          else if (dev_type == LDV_TXDMA)
+                                             channel += HXGE_TDMA_LD_START;
+                                          if (channel != ldvp->ldv)
+                                               continue;
+                                       }
+                                       ldvp->ldf_masks = masks;
+                                       status = hpi_intr_mask_set(handle, 
+                                                       ldvp->ldv, masks);
+                                       if (status != HPI_SUCCESS) {
+                                               HXGE_ERR(hxgep, "hpi_intr_mask_set failed");
+                                               return -1;
+                                       }
+                               }
+                       }
+               }
+               if (enable_int >= 0) {
+                       ldgp->arm = arm;
+                       status = hpi_intr_ldg_mgmt_set(handle, 
+                                       ldgp->ldg, arm, ldgp->timer);
+                       if (status != HPI_SUCCESS) {
+                               HXGE_ERR(hxgep, "hpi_intr_ldg_mgmt_set failed");
+                               return -1;
+                       }
+               }
+       }
+       return 0;
+}
+
+void get_ldf_flags(struct hxge_ldv *ldvp, int *ldf0, int *ldf1)
+{
+        hpi_handle_t    handle = ldvp->ldgp->hxgep->hw.hw_addr;
+        uint32_t vector0, vector1;
+
+        *ldf0 = 0;
+        *ldf1 = 0;
+
+        if (hpi_ldsv_ldfs_get(handle, ldvp->ldgp->ldg, &vector0, &vector1)
+               != HPI_SUCCESS) {
+               HXGE_ERR_PRINT("get_ldf_flags: hpi_ldsv_ldfs_get failed");
+       }
+       
+        /* Only check for regular LDF0 interrupt. LDF1 implies error and
+           is handled in a separate context. Also, LDF0 implies that the
+           RCR Threshold and/or RCR Timeout bits in the RDC control/status
+           register is set */
+        *ldf0 = ((vector0 &  (1 << ldvp->ldv)) != 0);
+
+        /* LDF1 indicates fatal error happened. Have to parse the RDC control
+           register for the exact error(s) */
+        *ldf1 = ((vector1 &  (1 << ldvp->ldv)) != 0);
+}
+
+
+void hxge_enable_interrupts(struct hxge_adapter *hxgep)
+{
+       hxge_interrupt_mgmt(hxgep, 1, 0, LDV_ALL, NULL, -1);
+}
+
+void hxge_disable_interrupts(struct hxge_adapter *hxgep)
+{
+       hxge_interrupt_mgmt(hxgep, 0, 1, LDV_ALL, NULL, -1);
+}
+
+void hxge_enable_rx_ints(struct hxge_adapter *hxgep, struct hxge_ldg *dev,
+                       int rdc)
+{  
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+       struct hxge_ldv *ldvp;
+       struct hxge_ldg *ldgp;
+       rdc_stat_t cs;
+       int channel;
+
+       if (hxgep->intr_type == POLLING_TYPE)
+               return;
+
+       /* For Rx devices, re-enable the mailbox interrupt
+           and couple of RCR bits. These are 1-shot and potentially need
+          to be reset */
+        list_for_each_entry(ldgp, &hxgep->ldgvp->ldgp, list) {
+               if (dev && (dev != ldgp))
+                       continue;
+                list_for_each_entry(ldvp, &ldgp->ldv_list, ldg_list) {
+                       if (ldvp->dev_type != LDV_RXDMA)
+                               continue;
+                       channel = ldvp->ldv-HXGE_RDMA_LD_START;
+                       if ((rdc >= 0) && (channel != rdc))
+                               continue;
+
+                       /* set up the CS register. The rcr timeout and 
+                        * threshold were cleared in process_rx, when the
+                        * cs register was read. If those bits are cleared
+                        * here, we could wipe out a potential pending 
+                        * threshold and/or timeout interrupt inadvertantly
+                        * (related to CR 6774415). So, clear all bits except
+                        * ptrs and pkts read when processing interrupts
+                        */
+
+                       cs.value = (ldvp->data & 
+                              (RDC_STAT_PKTREAD_MASK | RDC_STAT_PTRREAD_MASK));
+                        cs.bits.mex = 1;
+
+#ifdef DETECT_RCR_FULL
+                       /* Temporary Check: To detect RCR Full conditions
+                        * till we resolve the alignment requirement  issues
+                        * with RCR and RBRs
+                        */
+                       do {
+                               rdc_stat_t curr_cs;
+                               hpi_rxdma_control_status(handle, OP_GET,
+                                 ldvp->ldv-HXGE_RDMA_LD_START, &curr_cs);
+                               if (curr_cs.bits.rcr_full) {
+                                       HXGE_ERR(hxgep, "hxge_enable_rx_ints: RCR Full caught!");
+                               }
+                       } while (0);
+#endif
+                                       
+                        /* read nothing; don't want to write
+                           random old value in cs back! */
+                        if (hpi_rxdma_control_status(handle, OP_SET, 
+                                       ldvp->ldv-HXGE_RDMA_LD_START, &cs) != 
+                                       HPI_SUCCESS) {
+                               HXGE_ERR(hxgep, "hxge_enable_rx_ints: Failed to read Rx channel %d",ldvp->ldv-HXGE_RDMA_LD_START);
+                       }
+       
+               }
+       }
+       hxge_interrupt_mgmt(hxgep, -1, 0, LDV_RXDMA, dev, rdc);
+}
+
+void hxge_disable_rx_ints(struct hxge_adapter *hxgep, struct hxge_ldg *ldgp, 
+                         int rdc)
+{
+       hxge_interrupt_mgmt(hxgep, -1, 1, LDV_RXDMA, ldgp, rdc);
+}
+
+void hxge_enable_tx_ints(struct hxge_adapter *hxgep, struct hxge_ldg *ldgp)
+{
+       hxge_interrupt_mgmt(hxgep, -1, 0, LDV_TXDMA, ldgp, -1);
+}
+
+static void hxge_enable_ldg_ints(struct hxge_ldg *ldgp)
+{
+       hxge_interrupt_mgmt(ldgp->hxgep , 1, -1, LDV_ALL, ldgp, -1);
+}
+
+void hxge_disable_ldg_ints(struct hxge_ldg *ldgp)
+{
+       hxge_interrupt_mgmt(ldgp->hxgep , 0, -1, LDV_ALL, ldgp, -1);
+}
+
+void hxge_disable_tx_ints(struct hxge_adapter *hxgep)
+{
+       hxge_interrupt_mgmt(hxgep, -1, 1, LDV_TXDMA, NULL, -1);
+}
+
+
+
+/* Set up the hydra registers related to interrupt management. However,
+   interrupts are only enabled when the interaface is brought up i.e in
+   hxge_up 
+*/
+int hxge_set_hw_interrupt_regs (struct hxge_adapter *hxgep)
+{
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+       hpi_status_t    status = HPI_SUCCESS;
+       fzc_sid_t       sid;
+       int             i;
+       struct hxge_ldv *ldvp;
+       struct hxge_ldg *ldgp;
+
+       /* Configure the initial timer resolution */
+       if (hpi_fzc_ldg_timer_res_set (handle, hxgep->ldgvp->tmres)
+               != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hpi_fzc_ldg_timer_res_set failed");
+               return -1;
+       }
+               
+
+       /* Set up the logical device groups and relate them to the logical
+          devices. Also program the sid values  */
+
+       i = 0;
+       list_for_each_entry(ldgp, &hxgep->ldgvp->ldgp, list) {
+               list_for_each_entry(ldvp, &ldgp->ldv_list, ldg_list) {
+                       HXGE_DBG(hxgep, "Setting LDV %d->LDG %d",ldvp->ldv,ldgp->ldg);
+                       status = hpi_fzc_ldg_num_set(handle, ldvp->ldv, 
+                                       ldgp->ldg);
+                       if (status != HPI_SUCCESS) {
+                               HXGE_ERR(hxgep, "hpi_fzc_ldg_num_set failed");
+                               return -1;
+                       }
+               }
+               sid.vector = i++; /* just has to be unique for each entry */
+               sid.ldg = ldgp->ldg;
+               if (hpi_fzc_sid_set(handle, sid) != HPI_SUCCESS) {
+                       HXGE_ERR(hxgep, "hpi_fzc_sid_set failed");
+                       return -1;
+               }
+       }
+
+       return 0;
+          
+}
+
+/* Return the number of logical device groups that we want to support. This
+   is purely programmatic. The assumption in picking the number of groups
+   is the best potential combination that would minimize interrupt latency
+   and maximize throughput */
+
+static int get_num_ldgs(struct hxge_adapter *hxgep, struct ldv_array *ldv)
+{
+        int nldgs = 0;
+        int i;
+
+        /* Each Tx channel has its own group */
+        nldgs += hxgep->max_tdcs;
+        for (i = 0; i < hxgep->max_tdcs; i++) {
+                ldv->type =  LDV_TXDMA;
+                ldv->dev_no = HXGE_TDMA_LD_START+i;
+                ldv++;
+        }
+
+        /* Each Rx channel */
+        nldgs += hxgep->max_rdcs;
+        for (i = 0; i < hxgep->max_rdcs; i++) {
+                ldv->type =  LDV_RXDMA;
+                ldv->dev_no = HXGE_RDMA_LD_START+i;
+                ldv++;
+        }
+
+        /* VMAC */
+        nldgs++;
+        ldv->type = LDV_VMAC;
+        ldv->dev_no = HXGE_VMAC_LD;
+        ldv++;
+
+        /* PFC */
+        nldgs++;
+        ldv->type = LDV_PFC;
+        ldv->dev_no = HXGE_PFC_LD;
+        ldv++;
+
+        /* Device Errors */
+        nldgs++;
+        ldv->type = LDV_DEVERR;
+        ldv->dev_no = HXGE_SYS_ERROR_LD;
+
+        return nldgs;
+}
+
+
+static void
+hxge_ldg_uninit(struct hxge_adapter *hxgep)
+{
+        struct hxge_ldv *ldvp, *loc_ldvp;
+        struct hxge_ldg *ldgp, *loc_ldgp;
+
+        list_for_each_entry_safe(ldvp, loc_ldvp, &hxgep->ldgvp->ldvp, list) 
+                kfree(ldvp);
+
+        list_for_each_entry_safe(ldgp, loc_ldgp, &hxgep->ldgvp->ldgp, list) 
+                kfree(ldgp);
+
+        kfree(hxgep->ldgvp);
+
+}
+
+static void hxge_dump_ints(struct hxge_adapter *hxgep)
+{
+        struct hxge_ldgv *ldgvp;
+        struct hxge_ldv *ldvp;
+        struct hxge_ldg *ldgp;
+
+       HXGE_DBG(hxgep, "Hydra Interrupt Structure =>");
+       ldgvp = hxgep->ldgvp;
+       HXGE_DBG(hxgep, "  Timer resolution = 0x%x",ldgvp->tmres);
+       HXGE_DBG(hxgep, "  Max groups = 0x%x",ldgvp->max_ldgs);
+       HXGE_DBG(hxgep, "  Max devices = 0x%x",ldgvp->max_ldvs);
+       HXGE_DBG(hxgep, "  No. of groups = 0x%x",ldgvp->nldgs);
+       HXGE_DBG(hxgep, "  No. of devices = 0x%x",ldgvp->nldvs);
+
+        list_for_each_entry(ldgp, &hxgep->ldgvp->ldgp, list) {
+               HXGE_DBG(hxgep, "");
+               HXGE_DBG(hxgep, "   Logical Group %d =>",ldgp->ldg);
+               HXGE_DBG(hxgep, "      Vector = %d",ldgp->vector);
+               HXGE_DBG(hxgep, "      No. of devices= %d",ldgp->nldvs);
+               HXGE_DBG(hxgep, "      arm = %d",ldgp->arm);
+               list_for_each_entry(ldvp, &ldgp->ldv_list, ldg_list) {
+                       HXGE_DBG(hxgep, "");
+                       HXGE_DBG(hxgep, "      Logical Device %d =>",ldvp->ldv);
+                       HXGE_DBG(hxgep, "         Dev type =  %d",ldvp->dev_type);
+                       HXGE_DBG(hxgep, "         use_timer = %d",ldvp->use_timer);
+                       HXGE_DBG(hxgep, "         ldv_flags = 0x%x",ldvp->ldv_flags);
+                       HXGE_DBG(hxgep, "         ldf_mask = 0x%x",ldvp->ldf_masks);
+               }
+       }
+
+}
+
+/* Set up the Hydra interrupt structures - LDV and LDG */
+static int
+hxge_ldg_init(struct hxge_adapter *hxgep, int num_ints_required,
+                int num_ints_available, struct ldv_array *ldv_arr)
+{
+        struct hxge_ldgv *ldgvp;
+        struct hxge_ldv *ldvp;
+        struct hxge_ldg *ldgp = NULL;
+        int ldg_assigned = -1;
+        int i;
+
+
+        ldgvp = kzalloc(sizeof(struct hxge_ldgv), GFP_KERNEL);
+       if (!ldgvp)
+       {
+               HXGE_ERR(hxgep, "Could not allocate ldgv structure");
+               return -1;
+       }
+        hxgep->ldgvp = ldgvp;
+
+       HXGE_DBG(hxgep, "hxge_ldg_init: num_ints_avail=%d, num_ints_reqd=%d",num_ints_available,num_ints_required);
+
+        /* num_ints_required is what we want for the number of LDVs. However,
+           number of interrupts available defines how many LDGs we can have */
+        ldgvp->max_ldgs = num_ints_available;
+        ldgvp->max_ldvs = num_ints_required;
+        if (num_ints_required > HXGE_INT_MAX_LDG) {
+                HXGE_ERR(hxgep, "hxge_ldg_init: bad interrupt request");
+                return -1;
+        }
+
+        INIT_LIST_HEAD(&ldgvp->ldvp);
+        INIT_LIST_HEAD(&ldgvp->ldgp);
+        ldgvp->tmres = HXGE_TIMER_RESO;
+
+        /* Allocate the bins and fill then later. If we have fewer LDGs than
+           LDVs, then after we have reached the last LDG, lump the remaining
+           LDVs into that LDG */
+        for (i = 0; i < ldgvp->max_ldvs; i++) {
+                ldvp = kzalloc(sizeof(struct hxge_ldv), GFP_KERNEL);
+               INIT_LIST_HEAD(&ldvp->ldg_list);
+               INIT_LIST_HEAD(&ldvp->list);
+                ldgvp->nldvs++;
+                list_add_tail(&ldvp->list, &ldgvp->ldvp);
+                if (i < ldgvp->max_ldgs) { /* not the last LDG */
+                        ldgp = kzalloc(sizeof(struct hxge_ldg), GFP_KERNEL);
+                       if (!ldgp) {
+                               HXGE_ERR(hxgep, "Alloc failed for ldg structure");
+                               hxge_teardown_interrupt(hxgep);
+                               return -1;
+                       }
+                        ldgp->vector = -1;
+                       INIT_LIST_HEAD(&ldgp->ldv_list);
+                       INIT_LIST_HEAD(&ldgp->list);
+                        list_add_tail(&ldgp->list, &ldgvp->ldgp);
+                        ldgp->hxgep = hxgep;
+                        ldgp->intr_handler = hxge_intr;
+                        ldgvp->nldgs++;
+                        ++ldg_assigned;
+                        ldgp->ldg = ldg_assigned;
+                }
+               /* add LDV to the LDG list */
+                list_add_tail(&ldvp->ldg_list, &ldgp->ldv_list);
+                ldgp->nldvs++;
+                ldvp->ldgp = ldgp;
+                ldvp->dev_type = ldv_arr[i].type;
+                ldvp->ldv = ldv_arr[i].dev_no;
+                /* mask interrupts for all devices for starters */
+                ldvp->ldf_masks = (uint8_t)LD_IM_MASK;
+        }
+
+        /* Go through the devices we care about and assign interrupt handlers 
+          to them. Also enable timers for those devices we want it for  */
+        list_for_each_entry(ldvp, &ldgvp->ldvp, list) {
+           switch (ldvp->dev_type) {
+                case LDV_RXDMA :
+                        ldvp->intr_handler = hxge_rx_intr;
+                        ldgp->timer = HXGE_TIMER_LDG;
+                        break;
+                case LDV_TXDMA :
+                        ldvp->intr_handler = hxge_tx_intr;
+                        ldgp->timer = HXGE_TIMER_LDG;
+                        break;
+                case LDV_VMAC :
+                        ldvp->intr_handler = hxge_vmac_intr;
+                        ldgp->timer = HXGE_TIMER_LDG;
+                        break;
+                case LDV_PFC :
+                        ldvp->intr_handler = hxge_pfc_intr;
+                        ldgp->timer = HXGE_TIMER_LDG;
+                        break;
+                case LDV_DEVERR :
+                        ldvp->intr_handler = hxge_deverr_intr;
+                        break;
+                default:
+                        HXGE_ERR(hxgep, "hxge_ldg_init: Unsupported device type, %d",ldvp->dev_type);
+                        hxge_ldg_uninit(hxgep);
+                        return -1;
+            }
+        }
+
+       hxge_dump_ints(hxgep);
+
+        return 0;
+}
+
+/* Tear down the interrupt infrastructure. Typically, this is called when
+   an interface is taken down so that the precious interrupt resources are
+   freed for use by others */
+void hxge_teardown_interrupt(struct hxge_adapter *hxgep)
+{
+        struct hxge_ldv *ldvp;
+        struct hxge_ldg *ldgp;
+
+       /* Nothing to do if polling */
+       if (hxgep->intr_type == POLLING_TYPE)
+               return;
+
+
+        list_for_each_entry(ldgp, &hxgep->ldgvp->ldgp, list) {
+                ldvp = list_entry(ldgp->ldv_list.next, struct hxge_ldv,
+                                                        ldg_list);
+                if (ldgp->vector > 0)
+                        free_irq(ldgp->vector, ldgp);
+        }
+
+        switch (hxgep->intr_type) {
+                case MSIX_TYPE :
+                        pci_disable_msix(hxgep->pdev);
+                        break;
+                case MSI_TYPE:
+                        pci_disable_msi(hxgep->pdev);
+                        break;
+        }
+
+#ifdef CONFIG_PCI_MSI
+        if (hxgep->intr_type == MSIX_TYPE)
+                kfree(hxgep->msix);
+#endif
+        hxge_ldg_uninit(hxgep);
+}
+
+static int hxge_request_irqs(struct net_device *netdev)
+{
+        struct hxge_adapter *hxgep = netdev_priv(netdev);
+        struct hxge_ldv *ldvp;
+        struct hxge_ldg *ldgp;
+        int i = 0, status;
+
+        list_for_each_entry(ldgp, &hxgep->ldgvp->ldgp, list) {
+#ifdef CONFIG_PCI_MSI
+                if ((hxgep->intr_type == MSI_TYPE) ||
+                        (hxgep->intr_type == INTx_TYPE))
+                        ldgp->vector = hxgep->pdev->irq;
+                else
+                        ldgp->vector = hxgep->msix[i].vector;
+#else
+                ldgp->vector = hxgep->pdev->irq;
+#endif
+                ldvp = list_entry(ldgp->ldv_list.next,
+                                struct hxge_ldv, ldg_list);
+                snprintf(ldgp->irq_name, HXGE_MAX_IRQNAME, "%s_int%d",netdev->name, i);
+               HXGE_DBG(hxgep, "Allocating interrupt: irq=%d, dev=%d, intr_name=%s",ldgp->vector,ldvp->ldv, ldgp->irq_name);
+                /* If multiple blocks belong to the same group,
+                   then pass in the LDG pointer; otherwise, pass in LDV
+                  (this saves one indirection on interrupt side) */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+                status = request_irq(ldgp->vector, ldgp->intr_handler,
+                                    SA_SHIRQ, ldgp->irq_name, ldgp);
+#else
+                status = request_irq(ldgp->vector, ldgp->intr_handler,
+                                    IRQF_SHARED, ldgp->irq_name, ldgp);
+#endif
+                if (status) {
+                       HXGE_ERR(hxgep, "request_irq() failed, returned %d",
+                                status);
+                        /* no irq allocation done for ldvp. So, reset vector */
+                        ldgp->vector = -1;
+                        return status;
+                }
+                i++;
+        }
+
+       return 0;
+}
+
+/* This routine sets up the interupt infrastructure for Hydra such as the
+   LDV and LDG for the various functional blocks and allocates IRQs (either
+   legacy or MSIX) by requesting it from the kernel. Finally, it sets the
+   appropriate hardware state indicating LDGs and enabling the appropriate
+   interrupts for the required blocks */
+int hxge_setup_interrupt (struct net_device *netdev)
+{
+        struct hxge_adapter *hxgep = netdev_priv(netdev);
+        int num_ints_required,num_ints_available, i;
+#ifdef CONFIG_PCI_MSI
+        struct msix_entry *ptr, *msix_ent = NULL;
+#endif
+        struct ldv_array ldv_arr[HXGE_INT_MAX_LD];
+        int intr_type, status;
+
+       if (hxge_get_option("intr_type", &intr_type)) {
+               HXGE_ERR(hxgep, "hxge_setup_interrupt: intry_type invalid");
+               return -1;
+       }
+       
+       hxgep->intr_type = intr_type;
+       if (hxgep->intr_type == POLLING_TYPE)
+       {
+               HXGE_DBG(hxgep, "hxge_setup_interrupt: intr_type = polling, do nothing");
+               return 0;
+       }
+
+
+        /* Determine the number of logical device groups needed */
+        memset(ldv_arr, 0xff, sizeof(ldv_arr));
+        num_ints_required = get_num_ldgs(hxgep, ldv_arr);
+
+#ifdef CONFIG_PCI_MSI
+        switch (intr_type) {
+                case MSIX_TYPE :
+                        hxgep->intr_type = MSIX_TYPE;
+                        msix_ent = kzalloc( num_ints_required *
+                                sizeof(struct msix_entry), GFP_KERNEL);
+                        if (!msix_ent) {
+                                HXGE_ERR(hxgep, "hxge_setup_interrupt: Could not allocate msix entries");
+                                return -1;
+                        }
+                        hxgep->msix = msix_ent;
+                        for (i = 0, ptr = msix_ent; i < num_ints_required; i++,ptr++)
+                               ptr->entry = i;
+
+                        /* Keep trying till we get available vectors */
+                        num_ints_available = num_ints_required;
+                        while ((status = pci_enable_msix(hxgep->pdev, msix_ent,
+                                        num_ints_available)) > 0)
+                       {
+                                num_ints_available = status;
+                               HXGE_ERR(hxgep, "pci_enable_msix: status=%d",status);
+                       }
+
+                        if (status < 0) {
+                                HXGE_ERR(hxgep, "hxge_setup_interrupt: pci_enable_msix failed, status=%d",status);
+                                kfree(msix_ent);
+                               hxgep->msix = NULL;
+                                return -1;
+                        }
+                       HXGE_DBG(hxgep, "hxge_setup_interrupt: Interrupt type is MSIX_TYPE; %d interrupts available", num_ints_available);
+                        break;
+                case MSI_TYPE :
+                        num_ints_available = 1;
+                        if (!pci_enable_msi(hxgep->pdev)) {
+                                hxgep->intr_type = MSI_TYPE;
+                               HXGE_DBG(hxgep, "hxge_setup_interrupt: Interrupt type is MSI");
+                                break;
+                        }
+                        /* fall through; reverting to INTx */
+                        HXGE_DBG(hxgep, "hxge_setup_interrupt: No MSI, using INTx");
+                case INTx_TYPE :
+                        num_ints_available = 1;
+                        hxgep->intr_type = INTx_TYPE;
+                        break;
+                default :
+                        HXGE_ERR(hxgep, "hxge_setup_interrupt: Bad type");
+                        return -1;
+        }
+
+#else
+        num_ints_available = 1;
+        hxgep->intr_type = INTx_TYPE;
+#endif
+
+       if (num_ints_available < 1) {
+               HXGE_ERR(hxgep, "num_ints_available should be atleast 1");
+               return -1;
+       }
+               
+
+
+        /* Initialize Hydra interrupt data structures */
+        status = hxge_ldg_init(hxgep, num_ints_required, num_ints_available,
+                                ldv_arr);
+        if (status) {
+                HXGE_ERR(hxgep, "hxge_setup_interrupt: hxge_ldv_interrupt_init failed");
+#ifdef CONFIG_PCI_MSI
+               if (msix_ent) /* implies MSIX_TYPE */
+                       kfree(msix_ent);
+#endif
+                return -1;
+        }
+
+        /* Request for IRQs (in the case of msix, for each vector assigned) */
+        if (hxge_request_irqs(netdev)) {
+                HXGE_ERR(hxgep, "hxge_setup_interrupt: request_irq failed");
+                hxge_teardown_interrupt(hxgep);
+                return -1;
+        }
+
+        /* Enable the hardware interrupt registers. Setup the LDG and LDV
+           registers for the respective blocks */
+        if (hxge_set_hw_interrupt_regs(hxgep)) {
+                HXGE_ERR(hxgep, "hxge_setup_interrupt: hxge_set_hw_interrupt failed");
+                hxge_teardown_interrupt(hxgep);
+                return -1;
+        }
+
+        return 0;
+}
+       
diff --git a/drivers/net/hxge/hxge_main.c b/drivers/net/hxge/hxge_main.c
new file mode 100644 (file)
index 0000000..65a58dd
--- /dev/null
@@ -0,0 +1,1315 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#include "hxge.h"
+
+static const char hxge_driver_string[] = "Sun Microsystems(R) 10 Gigabit  Network Driver";
+#ifndef CONFIG_HXGE_NAPI
+#define DRIVERNAPI
+#else
+#define DRIVERNAPI "-NAPI"
+#endif
+#define DRV_VERSION "1.3.3"
+const char hxge_driver_version[] = DRV_VERSION;
+static const char hxge_copyright[] = "Copyright (c) 2009, 2011 Oracle America.";
+
+
+lb_property_t lb_properties[] = {
+        {normal, "normal", hxge_lb_normal},
+        {external, "external10g", hxge_lb_ext10g}
+};
+
+
+/* hxge_pci_tbl - PCI Device ID Table
+ *
+ * Last entry must be all 0s
+ *
+ * Macro expands to...
+ *   {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
+ */
+static struct pci_device_id hxge_pci_tbl[] = {
+       SUN_ETHERNET_DEVICE(PCI_DEVICE_ID_SUN_HYDRA),
+       /* required last entry */
+       {0,}
+};
+MODULE_DEVICE_TABLE(pci, hxge_pci_tbl);
+
+/* External Functions */
+extern int hxge_pfc_init_mac_addrs(struct hxge_adapter *hxgep);
+extern int hxge_pfc_hw_reset(struct hxge_adapter *hxgep);
+extern int hxge_init_param(struct hxge_adapter *hxgep);
+extern void hxge_init_stats(struct hxge_adapter *hxgep);
+extern void hxge_free_stats(struct hxge_adapter *hxgep);
+extern int hxge_set_mac_address(struct net_device *netdev, void *p);
+extern int hxge_vmac_init(struct hxge_adapter *hxgep);
+extern void hxge_vmac_uninit(struct hxge_adapter *hxgep);
+extern int hxge_link_intr(struct hxge_adapter *hxgep, int cmd);
+extern int hxge_get_option(const char *str, int *val);
+extern void hxge_enable_interrupts(struct hxge_adapter *hxgep);
+extern int hxge_enable_rx(struct hxge_adapter *hxgep);
+extern int hxge_enable_tx(struct hxge_adapter *hxgep);
+extern int hxge_disable_rx(struct hxge_adapter *hxgep);
+extern int hxge_disable_tx(struct hxge_adapter *hxgep);
+extern void hxge_disable_interrupts(struct hxge_adapter *hxgep);
+extern int hxge_alloc_rx(struct hxge_adapter *hxgep);
+extern int hxge_alloc_tx(struct hxge_adapter *hxgep);
+extern int hxge_setup_interrupt (struct net_device *netdev);
+extern void hxge_teardown_interrupt(struct hxge_adapter *hxgep);
+extern int hxge_peu_get_link_status(struct hxge_adapter *hxgep);
+extern int hxge_free_rx(struct hxge_adapter *hxgep);
+extern int hxge_ok_to_continue(struct hxge_adapter *hxgep);
+extern int hxge_block_reset(struct hxge_adapter *hxgep, int device);
+extern int hxge_peu_deverr_init(struct hxge_adapter *hxgep);
+extern void hxge_free_tx(struct hxge_adapter *hxgep);
+extern void hxge_reset_tx_channel(struct hxge_adapter *hxgep, int channel);
+extern void hxge_reset_rx_channel(struct hxge_adapter *hxgep, int channel);
+extern int hxge_reset_tdc(struct hxge_adapter *hxgep);
+extern int hxge_reset_rdc(struct hxge_adapter *hxgep);
+#ifdef CONFIG_HXGE_NAPI
+extern int hxge_poll(struct net_device *poll_dev, int *budget);
+#endif
+extern int hxge_start_xmit(struct sk_buff *skb, struct net_device *netdev);
+extern struct net_device_stats *hxge_get_stats(struct net_device *netdev);
+extern int hxge_classify_init(struct hxge_adapter *hxgep);
+extern int hxge_classify_uninit(struct hxge_adapter *hxgep);
+extern void hxge_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp);
+extern void hxge_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid);
+extern void hxge_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
+extern void hxge_set_multi(struct net_device *netdev);
+extern int hxge_get_tcam_properties(struct hxge_adapter *hxgep);
+extern int hxge_set_loopback(struct hxge_adapter *hxgep, boolean_t enable);
+
+#ifdef CONFIG_ERRINJECT
+extern int hxge_create_sysfs(struct net_device *netdev);
+extern void hxge_remove_sysfs(struct net_device *netdev);
+#endif
+
+
+/* Local Function Prototypes */
+
+static int hxge_init_module(void);
+static void hxge_exit_module(void);
+static int hxge_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void __devexit hxge_remove(struct pci_dev *pdev);
+static int hxge_open(struct net_device *netdev);
+static int hxge_close(struct net_device *netdev);
+static int hxge_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
+static int hxge_change_mtu(struct net_device *netdev, int new_mtu);
+static int hxge_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
+static void hxge_tx_timeout(struct net_device *dev);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+static void hxge_work_to_do(struct hxge_adapter *hxgep);
+#else
+static void hxge_work_to_do(struct work_struct *work);
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
+#define DMA_MASK       DMA_BIT_MASK(32)
+#else
+#define DMA_MASK       DMA_32BIT_MASK
+#endif
+
+
+static int hxge_sw_init(struct hxge_adapter *adapter);
+static int hxge_link_monitor(struct hxge_adapter *hxgep, int cmd);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/* for netdump / net console */
+static void hxge_netpoll (struct net_device *netdev);
+#endif
+
+static struct pci_driver hxge_driver = {
+       .name     = HXGE_DRIVER_NAME,
+       .id_table = hxge_pci_tbl,
+       .probe    = hxge_probe,
+       .remove   = __devexit_p(hxge_remove),
+};
+
+MODULE_AUTHOR("Oracle Corporation, <james.puthukattukaran@oracle.com>");
+MODULE_DESCRIPTION("Oracle Corporation(R) 10 Gigabit Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+static int debug = NETIF_MSG_HW | NETIF_MSG_PROBE;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)
+spinlock_t hxge_lock = SPIN_LOCK_UNLOCKED; /* HXGE PIO global lock */
+#else
+DEFINE_SPINLOCK(hxge_lock);
+#endif
+
+/**
+ * hxge_init_module - Driver Registration Routine
+ *
+ * hxge_init_module is called when the driver is loaded. It registers
+ * the driver with the PCI subsystem 
+ **/
+
+static int __init
+hxge_init_module(void)
+{
+       int ret;
+       printk(KERN_INFO "%s - version %s\n",
+              hxge_driver_string, hxge_driver_version);
+
+       printk(KERN_INFO "%s\n", hxge_copyright);
+
+       ret = pci_register_driver(&hxge_driver);
+
+       return ret;
+}
+module_init(hxge_init_module);
+
+/**
+ * hxge_exit_module - Driver Exit Routine
+ *
+ * hxge_exit_module is called when driver is unloaded via rmmod. It 
+ * unregisters itself from the PCI subsystem
+ *
+ **/
+
+static void __exit
+hxge_exit_module(void)
+{
+       pci_unregister_driver(&hxge_driver);
+}
+module_exit(hxge_exit_module);
+
+/**
+ * hxge_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+
+static void
+hxge_irq_disable(struct hxge_adapter *adapter)
+{
+       atomic_inc(&adapter->irq_sem);
+       hxge_disable_interrupts(adapter);
+       synchronize_irq(adapter->pdev->irq);
+}
+
+/**
+ * hxge_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ **/
+
+static void
+hxge_irq_enable(struct hxge_adapter *adapter)
+{
+       if (likely(atomic_dec_and_test(&adapter->irq_sem))) {
+               hxge_enable_interrupts(adapter);
+       }
+}
+
+/* Ignores linux network stack niceties and brings down the adapter */
+void
+hxge_disable_adapter(struct hxge_adapter *hxgep)
+{
+       /* Disable interrupts */
+       hxge_disable_interrupts(hxgep);
+
+       /* Disable TCAM */
+       hxge_classify_uninit(hxgep);    
+
+       /* Disable VMAC interface  */
+        hxge_vmac_uninit(hxgep);
+
+        /* Disable all Tx channels */
+        hxge_disable_tx(hxgep);
+
+        /* Disable all Rx channels */
+        hxge_disable_rx(hxgep);
+
+       /* Do a PEU reset to take care of CR 6668282 in the event that 
+        * the PCI links are not left in the proper state 
+        */
+       hxge_block_reset(hxgep, (LDV_RXDMA | LDV_TXDMA | LDV_VMAC));
+}
+
+int
+hxge_enable_adapter(struct hxge_adapter *hxgep)
+{
+       /* Do reset of all the major blocks, especially those that
+           are shared across channels and potentially blades. This is done
+          via the PEU space */
+       hxge_block_reset(hxgep, (LDV_RXDMA | LDV_TXDMA | LDV_VMAC));
+
+        /* Enable Tx DMA channels */
+        if (hxge_enable_tx(hxgep)) 
+       {       
+               if (!test_bit(HXGE_DEVICE_UP, &hxgep->state)) {
+                       HXGE_ERR(hxgep, "hxge_enable_adapter: hxge_enable_tx failed");
+                       hxge_disable_adapter(hxgep);
+                       return -1;
+               }
+       }
+
+        /* Enable the Rx DMA channels */
+        hxge_enable_rx(hxgep);
+
+       /* Allocate and enable TCAM */
+       hxge_classify_init(hxgep);
+
+        hxge_vmac_init(hxgep);
+
+       /* Now that all the feeds into Device Error (PEU, TDC, etc.)
+        * have been cleared/initialized, enable the Device Error
+        * [logical] device/function */
+
+       if (hxge_peu_deverr_init(hxgep))
+               return -1;
+
+       /* Enable interrupts for all devices */
+       hxge_enable_interrupts(hxgep);
+
+       return 0;
+}
+
+static int
+hxge_lif_up(struct hxge_adapter *hxgep)
+{
+       struct net_device *netdev = hxgep->netdev;
+
+       /* Start link monitoring */
+       hxgep->prev_link_status = -1;
+       hxge_link_monitor(hxgep, LINK_MONITOR_START);
+
+#ifdef CONFIG_HXGE_NAPI
+       netif_poll_enable(netdev);
+#endif
+
+       if (hxge_enable_adapter(hxgep))
+               return -1;
+
+       hxge_irq_enable(hxgep);
+
+       /* Enable Linux network stack */
+       netif_carrier_on(netdev);
+       netif_start_queue(netdev);
+
+       set_bit(HXGE_DEVICE_UP, &hxgep->state);
+       return 0;
+}
+
+static int
+hxge_up(struct hxge_adapter *hxgep)
+{
+       /* If we were in error shutdown state, this constitutes a
+         * manual intervention to bring it back up again. */
+
+       clear_bit(HXGE_DEVICE_SHUTTINGDOWN, &hxgep->state);
+
+       hxgep->statsp->accum_hard_errors += hxgep->statsp->hard_errors;
+       hxgep->statsp->accum_soft_errors += hxgep->statsp->soft_errors;
+       hxgep->statsp->accum_line_errors += hxgep->statsp->line_errors;
+       hxgep->statsp->hard_errors = 0; /* Reset all error rate counters */
+       hxgep->statsp->soft_errors = 0;
+       hxgep->statsp->line_errors = 0;
+       hxgep->ifup_time = jiffies; /* "t = 0" for error rate calc */
+
+       return(hxge_lif_up (hxgep)); /* local interface "up" work */
+}
+
+static void
+hxge_down(struct hxge_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+
+       clear_bit(HXGE_DEVICE_UP, &adapter->state);
+
+       hxge_link_monitor(adapter, LINK_MONITOR_STOP);
+       netif_carrier_off(netdev); /* avoids Tx timeouts */
+       netif_stop_queue(netdev);
+
+#ifdef CONFIG_HXGE_NAPI
+       netif_poll_disable(netdev);
+#endif
+       hxge_irq_disable(adapter);
+
+       /* Reset the adapter */
+       hxge_disable_adapter(adapter);
+}
+
+
+/* This routine memory maps the Hydra register (PIO/BAR0) */
+static int hxge_map_registers(struct net_device *netdev)
+{
+       unsigned long pio_base, pio_len;
+       struct hxge_adapter *adapter= netdev_priv(netdev);
+       struct pci_dev *pdev = adapter->pdev;
+       int err;
+       u32 vendorid;
+
+        pio_base = pci_resource_start(pdev, BAR_0);
+        pio_len = pci_resource_len(pdev, BAR_0);
+
+        err = -EIO;
+        adapter->hw.hw_addr = ioremap(pio_base, pio_len);
+        if (!adapter->hw.hw_addr)
+               return err;
+
+       /* There is a bug in the HW (we think) where the link retrain, which is
+          as part of the ASPM common clock configuration code, fails.
+          Consequently, the device is left in a completely initialized state
+           i.e. the BARs are reset and inaccessible by the time the driver is
+          loaded. We have verified that bypassing the common clock
+          configuration code works around the problem (pcie_aspm=off). This 
+          is a warning/informative message to the customer to check if the 
+          boot argument is passed
+       */
+       vendorid= readl(adapter->hw.hw_addr + PCI_VENDOR_ID);
+       if (vendorid== 0xffffffff) {
+               HXGE_ERR(adapter,"Device probe failed. The PCI BAR space is inaccessible! You may want to set the boot argument pcie_aspm=off");
+       }
+
+        netdev->mem_start = pio_base;
+        netdev->mem_end = pio_base + pio_len;
+
+       return 0;
+}
+
+/* This function runs periodically trigger off the one-shot timer and 
+   periodically monitors the link status (if monitoring is enabled). 
+   It notifies the kernel (linux network stack) of change in link status
+   so that the traffic control subsystem can take appropriate action */
+
+static void hxge_watchdog_timer(unsigned long data)
+{
+       struct hxge_adapter *hxgep = (struct hxge_adapter *)data;
+       int link_up = hxge_peu_get_link_status(hxgep);
+
+       /* Calling either netif_carrier_on if link is already up does nothing.
+          Similarly, calling netif_carrier_down if link is down does nothing
+           either */
+
+       if (link_up)
+               netif_carrier_on(hxgep->netdev);
+       else
+               netif_carrier_off(hxgep->netdev);
+
+       /* Log a change in link status */
+       if (hxgep->prev_link_status != link_up) {
+               HXGE_ERR(hxgep, "hxge_watchdog_timer: link is %s", (link_up) ? "up":"down");    
+               hxgep->prev_link_status = link_up;
+       }
+       mod_timer (&hxgep->wd_timer, jiffies + HXGE_LINK_TIMEOUT);
+}
+
+
+/* Initialize link management */
+static void hxge_init_link(struct hxge_adapter *hxgep)
+{
+       hxgep->link_monitor_state = LINK_MONITOR_DISABLED;
+       hxgep->link_mode = LINK_MODE_POLL;
+       setup_timer(&hxgep->wd_timer,hxge_watchdog_timer,(unsigned long)hxgep);
+}
+
+/* Start or stop link monitoring. If we want to be interrupted for a link 
+   state change, then we call this routine just once when turning on 
+   interrupt monitoring. For polling, this routine is called periodically
+   every HX_LINK_TIMEOUT seconds and the one-shot timer is set for the next
+   period. */
+static int hxge_link_monitor(struct hxge_adapter *hxgep, int cmd)
+{
+       if (netif_msg_link(hxgep)) {
+               HXGE_DBG(hxgep, "hxge_link_monitor: cmd = %d",cmd);
+               if (hxgep->link_monitor_state == LINK_MONITOR_DISABLED) {
+                       HXGE_DBG(hxgep, "hxge_link_monitor: Link monitoring disabled");
+               }
+               else {
+                       HXGE_DBG(hxgep, "hxge_link_monitor: Link monitoring enabled");
+               }
+       }
+
+       hxgep->statsp->link_monitor_cnt++;
+       switch (cmd) {
+               case LINK_MONITOR_START:
+                  /* Assert an interrupt when link state changes. */
+                  if (hxgep->link_mode == LINK_MODE_INTR) {
+                       if (hxge_link_intr(hxgep, cmd))
+                               goto fail;
+                   /* Periodically poll for for state change */
+                   } else if (hxgep->link_monitor_state == LINK_MONITOR_DISABLED) {
+                       hxgep->link_monitor_state = LINK_MONITOR_ENABLED;
+                       mod_timer (&hxgep->wd_timer, jiffies + HXGE_LINK_TIMEOUT);
+                   }
+                   HXGE_DBG(hxgep, "hxge_link_monitor: Link monitoring started");
+                   break;
+               case LINK_MONITOR_STOP: 
+                  if (hxgep->link_mode == LINK_MODE_INTR) {
+                       if (hxge_link_intr(hxgep, cmd))
+                               goto fail;
+                  } else if (hxgep->link_monitor_state == LINK_MONITOR_ENABLED)
+                  {   
+                       hxgep->link_monitor_state = LINK_MONITOR_DISABLED;
+                       del_timer_sync(&hxgep->wd_timer);
+                  }
+                   HXGE_DBG(hxgep, "hxge_link_monitor: Link monitoring stopped");
+                  break;
+               default:
+                  HXGE_ERR(hxgep, "hxge_link_monitor: Unknown command");
+                  break;
+       }
+       return 0;
+
+fail:
+       HXGE_ERR(hxgep, "hxge_link_monitor: failed");
+       return -1;
+}
+
+       
+
+static void hxge_init_locks(struct hxge_adapter *hxgep)
+{
+       spin_lock_init(&hxgep->lock);
+       spin_lock_init(&hxgep->stats_lock);
+       spin_lock_init(&hxgep->tcam_lock);
+       rwlock_init(&hxgep->wtd_lock);
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
+static const struct net_device_ops hxge_netdev_ops = {
+        .ndo_open               = hxge_open,
+        .ndo_stop               = hxge_close,
+        .ndo_start_xmit         = hxge_start_xmit,
+        .ndo_get_stats          = hxge_get_stats,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)
+        .ndo_set_multicast_list = hxge_set_multi,
+#else
+       .ndo_set_rx_mode        = hxge_set_multi,
+#endif
+        .ndo_validate_addr      = eth_validate_addr,
+        .ndo_set_mac_address    = hxge_set_mac_address,
+        .ndo_do_ioctl           = hxge_ioctl,
+        .ndo_tx_timeout         = hxge_tx_timeout,
+        .ndo_change_mtu         = hxge_change_mtu,
+       .ndo_vlan_rx_register   = hxge_vlan_rx_register,
+       .ndo_vlan_rx_add_vid    = hxge_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid   = hxge_vlan_rx_kill_vid,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = hxge_netpoll,
+#endif
+};
+#endif
+
+
+
+/**
+ * hxge_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in hxge_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * hxge_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+
+static int __devinit
+hxge_probe(struct pci_dev *pdev,
+            const struct pci_device_id *ent)
+{
+       struct net_device *netdev;
+       struct hxge_adapter *adapter;
+       static int cards_found = 0;
+       int err, pci_using_dac;
+
+       if ((err = pci_enable_device(pdev)))
+       {
+               HXGE_ERR_PRINT("hxge_probe: Failed to (PCI) enable device");
+               return err;
+       }
+
+       /* Hydra can address up to 44-bits of physical memory. Let the 
+           kernel know */
+       if (!(err = pci_set_dma_mask(pdev, HXGE_MAX_ADDRESS_BITS_MASK)) &&
+           !(err = pci_set_consistent_dma_mask(pdev, HXGE_MAX_ADDRESS_BITS_MASK))) {
+               pci_using_dac = 1;
+       } else {
+               if ((err = pci_set_dma_mask(pdev, DMA_MASK)) &&
+                   (err = pci_set_consistent_dma_mask(pdev, DMA_MASK))) {
+                       HXGE_ERR_PRINT("No usable DMA configuration, aborting");
+                       goto err_dma;
+               }
+               pci_using_dac = 0;
+       }
+
+       if ((err = pci_request_regions(pdev, HXGE_DRIVER_NAME)))
+               goto err_pci_reg;
+
+       pci_set_master(pdev);
+
+       err = -ENOMEM;
+       netdev = alloc_etherdev(sizeof(struct hxge_adapter));
+       if (!netdev)
+               goto err_alloc_etherdev;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+       SET_MODULE_OWNER(netdev);
+#endif
+
+       SET_NETDEV_DEV(netdev, &pdev->dev);
+
+       pci_set_drvdata(pdev, netdev);
+       adapter = netdev_priv(netdev);
+       adapter->netdev = netdev;
+       adapter->pdev = pdev;
+       adapter->msg_enable = debug;
+
+       if (hxge_map_registers(netdev) < 0)
+               goto err_mapfailed;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
+       netdev->open = &hxge_open;
+       netdev->stop = &hxge_close;
+       netdev->hard_start_xmit = &hxge_start_xmit;
+       netdev->get_stats = &hxge_get_stats;
+       netdev->set_multicast_list = &hxge_set_multi;
+       netdev->set_mac_address = &hxge_set_mac_address;
+       netdev->change_mtu = &hxge_change_mtu;
+       netdev->do_ioctl = &hxge_ioctl;
+       netdev->tx_timeout = &hxge_tx_timeout;
+       netdev->vlan_rx_register = hxge_vlan_rx_register;
+       netdev->vlan_rx_add_vid = hxge_vlan_rx_add_vid;
+       netdev->vlan_rx_kill_vid = hxge_vlan_rx_kill_vid;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       netdev->poll_controller = hxge_netpoll;
+#endif
+#else
+       netdev->netdev_ops = &hxge_netdev_ops;
+#endif
+
+       hxge_set_ethtool_ops(netdev);
+#ifdef CONFIG_HXGE_NAPI
+       netdev->poll = &hxge_poll;
+       netdev->weight = 64;
+#endif
+       netdev->watchdog_timeo = HXGE_TX_TIMEOUT;
+       strncpy(netdev->name, pci_name(pdev), strlen(pci_name(pdev)));
+
+       adapter->bd_number = cards_found;
+
+       HXGE_DBG(adapter, "Allocated adapter");
+
+       /* Initialize locks */
+       hxge_init_locks(adapter);
+       HXGE_DBG(adapter, "Got Locks");
+
+       /* Get the driver parameters */
+       if (hxge_init_param(adapter))
+               goto err_register;
+       HXGE_DBG(adapter, "Initialized parameter list");
+
+       /* setup the private structure */
+       if ((err = hxge_sw_init(adapter)))
+               goto err_sw_init;
+       HXGE_DBG(adapter, "Initialized hxgep with parameters");
+
+        if (hxge_pfc_hw_reset(adapter))
+        {
+                HXGE_ERR(adapter, "hxge_probe: Failed hxge_pfc_hw_reset");
+                goto err_register;
+        }
+       HXGE_DBG(adapter, "Reset the HW");
+
+       /* Initialize link management */
+       hxge_init_link(adapter);
+       HXGE_DBG(adapter, "Initialized the link");
+
+       /* Initialize and set up statistics for the device */
+       hxge_init_stats(adapter);
+       HXGE_DBG(adapter, "Initialized stats");
+
+       err = -EIO;
+
+       if (pci_using_dac)
+               netdev->features |= NETIF_F_HIGHDMA;
+
+       /* We have to provide our own locking for transmit */
+       netdev->features |= NETIF_F_LLTX;
+       netdev->features |= NETIF_F_SG;
+
+
+       if (adapter->flags & HXGE_TX_CHKSUM_ENABLED)
+               netdev->features |= (NETIF_F_IP_CSUM 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
+                               | NETIF_F_IPV6_CSUM
+#endif
+                               );
+
+
+       if (adapter->flags & HXGE_VLAN_ENABLED)
+               netdev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
+                                       
+       
+       /* copy the MAC address from the PFC block; all 16 of them */
+       if (hxge_pfc_init_mac_addrs(adapter)) {
+               HXGE_ERR(adapter, "EEPROM Read Error");
+               goto err_sw_init;
+       }
+       HXGE_DBG(adapter, "Initialized MAC addresses");
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+       INIT_WORK(&adapter->work_to_do,
+               (void (*)(void *))hxge_work_to_do, adapter);
+#else
+       INIT_WORK(&adapter->work_to_do, hxge_work_to_do);
+#endif
+
+       /* we're going to reset the device because we have no clue what
+           state we find it in */
+       netif_carrier_off(netdev);
+       netif_stop_queue(netdev);
+
+       strcpy(netdev->name, "eth%d");
+       if ((err = register_netdev(netdev)))
+               goto err_register;
+
+       HXGE_DBG(adapter, "hxge_probe: SMI(R) 10 Gb Ethernet Network Connection");
+
+#ifdef CONFIG_ERRINJECT
+       hxge_create_sysfs(netdev);
+#endif
+       cards_found++;
+       set_bit (HXGE_DEVICE_INITIALIZED, &adapter->state);
+       return 0;
+
+err_register:
+err_sw_init:
+       iounmap(adapter->hw.hw_addr);
+err_mapfailed:
+       free_netdev(netdev);
+err_alloc_etherdev:
+       pci_release_regions(pdev);
+err_pci_reg:
+err_dma:
+       pci_disable_device(pdev);
+       return err;
+}
+
+/**
+ * hxge_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * hxge_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.  The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+
+static void __devexit
+hxge_remove(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct hxge_adapter *adapter = netdev_priv(netdev);
+
+       if (!netdev)
+               return;
+
+       set_bit(HXGE_DRIVER_REMOVING, &adapter->state);
+#ifdef CONFIG_ERRINJECT
+       hxge_remove_sysfs(netdev);
+#endif
+
+       /* 
+        * grab the wtd lock before calling flush_scheduled work. Also called
+        * in hxge_down. However, if we are calling hxge_down via hxge_close
+        * from hxge_remove (when we do a rmmod without ifconfig down), we 
+        * could have a nasty deadlock situation. See hxge_down for details.
+        * 
+        */
+       write_lock(&adapter->wtd_lock);
+       
+       flush_scheduled_work();
+       unregister_netdev(netdev);
+
+       write_unlock(&adapter->wtd_lock);
+
+       hxge_free_stats(adapter);
+
+       iounmap(adapter->hw.hw_addr);
+       pci_release_regions(pdev);
+
+       free_netdev(netdev);
+
+       pci_disable_device(pdev);
+}
+
+/**
+ * hxge_sw_init - Initialize general software structures (struct hxge_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * hxge_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+
+static int __devinit
+hxge_sw_init(struct hxge_adapter *adapter)
+{
+       int flags;
+       int tcam;
+
+       adapter->max_tdcs = HXGE_MAX_TDCS; /* max Tx DMA channels per blade */
+       adapter->max_rdcs = HXGE_MAX_RDCS; /* max Rx DMA channels per blade */
+
+       adapter->default_block_size = PAGE_SIZE;
+       adapter->num_openers = 0;
+       if (hxge_get_option("intr_type", &adapter->intr_type)) {
+               HXGE_ERR(adapter, "hxge_sw_init: intr_type failed");
+               return -1;
+       }
+
+       /* Hydra supports IP (L4) checksumming in hardware */
+       if (hxge_get_option("chksum", &flags)) {
+               HXGE_ERR(adapter, "hxge_probe: chksum invalid");
+               return -1;
+       }
+
+       /* When Hydra enables HW TCP/UDP checksumming, it's for both Rx and
+         * Tx. There is no finer knob than that. So, when one of them is 
+         * disabled via the sw flag, it's still done in HW but ignored and
+        * redone by Linux 
+        */
+
+       if (flags) {
+               adapter->flags |= flags;
+               if (adapter->flags & HXGE_TX_CHKSUM_ENABLED)
+                       HXGE_DBG(adapter, "hxge_sw_init: HW TCP/UDP TX Chksum Enabled");
+               if (adapter->flags & HXGE_RX_CHKSUM_ENABLED)
+                       HXGE_DBG(adapter, "hxge_sw_init: HW TCP/UDP RX Chksum Enabled");
+       }
+
+       /* Get number of Rx dma channels */
+        if (hxge_get_option("rx_dma_channels", &adapter->max_rdcs)) {
+                HXGE_ERR(adapter, "Invalid rx_dma_channels option");
+                return -1;
+        }
+
+
+       /* Check for TCAM enablement */
+        if (hxge_get_option("tcam", &tcam)) {
+                HXGE_ERR(adapter, "tcam failed");
+                return -1;
+        }
+
+       if (!tcam && (adapter->max_rdcs > 1))
+       {
+               HXGE_ERR(adapter, "running with only 1 rx channel; other channels unused if tcam is disabled");
+               adapter->max_rdcs = 1;
+       }
+
+       if (tcam && (adapter->max_rdcs < HXGE_MAX_RDCS)) {
+               HXGE_ERR(adapter,"cannot have tcam enabled and have less than four channels; tcam needs all four channels enabled to work!");
+               return -1;
+       }
+       
+       if (tcam) {
+               HXGE_DBG(adapter, "hxge_sw_init: TCAM enabled");
+               adapter->flags |= HXGE_TCAM_ENABLED;
+       }
+
+       if (hxge_get_option("vlan_id", &adapter->vlan_id)) {
+               HXGE_ERR(adapter, "hxge_sw_init: vlan_id failed");
+               return -1;
+       }
+
+       if (hxge_get_option("vlan", &flags)) {
+               HXGE_ERR(adapter, "hxge_sw_init: vlan failed");
+               return -1;
+       }
+
+       if (flags) {
+               HXGE_DBG(adapter, "hxge_sw_init: VLAN enabled");
+               adapter->flags |= HXGE_VLAN_ENABLED;
+       }
+
+       if (hxge_get_option("tx_mark_ints", &adapter->tx_mark_ints)) {
+               HXGE_ERR(adapter, "hxge_sw_init: tx_mark_ints invalid");
+               return -1;
+       }
+
+       hxge_get_tcam_properties(adapter);
+
+        /* Throughput/latency tuning parameters. Can be changed via eththool */
+
+       if (hxge_get_option("rcr_timeout", &adapter->rcr_timeout)) {
+               HXGE_ERR(adapter, "rcr_timeout invalid");
+               return -1;
+       }
+
+       if (hxge_get_option("rcr_threshold", &flags)) {
+               HXGE_ERR(adapter, "rcr_threshold invalid");
+               return -1;
+       }
+       adapter->rcr_threshold = (uint16_t)flags;
+
+       if (hxge_get_option("max_rx_pkts", &flags)) {
+               HXGE_ERR(adapter, "max_rx_pkts invalid");
+               return -1;
+       }
+       adapter->max_rx_pkts = (uint16_t)flags;
+
+       return 0;
+}
+
+
+/**
+ * hxge_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+
+static int
+hxge_open (struct net_device *netdev)
+{
+       struct hxge_adapter *hxgep= netdev_priv(netdev);
+       int retval;
+
+       set_bit(HXGE_DEVICE_OPENING, &hxgep->state);
+       clear_bit(HXGE_DEVICE_FATAL, &hxgep->state);
+
+       /* Allocate hxge data structures only if first opener */
+       if (!hxgep->num_openers) {
+               HXGE_DBG(hxgep, "hxge: Allocating I/O buffers and resources");
+
+               if (hxge_alloc_rx (hxgep)) {
+                       HXGE_ERR(hxgep, "hxge_open: hxge_alloc_rx failed");
+                       return -1;
+               }
+       
+               if (hxge_alloc_tx (hxgep)) {
+                       HXGE_ERR(hxgep, "hxge_open: hxge_alloc_tx failed");
+                       return -1;
+               }
+
+               if (hxge_setup_interrupt(netdev)) {
+                       HXGE_ERR(hxgep, "hxge_open: hxge_setup_interrupt failed");
+                       return -1;
+               }
+
+               set_bit(HXGE_DEVICE_ALLOCATED, &hxgep->state);
+       }
+
+       /* Bring up the interface */
+       write_lock(&hxgep->wtd_lock);
+       spin_lock(&hxgep->lock);
+       retval = hxge_up(hxgep);
+       spin_unlock(&hxgep->lock);
+       write_unlock(&hxgep->wtd_lock);
+
+       hxgep->num_openers++;
+       if (retval || test_bit(HXGE_DEVICE_FATAL, &hxgep->state))
+       {
+               HXGE_ERR(hxgep, "hxge_open: Fatal error bringing hxge up");
+               hxge_close(netdev);
+               retval = -1;
+       }
+
+       /* We're either 'UP' or quiescent (dead) now */
+
+       clear_bit (HXGE_DEVICE_OPENING, &hxgep->state);
+
+       return retval;
+}
+
+
+/**
+ * hxge_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the drivers control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+
+static int
+hxge_close(struct net_device *netdev)
+{
+       struct hxge_adapter *adapter = netdev_priv(netdev);
+        int already_locked = test_bit(HXGE_DRIVER_REMOVING, &adapter->state);
+
+       set_bit (HXGE_DEVICE_CLOSING, &adapter->state);
+       clear_bit (HXGE_DEVICE_OPENING, &adapter->state);
+
+       /* Bring down the interface */
+       if (!already_locked) 
+               write_lock(&adapter->wtd_lock);
+
+       /* Force any work queue functions to just run. It will do nothing,
+        * of course, because the wtd_lock is held by this routine. We just
+        * want to make sure that nothing is outstanding which could run
+        * after the driver is removed. That would be very bad. Also, by
+        * this point, nothing new ever gets scheduled. Need "removing" to
+        * avoid nasty race with linkwatch_event under workqueue thread
+         * attempting to get the rtnl_lock (this is really a bug in Linux
+        * network layer)
+        */
+       if (already_locked)
+               flush_scheduled_work();
+
+
+       spin_lock(&adapter->lock);
+       hxge_down(adapter);
+       spin_unlock(&adapter->lock);
+
+       if (!already_locked)
+               write_unlock(&adapter->wtd_lock);
+
+       /* Free hxge data structures only if last closer */
+
+       adapter->num_openers--;
+       if (!adapter->num_openers) {
+               HXGE_DBG(adapter, "hxge: Freeing I/O buffers and resources");
+
+               /* Free up allocated resouces */
+               hxge_teardown_interrupt(adapter);
+
+               hxge_free_rx(adapter);
+
+               /* Free all Tx data structures */
+               hxge_free_tx(adapter);
+
+               clear_bit(HXGE_DEVICE_ALLOCATED, &adapter->state);
+       }
+
+       /* Back to quiescent (not UP) state */
+
+       clear_bit (HXGE_DEVICE_CLOSING, &adapter->state);
+
+       return 0;
+}
+
+
+/* Reinitialize the device and driver structures. This is a big hammer 
+   that will bring down the interface and bring it back up */
+static void hxge_reset_adapter(struct hxge_adapter *hxgep)
+{
+       HXGE_DBG(hxgep, "hxge_reset_adapter called");
+       WARN_ON(in_interrupt());
+
+       /* We are currently being reset. This could happen if there is a
+           separate thread of execution, say, from a user command line like 
+          ethtool. Wait till that completes */
+       if (test_and_set_bit(HXGE_DEVICE_RESETTING, &hxgep->state)) {
+               while (test_bit(HXGE_DEVICE_RESETTING, &hxgep->state))
+                       msleep(1);
+               return;
+       }
+
+       /* Shutting down adapter trumps resetting the adapter */
+       if (!(test_bit(HXGE_DEVICE_SHUTTINGDOWN, &hxgep->state))) {
+               spin_lock(&hxgep->lock);
+               hxge_down(hxgep);
+               hxge_lif_up (hxgep);    /* Maintain hard_errors/etc. counters */
+               spin_unlock(&hxgep->lock);
+       }
+
+       clear_bit(HXGE_DEVICE_RESETTING, &hxgep->state);
+       HXGE_DBG(hxgep, "hxge_reset_adapter done");
+}
+
+
+/* Take down the hxge device. This is a big hammer that will bring down
+   the interface and leave it down until manually brought back up. */
+static void hxge_shutdown_adapter(struct hxge_adapter *hxgep)
+{
+       HXGE_DBG(hxgep, "hxge_shutdown_adapter called");
+       WARN_ON(in_interrupt());
+       set_bit(HXGE_DEVICE_SHUTTINGDOWN, &hxgep->state);
+
+       /* If an hxge_reset_adapter() is in progress, wait for it to
+          complete. This could happen if there is a separate thread
+          of execution, say, from a user command line like ethtool. */
+       while (test_bit(HXGE_DEVICE_RESETTING, &hxgep->state))
+               msleep(1);
+
+       spin_lock(&hxgep->lock);
+       hxge_down(hxgep);
+       spin_unlock(&hxgep->lock);
+
+       /* HXGE_DEVICE_SHUTTINGDOWN only cleared in up/open */
+
+       HXGE_DBG(hxgep, "hxge_shutdown_adapter done");
+}
+
+
+/**
+ * hxge_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ **/
+
+static void
+hxge_tx_timeout(struct net_device *netdev)
+{
+       struct hxge_adapter *hxgep= netdev_priv(netdev);
+
+       /* Do the reset outside of interrupt context */
+       hxgep->statsp->tx_timeout_cnt++;
+
+       if (netif_queue_stopped(netdev))
+               netif_wake_queue(netdev);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+static void
+hxge_work_to_do(struct hxge_adapter *hxgep)
+#else
+static void
+hxge_work_to_do(struct work_struct *work)
+#endif
+{
+       int i;
+       int channel;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+       struct hxge_adapter *hxgep = container_of(work, struct hxge_adapter, work_to_do);
+#endif
+
+       HXGE_ERR(hxgep, "hxge_work_to_do called on cpu %d",smp_processor_id());
+       if (!read_trylock(&hxgep->wtd_lock)) {
+               return;
+       }
+
+       for (i = 0; i < MAX_CMD; i++) 
+               if (test_and_clear_bit(i, &hxgep->work_q.command)) {
+                       switch (i) {
+                          case RESET_TX_CHANNEL_0 : 
+                          case RESET_TX_CHANNEL_1 :
+                          case RESET_TX_CHANNEL_2 :
+                          case RESET_TX_CHANNEL_3 :
+                               channel =  i - RESET_TX_CHANNEL_0;
+                               HXGE_ERR(hxgep, "hxge_work_to_do: Resetting Tx channel %d", channel);
+                               hxge_reset_tx_channel(hxgep, channel);
+                               break;
+                          case RESET_RX_CHANNEL_0 :
+                          case RESET_RX_CHANNEL_1 :
+                          case RESET_RX_CHANNEL_2 :
+                          case RESET_RX_CHANNEL_3 :
+                               channel =  i - RESET_RX_CHANNEL_0;
+                               HXGE_ERR(hxgep, "hxge_work_to_do: Resetting Rx channel %d", channel);
+                               hxge_reset_rx_channel(hxgep, channel);
+                               break;
+                          case RESET_ADAPTER:
+                               HXGE_ERR(hxgep, "hxge_work_to_do: Resetting adapter");
+                               hxge_reset_adapter(hxgep);
+                               break;
+                          case RESET_TDC:
+                               HXGE_ERR(hxgep, "hxge_work_to_do: Resetting TDC core");
+                               hxge_reset_tdc(hxgep);
+                               break;
+                          case RESET_RDC:
+                               HXGE_ERR(hxgep, "hxge_work_to_do: Resetting RDC core");
+                               hxge_reset_rdc(hxgep);
+                               break;
+                          case RESET_PFC:
+                               /* For now, just reset the whole hxge */
+                               HXGE_ERR(hxgep, "hxge_work_to_do: Resetting PFC; resetting whole hxge");
+                               hxge_reset_adapter(hxgep);
+                               break;
+                          case RESET_VMAC:
+                               /* For now, just reset the whole hxge */
+                               HXGE_ERR(hxgep, "hxge_work_to_do: Resetting VMAC; resetting whole hxge");
+                               hxge_reset_adapter(hxgep);
+                               break;
+                          case SHUTDOWN_ADAPTER:
+                               HXGE_ERR(hxgep, "hxge_work_to_do: Shutting down adapter");
+                               hxge_shutdown_adapter(hxgep);
+                               break;
+                          default:
+                               HXGE_ERR(hxgep, "hxge_work_to_do: Uh? unknown command");
+                               break;
+                       }
+               }
+       read_unlock(&hxgep->wtd_lock);
+}
+
+
+/* Bypasses the OS structures and linux network stack niceties and directly
+   wacks the adapter. Currently used by ethtool for diagnostic tests where
+   the card might not be "up" but could be in an unknown state  */
+void hxge_reset (struct hxge_adapter *hxgep)
+{
+       spin_lock(&hxgep->lock);
+       hxge_disable_adapter(hxgep);
+       hxge_enable_adapter(hxgep);
+       spin_unlock(&hxgep->lock);
+}
+
+/**
+ * hxge_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ **/
+
+static int
+hxge_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct hxge_adapter *hxgep= netdev_priv(dev);
+       int old_mtu = dev->mtu;
+       int is_jumbo;
+       int err = 0;
+
+       HXGE_DBG(hxgep, "hxge_change_mtu : old_mtu=%d, new mtu = %d",old_mtu,new_mtu);
+       if (hxge_get_option("enable_jumbo", &is_jumbo)) {
+               HXGE_ERR(hxgep, "hxge_change_mtu: Could not read enable_jumbo");
+               return -1;
+       }
+
+       if ((new_mtu < ETH_ZLEN) || (new_mtu > MAX_JUMBO_FRAME_SIZE))
+               return -EINVAL;
+       if ((new_mtu > ETH_DATA_LEN) && !is_jumbo)
+               return -EINVAL;
+
+       dev->mtu = new_mtu;
+
+       /* The device is not up or the device is not present. In
+          either case, we set the MTU and just return. The MTU
+          for the hardware interface will be set when the 
+          VMAC is initialized */
+          
+        if (!netif_running(dev) || !netif_device_present(dev)) {
+               HXGE_DBG(hxgep, "hxge_change_mtu: interface not up");
+               return 0;
+        }
+
+
+       /* It is now a jumbo packet. So, we have to reset the adapter. We
+         * really want to only reset the Tx but we also change the size of the
+         * Rx frame size. So, reset the whole adapter for safety */
+       if (old_mtu > new_mtu) {
+               hxge_reset_adapter(hxgep);
+       }
+       else {
+               netif_stop_queue(dev);
+               hxge_vmac_uninit(hxgep);
+               err = hxge_vmac_init(hxgep);
+               /* If new mtu failed, then revert to old mtu and reinit vmac.
+                * Return failure to the caller
+                */
+               if (err) {
+                       HXGE_DBG(hxgep, "hxge_change_mtu: Bad MTU size, returning %d",err);
+                       dev->mtu = old_mtu;
+                       hxge_vmac_init(hxgep);
+               }
+               netif_wake_queue(dev);
+       }
+
+       if (!err) {
+               if (new_mtu > ETH_DATA_LEN)
+                       hxgep->vmac.is_jumbo = TRUE;
+               else
+                       hxgep->vmac.is_jumbo = FALSE;
+       }
+
+       return err; 
+} 
+
+
+static int 
+hxge_lb_ioctl(struct hxge_adapter *hxgep, void *data)
+{
+       struct lb_size_info *lb_size = (struct lb_size_info *)data;
+       int cmd = *(int *)data;
+
+       switch (cmd)
+       {
+               case GET_INFO_SIZE:
+                       lb_size->size = sizeof(lb_properties);
+                       HXGE_ERR(hxgep, "hxge_lb_ioctl: lb_size is  %d",lb_size->size);
+                       break;
+               case GET_INFO:
+                       memcpy((char *)data+sizeof(int),lb_properties,
+                               sizeof(lb_properties));
+                       break;
+               case GET_LB_MODE:
+                      lb_size->size = (uint32_t)hxgep->vmac.loopback;
+                      break;
+               case SET_LB_MODE:
+                       hxge_set_loopback(hxgep, (lb_size->size) ?TRUE : FALSE);
+               default:
+                       HXGE_ERR(hxgep, "hxge_lb_ioctl: Unsupported ioctl 0x%x",cmd);
+                       return -1;
+       }
+
+       return 0;
+}
+
+
+/**
+ * hxge_ioctl-
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ **/
+
+static int
+hxge_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+       struct hxge_adapter *hxgep = netdev_priv(netdev);
+
+       switch (cmd) {
+       case LB_IOC:
+               if  (!test_bit(HXGE_DEVICE_UP, &hxgep->state)) {
+                       HXGE_ERR(hxgep, "hxge_ioctl: interface is not up");
+                       return -1;
+               }
+               hxge_lb_ioctl(hxgep, ifr->ifr_data); 
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void
+hxge_netpoll(struct net_device *netdev)
+{
+
+}
+#endif
diff --git a/drivers/net/hxge/hxge_other.c b/drivers/net/hxge/hxge_other.c
new file mode 100644 (file)
index 0000000..4a743a3
--- /dev/null
@@ -0,0 +1,411 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#include "hpi/hpi_vir.h"
+#include "hpi/hpi_rxdma.h"
+#include "hxge.h"
+#include "hxge_peu_hw.h"
+
+extern void hxge_disable_interrupts(struct hxge_adapter *hxgep);
+
+int hxge_read_mac_addr (struct hxge_hw *hw)
+{
+       return 0;
+}
+
+void hxge_check_options(struct hxge_adapter *adapter)
+{
+
+}
+
+/* Get the status of the link */
+int
+hxge_peu_get_link_status(struct hxge_adapter *hxgep)
+{
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+       cip_link_stat_t link_stat;
+       
+       HXGE_REG_RD32(handle, CIP_LINK_STAT, &link_stat.value);
+
+       /* XPCS0 is the XAUI connector, the other two are part of IHL */
+       if (link_stat.bits.xpcs0_link_up) 
+               return 1;
+       else 
+               return 0;
+}
+
+
+/* See if device error rate exceeded, or if it's ok to continue using
+ * the hxge device.  This is sort of a first-order approximation to
+ * an intelligent/heuristical running health check.
+ *
+ * We want to allow for some RealWorld "Stuff Happens" (and it does,
+ * especially in a network environment), but still not let a kroaked
+ * hxge swamp the system with error handling/reporting (and, at 10Gb,
+ * errors can accumulate at a prodigous rate).
+ *
+ * Returns TRUE (non-zero) if ok to continue (e.g., recover/reset the
+ * device/subsystem) using hxge; FALSE (zero) to give up.
+ */
+
+int
+hxge_ok_to_continue(struct hxge_adapter *hxgep)
+{
+       /* Check hard device error rate */
+       if (hxgep->statsp->hard_errors >= HARD_ERROR_THRESHOLD) {
+               if (((hxgep->statsp->hard_errors * HZ * 86400)
+                     / (jiffies + 1 - hxgep->ifup_time)) /* +1 no div-by-0 */
+                   > HARD_ERROR_RATELIMIT) {
+                       return 0;
+               }
+       }
+
+       /* Check soft (generally, "recoverable") device error rate */
+       if (hxgep->statsp->soft_errors >= SOFT_ERROR_THRESHOLD) {
+               if (((hxgep->statsp->soft_errors * HZ * 86400)
+                     / (jiffies + 1 - hxgep->ifup_time)) /* +1 no div-by-0 */
+                   > SOFT_ERROR_RATELIMIT) {
+                       return 0;
+               }
+       }
+
+       /* For now, ignore "line" errors, even though this could
+        * conceivably impose a huge interrupt load on host CPU(s).
+        */
+
+       return (TRUE);          /* Error rates within limits, keep going */
+}
+
+int
+hxge_block_reset(struct hxge_adapter *hxgep, int device)
+{
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+       block_reset_t reset_reg;
+       int count = 5; /* # msecs to wait */
+       
+       HXGE_REG_RD32(handle, BLOCK_RESET, &reset_reg.value);
+
+       if (device & LDV_TXDMA) {
+               reset_reg.bits.tdc_rst = 1;
+       }
+       if (device & LDV_RXDMA) {
+               reset_reg.bits.rdc_rst = 1;
+       }
+       if (device & LDV_VMAC) {
+               reset_reg.bits.vmac_rst = 1;
+       }
+       if (device & LDV_PFC) {
+               reset_reg.bits.pfc_rst = 1;
+       }
+
+       HXGE_REG_WR32(handle, BLOCK_RESET, reset_reg.value);
+       while (--count && (reset_reg.bits.tdc_rst || reset_reg.bits.rdc_rst ||
+               reset_reg.bits.vmac_rst || reset_reg.bits.pfc_rst)) {
+               HXGE_REG_RD32(handle, BLOCK_RESET, &reset_reg.value);
+               msleep(1);
+       }
+
+       if (!count) {
+               HXGE_ERR(hxgep, "hxge_block_reset: Reset of PEU blocks did not complete: 0x%8.8x", reset_reg.value);
+               return -1;
+       }
+       return 0;
+}
+
+
+
+
+/* hxge_peu_deverr_init -- Initialize PEU & Device Error interrupt mask
+ *
+ * put here for lack of any other likely place to put it...
+ */
+int
+hxge_peu_deverr_init(struct hxge_adapter *hxgep)
+{
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+       int regv, status=0;
+
+       /* Initialize global PEU-related error handling */
+
+        HXGE_REG_RD32(handle, PEU_INTR_STAT, &regv);
+       if (regv) {             /* We're likely doomed if any set! */
+               /* While an interesting case (error flags should probably
+                * not be set), do not count against hxgep->hard_errors */
+               if (regv & ~2) { /* Ignore MSIX_PARERR here */
+                       HXGE_ERR(hxgep, "hxge_peu_deverr_init: Error! PEU_INTR_STAT 0x%8.8x hardware error flags set",
+                                (unsigned int)regv);
+                       status = regv;  /* Return error */
+               }
+       }
+
+       /* MSIX_PARERR sometimes erroneously asserted on poweron. If set
+        * here, assume that's the case, and mask it out. We risk missing
+        * a real MSIX_PARERR, but subsequent system reset/reboot should
+        * clear this condition, and re-enable trap on MSIX_PARERR */
+
+       regv = regv & 2;        /* Ignore MSIX_PARERR if initially asserted */
+       if (regv) {             /* Other than to note that detail in syslog */
+               HXGE_ERR(hxgep, "hxge_peu_deverr_init: MSIX workaround applied");
+       }
+        HXGE_REG_WR32(handle, PEU_INTR_MASK, regv); /* 0 = no disables */
+
+       /* Initialize Device Error interrupt */
+
+       HXGE_REG_RD32(handle, DEV_ERR_STAT, &regv);
+       if (regv) {             /* We're in trouble if any set! */
+               /* While an interesting case (error flags should probably
+                * not be set), do not count against hxgep->hard_errors */
+               if (regv & ~1) { /* Ignore MSIX_PARERR->PEU_ERR1 here */
+                       HXGE_ERR(hxgep, "hxge_deverr_init: Error! DEV_ERR_STAT 0x%8.8x hardware error flags set",
+                        regv);
+               status = regv;  /* Return error */
+               }
+       }
+       HXGE_REG_WR32(handle, DEV_ERR_MASK, 0); /* 0 = no disables */
+
+       return status;
+}
+
+
+
+/* General Hydra error interrupt handler
+ *
+ * Called from Device Error Interrupt (ldv 31) service, not RX DMA
+ *
+ * NB: *data is Device Error ldv 31, not an RX DMA channel ldv!
+ */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+irqreturn_t hxge_peu_deverr_intr(int irq, void *data, struct pt_regs *regs)
+#else
+irqreturn_t hxge_peu_deverr_intr(int irq, void *data)
+#endif
+{
+       struct hxge_ldv *ldvp = (struct hxge_ldv *)data; /* Device Error ldv */
+       struct hxge_adapter *hxgep = ldvp->ldgp->hxgep;
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+       peu_intr_stat_t psts, pclr;
+       int peu_fatal_flag = 0;
+       int regv32;             /* Temp/holding 32-bit register value */
+
+        HXGE_REG_RD32(handle, PEU_INTR_STAT, &psts.value);
+
+       HXGE_ERR(hxgep, "hxge_peu_deverr_intr: PEU hardware error interrupt (0x%8.8x)!",
+                (unsigned int)psts.value);
+
+       pclr.value = psts.value;
+
+       /* All "PEU" errors are hard device errors.  One might quibble
+        * over tdc_pioacc_err and rdc_pioacc_err being more specifically
+        * accountable under "RX" or "TX" errors (e.g., for ifconfig).
+        */
+
+       hxgep->statsp->hard_errors++;
+
+       if (psts.bits.spc_acc_err) {
+               HXGE_ERR(hxgep, "hxge_peu_errors: spc_acc_err");
+               hxgep->statsp->peu_spc_acc_err++;
+               hxgep->statsp->peu_errors++; /* PEU/generic summary count */
+               pclr.bits.spc_acc_err = 0;
+       }
+
+       if (psts.bits.tdc_pioacc_err) {
+               HXGE_ERR(hxgep, "hxge_peu_errors: tdc_pioacc_err");
+               hxgep->statsp->peu_pioacc_err++;
+               hxgep->statsp->tx_oerrors++; /* Tx summary count */
+               pclr.bits.tdc_pioacc_err = 0;
+       }
+
+       if (psts.bits.rdc_pioacc_err) {
+               HXGE_ERR(hxgep, "hxge_peu_errors: rdc_pioacc_err");
+               hxgep->statsp->peu_pioacc_err++;
+               hxgep->statsp->rx_ierrors++; /* Rx summary count */
+               pclr.bits.rdc_pioacc_err = 0;
+       }
+
+       if (psts.bits.pfc_pioacc_err) {
+               HXGE_ERR(hxgep, "hxge_peu_errors: pfc_pioacc_err");
+               hxgep->statsp->peu_pioacc_err++;
+               hxgep->statsp->peu_errors++; /* PEU/generic summary count */
+               pclr.bits.pfc_pioacc_err = 0;
+       }
+
+       if (psts.bits.vmac_pioacc_err) {
+               HXGE_ERR(hxgep, "hxge_peu_errors: vmac_pioacc_err");
+               hxgep->statsp->peu_pioacc_err++;
+               hxgep->statsp->peu_errors++; /* PEU/generic summary count */
+               pclr.bits.vmac_pioacc_err = 0;
+       }
+
+       if (psts.bits.cpl_hdrq_parerr) {
+               HXGE_ERR(hxgep, "hxge_peu_errors: cpl_hdrq_parerr");
+               hxgep->statsp->peu_pcie_parerr++;
+               hxgep->statsp->peu_errors++; /* PEU/generic summary count */
+               peu_fatal_flag = TRUE; /* PEU unrecoverable error */
+               pclr.bits.cpl_hdrq_parerr = 0;
+       }
+
+       if (psts.bits.cpl_dataq_parerr) {
+               HXGE_ERR(hxgep, "hxge_peu_errors: cpl_dataq_parerr");
+               hxgep->statsp->peu_pcie_parerr++;
+               hxgep->statsp->peu_errors++; /* PEU/generic summary count */
+               peu_fatal_flag = TRUE; /* PEU unrecoverable error */
+               pclr.bits.cpl_dataq_parerr = 0;
+       }
+
+       if (psts.bits.retryram_xdlh_parerr) {
+               HXGE_ERR(hxgep, "hxge_peu_errors: retryram_xdlh_parerr");
+               hxgep->statsp->peu_pcie_parerr++;
+               hxgep->statsp->peu_errors++; /* PEU/generic summary count */
+               peu_fatal_flag = TRUE; /* PEU unrecoverable error */
+               pclr.bits.retryram_xdlh_parerr = 0;
+       }
+
+       if (psts.bits.retrysotram_xdlh_parerr) {
+               HXGE_ERR(hxgep, "hxge_peu_errors: retrysotram_xdlh_parerr");
+               hxgep->statsp->peu_pcie_parerr++;
+               hxgep->statsp->peu_errors++; /* PEU/generic summary count */
+               peu_fatal_flag = TRUE; /* PEU unrecoverable error */
+               pclr.bits.retrysotram_xdlh_parerr = 0;
+       }
+
+       if (psts.bits.p_hdrq_parerr) {
+               HXGE_ERR(hxgep, "hxge_peu_errors: p_hdrq_parerr");
+               hxgep->statsp->peu_pcie_parerr++;
+               hxgep->statsp->peu_errors++; /* PEU/generic summary count */
+               peu_fatal_flag = TRUE; /* PEU unrecoverable error */
+               pclr.bits.p_hdrq_parerr = 0;
+       }
+
+       if (psts.bits.p_dataq_parerr) {
+               HXGE_ERR(hxgep, "hxge_peu_errors: p_dataq_parerr");
+               hxgep->statsp->peu_pcie_parerr++;
+               hxgep->statsp->peu_errors++; /* PEU/generic summary count */
+               peu_fatal_flag = TRUE; /* PEU unrecoverable error */
+               pclr.bits.p_dataq_parerr = 0;
+       }
+
+       if (psts.bits.np_hdrq_parerr) {
+               HXGE_ERR(hxgep, "hxge_peu_errors: np_hdrq_parerr");
+               hxgep->statsp->peu_pcie_parerr++;
+               hxgep->statsp->peu_errors++; /* PEU/generic summary count */
+               peu_fatal_flag = TRUE; /* PEU unrecoverable error */
+               pclr.bits.np_hdrq_parerr = 0;
+       }
+
+       if (psts.bits.np_dataq_parerr) {
+               HXGE_ERR(hxgep, "hxge_peu_errors: np_dataq_parerr");
+               hxgep->statsp->peu_pcie_parerr++;
+               hxgep->statsp->peu_errors++; /* PEU/generic summary count */
+               peu_fatal_flag = TRUE; /* PEU unrecoverable error */
+               pclr.bits.np_dataq_parerr = 0;
+       }
+
+       if (psts.bits.eic_msix_parerr) {
+               HXGE_REG_RD32(handle, MSIX_PERR_LOC, &regv32);
+               HXGE_ERR(hxgep, "hxge_peu_errors: eic_msix_parerr: 0x%8.8x", regv32);
+               hxgep->statsp->peu_hcr_msix_parerr++;
+               hxgep->statsp->peu_errors++; /* PEU/generic summary count */
+               peu_fatal_flag = TRUE; /* PEU unrecoverable error */
+               pclr.bits.eic_msix_parerr = 0;
+       }
+
+       if (psts.bits.hcr_parerr) {
+               HXGE_REG_RD32(handle, HCR_PERR_LOC, &regv32);
+               HXGE_ERR(hxgep, "hxge_peu_errors: hcr_parerr: 0x%8.8x", regv32);
+               hxgep->statsp->peu_hcr_msix_parerr++;
+               hxgep->statsp->peu_errors++; /* PEU/generic summary count */
+               peu_fatal_flag = TRUE; /* PEU unrecoverable error */
+               pclr.bits.hcr_parerr = 0;
+       }
+
+       if (pclr.value) {
+               HXGE_ERR(hxgep, "hxge_peu_deverr_intr: Unknown/unexpected/reserved PEU_INTR_STAT bits 0x%8.8x", pclr.value);
+       }
+
+       /* Now that we have "logged" the errors, try to recover from
+        * whatever happened.
+        *
+        * Unlike lesser errors, PEU_INTR_STAT errors are NOT RW1C bits.
+        * Rather, one must externally (to PEU_INTR_STAT register) clear
+        * the underlying fault conditions.
+        *
+        * Errors in the PEU block are irrecoverable from program con-
+        * trol, the Hydra needs a PCI bus reset (aka, reset/reboot the
+        * host OS). Other errors are -- in theory -- recoverable by
+        * resetting (and reinitializing) the hardware subsystem.
+        */
+
+       /* Check hxge viability */
+       
+       if (peu_fatal_flag) {
+               /* Irrecoverable ("FATAL") PEU-class error, time to die. */
+               HXGE_ERR(hxgep, "hxge_peu_deverr_intr: PEU FATAL error");
+               HXGE_ERR(hxgep, "                      Taking hxge device down");
+               hxge_disable_interrupts(hxgep);
+               set_bit(SHUTDOWN_ADAPTER, &hxgep->work_q.command);
+               schedule_work(&hxgep->work_to_do);
+       } else if (hxge_ok_to_continue(hxgep)) {
+
+               /* Error should/could be recoverable by resetting
+                * subsystem involved; reset and restart Hydra
+                * logic subsystem (resume operation) */
+
+               if (psts.bits.tdc_pioacc_err) {
+                       hxge_disable_tx_ints(hxgep);
+                       set_bit(RESET_TDC, &hxgep->work_q.command);
+                       schedule_work(&hxgep->work_to_do);
+               }
+               if (psts.bits.rdc_pioacc_err) {
+                       hxge_disable_rx_ints(hxgep, NULL, -1);
+                       set_bit(RESET_RDC, &hxgep->work_q.command);
+                       schedule_work(&hxgep->work_to_do);
+               }
+               if (psts.bits.pfc_pioacc_err) {
+                       set_bit(RESET_PFC, &hxgep->work_q.command);
+                       schedule_work(&hxgep->work_to_do);
+               }
+               if (psts.bits.vmac_pioacc_err) {
+                       set_bit(RESET_VMAC, &hxgep->work_q.command);
+                       schedule_work(&hxgep->work_to_do);
+               }
+       } else {
+               /* Too many errors,  "hxge_shutdown" the hxge device */
+               HXGE_ERR(hxgep, "hxge_peu_deverr_intr: Excessive hardware error rate");
+               HXGE_ERR(hxgep, "                      Taking hxge device down");
+               hxge_disable_interrupts(hxgep);
+               set_bit(SHUTDOWN_ADAPTER, &hxgep->work_q.command);
+               schedule_work(&hxgep->work_to_do);
+       }
+               
+       return (IRQ_HANDLED);
+}
+
+int hxge_link_intr (struct hxge_adapter *hxgep, int cmd)
+{
+        return -1;
+
+}
diff --git a/drivers/net/hxge/hxge_param.c b/drivers/net/hxge/hxge_param.c
new file mode 100644 (file)
index 0000000..39c7ab7
--- /dev/null
@@ -0,0 +1,237 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+
+#include "hxge.h"
+
+struct hxge_option {
+       enum {range, boolean, range_mod} type;
+       char    *name;
+       int     val;
+       int     def;
+       int     min;
+       int     max;
+       int     mod;
+};
+
+typedef enum {
+       param_enable_jumbo = 0,
+       param_intr_type,
+       param_rbr_entries,
+       param_rcr_entries,
+       param_rcr_timeout,
+       param_rcr_threshold,
+       param_rx_dma_channels,
+       param_tx_dma_channels,
+       param_num_tx_descs,
+       param_tx_buffer_size,
+       param_tx_mark_ints,
+       param_max_rx_pkts,
+       param_vlan_id,
+       param_strip_crc,
+       param_enable_vmac_ints,
+       param_promiscuous,
+       param_chksum,
+       param_vlan,
+       param_tcam,
+       param_tcam_seed,
+       param_tcam_ether_usr1,
+       param_tcam_ether_usr2,
+       param_tcam_tcp_ipv4,
+       param_tcam_udp_ipv4,
+       param_tcam_ipsec_ipv4,
+       param_tcam_stcp_ipv4,
+       param_tcam_tcp_ipv6,
+       param_tcam_udp_ipv6,
+       param_tcam_ipsec_ipv6,
+       param_tcam_stcp_ipv6,
+} hxge_param_t;
+
+       
+
+
+#define HXGE_PARAM(X, desc, default_val_addr) \
+       module_param_named(X, default_val_addr, int, 0); \
+       MODULE_PARM_DESC(X, desc);
+
+#define PARAM(x) hxge_arr[x].val
+
+struct hxge_option hxge_arr[] = {
+{ boolean, "enable_jumbo", 1, 0},
+{ range, "intr_type", MSIX_TYPE, MSI_TYPE, INTx_TYPE, POLLING_TYPE},
+{ range_mod, "rbr_entries", HXGE_RBR_RBB_DEFAULT, HXGE_RBR_RBB_DEFAULT, HXGE_RBR_RBB_MIN, HXGE_RBR_RBB_MAX, 64},
+{ range_mod, "rcr_entries", HXGE_RCR_DEFAULT, HXGE_RCR_DEFAULT, HXGE_RCR_MIN, HXGE_RCR_MAX, 32},
+{ range, "rcr_timeout", HXGE_RCR_TIMEOUT, HXGE_RCR_TIMEOUT, HXGE_RCR_TIMEOUT_MIN, HXGE_RCR_TIMEOUT_MAX},
+{ range, "rcr_threshold", HXGE_RCR_THRESHOLD, HXGE_RCR_THRESHOLD, HXGE_RCR_THRESHOLD_MIN, HXGE_RCR_THRESHOLD_MAX},
+{ range, "rx_dma_channels", HXGE_MAX_RDCS, HXGE_MAX_RDCS, HXGE_MIN_RDCS, HXGE_MAX_RDCS},
+{ range, "tx_dma_channels", HXGE_MAX_TDCS, HXGE_MAX_TDCS, HXGE_MIN_TDCS, HXGE_MAX_TDCS},
+{ range_mod, "num_tx_descs", HXGE_TX_DESCS_DEFAULT, HXGE_TX_DESCS_DEFAULT, HXGE_TX_DESCS_MIN, HXGE_TX_DESCS_MAX, 32},
+{ range, "tx_buffer_size", HXGE_TX_BUF_SZ_MIN, HXGE_TX_BUF_SZ_MIN, HXGE_TX_BUF_SZ_MIN, HXGE_TX_BUF_SZ_MAX},
+{ range, "tx_mark_ints", 32, 16, 1, HXGE_TX_DESCS_DEFAULT/4},
+{ range, "max_rx_pkts", HXGE_MAX_RX_PKTS, HXGE_MAX_RX_PKTS, 0, HXGE_MAX_RX_PKTS_MAX},
+{ range, "vlan_id", VLAN_ID_MIN, VLAN_ID_IMPLICIT, VLAN_ID_MIN, VLAN_ID_MAX},
+{ boolean, "strip_crc", 0, 0},
+{ boolean, "enable_vmac_ints", 0, 0},
+{ boolean, "promiscuous", 0, 0},
+{ range, "chksum", HXGE_CHKSUM_ENABLED, HXGE_CHKSUM_ENABLED, 0, HXGE_CHKSUM_ENABLED },
+{ boolean, "vlan", 1, 1},
+{ boolean, "tcam", 1, 1},
+{ range, "tcam_seed", 0x2323433, 0, 0, 0x7fffffff},
+{ range, "tcam_ether_usr1", 0, 0x40000, 0, 0x4ffff},
+{ range, "tcam_ether_usr2", 0, 0x40000, 0, 0x4ffff},
+{ range, "tcam_tcp_ipv4", 1, 1, 0, 2},
+{ range, "tcam_udp_ipv4", 1, 1, 0, 2},
+{ range, "tcam_ipsec_ipv4", 0, 1, 0, 2},
+{ range, "tcam_stcp_ipv4", 0, 1, 0, 2},
+{ range, "tcam_tcp_ipv6", 0, 1, 0, 2},
+{ range, "tcam_udp_ipv6", 0, 1, 0, 2},
+{ range, "tcam_ipsec_ipv6", 0, 1, 0, 2},
+{ range, "tcam_stcp_ipv6", 0, 1, 0, 2}
+};
+
+HXGE_PARAM(enable_jumbo, "enable jumbo packets", PARAM(param_enable_jumbo));
+HXGE_PARAM(intr_type, "Interrupt type (INTx=0, MSI=1, MSIx=2, Polling=3)", PARAM(param_intr_type));
+HXGE_PARAM(rbr_entries, "No. of RBR Entries", PARAM(param_rbr_entries));
+HXGE_PARAM(rcr_entries, "No. of RCR Entries", PARAM(param_rcr_entries));
+HXGE_PARAM(rcr_timeout, "RCR Timeout", PARAM(param_rcr_timeout));
+HXGE_PARAM(rcr_threshold, "RCR Threshold", PARAM(param_rcr_threshold));
+HXGE_PARAM(rx_dma_channels, "No. of Rx DMA Channels", PARAM(param_rx_dma_channels));
+HXGE_PARAM(tx_dma_channels, "No. of Tx DMA Channels", PARAM(param_tx_dma_channels));
+HXGE_PARAM(num_tx_descs, "No. of Tx Descriptors", PARAM(param_num_tx_descs));
+HXGE_PARAM(tx_buffer_size, "No. of Tx Buffers", PARAM(param_tx_buffer_size));
+HXGE_PARAM(tx_mark_ints, "Tx packets before getting marked interrupt", PARAM(param_tx_mark_ints));
+HXGE_PARAM(max_rx_pkts, "Max Rx Packets", PARAM(param_max_rx_pkts));
+HXGE_PARAM(vlan_id, "Implicit VLAN ID", PARAM(param_vlan_id));
+HXGE_PARAM(strip_crc, "Strip CRC at VMAC (0=disable, 1=enable)", PARAM(param_strip_crc));
+HXGE_PARAM(enable_vmac_ints, "Enable VMAC Interrupt Processing(0=disable, 1=enable)", PARAM(param_enable_vmac_ints));
+HXGE_PARAM(promiscuous, "Enable promiscuous mode (0=disable, 1=enable)",PARAM(param_promiscuous));
+HXGE_PARAM(chksum, "Enable HW Checksum(0=disable, 1=enable)",PARAM(param_chksum));
+HXGE_PARAM(vlan, "Enable VLAN(0=disable, 1=enable)",PARAM(param_vlan));
+HXGE_PARAM(tcam, "Enable TCAM(0=disable, 1=enable)",PARAM(param_tcam));
+HXGE_PARAM(tcam_seed, "Source hash seed",PARAM(param_tcam_seed));
+HXGE_PARAM(tcam_ether_usr1, "EtherType Class usr1",PARAM(param_tcam_ether_usr1));
+HXGE_PARAM(tcam_ether_usr2, "EtherType Class usr2",PARAM(param_tcam_ether_usr2));
+HXGE_PARAM(tcam_tcp_ipv4, "TCP over IPv4 class",PARAM(param_tcam_tcp_ipv4));
+HXGE_PARAM(tcam_udp_ipv4, "UDP over IPv4 class",PARAM(param_tcam_udp_ipv4));
+HXGE_PARAM(tcam_ipsec_ipv4, "IPSec over IPv4 class",PARAM(param_tcam_ipsec_ipv4));
+HXGE_PARAM(tcam_stcp_ipv4, "STCP over IPv4 class",PARAM(param_tcam_stcp_ipv4));
+HXGE_PARAM(tcam_tcp_ipv6, "TCP over IPv6 class",PARAM(param_tcam_tcp_ipv6));
+HXGE_PARAM(tcam_udp_ipv6, "UDP over IPv6 class",PARAM(param_tcam_udp_ipv6));
+HXGE_PARAM(tcam_ipsec_ipv6, "IPsec over IPv6 class",PARAM(param_tcam_ipsec_ipv6));
+HXGE_PARAM(tcam_stcp_ipv6, "STCP over IPv6 class",PARAM(param_tcam_stcp_ipv6));
+
+/* Find the value corresponding to the option name. Return -1 for 
+ * failure */
+
+static struct hxge_option *find_option(const char *option_name)
+{
+       int i;
+       for (i = 0; i < (sizeof(hxge_arr)/sizeof(struct hxge_option)); i++)
+               if (!strcmp(hxge_arr[i].name, option_name))
+                       return &hxge_arr[i];
+       return NULL; 
+}
+
+int hxge_get_option(const char *option_name, int *value)
+{
+       struct hxge_option *option = find_option(option_name);  
+
+       if (option)  {
+               *value = option->val;
+               return 0;
+       }
+       return -1;
+}
+
+int hxge_set_option(const char *option_name, int value)
+{
+       struct hxge_option *option = find_option(option_name);  
+       int orig_value;
+       
+       if (!option) {
+               HXGE_ERR_PRINT("Illegal option name");
+               return -1;
+       }
+
+       orig_value = option->val;
+       HXGE_DBG_PRINT("Setting %s to %d",option_name, value);
+       switch (option->type) {
+               case boolean :
+                       option->val = (value) ? 1 : 0;
+                       break;
+               case range_mod:
+                       if (value % option->mod) {
+                               HXGE_ERR_PRINT("value %d for %s is not multiple of %d", value, option_name, option->mod);
+                               return -1;
+                       }
+                       /* fall through */
+               case range :
+                       if ((value < option->min) || (value > option->max)) {
+                          HXGE_ERR_PRINT("value %d for %s out of range; min=%d, max=%d",value,option->name,option->min, option->max);
+                          return -1;
+                       }
+                       option->val = value;
+                       break;
+               default:
+                       HXGE_ERR_PRINT("Illegal option type");
+                       return -1;
+       }
+
+       return orig_value;
+}
+
+                               
+int hxge_init_param (struct hxge_adapter *hxgep)
+{
+       int i;
+       int entries = (sizeof(hxge_arr)/sizeof(struct hxge_option));
+       int val;
+
+       hxgep->param = hxge_arr;
+       /* validate options; leverage set function to do validation */
+       HXGE_DBG(hxgep, "hxge_init_param: %d parameters", entries);
+       for (i = 0; i < entries; i++) {
+               if (hxge_get_option(hxge_arr[i].name, &val)) {
+                       HXGE_ERR(hxgep, "hxge_init_param: failed param validation");
+                       return -1;
+               }
+               if (hxge_set_option(hxge_arr[i].name, val) < 0)
+                       return -1;
+       }
+       
+
+       return 0;
+}
+
+/* Restore default values to all driver parameters */
+void hxge_restore_defaults(struct hxge_adapter *hxgep)
+{
+       struct hxge_option *hxge_optp;
+       int len = (sizeof(hxge_arr)/sizeof(struct hxge_option));
+       int i;
+
+       for (hxge_optp =  hxgep->param, i = 0; i < len; i++, hxge_optp++)
+               hxge_optp->val = hxge_optp->def;
+}
diff --git a/drivers/net/hxge/hxge_peu_hw.h b/drivers/net/hxge/hxge_peu_hw.h
new file mode 100644 (file)
index 0000000..afbe973
--- /dev/null
@@ -0,0 +1,600 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#ifndef        _HXGE_PEU_HW_H
+#define        _HXGE_PEU_HW_H
+
+#define        PIO_BASE_ADDR                           0X000000
+#define        PIO_LDSV_BASE_ADDR                      0X800000
+#define        PIO_LDMASK_BASE_ADDR                    0XA00000
+
+#define        HCR_REG                                 (PIO_BASE_ADDR + 0x2000)
+#define        BLOCK_RESET                             (PIO_BASE_ADDR + 0x8000)
+#define        PEU_INTR_STAT                           (PIO_BASE_ADDR + 0x8148)
+#define        PEU_INTR_MASK                           (PIO_BASE_ADDR + 0x814C)
+#define        MSIX_PERR_LOC                           (PIO_BASE_ADDR + 0x8174)
+#define        HCR_PERR_LOC                            (PIO_BASE_ADDR + 0x8178)
+#define        PHY_DEBUG_TRAINING_VEC                  (PIO_BASE_ADDR + 0x80F4)
+#define        PEU_DEBUG_TRAINING_VEC                  (PIO_BASE_ADDR + 0x80F8)
+#define        DEV_ERR_STAT                            (PIO_BASE_ADDR + 0x8380)
+#define        DEV_ERR_MASK                            (PIO_BASE_ADDR + 0x8384)
+#define        CIP_LINK_STAT                           (PIO_BASE_ADDR + 0x801C)
+#define        LD_GRP_CTRL                             (PIO_BASE_ADDR + 0x8300)
+#define        LD_INTR_TIM_RES                         (PIO_BASE_ADDR + 0x8390)
+#define        LDSV0                                   (PIO_LDSV_BASE_ADDR + 0x0)
+#define        LDSV1                                   (PIO_LDSV_BASE_ADDR + 0x4)
+#define        LD_INTR_MASK                            (PIO_LDMASK_BASE_ADDR + 0x0)
+#define        LD_INTR_MGMT                            (PIO_LDMASK_BASE_ADDR + 0x4)
+#define        SID                                     (PIO_LDMASK_BASE_ADDR + 0x8)
+
+/*
+ * Register: DevErrStat         DEV_ERR_STAT           (PIO_BASE_ADDR + 0x8380)
+ *     also: DevErrMask         DEV_ERR_MASK           (PIO_BASE_ADDR + 0x8384)
+ * Device Error Status / Mask
+ * Description: Device Error Status logs errors that cannot be
+ * attributed to a given dma channel. It does not duplicate errors
+ * already observable via specific block logical device groups.
+ * Device Error Status bits [31:16] feed LDSV0.devErr0 Device Error
+ * Status bits [15:0] feed LDSV1.devErr1
+ * Fields:
+ *     Set to 1 if Reorder Buffer/Reorder Table has a single bit
+ *     ecc/parity error. This error condition is asserted by TDC to
+ *     PEU.
+ *     Set to 1 if RX Ctrl or Data FIFO has a single bit ecc error.
+ *     This error condition is asserted by RDC to PEU.
+ *     Set to 1 if any of the external block accesses have resulted
+ *     in error or if a parity error was detected in the SPROM
+ *     internal ram. Refer to peuIntrStat for the errors that
+ *     contribute to this bit.
+ *     Set to 1 if Reorder Buffer/Reorder Table has a double bit
+ *     ecc/parity error. This error condition is asserted by TDC to
+ *     PEU.
+ *     Set to 1 if RX Ctrl or Data FIFO has a double bit ecc error.
+ *     This error condition is asserted by RDC to PEU.
+ *     Set to 1 if any PEU ram (MSI-X, retrybuf/sot, p/np/cpl queues)
+ *     has a parity error Refer to peuIntrStat for the errors that
+ *     contribute to this bit.
+ */
+
+typedef union {
+       uint32_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint32_t        rsrvd:13;
+               uint32_t        tdc_err0:1;
+               uint32_t        rdc_err0:1;
+               uint32_t        rsrvd1:1;
+               uint32_t        rsrvd2:12;
+               uint32_t        vnm_pio_err1:1;
+               uint32_t        tdc_err1:1;
+               uint32_t        rdc_err1:1;
+               uint32_t        peu_err1:1;
+#else
+               uint32_t        peu_err1:1;
+               uint32_t        rdc_err1:1;
+               uint32_t        tdc_err1:1;
+               uint32_t        vnm_pio_err1:1;
+               uint32_t        rsrvd2:12;
+               uint32_t        rsrvd1:1;
+               uint32_t        rdc_err0:1;
+               uint32_t        tdc_err0:1;
+               uint32_t        rsrvd:13;
+#endif
+       } bits;
+} dev_err_stat_t;
+
+
+
+/*
+ * Register: BlockReset         BLOCK_RESET            (PIO_BASE_ADDR + 0x8000)
+ * Block Reset
+ * Description: Soft resets to modules. Blade domain modules are
+ * reset by setting the corresponding block reset to 1. Shared domain
+ * resets are sent to SPI for processing and corresponding action by
+ * SPI. Shared domains are reset only if all the blades have
+ * requested a reset for that block. Below is an example scenario :
+ * s/w initiates the reset by writing '1' to the dpmRst bit dpmRst
+ * bit remains '1' until dpmRstStat is detected to be 1. Once
+ * dpmRstStat is detected to be 1, even if s/w writes 1 to this bit
+ * again no new reset will be initiated to the shared domain, ie,
+ * DPM. dpmRstStat is driven by external i/f (shared domain status
+ * provided by SPI) dpmRstStat bit will show '1' as long as the input
+ * stays at 1 or until s/w reads the status and is cleared only after
+ * s/w reads it and if dpmRstStat is 0 by then.
+ * If Host wants to reset entire Hydra it should do so through the
+ * mailbox. In this case, the message interprettation is upto the
+ * software. Writing a '1' to any of these bits generates a single
+ * pulse to the SP module which then controls the reset of the
+ * respective block.
+ *
+ * Fields:
+ *     1 : indicates that an active reset has been applied to the SP
+ *     based on the request from all of the blades. Clears on Read
+ *     provided the reset to SP has been deasserted by then by SPI.
+ *     Setting to 1 allows this blade to request Service Processor
+ *     (Shared) reset. However, SP reset can only occur if all blades
+ *     agree. The success of reset request is indicated by spRstStat
+ *     = 1 which is wired-AND of request from all the blades. Current
+ *     request can be removed by writing a '0' to this bit. This bit
+ *     clears automatically on detecting spRstStat = 1.
+ *     Enable blade to service processor (Shared) reset voter
+ *     registration = 1, disabled = 0
+ *     Issue power reset to the EP Core Clears to 0, writing 0 has no
+ *     effect.
+ *     Issue core reset to the EP Core Clears to 0, writing 0 has no
+ *     effect.
+ *     Issue system reset (sysPor) to the PIPE Core This issues reset
+ *     to the EP core, PCIe domains of Tdc, Rdc, and CIP. This shuts
+ *     down the PCIe clock until Pipe core comes out of reset. The
+ *     status of the Pipe core can be read by reading out the
+ *     cipLinkStat register's pipe core status and pcie reset status
+ *     bits. Clears to 0, writing 0 has no effect.
+ *     1 : indicates that an active reset has been applied to the
+ *     NMAC based on the request from all of the blades. Clears on
+ *     Read provided the reset to NMAC has been deasserted by then by
+ *     SPI.
+ *     1 : indicates that an active reset has been applied to the TDP
+ *     based on the request from all of the blades. Clears on Read
+ *     provided the reset to TDP has been deasserted by then by SPI.
+ *     1 : indicates that an active reset has been applied to the DPM
+ *     based on the request from all of the blades. Clears on Read
+ *     provided the reset to DPM has been deasserted by then by SPI.
+ *     This bit is effective only if sharedVoterEn (bit 24 of this
+ *     reg) has been enabled. Writing '1' sends a request to SP to
+ *     reset NMAC if sharedVoterEn=1. Intended for backdoor access.
+ *     The success of reset request is indicated by nmacRstStat = 1
+ *     which is wired-AND of request from all the blades. This also
+ *     means that the reset request is successful only if all the
+ *     blades requested for reset of this block. Current request can
+ *     be removed by writing a '0' to this bit. This bit clears
+ *     automatically on detecting nmacRstStat = 1.
+ *     This bit is effective only if sharedVoterEn (bit 24 of this
+ *     reg) has been enabled. Writing '1' sends a request to SP to
+ *     reset TDP if sharedVoterEn=1. Intended for backdoor access.
+ *     Intended for backdoor access. The success of reset request is
+ *     indicated by tdpRstStat = 1 which is wired-AND of request from
+ *     all the blades. This also means that the reset request is
+ *     successful only if all the blades requested for reset of this
+ *     block. Current request can be removed by writing a '0' to this
+ *     bit. This bit clears automatically on detecting tdpRstStat =
+ *     1.
+ *     This bit is effective only if sharedVoterEn (bit 24 of this
+ *     reg) has been enabled. Writing '1' sends a request to SP to
+ *     reset DPM if sharedVoterEn=1. Intended for backdoor access.
+ *     Intended for backdoor access. The success of reset request is
+ *     indicated by dpmRstStat = 1 which is wired-AND of request from
+ *     all the blades. This also means that the reset request is
+ *     successful only if all the blades requested for reset of this
+ *     block. Current request can be removed by writing a '0' to this
+ *     bit. This bit clears automatically on detecting dpmRstStat =
+ *     1.
+ *     Setting to 1 generates tdcCoreReset and tdcPcieReset to the
+ *     TDC block. The reset will stay asserted for atleast 4 clock
+ *     cycles. Clears to 0, writing 0 has no effect.
+ *     Setting to 1 generates rdcCoreReset and rdcPcieReset to the
+ *     RDC block. The reset will stay asserted for atleast 4 clock
+ *     cycles. Clears to 0, writing 0 has no effect.
+ *     Setting to 1 generates reset to the PFC block. The reset will
+ *     stay asserted for atleast 4 clock cycles. Clears to 0, writing
+ *     0 has no effect.
+ *     Setting to 1 generates reset to the VMAC block. The reset will
+ *     stay asserted for atleast 4 clock cycles. Clears to 0, writing
+ *     0 has no effect.
+ */
+typedef union {
+       uint32_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint32_t        rsrvd:13;
+               uint32_t        sp_rst_stat:1;
+               uint32_t        sp_rst:1;
+               uint32_t        shared_voter_en:1;
+               uint32_t        epcore_pwr_rst:1;
+               uint32_t        epcore_core_rst:1;
+               uint32_t        pipe_sys_rst:1;
+               uint32_t        nmac_rst_stat:1;
+               uint32_t        tdp_rst_stat:1;
+               uint32_t        dpm_rst_stat:1;
+               uint32_t        rsrvd1:1;
+               uint32_t        nmac_rst:1;
+               uint32_t        tdp_rst:1;
+               uint32_t        dpm_rst:1;
+               uint32_t        rsrvd2:1;
+               uint32_t        tdc_rst:1;
+               uint32_t        rdc_rst:1;
+               uint32_t        pfc_rst:1;
+               uint32_t        vmac_rst:1;
+               uint32_t        rsrvd3:1;
+#else
+               uint32_t        rsrvd3:1;
+               uint32_t        vmac_rst:1;
+               uint32_t        pfc_rst:1;
+               uint32_t        rdc_rst:1;
+               uint32_t        tdc_rst:1;
+               uint32_t        rsrvd2:1;
+               uint32_t        dpm_rst:1;
+               uint32_t        tdp_rst:1;
+               uint32_t        nmac_rst:1;
+               uint32_t        rsrvd1:1;
+               uint32_t        dpm_rst_stat:1;
+               uint32_t        tdp_rst_stat:1;
+               uint32_t        nmac_rst_stat:1;
+               uint32_t        pipe_sys_rst:1;
+               uint32_t        epcore_core_rst:1;
+               uint32_t        epcore_pwr_rst:1;
+               uint32_t        shared_voter_en:1;
+               uint32_t        sp_rst:1;
+               uint32_t        sp_rst_stat:1;
+               uint32_t        rsrvd:13;
+#endif
+       } bits;
+} block_reset_t;
+
+
+/*
+ * Register: CipLinkStat        CIP_LINK_STAT          (PIO_BASE_ADDR + 0x801C)
+ * Link Status Register
+ * Description: This register returns the Link status
+ * Fields:
+ *     NMAC XPCS-2 Link Status
+ *     NMAC XPCS-1 Link Status
+ *     NMAC XPCS-0 Link Status
+ *     '1' indicates that pipe core went down suddenly when its reset
+ *     sources are at deactivated level. When this happens, the PCIe
+ *     domain logics are reset including the EP core, TDC/RDC PCIe
+ *     domains. All these logics, EP Core, and the pipe core are held
+ *     at reset until s/w writes 1 to this bit to clear status which
+ *     will also bring the PCIe domain out of reset
+ *     pipe core clock & reset status 1: core is up & running, ie,
+ *     PIPE core is out of reset and clock is ON
+ *     PCIe domain reset status 1: PCIe domain logics including EP
+ *     core are out of reset; This also implies that PCIe clock is up
+ *     and running
+ *     EP Core XDM Link State
+ *     EP Core RDM Link State
+ *     EP Core LTSSM State
+ */
+typedef union {
+       uint32_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint32_t        rsrvd:13;
+               uint32_t        xpcs2_link_up:1;
+               uint32_t        xpcs1_link_up:1;
+               uint32_t        xpcs0_link_up:1;
+               uint32_t        rsrvd1:6;
+               uint32_t        surprise_pipedn:1;
+               uint32_t        pipe_core_stable:1;
+               uint32_t        pcie_domain_stable:1;
+               uint32_t        xmlh_link_up:1;
+               uint32_t        rdlh_link_up:1;
+               uint32_t        xmlh_ltssm_state:5;
+#else
+               uint32_t        xmlh_ltssm_state:5;
+               uint32_t        rdlh_link_up:1;
+               uint32_t        xmlh_link_up:1;
+               uint32_t        pcie_domain_stable:1;
+               uint32_t        pipe_core_stable:1;
+               uint32_t        surprise_pipedn:1;
+               uint32_t        rsrvd1:6;
+               uint32_t        xpcs0_link_up:1;
+               uint32_t        xpcs1_link_up:1;
+               uint32_t        xpcs2_link_up:1;
+               uint32_t        rsrvd:13;
+#endif
+       } bits;
+} cip_link_stat_t;
+
+
+/*
+ * Register: PeuIntrStat        PEU_INTR_STAT          (PIO_BASE_ADDR + 0x8148)
+ *     also: PeuIntrMask        PEU_INTR_MASK          (PIO_BASE_ADDR + 0x814C)
+ * PEU Interrupt Status / Mask
+ * Description: Returns the parity error status of all of the PEU
+ * RAMs, and external (to peu) block pio access errors. External
+ * block pio access errors could be due to either host or SPI
+ * initiated accesses. These fields are RO and can be cleared only
+ * through a cip reset All these errors feed to devErrStat.peuErr1
+ * which in turn feed to LDSV1.devErr1
+ * Partity Error bits: These bits log the very first parity error
+ * detected in a particular memory. The corresponding memory location
+ * is logged in respective perrLoc registers. External Block PIO
+ * Access Error bits: These bits log the very first error that
+ * resulted in access error. The corresponding address is logged in
+ * respective accErrLog registers.
+ * These bits can be set by writing a '1' to the corresponding
+ * mirror bit in the peuIntrStatMirror register.
+ * Note: PEU RAM Parity Errors and their corresponding interrupt:
+ * When these bits are set and the device error status interrupt is
+ * not masked, the PEU attempts to send the corresponding interrupt
+ * back to the RC. Depending on which ram is impacted and the
+ * corresponding logic impacted in the EP core, a coherent interrupt
+ * message may not be sent in all cases. For the times when the EP
+ * core is unable to send an interrupt, the SPI interface is to be
+ * used for error diagnosis as the PEU interrupt status is logged
+ * regardless of whether the interrupt is sent to the RC. The
+ * following data was collected via simulation: -Parity error
+ * impacted rams that likely will be able to send an interrupt:
+ * npDataq, pDataq, cplDataq, hcr. -Parity error impacted rams that
+ * may not be able to send an interrupt: npHdrq, pHdrq, cplHdrq, MSIx
+ * table, retryram, retrysot.
+ *
+ * Fields:
+ *     Error indication from SPROM Controller for Sprom Download
+ *     access This error indicates that a parity error was detected
+ *     from SRAM. For more details, please refer to SPROM Controller
+ *     PRM.
+ *     Error indication from TDC for PIO access The error location
+ *     and type are logged in tdcPioaccErrLog
+ *     Error indication from RDC for PIO access The error location
+ *     and type are logged in rdcPioaccErrLog
+ *     Error indication from PFC for PIO access The error location
+ *     and type are logged in pfcPioaccErrLog
+ *     Error indication from VMAC for PIO access The error location
+ *     and type are logged in vmacPioaccErrLog
+ *     memory in PCIe data path and value unknown until packet flow
+ *     starts.
+ *     memory in PCIe data path and value unknown until packet flow
+ *     starts.
+ *     memory in PCIe data path and value unknown until packet flow
+ *     starts.
+ *     memory in PCIe data path and value unknown until packet flow
+ *     starts.
+ *     memory in PCIe data path and value unknown until packet flow
+ *     starts.
+ *     memory in PCIe data path and value unknown until packet flow
+ *     starts.
+ *     memory in PCIe data path and value unknown until packet flow
+ *     starts.
+ *     memory in PCIe data path and value unknown until packet flow
+ *     starts.
+ */
+typedef union {
+       uint32_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint32_t        rsrvd:11;
+               uint32_t        spc_acc_err:1;
+               uint32_t        tdc_pioacc_err:1;
+               uint32_t        rdc_pioacc_err:1;
+               uint32_t        pfc_pioacc_err:1;
+               uint32_t        vmac_pioacc_err:1;
+               uint32_t        rsrvd1:6;
+               uint32_t        cpl_hdrq_parerr:1;
+               uint32_t        cpl_dataq_parerr:1;
+               uint32_t        retryram_xdlh_parerr:1;
+               uint32_t        retrysotram_xdlh_parerr:1;
+               uint32_t        p_hdrq_parerr:1;
+               uint32_t        p_dataq_parerr:1;
+               uint32_t        np_hdrq_parerr:1;
+               uint32_t        np_dataq_parerr:1;
+               uint32_t        eic_msix_parerr:1;
+               uint32_t        hcr_parerr:1;
+#else
+               uint32_t        hcr_parerr:1;
+               uint32_t        eic_msix_parerr:1;
+               uint32_t        np_dataq_parerr:1;
+               uint32_t        np_hdrq_parerr:1;
+               uint32_t        p_dataq_parerr:1;
+               uint32_t        p_hdrq_parerr:1;
+               uint32_t        retrysotram_xdlh_parerr:1;
+               uint32_t        retryram_xdlh_parerr:1;
+               uint32_t        cpl_dataq_parerr:1;
+               uint32_t        cpl_hdrq_parerr:1;
+               uint32_t        rsrvd1:6;
+               uint32_t        vmac_pioacc_err:1;
+               uint32_t        pfc_pioacc_err:1;
+               uint32_t        rdc_pioacc_err:1;
+               uint32_t        tdc_pioacc_err:1;
+               uint32_t        spc_acc_err:1;
+               uint32_t        rsrvd:11;
+#endif
+       } bits;
+} peu_intr_stat_t;
+
+/*
+ * Register: PhyDebugTrainingVec
+ * peuPhy Debug Training Vector
+ * Description: peuPhy Debug Training Vector register.
+ * Fields:
+ *     Hard-coded value for peuPhy wrt global debug training block
+ *     signatures.
+ *     Blade Number, the value read depends on the blade this block
+ *     resides
+ *     debug training vector the sub-group select value of 0 selects
+ *     this vector
+ */
+typedef union {
+       uint32_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint32_t        dbg_msb:1;
+               uint32_t        bld_num:3;
+               uint32_t        phydbg_training_vec:28;
+#else
+               uint32_t        phydbg_training_vec:28;
+               uint32_t        bld_num:3;
+               uint32_t        dbg_msb:1;
+#endif
+       } bits;
+} phy_debug_training_vec_t;
+
+/*
+ * Register: PeuDebugTrainingVec
+ * PEU Debug Training Vector
+ * Description: PEU Debug Training Vector register.
+ * Fields:
+ *     Hard-coded value for PEU (VNMy - core clk domain) wrt global
+ *     debug training block signatures.
+ *     Blade Number, the value read depends on the blade this block
+ *     resides
+ *     debug training vector the sub-group select value of 0 selects
+ *     this vector
+ *     Hard-coded value for PEU (VNMy - core clk domain) wrt global
+ *     debug training block signatures.
+ *     Blade Number, the value read depends on the blade this block
+ *     resides
+ *     debug training vector the sub-group select value of 0 selects
+ *     this vector
+ */
+typedef union {
+       uint32_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint32_t        dbgmsb_upper:1;
+               uint32_t        bld_num_upper:3;
+               uint32_t        peudbg_upper_training_vec:12;
+               uint32_t        dbgmsb_lower:1;
+               uint32_t        bld_num_lower:3;
+               uint32_t        peudbg_lower_training_vec:12;
+#else
+               uint32_t        peudbg_lower_training_vec:12;
+               uint32_t        bld_num_lower:3;
+               uint32_t        dbgmsb_lower:1;
+               uint32_t        peudbg_upper_training_vec:12;
+               uint32_t        bld_num_upper:3;
+               uint32_t        dbgmsb_upper:1;
+#endif
+       } bits;
+} peu_debug_training_vec_t;
+
+/*
+ * Register: SID
+ * System Interrupt Data
+ * Description: System Interrupt Data (MSI Vectors)
+ * Fields:
+ *     Data sent along with the interrupt
+ */
+typedef union {
+       uint32_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint32_t        rsrvd:27;
+               uint32_t        data:5;
+#else
+               uint32_t        data:5;
+               uint32_t        rsrvd:27;
+#endif
+       } bits;
+} sid_t;
+
+/*
+ * Register: LdIntrTimRes
+ * Logical Device Interrupt Timer Resolution
+ * Description: Logical Device Interrupt Timer Resolution
+ * Fields:
+ *     Timer resolution in 250 MHz cycles
+ */
+typedef union {
+       uint32_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint32_t        rsrvd:12;
+               uint32_t        res:20;
+#else
+               uint32_t        res:20;
+               uint32_t        rsrvd:12;
+#endif
+       } bits;
+} ld_intr_tim_res_t;
+
+/*
+ * Register: LdIntrMask
+ * Logical Device Interrupt Mask
+ * Description: Logical Device Interrupt Mask
+ * Fields:
+ *     Flag1 mask for logical device N (0-31)
+ *     Flag0 mask for logical device N (0-31)
+ */
+typedef union {
+       uint32_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint32_t        rsrvd:30;
+               uint32_t        ldf1_mask:1;
+               uint32_t        ldf0_mask:1;
+#else
+               uint32_t        ldf0_mask:1;
+               uint32_t        ldf1_mask:1;
+               uint32_t        rsrvd:30;
+#endif
+       } bits;
+} ld_intr_mask_t;
+
+
+/*
+ * Register: LdIntrMgmt
+ * Logical Device Interrupt Management
+ * Description: Logical Device Interrupt Management
+ * Fields:
+ *     SW arms the logical device for interrupt. Cleared by HW after
+ *     interrupt issued. (1 = arm)
+ *     Timer set by SW. Hardware counts down.
+ */
+typedef union {
+       uint32_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint32_t        arm:1;
+               uint32_t        rsrvd:25;
+               uint32_t        timer:6;
+#else
+               uint32_t        timer:6;
+               uint32_t        rsrvd:25;
+               uint32_t        arm:1;
+#endif
+       } bits;
+} ld_intr_mgmt_t;
+
+
+/*
+ * Register: LdGrpCtrl
+ * Logical Device Group Control
+ * Description: LD Group assignment
+ * Fields:
+ *     Logical device group number of this logical device
+ */
+typedef union {
+       uint32_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint32_t        rsrvd:27;
+               uint32_t        num:5;
+#else
+               uint32_t        num:5;
+               uint32_t        rsrvd:27;
+#endif
+       } bits;
+} ld_grp_ctrl_t;
+
+
+
+#define HCR_ADDR_LO             0xC
+#define HCR_ADDR_HI             0x10
+
+
+
+
+#endif /* _HXGE_PEU_HW_H */
diff --git a/drivers/net/hxge/hxge_pfc.c b/drivers/net/hxge/hxge_pfc.c
new file mode 100644 (file)
index 0000000..b052113
--- /dev/null
@@ -0,0 +1,1108 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#include "hxge.h"
+#include "hpi/hpi_pfc.h"
+
+
+/* Static prototypes */
+static int hxge_pfc_set_mac_address(struct hxge_adapter *, uint32_t, 
+               pfc_mac_addr_t ether_addr);
+int hxge_vmac_promisc(struct hxge_adapter *, int);
+
+
+int
+hxge_get_tcam_properties(struct hxge_adapter *hxgep)
+{
+       tcam_class_t class;
+       p_hxge_class_pt_cfg_t class_config = &hxgep->class_config;
+
+       if (hxge_get_option("tcam_seed", &class_config->init_hash)) {
+               HXGE_ERR(hxgep, "tcam_seed failed");
+               return -1;
+       }
+
+       if (hxge_get_option("tcam_ether_usr1", &class_config->class_cfg[TCAM_CLASS_ETYPE_1]))
+       {
+               HXGE_ERR(hxgep, "tcam_ether_usr1 failed");
+               return -1;
+       }
+
+       if (hxge_get_option("tcam_ether_usr2", &class_config->class_cfg[TCAM_CLASS_ETYPE_2]))
+       {
+               HXGE_ERR(hxgep, "tcam_ether_usr2 failed");
+               return -1;
+       }
+
+       if (hxge_get_option("tcam_tcp_ipv4",&class_config->class_cfg[TCAM_CLASS_TCP_IPV4])) {
+
+               HXGE_ERR(hxgep, "tcam_tcp_ipv4 failed");
+               return -1;
+       }
+
+       if (hxge_get_option("tcam_udp_ipv4",&class_config->class_cfg[TCAM_CLASS_UDP_IPV4])) {
+
+               HXGE_ERR(hxgep, "tcam_udp_ipv4 failed");
+               return -1;
+       }
+
+       if (hxge_get_option("tcam_ipsec_ipv4",&class_config->class_cfg[TCAM_CLASS_AH_ESP_IPV4])) {
+
+               HXGE_ERR(hxgep, "tcam_ipsec_ipv4 failed");
+               return -1;
+       }
+
+       if (hxge_get_option("tcam_stcp_ipv4",&class_config->class_cfg[TCAM_CLASS_SCTP_IPV4])) {
+
+               HXGE_ERR(hxgep, "tcam_stcp_ipv4 failed");
+               return -1;
+       }
+
+       if (hxge_get_option("tcam_tcp_ipv6",&class_config->class_cfg[TCAM_CLASS_TCP_IPV6])) {
+
+               HXGE_ERR(hxgep, "tcam_tcp_ipv6 failed");
+               return -1;
+       }
+       
+       if (hxge_get_option("tcam_udp_ipv6",&class_config->class_cfg[TCAM_CLASS_UDP_IPV6])) {
+
+               HXGE_ERR(hxgep, "tcam_udp_ipv6 failed");
+               return -1;
+       }
+
+       if (hxge_get_option("tcam_ipsec_ipv6",&class_config->class_cfg[TCAM_CLASS_AH_ESP_IPV6])) {
+
+               HXGE_ERR(hxgep, "tcam_ipsec_ipv6 failed");
+               return -1;
+       }
+
+       if (hxge_get_option("tcam_stcp_ipv6",&class_config->class_cfg[TCAM_CLASS_SCTP_IPV6])) {
+
+               HXGE_ERR(hxgep, "tcam_stcp_ipv6 failed");
+               return -1;
+       }
+
+       for (class = TCAM_CLASS_TCP_IPV4; class < TCAM_CLASS_SCTP_IPV6; class++)
+       {
+               switch (class_config->class_cfg[class])  {
+                       case 0 : /* do nothing */
+                                break;
+                       case 1 : class_config->class_cfg[class] = HXGE_CLASS_TCAM_LOOKUP;
+                                break;
+                       case 2  : class_config->class_cfg[class] = HXGE_CLASS_DISCARD;
+                               break;
+                       default: HXGE_ERR(hxgep, "Bad class value");
+                                return -1;
+               }
+       }
+
+       return 0;
+
+}
+int
+hxge_pfc_config_tcam_enable(struct hxge_adapter *  hxgep)
+{
+        void                   *handle;        
+       boolean_t               enable = TRUE;
+       hpi_status_t            hpi_status;
+
+       if (!(hxgep->flags & HXGE_TCAM_ENABLED)) {
+               HXGE_DBG(hxgep, "TCAM not enabled");
+               return 0;
+       }
+
+       handle = hxgep->hw.hw_addr;
+       hpi_status = hpi_pfc_set_tcam_enable(handle, enable);
+       if (hpi_status != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "enable tcam failed");
+               return  -1;
+       }
+
+       HXGE_DBG(hxgep, "TCAM enabled");
+
+       return  0;
+}
+
+int
+hxge_pfc_config_tcam_disable(struct hxge_adapter *  hxgep)
+{
+       void *          handle;
+       boolean_t               enable = FALSE;
+       hpi_status_t            hpi_status;
+
+       handle = hxgep->hw.hw_addr;
+       hpi_status = hpi_pfc_set_tcam_enable(handle, enable);
+       if (hpi_status != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "disable tcam failed");
+               return  -1;
+       }
+
+       return  0;
+}
+int
+hxge_pfc_set_hash(struct hxge_adapter *hxgep, uint32_t seed)
+{
+        hpi_status_t            rs = HPI_SUCCESS;
+        hpi_handle_t            handle = hxgep->hw.hw_addr;
+        p_hxge_class_pt_cfg_t   p_class_cfgp;
+
+        HXGE_DBG(hxgep, " ==> hxge_pfc_set_hash");
+
+        p_class_cfgp = (p_hxge_class_pt_cfg_t)&hxgep->class_config;
+        p_class_cfgp->init_hash = seed;
+
+        rs = hpi_pfc_set_hash_seed_value(handle, seed);
+        if (rs & HPI_PFC_ERROR) {
+                HXGE_ERR(hxgep, " hxge_pfc_set_hash %x failed ", seed);
+                return -1;
+        }
+
+        HXGE_DBG(hxgep, " <== hxge_pfc_set_hash");
+
+        return 0;
+}
+
+static int 
+hxge_cfg_tcam_ip_class_get(struct hxge_adapter *hxgep, tcam_class_t class,
+    uint32_t *class_config)
+{
+        hpi_status_t    rs = HPI_SUCCESS;
+        tcam_key_cfg_t  cfg;
+        hpi_handle_t    handle = hxgep->hw.hw_addr;
+        uint32_t        ccfg = 0;
+
+        HXGE_DBG(hxgep, "==> hxge_cfg_tcam_ip_class_get");
+
+        memset(&cfg, 0, sizeof (tcam_key_cfg_t));
+
+        rs = hpi_pfc_get_l3_class_config(handle, class, &cfg);
+        if (rs & HPI_PFC_ERROR) {
+                HXGE_ERR(hxgep, "hxge_cfg_tcam_ip_class opt %x for class %d failed ", *class_config, class);
+                return -1;
+        }
+        if (cfg.discard)
+                ccfg |=  HXGE_CLASS_DISCARD;
+
+        if (cfg.lookup_enable)
+                ccfg |= HXGE_CLASS_TCAM_LOOKUP;
+
+        *class_config = ccfg;
+
+        HXGE_DBG(hxgep, " ==> hxge_cfg_tcam_ip_class_get %x", ccfg);
+
+        return 0;
+} 
+
+
+int
+hxge_pfc_ip_class_config_get(struct hxge_adapter *hxgep, tcam_class_t class,
+    uint32_t *config)
+{
+        uint32_t        t_class_config;
+
+        HXGE_DBG(hxgep, " ==> hxge_pfc_ip_class_config_get");
+        t_class_config = 0;
+        if (hxge_cfg_tcam_ip_class_get(hxgep, class, &t_class_config)) {
+                HXGE_ERR(hxgep, " hxge_pfc_ip_class_config_get for class %d tcam failed", class);
+                return -1;
+        }
+
+        HXGE_DBG(hxgep, " hxge_pfc_ip_class_config tcam %x", t_class_config);
+
+        *config = t_class_config;
+
+        HXGE_DBG(hxgep, "<== hxge_pfc_ip_class_config_get");
+        return 0;
+}
+
+static int
+hxge_pfc_ip_class_config(struct hxge_adapter *hxgep, tcam_class_t class, 
+                       uint32_t config)
+{
+        uint32_t                class_config;
+        p_hxge_class_pt_cfg_t   p_class_cfgp;
+        tcam_key_cfg_t          cfg;
+        hpi_handle_t            handle = hxgep->hw.hw_addr;
+        hpi_status_t            rs = HPI_SUCCESS;
+
+        HXGE_DBG(hxgep, " ==> hxge_pfc_ip_class_config");
+        p_class_cfgp = (p_hxge_class_pt_cfg_t)&hxgep->class_config;
+        class_config = p_class_cfgp->class_cfg[class];
+
+        if (class_config != config) {
+                p_class_cfgp->class_cfg[class] = config;
+                class_config = config;
+        }
+
+        if (class == TCAM_CLASS_ETYPE_1 || class == TCAM_CLASS_ETYPE_2) {
+                rs = hpi_pfc_set_l2_class_slot(handle,
+                    class_config & HXGE_CLASS_ETHER_TYPE_MASK,
+                    class_config & HXGE_CLASS_VALID,
+                    class - TCAM_CLASS_ETYPE_1);
+        } else {
+                if (class_config & HXGE_CLASS_DISCARD)
+                        cfg.discard = 1;
+                else
+                        cfg.discard = 0;
+                if (class_config & HXGE_CLASS_TCAM_LOOKUP)
+                        cfg.lookup_enable = 1;
+                else
+                        cfg.lookup_enable = 0;
+
+                rs = hpi_pfc_set_l3_class_config(handle, class, cfg);
+        }
+
+        if (rs & HPI_PFC_ERROR) {
+                HXGE_DBG(hxgep, "hxge_pfc_ip_class_config %x for class %d tcam failed", config, class);
+                return -1;
+        }
+
+        HXGE_DBG(hxgep, "<== hxge_pfc_ip_class_config");
+        return 0;
+}
+
+static int
+hxge_pfc_ip_class_config_all(struct hxge_adapter *hxgep)
+{
+        uint32_t        class_config;
+        tcam_class_t    cl;
+
+        HXGE_DBG(hxgep, "==> hxge_pfc_ip_class_config_all");
+
+        for (cl = TCAM_CLASS_ETYPE_1; cl <= TCAM_CLASS_SCTP_IPV6; cl++) {
+                if (cl == TCAM_CLASS_RESERVED_4 ||
+                    cl == TCAM_CLASS_RESERVED_5 ||
+                    cl == TCAM_CLASS_RESERVED_6 ||
+                    cl == TCAM_CLASS_RESERVED_7)
+                        continue;
+
+                class_config = hxgep->class_config.class_cfg[cl];
+                if (hxge_pfc_ip_class_config(hxgep, cl, class_config)) {
+                        HXGE_ERR(hxgep, "hxge_pfc_ip_class_config failed, class %d config %x ", cl, class_config);
+                       return -1;
+                }
+        }
+
+        HXGE_DBG(hxgep, "<== hxge_pfc_ip_class_config_all");
+        return 0;
+}
+
+static int
+hxge_pfc_update_hw(struct hxge_adapter *hxgep)
+{
+        p_hxge_class_pt_cfg_t   p_class_cfgp;
+
+        HXGE_DBG(hxgep, "==> hxge_pfc_update_hw");
+        p_class_cfgp = (p_hxge_class_pt_cfg_t)&hxgep->class_config;
+
+        if (hxge_pfc_set_hash(hxgep, p_class_cfgp->init_hash)) {
+                HXGE_DBG(hxgep, "hxge_pfc_set_hash Failed");
+                return -1;
+        }
+
+       /*TODO: Setup VLAN */
+
+        /* Configure hash value and classes */
+        if (hxge_pfc_ip_class_config_all(hxgep)) {
+                HXGE_ERR(hxgep, "hxge_pfc_ip_class_config_all Failed");
+                return -1;
+        }
+
+        return 0;
+}
+
+static  uint32_t
+hxge_get_blade_id(struct hxge_adapter *hxgep)
+{
+        phy_debug_training_vec_t        blade_id;
+
+        HXGE_DBG(hxgep, "==> hxge_get_blade_id");
+        HXGE_REG_RD32(hxgep->hw.hw_addr, PHY_DEBUG_TRAINING_VEC,
+            &blade_id.value);
+        HXGE_DBG(hxgep, "<== hxge_get_blade_id: id = %d",blade_id.bits.bld_num);
+
+        return (blade_id.bits.bld_num);
+}
+
+
+
+static int 
+hxge_tcam_default_add_entry(struct hxge_adapter *hxgep, tcam_class_t class)
+{
+        hpi_status_t            rs = HPI_SUCCESS;
+        uint32_t                location;
+        hxge_tcam_entry_t       entry;
+        hxge_tcam_spread_t      *key = NULL;
+        hxge_tcam_spread_t      *mask = NULL;
+        hpi_handle_t            handle = hxgep->hw.hw_addr;
+
+        memset(&entry, 0, sizeof (hxge_tcam_entry_t));
+
+        /*
+         * The class id and blade id are common for all classes
+         * Only use the blade id for matching and the rest are wild cards.
+         * This will allow one TCAM entry to match all traffic in order
+         * to spread the traffic using source hash.
+         */
+        key = &entry.key.spread;
+        mask = &entry.mask.spread;
+
+        key->blade_id = hxge_get_blade_id(hxgep);
+
+        mask->class_code = 0xf;
+        mask->class_code_l = 0x1;
+        mask->blade_id = 0;
+        mask->wild1 = 0x7ffffff;
+        mask->wild = 0xffffffff;
+        mask->wild_l = 0xffffffff;
+
+        location = class;
+
+        spin_lock(&hxgep->tcam_lock);
+        rs = hpi_pfc_tcam_entry_write(handle, location, &entry);
+        if (rs & HPI_PFC_ERROR) {
+                spin_unlock(&hxgep->tcam_lock);
+                HXGE_ERR(hxgep, " hxge_tcam_default_add_entry tcam entry write failed for location %d", location);
+                return -1;
+        }
+
+        /* Add the associative portion */
+        entry.match_action.value = 0;
+
+        /* Use source hash to spread traffic */
+        entry.match_action.bits.channel_d = 0;
+        entry.match_action.bits.channel_c = 1;
+        entry.match_action.bits.channel_b = 2;
+        entry.match_action.bits.channel_a = 3;
+        entry.match_action.bits.source_hash = 1;
+        entry.match_action.bits.discard = 0;
+
+        rs = hpi_pfc_tcam_asc_ram_entry_write(handle,
+            location, entry.match_action.value);
+        if (rs & HPI_PFC_ERROR) {
+                spin_lock(&hxgep->tcam_lock);
+                HXGE_DBG(hxgep, " hxge_tcam_default_add_entry tcam entry write failed for ASC RAM location %d", location);
+                return -1;
+        }
+
+        memcpy((void *) &entry,
+            (void *) &hxgep->classifier.tcam_entries[location].tce,
+            sizeof (hxge_tcam_entry_t));
+
+        spin_unlock(&hxgep->tcam_lock);
+        return 0;
+}
+
+
+
+/*
+ * Configure one TCAM entry for each class and make it match
+ * everything within the class in order to spread the traffic
+ * among the DMA channels based on the source hash.
+ *
+ * This is the default for now. This may change when Crossbow is
+ * available for configuring TCAM.
+ */
+static int
+hxge_tcam_default_config(struct hxge_adapter *hxgep)
+{
+        uint8_t         class;
+        uint32_t        class_config;
+
+        HXGE_DBG(hxgep, "==> hxge_tcam_default_config");
+
+        /*
+         * Add TCAM and its associative ram entries
+         * A wild card will be used for the class code in order to match
+         * any classes.
+         */
+        class = 0;
+        if (hxge_tcam_default_add_entry(hxgep, class)) {
+                HXGE_ERR(hxgep, "hxge_tcam_default_add_entry failed class %d ", class);
+                return -1;
+        }
+
+        /* Enable the classes */
+        for (class = TCAM_CLASS_TCP_IPV4;
+            class <= TCAM_CLASS_SCTP_IPV6; class++) {
+                /*
+                 * By default, it is set to HXGE_CLASS_TCAM_LOOKUP in
+                 * hxge_ndd.c. It may be overwritten in hxge.conf.
+                 */
+                class_config = hxgep->class_config.class_cfg[class];
+
+                if (hxge_pfc_ip_class_config(hxgep, class, class_config)) {
+                        HXGE_ERR(hxgep, "hxge_pfc_ip_class_config failed. class %d config %x ", class, class_config);
+                        return -1;
+                }
+        }
+
+        if (hxge_pfc_config_tcam_enable(hxgep)) {
+               HXGE_ERR(hxgep, "hxge_pfc_config_tcam_enable failed");
+               return -1;
+       }
+
+        HXGE_DBG(hxgep, "hxge_tcam_default_config done");
+
+        return 0;
+}
+
+
+int 
+hxge_classify_init_sw(struct hxge_adapter *hxgep)
+{
+        int             alloc_size;
+        hxge_classify_t *classify_ptr;
+
+        HXGE_DBG(hxgep, "==> hxge_classify_init_sw");
+        classify_ptr = &hxgep->classifier;
+
+        if (classify_ptr->state & HXGE_PFC_SW_INIT) {
+                HXGE_DBG(hxgep, "hxge_classify_init_sw already init");
+                return 0;
+        }
+
+        /* Init SW structures */
+        classify_ptr->tcam_size = TCAM_HXGE_TCAM_MAX_ENTRY;
+
+        alloc_size = sizeof (tcam_flow_spec_t) * classify_ptr->tcam_size;
+        classify_ptr->tcam_entries = kzalloc(alloc_size, GFP_KERNEL);
+        memset(classify_ptr->class_usage, 0, sizeof (classify_ptr->class_usage));
+
+        /* Start from the beginning of TCAM */
+        hxgep->classifier.tcam_location = 0;
+        classify_ptr->state |= HXGE_PFC_SW_INIT;
+
+        HXGE_DBG(hxgep, "<== hxge_classify_init_sw");
+
+        return 0;
+}
+
+
+int
+hxge_classify_init_hw(struct hxge_adapter *hxgep)
+{
+        HXGE_DBG(hxgep, "==> hxge_classify_init_hw");
+
+        if (hxgep->classifier.state & HXGE_PFC_HW_INIT) {
+                HXGE_DBG(hxgep, "hxge_classify_init_hw already init");
+                return 0;
+        }
+
+        /* Now do a real configuration */
+        if (hxge_pfc_update_hw(hxgep)) {
+                HXGE_ERR(hxgep, "hxge_pfc_update_hw failed");
+                return -1;
+        }
+
+        if (hxge_tcam_default_config(hxgep)) {
+                HXGE_ERR(hxgep, "hxge_tcam_default_config failed"); 
+                return -1;
+        }
+
+        hxgep->classifier.state |= HXGE_PFC_HW_INIT;
+
+        HXGE_DBG(hxgep, "<== hxge_classify_init_hw");
+        return 0;
+}
+
+int
+hxge_classify_exit_sw(struct hxge_adapter *hxgep)
+{
+        hxge_classify_t *classify_ptr;
+
+        HXGE_DBG(hxgep, "==> hxge_classify_exit_sw");
+        classify_ptr = &hxgep->classifier;
+
+        if (classify_ptr->tcam_entries) {
+                kfree(classify_ptr->tcam_entries);
+        }
+        hxgep->classifier.state = HXGE_PFC_HW_UNINIT;
+
+        HXGE_DBG(hxgep, "<== hxge_classify_exit_sw");
+
+        return 0;
+}
+
+
+int
+hxge_classify_init(struct hxge_adapter *hxgep)
+{
+        HXGE_DBG(hxgep, "==> hxge_classify_init");
+
+        if (hxge_classify_init_sw(hxgep)) {
+               HXGE_ERR(hxgep, "SW init failed");      
+                return -1;
+               }
+
+        if (hxge_classify_init_hw(hxgep)) {
+               HXGE_ERR(hxgep, "hxge_classify_init_hw failed");
+                hxge_classify_exit_sw(hxgep);
+                return -1;
+        }
+
+        HXGE_DBG(hxgep, "<== hxge_classify_init");
+        return 0;
+}
+
+int
+hxge_classify_uninit(struct hxge_adapter *hxgep)
+{
+        return (hxge_classify_exit_sw(hxgep));
+}
+
+void
+hxge_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
+{
+       struct hxge_adapter *hxgep = netdev_priv(netdev);
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+       hpi_status_t status;
+       int enable_vlan_id;
+
+       enable_vlan_id = (grp ? (hxgep->vlan_id > 0) : 0);
+       status = hpi_pfc_cfg_vlan_control_set(handle, 0, enable_vlan_id, 
+                               hxgep->vlan_id);
+       HXGE_DBG(hxgep, "Implicit VLAN ID %d",hxgep->vlan_id);
+       if (status != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hpi_pfc_cfg_vlan_control_set failed to enable VLAN");
+               return;
+       }
+       if (grp) {
+               HXGE_DBG(hxgep, "Adding vlan group");
+               /* Initialize the entire vlan table to avoid parity err */
+               hpi_pfc_cfg_vlan_table_clear(handle);
+       }
+       else {
+               HXGE_DBG(hxgep, "Removing vlan group");
+       }
+       hxgep->vlangrp = grp;
+}
+
+
+void
+hxge_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
+{
+        struct hxge_adapter *hxgep = netdev_priv(netdev);
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+       hpi_status_t status;
+
+       HXGE_DBG(hxgep, "Adding VID %d", vid);
+       status = hpi_pfc_cfg_vlan_table_entry_set(handle, vid);
+       if (status != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hpi_pfc_cfg_vlan_table_entry_set failed, status = %d", status);
+               return;
+       }
+}
+
+void
+hxge_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
+{
+        struct hxge_adapter *hxgep = netdev_priv(netdev);
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+       hpi_status_t status;
+       
+       HXGE_DBG(hxgep, "Removing VID %d", vid);
+       status = hpi_pfc_cfg_vlan_table_entry_clear(handle, vid);
+       if (status != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hpi_pfc_cfg_vlan_table_entry_clear failed");
+               return;
+       }
+}
+
+
+int
+hxge_set_mac_address(struct net_device *netdev, void *p)
+{
+       struct sockaddr *addr = (struct sockaddr *)p;
+       struct hxge_adapter *hxgep = netdev_priv(netdev);
+       pfc_mac_addr_t  mac_addr;
+       int status = 0;
+       int i;
+
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       MUTEX_ENTER(&hxgep->lock);
+
+       /* Hydra expects the MAC address to be in little endian (PCI device).
+         * So, we byte swap from network order (big endian) to little endian 
+        */
+
+       for (i = 0; i < ETH_ALEN; i++)
+               mac_addr.byte[i] = addr->sa_data[ETH_ALEN-1-i];
+
+       status = hxge_pfc_set_mac_address(hxgep, HXGE_MAC_DEFAULT_ADDR_SLOT,
+                               mac_addr);
+
+       memcpy(netdev->dev_addr, addr->sa_data, ETH_ALEN);
+       memcpy(&mac_addr.value, addr->sa_data, ETH_ALEN);
+
+       MUTEX_EXIT(&hxgep->lock);
+
+       if (status)
+               HXGE_ERR(hxgep, "Unable to set mac address");
+
+       return (status);
+}
+
+int
+hxge_add_mcast_addr(struct hxge_adapter *  hxgep, uint8_t *addrp)
+{
+       return  0;
+}
+
+int
+hxge_del_mcast_addr(struct hxge_adapter *  hxgep, uint8_t *addrp)
+{
+       return  0;
+}
+
+static int
+hxge_pfc_set_mac_address(struct hxge_adapter *  hxgep, uint32_t slot, 
+               pfc_mac_addr_t address)
+{
+       void *                  handle = hxgep->hw.hw_addr;
+       hpi_status_t            hpi_status;
+
+       hpi_status = hpi_pfc_set_mac_address(handle, slot, address.value);
+       if (hpi_status != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "failed to set PFC slot %d to MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
+                        slot, address.byte[5], address.byte[4],
+                        address.byte[3], address.byte[2],
+                        address.byte[1], address.byte[0]);
+               hpi_pfc_mac_addr_disable(handle, slot); /* Might as well try */
+               return  -1;
+       }
+
+       /* A MAC address of 00:00:00:00:00:00 is a call to disable
+        * that PFC MAC slot; all other addresses assumed valid and
+        * the PFC is enabled to match incoming traffic against that
+        * MAC address slot.
+        */
+
+       if (address.bits.addr) { /* Enable PFC MAC addr match */
+               hpi_status = hpi_pfc_mac_addr_enable(handle, slot);
+               if (hpi_status != HPI_SUCCESS) {
+                       HXGE_ERR(hxgep, "Failed to enable PFC slot %d for MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
+                                slot, address.byte[5], address.byte[4],
+                                address.byte[3], address.byte[2],
+                                address.byte[1], address.byte[0]);
+                       return  -1;
+               }
+       } else {                /* Disable PFC MAC==0 slot */
+               hpi_status = hpi_pfc_mac_addr_disable(handle, slot);
+               if (hpi_status != HPI_SUCCESS) {
+                       HXGE_ERR(hxgep, "Failed to disable PFC slot %d for MAC address 00:00:00:00:00:00",
+                                slot);
+                       return  -1;
+               }
+       }
+
+       return  0;
+}
+
+int
+hxge_pfc_num_macs_get(struct hxge_adapter *  hxgep, uint32_t *nmacs)
+{
+       *nmacs = PFC_N_MAC_ADDRESSES;
+       return  0;
+}
+
+
+static int
+hxge_pfc_config_init(struct hxge_adapter *  hxgep)
+{
+       void *  handle;
+       handle = hxgep->hw.hw_addr;
+
+       MUTEX_ENTER(&hxgep->lock);
+
+       (void) hpi_pfc_set_tcam_enable(handle, FALSE);
+       (void) hpi_pfc_set_l2_hash(handle, TRUE);
+
+       if (hxgep->flags & (HXGE_RX_CHKSUM_ENABLED | HXGE_TX_CHKSUM_ENABLED))
+               (void) hpi_pfc_set_tcp_cksum(handle, TRUE);
+       else
+               (void) hpi_pfc_set_tcp_cksum(handle, FALSE);
+
+       (void) hpi_pfc_set_default_dma(handle, 0);
+       (void) hpi_pfc_mac_addr_enable(handle, 0);
+       (void) hpi_pfc_set_force_csum(handle, FALSE);
+
+       /* Clear the interrupt masks */
+       hpi_pfc_set_interrupt_mask(handle, 0, 0, 0);
+        hpi_pfc_set_drop_log_mask(handle, 1, 1, 1, 1, 1);
+
+       MUTEX_EXIT(&hxgep->lock);
+       return  0;
+}
+
+int
+hxge_pfc_hw_reset(struct hxge_adapter *  hxgep)
+{
+       int status = 0;
+
+       HXGE_DBG(hxgep, "==> hxge_pfc_hw_reset");
+
+       status = hxge_pfc_config_init(hxgep);
+       if (status != 0) {
+               HXGE_ERR(hxgep, "failed PFC config init.");
+               return (status);
+       }
+
+       return  0;
+}
+
+
+static int hxge_pfc_load_hash_table(struct hxge_adapter *hxgep)
+{
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+       int i;
+
+
+       hpi_pfc_set_l2_hash(handle, FALSE);
+
+       for (i = 0; i < MAC_MAX_HASH_ENTRY; i++) 
+               if (hpi_pfc_set_multicast_hash_table(handle, i, 
+                                               hxgep->mcast_hash_tbl[i])) {
+                       HXGE_ERR(hxgep, "hpi_pfc_set_multicast_hash_table failed");
+                       return -1;
+       }
+
+       hpi_pfc_set_l2_hash(handle, TRUE);
+       return 0;
+
+}
+
+/* Took this routine from ether_crc_le in linux/crc32.h and modified the 
+ * way that the ethernet address is passed. Hydra computes the 
+ * address backwards i.e pass the highest octet first and work backwards
+ * to the lowest octet
+ */
+static 
+uint32_t crc32_le(unsigned char const *addr, size_t len)
+{
+        int i;
+       uint32_t crc = 0xffffffff;
+
+        while (len--) {
+                crc ^= addr[len];
+                for (i = 0; i < 8; i++)
+                        crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
+        }
+        return ((~crc) >> 24);
+}
+
+void hxge_set_multi (struct net_device *dev)
+{
+       struct hxge_adapter *hxgep = netdev_priv(dev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)
+       struct dev_mc_list *dmi = dev->mc_list;
+#else
+       struct netdev_hw_addr *dmi;
+#endif
+       uint16_t *filter_tbl= &hxgep->mcast_hash_tbl[0];
+       uint32_t crc;
+       uint8_t byte = 0;
+       
+       spin_lock(&hxgep->lock);
+
+       if (dev->flags & IFF_PROMISC)
+       {
+               HXGE_DBG(hxgep, "PROMISC enabled");
+               hxge_vmac_promisc(hxgep, 1);
+       }
+       else {
+               HXGE_DBG(hxgep, "PROMSC disabled");
+               hxge_vmac_promisc(hxgep, 0);
+       }
+
+       if (dev->flags & IFF_ALLMULTI) 
+       {
+               HXGE_DBG(hxgep, "Setting allmulti");
+               byte = 0xff;
+       }
+
+       memset(filter_tbl, byte, sizeof(uint16_t)*MAC_MAX_HASH_ENTRY);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)
+       while (dmi) {
+               HXGE_DBG(hxgep, "Adding %x:%x:%x:%x:%x:%x", dmi->dmi_addr[0],dmi->dmi_addr[1],dmi->dmi_addr[2],dmi->dmi_addr[3],dmi->dmi_addr[4],dmi->dmi_addr[5]);
+               crc = crc32_le(dmi->dmi_addr, ETH_ALEN);
+               filter_tbl[crc/MAC_MAX_HASH_ENTRY] |= 
+                               1 << (crc%MAC_MAX_HASH_ENTRY);
+               dmi = dmi->next;
+       }
+#else
+       netdev_for_each_mc_addr(dmi, dev) {
+               crc = crc32_le(dmi->addr, ETH_ALEN);
+               filter_tbl[crc/MAC_MAX_HASH_ENTRY] |= 
+                               1 << (crc%MAC_MAX_HASH_ENTRY);
+       }
+#endif
+       hxge_pfc_load_hash_table(hxgep);
+       spin_unlock(&hxgep->lock);
+}
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+irqreturn_t 
+hxge_pfc_intr(int irq, void *data, struct pt_regs *regs)
+#else
+irqreturn_t 
+hxge_pfc_intr(int irq, void *data)
+#endif
+{
+       struct hxge_ldv *ldvp   = (struct hxge_ldv *)data;
+        struct hxge_ldg *ldgp = ldvp->ldgp;
+       struct hxge_adapter *hxgep = ldgp->hxgep;
+       void *          handle;
+       p_hxge_pfc_stats_t      statsp;
+       pfc_int_status_t        int_status;
+       pfc_bad_cs_counter_t    bad_cs_count;
+       pfc_drop_counter_t      drop_count;
+       pfc_drop_log_t          drop_log;
+       pfc_vlan_par_err_log_t  vlan_par_err_log;
+       pfc_tcam_par_err_log_t  tcam_par_err_log;
+
+       handle = hxgep->hw.hw_addr;
+       statsp = (p_hxge_pfc_stats_t)&hxgep->statsp->pfc_stats;
+
+       /*
+        * need to read the pfc interrupt status register to figure out
+        * what is happenning
+        */
+       hpi_pfc_get_interrupt_status(handle, &int_status);
+
+       if (int_status.bits.pkt_drop) {
+               statsp->pkt_drop++;
+
+               /* Collect each individual drops */
+               hpi_pfc_get_drop_log(handle, &drop_log);
+
+               if (drop_log.bits.l2_addr_drop) {
+                       statsp->errlog.l2_addr_drop++;
+                       HXGE_DBG(hxgep, "dropped => l2_addr");
+               }
+               if (drop_log.bits.class_code_drop) {
+                       statsp->errlog.class_code_drop++;
+                       HXGE_DBG(hxgep, "dropped => class_code");
+               }
+               if (drop_log.bits.tcam_drop) {
+                       statsp->errlog.tcam_drop++;
+                       HXGE_DBG(hxgep, "dropped => tcam_drop");
+               }
+               if (drop_log.bits.tcp_ctrl_drop) {
+                       statsp->errlog.tcp_ctrl_drop++;
+                       HXGE_DBG(hxgep, "dropped => tcp_ctrl");
+               }
+
+               /* Collect the total drops for all kinds */
+               (void) hpi_pfc_get_drop_counter(handle, &drop_count.value);
+               statsp->drop_count += drop_count.bits.drop_count;
+       }
+
+       if (int_status.bits.tcam_parity_err) {
+               statsp->tcam_parity_err++;
+
+               (void) hpi_pfc_get_tcam_parity_log(handle, &tcam_par_err_log);
+               statsp->errlog.tcam_par_err_log = tcam_par_err_log.bits.addr;
+               HXGE_DBG(hxgep, "hxge_pfc_intr: TCAM parity error addr: 0x%x",tcam_par_err_log.bits.addr);
+       }
+
+       if (int_status.bits.vlan_parity_err) {
+               statsp->vlan_parity_err++;
+
+               (void) hpi_pfc_get_vlan_parity_log(handle, &vlan_par_err_log);
+               statsp->errlog.vlan_par_err_log = vlan_par_err_log.bits.addr;
+
+               HXGE_DBG(hxgep, "hxge_pfc_intr: vlan table parity error addr: 0x%x", vlan_par_err_log.bits.addr);
+       }
+
+       (void) hpi_pfc_get_bad_csum_counter(handle, &bad_cs_count.value);
+       statsp->bad_cs_count += bad_cs_count.bits.bad_cs_count;
+
+       (void) hpi_pfc_clear_interrupt_status(handle);
+       return (IRQ_HANDLED);
+}
+
+int
+hxge_pfc_mac_addr_get(struct hxge_adapter *  hxgep, int slot, uint8_t *mac_addr)
+{
+       hpi_status_t    hpi_status = HPI_SUCCESS;
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+
+       /* MAC is in big-endian format now because callers require it that
+        * way
+        */
+       hpi_status = hpi_pfc_get_mac_address(handle, slot, mac_addr);
+       if (hpi_status != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "slot %d failed", slot);
+               return (-1 | hpi_status);
+       }
+
+        if (!is_valid_ether_addr(mac_addr)) {
+                return -1;
+       }
+
+       return (0);
+}
+
+
+/* Look for MAC address from the 16 that are available. We program the
+   net_device with the first valid mac address that we find. This routine
+   only fails if we have not found any valid mac addressess.
+*/
+
+int
+hxge_pfc_mac_addrs_get(struct hxge_adapter *hxgep)
+{
+       int i, num_found = 0, nmacs;
+       uint8_t        mac_addr[ETH_ALEN];
+
+       hxge_pfc_num_macs_get(hxgep, &nmacs);
+       for (i = 0; i < nmacs; i++) {
+               if (hxge_pfc_mac_addr_get(hxgep, i, mac_addr)) {
+                       HXGE_DBG(hxgep, "Slot %d No valid MAC address",i);
+                       continue;
+               } else {
+                       if (num_found==0) { /* Primary MAC */
+//                             HXGE_ERR(hxgep,
+//                             "Setting Net Device MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
+//                                     mac_addr[0], mac_addr[1], mac_addr[2],
+//                                     mac_addr[3], mac_addr[4], mac_addr[5]);
+
+                               /* Copy the MAC address into net_device struct */
+                               memcpy(hxgep->netdev->dev_addr, mac_addr, ETH_ALEN);
+                               /* Used by ethtool */
+                               memcpy(hxgep->netdev->perm_addr, mac_addr, ETH_ALEN);
+                       num_found++;
+                       }
+               } 
+
+//             memcpy(&hxgep->vmac.mac_addr[i], mac_addr, ETH_ALEN);
+       }
+
+       if (!num_found)
+               return -1;      /* FAIL if not at least one valid MAC address */
+
+       return 0;
+}
+
+/* This routine is called from the probe function. It reads the MAC addresses
+ * from the HCR register space and writes them to the PFC MAC address
+ * registers which are used by the interface to filter MAC addresses
+ */
+int 
+hxge_pfc_init_mac_addrs(struct hxge_adapter *hxgep)
+{
+       int nmacs,i;
+       pfc_mac_addr_t mac_addr;
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+
+       uint32_t addr_hi, addr_lo;
+       peu_debug_training_vec_t blade;
+       int offset;
+       int hcr_mac_count;
+       peu_intr_stat_t peusts;
+
+       hxge_pfc_num_macs_get(hxgep, &nmacs);
+
+       /* CR 6687755 Skewed SPROM vs HCR offsets */
+
+       HXGE_REG_RD32(handle, PEU_DEBUG_TRAINING_VEC, &blade.value);
+       HXGE_DBG(hxgep, "Base address 0x%p", handle);
+       HXGE_DBG(hxgep, "...   PEU_DEBUG_TRAINING_VEC 0x%8.8x", blade.value);
+       HXGE_DBG(hxgep, "...   Blade number (U/L) %d/%d",
+                blade.bits.bld_num_upper, blade.bits.bld_num_lower);
+
+       if (blade.bits.bld_num_upper) {
+               offset = 0x08;  /* Hydra blade/ports 1-5 MAC count at 8 */
+       } else {
+               offset = 0x04;  /* Hydra blade/port 0 MAC count at 4 */
+       }
+
+       /* Get count of SPROM/HCR-resident static MAC addresses */
+
+       HXGE_REG_RD32(handle, HCR_REG + offset, &addr_lo);
+       hcr_mac_count = (addr_lo >> 8) & 0xffffff; /* MAC count in [31:08] */
+       if (hcr_mac_count > 4) {
+               HXGE_ERR(hxgep, "HCR MAC count %d too large",
+                        hcr_mac_count);
+               hcr_mac_count = 1; /* Only use first entry */
+       }
+
+       HXGE_DBG(hxgep, "...   HCR_REG_CNT 0x%8.8x (= %d)", addr_lo, hcr_mac_count);
+
+       offset += 4;            /* Step to first HCR MAC address */
+
+       /* Initialize ("fill") PFC with MAC addresses; copy all static
+        * MAC addresses from SPROM (HCR registers) into PFC, zero-filling
+        * the rest of the PFC
+        */
+
+       for (i = 0; i < nmacs; i++, hcr_mac_count--) {
+               if (hcr_mac_count > 0) {
+                       HXGE_REG_RD32(handle, HCR_REG + offset, &addr_lo);
+                       HXGE_REG_RD32(handle, HCR_REG + offset+4, &addr_hi);
+                       offset += 8;
+                       /* Device error interrupt not yet enabled so must
+                        * poll PEU_INTR_STAT to get a timely HCR parity
+                        * error report
+                        */
+                       HXGE_REG_RD32(handle, PEU_INTR_STAT, &peusts.value);
+                       if (peusts.bits.hcr_parerr) {
+                               HXGE_ERR(hxgep, "HCR Parity Error (PEU_INTR_STAT=0x%8.8x) reading MAC %d",
+                                        peusts.value, i);
+                               return (-1); /* Init failed */
+                       }
+               } else {
+                       addr_lo = 0; /* No more SPROM MAC addresses, so */
+                       addr_hi = 0; /*   fill rest of PFC with zeros */
+               }
+
+               mac_addr.byte[5] = ((addr_lo)) & 0xff; /* First 4 MAC octets */
+               mac_addr.byte[4] = ((addr_lo) >>  8) & 0xff;
+               mac_addr.byte[3] = ((addr_lo) >> 16) & 0xff;
+               mac_addr.byte[2] = ((addr_lo) >> 24) & 0xff;
+               mac_addr.byte[1] = ((addr_hi)) & 0xff; /* Final 2 MAC octets */
+               mac_addr.byte[0] = ((addr_hi) >>  8) & 0xff;
+
+               if (hcr_mac_count > 0) {
+                       HXGE_ERR(hxgep, "Initializing static MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
+                                mac_addr.byte[5], mac_addr.byte[4],
+                                mac_addr.byte[3], mac_addr.byte[2],
+                                mac_addr.byte[1], mac_addr.byte[0]);
+               }
+
+               hxge_pfc_set_mac_address(hxgep, i, mac_addr);
+       }
+
+       if (hxge_pfc_mac_addrs_get(hxgep))
+               return -1;
+
+       return 0;
+}
diff --git a/drivers/net/hxge/hxge_pfc.h b/drivers/net/hxge/hxge_pfc.h
new file mode 100644 (file)
index 0000000..801f0f5
--- /dev/null
@@ -0,0 +1,315 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#ifndef _HXGE_PFC_H
+#define        _HXGE_PFC_H
+
+/* 0 and 4095 are reserved */
+#define        VLAN_ID_MIN                     0
+#define        VLAN_ID_MAX                     4094
+#define        VLAN_ID_IMPLICIT                4094
+#define VLAN_MAX_ENTRIES               128
+
+#define        HXGE_MAC_DEFAULT_ADDR_SLOT      0
+
+#define        REG_PIO_WRITE64(handle, offset, value) \
+               HXGE_REG_WR64((handle), (offset), (value))
+#define        REG_PIO_READ64(handle, offset, val_p) \
+               HXGE_REG_RD64((handle), (offset), (val_p))
+
+#define        TCAM_CTL_RWC_TCAM_WR            0x0
+#define        TCAM_CTL_RWC_TCAM_CMP           0x2
+#define        TCAM_CTL_RWC_RAM_WR             0x4
+#define        TCAM_CTL_RWC_RAM_RD             0x5
+#define        TCAM_CTL_RWC_RWC_STAT           0x1
+#define        TCAM_CTL_RWC_RWC_MATCH          0x1
+
+#define MAC_MAX_HASH_ENTRY             16
+
+#define        WRITE_TCAM_REG_CTL(handle, ctl) \
+               REG_PIO_WRITE64(handle, PFC_TCAM_CTRL, ctl)
+
+#define        READ_TCAM_REG_CTL(handle, val_p) \
+               REG_PIO_READ64(handle, PFC_TCAM_CTRL, val_p)
+
+#define        WRITE_TCAM_REG_KEY0(handle, key)        \
+               REG_PIO_WRITE64(handle,  PFC_TCAM_KEY0, key)
+#define        WRITE_TCAM_REG_KEY1(handle, key) \
+               REG_PIO_WRITE64(handle,  PFC_TCAM_KEY1, key)
+#define        WRITE_TCAM_REG_MASK0(handle, mask)   \
+               REG_PIO_WRITE64(handle,  PFC_TCAM_MASK0, mask)
+#define        WRITE_TCAM_REG_MASK1(handle, mask)   \
+               REG_PIO_WRITE64(handle,  PFC_TCAM_MASK1, mask)
+
+#define        READ_TCAM_REG_KEY0(handle, val_p)       \
+               REG_PIO_READ64(handle,  PFC_TCAM_KEY0, val_p)
+#define        READ_TCAM_REG_KEY1(handle, val_p)       \
+               REG_PIO_READ64(handle,  PFC_TCAM_KEY1, val_p)
+#define        READ_TCAM_REG_MASK0(handle, val_p)      \
+               REG_PIO_READ64(handle,  PFC_TCAM_MASK0, val_p)
+#define        READ_TCAM_REG_MASK1(handle, val_p)      \
+               REG_PIO_READ64(handle,  PFC_TCAM_MASK1, val_p)
+
+typedef union _hxge_tcam_res_t {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t padding:34;
+               uint64_t reserved:15;
+               uint64_t parity:1;
+               uint64_t hit_count:4;
+               uint64_t channel_d:2;
+               uint64_t channel_c:2;
+               uint64_t channel_b:2;
+               uint64_t channel_a:2;
+               uint64_t source_hash:1;
+               uint64_t discard:1;
+#else
+               uint64_t discard:1;
+               uint64_t source_hash:1;
+               uint64_t channel_a:2;
+               uint64_t channel_b:2;
+               uint64_t channel_c:2;
+               uint64_t channel_d:2;
+               uint64_t hit_count:4;
+               uint64_t parity:1;
+               uint64_t reserved:15;
+               uint64_t padding:34;
+#endif
+       } bits;
+} hxge_tcam_res_t, *p_hxge_tcam_res_t;
+
+typedef struct tcam_reg {
+#if defined(__BIG_ENDIAN)
+       uint64_t        reg1;           /* 99:64 */
+       uint64_t        reg0;           /* 63:0 */
+#else
+       uint64_t        reg0;           /* 63:0 */
+       uint64_t        reg1;           /* 99:64 */
+#endif
+} hxge_tcam_reg_t;
+
+typedef struct hxge_tcam_ipv4_S {
+#if defined(__BIG_ENDIAN)
+       uint32_t        class_code:4;   /* 99:95 */
+       uint32_t        blade_id:3;     /* 94:91 */
+       uint32_t        rsrvd2:2;       /* 90:89 */
+       uint32_t        noport:1;       /* 88 */
+       uint32_t        protocol:8;     /* 87:80 */
+       uint32_t        l4_hdr;         /* 79:48 */
+       uint32_t        rsrvd:16;       /* 47:32 */
+       uint32_t        ip_daddr;       /* 31:0 */
+#else
+       uint32_t        ip_daddr;       /* 31:0 */
+       uint32_t        rsrvd:16;       /* 47:32 */
+       uint32_t        l4_hdr;         /* 79:48 */
+       uint32_t        protocol:8;     /* 87:80 */
+       uint32_t        noport:1;       /* 88 */
+       uint32_t        rsrvd2:2;       /* 90:89 */
+       uint32_t        blade_id:3;     /* 94:91 */
+       uint32_t        class_code:4;   /* 99:95 */
+#endif
+} hxge_tcam_ipv4_t;
+
+typedef struct hxge_tcam_ipv6_S {
+#if defined(__BIG_ENDIAN)
+       uint32_t        class_code:4;   /* 99:95 */
+       uint32_t        blade_id:3;     /* 94:91 */
+       uint64_t        rsrvd2:3;       /* 90:88 */
+       uint64_t        protocol:8;     /* 87:80 */
+       uint64_t        l4_hdr:32;      /* 79:48 */
+       uint64_t        rsrvd:48;       /* 47:0 */
+#else
+       uint64_t        rsrvd:48;       /* 47:0 */
+       uint64_t        l4_hdr:32;      /* 79:48 */
+       uint64_t        protocol:8;     /* 87:80 */
+       uint64_t        rsrvd2:3;       /* 90:88 */
+       uint32_t        blade_id:3;     /* 94:91 */
+       uint32_t        class_code:4;   /* 99:95 */
+#endif
+} hxge_tcam_ipv6_t;
+
+typedef struct hxge_tcam_enet_S {
+#if defined(__BIG_ENDIAN)
+       uint8_t         class_code:4;   /* 99:95 */
+       uint8_t         blade_id:3;     /* 94:91 */
+       uint8_t         rsrvd:3;        /* 90:88 */
+       uint8_t         eframe[11];     /* 87:0 */
+#else
+       uint8_t         eframe[11];     /* 87:0 */
+       uint8_t         rsrvd:3;        /* 90:88 */
+       uint8_t         blade_id:3;     /* 94:91 */
+       uint8_t         class_code:4;   /* 99:95 */
+#endif
+} hxge_tcam_ether_t;
+
+typedef struct hxge_tcam_spread_S {
+#if defined(_BIG_ENDIAN)
+        uint32_t        unused:28;      /* 127:100 */
+        uint32_t        class_code:4;   /* 99:96 */
+        uint32_t        class_code_l:1; /* 95:95 */
+        uint32_t        blade_id:4;     /* 94:91 */
+        uint32_t        wild1:27;       /* 90:64 */
+        uint32_t        wild;           /* 63:32 */
+        uint32_t        wild_l;         /* 31:0 */
+#else
+        uint32_t        wild_l;         /* 31:0 */
+        uint32_t        wild;           /* 63:32 */
+        uint32_t        wild1:27;       /* 90:64 */
+        uint32_t        blade_id:4;     /* 94:91 */
+        uint32_t        class_code_l:1; /* 95:95 */
+        uint32_t        class_code:4;   /* 99:96 */
+        uint32_t        unused:28;      /* 127:100 */
+#endif
+} hxge_tcam_spread_t;
+
+
+typedef struct hxge_tcam_entry_S {
+       union _hxge_tcam_entry {
+               hxge_tcam_ipv4_t        ipv4;
+               hxge_tcam_ipv6_t        ipv6;
+               hxge_tcam_ether_t       enet;
+               hxge_tcam_reg_t         regs;
+               hxge_tcam_spread_t      spread;
+       } key, mask;
+       hxge_tcam_res_t                 match_action;
+       uint16_t                        ether_type;
+} hxge_tcam_entry_t;
+
+#define        key_reg0                key.regs.reg0
+#define        key_reg1                key.regs.reg1
+#define        mask_reg0               mask.regs.reg0
+#define        mask_reg1               mask.regs.reg1
+
+#define        key0                    key.regs.reg0
+#define        key1                    key.regs.reg1
+#define        mask0                   mask.regs.reg0
+#define        mask1                   mask.regs.reg1
+
+#define        ip4_class_key           key.ipv4.class_code
+#define        ip4_blade_id_key        key.ipv4.blade_id
+#define        ip4_noport_key          key.ipv4.noport
+#define        ip4_proto_key           key.ipv4.protocol
+#define        ip4_l4_hdr_key          key.ipv4.l4_hdr
+#define        ip4_dest_key            key.ipv4.ip_daddr
+
+#define        ip4_class_mask          mask.ipv4.class_code
+#define        ip4_blade_id_mask       mask.ipv4.blade_id
+#define        ip4_noport_mask         mask.ipv4.noport
+#define        ip4_proto_mask          mask.ipv4.protocol
+#define        ip4_l4_hdr_mask         mask.ipv4.l4_hdr
+#define        ip4_dest_mask           mask.ipv4.ip_daddr
+
+#define        ip6_class_key           key.ipv6.class_code
+#define        ip6_blade_id_key        key.ipv6.blade_id
+#define        ip6_proto_key           key.ipv6.protocol
+#define        ip6_l4_hdr_key          key.ipv6.l4_hdr
+
+#define        ip6_class_mask          mask.ipv6.class_code
+#define        ip6_blade_id_mask       mask.ipv6.blade_id
+#define        ip6_proto_mask          mask.ipv6.protocol
+#define        ip6_l4_hdr_mask         mask.ipv6.l4_hdr
+
+#define        ether_class_key         key.ether.class_code
+#define        ether_blade_id_key      key.ether.blade_id
+#define        ether_ethframe_key      key.ether.eframe
+
+#define        ether_class_mask        mask.ether.class_code
+#define        ether_blade_id_mask     mask.ether.blade_id
+#define        ether_ethframe_mask     mask.ether.eframe
+
+typedef        struct _pfc_errlog {
+       uint32_t                tcp_ctrl_drop;    /* pfc_drop_log */
+       uint32_t                l2_addr_drop;
+       uint32_t                class_code_drop;
+       uint32_t                tcam_drop;
+       uint32_t                vlan_drop;
+
+       uint32_t                vlan_par_err_log; /* pfc_vlan_par_err_log */
+       uint32_t                tcam_par_err_log; /* pfc_tcam_par_err_log */
+} pfc_errlog_t, *p_pfc_errlog_t;
+
+typedef struct _pfc_stats {
+       uint32_t                pkt_drop;       /* pfc_int_status */
+       uint32_t                tcam_parity_err;
+       uint32_t                vlan_parity_err;
+
+       uint32_t                bad_cs_count;   /* pfc_bad_cs_counter */
+       uint32_t                drop_count;     /* pfc_drop_counter */
+       pfc_errlog_t            errlog;
+} hxge_pfc_stats_t, *p_hxge_pfc_stats_t;
+
+typedef enum pfc_tcam_class {
+       TCAM_CLASS_INVALID = 0,
+       TCAM_CLASS_DUMMY = 1,
+       TCAM_CLASS_ETYPE_1 = 2,
+       TCAM_CLASS_ETYPE_2,
+       TCAM_CLASS_RESERVED_4,
+       TCAM_CLASS_RESERVED_5,
+       TCAM_CLASS_RESERVED_6,
+       TCAM_CLASS_RESERVED_7,
+       TCAM_CLASS_TCP_IPV4,
+       TCAM_CLASS_UDP_IPV4,
+       TCAM_CLASS_AH_ESP_IPV4,
+       TCAM_CLASS_SCTP_IPV4,
+       TCAM_CLASS_TCP_IPV6,
+       TCAM_CLASS_UDP_IPV6,
+       TCAM_CLASS_AH_ESP_IPV6,
+       TCAM_CLASS_SCTP_IPV6,
+       TCAM_CLASS_ARP,
+       TCAM_CLASS_RARP,
+       TCAM_CLASS_DUMMY_12,
+       TCAM_CLASS_DUMMY_13,
+       TCAM_CLASS_DUMMY_14,
+       TCAM_CLASS_DUMMY_15,
+       TCAM_CLASS_MAX
+} tcam_class_t;
+
+typedef struct _tcam_key_cfg_t {
+       boolean_t       lookup_enable;
+       boolean_t       discard;
+} tcam_key_cfg_t;
+
+#define        HXGE_ETHER_FLOWS        (FLOW_ETHER_DHOST | FLOW_ETHER_SHOST | \
+                                       FLOW_ETHER_TYPE)
+#define        HXGE_VLAN_FLOWS         (FLOW_ETHER_TPID | FLOW_ETHER_TCI)
+#define        HXGE_ETHERNET_FLOWS     (HXGE_ETHER_FLOWS | HXGE_VLAN_FLOWS)
+#define        HXGE_PORT_FLOWS         (FLOW_ULP_PORT_REMOTE | FLOW_ULP_PORT_LOCAL)
+#define        HXGE_ADDR_FLOWS         (FLOW_IP_REMOTE | FLOW_IP_LOCAL)
+#define        HXGE_IP_FLOWS           (FLOW_IP_VERSION | FLOW_IP_PROTOCOL | \
+                                       HXGE_PORT_FLOWS | HXGE_ADDR_FLOWS)
+#define        HXGE_SUPPORTED_FLOWS    (HXGE_ETHERNET_FLOWS | HXGE_IP_FLOWS)
+
+#define        VID_MASK                ((1 << 12) - 1)
+#define        L2RDC_TBL_NUM_MASK      ((1 << 2) - 1)
+#define        CLS_CODE_MASK           ((1 << 5) - 1)
+#define        PID_MASK                ((1 << 8) - 1)
+#define        IP_PORT_MASK            ((1 << 16) - 1)
+
+#define        IP_ADDR_SA_MASK         0xFFFFFFFF
+#define        IP_ADDR_DA_MASK         IP_ADDR_SA_MASK
+#define        L4PT_SPI_MASK           IP_ADDR_SA_MASK
+
+#endif /* !_HXGE_PFC_H */
diff --git a/drivers/net/hxge/hxge_pfc_hw.h b/drivers/net/hxge/hxge_pfc_hw.h
new file mode 100644 (file)
index 0000000..f620c5f
--- /dev/null
@@ -0,0 +1,765 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#ifndef        _HXGE_PFC_HW_H
+#define        _HXGE_PFC_HW_H
+
+#define        PFC_BASE_ADDR                           0X0200000
+
+#define        PFC_VLAN_TABLE                          (PFC_BASE_ADDR + 0x0)
+#define        PFC_VLAN_CTRL                           (PFC_BASE_ADDR + 0x9000)
+#define        PFC_MAC_ADDR                            (PFC_BASE_ADDR + 0x10000)
+#define        PFC_MAC_ADDR_MASK                       (PFC_BASE_ADDR + 0x10080)
+#define        PFC_HASH_TABLE                          (PFC_BASE_ADDR + 0x10100)
+#define        PFC_L2_CLASS_CONFIG                     (PFC_BASE_ADDR + 0x20000)
+#define        PFC_L3_CLASS_CONFIG                     (PFC_BASE_ADDR + 0x20030)
+#define        PFC_TCAM_KEY0                           (PFC_BASE_ADDR + 0x20090)
+#define        PFC_TCAM_KEY1                           (PFC_BASE_ADDR + 0x20098)
+#define        PFC_TCAM_MASK0                          (PFC_BASE_ADDR + 0x200B0)
+#define        PFC_TCAM_MASK1                          (PFC_BASE_ADDR + 0x200B8)
+#define        PFC_TCAM_CTRL                           (PFC_BASE_ADDR + 0x200D0)
+#define        PFC_CONFIG                              (PFC_BASE_ADDR + 0x20100)
+#define        TCP_CTRL_MASK                           (PFC_BASE_ADDR + 0x20108)
+#define        SRC_HASH_VAL                            (PFC_BASE_ADDR + 0x20110)
+#define        PFC_INT_STATUS                          (PFC_BASE_ADDR + 0x30000)
+#define        PFC_DBG_INT_STATUS                      (PFC_BASE_ADDR + 0x30008)
+#define        PFC_INT_MASK                            (PFC_BASE_ADDR + 0x30100)
+#define        PFC_DROP_LOG                            (PFC_BASE_ADDR + 0x30200)
+#define        PFC_DROP_LOG_MASK                       (PFC_BASE_ADDR + 0x30208)
+#define        PFC_VLAN_PAR_ERR_LOG                    (PFC_BASE_ADDR + 0x30210)
+#define        PFC_TCAM_PAR_ERR_LOG                    (PFC_BASE_ADDR + 0x30218)
+#define        PFC_BAD_CS_COUNTER                      (PFC_BASE_ADDR + 0x30220)
+#define        PFC_DROP_COUNTER                        (PFC_BASE_ADDR + 0x30228)
+#define        PFC_AUTO_INIT                           (PFC_BASE_ADDR + 0x30300)
+
+
+/*
+ * Register: PfcVlanTable
+ * VLAN Table Registers
+ * Description: VLAN membership table. CPU programs in the VLANs that
+ * it wants to belong to. A blade may be a member of multiple VLANs.
+ * Bits [31:0] of the first entry corresponds to vlan members [31:0],
+ * bits [31:0] of the second entry corresponds to vlan members
+ * [63:32] and so on.
+ * Fields:
+ *     Odd parities of member[31:24], member[23:16], member[17:8],
+ *     member[7:0]. These parity bits are ignored when parEn in the
+ *     VLAN Control register is set to '0'.
+ *     Set to 1 to indicate that blade is a member of the VLAN IDs
+ *     (32 to 0) * entry number
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:28;
+               uint64_t        parity:4;
+               uint64_t        member:32;
+#else
+               uint64_t        member:32;
+               uint64_t        parity:4;
+               uint64_t        rsrvd:28;
+#endif
+       } bits;
+} pfc_vlan_table_t;
+
+
+/*
+ * Register: PfcVlanCtrl
+ * VLAN Control Register
+ * Description: VLAN control register. Controls VLAN table properties
+ * and implicit VLAN properties for non-VLAN tagged packets.
+ * Fields:
+ *     VLAN table parity debug write enable. When set to 1, software
+ *     writes the parity bits together with the data during a VLAN
+ *     table write. Otherwise, hardware automatically generates the
+ *     parity bits from the data.
+ *     Set to 1 to indicate the implicit VLAN ID is valid for use in
+ *     non-VLAN tagged packets filtering
+ *     Implicit VLAN ID for non-VLAN tagged packets
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:50;
+               uint64_t        par_en:1;
+               uint64_t        valid:1;
+               uint64_t        id:12;
+#else
+               uint64_t        id:12;
+               uint64_t        valid:1;
+               uint64_t        par_en:1;
+               uint64_t        rsrvd:50;
+#endif
+       } bits;
+} pfc_vlan_ctrl_t;
+
+
+/*
+ * Register: PfcMacAddr
+ * MAC Address
+ * Description: MAC Address - Contains a station's 48 bit MAC
+ * address. The first register corresponds to MAC address 0, the
+ * second register corresponds to MAC address 1 and so on. For a MAC
+ * address of format aa-bb-cc-dd-ee-ff, addr[47:0] corresponds to
+ * "aabbccddeeff". When used in conjunction with the MAC address
+ * filter mask registers, these registers can be used to construct
+ * either a unicast or multicast address. An address is considered
+ * matched if (DA & ~mask) == (MAC address & ~mask)
+ * Fields:
+ *     48 bits of stations's MAC address
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:16;
+               uint64_t        addr:48;
+#else
+               uint64_t        addr:48;
+               uint64_t        rsrvd:16;
+#endif
+       } bits;
+       uint8_t byte[8];
+} pfc_mac_addr_t;
+
+
+/*
+ * Register: PfcMacAddrMask
+ * MAC Address Filter
+ * Description: MAC Address Filter Mask - Contains the station's 48
+ * bit MAC address filter mask. The first register corresponds to MAC
+ * address 0 filter mask, the second register corresponds to MAC
+ * address 1 filter mask and so on. These filter masks cover MAC
+ * address bits 47:0 in the same order as the address registers
+ * Fields:
+ *     48 bits of stations's MAC address filter mask
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:16;
+               uint64_t        mask:48;
+#else
+               uint64_t        mask:48;
+               uint64_t        rsrvd:16;
+#endif
+       } bits;
+       uint8_t byte[8];
+} pfc_mac_addr_mask_t;
+
+
+/*
+ * Register: PfcHashTable
+ * MAC Multicast Hash Filter
+ * Description: MAC multicast hash table filter. The multicast
+ * destination address is used to perform Ethernet CRC-32 hashing
+ * with seed value 0xffffFfff. Bits 47:40 of the hash result are used
+ * to index one bit of this multicast hash table. If the bit is '1',
+ * the multicast hash matches.
+ * Fields:
+ *     16 bits of 256 bit hash table. First entry contains bits
+ *     [15:0], last entry contains bits [255:240]
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:48;
+               uint64_t        hash_val:16;
+#else
+               uint64_t        hash_val:16;
+               uint64_t        rsrvd:48;
+#endif
+       } bits;
+} pfc_hash_table_t;
+
+
+/*
+ * Register: PfcL2ClassConfig
+ * L2 Class Configuration
+ * Description: Programmable EtherType for class codes 2 and 3. The
+ * first register is class 2, and the second class 3
+ * Fields:
+ *     Set to 1 to indicate that the entry is valid for use in
+ *     classification
+ *     EtherType value
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:47;
+               uint64_t        valid:1;
+               uint64_t        etype:16;
+#else
+               uint64_t        etype:16;
+               uint64_t        valid:1;
+               uint64_t        rsrvd:47;
+#endif
+       } bits;
+} pfc_l2_class_config_t;
+
+
+/*
+ * Register: PfcL3ClassConfig
+ * L3 Class Configuration
+ * Description: Configuration for class codes 0x8-0xF. PFC can be set
+ * to discard certain classes of traffic, or to not initiate a TCAM
+ * match for that class
+ * Fields:
+ *     Set to 1 to discard all packets of this class code
+ *     Set to 1 to indicate that packets of this class should be sent
+ *     to the TCAM for perfect match
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:60;
+               uint64_t        discard:1;
+               uint64_t        tsel:1;
+               uint64_t        rsrvd1:2;
+#else
+               uint64_t        rsrvd1:2;
+               uint64_t        tsel:1;
+               uint64_t        discard:1;
+               uint64_t        rsrvd:60;
+#endif
+       } bits;
+} pfc_l3_class_config_t;
+
+
+/*
+ * Register: PfcTcamKey0
+ * TCAM Key 0
+ * Description: TCAM key value. Holds bit 63:0 of the TCAM key
+ * Fields:
+ *     bits 63:0 of tcam key
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        key:64;
+#else
+               uint64_t        key:64;
+#endif
+       } bits;
+} pfc_tcam_key0_t;
+
+
+/*
+ * Register: PfcTcamKey1
+ * TCAM Key 1
+ * Description: TCAM key value. Holds bit 99:64 of the TCAM key
+ * Fields:
+ *     bits 99:64 of tcam key
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:28;
+               uint64_t        key:36;
+#else
+               uint64_t        key:36;
+               uint64_t        rsrvd:28;
+#endif
+       } bits;
+} pfc_tcam_key1_t;
+
+
+/*
+ * Register: PfcTcamMask0
+ * TCAM Mask 0
+ * Description: TCAM mask value. Holds bit 63:0 of the TCAM mask
+ * Fields:
+ *     bits 63:0 of tcam mask
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        mask:64;
+#else
+               uint64_t        mask:64;
+#endif
+       } bits;
+} pfc_tcam_mask0_t;
+
+
+/*
+ * Register: PfcTcamMask1
+ * TCAM Mask 1
+ * Description: TCAM mask value. Holds bit 99:64 of the TCAM mask
+ * Fields:
+ *     bits 99:64 of tcam mask
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:28;
+               uint64_t        mask:36;
+#else
+               uint64_t        mask:36;
+               uint64_t        rsrvd:28;
+#endif
+       } bits;
+} pfc_tcam_mask1_t;
+
+
+/*
+ * Register: PfcTcamCtrl
+ * TCAM Control
+ * Description: TCAM and TCAM lookup memory access control register.
+ * Controls how TCAM and result lookup table are accessed by blade
+ * CPU. For a TCAM write, the data in the TCAM key and mask registers
+ * will be written to the TCAM. A compare will initiate a TCAM match
+ * with the data stored in the TCAM key register. The match bit is
+ * toggled, and the matching address is reported in the addr field.
+ * For an access to the TCAM result lookup memory, the TCAM 0 key
+ * register is used for the read/write data.
+ * Fields:
+ *     TCAM lookup table debug parity bit write enable. When a '1' is
+ *     written, software writes the parity bit together with the data
+ *     during a TCAM result lookup write. Otherwise, hardware
+ *     automatically generates the parity bit from the data.
+ *     3'b000 = TCAM write 3'b001 = reserved 3'b010 = TCAM compare
+ *     3'b011 = reserved 3'b100 = TCAM result lookup write 3'b101 =
+ *     TCAM result lookup read 3'b110 = reserved 3'b111 = reserved
+ *     Status of read/write/compare operation. When a zero is
+ *     written, hardware initiates access. Hardware writes a '1' to
+ *     the bit when it completes
+ *     Set to 1 if there is a TCAM match for compare command. Zero
+ *     otherwise
+ *     Address location for access of TCAM or RAM (valid values
+ *     0-42). For a compare, the location of the match is written
+ *     here by hardware.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:45;
+               uint64_t        par_en:1;
+               uint64_t        cmd:3;
+               uint64_t        status:1;
+               uint64_t        match:1;
+               uint64_t        rsrvd1:5;
+               uint64_t        addr:8;
+#else
+               uint64_t        addr:8;
+               uint64_t        rsrvd1:5;
+               uint64_t        match:1;
+               uint64_t        status:1;
+               uint64_t        cmd:3;
+               uint64_t        par_en:1;
+               uint64_t        rsrvd:45;
+#endif
+       } bits;
+} pfc_tcam_ctrl_t;
+
+
+/*
+ * Register: PfcConfig
+ * PFC General Configuration
+ * Description: PFC configuration options that are under the control
+ * of a blade CPU
+ * Fields:
+ *     MAC address enable mask. Each bit corresponds to one MAC
+ *     adress (lsb = addr0). With 16 MAC addresses, only the lower 16
+ *     bits are valid.
+ *     default DMA channel number
+ *     force TCP/UDP checksum result to always match
+ *     Enable for TCP/UDP checksum. If not enabled, the result will
+ *     never match.
+ *     Enable TCAM matching. If TCAM matching is not enabled, traffic
+ *     will be sent to the default DMA channel.
+ *     Enable L2 Multicast hash
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:24;
+               uint64_t        mac_addr_en:32;
+               uint64_t        default_dma:4;
+               uint64_t        force_cs_en:1;
+               uint64_t        tcp_cs_en:1;
+               uint64_t        tcam_en:1;
+               uint64_t        l2_hash_en:1;
+#else
+               uint64_t        l2_hash_en:1;
+               uint64_t        tcam_en:1;
+               uint64_t        tcp_cs_en:1;
+               uint64_t        force_cs_en:1;
+               uint64_t        default_dma:4;
+               uint64_t        mac_addr_en:32;
+               uint64_t        rsrvd:24;
+#endif
+       } bits;
+} pfc_config_t;
+
+
+/*
+ * Register: TcpCtrlMask
+ * TCP control bits mask
+ * Description: Mask of TCP control bits to forward onto downstream
+ * blocks The TCP packet's control bits are masked, and then bitwise
+ * OR'd to produce a signal to the Rx DMA. Normally, all bits are
+ * masked off except the TCP SYN bit. The Rx DMA uses this bitwise OR
+ * for statistics. When discard = 1, the packet will be dropped if
+ * the bitwise OR = 1.
+ * Fields:
+ *     Drop the packet if bitwise OR of the TCP control bits masked
+ *     on = 1
+ *     TCP end of data flag
+ *     TCP SYN flag
+ *     TCP reset flag
+ *     TCP push flag
+ *     TCP ack flag
+ *     TCP urgent flag
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:57;
+               uint64_t        discard:1;
+               uint64_t        fin:1;
+               uint64_t        syn:1;
+               uint64_t        rst:1;
+               uint64_t        psh:1;
+               uint64_t        ack:1;
+               uint64_t        urg:1;
+#else
+               uint64_t        urg:1;
+               uint64_t        ack:1;
+               uint64_t        psh:1;
+               uint64_t        rst:1;
+               uint64_t        syn:1;
+               uint64_t        fin:1;
+               uint64_t        discard:1;
+               uint64_t        rsrvd:57;
+#endif
+       } bits;
+} tcp_ctrl_mask_t;
+
+
+/*
+ * Register: SrcHashVal
+ * Source hash Seed Value
+ *     Hash CRC seed value
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        seed:32;
+#else
+               uint64_t        seed:32;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} src_hash_val_t;
+
+
+/*
+ * Register: PfcIntStatus
+ * PFC Interrupt Status
+ * Description: PFC interrupt status register
+ * Fields:
+ *     triggered when packet drop log captured a drop. Part of LDF 0.
+ *     Write 1 to clear.
+ *     TCAM result lookup table parity error. Part of LDF 0. Write 1
+ *     to clear.
+ *     VLAN table parity error. Part of LDF 0. Write 1 to clear.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:61;
+               uint64_t        pkt_drop:1;
+               uint64_t        tcam_parity_err:1;
+               uint64_t        vlan_parity_err:1;
+#else
+               uint64_t        vlan_parity_err:1;
+               uint64_t        tcam_parity_err:1;
+               uint64_t        pkt_drop:1;
+               uint64_t        rsrvd:61;
+#endif
+       } bits;
+} pfc_int_status_t;
+
+
+/*
+ * Register: PfcDbgIntStatus
+ * PFC Debug Interrupt Status
+ * Description: PFC debug interrupt status mirror register. This
+ * debug register triggers the same interrupts as those in the PFC
+ * Interrupt Status register. Interrupts in this mirror register are
+ * subject to the filtering of the PFC Interrupt Mask register.
+ * Fields:
+ *     Packet drop. Part of LDF 0.
+ *     TCAM result lookup table parity error. Part of LDF 0.
+ *     VLAN table parity error. Part of LDF 0.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:61;
+               uint64_t        pkt_drop:1;
+               uint64_t        tcam_parity_err:1;
+               uint64_t        vlan_parity_err:1;
+#else
+               uint64_t        vlan_parity_err:1;
+               uint64_t        tcam_parity_err:1;
+               uint64_t        pkt_drop:1;
+               uint64_t        rsrvd:61;
+#endif
+       } bits;
+} pfc_dbg_int_status_t;
+
+
+/*
+ * Register: PfcIntMask
+ * PFC Interrupt Mask
+ * Description: PFC interrupt status mask register
+ * Fields:
+ *     mask for pktDrop capture;
+ *     TCAM result lookup table parity error mask;
+ *     VLAN table parity error mask;
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:61;
+               uint64_t        pkt_drop_mask:1;
+               uint64_t        tcam_parity_err_mask:1;
+               uint64_t        vlan_parity_err_mask:1;
+#else
+               uint64_t        vlan_parity_err_mask:1;
+               uint64_t        tcam_parity_err_mask:1;
+               uint64_t        pkt_drop_mask:1;
+               uint64_t        rsrvd:61;
+#endif
+       } bits;
+} pfc_int_mask_t;
+
+
+/*
+ * Register: PfcDropLog
+ * Packet Drop Log
+ * Description: Packet drop log. Log for capturing packet drops. Log
+ * is re-armed when associated interrupt bit is cleared.
+ * Fields:
+ *     drop because bitwise OR of the tcp control bits masked on = 1
+ *     drop because L2 address did not match
+ *     drop because class code indicated drop
+ *     drop because TCAM result indicated drop
+ *     drop because blade was not a member of VLAN
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:59;
+               uint64_t        tcp_ctrl_drop:1;
+               uint64_t        l2_addr_drop:1;
+               uint64_t        class_code_drop:1;
+               uint64_t        tcam_drop:1;
+               uint64_t        vlan_drop:1;
+#else
+               uint64_t        vlan_drop:1;
+               uint64_t        tcam_drop:1;
+               uint64_t        class_code_drop:1;
+               uint64_t        l2_addr_drop:1;
+               uint64_t        tcp_ctrl_drop:1;
+               uint64_t        rsrvd:59;
+#endif
+       } bits;
+} pfc_drop_log_t;
+
+
+/*
+ * Register: PfcDropLogMask
+ * Packet Drop Log Mask
+ * Description: Mask for logging packet drop. If the drop type is
+ * masked off, it will not trigger the drop log to capture the packet
+ * drop
+ * Fields:
+ *     mask drop because bitwise OR of the tcp control bits masked on
+ *     = 1
+ *     mask drop because L2 address did not match
+ *     mask drop because class code indicated
+ *     mask drop because TCAM result indicated drop
+ *     mask drop because blade was not a member of VLAN
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:59;
+               uint64_t        tcp_ctrl_drop_mask:1;
+               uint64_t        l2_addr_drop_mask:1;
+               uint64_t        class_code_drop_mask:1;
+               uint64_t        tcam_drop_mask:1;
+               uint64_t        vlan_drop_mask:1;
+#else
+               uint64_t        vlan_drop_mask:1;
+               uint64_t        tcam_drop_mask:1;
+               uint64_t        class_code_drop_mask:1;
+               uint64_t        l2_addr_drop_mask:1;
+               uint64_t        tcp_ctrl_drop_mask:1;
+               uint64_t        rsrvd:59;
+#endif
+       } bits;
+} pfc_drop_log_mask_t;
+
+
+/*
+ * Register: PfcVlanParErrLog
+ * VLAN Parity Error Log
+ * Description: Log of parity errors in VLAN table.
+ * Fields:
+ *     address of parity error. Log is cleared when corresponding
+ *     interrupt bit is cleared by writing '1'.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:52;
+               uint64_t        addr:12;
+#else
+               uint64_t        addr:12;
+               uint64_t        rsrvd:52;
+#endif
+       } bits;
+} pfc_vlan_par_err_log_t;
+
+
+/*
+ * Register: PfcTcamParErrLog
+ * TCAM Parity Error Log
+ * Description: Log of parity errors in TCAM result lookup table.
+ * Fields:
+ *     address of parity error. Log is cleared when corresponding
+ *     interrupt bit is cleared by writing '1'.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:56;
+               uint64_t        addr:8;
+#else
+               uint64_t        addr:8;
+               uint64_t        rsrvd:56;
+#endif
+       } bits;
+} pfc_tcam_par_err_log_t;
+
+
+/*
+ * Register: PfcBadCsCounter
+ * PFC Bad Checksum Counter
+ * Description: Count number of bad TCP/UDP checksum. Only counted if
+ * L2 adddress matched
+ * Fields:
+ *     count of number of bad TCP/UDP checksums received. Clear on
+ *     read
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        bad_cs_count:32;
+#else
+               uint64_t        bad_cs_count:32;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} pfc_bad_cs_counter_t;
+
+
+/*
+ * Register: PfcDropCounter
+ * PFC Drop Counter
+ * Description: Count number of packets dropped due to VLAN
+ * membership, class code, TCP control bits, or TCAM results Only
+ * counted if L2 address matched.
+ * Fields:
+ *     Count of number of packets dropped due to VLAN, TCAM results.
+ *     Clear on read
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        drop_count:32;
+#else
+               uint64_t        drop_count:32;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} pfc_drop_counter_t;
+
+
+/*
+ * Register: PfcAutoInit
+ * PFC Auto Init
+ * Description: PFC Auto Initialization. Writing to this register
+ * triggers the auto initialization of the blade's TCAM entries with
+ * 100 bits of '0' for both key and mask. TCAM lookup is disabled
+ * during auto initialization.
+ * Fields:
+ *     TCAM auto initialization status. 0=busy, 1=done.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:63;
+               uint64_t        auto_init_status:1;
+#else
+               uint64_t        auto_init_status:1;
+               uint64_t        rsrvd:63;
+#endif
+       } bits;
+} pfc_auto_init_t;
+
+
+#endif /* _HXGE_PFC_HW_H */
diff --git a/drivers/net/hxge/hxge_rdc_hw.h b/drivers/net/hxge/hxge_rdc_hw.h
new file mode 100644 (file)
index 0000000..b376f10
--- /dev/null
@@ -0,0 +1,1601 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#ifndef        _HXGE_RDC_HW_H
+#define        _HXGE_RDC_HW_H
+
+#define        RDC_BASE_ADDR                           0X00300000
+
+#define        RDC_PAGE_HANDLE                         (RDC_BASE_ADDR + 0x8)
+#define        RDC_RX_CFG1                             (RDC_BASE_ADDR + 0x20)
+#define        RDC_RX_CFG2                             (RDC_BASE_ADDR + 0x28)
+#define        RDC_RBR_CFG_A                           (RDC_BASE_ADDR + 0x40)
+#define        RDC_RBR_CFG_B                           (RDC_BASE_ADDR + 0x48)
+#define        RDC_RBR_KICK                            (RDC_BASE_ADDR + 0x50)
+#define        RDC_RBR_QLEN                            (RDC_BASE_ADDR + 0x58)
+#define        RDC_RBR_HEAD                            (RDC_BASE_ADDR + 0x68)
+#define        RDC_RCR_CFG_A                           (RDC_BASE_ADDR + 0x80)
+#define        RDC_RCR_CFG_B                           (RDC_BASE_ADDR + 0x88)
+#define        RDC_RCR_QLEN                            (RDC_BASE_ADDR + 0x90)
+#define        RDC_RCR_TAIL                            (RDC_BASE_ADDR + 0xA0)
+#define        RDC_RCR_FLUSH                           (RDC_BASE_ADDR + 0xA8)
+#define        RDC_CLOCK_DIV                           (RDC_BASE_ADDR + 0xB0)
+#define        RDC_INT_MASK                            (RDC_BASE_ADDR + 0xB8)
+#define        RDC_STAT                                (RDC_BASE_ADDR + 0xC0)
+#define        RDC_PKT_COUNT                           (RDC_BASE_ADDR + 0xD0)
+#define        RDC_DROP_COUNT                          (RDC_BASE_ADDR + 0xD8)
+#define        RDC_BYTE_COUNT                          (RDC_BASE_ADDR + 0xE0)
+#define        RDC_PREF_CMD                            (RDC_BASE_ADDR + 0x100)
+#define        RDC_PREF_DATA                           (RDC_BASE_ADDR + 0x108)
+#define        RDC_SHADOW_CMD                          (RDC_BASE_ADDR + 0x110)
+#define        RDC_SHADOW_DATA                         (RDC_BASE_ADDR + 0x118)
+#define        RDC_SHADOW_PAR_DATA                     (RDC_BASE_ADDR + 0x120)
+#define        RDC_CTRL_FIFO_CMD                       (RDC_BASE_ADDR + 0x128)
+#define        RDC_CTRL_FIFO_DATA_LO                   (RDC_BASE_ADDR + 0x130)
+#define        RDC_CTRL_FIFO_DATA_HI                   (RDC_BASE_ADDR + 0x138)
+#define        RDC_CTRL_FIFO_DATA_ECC                  (RDC_BASE_ADDR + 0x140)
+#define        RDC_DATA_FIFO_CMD                       (RDC_BASE_ADDR + 0x148)
+#define        RDC_DATA_FIFO_DATA_LO                   (RDC_BASE_ADDR + 0x150)
+#define        RDC_DATA_FIFO_DATA_HI                   (RDC_BASE_ADDR + 0x158)
+#define        RDC_DATA_FIFO_DATA_ECC                  (RDC_BASE_ADDR + 0x160)
+#define        RDC_STAT_INT_DBG                        (RDC_BASE_ADDR + 0x200)
+#define        RDC_PREF_PAR_LOG                        (RDC_BASE_ADDR + 0x210)
+#define        RDC_SHADOW_PAR_LOG                      (RDC_BASE_ADDR + 0x218)
+#define        RDC_CTRL_FIFO_ECC_LOG                   (RDC_BASE_ADDR + 0x220)
+#define        RDC_DATA_FIFO_ECC_LOG                   (RDC_BASE_ADDR + 0x228)
+#define        RDC_FIFO_ERR_MASK                       (RDC_BASE_ADDR + 0x230)
+#define        RDC_FIFO_ERR_STAT                       (RDC_BASE_ADDR + 0x238)
+#define        RDC_FIFO_ERR_INT_DBG                    (RDC_BASE_ADDR + 0x240)
+#define        RDC_PEU_TXN_LOG                         (RDC_BASE_ADDR + 0x250)
+#define        RDC_DBG_TRAINING_VEC                    (RDC_BASE_ADDR + 0x300)
+#define        RDC_DBG_GRP_SEL                         (RDC_BASE_ADDR + 0x308)
+
+
+/*
+ * Register: RdcPageHandle
+ * Logical Page Handle
+ * Description: Logical page handle specifying upper bits of 64-bit
+ * PCIE addresses. Fields in this register are part of the dma
+ * configuration and cannot be changed once the dma is enabled.
+ * Fields:
+ *     Bits [63:44] of a 64-bit address, used to concatenate to a
+ *     44-bit address when generating 64-bit addresses on the PCIE
+ *     bus.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:44;
+               uint64_t        handle:20;
+#else
+               uint64_t        handle:20;
+               uint64_t        rsrvd:44;
+#endif
+       } bits;
+} rdc_page_handle_t;
+
+
+/*
+ * Register: RdcRxCfg1
+ * DMA Configuration 1
+ * Description: Configuration parameters for receive DMA block.
+ * Fields in this register are part of the dma configuration and
+ * cannot be changed once the dma is enabled.
+ * The usage of enable, reset, and qst is as follows. Software
+ * should use the following sequence to reset a DMA channel. First,
+ * set DMA.enable to 0, wait for DMA.qst=1 and then, set DMA.reset to
+ * 1. After DMA.reset is cleared by hardware and the DMA.qst is set
+ * to 1, software may then start configuring the DMA channel. The
+ * DMA.enable can be set or cleared while the DMA is in operation.
+ * The state machines of the DMA may not have returned to its initial
+ * states yet after the DMA.enable bit is cleared. This condition is
+ * indicated by the value of the DMA.qst. An example of DMA.enable
+ * being cleared during operation is when a fatal error occurs.
+ * Fields:
+ *     Set to 1 to enable the Receive DMA. If set to 0, packets
+ *     selecting this DMA will be discarded. On fatal errors, this
+ *     bit will be cleared by hardware. This bit cannot be set if sw
+ *     has not resolved any pending fatal error condition: i.e. any
+ *     RdcStat ldf1 error bits remain set.
+ *     Set to 1 to reset the DMA. Hardware will clear this bit after
+ *     reset is completed. A reset will bring the sepecific DMA back
+ *     to the power on state (including the DMA.en in this register).
+ *     When set to 1, it indicates all state associated with the DMA
+ *     are in its initial state following either dma reset or
+ *     disable. Thus, once this is set to 1, sw could start to
+ *     configure the DMA if needed.
+ *     Bits [43:32] of the Mailbox address.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        enable:1;
+               uint64_t        reset:1;
+               uint64_t        qst:1;
+               uint64_t        rsrvd1:17;
+               uint64_t        mbaddr_h:12;
+#else
+               uint64_t        mbaddr_h:12;
+               uint64_t        rsrvd1:17;
+               uint64_t        qst:1;
+               uint64_t        reset:1;
+               uint64_t        enable:1;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} rdc_rx_cfg1_t;
+
+
+/*
+ * Register: RdcRxCfg2
+ * DMA Configuration 2
+ * Description: Configuration parameters for receive DMA block.
+ * Fields in this register are part of the dma configuration and
+ * cannot be changed once the dma is enabled.
+ * Fields:
+ *     Bits [31:6] of the Mailbox address. Bits [5:0] are assumed to
+ *     be zero, or 64B aligned.
+ *     Multiple of 64Bs, 0 means no offset, b01 means 64B, b10 means
+ *     128B. b11 is invalid, hardware behavior not specified.
+ *     Set to 1 to select the entire header of 6B.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        mbaddr_l:26;
+               uint64_t        rsrvd1:3;
+               uint64_t        offset:2;
+               uint64_t        full_hdr:1;
+#else
+               uint64_t        full_hdr:1;
+               uint64_t        offset:2;
+               uint64_t        rsrvd1:3;
+               uint64_t        mbaddr_l:26;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} rdc_rx_cfg2_t;
+
+
+/*
+ * Register: RdcRbrCfgA
+ * RBR Configuration A
+ * Description: The following registers are used to configure and
+ * manage the RBR. Note that the entire RBR must stay within the
+ * 'page' defined by staddrBase. The behavior of the hardware is
+ * undefined if the last entry is outside of the page (if bits 43:18
+ * of the address of the last entry are different from bits 43:18 of
+ * the base address). Hardware will support wrapping around at the
+ * end of the ring buffer defined by LEN. LEN must be a multiple of
+ * 64. Fields in this register are part of the dma configuration and
+ * cannot be changed once the dma is enabled.
+ * HW does not check for all configuration errors across different
+ * fields.
+ *
+ * Fields:
+ *     Bits 15:6 of the maximum number of RBBs in the buffer ring.
+ *     Bits 5:0 are hardcoded to zero. The maximum is (2^16 - 64) and
+ *     is limited by the staddr value. (len + staddr) should not
+ *     exceed (2^16 - 64).
+ *     Bits [43:18] of the address for the RBR. This value remains
+ *     fixed, and is used as the base address of the ring. All
+ *     entries in the ring have this as their upper address bits.
+ *     Bits [17:6] of the address of the RBR. staddrBase concatinated
+ *     with staddr is the starting address of the RBR. (len + staddr)
+ *     should not exceed (2^16 - 64).
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        len:10;
+               uint64_t        len_lo:6;
+               uint64_t        rsrvd:4;
+               uint64_t        staddr_base:26;
+               uint64_t        staddr:12;
+               uint64_t        rsrvd1:6;
+#else
+               uint64_t        rsrvd1:6;
+               uint64_t        staddr:12;
+               uint64_t        staddr_base:26;
+               uint64_t        rsrvd:4;
+               uint64_t        len_lo:6;
+               uint64_t        len:10;
+#endif
+       } bits;
+} rdc_rbr_cfg_a_t;
+
+
+/*
+ * Register: RdcRbrCfgB
+ * RBR Configuration B
+ * Description: This register configures the block size, and the
+ * individual packet buffer sizes. The VLD bits of the three block
+ * sizes have to be set to 1 in normal operations. These bits may be
+ * turned off for debug purpose only. Fields in this register are
+ * part of the dma configuration and cannot be changed once the dma
+ * is enabled.
+ * Fields:
+ *     Buffer Block Size. b0 - 4K; b1 - 8K.
+ *     Set to 1 to indicate SIZE2 is valid, and enable hardware to
+ *     allocate buffers of size 2. Always set to 1 in normal
+ *     operation.
+ *     Size 2 of packet buffer. b0 - 2K; b1 - 4K.
+ *     Set to 1 to indicate SIZE1 is valid, and enable hardware to
+ *     allocate buffers of size 1. Always set to 1 in normal
+ *     operation.
+ *     Size 1 of packet buffer. b0 - 1K; b1 - 2K.
+ *     Set to 1 to indicate SIZE0 is valid, and enable hardware to
+ *     allocate buffers of size 0. Always set to 1 in normal
+ *     operation.
+ *     Size 0 of packet buffer. b00 - 256; b01 - 512; b10 - 1K; b11 -
+ *     reserved.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:39;
+               uint64_t        bksize:1;
+               uint64_t        vld2:1;
+               uint64_t        rsrvd1:6;
+               uint64_t        bufsz2:1;
+               uint64_t        vld1:1;
+               uint64_t        rsrvd2:6;
+               uint64_t        bufsz1:1;
+               uint64_t        vld0:1;
+               uint64_t        rsrvd3:5;
+               uint64_t        bufsz0:2;
+#else
+               uint64_t        bufsz0:2;
+               uint64_t        rsrvd3:5;
+               uint64_t        vld0:1;
+               uint64_t        bufsz1:1;
+               uint64_t        rsrvd2:6;
+               uint64_t        vld1:1;
+               uint64_t        bufsz2:1;
+               uint64_t        rsrvd1:6;
+               uint64_t        vld2:1;
+               uint64_t        bksize:1;
+               uint64_t        rsrvd:39;
+#endif
+       } bits;
+} rdc_rbr_cfg_b_t;
+
+
+/*
+ * Register: RdcRbrKick
+ * RBR Kick
+ * Description: Block buffer addresses are added to the ring buffer
+ * by software. When software writes to the Kick register, indicating
+ * the number of descriptors added, hardware will update the internal
+ * state of the corresponding buffer pool.
+ * HW does not check for all configuration errors across different
+ * fields.
+ *
+ * Fields:
+ *     Number of Block Buffers added by software. Hardware effect
+ *     will be triggered when the register is written to.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:48;
+               uint64_t        bkadd:16;
+#else
+               uint64_t        bkadd:16;
+               uint64_t        rsrvd:48;
+#endif
+       } bits;
+} rdc_rbr_kick_t;
+
+
+/*
+ * Register: RdcRbrQlen
+ * RBR Queue Length
+ * Description: The current number of entries in the RBR.
+ * Fields:
+ *     Number of block addresses in the ring buffer.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:48;
+               uint64_t        qlen:16;
+#else
+               uint64_t        qlen:16;
+               uint64_t        rsrvd:48;
+#endif
+       } bits;
+} rdc_rbr_qlen_t;
+
+
+/*
+ * Register: RdcRbrHead
+ * RBR Head
+ * Description: Lower bits of the RBR head pointer. Software programs
+ * the upper bits, specified in rdcRbrConfigA.staddrBase.
+ * Fields:
+ *     Bits [17:2] of the software posted address, 4B aligned. This
+ *     pointer is updated by hardware after each block buffer is
+ *     consumed.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:46;
+               uint64_t        head:16;
+               uint64_t        rsrvd1:2;
+#else
+               uint64_t        rsrvd1:2;
+               uint64_t        head:16;
+               uint64_t        rsrvd:46;
+#endif
+       } bits;
+} rdc_rbr_head_t;
+
+
+/*
+ * Register: RdcRcrCfgA
+ * RCR Configuration A
+ * Description: The RCR should be within the 'page' defined by the
+ * staddrBase, i.e. staddrBase concatenate with STADDR plus 8 x LEN
+ * should be within the last address of the 'page' defined by
+ * staddrBase. The length must be a multiple of 32. Fields in this
+ * register are part of the dma configuration and cannot be changed
+ * once the dma is enabled.
+ * HW does not check for all configuration errors across different
+ * fields.
+ *
+ * Fields:
+ *     Bits 15:5 of the maximum number of 8B entries in RCR. Bits 4:0
+ *     are hard-coded to zero. The maximum size is (2^16 - 32) and is
+ *     limited by staddr value. (len + staddr) should not exceed
+ *     (2^16 - 32).
+ *     Bits [43:19] of the Start address for the RCR.
+ *     Bits [18:6] of start address for the RCR. (len + staddr)
+ *     should not exceed (2^16 - 32).
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        len:11;
+               uint64_t        len_lo:5;
+               uint64_t        rsrvd:4;
+               uint64_t        staddr_base:25;
+               uint64_t        staddr:13;
+               uint64_t        rsrvd1:6;
+#else
+               uint64_t        rsrvd1:6;
+               uint64_t        staddr:13;
+               uint64_t        staddr_base:25;
+               uint64_t        rsrvd:4;
+               uint64_t        len_lo:5;
+               uint64_t        len:11;
+#endif
+       } bits;
+} rdc_rcr_cfg_a_t;
+
+
+/*
+ * Register: RdcRcrCfgB
+ * RCR Configuration B
+ * Description: RCR configuration settings.
+ * Fields:
+ *     Packet Threshold; when the number of packets enqueued in RCR
+ *     is strictly larger than PTHRES, the DMA MAY issue an interrupt
+ *     if enabled.
+ *     Enable timeout. If set to one, enable the timeout. A timeout
+ *     will initiate an update of the software visible states. If
+ *     interrupt is armed, in addition to the update, an interrupt to
+ *     CPU will be generated, and the interrupt disarmed.
+ *     Time out value. The system clock is divided down by the value
+ *     programmed in the Receive DMA Clock Divider register.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        pthres:16;
+               uint64_t        entout:1;
+               uint64_t        rsrvd1:9;
+               uint64_t        timeout:6;
+#else
+               uint64_t        timeout:6;
+               uint64_t        rsrvd1:9;
+               uint64_t        entout:1;
+               uint64_t        pthres:16;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} rdc_rcr_cfg_b_t;
+
+
+/*
+ * Register: RdcRcrQlen
+ * RCR Queue Length
+ * Description: The number of entries in the RCR.
+ * Fields:
+ *     Number of packets queued. Initialize to zero after the RCR
+ *     Configuration A register is written to.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:48;
+               uint64_t        qlen:16;
+#else
+               uint64_t        qlen:16;
+               uint64_t        rsrvd:48;
+#endif
+       } bits;
+} rdc_rcr_qlen_t;
+
+
+/*
+ * Register: RdcRcrTail
+ * RCR Tail
+ * Description: Lower bits of the RCR tail pointer. Software programs
+ * the upper bits, specified in rdcRcrConfigA.staddrBase.
+ * Fields:
+ *     Address of the RCR Tail Pointer [18:3] (points to the next
+ *     available location.) Initialized after the RCR Configuration A
+ *     register is written to.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:45;
+               uint64_t        tail:16;
+               uint64_t        rsrvd1:3;
+#else
+               uint64_t        rsrvd1:3;
+               uint64_t        tail:16;
+               uint64_t        rsrvd:45;
+#endif
+       } bits;
+} rdc_rcr_tail_t;
+
+
+/*
+ * Register: RdcRcrFlush
+ * RCR Flush
+ * Description: This register will force an update to the RCR in
+ * system memory.
+ * Fields:
+ *     Set to 1 to force the hardware to store the shadow tail block
+ *     to DRAM if the hardware state (queue length and pointers) is
+ *     different from the software visible state. Reset to 0 by
+ *     hardware when done.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:63;
+               uint64_t        flush:1;
+#else
+               uint64_t        flush:1;
+               uint64_t        rsrvd:63;
+#endif
+       } bits;
+} rdc_rcr_flush_t;
+
+
+/*
+ * Register: RdcClockDiv
+ * Receive DMA Clock Divider
+ * Description: The granularity of the DMA timers is determined by
+ * the following counter. This is used to drive the DMA timeout
+ * counters. For a 250MHz system clock, a value of 25000 (decimal)
+ * will yield a granularity of 100 usec.
+ * Fields:
+ *     System clock divider, determines the granularity of the DMA
+ *     timeout count-down. The hardware count down is count+1.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:48;
+               uint64_t        count:16;
+#else
+               uint64_t        count:16;
+               uint64_t        rsrvd:48;
+#endif
+       } bits;
+} rdc_clock_div_t;
+
+
+/*
+ * Register: RdcIntMask
+ * RDC Interrupt Mask
+ * Description: RDC interrupt status register. RCRTHRES and RCRTO
+ * bits are used to keep track of normal DMA operations, while the
+ * remaining bits are primarily used to detect error conditions.
+ * Fields:
+ *     Set to 0 to enable flagging when rdc receives a response
+ *     completion timeout from peu. Part of LDF 1.
+ *     Set to 1 to enable flagging when rdc receives a poisoned
+ *     completion or non-zero (unsuccessful) completion status
+ *     received from PEU. Part of LDF 1.
+ *     Set to 0 to enable flagging when RCR threshold crossed. Part
+ *     of LDF 0.
+ *     Set to 0 to enable flagging when RCR timeout. Part of LDF 0.
+ *     Set to 0 to enable flagging when read from rcr shadow ram
+ *     generates a parity error Part of LDF 1.
+ *     Set to 0 to enable flagging when read from rbr prefetch ram
+ *     generates a parity error Part of LDF 1.
+ *     Set to 0 to enable flagging when Receive Block Ring prefetch
+ *     is empty (not enough buffer blocks available depending on
+ *     incoming pkt size) when hardware tries to queue a packet.
+ *     Incoming packets will be discarded. Non-fatal error. Part of
+ *     LDF 1.
+ *     Set to 0 to enable flagging when packet discard because of RCR
+ *     shadow full.
+ *     Set to 0 to enable flagging when Receive Completion Ring full
+ *     when hardware tries to enqueue the completion status of a
+ *     packet. Part of LDF 1.
+ *     Set to 0 to enable flagging when RBR empty when hardware
+ *     attempts to prefetch. Part of LDF 1.
+ *     Set to 0 to enable flagging when Receive Block Ring full when
+ *     software tries to post more blocks. Part of LDF 1.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:10;
+               uint64_t        rbr_cpl_to:1;
+               uint64_t        peu_resp_err:1;
+               uint64_t        rsrvd1:5;
+               uint64_t        rcr_thres:1;
+               uint64_t        rcr_to:1;
+               uint64_t        rcr_shadow_par_err:1;
+               uint64_t        rbr_prefetch_par_err:1;
+               uint64_t        rsrvd2:2;
+               uint64_t        rbr_pre_empty:1;
+               uint64_t        rcr_shadow_full:1;
+               uint64_t        rsrvd3:2;
+               uint64_t        rcr_full:1;
+               uint64_t        rbr_empty:1;
+               uint64_t        rbr_full:1;
+               uint64_t        rsrvd4:2;
+               uint64_t        rsrvd5:32;
+#else
+               uint64_t        rsrvd5:32;
+               uint64_t        rsrvd4:2;
+               uint64_t        rbr_full:1;
+               uint64_t        rbr_empty:1;
+               uint64_t        rcr_full:1;
+               uint64_t        rsrvd3:2;
+               uint64_t        rcr_shadow_full:1;
+               uint64_t        rbr_pre_empty:1;
+               uint64_t        rsrvd2:2;
+               uint64_t        rbr_prefetch_par_err:1;
+               uint64_t        rcr_shadow_par_err:1;
+               uint64_t        rcr_to:1;
+               uint64_t        rcr_thres:1;
+               uint64_t        rsrvd1:5;
+               uint64_t        peu_resp_err:1;
+               uint64_t        rbr_cpl_to:1;
+               uint64_t        rsrvd:10;
+#endif
+       } bits;
+} rdc_int_mask_t;
+
+
+/*
+ * Register: RdcStat
+ * RDC Control And Status
+ * Description: The DMA channels are controlled using this register.
+ * Fields:
+ *     Set to 1 to indicate rdc received a response completion
+ *     timeout from peu. Fatal error. Part of LDF 1.
+ *     Set to 1 to indicate poisoned completion or non-zero
+ *     (unsuccessful) completion status received from PEU. Part of
+ *     LDF 1.
+ *     Set to 1 to enable mailbox update. Hardware will reset to 0
+ *     after one update. Software needs to set to 1 for each update.
+ *     Write 0 has no effect. Note that once set by software, only
+ *     hardware can reset the value. This bit is also used to keep
+ *     track of the exclusivity between threshold triggered or
+ *     timeout triggered interrupt. If this bit is not set, there
+ *     will be no timer based interrupt, and threshold based
+ *     interrupt will not issue a mailbox update. It is recommended
+ *     that software should set this bit to one when arming the
+ *     device for interrupt.
+ *     Set to 1 to indicate RCR threshold crossed. This is a level
+ *     event. Part of LDF 0.
+ *     Set to 1 to indicate RCR time-outed if MEX bit is set and the
+ *     queue length is non-zero when timeout occurs. When software
+ *     writes 1 to this bit, RCRTO will be reset to 0. Part of LDF 0.
+ *     Set to 1 to indicate read from rcr shadow ram generates a
+ *     parity error Writing a 1 to this register also clears the
+ *     rdcshadowParLog register Fatal error. Part of LDF 1.
+ *     Set to 1 to indicate read from rbr prefetch ram generates
+ *     parity error Writing a 1 to this register also clears the
+ *     rdcPrefParLog register Fatal error. Part of LDF 1.
+ *     Set to 1 to indicate Receive Block Ring prefetch is empty (not
+ *     enough buffer blocks available depending on incoming pkt size)
+ *     when hardware tries to queue a packet. Incoming packets will
+ *     be discarded. Non-fatal error. Part of LDF 1.
+ *     Set to 1 to indicate packet discard because of RCR shadow
+ *     full. RCR Shadow full cannot be set to 1 in a normal
+ *     operation. When set to 1, it indicates a fatal error. Part of
+ *     LDF 1.
+ *     Set to 1 to indicate Receive Completion Ring full when
+ *     hardware tries to enqueue the completion status of a packet.
+ *     Incoming packets will be discarded. No buffer consumed. Fatal
+ *     error. Part of LDF 1.
+ *     Set to 1 to indicate RBR empty when hardware attempts to
+ *     prefetch. Part of LDF 1.
+ *     Set to 1 to indicate Receive Buffer Ring full when software
+ *     writes the kick register with a value greater than the length
+ *     of the RBR length. Incoming packets will be discarded. Fatal
+ *     error. Part of LDF 1.
+ *     Number of buffer pointers read. Used to advance the RCR head
+ *     pointer.
+ *     Number of packets read; when written to, decrement the QLEN
+ *     counter by PKTREAD. QLEN is lower bounded to zero.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:10;
+               uint64_t        rbr_cpl_to:1;
+               uint64_t        peu_resp_err:1;
+               uint64_t        rsrvd1:4;
+               uint64_t        mex:1;
+               uint64_t        rcr_thres:1;
+               uint64_t        rcr_to:1;
+               uint64_t        rcr_shadow_par_err:1;
+               uint64_t        rbr_prefetch_par_err:1;
+               uint64_t        rsrvd2:2;
+               uint64_t        rbr_pre_empty:1;
+               uint64_t        rcr_shadow_full:1;
+               uint64_t        rsrvd3:2;
+               uint64_t        rcr_full:1;
+               uint64_t        rbr_empty:1;
+               uint64_t        rbr_full:1;
+               uint64_t        rsrvd4:2;
+               uint64_t        ptrread:16;
+               uint64_t        pktread:16;
+#else
+               uint64_t        pktread:16;
+               uint64_t        ptrread:16;
+               uint64_t        rsrvd4:2;
+               uint64_t        rbr_full:1;
+               uint64_t        rbr_empty:1;
+               uint64_t        rcr_full:1;
+               uint64_t        rsrvd3:2;
+               uint64_t        rcr_shadow_full:1;
+               uint64_t        rbr_pre_empty:1;
+               uint64_t        rsrvd2:2;
+               uint64_t        rbr_prefetch_par_err:1;
+               uint64_t        rcr_shadow_par_err:1;
+               uint64_t        rcr_to:1;
+               uint64_t        rcr_thres:1;
+               uint64_t        mex:1;
+               uint64_t        rsrvd1:4;
+               uint64_t        peu_resp_err:1;
+               uint64_t        rbr_cpl_to:1;
+               uint64_t        rsrvd:10;
+#endif
+       } bits;
+} rdc_stat_t;
+
+
+/*
+ * Register: RdcPktCount
+ * Rx DMA Packet Counter
+ * Description: Counts the number of packets received from the Rx
+ * Virtual MAC for this DMA channel.
+ * Fields:
+ *     Count of SYN packets received from RVM. This counter
+ *     saturates.
+ *     Count of packets received from RVM. This counter saturates.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        syn_pkt_count:32;
+               uint64_t        pkt_count:32;
+#else
+               uint64_t        pkt_count:32;
+               uint64_t        syn_pkt_count:32;
+#endif
+       } bits;
+} rdc_pkt_count_t;
+
+
+/*
+ * Register: RdcDropCount
+ * Rx DMA Dropped Packet Counters
+ * Description: Counts the number of packets dropped due to different
+ * types of errors.
+ * Fields:
+ *     Count of packets dropped because they were longer than the
+ *     maximum length. This counter saturates.
+ *     Count of packets dropped because there was no block available
+ *     in the RBR Prefetch Buffer. This counter saturates.
+ *     Count of packets dropped because the RVM marked the packet as
+ *     errored. This counter saturates.
+ *     Count of packets dropped because there was a framing error
+ *     from the RVM. This counter saturates.
+ *     Count of packets dropped because the packet did not fit in the
+ *     rx ram. This counter saturates.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:16;
+               uint64_t        too_long:8;
+               uint64_t        no_rbr_avail:8;
+               uint64_t        rvm_error:8;
+               uint64_t        frame_error:8;
+               uint64_t        rxram_error:8;
+               uint64_t        rsrvd1:8;
+#else
+               uint64_t        rsrvd1:8;
+               uint64_t        rxram_error:8;
+               uint64_t        frame_error:8;
+               uint64_t        rvm_error:8;
+               uint64_t        no_rbr_avail:8;
+               uint64_t        too_long:8;
+               uint64_t        rsrvd:16;
+#endif
+       } bits;
+} rdc_drop_count_t;
+
+
+/*
+ * Register: RdcByteCount
+ * Rx DMA Byte Counter
+ * Description: Counts the number of bytes transferred by dma for all
+ * channels.
+ * Fields:
+ *     Count of bytes transferred by dma. This counter saturates.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        count:32;
+#else
+               uint64_t        count:32;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} rdc_byte_count_t;
+
+
+/*
+ * Register: RdcPrefCmd
+ * Rx DMA Prefetch Buffer Command
+ * Description: Allows debug access to the entire prefetch buffer,
+ * along with the rdcPrefData register. Writing the rdcPrefCmd
+ * triggers the access. For writes, software writes the 32 bits of
+ * data to the rdcPrefData register before writing the write command
+ * to this register. For reads, software first writes the the read
+ * command to this register, then reads the 32-bit value from the
+ * rdcPrefData register. The status field should be polled by
+ * software until it goes low, indicating the read or write has
+ * completed.
+ * Fields:
+ *     status of indirect access 0=busy 1=done
+ *     Command type. 1 indicates a read command, 0 a write command.
+ *     enable writing of parity bits 1=enabled, 0=disabled
+ *     DMA channel of entry to read or write
+ *     Entry in the prefetch buffer to read or write
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        status:1;
+               uint64_t        cmd:1;
+               uint64_t        par_en:1;
+               uint64_t        rsrvd1:22;
+               uint64_t        dmc:2;
+               uint64_t        entry:5;
+#else
+               uint64_t        entry:5;
+               uint64_t        dmc:2;
+               uint64_t        rsrvd1:22;
+               uint64_t        par_en:1;
+               uint64_t        cmd:1;
+               uint64_t        status:1;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} rdc_pref_cmd_t;
+
+
+/*
+ * Register: RdcPrefData
+ * Rx DMA Prefetch Buffer Data
+ * Description: See rdcPrefCmd register.
+ * Fields:
+ *     For writes, parity bits is written into prefetch buffer. For
+ *     reads, parity bits read from the prefetch buffer.
+ *     For writes, data which is written into prefetch buffer. For
+ *     reads, data read from the prefetch buffer.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:28;
+               uint64_t        par:4;
+               uint64_t        data:32;
+#else
+               uint64_t        data:32;
+               uint64_t        par:4;
+               uint64_t        rsrvd:28;
+#endif
+       } bits;
+} rdc_pref_data_t;
+
+
+/*
+ * Register: RdcShadowCmd
+ * Rx DMA Shadow Tail Command
+ * Description: Allows debug access to the entire shadow tail, along
+ * with the rdcShadowData register. Writing the rdcShadowCmd triggers
+ * the access. For writes, software writes the 64 bits of data to the
+ * rdcShadowData register before writing the write command to this
+ * register. For reads, software first writes the the read command to
+ * this register, then reads the 64-bit value from the rdcShadowData
+ * register. The valid field should be polled by software until it
+ * goes low, indicating the read or write has completed.
+ * Fields:
+ *     status of indirect access 0=busy 1=done
+ *     Command type. 1 indicates a read command, 0 a write command.
+ *     enable writing of parity bits 1=enabled, 0=disabled
+ *     DMA channel of entry to read or write
+ *     Entry in the shadow tail to read or write
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        status:1;
+               uint64_t        cmd:1;
+               uint64_t        par_en:1;
+               uint64_t        rsrvd1:23;
+               uint64_t        dmc:2;
+               uint64_t        entry:4;
+#else
+               uint64_t        entry:4;
+               uint64_t        dmc:2;
+               uint64_t        rsrvd1:23;
+               uint64_t        par_en:1;
+               uint64_t        cmd:1;
+               uint64_t        status:1;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} rdc_shadow_cmd_t;
+
+
+/*
+ * Register: RdcShadowData
+ * Rx DMA Shadow Tail Data
+ * Description: See rdcShadowCmd register.
+ * Fields:
+ *     For writes, data which is written into shadow tail. For reads,
+ *     data read from the shadow tail.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        data:64;
+#else
+               uint64_t        data:64;
+#endif
+       } bits;
+} rdc_shadow_data_t;
+
+
+/*
+ * Register: RdcShadowParData
+ * Rx DMA Shadow Tail Parity Data
+ * Description: See rdcShadowCmd register.
+ * Fields:
+ *     For writes, parity data is written into shadow tail. For
+ *     reads, parity data read from the shadow tail.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rsrvd1:24;
+               uint64_t        parity_data:8;
+#else
+               uint64_t        parity_data:8;
+               uint64_t        rsrvd1:24;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} rdc_shadow_par_data_t;
+
+
+/*
+ * Register: RdcCtrlFifoCmd
+ * Rx DMA Control Fifo Command
+ * Description: Allows debug access to the entire Rx Ctl FIFO, along
+ * with the rdcCtrlFifoData register. Writing the rdcCtrlFifoCmd
+ * triggers the access. For writes, software writes the 128 bits of
+ * data to the rdcCtrlFifoData registers before writing the write
+ * command to this register. For reads, software first writes the the
+ * read command to this register, then reads the 128-bit value from
+ * the rdcCtrlFifoData registers. The valid field should be polled by
+ * software until it goes low, indicating the read or write has
+ * completed.
+ * Fields:
+ *     status of indirect access 0=busy 1=done
+ *     Command type. 1 indicates a read command, 0 a write command.
+ *     enable writing of ECC bits 1=enabled, 0=disabled
+ *     Entry in the rx control ram to read or write
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        status:1;
+               uint64_t        cmd:1;
+               uint64_t        ecc_en:1;
+               uint64_t        rsrvd1:20;
+               uint64_t        entry:9;
+#else
+               uint64_t        entry:9;
+               uint64_t        rsrvd1:20;
+               uint64_t        ecc_en:1;
+               uint64_t        cmd:1;
+               uint64_t        status:1;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} rdc_ctrl_fifo_cmd_t;
+
+
+/*
+ * Register: RdcCtrlFifoDataLo
+ * Rx DMA Control Fifo Data Lo
+ * Description: Lower 64 bits read or written to the Rx Ctl FIFO. See
+ * rdcCtrlFifoCmd register.
+ * Fields:
+ *     For writes, data which is written into rx control ram. For
+ *     reads, data read from the rx control ram.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        data:64;
+#else
+               uint64_t        data:64;
+#endif
+       } bits;
+} rdc_ctrl_fifo_data_lo_t;
+
+
+/*
+ * Register: RdcCtrlFifoDataHi
+ * Rx DMA Control Fifo Data Hi
+ * Description: Upper 64 bits read or written to the Rx Ctl FIFO. See
+ * rdcCtrlFifoCmd register.
+ * Fields:
+ *     For writes, data which is written into rx control ram. For
+ *     reads, data read from the rx control ram.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        data:64;
+#else
+               uint64_t        data:64;
+#endif
+       } bits;
+} rdc_ctrl_fifo_data_hi_t;
+
+
+/*
+ * Register: RdcCtrlFifoDataEcc
+ * Rx DMA Control Fifo Data ECC
+ * Description: 16 bits ECC data read or written to the Rx Ctl FIFO.
+ * See rdcCtrlFifoCmd register.
+ * Fields:
+ *     For writes, data which is written into rx control ram. For
+ *     reads, data read from the rx control ram.
+ *     For writes, data which is written into rx control ram. For
+ *     reads, data read from the rx control ram.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rsrvd1:16;
+               uint64_t        ecc_data_hi:8;
+               uint64_t        ecc_data_lo:8;
+#else
+               uint64_t        ecc_data_lo:8;
+               uint64_t        ecc_data_hi:8;
+               uint64_t        rsrvd1:16;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} rdc_ctrl_fifo_data_ecc_t;
+
+
+/*
+ * Register: RdcDataFifoCmd
+ * Rx DMA Data Fifo Command
+ * Description: Allows debug access to the entire Rx Data FIFO, along
+ * with the rdcDataFifoData register. Writing the rdcCtrlFifoCmd
+ * triggers the access. For writes, software writes the 128 bits of
+ * data to the rdcDataFifoData registers before writing the write
+ * command to this register. For reads, software first writes the the
+ * read command to this register, then reads the 128-bit value from
+ * the rdcDataFifoData registers. The valid field should be polled by
+ * software until it goes low, indicating the read or write has
+ * completed.
+ * Fields:
+ *     status of indirect access 0=busy 1=done
+ *     Command type. 1 indicates a read command, 0 a write command.
+ *     enable writing of ECC bits 1=enabled, 0=disabled
+ *     Entry in the rx data ram to read or write
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        status:1;
+               uint64_t        cmd:1;
+               uint64_t        ecc_en:1;
+               uint64_t        rsrvd1:18;
+               uint64_t        entry:11;
+#else
+               uint64_t        entry:11;
+               uint64_t        rsrvd1:18;
+               uint64_t        ecc_en:1;
+               uint64_t        cmd:1;
+               uint64_t        status:1;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} rdc_data_fifo_cmd_t;
+
+
+/*
+ * Register: RdcDataFifoDataLo
+ * Rx DMA Data Fifo Data Lo
+ * Description: Lower 64 bits read or written to the Rx Data FIFO.
+ * See rdcDataFifoCmd register.
+ * Fields:
+ *     For writes, data which is written into rx data ram. For reads,
+ *     data read from the rx data ram.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        data:64;
+#else
+               uint64_t        data:64;
+#endif
+       } bits;
+} rdc_data_fifo_data_lo_t;
+
+
+/*
+ * Register: RdcDataFifoDataHi
+ * Rx DMA Data Fifo Data Hi
+ * Description: Upper 64 bits read or written to the Rx Data FIFO.
+ * See rdcDataFifoCmd register.
+ * Fields:
+ *     For writes, data which is written into rx data ram. For reads,
+ *     data read from the rx data ram.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        data:64;
+#else
+               uint64_t        data:64;
+#endif
+       } bits;
+} rdc_data_fifo_data_hi_t;
+
+
+/*
+ * Register: RdcDataFifoDataEcc
+ * Rx DMA Data Fifo ECC Data
+ * Description: 16 bits ECC data read or written to the Rx Data FIFO.
+ * See rdcDataFifoCmd register.
+ * Fields:
+ *     For writes, data which is written into rx data ram. For reads,
+ *     data read from the rx data ram.
+ *     For writes, data which is written into rx data ram. For reads,
+ *     data read from the rx data ram.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rsrvd1:16;
+               uint64_t        ecc_data_hi:8;
+               uint64_t        ecc_data_lo:8;
+#else
+               uint64_t        ecc_data_lo:8;
+               uint64_t        ecc_data_hi:8;
+               uint64_t        rsrvd1:16;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} rdc_data_fifo_data_ecc_t;
+
+
+/*
+ * Register: RdcStatIntDbg
+ * RDC Debug Control and Status Interrupt
+ * Description: RDC debug control and status interrupt register.
+ * Debug RDC control and status register bits to check if interrupt
+ * is asserted used to detect error conditions.
+ * Fields:
+ *     Set to 1 to enable interrupt Part of LDF 1.
+ *     Set to 1 to enable interrupt Part of LDF 1.
+ *     Set to 1 to enable interrupt Part of LDF 0.
+ *     Set to 1 to enable interrupt Part of LDF 0.
+ *     Set to 1 to enable interrupt Part of LDF 1.
+ *     Set to 1 to enable interrupt Part of LDF 1.
+ *     Set to 1 to enable interrupt Part of LDF 1.
+ *     Set to 1 to enable interrupt
+ *     Set to 1 to enable interrupt Part of LDF 1.
+ *     Set to 1 to enable interrupt Part of LDF 1.
+ *     Set to 1 to enable interrupt Part of LDF 1.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:10;
+               uint64_t        rbr_cpl_to:1;
+               uint64_t        peu_resp_err:1;
+               uint64_t        rsrvd1:5;
+               uint64_t        rcr_thres:1;
+               uint64_t        rcr_to:1;
+               uint64_t        rcr_shadow_par_err:1;
+               uint64_t        rbr_prefetch_par_err:1;
+               uint64_t        rsrvd2:2;
+               uint64_t        rbr_pre_empty:1;
+               uint64_t        rcr_shadow_full:1;
+               uint64_t        rsrvd3:2;
+               uint64_t        rcr_full:1;
+               uint64_t        rbr_empty:1;
+               uint64_t        rbr_full:1;
+               uint64_t        rsrvd4:2;
+               uint64_t        rsrvd5:32;
+#else
+               uint64_t        rsrvd5:32;
+               uint64_t        rsrvd4:2;
+               uint64_t        rbr_full:1;
+               uint64_t        rbr_empty:1;
+               uint64_t        rcr_full:1;
+               uint64_t        rsrvd3:2;
+               uint64_t        rcr_shadow_full:1;
+               uint64_t        rbr_pre_empty:1;
+               uint64_t        rsrvd2:2;
+               uint64_t        rbr_prefetch_par_err:1;
+               uint64_t        rcr_shadow_par_err:1;
+               uint64_t        rcr_to:1;
+               uint64_t        rcr_thres:1;
+               uint64_t        rsrvd1:5;
+               uint64_t        peu_resp_err:1;
+               uint64_t        rbr_cpl_to:1;
+               uint64_t        rsrvd:10;
+#endif
+       } bits;
+} rdc_stat_int_dbg_t;
+
+
+/*
+ * Register: RdcPrefParLog
+ * Rx DMA Prefetch Buffer Parity Log
+ * Description: RDC DMA Prefetch Buffer parity log register This
+ * register logs the first parity error that is encountered. Writing
+ * a 1 to RdcStat::rbrPrefetchParErr clears this register
+ * Fields:
+ *     Address of parity error
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:57;
+               uint64_t        address:7;
+#else
+               uint64_t        address:7;
+               uint64_t        rsrvd:57;
+#endif
+       } bits;
+} rdc_pref_par_log_t;
+
+
+/*
+ * Register: RdcShadowParLog
+ * Rx DMA Shadow Tail Parity Log
+ * Description: RDC DMA Shadow Tail parity log register This register
+ * logs the first parity error that is encountered. Writing a 1 to
+ * RdcStat::rcrShadowParErr clears this register
+ * Fields:
+ *     Address of parity error
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rsrvd1:26;
+               uint64_t        address:6;
+#else
+               uint64_t        address:6;
+               uint64_t        rsrvd1:26;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} rdc_shadow_par_log_t;
+
+
+/*
+ * Register: RdcCtrlFifoEccLog
+ * Rx DMA Control Fifo ECC Log
+ * Description: RDC DMA Control FIFO ECC log register This register
+ * logs the first ECC error that is encountered. A double-bit ecc
+ * error over writes any single-bit ecc error previously logged
+ * Fields:
+ *     Address of ECC error for upper 64 bits Writing a 1 to
+ *     RdcFifoErrStat::rxCtrlFifoDed[1] or
+ *     RdcFifoErrStat::rxCtrlFifoSec[1] clears this register
+ *     Address of ECC error for lower 64 bits Writing a 1 to
+ *     RdcFifoErrStat::rxCtrlFifoDed[0] or
+ *     RdcFifoErrStat::rxCtrlFifoSec[0] clears this register
+ *     ECC syndrome for upper 64 bits Writing a 1 to
+ *     RdcFifoErrStat::rxCtrlFifoDed[1] or
+ *     RdcFifoErrStat::rxCtrlFifoSec[1] clears this register
+ *     ECC syndrome for lower 64 bits Writing a 1 to
+ *     RdcFifoErrStat::rxCtrlFifoDed[0] or
+ *     RdcFifoErrStat::rxCtrlFifoSec[0] clears this register
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:7;
+               uint64_t        address_hi:9;
+               uint64_t        rsrvd1:7;
+               uint64_t        address_lo:9;
+               uint64_t        rsrvd2:8;
+               uint64_t        syndrome_hi:8;
+               uint64_t        rsrvd3:8;
+               uint64_t        syndrome_lo:8;
+#else
+               uint64_t        syndrome_lo:8;
+               uint64_t        rsrvd3:8;
+               uint64_t        syndrome_hi:8;
+               uint64_t        rsrvd2:8;
+               uint64_t        address_lo:9;
+               uint64_t        rsrvd1:7;
+               uint64_t        address_hi:9;
+               uint64_t        rsrvd:7;
+#endif
+       } bits;
+} rdc_ctrl_fifo_ecc_log_t;
+
+
+/*
+ * Register: RdcDataFifoEccLog
+ * Rx DMA Data Fifo ECC Log
+ * Description: RDC DMA data FIFO ECC log register This register logs
+ * the first ECC error that is encountered. A double-bit ecc error
+ * over writes any single-bit ecc error previously logged
+ * Fields:
+ *     Address of ECC error for upper 64 bits Writing a 1 to
+ *     RdcFifoErrStat::rxDataFifoDed[1] or
+ *     RdcFifoErrStat::rxDataFifoSec[1] clears this register
+ *     Address of ECC error for lower 64 bits Writing a 1 to
+ *     RdcFifoErrStat::rxDataFifoDed[0] or
+ *     RdcFifoErrStat::rxDataFifoSec[0] clears this register
+ *     ECC syndrome for upper 64 bits Writing a 1 to
+ *     RdcFifoErrStat::rxDataFifoDed[1] or
+ *     RdcFifoErrStat::rxDataFifoSec[1] clears this register
+ *     ECC syndrome for lower 64 bits Writing a 1 to
+ *     RdcFifoErrStat::rxDataFifoDed[0] or
+ *     RdcFifoErrStat::rxDataFifoSec[0] clears this register
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:5;
+               uint64_t        address_hi:11;
+               uint64_t        rsrvd1:5;
+               uint64_t        address_lo:11;
+               uint64_t        rsrvd2:8;
+               uint64_t        syndrome_hi:8;
+               uint64_t        rsrvd3:8;
+               uint64_t        syndrome_lo:8;
+#else
+               uint64_t        syndrome_lo:8;
+               uint64_t        rsrvd3:8;
+               uint64_t        syndrome_hi:8;
+               uint64_t        rsrvd2:8;
+               uint64_t        address_lo:11;
+               uint64_t        rsrvd1:5;
+               uint64_t        address_hi:11;
+               uint64_t        rsrvd:5;
+#endif
+       } bits;
+} rdc_data_fifo_ecc_log_t;
+
+
+/*
+ * Register: RdcFifoErrMask
+ * FIFO Error Interrupt Mask
+ * Description: FIFO Error interrupt mask register. Control the
+ * interrupt assertion of FIFO Errors. see FIFO Error Status register
+ * for more description
+ * Fields:
+ *     Set to 0 to enable flagging when rx ctrl ram logs ecc single
+ *     bit error Part of Device Error 0.
+ *     Set to 0 to enable flagging when rx ctrl ram logs ecc double
+ *     bit error Part of Device Error 1.
+ *     Set to 0 to enable flagging when rx data ram logs ecc single
+ *     bit error Part of Device Error 0.
+ *     Set to 0 to enable flagging when rx data ram logs ecc double
+ *     bit error Part of Device Error 1.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rsrvd1:24;
+               uint64_t        rx_ctrl_fifo_sec:2;
+               uint64_t        rx_ctrl_fifo_ded:2;
+               uint64_t        rx_data_fifo_sec:2;
+               uint64_t        rx_data_fifo_ded:2;
+#else
+               uint64_t        rx_data_fifo_ded:2;
+               uint64_t        rx_data_fifo_sec:2;
+               uint64_t        rx_ctrl_fifo_ded:2;
+               uint64_t        rx_ctrl_fifo_sec:2;
+               uint64_t        rsrvd1:24;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} rdc_fifo_err_mask_t;
+
+
+/*
+ * Register: RdcFifoErrStat
+ * FIFO Error Status
+ * Description: FIFO Error Status register. Log status of FIFO
+ * Errors. Rx Data buffer is physically two seperate memory, each of
+ * the two error bits point to one of the memory. Each entry in the
+ * rx ctrl point to 2 buffer locations and they are read seperatly.
+ * The two error bits point to each half of the entry.
+ * Fields:
+ *     Set to 1 by HW to indicate rx control ram received a ecc
+ *     single bit error Writing a 1 to either bit clears the
+ *     RdcCtrlFifoEccLog register Non-Fatal error. Part of Device
+ *     Error 0
+ *     Set to 1 by HW to indicate rx control ram received a ecc
+ *     double bit error Writing a 1 to either bit clears the
+ *     RdcCtrlFifoEccLog register Fatal error. Part of Device Error 1
+ *     Set to 1 by HW to indicate rx data ram received a ecc single
+ *     bit error Writing a 1 to either bit clears the
+ *     RdcDataFifoEccLog register Non-Fatal error. Part of Device
+ *     Error 0
+ *     Set to 1 by HW to indicate rx data ram received a ecc double
+ *     bit error Writing a 1 to either bit clears the
+ *     RdcDataFifoEccLog register Fatal error. Part of Device Error 1
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:56;
+               uint64_t        rx_ctrl_fifo_sec:2;
+               uint64_t        rx_ctrl_fifo_ded:2;
+               uint64_t        rx_data_fifo_sec:2;
+               uint64_t        rx_data_fifo_ded:2;
+#else
+               uint64_t        rx_data_fifo_ded:2;
+               uint64_t        rx_data_fifo_sec:2;
+               uint64_t        rx_ctrl_fifo_ded:2;
+               uint64_t        rx_ctrl_fifo_sec:2;
+               uint64_t        rsrvd:56;
+#endif
+       } bits;
+} rdc_fifo_err_stat_t;
+
+
+/*
+ * Register: RdcFifoErrIntDbg
+ * FIFO Error Interrupt Debug
+ * Description: FIFO Error interrupt Debug register. Debug Control
+ * the interrupt assertion of FIFO Errors.
+ * Fields:
+ *     Set to 1 to enable interrupt Part of Device Error 0.
+ *     Set to 1 to enable interrupt Part of Device Error 1.
+ *     Set to 1 to enable interrupt Part of Device Error 0.
+ *     Set to 1 to enable interrupt Part of Device Error 1.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rsrvd1:24;
+               uint64_t        rx_ctrl_fifo_sec:2;
+               uint64_t        rx_ctrl_fifo_ded:2;
+               uint64_t        rx_data_fifo_sec:2;
+               uint64_t        rx_data_fifo_ded:2;
+#else
+               uint64_t        rx_data_fifo_ded:2;
+               uint64_t        rx_data_fifo_sec:2;
+               uint64_t        rx_ctrl_fifo_ded:2;
+               uint64_t        rx_ctrl_fifo_sec:2;
+               uint64_t        rsrvd1:24;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} rdc_fifo_err_int_dbg_t;
+
+
+/*
+ * Register: RdcPeuTxnLog
+ * PEU Transaction Log
+ * Description: PEU Transaction Log register. Counts the memory read
+ * and write requests sent to peu block. For debug only.
+ * Fields:
+ *     Counts the memory write transactions sent to peu block. This
+ *     counter saturates. This counter increments when vnmDbg is on
+ *     Counts the memory read transactions sent to peu block. This
+ *     counter saturates. This counter increments when vnmDbg is on
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rsrvd1:16;
+               uint64_t        peu_mem_wr_count:8;
+               uint64_t        peu_mem_rd_count:8;
+#else
+               uint64_t        peu_mem_rd_count:8;
+               uint64_t        peu_mem_wr_count:8;
+               uint64_t        rsrvd1:16;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} rdc_peu_txn_log_t;
+
+
+/*
+ * Register: RdcDbgTrainingVec
+ * Debug Training Vector
+ * Description: Debug Training Vector register Debug Training Vector
+ * for the coreClk domain. For the pcieClk domain, the dbgxMsb and
+ * dbgyMsb values are flipped on the debug bus.
+ * Fields:
+ *     Blade Number, the value read depends on the blade this block
+ *     resides
+ *     debug training vector the sub-group select value of 0 selects
+ *     this vector
+ *     Blade Number, the value read depends on the blade this block
+ *     resides
+ *     debug training vector the sub-group select value of 0 selects
+ *     this vector
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        dbgx_msb:1;
+               uint64_t        dbgx_bld_num:3;
+               uint64_t        dbgx_training_vec:12;
+               uint64_t        dbgy_msb:1;
+               uint64_t        dbgy_bld_num:3;
+               uint64_t        dbgy_training_vec:12;
+#else
+               uint64_t        dbgy_training_vec:12;
+               uint64_t        dbgy_bld_num:3;
+               uint64_t        dbgy_msb:1;
+               uint64_t        dbgx_training_vec:12;
+               uint64_t        dbgx_bld_num:3;
+               uint64_t        dbgx_msb:1;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} rdc_dbg_training_vec_t;
+
+
+/*
+ * Register: RdcDbgGrpSel
+ * Debug Group Select
+ * Description: Debug Group Select register. Debug Group Select
+ * register selects the group of signals brought out on the debug
+ * port
+ * Fields:
+ *     high 32b sub-group select
+ *     low 32b sub-group select
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:48;
+               uint64_t        dbg_h32_sub_sel:8;
+               uint64_t        dbg_l32_sub_sel:8;
+#else
+               uint64_t        dbg_l32_sub_sel:8;
+               uint64_t        dbg_h32_sub_sel:8;
+               uint64_t        rsrvd:48;
+#endif
+       } bits;
+} rdc_dbg_grp_sel_t;
+
+
+#endif /* _HXGE_RDC_HW_H */
diff --git a/drivers/net/hxge/hxge_rxdma.c b/drivers/net/hxge/hxge_rxdma.c
new file mode 100644 (file)
index 0000000..e9f4bf0
--- /dev/null
@@ -0,0 +1,1959 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#include "hpi/hpi_rxdma.h"
+#include "hpi/hpi_vir.h"
+#include "hxge.h"
+
+extern wait_queue_head_t ethtool_evnt;
+extern volatile int ethtool_cond;
+extern struct sk_buff *ethtool_skb;
+extern int hxge_get_option(const char *str, int *val);
+extern int hxge_ok_to_continue(struct hxge_adapter *hxgep);
+extern int hxge_block_reset(struct hxge_adapter *hxgep, int device);
+extern void hxge_disable_interrupts(struct hxge_adapter *hxgep);
+static int strip_crc_bytes = 0;
+extern int hxge_vmac_rx_set_framesize(struct hxge_adapter *hxgep, uint16_t size);
+
+#ifndef CONFIG_ERRINJECT
+
+#define HXGE_KMALLOC kmalloc
+#define ALLOC_SKB dev_alloc_skb
+#define ALLOC_PAGES alloc_pages
+
+#else
+
+#define HXGE_KMALLOC hxge_kmalloc
+#define ALLOC_SKB hxge_alloc_skb
+#define ALLOC_PAGES hxge_alloc_pages
+
+static void *hxge_kmalloc(struct hxge_adapter *hxgep, size_t size, gfp_t gfp)
+{
+
+       if (hxgep->err_flags & KMEM_FAILURE)
+               return NULL;
+       else 
+               return (kmalloc(size, gfp));
+}
+
+static struct sk_buff *hxge_alloc_skb(struct hxge_adapter *hxgep, 
+                                       unsigned int size)
+{
+       if (hxgep->err_flags & SKB_FAILURE)
+               return NULL;
+       else
+               return (dev_alloc_skb(size));
+}
+
+static inline struct page *
+hxge_alloc_pages(struct hxge_adapter *hxgep, gfp_t gfp_mask, unsigned int order)
+{
+       if (hxgep->err_flags & ALLOC_PAGES_FAILURE)
+               return NULL;
+       else
+               return (alloc_pages(gfp_mask, order));
+}
+#endif
+
+static void parse_rdc_stat(const char *prefix, rdc_stat_t cs)
+{
+       char rdc_str[400];
+       char *str;
+
+               rdc_str[0] = '\0';
+               str = rdc_str;
+
+               if (cs.bits.mex)
+                       str = strcat(str, "mex ");
+
+               if (cs.bits.rcr_thres)
+                       str = strcat(str, "rcr_thres ");
+
+               if (cs.bits.rcr_to) 
+                       str  = strcat(str , "rcr_to ");
+       
+                if (cs.bits.rbr_cpl_to) 
+                       str  = strcat(str , "rbr_cpl ");
+
+                if (cs.bits.peu_resp_err)
+                       str  = strcat(str , "peu_resp ");
+       
+                if (cs.bits.rcr_shadow_par_err)
+                       str  = strcat(str , "rcr_shad ");
+
+                if (cs.bits.rbr_prefetch_par_err)
+                       str  = strcat(str , "rbr_pre_par ");
+
+                if (cs.bits.rbr_pre_empty)
+                       str  = strcat(str , "rbr_preempty ");
+
+                if (cs.bits.rcr_shadow_full)
+                       str  = strcat(str , "rcr_shad_full ");
+
+                if (cs.bits.rcr_full) 
+                       str  = strcat(str , "rcr_full ");
+
+                if (cs.bits.rbr_empty)
+                       str  = strcat(str , "rbr_empty ");
+
+                if (cs.bits.rbr_full)
+                       str  = strcat(str , "rbr_full ");
+       
+       HXGE_ERR_PRINT("                %s =>  %s",prefix,str);
+}
+
+
+/* Creating a hash entry based on the DMA address value that is assigned to
+   a particular RBR block. This is the way that the receive code is able to 
+   find the RBR block from a given DMA address. Note that the DMA address is a
+   page-aligned address. So, the compare takes place at the page level only */
+static int add_to_hash_table(
+#ifdef CONFIG_ERRINJECT
+               struct hxge_adapter *hxgep,
+#endif
+               rx_rbr_ring_t *rbr_ring, int index)
+{
+       struct rx_hash_entry *hash_entry;
+       struct rbr_desc_addr_t desc_addr = rbr_ring->buf_blocks[index].addr;
+
+       int bucket  = (desc_addr.dma_addr>>PAGE_SHIFT) & (HASH_TABLE_SIZE-1);
+
+       hash_entry = HXGE_KMALLOC(
+#ifdef CONFIG_ERRINJECT
+                       hxgep, 
+#endif
+                       sizeof(struct rx_hash_entry), GFP_ATOMIC);
+       if (!hash_entry) {
+               HXGE_ERR_PRINT("Failed to get memory");
+               return RX_FAILURE;
+       }
+       
+       hash_entry->dma_addr = desc_addr.dma_addr;
+       hash_entry->index = index;
+       if (rbr_ring->hash_table[bucket] == NULL) 
+               hash_entry->next = NULL;
+       else
+               hash_entry->next = rbr_ring->hash_table[bucket];
+
+       rbr_ring->hash_table[bucket] = hash_entry;
+
+       return RX_NO_ERR;
+}
+
+static void free_hash_table(rx_rbr_ring_t *rbr_ring)
+{
+       struct rx_hash_entry *ptr, *next;
+       int i;
+               
+       for (i = 0; i < HASH_TABLE_SIZE; i++) {
+               next = ptr = rbr_ring->hash_table[i]; 
+               while (next != NULL) {
+                       next = ptr->next;
+                       kfree(ptr);
+                       ptr = next;
+               }
+               rbr_ring->hash_table[i] = NULL;
+       }
+}
+
+static int get_index_from_hash(rx_rbr_ring_t *rbr_ring, uint64_t pkt_addr)
+{
+       int bucket = (pkt_addr >> PAGE_SHIFT) & (HASH_TABLE_SIZE-1);
+       struct rx_hash_entry *ptr;
+
+        /* Look in the hash table for a match */
+        for (ptr = rbr_ring->hash_table[bucket]; ptr != NULL; ptr=ptr->next)
+                if (ptr->dma_addr ==  (pkt_addr & PAGE_MASK))
+                        break;
+
+        /* did not find it in the hash table. So, add it */
+        if (!ptr) {
+                HXGE_ERR_PRINT("Did not find mapping. pkt_addr : 0x%llx",pkt_addr);
+                return RX_FAILURE;
+        }
+
+        return(ptr->index);
+}
+
+#ifdef CONFIG_SKB_SHARED
+static int remove_hash_entry(rx_rbr_ring_t *rbr_ring, unsigned long pkt_addr)
+{
+       int bucket = (pkt_addr >> PAGE_SHIFT) & (HASH_TABLE_SIZE-1);
+       struct rx_hash_entry *ptr, *prev_ptr = NULL;
+
+        /* Look in the hash table for a match */
+        for (ptr = rbr_ring->hash_table[bucket]; ptr != NULL; 
+                               prev_ptr=ptr, ptr=ptr->next)
+               if (ptr->dma_addr == (pkt_addr & PAGE_MASK))
+                       break;
+       
+        /* Did not find it in the hash table; something wrong.. */
+        if (!ptr) {
+                HXGE_ERR_PRINT("Did not find mapping. pkt_addr : %lu",pkt_addr);
+                return RX_FAILURE;
+        }
+
+       if (ptr == rbr_ring->hash_table[bucket])
+               rbr_ring->hash_table[bucket] = ptr->next;
+       else
+               prev_ptr->next = ptr->next;
+       kfree(ptr);
+       return RX_NO_ERR;
+}
+#endif
+
+static void free_dma_buffer(struct hxge_adapter *hxgep, 
+       struct rx_rbr_entry_t *buf_block, boolean_t free_page)
+{
+       int order = (PAGE_SHIFT-12);
+       if (buf_block->addr.dma_addr)
+               pci_unmap_page(hxgep->pdev, buf_block->addr.dma_addr,
+                               PAGE_SIZE, PCI_DMA_FROMDEVICE);
+       if ((free_page)  && (buf_block->page))
+               __free_pages(buf_block->page, order);
+
+       buf_block->addr.dma_addr = 0;
+       buf_block->addr.vaddr = NULL;
+       buf_block->page = NULL;
+}
+
+
+static void hxge_free_rx_channel(struct hxge_adapter *hxgep, uint16_t rdc)
+{
+       int i;
+       struct rx_ring_t *rx_ring = &hxgep->rx_ring[rdc];
+       struct rx_rbr_entry_t *buf_blocks = rx_ring->rbr.buf_blocks;
+
+       /* Assumption: Entries filled from top down. The first null entry 
+           vaddr indicates end of list */
+       if (buf_blocks) {
+               for (i = 0; buf_blocks[i].addr.vaddr && 
+                                       (i < rx_ring->rbr.num_rbr_entries); i++)
+                       free_dma_buffer(hxgep, &buf_blocks[i], TRUE);
+       }
+       HXGE_DBG(hxgep, "Channel %d :",rdc);
+       HXGE_DBG(hxgep, "    Freed buf blocks");
+
+       if (rx_ring->rbr.rbr_addr.vaddr) 
+               pci_free_consistent(hxgep->pdev, 
+                       rx_ring->rbr.num_rbr_entries*sizeof(rbr_desc_entry_t),
+                       rx_ring->rbr.rbr_addr.vaddr,
+                       rx_ring->rbr.rbr_addr.dma_addr);
+       HXGE_DBG(hxgep, "    Freed RBR Descriptor Ring");
+
+       if (rx_ring->rcr.rcr_addr.vaddr)
+               pci_free_consistent(hxgep->pdev, 
+                       rx_ring->rcr.num_rcr_entries*sizeof(rcr_entry_t),
+                       rx_ring->rcr.rcr_addr.vaddr,
+                       rx_ring->rcr.rcr_addr.dma_addr);
+       HXGE_DBG(hxgep, "    Freed RCR Descriptor Ring");
+
+       if (rx_ring->mbox.vaddr)
+               pci_free_consistent(hxgep->pdev, sizeof(rxdma_mailbox_t),
+                       rx_ring->mbox.vaddr,
+                       rx_ring->mbox.dma_addr);
+       HXGE_DBG(hxgep, "    Freed Mailbox");
+
+       if (rx_ring->rbr.buf_blocks)
+               free_pages((unsigned long)rx_ring->rbr.buf_blocks, 
+                               rx_ring->rbr.buf_blocks_order);
+       HXGE_DBG(hxgep, "    Freed Buf block Pages");
+
+       free_hash_table(&rx_ring->rbr);
+       HXGE_DBG(hxgep, "    Freed Hash Table");
+}
+
+void hxge_free_rx (struct hxge_adapter *hxgep)
+{
+       int i;
+       
+       for (i = 0; i < hxgep->max_rdcs; i++)
+               hxge_free_rx_channel(hxgep, i);
+
+       if (hxgep->rx_ring)
+               kfree(hxgep->rx_ring);
+       hxgep->rx_ring = NULL;
+}
+
+/* Allocate buffers (if alloc is TRUE), initialize the buf_block meta data 
+ * structure and update the hydra RBR kick registers. Also, update the 
+ * free location in the RBR descriptor ring where the new free buffer will
+ * go 
+ */
+static int setup_dma_buffers(struct hxge_adapter *hxgep, int channel,
+                       struct rx_rbr_entry_t *buf_block, int entries, 
+                       boolean_t alloc, boolean_t init)
+{
+       struct page *page;
+       int order,i;
+       struct rx_rbr_entry_t *ptr;
+       rx_rbr_ring_t *rbr_ring = &hxgep->rx_ring[channel].rbr;
+       int rbr_loc = rbr_ring->rbr_free_loc;
+        hpi_handle_t    handle = hxgep->hw.hw_addr;
+       int retval = RX_NO_ERR;
+
+        order = (PAGE_SHIFT-12);
+       for (i = 0, ptr = buf_block; i < entries; i++, ptr++) {
+               if (likely(alloc)) {
+                       BUG_ON(ptr->page);
+                       ptr->page = page = ALLOC_PAGES(
+#ifdef CONFIG_ERRINJECT
+                                               hxgep,  
+#endif
+                                               GFP_ATOMIC, order);
+                       if (!page) {
+                               HXGE_ERR(hxgep, "could not allocate buffer");
+                               retval = RX_DROP_PKT;
+                               goto failed;
+                       }
+                       ptr->addr.vaddr = (rbr_desc_entry_t *)page_address(page);
+                       ptr->addr.dma_addr = pci_map_page(hxgep->pdev,
+                               ptr->page, 0, PAGE_SIZE, PCI_DMA_FROMDEVICE); 
+
+                       if (!ptr->addr.dma_addr) {
+                               HXGE_ERR(hxgep, "pci_map_page failed");
+                               retval = RX_FAILURE;
+                               goto failed;
+                       }
+                       retval = add_to_hash_table(
+#ifdef CONFIG_ERRINJECT
+                                       hxgep,
+#endif
+                                       rbr_ring, ptr->index);
+                       if (retval < 0) {
+                               HXGE_ERR(hxgep, "add_to_hash_table failed");
+                               goto failed;
+                       }
+               }
+               ptr->in_use = 0;
+               rbr_ring->rbr_addr.vaddr[rbr_loc] = 
+                                       ptr->addr.dma_addr >> PAGE_SHIFT;
+               rbr_loc = (rbr_loc+1) % rbr_ring->num_rbr_entries;
+       }
+
+       /* Only done when the channel is initialized */
+       if (init == TRUE) {
+               rbr_ring->rbr_free_loc = 0;
+               rbr_ring->pages_to_post = 0; 
+               hpi_rxdma_rdc_rbr_kick(handle, channel, entries);
+               HXGE_ERR(hxgep, "Initially kicked %d",entries);
+               return RX_NO_ERR;
+       }
+
+       rbr_ring->rbr_free_loc = rbr_loc;
+       rbr_ring->pages_to_post = entries;
+
+       if (rbr_ring->rbr_empty_flag) 
+               rbr_ring->rbr_empty_threshold++;
+       else
+               hpi_rxdma_rdc_rbr_kick(handle, channel, rbr_ring->pages_to_post);
+
+       return RX_NO_ERR;
+
+failed:
+       for (; alloc && i && (ptr >= buf_block); i--, ptr--)
+               free_dma_buffer(hxgep, ptr, TRUE);
+
+       return retval;
+}
+
+
+static void print_regs(struct hxge_adapter *hxgep, int type, int channel) 
+{
+        hpi_handle_t    handle = hxgep->hw.hw_addr;
+       rdc_rx_cfg1_t cfg_1;
+       rdc_rx_cfg2_t cfg_2;
+        rdc_rbr_cfg_a_t cfga;
+        rdc_rbr_cfg_b_t cfgb;
+        rdc_rcr_cfg_a_t rcr_cfga;
+        rdc_rcr_cfg_b_t rcr_cfgb;
+
+       switch (type) {
+       case LDV_RXDMA:
+               HXGE_DBG(hxgep, "Rx REGISTERS :");
+               RXDMA_REG_READ64(handle, RDC_RX_CFG1, channel, &cfg_1.value);
+               HXGE_DBG(hxgep, "  DMA Configuration 1 : 0x%llx",cfg_1.value);
+               RXDMA_REG_READ64(handle, RDC_RX_CFG2, channel, &cfg_2.value);
+               HXGE_DBG(hxgep, "  DMA Configuration 2 : 0x%llx", cfg_2.value);
+               RXDMA_REG_READ64(handle, RDC_RBR_CFG_A, channel, &cfga.value);
+               HXGE_DBG(hxgep, "  RBR Configuration A : 0x%llx",cfga.value);
+               RXDMA_REG_READ64(handle, RDC_RBR_CFG_B, channel, &cfgb.value);
+               HXGE_DBG(hxgep, "  RBR Configuration B : 0x%llx", cfgb.value);
+               RXDMA_REG_READ64(handle, RDC_RCR_CFG_A, channel, &rcr_cfga.value);
+               HXGE_DBG(hxgep, "  RCR Configuration A : 0x%llx", rcr_cfga.value);
+                RXDMA_REG_READ64(handle, RDC_RCR_CFG_B, channel, &rcr_cfgb.value);
+               HXGE_DBG(hxgep, "  RCR Configuration B : 0x%llx", rcr_cfgb.value);
+               break;
+       default:
+               HXGE_ERR(hxgep, "Invalid type to print_regs : %d", type);
+               break;
+       }
+}
+       
+
+static int hxge_map_rx_to_hw(struct hxge_adapter *hxgep, int rdc)
+{
+       rdc_desc_cfg_t cfg_desc;
+        hpi_handle_t    handle = hxgep->hw.hw_addr;
+       struct rx_ring_t *rx_ring = &hxgep->rx_ring[rdc];
+
+       /* Setup the mailbox location */
+       cfg_desc.mbox_enable = 1;
+       cfg_desc.mbox_addr = rx_ring->mbox.dma_addr;
+
+       rx_ring->full_hdr = FALSE; /* 2 bytes of header */
+       rx_ring->offset = 0;   /* no SW offset */
+       cfg_desc.full_hdr = rx_ring->full_hdr;
+       cfg_desc.offset = rx_ring->offset;
+       
+       cfg_desc.rbr_addr = rx_ring->rbr.rbr_addr.dma_addr;
+       cfg_desc.rbr_len = rx_ring->rbr.num_rbr_entries;
+       cfg_desc.page_size = hxgep->default_block_size;
+       cfg_desc.valid0 = 1;
+       cfg_desc.size0 = rx_ring->rbr.pkt_buf_size_bytes[0];
+       cfg_desc.valid1 = 1;
+       cfg_desc.size1 = rx_ring->rbr.pkt_buf_size_bytes[1];
+       cfg_desc.valid2 = 1;
+       cfg_desc.size2 = rx_ring->rbr.pkt_buf_size_bytes[2];
+
+       /* RCR stuff */
+       cfg_desc.rcr_addr = rx_ring->rcr.rcr_addr.dma_addr;
+       cfg_desc.rcr_len = rx_ring->rcr.num_rcr_entries;
+       cfg_desc.rcr_threshold = hxgep->rcr_threshold;
+
+        /* Set the registers */        
+       if (hpi_rxdma_cfg_rdc_ring(handle, rx_ring->rdc, &cfg_desc) !=
+                               HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "Configuration of Rx failed!");
+               return RX_FAILURE;
+       }
+
+       if (hpi_rxdma_cfg_clock_div_set(handle, HXGE_RCR_CLK_RESO) != 
+                                       HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hpi_rxdma_cfg_clock_div_set failed!");
+               return RX_FAILURE;
+       }
+
+       /* Needed when processing RCE buffers */
+       RXDMA_REG_READ64(handle, RDC_PAGE_HANDLE, rdc, &rx_ring->page_hdl.value);
+       print_regs(hxgep, LDV_RXDMA, rdc);
+       return RX_NO_ERR;
+}
+
+/* Initialize the Rx channel. This is called at driver initialzation time when
+   channel is created and also anytime that the channel is reset (on error 
+   situations, for example) */
+
+static int hxge_init_rx_channel(struct hxge_adapter *hxgep, int channel)
+{
+       struct rx_ring_t *rx_ring = &hxgep->rx_ring[channel];
+       struct rx_rbr_entry_t *buf_blocks = rx_ring->rbr.buf_blocks;
+       int i, alloc;
+
+       rx_ring->first_time = 1; /* CR 6769038 */
+       rx_ring->rbr.pkt_buf_size[0] = RBR_BUFSZ0_256B;
+       rx_ring->rbr.pkt_buf_size_bytes[0] = RBR_BUFSZ0_256_BYTES;
+        rx_ring->rbr.pkt_buf_size[1] = RBR_BUFSZ0_1K;
+        rx_ring->rbr.pkt_buf_size_bytes[1] = RBR_BUFSZ1_1K_BYTES;
+        rx_ring->rbr.pkt_buf_size[2] = RBR_BUFSZ2_2K;
+        rx_ring->rbr.pkt_buf_size_bytes[2] = RBR_BUFSZ2_2K_BYTES;
+        rx_ring->rbr.pkt_buf_size[3] = -1; /* special case; block size */
+       rx_ring->rbr.pkt_buf_size_bytes[3] = hxgep->default_block_size;
+
+       /* Initialize the RCR entries. Hardware can now use it */
+       memset(rx_ring->rcr.rcr_addr.vaddr, 0, 
+                       rx_ring->rcr.num_rcr_entries*sizeof(rcr_entry_t));
+        for (i = 0; i < rx_ring->rcr.num_rcr_entries; i++)
+               rx_ring->rcr.rcr_addr.vaddr[i] = (rcr_entry_t)RCR_INIT_PATTERN;
+       rx_ring->rcr.rcr_curr_loc = 0;
+
+       /* Initialize the mailbox as well */
+       memset(rx_ring->mbox.vaddr, 0, sizeof(rxdma_mailbox_t));
+
+       /* Initialize statistics */
+       memset(&rx_ring->stats, 0, sizeof(struct rx_ring_stats_t));
+
+       /* Program the hydra registers with the information about the Rx
+           channels and buffers */
+       if (hxge_map_rx_to_hw(hxgep, channel))
+               return RX_FAILURE;
+
+       /* hxge_init_rx_channel can be called from hxge_work_to_do during
+        * a channel reset, in which case we do not want to allocate
+        * new buffers (memory leak); just reuse the existing ones
+        */
+       alloc = test_bit(HXGE_DEVICE_OPENING, &hxgep->state) ? TRUE : FALSE;
+        if (setup_dma_buffers(hxgep, channel, buf_blocks,
+                        rx_ring->rbr.num_rbr_entries, alloc, TRUE) < 0)
+        {
+                HXGE_ERR(hxgep, "setup_dma_buffers failed");
+                return RX_FAILURE;
+        }
+       set_bit(RING_INIT, &rx_ring->state);
+       return RX_NO_ERR;
+}
+
+static void hxge_scrub_rx_mem(struct hxge_adapter *hxgep)
+{
+       int i;
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+
+        /*
+         * Scrub the RDC Rx DMA Prefetch Buffer Command.
+         */
+        for (i = 0; i < 128; i++) {
+                HXGE_REG_WR64(handle, RDC_PREF_CMD, i);
+        }
+
+        /*
+         * Scrub Rx DMA Shadow Tail Command.
+         */
+        for (i = 0; i < 64; i++) {
+                HXGE_REG_WR64(handle, RDC_SHADOW_CMD, i);
+        }
+
+        /*
+         * Scrub Rx DMA Control Fifo Command.
+         */
+        for (i = 0; i < 512; i++) {
+                HXGE_REG_WR64(handle, RDC_CTRL_FIFO_CMD, i);
+        }
+
+        /*
+         * Scrub Rx DMA Data Fifo Command.
+         */
+        for (i = 0; i < 1536; i++) {
+                HXGE_REG_WR64(handle, RDC_DATA_FIFO_CMD, i);
+        }
+}
+
+static int hxge_enable_rx_channel (struct hxge_adapter *hxgep, int rdc)
+{
+       struct rx_ring_t *rx_ring = &hxgep->rx_ring[rdc];
+        hpi_handle_t    handle = hxgep->hw.hw_addr;
+       rdc_int_mask_t rdc_mask;
+       hpi_status_t    status;
+
+
+        /* Reset the Rx DMA channel */
+        if (hpi_rxdma_cfg_rdc_reset(handle, rdc) != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hpi_rxdma_cfg_rdc_reset failed");
+       }
+
+       /* Initialize Rx data structures and some of the HW registers */
+        hxge_init_rx_channel(hxgep, rdc);
+
+       /* Enable the mbox update */
+       if (hpi_rxdma_channel_mex_set(handle, rdc) != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hpi_rxdma_channel_mex_set failed");
+       }
+
+       /* Enable the RCR timeout, if needed; otherwise explicitly disable */
+       hxgep->rcr_cfgb_cpy = 0;
+       if (hxgep->rcr_timeout > 0) {
+               status = hpi_rxdma_cfg_rdc_rcr_timeout(handle, rdc, 
+                                       hxgep->rcr_timeout);
+               hxgep->rcr_cfgb_cpy = RCR_CFGB_ENABLE_TIMEOUT | hxgep->rcr_timeout;
+       }
+       else
+               status = hpi_rxdma_cfg_rdc_rcr_timeout_disable(handle, rdc);
+
+       if (status != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hpi_rxdma_cfg_rdc_rcr_timeout failed");
+       }
+       
+
+       /* Clear all the bits in the RDC Stat and Control */
+       if (hpi_rxdma_channel_cs_clear_all(handle, rdc) != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hpi_rxdma_channel_cs_clear_all failed");
+       }
+
+
+       /* Clear all the event masks */
+       rdc_mask.value = 0;
+       hpi_rxdma_event_mask(handle, OP_SET, rdc, &rdc_mask);
+
+       /* Unmask the appropriate LDV for this Rx channel */
+       hxge_enable_rx_ints(hxgep, NULL, rdc);
+
+
+       /* Enable the Rx DMA channel */
+       if (hpi_rxdma_cfg_rdc_enable(handle, rdc) != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hpi_rxdma_cfg_rdc_enable failed");
+       }
+
+       set_bit(RING_ENABLED, &rx_ring->state);
+       HXGE_ERR(hxgep, "Channel %d enabled", rdc);
+
+
+       return RX_NO_ERR;
+}
+
+static int hxge_disable_rx_channel(struct hxge_adapter *hxgep, int rdc)
+{
+        hpi_handle_t    handle = hxgep->hw.hw_addr;
+       struct rx_ring_t  *rx_ring = &hxgep->rx_ring[rdc];
+
+       if (!test_and_clear_bit(RING_ENABLED, &rx_ring->state))
+               return RX_NO_ERR;
+
+       /* Disable RCR timeout */
+       hxgep->rcr_cfgb_cpy = 0;
+       if (hpi_rxdma_cfg_rdc_rcr_timeout_disable(handle, rdc) != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hpi_rxdma_cfg_rdc_rcr_timeout_disable failed");
+       }
+
+       /* Disable the Rx DMA channel */
+       if (hpi_rxdma_cfg_rdc_disable(handle, rdc) != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hpi_rxdma_cfg_rdc_disable failed");
+       }
+       return RX_NO_ERR;
+}
+
+
+int valid_alignment(uint64_t addr, uint64_t size, int shift)
+{
+       uint64_t max_addr = (1 << shift);
+       uint64_t mask = max_addr - 1;
+
+       if (((addr & mask) & (0x3 << (shift-1))) != (((addr & mask) + (size-8)) & (0x3 << (shift-1))))
+               return 0;
+
+       return 1;
+}
+
+
+/* This routine is called once per Rx DMA channel. It allocates the requisite
+   data structures for the receive ring  and sets up the hardware registers
+   to point to them. For example, the RBR, RCR and mailbox structures */
+
+static int hxge_alloc_rx_channel (struct hxge_adapter *hxgep, uint16_t rdc)
+{
+       struct rx_ring_t *rx_ring = &hxgep->rx_ring[rdc];
+       int rbr_entries, rcr_entries;
+       int i;
+       unsigned int size;
+       struct rx_rbr_entry_t *buf_blocks, *buf_block;
+
+       if (hxge_get_option("rbr_entries",&rbr_entries)) {
+               HXGE_ERR(hxgep, "rbr_entries invalid");
+               return RX_FAILURE;
+       }
+
+       if(hxge_get_option("rcr_entries", &rcr_entries)) {
+               HXGE_ERR(hxgep, "rcr_entries invalid");
+               return RX_FAILURE;
+       }
+
+       rx_ring->rdc = rdc;
+       rx_ring->rbr.num_rbr_entries = rbr_entries;     
+       rx_ring->rcr.num_rcr_entries = rcr_entries;
+
+       /* Allocate metadata to keep track of buffer blocks */
+       size = (rbr_entries*sizeof(struct rx_rbr_entry_t));
+       rx_ring->rbr.buf_blocks_order = get_order(size);
+       buf_blocks = rx_ring->rbr.buf_blocks = 
+                       (struct rx_rbr_entry_t *)__get_free_pages(GFP_KERNEL,
+                               rx_ring->rbr.buf_blocks_order);
+
+       if (!buf_blocks) {
+               HXGE_ERR(hxgep, "Failed to get buf blocks, %lu bytes", rbr_entries*sizeof(struct rx_rbr_entry_t));
+               return RX_FAILURE;
+       }
+       for (i = 0, buf_block=&buf_blocks[0]; i < rbr_entries; 
+                                               i++, buf_block++) {
+               memset(buf_block, 0, sizeof(struct rx_rbr_entry_t));    
+               buf_block->index = i;
+       }
+
+        rx_ring->rbr.pkt_buf_size[0] = RBR_BUFSZ0_256B;
+        rx_ring->rbr.pkt_buf_size_bytes[0] = RBR_BUFSZ0_256_BYTES;
+        rx_ring->rbr.pkt_buf_size[1] = RBR_BUFSZ0_1K;
+        rx_ring->rbr.pkt_buf_size_bytes[1] = RBR_BUFSZ1_1K_BYTES;
+        rx_ring->rbr.pkt_buf_size[2] = RBR_BUFSZ2_2K;
+        rx_ring->rbr.pkt_buf_size_bytes[2] = RBR_BUFSZ2_2K_BYTES;
+        rx_ring->rbr.pkt_buf_size[3] = -1; /* special case; block size */
+        rx_ring->rbr.pkt_buf_size_bytes[3] = hxgep->default_block_size;
+
+       /* The PRM mandates a formula to compute the RCRs based on the 
+        * smallest possible buffer size. This guarantees the we will
+        * see a rbr empty and not an rcr full (see CR 6779304 why this is 
+        * important).
+        */
+       do {
+               int compute_rcrs;
+               compute_rcrs = rbr_entries * 
+               (hxgep->default_block_size/rx_ring->rbr.pkt_buf_size_bytes[0]);
+               if (compute_rcrs > rx_ring->rcr.num_rcr_entries) {
+                       HXGE_ERR(hxgep, "%d rcr entries not sufficient for driver to function. You need at least %d rcr entries.",rcr_entries, compute_rcrs);
+                       return RX_FAILURE;
+               }
+               else
+                       rx_ring->rcr.num_rcr_entries = compute_rcrs;
+       } while (0);
+       HXGE_DBG(hxgep, "RBR = %d, RCR = %d",rbr_entries, rx_ring->rcr.num_rcr_entries);
+               
+       /* Allocate the RBR descriptor ring. We allocate a power of two
+         * larger than we really need to assure that we meet the alignment
+         * restriction of the PRM. We do the same thing for the RCR further
+         * down
+         */
+       rx_ring->rbr.rbr_addr.vaddr = pci_alloc_consistent( hxgep->pdev, 
+               rx_ring->rbr.num_rbr_entries*sizeof(rbr_desc_entry_t),
+               &rx_ring->rbr.rbr_addr.dma_addr);
+       if (!rx_ring->rbr.rbr_addr.vaddr) {
+               HXGE_ERR(hxgep, "Could not get DMA for RBR, channel %d",rdc);
+       }
+
+       /* Now validate the alignment */
+       if (!valid_alignment(rx_ring->rbr.rbr_addr.dma_addr,
+                          rbr_entries*sizeof(rbr_desc_entry_t), 18)) {
+       HXGE_ERR(hxgep, "RBR Desc @ 0x%lx not aligned properly, channel %d",
+                       (long unsigned int)rx_ring->rbr.rbr_addr.dma_addr, rdc);
+               return RX_FAILURE;
+       }
+
+       rx_ring->rcr.rcr_addr.vaddr = pci_alloc_consistent(hxgep->pdev, 
+                       rx_ring->rcr.num_rcr_entries*sizeof(rcr_entry_t),
+                       &rx_ring->rcr.rcr_addr.dma_addr);
+       if (!rx_ring->rcr.rcr_addr.vaddr) {
+               HXGE_ERR(hxgep, "Could not get DMA for RCR, channel %d",rdc);
+               return RX_FAILURE;
+       }
+
+       if (!valid_alignment(rx_ring->rcr.rcr_addr.dma_addr,
+                       rx_ring->rcr.num_rcr_entries*sizeof(rcr_entry_t), 19)) {
+       HXGE_ERR(hxgep, "RCR Desc @ 0x%lx aligned properly, channel %d",
+                       (long unsigned int)rx_ring->rcr.rcr_addr.dma_addr, rdc);
+               return RX_FAILURE;
+       }
+       memset(rx_ring->rcr.rcr_addr.vaddr, 0, 
+                       rx_ring->rcr.num_rcr_entries*sizeof(rcr_entry_t));
+
+       HXGE_DBG(hxgep, "Allocated RBR at 0x%p (0x%llx) of size %d",rx_ring->rbr.rbr_addr.vaddr, rx_ring->rbr.rbr_addr.dma_addr, (int)(rbr_entries*sizeof(rbr_desc_entry_t)));
+       HXGE_DBG(hxgep, "Allocated RCR at 0x%p (0x%llx) of size %d",rx_ring->rcr.rcr_addr.vaddr, rx_ring->rcr.rcr_addr.dma_addr, (int)(rx_ring->rcr.num_rcr_entries*sizeof(rcr_entry_t)));
+       
+       rx_ring->mbox.vaddr = pci_alloc_consistent(hxgep->pdev,
+                                sizeof(rxdma_mailbox_t), 
+                                &rx_ring->mbox.dma_addr);
+       if (!rx_ring->mbox.vaddr) {
+               HXGE_ERR(hxgep, "Could not get DMA for mailbox, channel %d",rdc);
+       }
+
+       return RX_NO_ERR;
+}
+
+
+int hxge_alloc_rx(struct hxge_adapter *hxgep)
+{
+       int i;
+       int stripcrc = 0;
+
+       if (hxge_get_option("strip_crc", &stripcrc)) {
+               HXGE_ERR(hxgep, "Cannot get strip_crc value");
+               return RX_FAILURE;
+       }
+       if (stripcrc)
+               strip_crc_bytes = 0;
+       else
+               strip_crc_bytes = 4;
+
+       hxgep->rx_ring = kzalloc(sizeof(struct rx_ring_t)*hxgep->max_rdcs,
+                                       GFP_KERNEL);
+       if (!hxgep->rx_ring) {
+               HXGE_ERR(hxgep, "Could not alloc rx_ring");
+               return RX_FAILURE;
+       }
+
+       for (i = 0; i < hxgep->max_rdcs; i++) {
+               if (hxge_alloc_rx_channel(hxgep, i)) {
+                       HXGE_ERR(hxgep, "Could not alloc rx for channel");
+                       hxge_free_rx(hxgep);
+                       return RX_FAILURE;
+               }
+       }
+
+       return RX_NO_ERR;
+}
+
+int hxge_enable_rx(struct hxge_adapter *hxgep)
+{
+       hpi_handle_t  handle = hxgep->hw.hw_addr;
+       rdc_fifo_err_mask_t  fifo_mask;
+       unsigned long long   reg64 = 0xfeedfacedeadbeefULL;
+       int i;
+
+       /* Scrub/initialize RDC memory */
+       hxge_scrub_rx_mem(hxgep);
+
+       /* Reset the FIFO Error Status */
+       HXGE_REG_RD64(handle, RDC_FIFO_ERR_STAT, &reg64);
+       if (reg64) {
+               /* While an interesting case (error flags should probably
+                * not be set), do not count against hxgep->hard_errors */
+               HXGE_ERR(hxgep, "RDC_FIFO_ERR_STAT 0x%16.16x hardware error flags set",
+                        (unsigned int)reg64);
+       }
+        HXGE_REG_WR64(handle, RDC_FIFO_ERR_STAT, reg64); /* RW1C err bits */
+
+       /* Set the error mask to receive interrupts */
+       fifo_mask.value = 0;
+       if (hpi_rx_fifo_mask(handle, OP_SET, &fifo_mask) != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hpi_rx_fifo_mask failed");
+       }
+
+       /* Enable all appropriate RX DMA channels */
+
+       for (i = 0; i < hxgep->max_rdcs; i++) {
+               if (hxge_enable_rx_channel(hxgep, i)) {
+                       HXGE_ERR(hxgep, "Could not enable Rx chan %i",i);
+                       return RX_FAILURE;
+               }
+       }
+
+       hxge_enable_rx_ints(hxgep, NULL, -1);
+
+       return RX_NO_ERR;
+}
+
+int hxge_disable_rx(struct hxge_adapter *hxgep)
+{
+       int i;
+
+       /* Disable Rx interrupts */
+       hxge_disable_rx_ints(hxgep,NULL, -1);
+
+       /* Disable all channels. Print warning message but don't exit until
+          attempting to disable all of them */
+       for (i = 0; i < hxgep->max_rdcs; i++) {
+               if (hxge_disable_rx_channel(hxgep, i)) {
+                       HXGE_ERR(hxgep, "Could not disable Rx chan %i",i);
+                       return RX_FAILURE;
+               }
+       }
+       return RX_NO_ERR;
+}
+
+
+
+/* Reset entire Rx ("RDC") subsystem */
+int hxge_reset_rdc(struct hxge_adapter *hxgep)
+{
+       /* Shutdown all receive traffic first */
+
+       hxge_disable_rx(hxgep);
+
+       /* Generate rdc_core logic reset */
+
+       hxge_block_reset(hxgep, LDV_RXDMA);
+
+       /* Bring up all the receive channels now */
+
+       hxge_enable_rx(hxgep);
+
+       return RX_NO_ERR;
+}
+
+
+/* This routines takes a DMA pkt_addr provided in an RCR descriptor entry and
+   finds out the buffer block (CPU addr) in the RBR that matches it */
+static struct rx_rbr_entry_t *get_buf_block(struct rx_ring_t *rx_ring, 
+                               rcr_entry_t *rcr_entry, uint32_t blk_size,                                      uint64_t *offset, int first_rcr)
+{
+       rx_rbr_ring_t *rbr_ring = &rx_ring->rbr;
+       int index;
+       struct rx_rbr_entry_t *buf_block;
+       uint64_t pkt_addr;
+       int pktsz;
+
+       /* Get 64-bit packet address */
+       pkt_addr = rcr_entry->bits.pkt_buf_addr << RCR_PKT_BUF_ADDR_SHIFT_FULL;
+       pkt_addr |= ((rx_ring->page_hdl.value & 0xfffff) 
+                                       << HXGE_MAX_ADDRESS_BITS);
+
+       *offset = pkt_addr & (blk_size - 1);
+       pktsz = ((first_rcr == 0) ?  blk_size : 
+                  rbr_ring->pkt_buf_size_bytes[rcr_entry->bits.pktbufsz]);
+
+
+       /* Hit CR 6698258. The workaround is to ignore this entry and call it
+        * a success. The entry will be populated on the next interrupt */
+       if ((rcr_entry->value == 0x0) || (rcr_entry->value == RCR_INIT_PATTERN)
+              || ((index = get_index_from_hash(rbr_ring, pkt_addr)) < 0))
+       {
+               HXGE_ERR_PRINT("bad hash entry for pkt address 0x%llx",(unsigned long long)pkt_addr);
+               goto fail;
+       }
+               
+       buf_block = &rbr_ring->buf_blocks[index];
+       buf_block->pkt_size = pktsz;
+       return buf_block;
+
+fail:
+       HXGE_ERR_PRINT("rcr_entry 0x%p: 0x%lx, pkt_addr: 0x%lx",rcr_entry, (unsigned long)rcr_entry->value,(unsigned long)rcr_entry->bits.pkt_buf_addr);
+
+       HXGE_ERR_PRINT("   multi=%d",rcr_entry->bits.multi);
+       HXGE_ERR_PRINT("   pkt_type=%d",rcr_entry->bits.pkt_type);
+       HXGE_ERR_PRINT("   error=%d",rcr_entry->bits.error);
+       HXGE_ERR_PRINT("   l2_len=%d",rcr_entry->bits.l2_len);
+       HXGE_ERR_PRINT("   pktbufsz=%d",rcr_entry->bits.pktbufsz);
+       HXGE_ERR_PRINT("   pkt_addr=0x%lux",(unsigned long)rcr_entry->bits.pkt_buf_addr);
+       return NULL;
+}
+
+static void update_buf_block(struct rx_rbr_entry_t *buf_block, 
+                               uint32_t blk_size)
+{
+       if (!buf_block->in_use) /* not in use; virgin block */ {
+               buf_block->in_use = 1;
+               buf_block->max_pkts = blk_size / buf_block->pkt_size;
+       } else  /* already in use */
+               buf_block->in_use++;
+
+       /* Check if the buffer block is full. If so, mark it as "can be 
+           freed" once the packet is copied out of it */       
+       if (buf_block->in_use == buf_block->max_pkts)
+               buf_block->in_use = -1;
+#ifdef DBG
+       HXGE_DBG_PRINT("BUF_BLOCK [%d] => %p",index,buf_block);
+       HXGE_DBG_PRINT("        in_use = %d", buf_block->in_use);
+       HXGE_DBG_PRINT("        pkt_size = %d", buf_block->pkt_size);
+       HXGE_DBG_PRINT("        max_pkts = %d", buf_block->max_pkts);
+       HXGE_DBG_PRINT("PKT_ADDR : 0x%lx, offset=0x%lx",(unsigned long)pkt_addr,(unsigned long)*offset);
+#endif
+
+}
+
+#ifdef CONFIG_SKB_SHARED
+static void unmap_dma_buffer(struct hxge_adapter *hxgep,  int channel,
+                               struct rx_rbr_entry_t *buf_block)
+{
+       struct rx_ring_t *rx_ring = &hxgep->rx_ring[channel];
+       remove_hash_entry(&rx_ring->rbr, buf_block->addr.dma_addr);
+       free_dma_buffer(hxgep, buf_block, FALSE);
+}
+
+/* This routine is called for jumbo packets where a packet spans more than one
+ * buffer block. The routine sets up skb fragments to avoid having to do 
+ * expensive copies of large buffers. */
+
+static int setup_skb_frag(struct sk_buff *skb, struct hxge_adapter *hxgep,
+       int channel, struct rx_rbr_entry_t *buf_block, uint32_t offset, 
+       uint32_t len)
+{
+       int free = skb_shinfo(skb)->nr_frags;
+       skb_frag_t *fragp;
+
+       if (free >= MAX_SKB_FRAGS) {
+               HXGE_ERR(hxgep, "Too many skb fragments attempted!");
+               return RX_FAILURE;
+       }
+               
+       /* setup the old page to a skb fragment */
+       fragp = &skb_shinfo(skb)->frags[free];
+       fragp->page = buf_block->page;
+       fragp->page_offset = offset;
+       fragp->size = len;
+
+       /* Unmap the DMA view from the old page (do not free it!), allocate 
+          a new page and have the buf block meta data point to it */
+
+       unmap_dma_buffer(hxgep, channel, buf_block); /* unmap and remove hash */
+       if (setup_dma_buffers(hxgep, channel, buf_block, 1, TRUE, FALSE) < 0) {
+               HXGE_ERR(hxgep, "setup_dma_buffer failed");
+               buf_block->in_use = 0; /* can be re-used again */
+               return RX_DROP_PKT;
+       }
+
+       /* No errors. So, we can now account for this entry */
+       skb_shinfo(skb)->nr_frags++;
+       return RX_NO_ERR;
+       
+}
+#endif
+
+
+static inline void process_pkt_hdr (pkt_hdr_twobyte_t *pkt_hdr) 
+{
+       HXGE_DBG_PRINT("PKT_HDR =>");
+        HXGE_DBG_PRINT("  drop_code = %d",pkt_hdr->bits.drop_code);
+        HXGE_DBG_PRINT("  tcamhit = %d",pkt_hdr->bits.tcamhit);
+        HXGE_DBG_PRINT("  badip = %d",pkt_hdr->bits.badip);
+        HXGE_DBG_PRINT("  noport = %d",pkt_hdr->bits.noport);
+        HXGE_DBG_PRINT("  bcast_frame = %d",pkt_hdr->bits.bcast_frame);
+        HXGE_DBG_PRINT("  vlan = %d",pkt_hdr->bits.vlan);
+        HXGE_DBG_PRINT("  class= %d",pkt_hdr->bits.class);
+        HXGE_DBG_PRINT("  maccheck= %d",pkt_hdr->bits.maccheck);
+        HXGE_DBG_PRINT("  l4_cs_eq= %d",pkt_hdr->bits.l4_cs_eq);
+}
+
+/* This routine processes the first RCR entry for a packet. This could be the
+ * only packet (packet size <= block size) or could be the first entry in a 
+ * multi entry RCR packet (jumbo frames). In either case, it sets up the skb
+ * buffer and initializes it appropriately based on packet size 
+ */
+struct sk_buff *process_first_rcr_entry(struct hxge_adapter *hxgep, 
+               struct rx_ring_t *rx_ring, int *bytes_remaining)
+{
+       rcr_entry_t *rcr_entry;
+       rx_rcr_ring_t *rcr_ring = &rx_ring->rcr;
+       struct rx_rbr_entry_t *buf_block;
+       struct sk_buff *skb;
+       uint32_t l2_len, hdr_len, len, data_size;
+       unsigned char *cpu_addr;
+       pkt_hdr_twobyte_t *pkt_hdr;
+       uint64_t offset;
+       uint32_t data_offset;
+
+       *bytes_remaining = RX_NO_ERR;
+       rcr_entry = GET_RCR_ENTRY(rcr_ring);
+
+       HXGE_DBG(hxgep, "rcr_ring loc : 0x%p", rcr_ring->rcr_addr.vaddr);
+        HXGE_DBG(hxgep, "rcr_curr_loc : %d",rcr_ring->rcr_curr_loc); 
+        HXGE_DBG(hxgep, "rcr entry: 0x%lux",(unsigned long)rcr_ring->rcr_addr.vaddr[rcr_ring->rcr_curr_loc].value);
+       /* Get index into buf_blocks meta data so that we can get to the
+           CPU address from the DMA address, among other things */
+       if (!(buf_block = get_buf_block(rx_ring, rcr_entry, hxgep->default_block_size, &offset, 1))) {
+               HXGE_ERR(hxgep, "Bad pkt_addr");
+               HXGE_ERR(hxgep, "rcr_curr_loc : %d",rcr_ring->rcr_curr_loc); 
+               return NULL;
+       }
+
+       update_buf_block(buf_block, hxgep->default_block_size);
+       cpu_addr = (char *)buf_block->addr.vaddr + offset;
+       pkt_hdr = (pkt_hdr_twobyte_t *)cpu_addr;
+
+#if 0
+       process_pkt_hdr(pkt_hdr);
+#endif
+
+       /* Get to the actual data part of the packet received */
+       data_offset  = rx_ring->offset + (rx_ring->full_hdr ? 6 : 2);
+       data_size = buf_block->pkt_size - data_offset;
+       cpu_addr += data_offset;
+       hdr_len = ETH_HLEN;
+
+       len = l2_len = rcr_entry->bits.l2_len;
+       *bytes_remaining = l2_len;
+
+       rx_ring->stats.ipackets++;
+       rx_ring->stats.ibytes += l2_len;
+       if (l2_len > ETH_FRAME_LEN)
+               rx_ring->stats.jumbo_pkts++;
+
+       /* Create pkt_hdr structure and check for vlan */
+       if (pkt_hdr->bits.vlan)
+               hdr_len += 4;
+
+       /* TODO: There is the case where we could get small packets with 
+                taking up an entire buffer block mostly wasted. This happens
+                if we the packet size options programmed into the config
+                 registers are limited. For example, if only a packet size of
+                 256B is set, then anything >256B will take up an entire 
+                4KB block! Need to copy out the small packet in this case */
+
+#ifdef CONFIG_SKB_SHARED
+       if (rcr_entry->bits.multi) 
+               len = hdr_len;
+#endif
+       skb = ALLOC_SKB(
+#ifdef CONFIG_ERRINJECT
+                       hxgep, 
+#endif
+                       len + NET_IP_ALIGN);
+       if (!skb) {
+               HXGE_ERR(hxgep, "Could not allocate skb!");
+               *bytes_remaining = RX_DROP_PKT;
+               return NULL;
+       }
+
+       skb_reserve(skb, NET_IP_ALIGN);
+       skb->dev = hxgep->netdev;
+
+       /* Let Linux know the status of IP checksumming. If we have HW (IP) 
+         * chksum available, then it's already done.  Otherwise, we let Linux 
+         * know that no checksum has been done.
+         */
+
+       if ((hxgep->flags & HXGE_RX_CHKSUM_ENABLED) && 
+            !pkt_hdr->bits.noport && !rcr_entry->bits.error &&
+            ((rcr_entry->bits.pkt_type == RCR_PKT_TCP) ||
+            (rcr_entry->bits.pkt_type == RCR_PKT_UDP)) &&
+            pkt_hdr->bits.l4_cs_eq)
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+       else {
+               if (((rcr_entry->bits.pkt_type == RCR_PKT_TCP) || 
+                   (rcr_entry->bits.pkt_type == RCR_PKT_UDP)) && 
+                       (!pkt_hdr->bits.l4_cs_eq) && (!pkt_hdr->bits.noport))
+                       HXGE_DBG(hxgep, "Checksum failed");
+               skb->ip_summed = CHECKSUM_NONE;
+       }
+
+#ifndef CONFIG_SKB_SHARED
+       if (rcr_entry->bits.multi)
+               len = data_size;
+#endif
+
+       memcpy(skb_put(skb, len), cpu_addr, len); 
+#ifdef CONFIG_SKB_SHARED
+       if (rcr_entry->bits.multi) /* Copy packet data into fragment */ {
+               int retval; 
+               skb->len += (l2_len - len);
+               skb->data_len = l2_len - len;
+               skb->truesize += (l2_len - len);
+               skb_shinfo(skb)->nr_frags = 0;
+               retval = setup_skb_frag(skb, hxgep, rx_ring->rdc, buf_block, 
+                       data_offset + len, data_size-len);
+               if (retval < 0) 
+                       *bytes_remaining = retval;
+               else 
+                       *bytes_remaining -= data_size;
+       } else 
+#endif
+       { /* in single packet case, check if buf block can be freed */ 
+               if ((buf_block->in_use < 0) && (setup_dma_buffers(hxgep, 
+                       rx_ring->rdc, buf_block, 1, FALSE, FALSE) < 0))
+                       *bytes_remaining = RX_FAILURE;
+               else
+                       *bytes_remaining -= len;
+       }
+       
+       /* Increment to next location in the RCR descriptor table */    
+       INCREMENT_RCR_ENTRY_TO_NEXT(rcr_ring);
+       return skb;
+}
+
+
+/* This routine is called only for packets that span multiple buffer blocks 
+ * and is not called for single packet cases. It processes the multiple RCR
+ * entries for large packets and sets up the skb fragments for each buffer 
+ * block (parts of the packet data)
+ */
+static int process_rcr_entries(struct hxge_adapter *hxgep, 
+       struct rx_ring_t *rx_ring, struct sk_buff *skb, int bytes_remaining)
+{
+       struct rx_rbr_entry_t *buf_block;
+       rx_rcr_ring_t *rcr_ring = &rx_ring->rcr;
+       rcr_entry_t *rcr_entry; 
+       int len;
+       uint64_t offset;
+       int retval = RX_NO_ERR;
+
+       rcr_entry = GET_RCR_ENTRY(rcr_ring);    
+
+       /* Get index into buf_blocks meta data so that we can get to the
+           CPU address from the DMA address, among other things */
+       if (!(buf_block = get_buf_block(rx_ring, rcr_entry, 
+                       hxgep->default_block_size, &offset, 0))) 
+       {
+                HXGE_ERR(hxgep, "Bad pkt_addr");
+                HXGE_ERR(hxgep, "rcr_curr_loc : %d",rcr_ring->rcr_curr_loc);
+               return RX_FAILURE;
+       }
+
+       update_buf_block(buf_block, hxgep->default_block_size);
+       len = min(buf_block->pkt_size, (uint32_t)bytes_remaining);
+#ifdef CONFIG_SKB_SHARED
+       if ((retval = setup_skb_frag(skb, hxgep, rx_ring->rdc, 
+                       buf_block, 0, len)) < 0) {
+               HXGE_ERR(hxgep, "could not get skb fragment");
+               return retval;
+       }
+#else
+       memcpy(skb_put(skb, len), (char *)buf_block->addr.vaddr + offset, len);
+       if (buf_block->in_use < 0)
+               if ((retval = setup_dma_buffers(hxgep, rx_ring->rdc, 
+                               buf_block, 1,
+                                        FALSE, FALSE)) < 0) {
+                HXGE_ERR(hxgep,"setup_dma_buffers failed");
+                return retval;
+        }
+
+#endif
+       
+       INCREMENT_RCR_ENTRY_TO_NEXT(rcr_ring);
+       return (bytes_remaining - len);
+}
+
+static void free_skb(struct sk_buff *skb)
+{
+       if (!skb)
+               return;
+
+       dev_kfree_skb_any(skb);
+}
+
+
+/* This routine is called by the packet processing routine in the event of
+ * a failure that is related (currently) to memory allocation failure. In that
+ * case, we opt to drop the packet rather than declare this a catastrophic
+ * failure i.e. requiring a reset of the channel, which will flush out valid
+ * packets that are awaiting processing. Instead, we just drop the current
+ * packet and move ahead with processing as usual.
+ *
+ * NOTE: The implicit assumption in this routine is that update_buf_block has
+ * already been called for the first rcr_entry that we are processing, always.
+ */
+
+int drop_packet(struct hxge_adapter *hxgep, struct rx_ring_t *rx_ring,
+                               struct sk_buff *skb)
+{
+       rx_rcr_ring_t *rcr_ring = &rx_ring->rcr;
+       int rcr_processed = 0;
+
+       rx_ring->stats.nomem_drop++;
+       if (skb) 
+               free_skb(skb);
+       
+       /* Go through and reassign the buffer to the hardware */
+       do {
+               uint64_t ignore;
+               struct rx_rbr_entry_t *buf_block;
+               rcr_entry_t *rcr = GET_RCR_ENTRY(rcr_ring);
+       
+               buf_block = get_buf_block(rx_ring, rcr, 
+                               hxgep->default_block_size, &ignore, 1);
+               if (!buf_block) {
+
+                       /* we've already cleaned up the first multi entry
+                        * in setup_skb_frag by clearing the in_use bit for 
+                        * re-use. So, just skip and go to the next one
+                        */
+                       if  (!rcr_processed && rcr->bits.multi)
+                               continue;
+                       
+                       /* Something wrong; the buf_block should be in the 
+                        * hash list for non-multi case
+                        */
+                       HXGE_ERR(hxgep, "get_buf_block failed");
+                       return RX_FAILURE;
+               }
+
+               /* Use rcr_processed as "first time through this loop" 
+                * in_use count. Please see "NOTE" above
+                */
+               if (rcr_processed)
+                       update_buf_block(buf_block, hxgep->default_block_size);
+
+               BUG_ON(buf_block->in_use < -1);
+               if (buf_block->in_use < 0)
+                       setup_dma_buffers(hxgep, rx_ring->rdc, buf_block, 
+                               1, FALSE, FALSE);
+               rcr_processed++;
+               INCREMENT_RCR_ENTRY_TO_NEXT(rcr_ring);
+               if (!rcr->bits.multi)
+                       break;
+       } while (TRUE);
+       
+
+       //HXGE_ERR(hxgep, "Dropped %d packets",rcr_processed);
+       return rcr_processed;
+}
+
+/* Process one packet. This could be either a single or a multiple RCR entry
+   case. 
+   ASSUMPTION: The code assumes that a multi-buffer scenario implies that all 
+   except the last is a full buffer block. While it does not need to be, it 
+   makes coding simpler */
+
+static int hxge_process_one_pkt (struct hxge_adapter *hxgep,
+               struct rx_ring_t *rx_ring, struct sk_buff **skb_list)
+{
+       struct sk_buff *skb = NULL;
+       int bytes_remaining;
+       int rcr_entries_read = 0;
+               
+       /* This routine processes the first entry of the RCR for this packet,
+          including allocating a skbuff and copying the header */
+       skb = process_first_rcr_entry(hxgep, rx_ring, &bytes_remaining);
+       if (!skb || (bytes_remaining < 0))
+               goto failed;
+               
+       rcr_entries_read++;
+
+       /* This can only be true for multi-packet cases. For single packet,
+          everything processed in first rcr entry */
+       while (bytes_remaining > 0) {
+               bytes_remaining = process_rcr_entries(hxgep, rx_ring, skb, 
+                                                       bytes_remaining);
+               if (bytes_remaining < 0)
+                       goto failed;
+               rcr_entries_read++;
+       }
+
+        /* Remove the ethernet crc from the packet before passing to the 
+          network stack */
+       pskb_trim(skb, skb->len - strip_crc_bytes);
+
+       if (!test_bit(HXGE_DEVICE_TESTING, &hxgep->state))
+               skb->protocol = eth_type_trans(skb, hxgep->netdev);
+
+       /* If we are running diagnostic tests, then don't pass the skb to 
+          the OS. Instead, the diag test routine will manage the skb's 
+          itself */
+       if (unlikely(test_bit(HXGE_DEVICE_TESTING, &hxgep->state))) {
+               if (*skb_list == NULL) {
+                       *skb_list = skb;
+                       skb->next = NULL;
+               }
+               else {
+                       skb->next = (*skb_list)->next;
+                       (*skb_list)->next = skb;
+               }
+               
+       } else {
+       
+       /* Pass skb up the linux network stack for processing */
+#ifdef CONFIG_HXGE_NAPI
+               netif_receive_skb(skb);
+#else
+               netif_rx(skb);
+#endif
+               hxgep->netdev->last_rx = jiffies;
+       }
+
+       return rcr_entries_read;
+
+failed:
+       if (bytes_remaining == RX_DROP_PKT) {
+               int rcrs = drop_packet(hxgep, rx_ring, skb);
+               if (rcrs < 0)
+                       return RX_FAILURE;
+               else
+                       return (rcrs + rcr_entries_read);
+       }
+       HXGE_ERR(hxgep, "Bad pkt_addr on channel %d, bytes_remaining: %d",rx_ring->rdc, bytes_remaining);
+       return RX_FAILURE;
+}
+
+
+/* Workaroud for CR 6698258. Scan through the rcr entries that the HW
+   has fully populated. The assumption in the code is that there is 
+   a complete set of packets in this list. If not, the processing
+   code will catch it manifested in various ways. The routine 
+   converts RCR entries into number of packets, which is then used
+   as a limit on the packets to process.
+*/
+uint32_t scan_for_last_eop(struct rx_ring_t *rx_ring, int num_rcrs)
+{
+       rx_rcr_ring_t *rcr_ring = &rx_ring->rcr;
+       rcr_entry_t *rcr_entry = GET_RCR_ENTRY(rcr_ring);
+       uint32_t loc = rcr_ring->rcr_curr_loc;
+       int rcrs = 0;
+       uint32_t pkts = 0;
+
+       while ((rcrs < num_rcrs) && (rcr_entry->value != 0) && 
+               (rcr_entry->value != RCR_INIT_PATTERN)) 
+       {
+               if (!rcr_entry->bits.multi) 
+                       pkts++;
+               loc = (loc + 1) % rcr_ring->num_rcr_entries;
+               rcr_entry = &rcr_ring->rcr_addr.vaddr[loc];
+               rcrs++;
+       }
+       return pkts;
+}
+
+
+
+/* This routine processes the Rx channels. For each network device, all
+   the Rx channels are processed for packets even though each individual 
+   channel has its own interrupt handler called (NAPI case only). This is 
+   because the higher network layers are unaware of channels and only work 
+   with a network device. For non-NAPI case, channel processing happens in
+   parallel */
+#ifdef CONFIG_HXGE_NAPI
+int hxge_process_packets(struct hxge_adapter *hxgep, int work_to_do,
+               struct hxge_ldv *ldvp, struct sk_buff **skb_list)
+#else
+int hxge_process_packets(struct hxge_adapter *hxgep, struct hxge_ldv *ldvp, 
+               struct sk_buff **skb_list)
+#endif
+{
+       int channel = ldvp->ldv-HXGE_RDMA_LD_START;
+       struct rx_ring_t *rx_ring = &hxgep->rx_ring[channel];
+       uint32_t max_pkts, scan_pkts;
+       int pkts_processed = 0, rcr_entries_read=0, rcr_entries_processed=0;
+       rdc_stat_t *cs = (rdc_stat_t *)&ldvp->data;
+#ifdef USE_MBOX
+       rxdma_mailbox_t *mboxp;
+       uint32_t mbox_rcrtail;
+#endif
+       uint32_t num_entries;
+        hpi_handle_t    handle = hxgep->hw.hw_addr;
+#ifdef USE_PIO
+       uint32_t rcr_tail, rcrtail_index;
+#endif
+
+       if (channel != rx_ring->rdc) { /* should match */ 
+               HXGE_ERR(hxgep, "channels do not match!");
+               return RX_FAILURE;
+       }
+       
+       /* not enabled; don't return error since no harm done */
+       if (!test_bit(RING_ENABLED, &rx_ring->state)) {
+               HXGE_ERR(hxgep, "Channel %d not enabled",channel);
+               return RX_NO_ERR;
+       } 
+
+
+       /* Determine the max number of packets that can be processed */
+       max_pkts = hxgep->max_rx_pkts;
+#ifdef CONFIG_HXGE_NAPI
+       max_pkts = min((uint32_t)work_to_do, max_pkts);
+#endif
+#ifdef USE_PIO
+       if (hpi_rxdma_rdc_rcr_tail_get(handle, channel, &rcr_tail) 
+                               != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hpi_rxdma_rdc_rcr_tail_get failed");
+       }
+       
+       rcrtail_index = rcr_tail  - (uint32_t)(((uint64_t)rx_ring->rcr.rcr_addr.dma_addr & 0x7ffffULL) >> 3);
+
+       if (rcrtail_index >= rx_ring->rcr.rcr_curr_loc)
+               num_entries = rcrtail_index - rx_ring->rcr.rcr_curr_loc;
+       else
+               num_entries = rx_ring->rcr.num_rcr_entries - 
+                               (rx_ring->rcr.rcr_curr_loc - rcrtail_index);
+#endif
+
+#ifdef USE_MBOX
+
+       mboxp = (rxdma_mailbox_t *)rx_ring->mbox.vaddr;
+       mbox_rcrtail = mboxp->rcr_tail.bits.tail;
+       mbox_rcrtail = mbox_rcrtail - (uint32_t)(((uint64_t)rx_ring->rcr.rcr_addr.dma_addr & 0x7ffffULL) >> 3);
+       if (mbox_rcrtail >= rx_ring->rcr.rcr_curr_loc)
+               num_entries = mbox_rcrtail - rx_ring->rcr.rcr_curr_loc;
+       else
+               num_entries = rx_ring->rcr.num_rcr_entries - 
+                       (rx_ring->rcr.rcr_curr_loc - mbox_rcrtail);
+
+       if  (rx_ring->rbr.rbr_empty_flag) {
+               uint16_t qlen;
+               if (hpi_rxdma_rdc_rcr_qlen_get(handle, channel, &qlen) 
+                               != HPI_SUCCESS) {
+                       HXGE_ERR(hxgep, "qlen read failed for channel %i",channel);
+                       return RX_FAILURE;
+               }
+               HXGE_DBG(hxgep, "channel %d , qlen = %d",channel,qlen);
+               num_entries  = qlen;
+       }
+#endif
+
+       max_pkts = min(max_pkts, num_entries);
+       scan_pkts = scan_for_last_eop(rx_ring, num_entries);
+       max_pkts = min(max_pkts, scan_pkts);
+
+       if (!max_pkts) 
+               return RX_NO_ERR;
+
+       do {
+               rcr_entries_read = hxge_process_one_pkt(hxgep, rx_ring, skb_list);      
+               HXGE_DBG(hxgep, "%d rcr entries read",rcr_entries_read);
+               if (rcr_entries_read < 0) 
+                       break;
+
+               rcr_entries_processed += rcr_entries_read;
+               HXGE_DBG(hxgep, "%d rcr entries processed",rcr_entries_processed);
+       } while ((rcr_entries_read > 0) && (++pkts_processed < max_pkts));
+       
+       HXGE_DBG(hxgep, "%d pkts processed",pkts_processed);
+
+       if (rcr_entries_read <= 0) {
+               HXGE_ERR(hxgep, "Channel %d =>  ",channel);
+#ifdef USE_MBOX
+               HXGE_ERR(hxgep, "       MBOX Info");
+               HXGE_ERR(hxgep, "               RCR Tail(index) = %d",mbox_rcrtail);
+               HXGE_ERR(hxgep, "               RCR Qlen = %d",mboxp->rcr_qlen.bits.qlen);
+               parse_rdc_stat("MBOX RDC ", mboxp->rxdma_ctl_stat);
+#endif
+               parse_rdc_stat("PIO  RDC ", (rdc_stat_t)ldvp->data);
+               HXGE_ERR(hxgep, "       SW  RCR Head                = %d",rx_ring->rcr.rcr_curr_loc);
+               HXGE_ERR(hxgep, "       Num RCR Entries             = %d",num_entries);
+               HXGE_ERR(hxgep, "       Packets found scan_eop      = %d",scan_pkts);
+               HXGE_ERR(hxgep, "       RCR Entries Processed       = %d",rcr_entries_processed);
+               HXGE_ERR(hxgep, "       Num Packets Processed       = %d",pkts_processed);
+               HXGE_ERR(hxgep, "       RCR Entries Read (curr pkt) = %d",rcr_entries_read);
+               return RX_FAILURE;
+       }
+
+       if (hxgep->adaptive_rx)
+               RXDMA_REG_WRITE64(handle, RDC_RCR_CFG_B, channel, max_pkts << 16 | hxgep->rcr_cfgb_cpy);
+
+       /* CR 6769038 Workaround */
+
+       if (rx_ring->first_time && pkts_processed) {
+               pkts_processed--;
+               rx_ring->first_time--;
+       }
+
+
+       
+       /* Update the RDC Status/Control with packets and rcr entries read */
+       cs->bits.ptrread = rcr_entries_processed;
+       cs->bits.pktread = pkts_processed;
+       return pkts_processed;
+}
+
+void hxge_reset_rx_channel(struct hxge_adapter *hxgep, int rdc)
+{
+       struct rx_ring_t *rx_ring = &hxgep->rx_ring[rdc];
+
+       HXGE_ERR(hxgep, "Entering routine");
+       if (test_and_set_bit(RING_RESET, &rx_ring->state))
+               return;
+
+       spin_lock(&hxgep->lock);
+       hxge_disable_rx_channel(hxgep, rdc);
+       hxge_enable_rx_channel(hxgep, rdc);
+       spin_unlock(&hxgep->lock);
+
+       clear_bit(RING_RESET, &rx_ring->state);
+       HXGE_ERR(hxgep, "Exiting routine");
+}
+
+/* Called to update the cumulative Rx stats structure. This is later used 
+   to fill in the net_device_stats structure for higher level client such as
+   ifconfig */
+static void update_rx_err_stats(hpi_handle_t handle, struct rx_ring_t *rx_ring)
+{
+       struct rx_ring_stats_t *stats = &rx_ring->stats;
+        rdc_drop_count_t drop_cnt;
+
+        RXDMA_REG_READ64(handle, RDC_DROP_COUNT, rx_ring->rdc, &drop_cnt.value);
+
+       stats->pkt_too_long += drop_cnt.bits.too_long;
+       stats->no_rbr_avail += drop_cnt.bits.no_rbr_avail;
+       stats->rvm_errors += drop_cnt.bits.rvm_error;
+       stats->ram_errors += drop_cnt.bits.rxram_error;
+       stats->frame_errors += drop_cnt.bits.frame_error;
+
+       stats->ierrors += drop_cnt.bits.too_long
+               + drop_cnt.bits.no_rbr_avail
+               + drop_cnt.bits.rvm_error
+               + drop_cnt.bits.rxram_error
+               + drop_cnt.bits.frame_error;
+
+}
+
+
+/* Error handler, specifically for fatal errors. Report the error to the
+   system log. */
+static rdc_stat_t process_rx(struct hxge_ldv *ldvp, int *got_ldf1)
+{
+       struct hxge_adapter *hxgep = ldvp->ldgp->hxgep;
+        hpi_handle_t    handle = hxgep->hw.hw_addr;
+       rdc_stat_t      cs;
+       int channel = ldvp->ldv-HXGE_RDMA_LD_START;
+       struct rx_ring_t *rx_ring = &hxgep->rx_ring[channel];
+       struct rx_ring_stats_t *stats = &rx_ring->stats;
+       rdc_rbr_qlen_t rbr_qlen;
+
+       hpi_rxdma_control_status(handle, OP_GET, channel, &cs);
+       cs.bits.ptrread = 0;
+       cs.bits.pktread = 0;
+       hpi_rxdma_control_status(handle, OP_SET, channel, &cs);
+       ldvp->data = cs.value; /* Used to store npkts and nptrs later */
+
+       if (cs.bits.rcr_to)  
+               stats->rcr_to++;
+
+       if (cs.bits.rcr_thres) 
+               stats->rcr_thres++;
+
+       if (cs.value & RDC_LDF1) {
+               *got_ldf1 = 1;
+               if (cs.bits.rbr_cpl_to) {
+                       HXGE_ERR(hxgep, "Fatal Error: Response completion timeout from PEU");
+                       stats->rbr_cpl_tmout++;
+                       stats->ierrors++;
+               } 
+
+               if (cs.bits.peu_resp_err) {
+                       HXGE_ERR(hxgep, "Fatal Error: Poisoned completion from PEU");
+                       stats->peu_resp_err++;
+                       stats->ierrors++;
+               } 
+
+               if (cs.bits.rcr_shadow_par_err) {
+                       HXGE_ERR(hxgep, "Fatal Error: RCR shadow ram parity error");
+                       stats->rcr_shadow_parity++;
+                       stats->ierrors++;
+               } 
+
+               if (cs.bits.rbr_prefetch_par_err) {
+                       HXGE_ERR(hxgep, "Fatal Error: RBR prefetch parity error");
+                       stats->rcr_prefetch_parity++;
+                       stats->ierrors++;
+               }
+
+               if (cs.bits.rbr_pre_empty) {
+                       HXGE_ERR(hxgep, "Fatal Error: Not enough RBR buffers to prefetch!");
+                       stats->rbr_prefetch_empty++;
+                       stats->ierrors++;
+               }
+
+               if (cs.bits.rcr_shadow_full) {
+                       HXGE_ERR(hxgep, "Fatal Error: RCR Shadow Full");
+                       stats->rcr_shadow_full++;
+                       stats->ierrors++;
+               }
+
+               if (cs.bits.rcr_full) {
+                       HXGE_ERR(hxgep, "Fatal Error: No space in  RCR descriptor ring");
+                       stats->rcr_full++;
+                       stats->ierrors++;
+               }
+
+               /* Re-enable the DMA channel. But, before returing from the
+                  interrupt, process as many packets from the RCR as possible
+                  to minimize the number of these interrupts we will receive
+               */
+               if (cs.bits.rbr_empty) {
+                       rdc_rx_cfg1_t cfg;
+                       hpi_rxdma_rdc_rbr_qlen_get(handle, channel, &rbr_qlen);
+                       HXGE_DBG(hxgep, "Fatal Error: No more RBR buffers available for use, chan =  %d, qlen = %d",channel, rbr_qlen.bits.qlen);
+                       stats->rbr_empty++;
+                       stats->ierrors++;
+                       if (hpi_rxdma_cfg_rdc_wait_for_qst(handle, channel, &cfg,1)
+                                       != HPI_SUCCESS) {
+                               HXGE_ERR(hxgep, "qst bit did not quiet down");                           
+                       }
+                       else 
+                               rx_ring->rbr.rbr_empty_flag++;
+               }
+
+               if (cs.bits.rbr_full) {
+                       HXGE_ERR(hxgep, "Fatal Error: No space for more RBR buffers in hardware!");
+                       stats->rbr_full++;
+                       stats->ierrors++;
+               }
+
+               /* Update dropped-packets counts from Hydra's counters */
+               update_rx_err_stats(handle, rx_ring);
+       }
+
+       return cs;
+}
+
+#ifdef CONFIG_HXGE_NAPI
+/**
+ * hxge_poll  - NAPI Rx polling callback. This is called once for each
+ * device. So, this routine will have to go through and process the Rx
+ * packets from all the channels for the device. So, Rx interrupts for all
+ * channels must be disabled at this point. 
+ *
+ * work_to_do - Represents total work on this call of hxge_poll
+ * work_per_channel - divide the total work allowed equally between channels
+ *                   to avoid starvation
+ * work_in_last_iteration - used as an idicator that no more packets available
+ *                    across all channels. So, we can stop
+ * @adapter: board private structure
+ **/
+int
+hxge_poll(struct net_device *netdev, int *budget)
+{
+        struct hxge_adapter *hxgep = netdev->priv;
+        int work_to_do = min(*budget, netdev->quota);
+        int work_done = 0;
+       int work_per_channel;
+       struct hxge_ldgv *ldgvp = hxgep->ldgvp;
+       struct hxge_ldv *ldvp;
+       int got_ldf0, got_ldf1, pkt_cnt = 0, work_in_last_iteration;
+       
+
+       /* Go through each Rx channel and process packets received. If there
+           is an error, then reset the channel and continue with other channels
+          and then exit after all channels are processed. To avoid starving
+           a specific channel, we will equally budget the work_to_do across all
+           channels. If we have any left over, we will go through a second 
+          round till we hit the budget limit */
+
+       work_per_channel = work_to_do / hxgep->max_rdcs;
+       do {
+               rdc_stat_t cs;
+
+               work_in_last_iteration = 0;
+               list_for_each_entry (ldvp, &ldgvp->ldvp, list) {        
+                       if (ldvp->dev_type != LDV_RXDMA)
+                               continue;
+                       cs = process_rx(ldvp, &got_ldf1);
+                       pkt_cnt = hxge_process_packets(hxgep, 
+                                   work_per_channel, 
+                                   ldvp->ldv-HXGE_RDMA_LD_START,NULL);
+                       if (pkt_cnt < 0) {
+                               HXGE_ERR("hxge_process_packets failed");
+                               got_ldf1 = 1;
+                       } else /* keep count of packets processed */ {
+                               HXGE_DBG("Channel %d = Processed %d pkts",ldvp->ldv-HXGE_RDMA_LD_START,pkt_cnt);
+                               work_done += pkt_cnt; 
+                               work_in_last_iteration += pkt_cnt;
+                               work_to_do -= pkt_cnt;
+                       }
+                       if (got_ldf1)  {
+                               set_bit(RESET_RX_CHANNEL_0+ldvp->ldv-HXGE_RDMA_LD_START, &hxgep->work_q.command);
+                               schedule_work(&hxgep->work_to_do);
+                       }
+
+               }
+       } while ((work_in_last_iteration > 0) && (work_to_do > 0));
+
+
+       HXGE_DBG(hxgep, "Processed %d packets for all channels",work_done);
+        if ((work_to_do <= 0) || (work_in_last_iteration <= 0)) {
+                netif_rx_complete(netdev);
+                hxge_enable_rx_ints(hxgep, NULL, -1);
+                return 0;
+        }
+
+        /* still more Rx processing to do */
+        *budget -= work_done;
+        netdev->quota -= work_done;
+        return 1;
+}
+#endif
+
+/* Rx Interrupt handling. It can be called for each channel instance if they
+   assigned to separate LDGs. However, given the nature of NAPI handling
+   (a device can only be queued once to a given CPU; multiple instances of 
+   the same device cannot be queued, even to different CPUs), only one 
+   CPU at any given time handles a given device Rx channels. However, for
+   the non-NAPI case, multiple CPUs can be processing different channels 
+   Rx buffers at the same time. However, careful locking will be required 
+   when the skb is created and queued from different CPUs for the same
+   device */
+  
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+irqreturn_t hxge_rx_intr(int irq, void *data, struct pt_regs *regs)
+#else
+irqreturn_t hxge_rx_intr(int irq, void *data)
+#endif
+{
+       struct hxge_ldv *ldvp = (struct hxge_ldv *)data;
+        struct hxge_ldg *ldgp = ldvp->ldgp;
+       struct hxge_adapter *hxgep = ldgp->hxgep;
+#ifdef CONFIG_HXGE_NAPI
+        struct net_device *netdev = hxgep->netdev;
+#endif
+        int got_ldf0, got_ldf1;
+       int pkts_rcvd;
+       int channel = ldvp->ldv-HXGE_RDMA_LD_START;
+       rdc_stat_t cs;
+
+       get_ldf_flags(ldvp, &got_ldf0, &got_ldf1);
+       /* Check if this is our interrupt. If not, probably shared. So just
+           return and let other shared handlers check and take care of it */
+       if (!got_ldf0 && !got_ldf1)
+               return IRQ_NONE;
+
+#ifdef CONFIG_HXGE_NAPI
+       /* Go ahead and queue  device for processing later. However, ensure
+           that all Rx channel device interrupts are masked since the packets
+          that have arrived at all channels are processed at the same time
+           by one CPU */
+       if (likely(netif_rx_schedule_prep(netdev))) 
+       {
+               HXGE_DBG(hxgep, "Disable Rx Ints and schedule poll");
+               hxge_disable_rx_ints(hxgep, NULL, -1);
+                __netif_rx_schedule(netdev);
+       }
+#else
+       /* Process errors first. If fatal, then we reset the channel
+           instead of attempting to process packets */
+       cs = process_rx(ldvp, &got_ldf1);
+
+       /* If not fatal error (taken care of by the error routine), 
+          then go ahead and see if there are packets to be received. 
+          Note that Rx processing can be done by different CPUs for 
+          different channels.  hxge_process_packets must take care of 
+          synchronization in required areas */
+
+       if (unlikely(test_bit(HXGE_DEVICE_TESTING, &hxgep->state))) {
+               pkts_rcvd = hxge_process_packets(hxgep, ldvp, &ethtool_skb);
+               if (pkts_rcvd > 0) {
+                       HXGE_DBG(hxgep, "%d pkts rcvd",pkts_rcvd);
+                       ethtool_cond -= pkts_rcvd;
+               }
+               if (!ethtool_cond || (pkts_rcvd < 0))
+                       wake_up_interruptible(&ethtool_evnt);
+       } else
+               if (hxge_process_packets(hxgep, ldvp, NULL) < 0) {
+                       HXGE_ERR(hxgep, "hxge_process_packets failed");
+                       hxge_disable_rx_ints(hxgep, ldgp, channel);
+                       got_ldf1 = 1; /* fall through */
+       }
+
+       if (got_ldf1) {
+               hpi_handle_t handle = hxgep->hw.hw_addr;
+               struct rx_ring_t *rx_ring = &hxgep->rx_ring[channel];
+               
+               if (cs.bits.rbr_empty && rx_ring->rbr.rbr_empty_flag) {
+                       int i;
+                       HXGE_DBG(hxgep, "Posting %d buffers",rx_ring->rbr.rbr_empty_threshold);
+                       hpi_rxdma_rdc_rbr_kick(handle, channel, 
+                                       rx_ring->rbr.rbr_empty_threshold);
+                       rx_ring->stats.rbr_empty_posted += rx_ring->rbr.rbr_empty_threshold;
+                       rx_ring->rbr.rbr_empty_flag--;
+                       rx_ring->rbr.rbr_empty_threshold = 0;
+                       hxge_vmac_rx_set_framesize(hxgep, 1);
+                       HXGE_DBG(hxgep, "Disabled VMAC");
+                       if (hpi_rxdma_cfg_rdc_enable(handle, channel)
+                                                       != HPI_SUCCESS) {
+                               hxge_vmac_rx_set_framesize(hxgep, hxgep->vmac.rx_max_framesize);
+                               HXGE_ERR(hxgep, "hpi_rxdma_cfg_rdc_enable failed");
+                               set_bit(RESET_RX_CHANNEL_0+channel,
+                                                &hxgep->work_q.command);
+                               schedule_work(&hxgep->work_to_do);
+                               goto failed;
+                       } else {
+                               HXGE_DBG(hxgep, "Re-enabled RDC Channel %d",channel);
+                       }
+
+                       HXGE_DBG(hxgep, "Enabled the RDC Channel");
+                       /* a delay loop; forcing PIO reads to cause any 
+                        * preceding PIO writes to complete??
+                        */
+                       for (i = 0; i < 5; i++) 
+                               udelay(100);
+                       
+                       HXGE_DBG(hxgep, "Completed wait cycle");
+
+                       hxge_vmac_rx_set_framesize(hxgep, hxgep->vmac.rx_max_framesize);
+                       rx_ring->stats.rbr_empty_handled++;
+                       HXGE_DBG(hxgep, "Enabled VMAC");
+               } else {
+                       HXGE_ERR(hxgep, "Resetting on LDF1");
+                       /* Reset the channel. We do this for all fatal (LDF1) 
+                        * errors. We assume that the reset will clear out the 
+                        * error bits as well */
+                       set_bit(RESET_RX_CHANNEL_0+channel, 
+                               &hxgep->work_q.command);
+                       schedule_work(&hxgep->work_to_do);
+                       goto failed;
+               }
+       }
+       hxge_enable_rx_ints(hxgep, ldgp, channel);
+failed:
+#endif
+        return (IRQ_HANDLED);
+}
+
+
+
+/* Receive error interrupt handler
+ *
+ * Called from Device Error Interrupt (ldv 31) service, not RX DMA
+ *
+ * NB: *data is Device Error ldv 31, not an RX DMA channel ldv!
+ */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+irqreturn_t hxge_rx_deverr_intr(int irq, void *data, struct pt_regs *regs)
+#else
+irqreturn_t hxge_rx_deverr_intr(int irq, void *data)
+#endif
+{
+       struct hxge_ldv *ldvp = (struct hxge_ldv *)data; /* Device Error ldv */
+       struct hxge_adapter *hxgep = ldvp->ldgp->hxgep;
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+       rdc_fifo_err_stat_t sts, clr;
+       int hard_error = 0;
+
+       if (hpi_rx_fifo_status(handle, OP_GET, &sts) 
+               != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hpi_rx_fifo_status failed");
+       }
+
+       HXGE_ERR(hxgep, "RX hardware error interrupt (0x%16.16x)!",
+                (unsigned int)sts.value);
+
+       clr.value = sts.value;
+
+       if (sts.bits.rx_ctrl_fifo_sec) {
+               HXGE_ERR(hxgep, "rx_ctrl_fifo_sec");
+               hxgep->statsp->rx_ctrl_sec++;
+               hxgep->statsp->soft_errors++; /* Soft (recovered) dev error */
+               clr.bits.rx_ctrl_fifo_sec = 0;
+       }
+
+       if (sts.bits.rx_ctrl_fifo_ded) {
+               HXGE_ERR(hxgep, "rx_ctrl_fifo_ded");
+               hxgep->statsp->rx_ctrl_ded++;
+               hxgep->statsp->rx_ierrors++; /* Rx summary count */
+               hxgep->statsp->hard_errors++; /* Hard device error */
+               hard_error = TRUE;
+               clr.bits.rx_ctrl_fifo_ded = 0;
+       }
+
+       if (sts.bits.rx_data_fifo_sec) {
+               HXGE_ERR(hxgep, "rx_data_fifo_sec");
+               hxgep->statsp->rx_data_sec++;
+               hxgep->statsp->soft_errors++; /* Soft (recovered) dev error */
+               clr.bits.rx_data_fifo_sec = 0;
+       }
+
+       if (sts.bits.rx_data_fifo_ded) {
+               HXGE_ERR(hxgep, "rx_data_fifo_ded");
+               hxgep->statsp->rx_data_ded++;
+               hxgep->statsp->rx_ierrors++; /* Rx summary count */
+               hxgep->statsp->hard_errors++; /* Hard device error */
+               hard_error = TRUE;
+               clr.bits.rx_data_fifo_ded = 0;
+       }
+
+       if (clr.value) {
+               HXGE_ERR(hxgep, "Unknown/unexpected/reserved RDC_FIFO_ERR_STAT bits 0x%16.16x", (unsigned int)clr.value);
+               hxgep->statsp->hard_errors++; /* Unknown hard device error */
+               hard_error = TRUE; /* Whatever, it's bad; hammer something */
+       }
+
+       /* Now that we have "logged" the errors, try to recover from
+        * whatever happened.  Note that "SEC" (Single Bit ECC) is
+        * recovered by hardware, and needs no further action here.
+        */
+
+       /* Acknowledge (and clear) error status bits */
+
+       hpi_rx_fifo_status(handle, OP_SET, &sts);
+
+       /* Resume processing unless too many errors (hard or soft) */
+
+       if (hxge_ok_to_continue(hxgep)) {
+               if (hard_error) {
+                       /* Double-bit error, integrity lost, reset Rx */
+                       hxge_disable_rx_ints(hxgep, NULL, -1);
+                       set_bit(RESET_RDC, &hxgep->work_q.command);
+                       schedule_work(&hxgep->work_to_do);
+               } /* Else single-bit error, just dismiss and continue */
+       } else {
+               HXGE_ERR(hxgep, "Excessive hardware error rate");
+               HXGE_ERR(hxgep, "                      Taking hxge device down");
+               hxge_disable_interrupts(hxgep);
+               set_bit(SHUTDOWN_ADAPTER, &hxgep->work_q.command);
+               schedule_work(&hxgep->work_to_do);
+       }
+
+       return (IRQ_HANDLED);
+}
diff --git a/drivers/net/hxge/hxge_rxdma.h b/drivers/net/hxge/hxge_rxdma.h
new file mode 100644 (file)
index 0000000..8776e0f
--- /dev/null
@@ -0,0 +1,436 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#ifndef        _HXGE_HXGE_RXDMA_H
+#define        _HXGE_HXGE_RXDMA_H
+
+#include "hxge_rdc_hw.h"
+
+#define        RXDMA_CK_DIV_DEFAULT            7500    /* 25 usec */
+#define        RXDMA_RCR_PTHRES_DEFAULT        0x20
+#define        RXDMA_RCR_TO_DEFAULT            0x8
+#define        RXDMA_HDR_SIZE_DEFAULT          2
+#define        RXDMA_HDR_SIZE_FULL             6       /* entire header of 6B */
+
+/*
+ * Receive Completion Ring (RCR)
+ */
+#define        RCR_PKT_BUF_ADDR_SHIFT          0                       /* bit 37:0 */
+#define        RCR_PKT_BUF_ADDR_SHIFT_FULL     6       /* fulll buffer address */
+#define        RCR_PKT_BUF_ADDR_MASK           0x0000003FFFFFFFFFULL
+#define        RCR_PKTBUFSZ_SHIFT              38                      /* bit 39:38 */
+#define        RCR_PKTBUFSZ_MASK               0x000000C000000000ULL
+#define        RCR_L2_LEN_SHIFT                40                      /* bit 39:38 */
+#define        RCR_L2_LEN_MASK                 0x003fff0000000000ULL
+#define        RCR_ERROR_SHIFT                 54                      /* bit 57:55 */
+#define        RCR_ERROR_MASK                  0x03C0000000000000ULL
+#define        RCR_PKT_TYPE_SHIFT              61                      /* bit 62:61 */
+#define        RCR_PKT_TYPE_MASK               0x6000000000000000ULL
+#define        RCR_MULTI_SHIFT                 63                      /* bit 63 */
+#define        RCR_MULTI_MASK                  0x8000000000000000ULL
+
+#define        RCR_PKTBUFSZ_0                  0x00
+#define        RCR_PKTBUFSZ_1                  0x01
+#define        RCR_PKTBUFSZ_2                  0x02
+#define        RCR_SINGLE_BLOCK                0x03
+
+#define        RCR_NO_ERROR                    0x0
+#define        RCR_CTRL_FIFO_DED               0x1
+#define        RCR_DATA_FIFO_DED               0x2
+#define        RCR_ERROR_RESERVE               0x4
+
+#define RCR_PKT_TCP                    0x1
+#define RCR_PKT_UDP                    0x2
+#define        RCR_PKT_IS_TCP                  0x2000000000000000ULL
+#define        RCR_PKT_IS_UDP                  0x4000000000000000ULL
+#define        RCR_PKT_IS_SCTP                 0x6000000000000000ULL
+
+#define        RDC_INT_MASK_RBRFULL_SHIFT      34              /* bit 2: 0 to flag */
+#define        RDC_INT_MASK_RBRFULL_MASK       0x0000000400000000ULL
+#define        RDC_INT_MASK_RBREMPTY_SHIFT     35              /* bit 3: 0 to flag */
+#define        RDC_INT_MASK_RBREMPTY_MASK      0x0000000800000000ULL
+#define        RDC_INT_MASK_RCRFULL_SHIFT      36              /* bit 4: 0 to flag */
+#define        RDC_INT_MASK_RCRFULL_MASK       0x0000001000000000ULL
+#define        RDC_INT_MASK_RCRSH_FULL_SHIFT   39              /* bit 7: 0 to flag */
+#define        RDC_INT_MASK_RCRSH_FULL_MASK    0x0000008000000000ULL
+#define        RDC_INT_MASK_RBR_PRE_EMPTY_SHIFT        40      /* bit 8: 0 to flag */
+#define        RDC_INT_MASK_RBR_PRE_EMPTY_MASK 0x0000010000000000ULL
+#define        RDC_INT_MASK_RCR_SHA_PAR_SHIFT  43              /* bit 12: 0 to flag */
+#define        RDC_INT_MASK_RCR_SHA_PAR_MASK   0x0000080000000000ULL
+#define        RDC_INT_MASK_RBR_PRE_PAR_SHIFT  44              /* bit 11: 0 to flag */
+#define        RDC_INT_MASK_RBR_PRE_PAR_MASK   0x0000100000000000ULL
+#define        RDC_INT_MASK_RCRTO_SHIFT        45              /* bit 13: 0 to flag */
+#define        RDC_INT_MASK_RCRTO_MASK         0x0000200000000000ULL
+#define        RDC_INT_MASK_THRES_SHIFT        46              /* bit 14: 0 to flag */
+#define        RDC_INT_MASK_THRES_MASK         0x0000400000000000ULL
+#define        RDC_INT_MASK_RBR_CPL_SHIFT      53              /* bit 21: 0 to flag */
+#define        RDC_INT_MASK_RBR_CPL_MASK       0x0020000000000000ULL
+#define        RDC_INT_MASK_ALL        (RDC_INT_MASK_RBRFULL_MASK |            \
+                               RDC_INT_MASK_RBREMPTY_MASK |            \
+                               RDC_INT_MASK_RCRFULL_MASK |             \
+                               RDC_INT_MASK_RCRSH_FULL_MASK |          \
+                               RDC_INT_MASK_RBR_PRE_EMPTY_MASK |       \
+                               RDC_INT_MASK_RCR_SHA_PAR_MASK |         \
+                               RDC_INT_MASK_RBR_PRE_PAR_MASK |         \
+                               RDC_INT_MASK_RCRTO_MASK |               \
+                               RDC_INT_MASK_THRES_MASK |               \
+                               RDC_INT_MASK_RBR_CPL_MASK)
+
+#define        RDC_LDF1                (RDC_INT_MASK_RBRFULL_MASK |            \
+                               RDC_INT_MASK_RBREMPTY_MASK |            \
+                               RDC_INT_MASK_RCRFULL_MASK |             \
+                               RDC_INT_MASK_RCRSH_FULL_MASK |          \
+                               RDC_INT_MASK_RBR_PRE_EMPTY_MASK |       \
+                               RDC_INT_MASK_RCR_SHA_PAR_MASK |         \
+                               RDC_INT_MASK_RBR_PRE_PAR_MASK |         \
+                               RDC_INT_MASK_RBR_CPL_MASK)
+                               
+
+#define        RDC_STAT_PKTREAD_SHIFT                  0       /* WO, bit 15:0 */
+#define        RDC_STAT_PKTREAD_MASK                   0x000000000000ffffULL
+#define        RDC_STAT_PTRREAD_SHIFT                  16      /* WO, bit 31:16 */
+#define        RDC_STAT_PTRREAD_MASK                   0x00000000FFFF0000ULL
+
+#define        RDC_STAT_RBRFULL_SHIFT                  34      /* RO, bit 34 */
+#define        RDC_STAT_RBRFULL                        0x0000000400000000ULL
+#define        RDC_STAT_RBRFULL_MASK                   0x0000000400000000ULL
+#define        RDC_STAT_RBREMPTY_SHIFT                 35      /* RW1C, bit 35 */
+#define        RDC_STAT_RBREMPTY                       0x0000000800000000ULL
+#define        RDC_STAT_RBREMPTY_MASK                  0x0000000800000000ULL
+#define        RDC_STAT_RCR_FULL_SHIFT                 36      /* RW1C, bit 36 */
+#define        RDC_STAT_RCR_FULL                       0x0000001000000000ULL
+#define        RDC_STAT_RCR_FULL_MASK                  0x0000001000000000ULL
+
+#define        RDC_STAT_RCR_SHDW_FULL_SHIFT            39      /* RO, bit 39 */
+#define        RDC_STAT_RCR_SHDW_FULL                  0x0000008000000000ULL
+#define        RDC_STAT_RCR_SHDW_FULL_MASK             0x0000008000000000ULL
+#define        RDC_STAT_RBR_PRE_EMPTY_SHIFT            40      /* RO, bit 40 */
+#define        RDC_STAT_RBR_PRE_EMPTY                  0x0000010000000000ULL
+#define        RDC_STAT_RBR_PRE_EMPTY_MASK             0x0000010000000000ULL
+
+#define        RDC_STAT_RCR_SHA_PAR_SHIFT              43      /* RO, bit 43 */
+#define        RDC_STAT_RCR_SHA_PAR                    0x0000080000000000ULL
+#define        RDC_STAT_RCR_SHA_PAR_MASK               0x0000080000000000ULL
+#define        RDC_STAT_RBR_PRE_PAR_SHIFT              44      /* RO, bit 44 */
+#define        RDC_STAT_RBR_PRE_PAR                    0x0000100000000000ULL
+#define        RDC_STAT_RBR_PRE_PAR_MASK               0x0000100000000000ULL
+
+#define        RDC_STAT_RCR_TO_SHIFT                   45      /* RW1C, bit 45 */
+#define        RDC_STAT_RCR_TO                         0x0000200000000000ULL
+#define        RDC_STAT_RCR_TO_MASK                    0x0000200000000000ULL
+#define        RDC_STAT_RCR_THRES_SHIFT                46      /* RO, bit 46 */
+#define        RDC_STAT_RCR_THRES                      0x0000400000000000ULL
+#define        RDC_STAT_RCR_THRES_MASK                 0x0000400000000000ULL
+#define        RDC_STAT_RCR_MEX_SHIFT                  47      /* RW, bit 47 */
+#define        RDC_STAT_RCR_MEX                        0x0000800000000000ULL
+#define        RDC_STAT_RCR_MEX_MASK                   0x0000800000000000ULL
+
+#define        RDC_STAT_RBR_CPL_SHIFT                  53      /* RO, bit 53 */
+#define        RDC_STAT_RBR_CPL                        0x0020000000000000ULL
+#define        RDC_STAT_RBR_CPL_MASK                   0x0020000000000000ULL
+#define        RX_DMA_CTRL_STAT_ENT_MASK_SHIFT         32
+
+#define        RDC_STAT_ERROR                          (RDC_INT_MASK_ALL << \
+                                               RX_DMA_CTRL_STAT_ENT_MASK_SHIFT)
+
+/* the following are write 1 to clear bits */
+#define        RDC_STAT_WR1C           (RDC_STAT_RBREMPTY |            \
+                               RDC_STAT_RCR_SHDW_FULL |        \
+                               RDC_STAT_RBR_PRE_EMPTY |        \
+                               RDC_STAT_RCR_TO |               \
+                               RDC_STAT_RCR_THRES)
+
+#define RCR_CFGB_ENABLE_TIMEOUT        0x8000
+
+typedef union _rcr_entry_t {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t multi:1;
+               uint64_t pkt_type:2;
+               uint64_t reserved1:3;
+               uint64_t error:3;
+               uint64_t reserved2:1;
+               uint64_t l2_len:14;
+               uint64_t pktbufsz:2;
+               uint64_t pkt_buf_addr:38;
+#else
+               uint64_t pkt_buf_addr:38;
+               uint64_t pktbufsz:2;
+               uint64_t l2_len:14;
+               uint64_t reserved2:1;
+               uint64_t error:3;
+               uint64_t reserved1:3;
+               uint64_t pkt_type:2;
+               uint64_t multi:1;
+#endif
+       } bits;
+} rcr_entry_t, *p_rcr_entry_t;
+
+typedef union _pkt_hdr_twobyte_t {
+       uint16_t value;
+       struct {
+#if defined (_BIG_ENDIAN)
+               uint16_t rsvd:1;
+               uint16_t l4_cs_eq:1;
+               uint16_t maccheck:1;
+               uint16_t class:5;
+               uint16_t vlan:1;
+               uint16_t bcast_frame:1;
+               uint16_t noport:1;
+               uint16_t badip:1;
+               uint16_t tcamhit:1;
+               uint16_t drop_code:3;
+#else
+               uint16_t drop_code:3;
+               uint16_t tcamhit:1;
+               uint16_t badip:1;
+               uint16_t noport:1;
+               uint16_t bcast_frame:1;
+               uint16_t vlan:1;
+               uint16_t class:5;
+               uint16_t maccheck:1;
+               uint16_t l4_cs_eq:1;
+               uint16_t rsvd:1;
+#endif
+       } bits;
+} pkt_hdr_twobyte_t, *p_pkt_hdr_twobyte_t;
+               
+
+#define        RX_DMA_MAILBOX_BYTE_LENGTH      64
+#define        RX_DMA_MBOX_UNUSED_1            8
+#define        RX_DMA_MBOX_UNUSED_2            16
+
+typedef struct _rxdma_mailbox_t {
+       rdc_stat_t              rxdma_ctl_stat;         /* 8 bytes */
+       rdc_rbr_qlen_t          rbr_qlen;               /* 8 bytes */
+       rdc_rbr_head_t          rbr_hdh;                /* 8 bytes */
+       uint8_t                 resv_1[RX_DMA_MBOX_UNUSED_1];
+       rdc_rcr_tail_t          rcr_tail;               /* 8 bytes */
+       uint8_t                 resv_2[RX_DMA_MBOX_UNUSED_1];
+       rdc_rcr_qlen_t          rcr_qlen;               /* 8 bytes */
+       uint8_t                 resv_3[RX_DMA_MBOX_UNUSED_1];
+} rxdma_mailbox_t, *p_rxdma_mailbox_t;
+
+/*
+ * hardware workarounds: kick 16 (was 8 before)
+ */
+#define        HXGE_RXDMA_POST_BATCH           16
+
+#define        RXBUF_START_ADDR(a, index, bsize)       ((a & (index * bsize))
+#define        RXBUF_OFFSET_FROM_START(a, start)       (start - a)
+#define        RXBUF_64B_ALIGNED               64
+
+#define        HXGE_RXBUF_EXTRA                34
+
+/*
+ * Receive buffer thresholds and buffer types
+ */
+#define        HXGE_RX_BCOPY_SCALE     8       /* use 1/8 as lowest granularity */
+
+typedef enum  {
+       HXGE_RX_COPY_ALL = 0,           /* do bcopy on every packet      */
+       HXGE_RX_COPY_1,                 /* bcopy on 1/8 of buffer posted */
+       HXGE_RX_COPY_2,                 /* bcopy on 2/8 of buffer posted */
+       HXGE_RX_COPY_3,                 /* bcopy on 3/8 of buffer posted */
+       HXGE_RX_COPY_4,                 /* bcopy on 4/8 of buffer posted */
+       HXGE_RX_COPY_5,                 /* bcopy on 5/8 of buffer posted */
+       HXGE_RX_COPY_6,                 /* bcopy on 6/8 of buffer posted */
+       HXGE_RX_COPY_7,                 /* bcopy on 7/8 of buffer posted */
+       HXGE_RX_COPY_NONE               /* don't do bcopy at all         */
+} hxge_rxbuf_threshold_t;
+
+typedef enum  {
+       HXGE_RBR_TYPE0 = RCR_PKTBUFSZ_0,  /* bcopy buffer size 0 (small) */
+       HXGE_RBR_TYPE1 = RCR_PKTBUFSZ_1,  /* bcopy buffer size 1 (medium) */
+       HXGE_RBR_TYPE2 = RCR_PKTBUFSZ_2   /* bcopy buffer size 2 (large) */
+} hxge_rxbuf_type_t;
+
+typedef        struct _rdc_errlog {
+       rdc_pref_par_log_t      pre_par;
+       rdc_pref_par_log_t      sha_par;
+       uint8_t                 compl_err_type;
+} rdc_errlog_t;
+
+
+
+/* RBR Descriptor entries are 4-bytes long */
+typedef uint32_t rbr_desc_entry_t;
+
+struct rx_desc_t {
+       caddr_t         vaddr;
+       dma_addr_t    dma_addr;
+};
+
+struct rx_hash_entry {
+       unsigned long dma_addr;
+       int index;
+       struct rx_hash_entry *next;
+};
+
+
+/* Receive Completion Ring */
+typedef struct _rx_rcr_ring_t {
+
+        uint32_t                num_rcr_entries;
+        struct rcr_desc_t {
+               rcr_entry_t     *vaddr;
+               dma_addr_t      dma_addr;
+        } rcr_addr;
+
+       /* Current location where processing is to take place next */
+       uint32_t                rcr_curr_loc;
+
+        /* Copies of HW registers */
+        rdc_rcr_cfg_a_t         rcr_cfga;
+        rdc_rcr_cfg_b_t         rcr_cfgb;
+        boolean_t               cfg_set;
+} rx_rcr_ring_t, *p_rx_rcr_ring_t;
+
+
+struct rx_rbr_entry_t {
+       struct rbr_desc_addr_t {
+               rbr_desc_entry_t *vaddr;
+               dma_addr_t      dma_addr;
+       } addr;
+       int                     index;
+       struct page             *page;
+       uint32_t                max_pkts;
+       uint32_t                pkt_size;
+       int                     in_use;
+};
+
+
+struct rx_ring_stats_t {
+       /* Maintained by software */
+
+       uint64_t        ipackets;
+       uint64_t        ibytes;
+       uint64_t        ierrors;
+       uint64_t        jumbo_pkts;
+       uint64_t        nomem_drop;
+
+       uint64_t        ecc_errors;
+
+       uint64_t        rbr_cpl_tmout;
+       uint64_t        peu_resp_err;
+       uint64_t        rcr_shadow_parity;
+       uint64_t        rcr_prefetch_parity;
+       uint64_t        rbr_prefetch_empty;
+       uint64_t        rcr_shadow_full;
+       uint64_t        rcr_full;
+       uint64_t        rbr_empty;
+       uint64_t        rbr_empty_handled;
+       uint64_t        rbr_empty_posted;
+       uint64_t        rbr_full;
+       uint64_t        rcr_to;
+       uint64_t        rcr_thres;
+
+       /* Hardware counters */
+       uint64_t        pkt_cnt; 
+       uint64_t        pkt_too_long;
+       uint64_t        no_rbr_avail;
+       uint64_t        rvm_errors;
+       uint64_t        frame_errors;
+       uint64_t        ram_errors;
+
+       uint64_t        crc_errors;
+       
+};
+
+
+typedef struct _rx_rbr_ring_t {
+
+       struct rx_rbr_entry_t   *buf_blocks;
+       struct rbr_desc_t {
+               rbr_desc_entry_t *vaddr;
+               dma_addr_t       dma_addr;
+       } rbr_addr;
+       unsigned int            buf_blocks_order;
+       uint32_t                num_rbr_entries;
+       uint32_t                rbr_free_loc;
+       uint32_t                pages_to_post;
+       uint16_t                rbr_empty_threshold;
+       uint16_t                rbr_empty_flag;  /* we are in empty procesing */
+       struct rx_hash_entry *hash_table[HASH_TABLE_SIZE];
+       
+       
+       /* Copies of what is in the HW registers */
+        rdc_rbr_cfg_a_t         rbr_cfga;
+        rdc_rbr_cfg_b_t         rbr_cfgb;
+        rdc_rbr_kick_t          rbr_kick;
+       boolean_t               cfg_set;
+
+       /* what goes into RBR Configuration B register */
+        uint16_t                 pkt_buf_size[4];
+        uint16_t                 pkt_buf_size_bytes[4];
+} rx_rbr_ring_t, *p_rx_rbr_ring_t;
+
+struct rx_ring_t {
+       uint16_t                rdc;
+
+       /* Copies of some HW register */
+        rdc_page_handle_t       page_hdl;
+       uint16_t                offset;
+       boolean_t               full_hdr;
+       unsigned long           state;
+
+       rx_rbr_ring_t           rbr;
+       rx_rcr_ring_t           rcr;
+       struct rx_desc_t        mbox;
+       uint16_t                dma_clk_res;
+       int                     first_time; /* CR 6769038 */
+       struct rx_ring_stats_t  stats;
+
+};
+
+#define RX_NO_ERR       0
+#define RX_DROP_PKT    -1
+#define RX_FAILURE     -2
+
+#define RCR_INIT_PATTERN       0x5a5a6b6b7c7c8d8dULL
+
+#define GET_RCR_ENTRY(entry) \
+       &entry->rcr_addr.vaddr[entry->rcr_curr_loc]
+
+/* SW workaround for CR 6698258: One of the side effects of this bug is to
+ * push rcr entries that have already been processed, causing the packet 
+ * processing routines to complain about "bad packets". Hydra could flush
+ * 64B cache line into memory at particular junctures (see bug for details).
+ * In order to avoid getting old packet addresses, we should initialize 
+ * the entire cache line once we have processed the last entry in a cache
+ * line (rcr_ring is aligned to 64B)
+ */
+#define INCREMENT_RCR_ENTRY_TO_NEXT(rcr_ring) \
+       { \
+        if ((rcr_ring->rcr_curr_loc & 0x7) == 0x7) { \
+                uint32_t tmp_loc = rcr_ring->rcr_curr_loc- 7; \
+                int i; \
+                for (i = 0; i < 8; i++) \
+                        rcr_ring->rcr_addr.vaddr[tmp_loc+i].value = RCR_INIT_PATTERN; \
+        } \
+       rcr_ring->rcr_curr_loc = (rcr_ring->rcr_curr_loc+1) % rcr_ring->num_rcr_entries; \
+       }
+#endif 
diff --git a/drivers/net/hxge/hxge_stats.c b/drivers/net/hxge/hxge_stats.c
new file mode 100644 (file)
index 0000000..0701f97
--- /dev/null
@@ -0,0 +1,104 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#include "hxge.h"
+
+void
+hxge_init_stats(struct hxge_adapter *hxgep)
+{
+       HXGE_DBG(hxgep, "Initializing statistics");
+        hxgep->statsp = kzalloc(sizeof(hxge_stats_t), GFP_KERNEL);
+}
+
+void
+hxge_free_stats(struct hxge_adapter *hxgep)
+{
+       HXGE_DBG(hxgep, "Free statistics");
+       if (hxgep->statsp) 
+               kfree(hxgep->statsp);
+       hxgep->statsp = NULL;
+}
+
+
+/* Get the Hydra network statistics and package the information in a format
+ * that can displayed by the OS network layer */
+struct net_device_stats *
+hxge_get_stats (struct net_device *netdev)
+{
+        struct hxge_adapter *hxgep= netdev_priv(netdev);
+        struct net_device_stats  *stats = &hxgep->net_stats;
+        struct rx_ring_t *rx_ring;
+        struct tx_ring_t *tx_ring;
+        int i;
+       hxge_vmac_stats_t *vmac_stats = &hxgep->statsp->vmac_stats;
+       
+        spin_lock(&hxgep->stats_lock);
+
+        memset(stats, 0, sizeof(struct net_device_stats));
+
+        for (i = 0, rx_ring=&hxgep->rx_ring[i];
+            rx_ring && i < hxgep->max_rdcs;
+            i++, rx_ring=&hxgep->rx_ring[i]) {
+                stats->rx_packets += rx_ring->stats.ipackets;
+                stats->rx_bytes   += rx_ring->stats.ibytes;
+                stats->rx_errors  += rx_ring->stats.ierrors;
+
+                /* Various reasons for dropped packets */
+                stats->rx_dropped += rx_ring->stats.pkt_too_long
+                       + rx_ring->stats.no_rbr_avail
+                       + rx_ring->stats.rvm_errors
+                       + rx_ring->stats.frame_errors
+                       + rx_ring->stats.ram_errors 
+                       + rx_ring->stats.nomem_drop
+                       + vmac_stats->rx_drop_frame_cnt;
+                             
+                stats->rx_frame_errors += rx_ring->stats.frame_errors;
+                stats->rx_crc_errors += rx_ring->stats.crc_errors;
+                stats->rx_over_errors += rx_ring->stats.no_rbr_avail;
+                stats->rx_length_errors += rx_ring->stats.pkt_too_long;
+        }
+
+       /* Account for non-channel-specific RX errors */
+       stats->rx_errors += hxgep->statsp->rx_ierrors
+               + hxgep->statsp->peu_errors; /* Count PEU as "RX" for now */
+
+        for (i = 0, tx_ring=&hxgep->tx_ring[i];
+            tx_ring && i < hxgep->max_tdcs;
+            i++, tx_ring=&hxgep->tx_ring[i]) {
+               stats->tx_packets += tx_ring->stats.opackets;
+               stats->tx_bytes   += tx_ring->stats.obytes;
+               stats->tx_errors  += tx_ring->stats.oerrors;
+               stats->tx_dropped += tx_ring->stats.hdr_error_cnt
+                       + tx_ring->stats.abort_cnt
+                       + tx_ring->stats.runt_cnt;
+       }
+
+       /* Account for non-channel-specific TX errors */
+       stats->tx_errors += hxgep->statsp->tx_oerrors;
+
+        spin_unlock(&hxgep->stats_lock);
+
+        return stats;
+}
diff --git a/drivers/net/hxge/hxge_sysfs.c b/drivers/net/hxge/hxge_sysfs.c
new file mode 100644 (file)
index 0000000..36ed679
--- /dev/null
@@ -0,0 +1,112 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#include "hxge.h"
+#include <linux/sysfs.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+#define DEV_TYPE  class_device
+#define to_net_dev(class) container_of(class, struct net_device, class_dev)
+static ssize_t errinject_show(struct class_device *, char *);
+static ssize_t errinject_store(struct class_device *, const char *, size_t);
+static CLASS_DEVICE_ATTR(errinject, S_IWUSR | S_IRUGO, errinject_show, errinject_store);
+#else
+#define DEV_TYPE device
+static ssize_t errinject_show(struct device *, struct device_attribute *, 
+                               char *);
+static ssize_t errinject_store(struct device *, struct device_attribute *, 
+                               const char *, size_t);
+DEVICE_ATTR(errinject, S_IWUSR | S_IRUGO, errinject_show, errinject_store);
+#endif
+
+
+static ssize_t errinject_show (struct DEV_TYPE *dev, 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
+                               struct device_attribute *attr,
+#endif
+                               char *buf)
+{
+       struct hxge_adapter *hxgep = netdev_priv(to_net_dev(dev));
+       
+       return (sprintf(buf, "%#lx\n", hxgep->err_flags));
+}
+
+static ssize_t errinject_store (struct DEV_TYPE *dev,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
+                               struct device_attribute *attr,
+#endif
+                               const char *buf,
+                               size_t len)
+{
+       unsigned long val;
+       char *endp;
+       struct hxge_adapter *hxgep = netdev_priv(to_net_dev(dev));
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       val = simple_strtoul(buf, &endp, 16);
+       if (endp == buf)
+               return -EINVAL;
+
+       HXGE_ERR(hxgep, "val is 0x%lx, len = %d", val, (int)len);
+       spin_lock(&hxgep->lock);
+       hxgep->err_flags = val;
+       spin_unlock(&hxgep->lock);
+       HXGE_ERR(hxgep, "Setting err_flags to 0x%lx", hxgep->err_flags);
+       return len;
+       
+}
+
+
+int hxge_create_sysfs(struct net_device *netdev)
+{
+       struct DEV_TYPE *dev;
+       int ret;
+
+       printk(KERN_DEBUG "Creating errinject device file.. \n");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+       dev = &netdev->class_dev;
+       ret = class_device_create_file(dev, &class_device_attr_errinject);
+#else
+       dev = &netdev->dev;
+       ret = device_create_file(dev, &dev_attr_errinject);
+#endif
+       return ret;
+}
+
+void hxge_remove_sysfs(struct net_device *netdev)
+{
+       struct DEV_TYPE *dev;
+
+       printk(KERN_DEBUG "Removing errinject device.. \n");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+       dev = &netdev->class_dev;
+       class_device_remove_file(dev, &class_device_attr_errinject);
+#else
+       dev = &netdev->dev;
+       device_remove_file(dev, &dev_attr_errinject);
+#endif
+}
diff --git a/drivers/net/hxge/hxge_tdc_hw.h b/drivers/net/hxge/hxge_tdc_hw.h
new file mode 100644 (file)
index 0000000..f2425f3
--- /dev/null
@@ -0,0 +1,1384 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#ifndef        _HXGE_TDC_HW_H
+#define        _HXGE_TDC_HW_H
+
+#define        TDC_BASE_ADDR                           0X00400000
+
+#define        TDC_PAGE_HANDLE                         (TDC_BASE_ADDR + 0x8)
+#define        TDC_TDR_CFG                             (TDC_BASE_ADDR + 0x20)
+#define        TDC_TDR_HEAD                            (TDC_BASE_ADDR + 0x28)
+#define        TDC_TDR_PRE_HEAD                        (TDC_BASE_ADDR + 0x30)
+#define        TDC_TDR_KICK                            (TDC_BASE_ADDR + 0x38)
+#define        TDC_INT_MASK                            (TDC_BASE_ADDR + 0x40)
+#define        TDC_STAT                                (TDC_BASE_ADDR + 0x48)
+#define        TDC_MBH                                 (TDC_BASE_ADDR + 0x50)
+#define        TDC_MBL                                 (TDC_BASE_ADDR + 0x58)
+#define        TDC_BYTE_CNT                            (TDC_BASE_ADDR + 0x80)
+#define        TDC_TDR_QLEN                            (TDC_BASE_ADDR + 0x88)
+#define        TDC_RTAB_PTR                            (TDC_BASE_ADDR + 0x90)
+#define        TDC_DROP_CNT                            (TDC_BASE_ADDR + 0x98)
+#define        TDC_LAST_PKT_RBUF_PTRS                  (TDC_BASE_ADDR + 0xA8)
+#define        TDC_PREF_CMD                            (TDC_BASE_ADDR + 0x100)
+#define        TDC_PREF_DATA                           (TDC_BASE_ADDR + 0x108)
+#define        TDC_PREF_PAR_DATA                       (TDC_BASE_ADDR + 0x110)
+#define        TDC_REORD_BUF_CMD                       (TDC_BASE_ADDR + 0x120)
+#define        TDC_REORD_BUF_DATA                      (TDC_BASE_ADDR + 0x128)
+#define        TDC_REORD_BUF_ECC_DATA                  (TDC_BASE_ADDR + 0x130)
+#define        TDC_REORD_TBL_CMD                       (TDC_BASE_ADDR + 0x140)
+#define        TDC_REORD_TBL_DATA_LO                   (TDC_BASE_ADDR + 0x148)
+#define        TDC_REORD_TBL_DATA_HI                   (TDC_BASE_ADDR + 0x150)
+#define        TDC_PREF_PAR_LOG                        (TDC_BASE_ADDR + 0x200)
+#define        TDC_REORD_BUF_ECC_LOG                   (TDC_BASE_ADDR + 0x208)
+#define        TDC_REORD_TBL_PAR_LOG                   (TDC_BASE_ADDR + 0x210)
+#define        TDC_FIFO_ERR_MASK                       (TDC_BASE_ADDR + 0x220)
+#define        TDC_FIFO_ERR_STAT                       (TDC_BASE_ADDR + 0x228)
+#define        TDC_FIFO_ERR_INT_DBG                    (TDC_BASE_ADDR + 0x230)
+#define        TDC_STAT_INT_DBG                        (TDC_BASE_ADDR + 0x240)
+#define        TDC_PKT_REQ_TID_TAG                     (TDC_BASE_ADDR + 0x250)
+#define        TDC_SOP_PREF_DESC_LOG                   (TDC_BASE_ADDR + 0x260)
+#define        TDC_PREF_DESC_LOG                       (TDC_BASE_ADDR + 0x268)
+#define        TDC_PEU_TXN_LOG                         (TDC_BASE_ADDR + 0x270)
+#define        TDC_DBG_TRAINING_VEC                    (TDC_BASE_ADDR + 0x300)
+#define        TDC_DBG_GRP_SEL                         (TDC_BASE_ADDR + 0x308)
+
+
+/*
+ * Register: TdcPageHandle
+ * Logical Page Handle
+ * Description: Upper 20 bits [63:44] to use for all accesses over
+ * the PCI-E bus. Fields in this register are part of the dma
+ * configuration and cannot be changed once the dma is enabled.
+ * Fields:
+ *     Page handle, bits [63:44] of all PCI-E transactions for this
+ *     channel.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:44;
+               uint64_t        page_handle:20;
+#else
+               uint64_t        page_handle:20;
+               uint64_t        rsrvd:44;
+#endif
+       } bits;
+} tdc_page_handle_t;
+
+
+/*
+ * Register: TdcTdrCfg
+ * Transmit Ring Configuration
+ * Description: Configuration parameters for transmit DMA block.
+ * Software configures the location of the transmit ring in host
+ * memory, as well as its maximum size. Fields in this register are
+ * part of the dma configuration and cannot be changed once the dma
+ * is enabled.
+ * HW does not check for all configuration errors across different
+ * fields.
+ * The usage of enable, reset, and qst is as follows. Software
+ * should use the following sequence to reset a DMA channel. First,
+ * set DMA.enable to 0, wait for DMA.qst=1 and then, set DMA.reset to
+ * 1. After DMA.reset is cleared by hardware and the DMA.qst is set
+ * to 1, software may then start configuring the DMA channel. The
+ * DMA.enable can be set or cleared while the DMA is in operation.
+ * The state machines of the DMA may not have returned to its initial
+ * states yet after the DMA.enable bit is cleared. This condition is
+ * indicated by the value of the DMA.qst. An example of DMA.enable
+ * being cleared during operation is when a fatal error occurs.
+ * Fields:
+ *     Bits [15:5] of the maximum number of entries in the Transmit
+ *     Queue ring buffer. Bits [4:0] are always 0. Maximum number of
+ *     entries is (2^16 - 32) and is limited by the staddr value.
+ *     (len + staddr) should not exceed (2^16 - 32).
+ *     Set to 1 to enable the Transmit DMA. On fatal errors, this bit
+ *     will be cleared by hardware. This bit cannot be set if sw has
+ *     not resolved any pending fatal error condition: i.e. any
+ *     TdcStat ldf1 error bits remain set.
+ *     Set to 1 to reset the DMA. Hardware will clear this bit after
+ *     reset is completed. A reset will bring the sepecific DMA back
+ *     to the power on state (including the DMA.en in this register).
+ *     When set to 1, it indicates all state associated with the DMA
+ *     are in its initial state following either dma reset or
+ *     disable. Thus, once this is set to 1, sw could start to
+ *     configure the DMA if needed. In an extreme case such as if a
+ *     parity error on an EOP descriptor prevents recognition of the
+ *     EOP, it is possible that the qst bit will not be set even
+ *     though the dma engine has been disabled.
+ *     Address bits [43:19] of the start address for the transmit
+ *     ring buffer. The value in this field is dependent on len
+ *     field. (len + staddr) should not exceed (2^16 - 32).
+ *     Bits [18:6] of the start address for the transmit ring buffer.
+ *     Bits [5:0] are assumed to be zero, or 64B aligned.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        len:11;
+               uint64_t        rsrvd:5;
+               uint64_t        enable:1;
+               uint64_t        reset:1;
+               uint64_t        qst:1;
+               uint64_t        rsrvd1:1;
+               uint64_t        staddr_base:25;
+               uint64_t        staddr:13;
+               uint64_t        rsrvd2:6;
+#else
+               uint64_t        rsrvd2:6;
+               uint64_t        staddr:13;
+               uint64_t        staddr_base:25;
+               uint64_t        rsrvd1:1;
+               uint64_t        qst:1;
+               uint64_t        reset:1;
+               uint64_t        enable:1;
+               uint64_t        rsrvd:5;
+               uint64_t        len:11;
+#endif
+       } bits;
+} tdc_tdr_cfg_t;
+
+
+/*
+ * Register: TdcTdrHead
+ * Transmit Ring Head
+ * Description: Read-only register software call poll to determine
+ * the current head of the transmit ring, from the tdcTxPkt block.
+ * Software uses this to know which Tdr entries have had their
+ * descriptors transmitted. These entries and their descriptors may
+ * then be reused by software.
+ * Fields:
+ *     Hardware will toggle this bit every time the head is wrapped
+ *     around the configured ring buffer.
+ *     Entry in transmit ring which will be the next descriptor
+ *     transmitted. Software should consider the Tdr full if head ==
+ *     TdcTdrKick::tail and wrap != TdcTdrKick::wrap. The ring is
+ *     empty of head == TdcTdrKick::tail and wrap ==
+ *     TdcTdrKick::wrap.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:47;
+               uint64_t        wrap:1;
+               uint64_t        head:16;
+#else
+               uint64_t        head:16;
+               uint64_t        wrap:1;
+               uint64_t        rsrvd:47;
+#endif
+       } bits;
+} tdc_tdr_head_t;
+
+
+/*
+ * Register: TdcTdrPreHead
+ * Transmit Ring Prefetch Head
+ * Description: Read-only register software call poll to determine
+ * the current prefetch head of the transmit ring, from the tdcPktReq
+ * block. Transmit descriptors are prefetched into chip memory.
+ * Indicates next descriptor to be read from host memory. For debug
+ * use only.
+ * Fields:
+ *     Hardware will toggle this bit every time the prefetch head is
+ *     wrapped around the configured ring buffer.
+ *     Entry in transmit ring which will be fetched next from host
+ *     memory.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:47;
+               uint64_t        wrap:1;
+               uint64_t        head:16;
+#else
+               uint64_t        head:16;
+               uint64_t        wrap:1;
+               uint64_t        rsrvd:47;
+#endif
+       } bits;
+} tdc_tdr_pre_head_t;
+
+
+/*
+ * Register: TdcTdrKick
+ * Transmit Ring Kick
+ * Description: After posting transmit descriptors to the Transmit
+ * Ring, software updates the tail pointer to inform Hydra of the new
+ * descriptors. Software can only post descriptors through this
+ * register when the entire packet is in the ring. Otherwise,
+ * hardware dead-lock can occur. If an overflow kick occurs when the
+ * channel is disabled, tdcStat.txRngOflow (Transmit Ring Overflow)
+ * status is not set.
+ * Fields:
+ *     Software needs to toggle this bit every time the tail is
+ *     wrapped around the configured ring buffer.
+ *     Entry where the next valid descriptor will be added (one entry
+ *     past the last valid descriptor.)
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:47;
+               uint64_t        wrap:1;
+               uint64_t        tail:16;
+#else
+               uint64_t        tail:16;
+               uint64_t        wrap:1;
+               uint64_t        rsrvd:47;
+#endif
+       } bits;
+} tdc_tdr_kick_t;
+
+
+/*
+ * Register: TdcIntMask
+ * Transmit Event Mask
+ * Description: The Tx DMA can generate a number of LDF events. The
+ * events can be enabled by software by setting the corresponding bit
+ * to 0. The default value of 1 means the event is masked and no LDF
+ * event is generated.
+ * Fields:
+ *     Set to 0 to select the event to raise the LDF for packets
+ *     marked. An LDF 0 event.
+ *     Set to 0 to select the event to raise the LDF when poisoned
+ *     completion or non-zero (unsuccessful) completion status
+ *     received from PEU. An LDF 1 event.
+ *     Set to 0 to select the event to raise the LDF when total bytes
+ *     transmitted compared against pkt internal header bytes
+ *     transmitted mismatch. An LDF 1 event.
+ *     Set to 0 to select the event to raise the LDF when a runt
+ *     packet is dropped (when VMAC does not allow runt packets to be
+ *     padded). An LDF 1 event.
+ *     Set to 0 to select the event to raise the LDF when the packet
+ *     size exceeds hardware limit. An LDF 1 event.
+ *     Set to 0 to select the event to raise the LDF to indicate
+ *     Transmit Ring Overflow An LDF 1 event.
+ *     Set to 0 to select the event to raise the LDF to indicate
+ *     parity error on the tdr prefetch buffer occurred. An LDF 1
+ *     event.
+ *     Set to 0 to select the event to raise the LDF to indicate tdc
+ *     received a response completion timeout from peu for tdr
+ *     descriptor prefetch An LDF 1 event.
+ *     Set to 0 to select the event to raise the LDF to indicate tdc
+ *     received a response completion timeout from peu for packet
+ *     data request An LDF 1 event.
+ *     Set to 0 to select the event to raise the LDF to indicate tdc
+ *     did not receive an SOP in the 1st descriptor as was expected
+ *     or the numPtr in the 1st descriptor was set to 0. An LDF 1
+ *     event.
+ *     Set to 0 to select the event to raise the LDF to indicate tdc
+ *     received an unexpected SOP descriptor error. An LDF 1 event.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:48;
+               uint64_t        marked:1;
+               uint64_t        rsrvd1:5;
+               uint64_t        peu_resp_err:1;
+               uint64_t        pkt_size_hdr_err:1;
+               uint64_t        runt_pkt_drop_err:1;
+               uint64_t        pkt_size_err:1;
+               uint64_t        tx_rng_oflow:1;
+               uint64_t        pref_par_err:1;
+               uint64_t        tdr_pref_cpl_to:1;
+               uint64_t        pkt_cpl_to:1;
+               uint64_t        invalid_sop:1;
+               uint64_t        unexpected_sop:1;
+#else
+               uint64_t        unexpected_sop:1;
+               uint64_t        invalid_sop:1;
+               uint64_t        pkt_cpl_to:1;
+               uint64_t        tdr_pref_cpl_to:1;
+               uint64_t        pref_par_err:1;
+               uint64_t        tx_rng_oflow:1;
+               uint64_t        pkt_size_err:1;
+               uint64_t        runt_pkt_drop_err:1;
+               uint64_t        pkt_size_hdr_err:1;
+               uint64_t        peu_resp_err:1;
+               uint64_t        rsrvd1:5;
+               uint64_t        marked:1;
+               uint64_t        rsrvd:48;
+#endif
+       } bits;
+} tdc_int_mask_t;
+
+
+/*
+ * Register: TdcStat
+ * Transmit Control and Status
+ * Description: Combined control and status register. When writing to
+ * this register, any bit that software wishes not to change should
+ * be written to 0. The TdcStat register may be read or written only
+ * when no mailbox updates are pending. Accordingly, the expected
+ * algorithm for software to use in tracking marked packets and
+ * mailbox updates is one of the following only: 1) enable
+ * interrupts, enable mb, send a single marked packet, wait for Ldf0,
+ * clear marked, repeat or 2) disable interrupts, never enable mb,
+ * send one or more marked packets, poll TdcStat for marked/mMarked
+ * state, clear marked/mMarked bits, repeat. If interrupts are
+ * enabled, upon receiving an Ldf1 interrupt for a given channel
+ * software must wait until a channel's Qst bit has asserted before
+ * reading TdcStat for corresponding error information and before
+ * writing to TdcStat to clear error state.
+ * Fields:
+ *     A wrap-around counter to keep track of packets transmitted.
+ *     Reset to zero when the DMA is reset
+ *     The pktCnt corresponds to the last packet with the MARK bit
+ *     set. Reset to zero when the DMA is reset.
+ *     Set to 1 to cause HW to update the mailbox when the next
+ *     packet with the marked bit set is transmitted. HW clears this
+ *     bit to zero after the mailbox update has completed. Note that,
+ *     correspondingly, the TdcStat data for the Tx mailbox write
+ *     will reflect the state of mb prior to the mb bit's update for
+ *     the marked packet being sent. Software should send only one
+ *     marked packet per assertion of the mb bit. Multiple marked
+ *     packets after setting the mb bit and before receiving the
+ *     corresponding mailbox update is not supported. Precautionary
+ *     note: Emphasize HW is responsible for clearing this bit. If
+ *     software clears this bit, the behavior is undefined.
+ *     Set to 1 when a packet with the mark bit set is transmitted.
+ *     If mb is set at the time of the marked packet transmission,
+ *     marked will not be set until the corresponding mailbox write
+ *     has completed. Note that, correspondingly, the TdcStat data
+ *     for the Tx mailbox write will reflect the state of marked
+ *     prior to the marked bit's update for the marked packet being
+ *     sent. Software may read the register to clear the bit.
+ *     Alternatively, software may write a 1 to clear the MARKED bit
+ *     (Write 0 has no effect). In the case of write 1, if mMarked
+ *     bit is set, MARKED bit will NOT be cleared. This bit is used
+ *     to generate LDF 0 consistent with settings in TdcIntMask.
+ *     Overflow bit for MARKED register bit. Indicates that multiple
+ *     marked packets have been transmitted since the last clear of
+ *     the marked bit. If hardware is waiting to update MARKED until
+ *     a mailbox write has completed, when another marked packet is
+ *     transmitted, mMarked will also not be set until the mailbox
+ *     write completes. Note that, correspondingly, the TdcStat data
+ *     for the Tx mailbox write will reflect the state of mMarked
+ *     prior to the mMarked bit's update for the marked packet being
+ *     sent. Software reads to clear. A write 1 to MARKED bit will
+ *     also clear the mMarked bit. A write 0 has no effect.
+ *     Set to 1 to indicate poisoned completion or non-zero
+ *     (unsuccessful) completion status received from PEU. Part of
+ *     LDF 1.
+ *     Set to 1 to indicate tdc descriptor error: total bytes
+ *     transmitted compared against pkt internal header bytes
+ *     transmitted mismatch. Fatal error. Part of LDF 1.
+ *     Set to 1 when a runt packet is dropped (when VMAC does not
+ *     allow runt packets to be padded. Fatal error. Part of LDF1.
+ *     Set to 1 when the packet size exceeds hardware limit: the sum
+ *     of gathers exceeds the maximum transmit length (specified in
+ *     the Tx VMAC Configuration register txMaxFrameLength) or any
+ *     descriptor attempts to transmit more than 4K. Writing a 1
+ *     clears the value to 0. Writing a 0 has no effect. Part of LDF
+ *     1. Note that packet size for the purpose of this error is
+ *     determined by the actual transfer size from the Tdc to the Tdp
+ *     and not from the totXferSize field of the internal header.
+ *     Set to 1 to indicate Transmit Ring Overflow: Tail > Ringlength
+ *     or if the relative position of the shadow tail to the ring
+ *     tail is not correct with respect to the wrap bit. Transmit
+ *     Ring Overflow status is not set, if the dma is disabled. Fatal
+ *     error. Part of LDF1.
+ *     Set to 1 by HW to indicate parity error on the tdr prefetch
+ *     buffer occurred. Writing a 1 clears the parity error log
+ *     register Part of LDF 1.
+ *     Set to 1 to indicate tdc received a response completion
+ *     timeout from peu for tdr descriptor prefetch Fatal error. Part
+ *     of LDF 1.
+ *     Set to 1 to indicate tdc received a response completion
+ *     timeout from peu for packet data request Fatal error. Part of
+ *     LDF 1.
+ *     Set to 1 to indicate tdc did not receive an SOP in the 1st
+ *     descriptor as was expected or the numPtr in the 1st descriptor
+ *     was set to 0. Fatal error. Part of LDF 1.
+ *     Set to 1 to indicate tdc received an unexpected SOP descriptor
+ *     error. Fatal error. Part of LDF 1.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:4;
+               uint64_t        pkt_cnt:12;
+               uint64_t        rsrvd1:4;
+               uint64_t        lastmark:12;
+               uint64_t        rsrvd2:2;
+               uint64_t        mb:1;
+               uint64_t        rsrvd3:13;
+               uint64_t        marked:1;
+               uint64_t        m_marked:1;
+               uint64_t        rsrvd4:4;
+               uint64_t        peu_resp_err:1;
+               uint64_t        pkt_size_hdr_err:1;
+               uint64_t        runt_pkt_drop_err:1;
+               uint64_t        pkt_size_err:1;
+               uint64_t        tx_rng_oflow:1;
+               uint64_t        pref_par_err:1;
+               uint64_t        tdr_pref_cpl_to:1;
+               uint64_t        pkt_cpl_to:1;
+               uint64_t        invalid_sop:1;
+               uint64_t        unexpected_sop:1;
+#else
+               uint64_t        unexpected_sop:1;
+               uint64_t        invalid_sop:1;
+               uint64_t        pkt_cpl_to:1;
+               uint64_t        tdr_pref_cpl_to:1;
+               uint64_t        pref_par_err:1;
+               uint64_t        tx_rng_oflow:1;
+               uint64_t        pkt_size_err:1;
+               uint64_t        runt_pkt_drop_err:1;
+               uint64_t        pkt_size_hdr_err:1;
+               uint64_t        peu_resp_err:1;
+               uint64_t        rsrvd4:4;
+               uint64_t        m_marked:1;
+               uint64_t        marked:1;
+               uint64_t        rsrvd3:13;
+               uint64_t        mb:1;
+               uint64_t        rsrvd2:2;
+               uint64_t        lastmark:12;
+               uint64_t        rsrvd1:4;
+               uint64_t        pkt_cnt:12;
+               uint64_t        rsrvd:4;
+#endif
+       } bits;
+} tdc_stat_t;
+
+
+/*
+ * Register: TdcMbh
+ * Tx DMA Mailbox High
+ * Description: Upper bits of Tx DMA mailbox address in host memory.
+ * Fields in this register are part of the dma configuration and
+ * cannot be changed once the dma is enabled.
+ * Fields:
+ *     Bits [43:32] of the Mailbox address.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:52;
+               uint64_t        mbaddr:12;
+#else
+               uint64_t        mbaddr:12;
+               uint64_t        rsrvd:52;
+#endif
+       } bits;
+} tdc_mbh_t;
+
+
+/*
+ * Register: TdcMbl
+ * Tx DMA Mailbox Low
+ * Description: Lower bits of Tx DMA mailbox address in host memory.
+ * Fields in this register are part of the dma configuration and
+ * cannot be changed once the dma is enabled.
+ * Fields:
+ *     Bits [31:6] of the Mailbox address. Bits [5:0] are assumed to
+ *     be zero, or 64B aligned.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        mbaddr:26;
+               uint64_t        rsrvd1:6;
+#else
+               uint64_t        rsrvd1:6;
+               uint64_t        mbaddr:26;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} tdc_mbl_t;
+
+
+/*
+ * Register: TdcByteCnt
+ * Tx DMA Byte Count
+ * Description: Counts the number of bytes transmitted to the tx
+ * datapath block. This count may increment in advance of
+ * corresponding updates to TdcStat for the bytes transmitted.
+ * Fields:
+ *     Number of bytes transmitted from transmit ring. This counter
+ *     will saturate. This register is cleared on read.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        byte_count:32;
+#else
+               uint64_t        byte_count:32;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} tdc_byte_cnt_t;
+
+
+/*
+ * Register: TdcTdrQlen
+ * Tdr Queue Length
+ * Description: Number of descriptors in Tdr For debug only. Note:
+ * Not analogous to either rdc.rbrQlen or tdc.tdcKick -
+ * tdc.tdcTdrHead. Indicates depth of the two intermediate descriptor
+ * usage points rather than end-to-end descriptor availability.
+ * Fields:
+ *     Current number of descriptors in Tdr, unprefetched
+ *     Current number of descriptors in Tdr in prefetch buffer, i.e.
+ *     those which have been prefetched but have not yet been
+ *     allocated to the RTab.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        tdr_qlen:16;
+               uint64_t        tdr_pref_qlen:16;
+#else
+               uint64_t        tdr_pref_qlen:16;
+               uint64_t        tdr_qlen:16;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} tdc_tdr_qlen_t;
+
+
+/*
+ * Register: TdcRtabPtr
+ * RTAB pointers
+ * Description: Status of the reorder table pointers Writing to this
+ * register is for debug purposes only and is enabled when vnmDbgOn
+ * is set to 1
+ * Fields:
+ *     Current rtab head pointer, used in the txPkt block This
+ *     register is used to dequeue entries in the reorder table when
+ *     packets are sent out
+ *     Current rtab head pointer, used in the pktResp block This
+ *     register is used to scan entries in the reorder table when
+ *     packet data response completions arrive
+ *     Current rtab tail pointer, used in the pktReq block This
+ *     register is used to allocate entries in the reorder table when
+ *     packet data requests are made
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:24;
+               uint64_t        pkt_rtab_head:8;
+               uint64_t        rsrvd1:7;
+               uint64_t        rtab_head:9;
+               uint64_t        rsrvd2:7;
+               uint64_t        rtab_tail:9;
+#else
+               uint64_t        rtab_tail:9;
+               uint64_t        rsrvd2:7;
+               uint64_t        rtab_head:9;
+               uint64_t        rsrvd1:7;
+               uint64_t        pkt_rtab_head:8;
+               uint64_t        rsrvd:24;
+#endif
+       } bits;
+} tdc_rtab_ptr_t;
+
+
+/*
+ * Register: TdcDropCnt
+ * Packet Drop Counter
+ * Description: Counts the number of runt, aborted and size
+ * mismatched packets dropped by the tx datapath block.
+ * Fields:
+ *     Number of dropped due to pktSizeHdrErr. This counter will
+ *     saturate. This counter is cleared on read.
+ *     Number of dropped due to packet abort bit being set. Many
+ *     different error events could be the source of packet abort
+ *     drop. Descriptor-related error events include those errors
+ *     encountered while in the middle of processing a packet
+ *     request: 1. unexpectedSop; 2. non-SOP descriptor parity error
+ *     (prefParErr); 3. ran out of non-SOP descriptors due to peu
+ *     response errors (tdrPrefCplTo or peuRespErr) or the channel
+ *     being disabled before the TDR request can be made. Packet
+ *     response errors encountered while in the middle of processing
+ *     a packet request also can trigger the packet abort: 4. packet
+ *     response did not return due to peu response errors ( pktCplTo
+ *     or peuRespErr); 5. Rtab parity error (reordTblParErr). This
+ *     counter will saturate. This counter is cleared on read. Note
+ *     that packet aborts are not counted until the packet is cleared
+ *     from the RTab, which may be an arbitrary amount of time after
+ *     the corresponding error is logged in TdcStat. In most cases,
+ *     this will occur before the channel is quiesced following
+ *     channel disable. In an extreme case such as if a parity error
+ *     on an EOP descriptor prevents recognition of the EOP, it is
+ *     possible that the quiescent bit itself will not be set
+ *     although the packet drop counter will be incremented.
+ *     Number of dropped due to runt packet size error. This counter
+ *     will saturate. This counter is cleared on read.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:40;
+               uint64_t        hdr_size_error_count:8;
+               uint64_t        abort_count:8;
+               uint64_t        runt_count:8;
+#else
+               uint64_t        runt_count:8;
+               uint64_t        abort_count:8;
+               uint64_t        hdr_size_error_count:8;
+               uint64_t        rsrvd:40;
+#endif
+       } bits;
+} tdc_drop_cnt_t;
+
+
+/*
+ * Register: TdcLastPktRbufPtrs
+ * Last Packet RBUF Pointers
+ * Description: Logs the RBUF head and tail pointer of the last
+ * packet sent by the tx datapath block.
+ * Fields:
+ *     Logs the RBUF tail pointer of the last packet sent
+ *     Logs the RBUF head pointer of the last packet sent
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:36;
+               uint64_t        rbuf_tail_ptr:12;
+               uint64_t        rsrvd1:4;
+               uint64_t        rbuf_head_ptr:12;
+#else
+               uint64_t        rbuf_head_ptr:12;
+               uint64_t        rsrvd1:4;
+               uint64_t        rbuf_tail_ptr:12;
+               uint64_t        rsrvd:36;
+#endif
+       } bits;
+} tdc_last_pkt_rbuf_ptrs_t;
+
+
+/*
+ * Register: TdcPrefCmd
+ * Tx DMA Prefetch Buffer Command
+ * Description: Allows debug access to the entire prefetch buffer.
+ * For writes, software writes the tdcPrefData and tdcPrefParData
+ * registers, before writing the tdcPrefCmd register. For reads,
+ * software writes the tdcPrefCmd register, then reads the
+ * tdcPrefData and tdcPrefParData registers. The valid field should
+ * be polled by software until it goes low, indicating the read or
+ * write has completed. Writing the tdcPrefCmd triggers the access.
+ * Fields:
+ *     status of indirect access 0=busy 1=done
+ *     Command type. 1 indicates a read command, 0 a write command.
+ *     enable writing of parity bits 1=enabled, 0=disabled
+ *     DMA channel of entry to read or write
+ *     Entry in the prefetch buffer to read or write
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        status:1;
+               uint64_t        cmd:1;
+               uint64_t        par_en:1;
+               uint64_t        rsrvd1:23;
+               uint64_t        dmc:2;
+               uint64_t        entry:4;
+#else
+               uint64_t        entry:4;
+               uint64_t        dmc:2;
+               uint64_t        rsrvd1:23;
+               uint64_t        par_en:1;
+               uint64_t        cmd:1;
+               uint64_t        status:1;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} tdc_pref_cmd_t;
+
+
+/*
+ * Register: TdcPrefData
+ * Tx DMA Prefetch Buffer Data
+ * Description: See tdcPrefCmd register.
+ * Fields:
+ *     For writes, data which is written into prefetch buffer. For
+ *     reads, data read from the prefetch buffer.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        data:64;
+#else
+               uint64_t        data:64;
+#endif
+       } bits;
+} tdc_pref_data_t;
+
+
+/*
+ * Register: TdcPrefParData
+ * Tx DMA Prefetch Buffer Parity Data
+ * Description: See tdcPrefCmd register.
+ * Fields:
+ *     For writes, parity data which is written into prefetch buffer.
+ *     For reads, parity data read from the prefetch buffer.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:56;
+               uint64_t        par_data:8;
+#else
+               uint64_t        par_data:8;
+               uint64_t        rsrvd:56;
+#endif
+       } bits;
+} tdc_pref_par_data_t;
+
+
+/*
+ * Register: TdcReordBufCmd
+ * Tx DMA Reorder Buffer Command
+ * Description: Allows debug access to the entire Reorder buffer. For
+ * writes, software writes the tdcReordBufData and tdcReordBufEccData
+ * before writing the tdcReordBufCmd register. For reads, software
+ * writes the tdcReordBufCmd register, then reads the tdcReordBufData
+ * and tdcReordBufEccData registers. The valid field should be polled
+ * by software until it goes low, indicating the read or write has
+ * completed. Writing the tdcReordBufCmd triggers the access.
+ * Fields:
+ *     status of indirect access 0=busy 1=done
+ *     Command type. 1 indicates a read command, 0 a write command.
+ *     enable writing of ecc bits 1=enabled, 0=disabled
+ *     Entry in the reorder buffer to read or write
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        status:1;
+               uint64_t        cmd:1;
+               uint64_t        ecc_en:1;
+               uint64_t        rsrvd1:17;
+               uint64_t        entry:12;
+#else
+               uint64_t        entry:12;
+               uint64_t        rsrvd1:17;
+               uint64_t        ecc_en:1;
+               uint64_t        cmd:1;
+               uint64_t        status:1;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} tdc_reord_buf_cmd_t;
+
+
+/*
+ * Register: TdcReordBufData
+ * Tx DMA Reorder Buffer Data
+ * Description: See tdcReordBufCmd register.
+ * Fields:
+ *     For writes, data which is written into reorder buffer. For
+ *     reads, data read from the reorder buffer.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        data:64;
+#else
+               uint64_t        data:64;
+#endif
+       } bits;
+} tdc_reord_buf_data_t;
+
+
+/*
+ * Register: TdcReordBufEccData
+ * Tx DMA Reorder Buffer ECC Data
+ * Description: See tdcReordBufCmd register.
+ * Fields:
+ *     For writes, ecc data which is written into reorder buffer. For
+ *     reads, ecc data read from the reorder buffer.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:56;
+               uint64_t        ecc_data:8;
+#else
+               uint64_t        ecc_data:8;
+               uint64_t        rsrvd:56;
+#endif
+       } bits;
+} tdc_reord_buf_ecc_data_t;
+
+
+/*
+ * Register: TdcReordTblCmd
+ * Tx DMA Reorder Table Command
+ * Description: Allows debug access to the entire Reorder Table. For
+ * writes, software writes the tdcReordTblData and tdcReordTblParData
+ * before writing the tdcReordTblCmd register. For reads, software
+ * writes the tdcReordTblCmd register, then reads the tdcReordTblData
+ * and tdcReordTblParData registers. The valid field should be polled
+ * by software until it goes low, indicating the read or write has
+ * completed. Writing the tdcReordTblCmd triggers the access.
+ * Fields:
+ *     status of indirect access 0=busy 1=done
+ *     Command type. 1 indicates a read command, 0 a write command.
+ *     enable writing of par bits 1=enabled, 0=disabled
+ *     Address in the reorder table to read from or write to
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        status:1;
+               uint64_t        cmd:1;
+               uint64_t        par_en:1;
+               uint64_t        rsrvd1:21;
+               uint64_t        entry:8;
+#else
+               uint64_t        entry:8;
+               uint64_t        rsrvd1:21;
+               uint64_t        par_en:1;
+               uint64_t        cmd:1;
+               uint64_t        status:1;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} tdc_reord_tbl_cmd_t;
+
+
+/*
+ * Register: TdcReordTblDataLo
+ * Tx DMA Reorder Table Data Lo
+ * Description: See tdcReordTblCmd register.
+ * Fields:
+ *     For writes, data which is written into reorder table. For
+ *     reads, data read from the reorder table.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        data:64;
+#else
+               uint64_t        data:64;
+#endif
+       } bits;
+} tdc_reord_tbl_data_lo_t;
+
+
+/*
+ * Register: TdcReordTblDataHi
+ * Tx DMA Reorder Table Data Hi
+ * Description: See tdcReordTblCmd register.
+ * Fields:
+ *     For writes, parity data which is written into reorder table.
+ *     For reads, parity data read from the reorder table.
+ *     For writes, data which is written into reorder table. For
+ *     reads, data read from the reorder table.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:47;
+               uint64_t        par_data:9;
+               uint64_t        hi_data:8;
+#else
+               uint64_t        hi_data:8;
+               uint64_t        par_data:9;
+               uint64_t        rsrvd:47;
+#endif
+       } bits;
+} tdc_reord_tbl_data_hi_t;
+
+
+/*
+ * Register: TdcPrefParLog
+ * Tx DMA Prefetch Buffer Parity Log
+ * Description: TDC DMA Prefetch Buffer parity log register This
+ * register logs the first parity error encountered. Writing a 1 to
+ * TdcStat::prefParErr clears this register and re-arms for logging
+ * the next error
+ * Fields:
+ *     Address of parity error read data
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rsrvd1:26;
+               uint64_t        address:6;
+#else
+               uint64_t        address:6;
+               uint64_t        rsrvd1:26;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} tdc_pref_par_log_t;
+
+
+/*
+ * Register: TdcReordBufEccLog
+ * Tx Reorder Buffer ECC Log
+ * Description: TDC Reorder Buffer ECC log register This register
+ * logs the first ECC error encountered. Writing a 1 to
+ * tdcFifoErrStat::reordBufDedErr or tdcFifoErrStat::reordBufSecErr
+ * clears this register and re-arms for logging
+ * Fields:
+ *     Address of ECC error
+ *     Syndrome of ECC error
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rsrvd1:4;
+               uint64_t        address:12;
+               uint64_t        rsrvd2:8;
+               uint64_t        syndrome:8;
+#else
+               uint64_t        syndrome:8;
+               uint64_t        rsrvd2:8;
+               uint64_t        address:12;
+               uint64_t        rsrvd1:4;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} tdc_reord_buf_ecc_log_t;
+
+
+/*
+ * Register: TdcReordTblParLog
+ * Tx Reorder Table Parity Log
+ * Description: TDC Reorder Table parity log register This register
+ * logs the first parity error encountered. Writing a 1 to
+ * tdcFifoErrStat::reordTblParErr clears this register and re-arms
+ * for logging
+ * Fields:
+ *     Address of parity error
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rsrvd1:24;
+               uint64_t        address:8;
+#else
+               uint64_t        address:8;
+               uint64_t        rsrvd1:24;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} tdc_reord_tbl_par_log_t;
+
+
+/*
+ * Register: TdcFifoErrMask
+ * FIFO Error Mask
+ * Description: FIFO Error Mask register. Mask status of Reorder
+ * Buffer and Reorder Table Buffer Errors.
+ * Fields:
+ *     Set to 0 to select the event to raise the LDF to indicate
+ *     reorder table ram received a parity error An Device Error 1
+ *     event.
+ *     Set to 0 to select the event to raise the LDF to indicate
+ *     reorder buffer ram received a ecc double bit error An Device
+ *     Error 1 event.
+ *     Set to 0 to select the event to raise the LDF to indicate
+ *     reorder buffer ram received a ecc single bit error An Device
+ *     Error 0 event.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:61;
+               uint64_t        reord_tbl_par_err:1;
+               uint64_t        reord_buf_ded_err:1;
+               uint64_t        reord_buf_sec_err:1;
+#else
+               uint64_t        reord_buf_sec_err:1;
+               uint64_t        reord_buf_ded_err:1;
+               uint64_t        reord_tbl_par_err:1;
+               uint64_t        rsrvd:61;
+#endif
+       } bits;
+} tdc_fifo_err_mask_t;
+
+
+/*
+ * Register: TdcFifoErrStat
+ * FIFO Error Status
+ * Description: FIFO Error Status register. Log status of Reorder
+ * Buffer and Reorder Table Buffer Errors.
+ * Fields:
+ *     Set to 1 by HW to indicate reorder table ram received a parity
+ *     error Writing a 1 clears this bit and also clears the
+ *     TdcReordTblParLog register Fatal error. Part of Device Error
+ *     1.
+ *     Set to 1 by HW to indicate reorder buffer ram received a
+ *     double bit ecc error Writing a 1 clears this bit and also
+ *     clears the tdcReordBufEccLog register Fatal error. Part of
+ *     Device Error 1.
+ *     Set to 1 by HW to indicate reorder buffer ram received a
+ *     single bit ecc error Writing a 1 clears this bit and also
+ *     clears the tdcReordBufEccLog register Non-Fatal error. Part of
+ *     Device Error 0.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:61;
+               uint64_t        reord_tbl_par_err:1;
+               uint64_t        reord_buf_ded_err:1;
+               uint64_t        reord_buf_sec_err:1;
+#else
+               uint64_t        reord_buf_sec_err:1;
+               uint64_t        reord_buf_ded_err:1;
+               uint64_t        reord_tbl_par_err:1;
+               uint64_t        rsrvd:61;
+#endif
+       } bits;
+} tdc_fifo_err_stat_t;
+
+
+/*
+ * Register: TdcFifoErrIntDbg
+ * FIFO Error Interrupt Debug
+ * Description: FIFO Error Interrupt Debug register. Write this
+ * regsiter to set bits in TdcFifoErrStat, allowing debug creation of
+ * interrupts without needing to create the actual events. This
+ * register holds no state. Reading this register gives the Tdc Fifo
+ * Err Status data. Clear interrupt state by clearing TdcFifoErrStat.
+ * For Debug only
+ * Fields:
+ *     Set to 1 to select the event to raise the LDF to indicate
+ *     reorder table ram received a parity error An Device Error 1
+ *     event.
+ *     Set to 1 to select the event to raise the LDF to indicate
+ *     reorder buffer ram received a ecc double bit error An Device
+ *     Error 1 event.
+ *     Set to 1 to select the event to raise the LDF to indicate
+ *     reorder buffer ram received a ecc single bit error An Device
+ *     Error 0 event.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:61;
+               uint64_t        reord_tbl_par_err:1;
+               uint64_t        reord_buf_ded_err:1;
+               uint64_t        reord_buf_sec_err:1;
+#else
+               uint64_t        reord_buf_sec_err:1;
+               uint64_t        reord_buf_ded_err:1;
+               uint64_t        reord_tbl_par_err:1;
+               uint64_t        rsrvd:61;
+#endif
+       } bits;
+} tdc_fifo_err_int_dbg_t;
+
+
+/*
+ * Register: TdcStatIntDbg
+ * Transmit Status Interrupt Debug
+ * Description: Write this regsiter to set bits in TdcStat, allowing
+ * debug creation of interrupts without needing to create the actual
+ * events. This register holds no state. Reading this register gives
+ * the Transmit Control and Status data. Clear interrupt state by
+ * clearing TdcStat. For Debug only
+ * Fields:
+ *     Set to 1 to select the event to raise the LDF for packets
+ *     marked. An LDF 0 event.
+ *     Set to 1 to select the event to raise the LDF when poisoned
+ *     completion or non-zero (unsuccessful) completion status
+ *     received from PEU. An LDF 1 event.
+ *     Set to 1 to select the event to raise the LDF when total bytes
+ *     transmitted compared against pkt internal header bytes
+ *     transmitted mismatch. An LDF 1 event.
+ *     Set to 1 to select the event to raise the LDF when a runt
+ *     packet is dropped (when VMAC does not allow runt packets to be
+ *     padded). An LDF 1 event.
+ *     Set to 1 to select the event to raise the LDF when the packet
+ *     size exceeds hardware limit. An LDF 1 event.
+ *     Set to 1 to select the event to raise the LDF to indicate
+ *     Transmit Ring Overflow An LDF 1 event.
+ *     Set to 1 to select the event to raise the LDF to indicate
+ *     parity error on the tdr prefetch buffer occurred. An LDF 1
+ *     event.
+ *     Set to 1 to select the event to raise the LDF to indicate tdc
+ *     received a response completion timeout from peu for tdr
+ *     descriptor prefetch An LDF 1 event.
+ *     Set to 1 to select the event to raise the LDF to indicate tdc
+ *     received a response completion timeout from peu for packet
+ *     data request An LDF 1 event.
+ *     Set to 1 to select the event to raise the LDF to indicate tdc
+ *     did not receive an SOP in the 1st descriptor as was expected
+ *     or the numPtr in the 1st descriptor was set to 0. An LDF 1
+ *     event.
+ *     Set to 1 to select the event to raise the LDF to indicate tdc
+ *     received an unexpected SOP descriptor error. An LDF 1 event.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:48;
+               uint64_t        marked:1;
+               uint64_t        rsrvd1:5;
+               uint64_t        peu_resp_err:1;
+               uint64_t        pkt_size_hdr_err:1;
+               uint64_t        runt_pkt_drop_err:1;
+               uint64_t        pkt_size_err:1;
+               uint64_t        tx_rng_oflow:1;
+               uint64_t        pref_par_err:1;
+               uint64_t        tdr_pref_cpl_to:1;
+               uint64_t        pkt_cpl_to:1;
+               uint64_t        invalid_sop:1;
+               uint64_t        unexpected_sop:1;
+#else
+               uint64_t        unexpected_sop:1;
+               uint64_t        invalid_sop:1;
+               uint64_t        pkt_cpl_to:1;
+               uint64_t        tdr_pref_cpl_to:1;
+               uint64_t        pref_par_err:1;
+               uint64_t        tx_rng_oflow:1;
+               uint64_t        pkt_size_err:1;
+               uint64_t        runt_pkt_drop_err:1;
+               uint64_t        pkt_size_hdr_err:1;
+               uint64_t        peu_resp_err:1;
+               uint64_t        rsrvd1:5;
+               uint64_t        marked:1;
+               uint64_t        rsrvd:48;
+#endif
+       } bits;
+} tdc_stat_int_dbg_t;
+
+
+/*
+ * Register: TdcPktReqTidTag
+ * Packet Request TID Tag
+ * Description: Packet Request TID Tag register Track the packet
+ * request TID currently used
+ * Fields:
+ *     When set to 1, it indicates the TID is currently being used
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        pkt_req_tid_tag:24;
+               uint64_t        rsrvd1:8;
+#else
+               uint64_t        rsrvd1:8;
+               uint64_t        pkt_req_tid_tag:24;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} tdc_pkt_req_tid_tag_t;
+
+
+/*
+ * Register: TdcSopPrefDescLog
+ * SOP Prefetch Descriptor Log
+ * Description: SOP Descriptor Log register Logs the last SOP
+ * prefetch descriptor processed by the packet request block. This
+ * log could represent the current SOP prefetch descriptor if the
+ * packet request block did not complete issuing the data requests
+ * from this descriptor. Descriptors are logged to this register when
+ * the packet request block is expecting an SOP descriptor, and it
+ * receives it.
+ * Fields:
+ *     Represents the last or current SOP descriptor being processed
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        sop_pref_desc_log:64;
+#else
+               uint64_t        sop_pref_desc_log:64;
+#endif
+       } bits;
+} tdc_sop_pref_desc_log_t;
+
+
+/*
+ * Register: TdcPrefDescLog
+ * Prefetch Descriptor Log
+ * Description: SOP Descriptor Log register Logs the last prefetch
+ * descriptor processed by the packet request block. This log could
+ * represent the current prefetch descriptor if the packet request
+ * block did not complete issuing the data requests from this
+ * descriptor. The contents in this register could differ from the
+ * SOP Prefetch Descriptor Log register if a particular packet
+ * requires usage of more than 1 descriptor. Descriptors are logged
+ * to this register when the packet request block is expecting a
+ * descriptor after the SOP descriptor.
+ * Fields:
+ *     Represents the last or current descriptor being processed
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        pref_desc_log:64;
+#else
+               uint64_t        pref_desc_log:64;
+#endif
+       } bits;
+} tdc_pref_desc_log_t;
+
+
+/*
+ * Register: TdcPeuTxnLog
+ * PEU Transaction Log
+ * Description: PEU Transaction Log register. Counts the memory read
+ * and write requests sent to peu block. For debug only.
+ * Fields:
+ *     Counts the memory write transactions sent to peu block. This
+ *     counter saturates. This counter increments when vnmDbg is on
+ *     Counts the memory read transactions sent to peu block. This
+ *     counter saturates. This counter increments when vnmDbg is on
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rsrvd1:16;
+               uint64_t        peu_mem_wr_count:8;
+               uint64_t        peu_mem_rd_count:8;
+#else
+               uint64_t        peu_mem_rd_count:8;
+               uint64_t        peu_mem_wr_count:8;
+               uint64_t        rsrvd1:16;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} tdc_peu_txn_log_t;
+
+
+/*
+ * Register: TdcDbgTrainingVec
+ * Debug Training Vector
+ * Description: Debug Training Vector register. Debug Training Vector
+ * for the coreClk domain. For the pcieClk domain, the dbgxMsb and
+ * dbgyMsb values are flipped on the debug bus.
+ * Fields:
+ *     Blade Number, the value read depends on the blade this block
+ *     resides
+ *     debug training vector the sub-group select value of 0 selects
+ *     this vector
+ *     Blade Number, the value read depends on the blade this block
+ *     resides
+ *     debug training vector the sub-group select value of 0 selects
+ *     this vector
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        dbgx_msb:1;
+               uint64_t        dbgx_bld_num:3;
+               uint64_t        dbgx_training_vec:12;
+               uint64_t        dbgy_msb:1;
+               uint64_t        dbgy_bld_num:3;
+               uint64_t        dbgy_training_vec:12;
+#else
+               uint64_t        dbgy_training_vec:12;
+               uint64_t        dbgy_bld_num:3;
+               uint64_t        dbgy_msb:1;
+               uint64_t        dbgx_training_vec:12;
+               uint64_t        dbgx_bld_num:3;
+               uint64_t        dbgx_msb:1;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} tdc_dbg_training_vec_t;
+
+
+/*
+ * Register: TdcDbgGrpSel
+ * Debug Group Select
+ * Description: Debug Group Select register. Debug Group Select
+ * register selects the group of signals brought out on the debug
+ * port
+ * Fields:
+ *     high 32b sub-group select
+ *     low 32b sub-group select
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:48;
+               uint64_t        rsrvd1:1;
+               uint64_t        dbg_h32_sub_sel:7;
+               uint64_t        rsrvd2:1;
+               uint64_t        dbg_l32_sub_sel:7;
+#else
+               uint64_t        dbg_l32_sub_sel:7;
+               uint64_t        rsrvd2:1;
+               uint64_t        dbg_h32_sub_sel:7;
+               uint64_t        rsrvd1:1;
+               uint64_t        rsrvd:48;
+#endif
+       } bits;
+} tdc_dbg_grp_sel_t;
+
+
+#endif /* _HXGE_TDC_HW_H */
diff --git a/drivers/net/hxge/hxge_txdma.c b/drivers/net/hxge/hxge_txdma.c
new file mode 100644 (file)
index 0000000..7070f01
--- /dev/null
@@ -0,0 +1,2218 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#include "hpi/hpi_txdma.h"
+#include "hxge.h"
+
+/* failure return codes for map_skbdata_to_descs and copy_skbdata_to_descs
+ * respectively */
+#define MAP_DESC_FAILED  -1
+#define COPY_DESC_FAILED -2
+
+extern int hxge_ok_to_continue(struct hxge_adapter *hxgep);
+extern int hxge_block_reset(struct hxge_adapter *hxgep, int device);
+extern void hxge_disable_interrupts(struct hxge_adapter *hxgep);
+
+
+static int start_reclaim_thread(struct tx_ring_t *tx_ring);
+static int stop_reclaim_thread(struct tx_ring_t *tx_ring);
+
+#ifdef CONFIG_ERRINJECT
+
+#define FREE_SKB       hxge_free_skb
+
+static atomic_t skb_count = ATOMIC_INIT(0);
+void hxge_free_skb(struct sk_buff *skb)
+{
+       atomic_dec(&skb_count);
+       dev_kfree_skb_any(skb);
+}
+
+
+#else
+#define FREE_SKB       dev_kfree_skb_any
+#endif
+
+
+/* Program the Tx registers in hardware to get it ready for transmit. The 
+ * enabling of the channel is done later 
+ */
+static int hxge_map_tx_to_hw(struct hxge_adapter *hxgep, int channel)
+{
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+       struct tx_ring_t *tx_ring = &hxgep->tx_ring[channel];
+       tdc_tdr_cfg_t tdr_cfg;
+       tdc_int_mask_t ev_mask;
+
+       /* Reset already completed, so don't need to set that bit. Set the 
+          DMA address of the Tx descriptor ring. Also the entries in the
+          ring */
+       tdr_cfg.value = 0;
+       tdr_cfg.value = tx_ring->desc_ring.dma_addr & TDC_TDR_CFG_ADDR_MASK;
+       tdr_cfg.bits.len = tx_ring->num_tdrs >> 5;
+       if (hpi_txdma_ring_config(handle, OP_SET, channel, &tdr_cfg.value) !=
+               HPI_SUCCESS)
+       {
+               HXGE_ERR(hxgep, "hpi_txdma_ring_config failed");
+               return -1;
+       }
+
+       /* Write the mailbox register */
+       if (hpi_txdma_mbox_config(handle, OP_SET, channel, 
+                       &tx_ring->mbox.dma_addr) != HPI_SUCCESS)
+       {
+               HXGE_ERR(hxgep, "hpi_txdma_mbox_config failed");
+               return -1;
+       }
+
+       /* Setup the transmit event mask */
+       ev_mask.value = 0;
+
+       /* CR 6678180 workaround - Mask Tx ring overflow to avoid getting
+        * false overflow interrupts
+        */
+       ev_mask.bits.tx_rng_oflow = 1; 
+       if (hpi_txdma_event_mask(handle, OP_SET, channel, &ev_mask) != 
+                       HPI_SUCCESS)
+       {
+               HXGE_ERR(hxgep, "hpi_txdma_event_mask failed");
+               return -1;
+       }
+
+       return 0;
+}
+
+
+/* Assumes that the skb->csum is prep'ed for hw checksumming. This routine
+ * just completes what the hardware would have done. There is here as a 
+ * workaround for a hw checksum bug
+*/
+static int fixup_checksum(struct sk_buff *skb
+#ifdef CONFIG_ERRINJECT
+                         , struct hxge_adapter *hxgep
+#endif
+)
+
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+        unsigned int csum;
+        int ret = 0;
+       int offset = skb->h.raw - skb->data;
+
+        if (skb_cloned(skb)) {
+                ret = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+                if (ret)
+                        goto out;
+        }
+
+        BUG_ON(offset > (int)skb->len);
+        csum = skb_checksum(skb, offset, skb->len-offset, 0);
+
+        offset = skb->tail - skb->h.raw;
+        BUG_ON(offset <= 0);
+        BUG_ON(skb->csum + 2 > offset);
+
+        *(u16*)(skb->h.raw + skb->csum) = csum_fold(csum);
+#ifdef CONFIG_ERRINJECT
+       if (hxgep->err_flags & CHKSUM_FAILURE) {
+               HXGE_ERR(hxgep, "Injecting checksum error");
+               *(u16*)(skb->h.raw + skb->csum) = 0;
+       }
+#endif
+#else
+       __wsum csum;
+        int ret = 0, offset;
+
+        offset = skb->csum_start - skb_headroom(skb);
+        BUG_ON(offset >= skb_headlen(skb));
+        csum = skb_checksum(skb, offset, skb->len - offset, 0);
+
+        offset += skb->csum_offset;
+        BUG_ON(offset + sizeof(__sum16) > skb_headlen(skb));
+
+        if (skb_cloned(skb) &&
+            !skb_clone_writable(skb, offset + sizeof(__sum16))) {
+                ret = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+                if (ret)
+                        goto out;
+        }
+        *(__sum16 *)(skb->data + offset) = csum_fold(csum);
+#ifdef CONFIG_ERRINJECT
+       if (hxgep->err_flags & CHKSUM_FAILURE) {
+                HXGE_ERR(hxgep, "Injecting checksum error");
+               *(__sum16 *)(skb->data + offset) = 0;
+       }
+#endif
+#endif
+out:
+        return ret;
+}
+
+
+/* This routine initializes the data structures specific to a channel. 
+ * Additionally, it initializes the tx channel related registers in the 
+ * hydra hardware 
+ */
+
+static int hxge_init_tx_channel(struct hxge_adapter *hxgep, int channel)
+{
+       struct tx_ring_t *tx_ring = &hxgep->tx_ring[channel];
+       int num_tdrs = tx_ring->num_tdrs;
+       int buffer_size = tx_ring->tx_buffer_size, i;
+       struct tx_buf_t *tx_buf;
+       dma_addr_t dma_addr;
+       caddr_t vaddr;
+       
+       HXGE_DBG(hxgep, "Calling hxge_init_tx_channel for channel %d",channel);
+       
+       /* initialize the Tx descriptor ring */
+       memset(tx_ring->desc_ring.vaddr, 0, sizeof(tx_desc_t)*num_tdrs);
+       HXGE_DBG(hxgep, "Initializing Tx Descriptor ring at 0x%p",tx_ring->desc_ring.vaddr);
+
+       /* Initialize the Tx buffers */
+       //memset(tx_ring->data_buf.vaddr, 0, sizeof(struct tx_buf_t)*num_tdrs);
+       
+       HXGE_DBG(hxgep, "Initializing Tx Buffers for headers");
+       dma_addr = tx_ring->data_buf.dma_addr;
+       vaddr    = tx_ring->data_buf.vaddr;
+       for (i = 0, tx_buf=tx_ring->tx_buf; i < num_tdrs; 
+               i++, tx_buf++, dma_addr += buffer_size, vaddr += buffer_size) {
+               tx_buf->map.dma_addr = dma_addr;
+               tx_buf->map.vaddr    = vaddr;
+               tx_buf->flags    = TX_FLAGS_UNUSED;
+       }
+       
+       /* Entire ring available at start */
+       atomic_set(&tx_ring->descs_avail, num_tdrs);
+       tx_ring->tail = 0;
+       tx_ring->wrap = FALSE; /* really does not matter since it's a toggle */
+       tx_ring->reclaim_head = 0;
+       tx_ring->reclaim_wrap = FALSE; 
+       tx_ring->hxgep = hxgep;
+       tx_ring->mark_ints = 0;
+       
+       /* Initialize the mailbox */
+       memset(tx_ring->mbox.vaddr, 0, sizeof(txdma_mailbox_t));
+
+       hxge_map_tx_to_hw(hxgep, channel);
+
+       /* Start the reclaim thread */
+       tx_ring->thread_pid = -1;
+       start_reclaim_thread(tx_ring);
+       return 0;
+}
+
+/* Caller must have the Tx ring lock */
+static int reclaim_tx_ring(struct hxge_adapter *hxgep, 
+               struct tx_ring_t *tx_ring, tdc_tdr_head_t head_reg)
+{
+       int descs_processed = 0;
+       boolean_t head_wrap;
+       int head_index;
+       struct tx_buf_t *tx_buf;
+       int wrapped;
+       unsigned long start_time = jiffies;
+       int full;
+
+       head_wrap = head_reg.bits.wrap;
+       head_index = head_reg.bits.head;
+       wrapped = (head_wrap != tx_ring->reclaim_wrap);
+        full = ((head_index == tx_ring->reclaim_head) && wrapped);
+
+
+       if (head_index >= tx_ring->num_tdrs) {
+               HXGE_ERR(hxgep, "head_index exceeds ring size! (head_index = 0x%x, Tx ring size = 0x%x",head_index, tx_ring->num_tdrs);
+               BUG();
+       }
+
+        if (full && atomic_read(&tx_ring->descs_avail)) {
+                HXGE_ERR(hxgep, "discrepancy in buffer mgmt: hd=0x%x,rhd=0x%x, hwrp=%d, rwrp=%d, descs_avail=%d",head_index, head_wrap, tx_ring->reclaim_head, tx_ring->reclaim_wrap, atomic_read(&tx_ring->descs_avail));
+                BUG();
+        }
+
+       while (!time_after(jiffies, start_time+800) &&
+               ((tx_ring->reclaim_head != head_index) || wrapped))
+       {
+               wrapped = 0;
+               tx_buf = &tx_ring->tx_buf[tx_ring->reclaim_head];
+               if (tx_buf->flags & TX_FLAGS_UNMAP) /* mapped data */ {
+                       int len; 
+                       HXGE_DBG(hxgep, "Unmapping @(%p,%d)",(char *)tx_buf->map.dma_addr,tx_buf->map.len);
+                       len = (tx_buf->flags & TX_FLAGS_ALLOC) ? PAGE_SIZE :
+                                       tx_buf->map.len;
+                       pci_unmap_page(hxgep->pdev, tx_buf->map.dma_addr, 
+                                       len, PCI_DMA_TODEVICE);
+               }
+
+               if (tx_buf->flags & TX_FLAGS_ALLOC) {
+                       HXGE_DBG(hxgep, "Freeing tx_buf->map.vaddr@%p of len %d (channel %d)",tx_buf->map.vaddr, (int)PAGE_SIZE, tx_ring->tdc);
+                       free_page((unsigned long)tx_buf->map.vaddr);
+               }
+
+               tx_buf->map.vaddr = 0;
+               tx_buf->map.dma_addr = 0;
+               tx_buf->map.len = 0;
+                               
+               if (tx_buf->skb) {
+                       /* free the header array for gso */
+                       if (SKB_IS_GSO(tx_buf->skb)) {
+                               int i;
+                               struct skb_hdr_info_t *skb_hdr = 
+                                   (struct skb_hdr_info_t *)tx_buf->skb->cb;
+                               struct pci_dma_map_t *pci_map = &skb_hdr->pci_map;
+                               pci_free_consistent(hxgep->pdev, 
+                                       skb_hdr->hdr_array.len, 
+                                       skb_hdr->hdr_array.vaddr, 
+                                       skb_hdr->hdr_array.dma_addr);
+
+
+                               if (pci_map->num_dma_mappings) {
+                                       for (i = 0; 
+                                               i < pci_map->num_dma_mappings; 
+                                               i++)
+                                               pci_unmap_page(hxgep->pdev,
+                                                          pci_map->dma_map[i].dma_addr,
+                                                  pci_map->dma_map[i].len, 
+                                                  PCI_DMA_TODEVICE);
+                                       kfree(pci_map->dma_map);
+                               }
+                       }
+                       FREE_SKB(tx_buf->skb);
+                       tx_buf->skb = NULL;
+               }
+               tx_buf->flags = TX_FLAGS_UNUSED;
+                tx_ring->reclaim_head = (tx_ring->reclaim_head + 1) %
+                                tx_ring->num_tdrs;
+                if (!tx_ring->reclaim_head) {
+                        if (tx_ring->reclaim_wrap == TRUE)
+                                tx_ring->reclaim_wrap = FALSE;
+                        else
+                                tx_ring->reclaim_wrap = TRUE;
+                }
+                descs_processed++;
+       }
+
+       atomic_add(descs_processed, &tx_ring->descs_avail);
+       if (netif_queue_stopped(hxgep->netdev))
+               netif_wake_queue(hxgep->netdev);
+
+       return descs_processed;
+}
+
+static int entries_to_process(struct hxge_adapter *hxgep, 
+                       struct tx_ring_t *tx_ring, tdc_tdr_head_t *head_reg)
+{
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+       int head_index;
+       boolean_t head_wrap;
+
+       if (hpi_txdma_ring_head_get(handle, tx_ring->tdc, head_reg) 
+               != HPI_SUCCESS)
+       {
+               HXGE_ERR(hxgep, "hpi_txdma_ring_head_get_failed for channel %d",tx_ring->tdc);
+               return -1;
+       }
+       head_index = head_reg->bits.head;
+       head_wrap  = (head_reg->bits.wrap) ? TRUE : FALSE;
+       if (((head_index != tx_ring->reclaim_head) ||
+               (head_wrap != tx_ring->reclaim_wrap)))
+               return 1;
+
+       return 0;
+}
+
+/* When killing the reclaim thread (either due to interface bringdown or 
+ * driver unload), make sure that all pending Tx descriptors have been sent
+ * before stopping the Tx channel
+ */
+int wait_till_empty(struct hxge_adapter *hxgep, struct tx_ring_t *tx_ring)
+{
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+       int hindex;
+       boolean_t hwrap;
+       tdc_tdr_head_t head_reg;
+       int count = 5;
+
+       do {
+               msleep(1);
+               hpi_txdma_ring_head_get(handle, tx_ring->tdc, &head_reg);
+               hindex = head_reg.bits.head;
+               hwrap = head_reg.bits.wrap;
+       } while(!TXDMA_RING_EMPTY(hindex, hwrap, tx_ring->tail,tx_ring->wrap)
+                       && --count);
+
+       if (!count) {
+               HXGE_ERR(hxgep, "Pending Tx Descriptors not all sent out!");
+               return -1;
+       }
+
+       return 0;
+}
+
+       
+
+/* There is one kernel thread per Tx channel to reclaim unused Tx descriptor
+ * rings for use by the Tx channel. The thread periodically wakes up to 
+ * do reclaim work. Otherwise, it is woken up immediately when a Tx completes
+ * (hxge_tx_intr) when there is reclaim work for sure. It is also woken up
+ * if there is high transmit traffic and an immediate need to free up 
+ * space (hxge_start_xmit)
+ */
+
+static int reclaim_thread(void *data) { 
+       struct tx_ring_t *tx_ring = data; 
+       struct hxge_adapter *hxgep = tx_ring->hxgep;
+       int ret_val;
+       tdc_tdr_head_t head_reg;
+
+
+       daemonize("tx_reclaim_%d", tx_ring->tdc);
+       while (1) {
+
+                wait_event_interruptible_timeout(tx_ring->reclaim_event, 
+                   (ret_val = entries_to_process(hxgep, tx_ring,&head_reg)),
+                   RECLAIM_TIMEOUT);
+
+               if (ret_val < 0)
+                       break;
+
+               /* Ready to get killed. make sure that any outstanding 
+                * descriptors are freed before leaving; otherwise we 
+                * can be leaking skbs
+                */
+               if (tx_ring->kill_reclaim == TRUE) {
+                       wait_till_empty(hxgep, tx_ring);
+                       reclaim_tx_ring(hxgep, tx_ring, head_reg);
+                       break;
+               }
+
+               /* Try to get the lock. If already taken, probably initializing 
+                  the channel due to some error. Return and try later */
+               if (test_and_set_bit(RING_RECLAIM, &tx_ring->state))
+                       continue;
+
+                reclaim_tx_ring(hxgep, tx_ring, head_reg);
+               clear_bit(RING_RECLAIM, &tx_ring->state);
+       }
+
+       while (tx_ring->kill_reclaim == FALSE);
+       complete(&tx_ring->reclaim_complete);
+       return 0;
+
+}
+
+static int start_reclaim_thread(struct tx_ring_t *tx_ring)
+{
+        tx_ring->kill_reclaim = FALSE;
+        init_completion(&tx_ring->reclaim_complete);
+        init_waitqueue_head(&tx_ring->reclaim_event);
+        tx_ring->thread_pid = kernel_thread(reclaim_thread,  tx_ring, CLONE_FS|CLONE_FILES);
+        if (tx_ring->thread_pid < 0) {
+                HXGE_ERR_PRINT("Failed to start kernel thread");
+                return -1;
+        }
+        HXGE_DBG_PRINT("reclaim thread %d started", tx_ring->tdc);
+        return 0;
+}
+
+static int stop_reclaim_thread(struct tx_ring_t *tx_ring)
+{
+        tx_ring->kill_reclaim = TRUE;
+        wake_up_interruptible(&tx_ring->reclaim_event);
+        wait_for_completion(&tx_ring->reclaim_complete);
+       tx_ring->thread_pid = -1;
+        HXGE_DBG_PRINT("reclaim thread %d killed", tx_ring->tdc);
+        return 0;
+}
+
+
+
+/* Allocate data structures to manage the transmit channel including calling
+ * the routine that intializes the HW registers specific to this transmit 
+ * channel 
+ */
+static int hxge_alloc_tx_channel(struct hxge_adapter *hxgep, int channel)
+{
+       struct tx_ring_t *tx_ring = &hxgep->tx_ring[channel];
+       uint32_t size;
+       int num_tdrs;
+
+       spin_lock_init(&tx_ring->lock);
+       HXGE_DBG(hxgep, "Calling hxge_alloc_tx_channel for channel %d", channel);
+       if (hxge_get_option("num_tx_descs", &num_tdrs)) {
+               HXGE_ERR(hxgep, "invalid value for num_tx_descriptors");
+               return -1;
+       }
+
+       tx_ring->num_tdrs = num_tdrs;
+       tx_ring->hxgep = hxgep;
+
+       if (hxge_get_option("tx_buffer_size", &tx_ring->tx_buffer_size)) {
+               HXGE_ERR(hxgep, "invalid tx_buffer_size");
+               return -1;
+       }
+       
+       tx_ring->tdc = channel;
+       tx_ring->desc_ring.vaddr = pci_alloc_consistent(hxgep->pdev, 
+                       sizeof(tx_desc_t)*tx_ring->num_tdrs, 
+                       &tx_ring->desc_ring.dma_addr);
+       if (!tx_ring->desc_ring.vaddr) {
+               HXGE_ERR(hxgep, "Could not alloate descriptor ring");
+               return -1;
+       }
+       HXGE_DBG(hxgep, "Allocated Tx Descriptor Ring at %p, %llx", tx_ring->desc_ring.vaddr, tx_ring->desc_ring.dma_addr);
+
+       if (!valid_alignment(tx_ring->data_buf.dma_addr, 
+               sizeof(tx_desc_t)*tx_ring->num_tdrs, 19)) {
+               HXGE_ERR(hxgep, "Tx Descriptor Ring not aligned");
+               return -1;
+       }
+
+       /* TODO: Allocate tx buffers. All packets need to have the packet header
+          prepended to them. The skbs coming in might not have head room 
+          for the packet header. So, these tx buffers are used to allocate
+          the header and then copy the skb header+data into them */
+
+       tx_ring->tx_buf = kzalloc(num_tdrs*sizeof(struct tx_buf_t), GFP_KERNEL);
+
+       if (!tx_ring->tx_buf) {
+               HXGE_ERR(hxgep, "could not allocate Tx Buffers");
+               return -1;
+       }
+       HXGE_DBG(hxgep, "Allocated Tx Buffer Array at %p", tx_ring->tx_buf);
+       
+       size = tx_ring->tx_buffer_size * num_tdrs; /* in bytes */
+       tx_ring->data_buf.vaddr = pci_alloc_consistent(hxgep->pdev, size, 
+                                       &tx_ring->data_buf.dma_addr);
+       if (!tx_ring->data_buf.vaddr) {
+               HXGE_ERR(hxgep, "could not allocate tx buffers");
+               return -1;
+       }
+       HXGE_DBG(hxgep, "Allocated Tx Data Buffers at %p", tx_ring->data_buf.vaddr);
+       
+
+
+       /* Allocate mailbox */
+       tx_ring->mbox.vaddr = pci_alloc_consistent(hxgep->pdev, 
+                       sizeof(txdma_mailbox_t), &tx_ring->mbox.dma_addr);
+       if (!tx_ring->mbox.vaddr) {
+               HXGE_ERR(hxgep, "could not allocate mbox");
+               return -1;
+       }
+
+       return 0;
+
+}
+
+static void hxge_free_tx_channel(struct hxge_adapter *hxgep, int channel)
+{
+       struct tx_ring_t *tx_ring = &hxgep->tx_ring[channel];
+       int size;
+
+       
+       if (tx_ring->desc_ring.vaddr) {
+               size = sizeof(tx_desc_t) * tx_ring->num_tdrs;
+               pci_free_consistent(hxgep->pdev, size, 
+                   tx_ring->desc_ring.vaddr, tx_ring->desc_ring.dma_addr);
+       }
+
+       if (tx_ring->data_buf.vaddr) {
+               size = tx_ring->tx_buffer_size * tx_ring->num_tdrs;
+               pci_free_consistent(hxgep->pdev, size, 
+                   tx_ring->data_buf.vaddr, tx_ring->data_buf.dma_addr);
+       }
+
+       if (tx_ring->mbox.vaddr) 
+               pci_free_consistent(hxgep->pdev, sizeof(txdma_mailbox_t),
+                       tx_ring->mbox.vaddr, tx_ring->mbox.dma_addr);
+
+       if (tx_ring->tx_buf)
+               kfree(tx_ring->tx_buf);
+}
+
+void hxge_free_tx(struct hxge_adapter *hxgep)
+{
+       int i;
+
+       for (i = 0; i < hxgep->max_tdcs; i++)
+               hxge_free_tx_channel(hxgep, i);
+
+       if (hxgep->tx_ring)     
+               kfree(hxgep->tx_ring);
+
+       hxgep->tx_ring = NULL;
+
+#ifdef CONFIG_ERRINJECT
+       if (atomic_read(&skb_count)) {
+               HXGE_ERR(hxgep,"All SKBs have not been freed! Memory leak, skb pending = %d", atomic_read(&skb_count));
+       }
+#endif
+}
+
+int hxge_alloc_tx(struct hxge_adapter *hxgep)
+{
+       int i;
+
+       if (hxge_get_option("tx_dma_channels", &hxgep->max_tdcs)) {
+               HXGE_ERR(hxgep, "invalid value for tx_dma_channels option");
+               return -1;
+       }
+
+       hxgep->tx_ring = kzalloc(hxgep->max_tdcs*sizeof(struct tx_ring_t), 
+                                       GFP_KERNEL);
+       if (!hxgep->tx_ring) {
+               HXGE_ERR(hxgep, "Could not allocate tx_ring");
+               return -1;
+       }
+
+       for (i = 0; i < hxgep->max_tdcs; i++) 
+               if (hxge_alloc_tx_channel(hxgep, i)) {
+                       HXGE_ERR(hxgep, "could not alloc tx for channel");
+                       hxge_free_tx(hxgep);
+                       return -1;
+               }
+
+       return 0;
+}
+
+static int hxge_disable_tx_channel(struct hxge_adapter *hxgep, int channel)
+{
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+       struct tx_ring_t  *tx_ring = &hxgep->tx_ring[channel];
+
+       clear_bit(RING_ENABLED, &tx_ring->state);
+
+       /* Stop the reclaim thread */
+       if (tx_ring->thread_pid >  0) 
+               stop_reclaim_thread(tx_ring);
+       else
+               HXGE_DBG(hxgep, "Reclaim thread for Tx channel %d already stopped?",channel);
+
+       /* Disable transmits through this channel */
+       if (hpi_txdma_channel_disable(handle, channel) != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hpi_txdma_channel_disable failed");
+       }
+       HXGE_DBG(hxgep, "Channel %d disabled",channel);
+       return 0;
+}
+
+int hxge_disable_tx(struct hxge_adapter *hxgep)
+{      
+       int i;
+       struct tx_ring_t  *tx_ring;
+
+       hxge_disable_tx_ints(hxgep);
+
+       for (i = 0; i < hxgep->max_tdcs; i++) {
+               tx_ring = &hxgep->tx_ring[i];
+               spin_lock(&tx_ring->lock); 
+               if (hxge_disable_tx_channel(hxgep, i)) {
+                       HXGE_ERR(hxgep, "Could not disable channel %i",i);
+               }
+               spin_unlock(&tx_ring->lock);
+               /* Free any pending skbs that were queued up for transmission
+                  but did not get a chance to be sent */
+               if (tx_ring->tx_buf) {
+                       int j;
+                       for (j = 0; j < tx_ring->num_tdrs; j++) {
+                               struct tx_buf_t *tx_buf = &tx_ring->tx_buf[j];
+                               if (tx_buf->skb) {
+                                       FREE_SKB(tx_buf->skb);
+                                       tx_buf->skb = NULL;
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
+static int hxge_enable_tx_channel(struct hxge_adapter *hxgep, int channel)
+{
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+       tdc_stat_t cs;
+       struct tx_ring_t  *tx_ring = &hxgep->tx_ring[channel];
+
+       /* Reset the channel */
+       hpi_txdma_channel_reset(handle, channel);
+
+       /* Explicitly set the kick register to zero because reset does not
+           do it. Set tail and wrap to zero */
+       hpi_txdma_desc_kick_reg_set(handle, channel, 0, 0);
+
+       /* Explicitly clear out the Tx Stat register; some of them are 
+           RW1C types. The channel reset does not seem to do it */
+       cs.value = (u64)~0ULL;
+       hpi_txdma_control_status(handle, OP_SET, 0, &cs);
+
+       hxge_init_tx_channel(hxgep, channel);
+
+
+       /* Make sure that reclaim thread is not running when we reinitialize
+           this Tx channel. We make the assumption that the tx_ring lock 
+          WILL be locked by caller except in initialiation case. So, this
+          statement means the following :
+               1. In the initialiation case, it is doing exactly that i.e
+                  initializing the lock
+               2. In the reset channel case (or any other case for that 
+                  matter), it serves a unlocking the lock */
+
+       spin_lock_init(&tx_ring->lock);
+
+       /* Set the enable bit for the channel to start transmits */
+       hpi_txdma_channel_enable(handle, channel);
+       set_bit(RING_ENABLED, &tx_ring->state);
+
+       HXGE_ERR(hxgep, "Channel %d enabled",channel);
+
+       return 0;
+}
+
+/* Re-enable Tx channel (e.g., in response to LDF1 channel disable) */
+static int hxge_reenable_tx_channel(struct hxge_adapter *hxgep, int channel)
+{
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+       struct tx_ring_t  *tx_ring = &hxgep->tx_ring[channel];
+
+       /* The various TdcStat, kick, head, etc. registers should have
+           remained valid and should NOT need to be re-initialized.
+          We should just "resume" from whence we were "paused". */
+
+       if ((!test_bit(RING_ENABLED, &tx_ring->state))
+            || (test_bit(RING_RESET, &tx_ring->state)))
+               return 0;       /* Explicitly disabled; leave un-enabled */
+
+       /* Set the enable bit for the channel to re-start Tx operations */
+       hpi_txdma_channel_enable(handle, channel);
+
+       HXGE_DBG(hxgep, "Channel %d re-enabled",channel);
+
+       return 0;
+}
+
+/* Wait for Tx channel idle (wait for QST to set) */
+static int hxge_qstwait_tx_channel(struct hxge_adapter *hxgep, int channel)
+{
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+       hpi_status_t hsts;
+
+       /* Wait for Tx operations to quiesce (QST to be set) */
+
+       hsts = hpi_txdma_control_reset_wait(handle, channel);
+       if (hsts != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "Channel %d failed to idle (QST not set)", channel);
+       }
+               
+       return 0;
+}
+
+void hxge_reset_tx_channel(struct hxge_adapter *hxgep, int channel)
+{
+       struct tx_ring_t  *tx_ring = &hxgep->tx_ring[channel];
+
+       HXGE_ERR(hxgep, "Starting tx reset");
+       /* If already in this code, then return */
+       if (test_and_set_bit(RING_RESET, &tx_ring->state)) 
+               return; 
+
+       /* We don't want the reclaim thread to run while we resetting. If
+           already in reclaim, then wait for it to finish */
+       while (test_and_set_bit(RING_RECLAIM, &tx_ring->state))
+               mdelay(1);
+
+       /* Not calling unlock; hxge_init_tx_channel will initialize it
+        * unlocked */
+       spin_lock(&tx_ring->lock);
+
+       hxge_disable_tx_channel(hxgep, channel);
+       hxge_enable_tx_channel(hxgep, channel);
+
+       clear_bit(RING_RECLAIM, &tx_ring->state);
+       clear_bit(RING_RESET, &tx_ring->state);
+       HXGE_ERR(hxgep, "Tx channel reset complete");
+}
+
+/* Enable Transmits. Also, enable Tx interrupts */
+int hxge_enable_tx(struct hxge_adapter *hxgep)
+{
+       int i;
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+       uint64_t reg64 = 0xfeedfacedeadbeefULL;
+       uint64_t data;
+
+       /* Initialize global TX-related error handling */
+
+       HXGE_REG_RD64(handle, TDC_FIFO_ERR_STAT, &reg64);
+       if (reg64) {
+               /* While an interesting case (error flags should probably
+                * not be set), do not count against hxgep->hard_errors */
+               HXGE_ERR(hxgep, "TDC_FIFO_ERR_STAT 0x%16.16x hardware error flags set",
+                        (unsigned int)reg64);
+       }
+       HXGE_REG_WR64(handle, TDC_FIFO_ERR_STAT, reg64); /* RW1C err bits */
+       HXGE_REG_WR64(handle, TDC_FIFO_ERR_MASK, 0); /* 0 = no disables */
+
+
+       /* Scrub rtab memory */
+       HXGE_REG_WR64(handle, TDC_REORD_TBL_DATA_HI, 0);
+       HXGE_REG_WR64(handle, TDC_REORD_TBL_DATA_LO, 0);
+       for (i = 0; i < 256; i++) {
+               HXGE_REG_WR64(handle, TDC_REORD_TBL_CMD, i);
+               do {
+                       HXGE_REG_RD64(handle, TDC_REORD_TBL_CMD, &reg64);
+               } while (!(reg64 & 0x80000000ULL));
+
+               HXGE_REG_WR64(handle, TDC_REORD_TBL_CMD, (1ULL << 30) | i);
+               do {
+                       HXGE_REG_RD64(handle, TDC_REORD_TBL_CMD, &reg64);
+               } while (!(reg64 & 0x80000000ULL));
+
+               
+               HXGE_REG_RD64(handle, TDC_REORD_TBL_DATA_LO, &reg64);
+               HXGE_REG_RD64(handle, TDC_REORD_TBL_DATA_HI, &data);
+               data &= 0xffULL; /* save only data bits, not parity */
+               
+               if (reg64 | data) {
+                       HXGE_ERR(hxgep, "Error reading RTAB data regs, entry: 0x%x, data lo: 0x%llx, data hi: 0x%llx",i, reg64, data);
+                       HXGE_REG_RD64(handle, TDC_FIFO_ERR_STAT, &reg64);
+                       if (reg64) {
+                               HXGE_ERR(hxgep, "ReordTbl parity error, entry: %x, fifo error stat: 0x%llx", i, reg64);
+                       }
+                       return -1;
+               }
+       }
+
+       /* Now enable each of the TDC DMA channels */
+
+       for (i = 0; i < hxgep->max_tdcs; i++)
+               hxge_enable_tx_channel(hxgep, i);
+
+       /* Enable Tx interrupts */
+       hxge_enable_tx_ints(hxgep, NULL);
+
+       return 0;
+}
+
+
+/* Reset entire Tx ("TDC") subsystem */
+int hxge_reset_tdc(struct hxge_adapter *hxgep)
+{
+       /* Quiesce ("shutdown") all transmit activity first */
+
+       hxge_disable_tx(hxgep);
+
+       /* Generate tdc_core logic reset */
+
+       hxge_block_reset(hxgep, LDV_TXDMA);
+
+       /* Finally, bring all the Tx channels back up */
+
+       hxge_enable_tx(hxgep);
+
+       return 0;
+}
+
+
+/* Re-enable Transmits/Tx interrupts (e.g., after LDF1 auto-disable) */
+int hxge_reenable_tx(struct hxge_adapter *hxgep)
+{
+       int i;
+
+       for (i = 0; i < hxgep->max_tdcs; i++)
+               hxge_reenable_tx_channel(hxgep, i);
+
+       /* We assume the Tx interrupts "enablement" was unchanged by
+        * whatever course of events led us here. */
+
+       return 0;
+}
+
+
+/* Wait for Transmits/Tx to go idle (wait for Tx QST to set) */
+int hxge_qstwait_tx(struct hxge_adapter *hxgep)
+{
+       int i;
+
+       for (i = 0; i < hxgep->max_tdcs; i++)
+               hxge_qstwait_tx_channel(hxgep, i);
+
+       return 0;
+}
+
+
+static int get_desc_required(struct tx_ring_t *tx_ring, struct sk_buff *skb)
+{
+       int skb_len = skb->len;
+       int num_descs = 0, len, tx_len;
+
+       if ((skb_len + TX_PKT_HEADER_SIZE < tx_ring->tx_buffer_size) &&
+           !skb_shinfo(skb)->nr_frags)
+               return 1;
+
+       len = skb_headlen(skb);
+       num_descs++; /* one for internal header */
+       while (len) {
+               tx_len = len < TX_MAX_TRANSFER_LENGTH ? 
+                                       len : TX_MAX_TRANSFER_LENGTH;
+               len -= tx_len;
+               num_descs++;
+       }
+
+       /* The max size of an SKB fragment is one page size i.e 4096 bytes. 
+        * However, due to a bug, the max size that one Tx descriptor buffer
+        * can transfer is 4076 bytes. So, worst case, we might need at most
+        * two descriptors to send one fragment 
+        */ 
+       if (skb_shinfo(skb)->nr_frags) {
+               num_descs += (2*skb_shinfo(skb)->nr_frags);
+               return num_descs;
+       }
+
+       return num_descs;
+}
+
+
+/* Pick the next channel to transmit on. We pick the CPU that the transmit
+ * thread is running on (hoping cpu affinity helps). If that particular
+ * channel does not have sufficient descriptors for this skb, then do a
+ * round robin from that point till we find one that has space; better to 
+ * find one than just return attempting a retransmit from higher layers
+ */
+static struct tx_ring_t *get_channel_to_transmit(struct hxge_adapter *hxgep, 
+                       struct sk_buff *skb, int *state, int *desc_required)
+{      
+       uint8_t tx_channel_state = 0;
+       struct tx_ring_t *tx_ring = NULL;
+       int channel, start_channel, channels_tried;
+       int attempt = 1; /* 1 ms */
+
+       *state = NETDEV_TX_OK;
+
+       channel = start_channel = smp_processor_id() % hxgep->max_tdcs;
+       for (channels_tried = 0; channels_tried < hxgep->max_tdcs; 
+               channels_tried++, channel = (channel+1) % hxgep->max_tdcs)
+       {
+                tx_ring = &hxgep->tx_ring[channel];
+
+               if (!test_bit(RING_ENABLED, &tx_ring->state)) {
+                       tx_channel_state |= (1 << channel); 
+                       continue;
+               }
+               /* Grab the Tx channel lock to avoid race between multiple Tx
+                * threads using this channel. Also, synchronizes with the 
+                * reset code since we don't want to be in here while a reset 
+                * is happening and visa versa.
+                */
+               while (!(spin_trylock(&tx_ring->lock))) {
+                       mdelay(1);
+                       if (!attempt) {
+                               HXGE_ERR(hxgep, "Could not get tx lock!");
+                               tx_ring->stats.txlock_acquire_failed++;
+
+                               dev_kfree_skb_any(skb);
+                               *state = NETDEV_TX_OK;
+                               return NULL;
+                       }
+                       attempt--;
+               }
+               if (*desc_required < 0)
+                       *desc_required = get_desc_required(tx_ring, skb);
+               if (atomic_read(&tx_ring->descs_avail) < *desc_required) {
+                       wake_up_interruptible(&tx_ring->reclaim_event);
+                       spin_unlock(&tx_ring->lock);
+                       continue;
+               }
+               else break;
+       }
+
+       if (tx_channel_state == (1 << HXGE_MAX_TDCS) -1) {
+               HXGE_ERR(hxgep, "All channels disabled!");
+               dev_kfree_skb_any(skb);
+               *state = NETDEV_TX_OK;
+               return NULL;
+       }
+
+       if (channels_tried == hxgep->max_tdcs) {
+                *state = NETDEV_TX_BUSY;
+               return NULL;
+       }
+
+       return tx_ring;
+}
+
+static inline int valid_packet(struct hxge_adapter *hxgep, 
+                       struct tx_ring_t *tx_ring, struct sk_buff *skb)
+{
+       int skb_len = skb->len;
+
+       /* Badly constructed skb */
+       if (unlikely(!skb || (skb_len <= 0))) {
+               HXGE_ERR(hxgep, "Badly formed skb!");
+               return 0;
+       }
+
+       /* More skb fragments than we have Tx descriptor ring entries */
+       if (unlikely(skb_shinfo(skb)->nr_frags + 1 > tx_ring->num_tdrs)) {
+               HXGE_ERR(hxgep, "Too many skb fragments than space allows");
+               return 0;
+       }
+
+       /* packet larger than MTU size. Really shoud not happen since higher 
+           layer protocol probably needs to fragment the packet before sending 
+           to us */
+       if (skb_len > hxgep->vmac.maxframesize) {
+               HXGE_ERR(hxgep, "skb_len is %d, Packet size MTU (max frame size) supported",skb_len);
+               return 0;
+       }
+
+       return 1;
+
+}
+
+/* A utility routine to allocate a new data buffer for transmit if the 
+ * current one is full. The caller must ensure that the curr_index is properly
+ * updated
+ */
+static inline struct tx_buf_t *get_txbuf(struct hxge_adapter *hxgep, 
+               struct tx_ring_t *tx_ring, int *desc_required)
+{
+        struct tx_buf_t *tx_buf; 
+        tx_buf = &tx_ring->tx_buf[tx_ring->curr_index];
+
+        if (!tx_buf->flags) /* unused location; allocate new buffer */
+        {
+
+#ifdef CONFIG_ERRINJECT
+               if (hxgep->err_flags & ALLOC_PAGES_FAILURE) {
+                       HXGE_ERR(hxgep, "no page alloc'ed (errinj)");
+                       return NULL;
+               }
+#endif
+       
+               /* allocate new page */
+                tx_buf->map.vaddr = (caddr_t) __get_free_page(GFP_DMA);
+
+               if (!tx_buf->map.vaddr) {
+                       HXGE_ERR(hxgep, "no page alloc'ed");
+                       return NULL;
+               }
+
+#ifdef CONFIG_ERRINJECT
+               if (hxgep->err_flags & PCIMAP_FAILURE) {
+                       HXGE_ERR(hxgep, "pci_map_page failed (errinj)");
+                       free_page((unsigned long)tx_buf->map.vaddr);
+                       return NULL;
+               }
+#endif
+
+               /* grab a DMA-map for the page */
+                tx_buf->map.dma_addr = pci_map_page(hxgep->pdev,
+                        virt_to_page(tx_buf->map.vaddr),
+                        offset_in_page(tx_buf->map.vaddr),
+                        PAGE_SIZE, PCI_DMA_TODEVICE);
+
+               if (!tx_buf->map.dma_addr)
+               {
+                       HXGE_ERR(hxgep, "pc_map_page failed");
+                       free_page((unsigned long)tx_buf->map.vaddr);
+                       return NULL;
+               }
+
+               tx_buf->map.len = 0;
+                tx_buf->flags = TX_FLAGS_DATA | TX_FLAGS_ALLOC | TX_FLAGS_UNMAP;
+                tx_buf->skb = NULL; /* should be set in hdr desc */
+               ++*desc_required; 
+        }
+
+
+       return tx_buf;
+}
+
+/* Utility routine to write the transmit descriptors into the Tx descriptor 
+ * ring for the HW to process. Only the non-SOP entries are written using 
+ * this routine.
+ */
+static int write_tx_descs(struct hxge_adapter *hxgep, struct tx_ring_t *tx_ring,
+                               int start, int num_descs)
+{
+       int i;
+       tx_desc_t desc;
+       desc.value = 0;
+
+       
+       for (i = start; i < (start+num_descs); i++) {
+               struct tx_buf_t *tx_buf;
+               hpi_handle_t handle;
+               tx_desc_t *descp;
+
+               handle = &tx_ring->desc_ring.vaddr[i % tx_ring->num_tdrs];
+               tx_buf = &tx_ring->tx_buf[i % tx_ring->num_tdrs];
+               if (hpi_txdma_desc_gather_set(handle, &desc, 1, 0, 0,
+                   tx_buf->map.dma_addr, tx_buf->map.len) != HPI_SUCCESS)
+               {
+                       HXGE_ERR(hxgep, "hpi_txdma_desc_gather_set failed");
+                       return -1;
+               }
+               descp = (tx_desc_t *)handle;
+               HXGE_DBG(hxgep, "TX_BUF");
+               HXGE_DBG(hxgep, "       tx_buf->len : %d",tx_buf->map.len);
+               HXGE_DBG(hxgep, "       tx_buf->vaddr : %p",tx_buf->map.vaddr);
+               HXGE_DBG(hxgep, "       tx_buf->dma_addr: %p",(void *)tx_buf->map.dma_addr);
+               HXGE_DBG(hxgep, " DESC =>");
+               HXGE_DBG(hxgep, "    SOP:%d, mark:%d, num_ptr:%d, len:%d, sad:0x%llx", 
+                       descp->bits.sop, descp->bits.mark, 
+                       descp->bits.num_ptr, descp->bits.tr_len,
+                        (unsigned long long)descp->bits.sad);  
+       }
+       return 0;
+}
+                       
+/* This routine copies data from the SKB to staging buffers instead of 
+ * using scatter gather lists like map_skbdata_to_descs. This routine is 
+ * called when the number of skb fragments approach or exceed the 15 
+ * descriptors per packet limit
+ */
+static int copy_skbdata_to_descs(struct hxge_adapter *hxgep, 
+               struct tx_ring_t *tx_ring, char *data_ptr, uint32_t len,
+               int *desc_required)
+{
+       struct tx_buf_t *tx_buf = NULL;
+       
+       while (len) {
+               uint32_t max_len;
+               uint32_t tx_len;
+
+               tx_buf = get_txbuf(hxgep, tx_ring, desc_required);
+
+               if (!tx_buf || !(tx_buf->flags & TX_FLAGS_ALLOC)) {
+                       HXGE_ERR(hxgep, "tx_buf (%p) alloc failed",tx_buf);
+                       return COPY_DESC_FAILED;
+               }
+
+               max_len = TX_MAX_TRANSFER_LENGTH - tx_buf->map.len;
+               tx_len = len < max_len ?  len : max_len;
+
+               memcpy(tx_buf->map.vaddr + tx_buf->map.len, data_ptr, tx_len);
+               tx_buf->map.len += tx_len;
+               data_ptr += tx_len;
+               len -= tx_len;
+
+               /* the buffer is full; start new buffer next time around */
+               if (tx_buf->map.len == TX_MAX_TRANSFER_LENGTH)
+                       TXDMA_GET_NEXT_INDEX(tx_ring, 1);
+       }
+
+       /* corner case: When we are the last skb fragment calling in and 
+         * we happened to just fill this data buffer, we don't want to bump 
+         * the index in this case because we did it at the tail end of the
+         * while loop above. However, we do want the caller of this routine
+         * to bump to the next index a new packet
+        */
+       if (tx_buf && (tx_buf->map.len < TX_MAX_TRANSFER_LENGTH))
+               return 1;
+
+       return 0;
+}
+
+/* To map skb data into Tx descriptor ring entries. The case for the internal
+ * header is done separately (not here). Also, this does not include the 
+ * case where the skb is copied in to the tx buffer 
+ */
+static int map_skbdata_to_descs(struct hxge_adapter *hxgep,
+               struct tx_ring_t *tx_ring, char *data_ptr, uint32_t len,
+               int *desc_required)
+{
+       uint32_t tx_len;
+       struct tx_buf_t *tx_buf;
+
+       while (len) {
+               tx_buf = &tx_ring->tx_buf[tx_ring->curr_index];
+               tx_len = len < TX_MAX_TRANSFER_LENGTH ?
+                                   len : TX_MAX_TRANSFER_LENGTH;
+
+#ifdef CONFIG_ERRINJECT
+               if (hxgep->err_flags & PCIMAP_FAILURE) {
+                       HXGE_ERR(hxgep, "pcimap err injected");
+                       return MAP_DESC_FAILED;
+               }
+#endif
+                       
+                tx_buf->map.dma_addr = pci_map_page(hxgep->pdev,
+                                        virt_to_page(data_ptr),
+                                        offset_in_page(data_ptr), tx_len,
+                                        PCI_DMA_TODEVICE);
+
+               if (!tx_buf->map.dma_addr) {
+                       HXGE_ERR(hxgep, "pci_map_page failed");
+                       return MAP_DESC_FAILED;
+               }
+
+                tx_buf->map.len = tx_len;
+               tx_buf->map.vaddr = data_ptr;
+                tx_buf->flags = TX_FLAGS_DATA | TX_FLAGS_UNMAP;
+                tx_buf->skb = NULL; /* already set in hdr */
+                data_ptr += tx_len;
+                len -= tx_len;
+               TXDMA_GET_NEXT_INDEX(tx_ring, 1);
+                ++*desc_required;
+
+       }
+
+       return 0;
+}
+
+/* Cleanup up in the event of a failure either in map_skbdata_to_descs
+ * or copy_skbdata_to_descs. Free up allocated pages and unmap dma
+ * mappings as appropriate. Also move the curr_index back for next packet
+ */
+
+static void cleanup_descs(struct hxge_adapter *hxgep, 
+                       struct tx_ring_t *tx_ring, int descs)
+{ 
+       struct tx_buf_t *tx_buf;
+
+       while (descs) {
+               TXDMA_DEC_INDEX(tx_ring);
+               tx_buf = &tx_ring->tx_buf[tx_ring->curr_index];
+               if (tx_buf->flags & TX_FLAGS_UNMAP) {
+                       int len = (tx_buf->flags & TX_FLAGS_ALLOC) ? PAGE_SIZE :
+                               tx_buf->map.len;
+                       pci_unmap_page(hxgep->pdev, tx_buf->map.dma_addr, 
+                               len, PCI_DMA_TODEVICE);
+               }
+               if (tx_buf->flags & TX_FLAGS_ALLOC) 
+                       free_page((unsigned long)tx_buf->map.vaddr);
+
+               memset(tx_buf, 0, sizeof(struct tx_buf_t));
+               descs--;
+       }
+}
+
+
+
+/* Fill in the internal header set up in a Tx buffer by the transmit code. This
+ * requires tunneling through the ethernet payload and getting inforamtion from
+ * the L2, L3 and L4 layers to fill in information required.
+ * Arguments:
+ *     pkt_hdr - Pointer to where the header information
+ *     skb     - Contains the data payload
+ *     len     - The total length of the data payload excluding internal header
+ */
+static void fill_tx_hdr(tx_pkt_header_t *pkt_hdr, struct sk_buff *skb, int len
+#ifdef CONFIG_ERRINJECT
+                       , struct hxge_adapter *hxgep
+#endif
+)
+{
+       uint8_t                 *ip_p = NULL;
+       uint16_t                eth_type;
+       char                    *proto_hdr = NULL;
+       struct udphdr           *udp_hdr = NULL;
+       struct tcphdr           *tcp_hdr = NULL;
+       struct iphdr            *ip_hdr = NULL;
+       uint8_t                 ip_proto = 0;
+       struct ipv6hdr          *ipv6_hdr = NULL;
+       struct skb_hdr_info_t   *skb_hdr_info;
+
+       skb_hdr_info = (struct skb_hdr_info_t *)skb->cb;
+       memset(pkt_hdr, 0, sizeof(tx_pkt_header_t));
+       pkt_hdr->bits.tot_xfer_len = len;
+       
+       /* Read the type field from the ethernet frame */
+       eth_type = ntohs(skb->protocol);
+
+
+       /* This is when type < 1500 i.e. 802.3 type and not Ethernet III */
+       if (eth_type < ETH_DATA_LEN) { 
+               if (*(skb->data + ETH_HLEN) == LLC_SAP_SNAP) {
+                       eth_type = ntohs(*((uint16_t*)(skb->data + ETH_HLEN + 6)));
+                       if (eth_type == ETH_P_IP || eth_type == ETH_P_IPV6)
+                               ip_p = (uint8_t*)(skb->data + ETH_HLEN + 8);
+               } else return;
+        } else if (eth_type == ETH_P_8021Q) { /* VLAN support */
+
+                pkt_hdr->bits.vlan = 1;
+                eth_type = ntohs(((struct vlan_ethhdr *)skb->data)->h_vlan_encapsulated_proto);
+                if (eth_type == ETH_P_IP || eth_type == ETH_P_IPV6)
+                        ip_p = (uint8_t*)(skb->data + VLAN_ETH_HLEN);
+        } else  /* Ethernet III type */
+                ip_p = (uint8_t*)(skb->data + ETH_HLEN);
+
+
+       /* Now we have got the "real" type value. Tunnel through the IP 
+           payload to get L3 and L4 information needed in the header */
+       switch (eth_type) {
+       case ETH_P_IP : /* IPv4 */
+               ip_hdr = (struct iphdr *)ip_p;
+               pkt_hdr->bits.ip_ver = 0;
+               pkt_hdr->bits.ihl = ip_hdr->ihl;
+               pkt_hdr->bits.l3start = ((ulong)ip_hdr - (ulong)skb->data) >> 1;
+               ip_proto = ip_hdr->protocol;
+               proto_hdr = (char *)ip_hdr + (ip_hdr->ihl<<2);
+               break;
+       case ETH_P_IPV6: /* IPv6 */
+               ipv6_hdr = (struct ipv6hdr *)ip_p;
+               pkt_hdr->bits.ip_ver = 1;
+               pkt_hdr->bits.ihl = 40 >> 2; /* hard-coded */
+               pkt_hdr->bits.l3start = ((ulong)ipv6_hdr - (ulong)skb->data)>>1;
+               ip_proto = ipv6_hdr->nexthdr;
+               proto_hdr = (char *)ipv6_hdr + 40;
+               break;
+       default :
+               return;
+               break;
+       }
+
+       /* Checksumming is done only if Linux has marked for it to be done. 
+          The driver has notified Linux that it does L4 checksumming as part
+          of initialization but there are scenarios where Linux will have to
+          do checksumming itself (IP fragments). So, check the ip_summed field
+          to see if Linux has requested for it */
+
+       /* TODO: Is a zero value in l4stuff a valid offset? How does one turn 
+                 off checksumming on a per-packet basis on Hydra? */
+       switch (ip_proto) {
+       case IPPROTO_TCP : 
+               tcp_hdr = (struct tcphdr *)proto_hdr;
+               pkt_hdr->bits.l4start = (ulong)tcp_hdr - (ulong)skb->data;
+               skb_hdr_info->l4_payload_offset  = pkt_hdr->bits.l4start + 
+                                                       (tcp_hdr->doff << 2);
+               pkt_hdr->bits.l4start >>=1;
+               if (skb->ip_summed == HXGE_CHECKSUM) {/* hardware do checksum */
+                       pkt_hdr->bits.cksum_en_pkt_type = 1;
+                       pkt_hdr->bits.l4stuff = pkt_hdr->bits.l4start +
+                                               (SKB_CKSUM_OFFSET(skb) >> 1);
+#ifdef CONFIG_ERRINJECT
+                       if (hxgep->err_flags & CHKSUM_FAILURE) {
+                                        HXGE_ERR(hxgep, "Injecting checksum error");
+                                pkt_hdr->bits.l4stuff--;
+                       }
+#endif
+               }
+               break;
+       case IPPROTO_UDP :
+               udp_hdr = (struct udphdr *)proto_hdr;
+               pkt_hdr->bits.l4start = (ulong)udp_hdr - (ulong)skb->data;
+               skb_hdr_info->l4_payload_offset = pkt_hdr->bits.l4start + 
+                                               sizeof(struct udphdr);
+               pkt_hdr->bits.l4start >>= 1;
+
+
+
+               if (skb->ip_summed == HXGE_CHECKSUM) {
+                       /* workaround a hw checksum offload for udp/ipv6. 
+                          Complete the partial checksum that was already
+                          setup in skb->csum just like the hw would have done
+                          it */
+
+                       if (eth_type == ETH_P_IPV6) {
+                               fixup_checksum(skb
+#ifdef CONFIG_ERRINJECT
+                               ,hxgep
+#endif
+                               );      
+                               break;
+                       }
+                       pkt_hdr->bits.cksum_en_pkt_type = 2;
+                       pkt_hdr->bits.l4stuff = pkt_hdr->bits.l4start +
+                                               (SKB_CKSUM_OFFSET(skb) >> 1);
+#ifdef CONFIG_ERRINJECT
+                       if (hxgep->err_flags & CHKSUM_FAILURE) {
+                                        HXGE_ERR(hxgep, "Injecting checksum error");
+                                pkt_hdr->bits.l4stuff--;
+                       }
+#endif
+
+               }
+               break;
+       default :
+               break;
+       }
+}
+
+
+/* The main routine for transmitting a packet. It is called directly by the 
+ * Linux network stack via the hard_xmit_frame network device function pointer.
+ * It determines which channel to pick for transmit, maps the packet data to
+ * Tx descriptor ring entries, creates the internal packet header and informs
+ * hydra of the new descriptor entries via the kick register
+ */
+
+int hxge_tx_ring(struct sk_buff *skb, struct net_device *netdev)
+
+{
+       int channel, desc_required=-1, hdr_index, i;
+       struct hxge_adapter *hxgep = netdev_priv(netdev);
+       struct tx_ring_t *tx_ring;
+       int skb_len = skb->len, tot_len;
+       int len;
+       struct tx_buf_t *tx_buf;
+       tx_desc_t desc;
+       tx_desc_t *descp;
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+       tx_pkt_header_t *pkt_hdr;
+       int state;
+
+       /* 
+        * Get channel to transmit on. It returns with the tx_ring->lock locked
+        * if successful 
+        */
+
+       tx_ring = get_channel_to_transmit(hxgep, skb, &state, &desc_required);
+       if (!tx_ring) {
+                if (state == NETDEV_TX_BUSY) {
+                       if (!netif_queue_stopped(netdev))
+                               netif_stop_queue(netdev);
+               }
+               return (state);
+       }
+
+       /* Validate the packet */
+       if (!valid_packet(hxgep, tx_ring, skb)) {
+               HXGE_ERR(hxgep, "Freeing skb due to invalid packet");
+               dev_kfree_skb_any(skb);
+               spin_unlock(&tx_ring->lock);
+               return (NETDEV_TX_OK);
+       }
+
+
+       channel = tx_ring->tdc;
+
+       /* There is space for at least the current packet */
+
+       TXDMA_GET_CURR_INDEX(tx_ring);
+       hdr_index= tx_ring->curr_index;
+       tx_buf = &tx_ring->tx_buf[hdr_index];
+        tx_buf->map.vaddr = tx_ring->data_buf.vaddr + 
+                               (hdr_index*tx_ring->tx_buffer_size);
+
+        tx_buf->map.dma_addr = tx_ring->data_buf.dma_addr + 
+                               (hdr_index*tx_ring->tx_buffer_size);
+       tx_buf->flags = TX_FLAGS_HDR;
+       tx_buf->map.len = TX_PKT_HEADER_SIZE; /* assume just header; no data content */
+       tx_buf->skb = skb;
+       skb_orphan(skb);
+#ifdef CONFIG_ERRINJECT
+       atomic_inc(&skb_count);
+#endif
+
+       tot_len = TX_PKT_HEADER_SIZE;
+       /* Increment to next free entry */
+       TXDMA_GET_NEXT_INDEX(tx_ring, 1);
+
+#if 0
+       HXGE_DBG(hxgep, "Have %d descs", desc_required);
+       HXGE_DBG(hxgep, "SKB => ");
+       HXGE_DBG(hxgep, "   skb->len = %d",skb->len);
+       HXGE_DBG(hxgep, "   skb->priority = %d", skb->priority);
+       HXGE_DBG(hxgep, "   skb->data_len= %d", skb->data_len);
+       HXGE_DBG(hxgep, "   skb->nr_frags= %d", skb_shinfo(skb)->nr_frags);
+#endif
+       
+       if (desc_required == 1) /* small packet */  {
+               len = skb_headlen(skb);
+               memcpy((char *)tx_buf->map.vaddr + TX_PKT_HEADER_SIZE, skb->data, 
+                                       len);
+               tx_buf->flags = TX_FLAGS_ALL;
+               tx_buf->map.len += len; /* data len in addition to internal hdr */
+               tot_len += len;
+       } else {
+               int ret = 0;
+               desc_required = 1; /* for header */
+
+               if (map_skbdata_to_descs(hxgep, tx_ring, 
+                     (char *)skb->data, skb_headlen(skb),&desc_required) < 0)
+               {
+                       HXGE_ERR(hxgep, "map_skbdata_to_descs failed");
+                       FREE_SKB(skb);
+                       cleanup_descs(hxgep, tx_ring, desc_required);
+                       spin_unlock(&tx_ring->lock);
+                       return (NETDEV_TX_OK);
+               }   
+               
+               for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+                       skb_frag_t *fragp = &skb_shinfo(skb)->frags[i];
+                       char *dat = (char *)page_address(fragp->page)+fragp->page_offset;
+
+                       HXGE_DBG(hxgep, "Frag %d @ (%p,%d), len %d",i,(char *)fragp->page, fragp->page_offset,fragp->size);
+
+
+                       /* CR 7104801: If the number of skb fragments are more
+                        * the number of tx descriptors available, then we
+                        * have to copy and consolidate the remaining fragments 
+                        * into newly allocated buffers. We need to make 
+                        * sure that at least 3 descriptor entries are reserved
+                        * for the copy giving us a total of 12KB (4KB page).
+                        * This should be sufficient on Hydra where the largest
+                        * packet cannot exceed 9KB
+                        */
+                       if (desc_required > HXGE_TX_DESCS_PER_PACKET-4) 
+                               ret = copy_skbdata_to_descs(hxgep, tx_ring, 
+                                       dat, fragp->size, &desc_required);
+                       else 
+                               ret = map_skbdata_to_descs(hxgep, tx_ring, dat,
+                                        fragp->size, &desc_required);
+
+                       if (ret < 0)
+                       {
+                               char fn[25];
+                               if (ret == COPY_DESC_FAILED)
+                                       strcpy(fn, "copy_skbdata_to_descs");
+                               else
+                                       strcpy(fn, "map_skbdata_to_descs");
+                                       
+                               HXGE_ERR(hxgep, "%s failed", fn);
+                               FREE_SKB(skb);
+                               cleanup_descs(hxgep, tx_ring, desc_required);
+                               spin_unlock(&tx_ring->lock);
+                               return (NETDEV_TX_OK);
+                       }
+                       
+               }
+               tot_len += skb_len;
+
+               /* copy_skbdata_to_descs ends in the middle of a tx_buf; need
+                * to point to new one for next packet
+                */
+               if (ret > 0)
+                       TXDMA_GET_NEXT_INDEX(tx_ring, 1);
+               
+       }
+
+       /* write out the non-SOP descriptors now */
+       write_tx_descs(hxgep, tx_ring, hdr_index+1, desc_required-1);
+
+       /* Create internal header. This requires tunneling into packet
+          data. When doing ethtool testing, just fill total len and ignore
+           other fields in the skb header  */
+       if (unlikely(test_bit(HXGE_DEVICE_TESTING, &hxgep->state))) {
+               pkt_hdr = (tx_pkt_header_t *)tx_buf->map.vaddr;
+               pkt_hdr->value = 0;
+               pkt_hdr->bits.tot_xfer_len = tot_len+skb->priority;
+               HXGE_DBG(hxgep, "Internal header size is %d", pkt_hdr->bits.tot_xfer_len);
+       }
+       else 
+               fill_tx_hdr((tx_pkt_header_t *)tx_buf->map.vaddr, skb, tot_len
+#ifdef CONFIG_ERRINJECT
+               , hxgep
+#endif
+);
+
+
+       /* Set up and write the SOP descriptor. The length does not include 
+        * internal packet length; just the data packet only */
+
+       desc.value = 0;
+       tx_ring->mark_ints = (tx_ring->mark_ints+1) % hxgep->tx_mark_ints;
+
+
+       hpi_txdma_desc_gather_set(&tx_ring->desc_ring.vaddr[hdr_index], &desc, 
+                               0, (tx_ring->mark_ints == 0), desc_required,
+                               tx_buf->map.dma_addr, tx_buf->map.len);
+
+
+       tx_ring->stats.descs_used[desc_required]++;
+
+       /* Sanity Test: descriptors used should never exceed HW limit of 15 */
+        if (desc_required > HXGE_TX_DESCS_PER_PACKET) {
+               HXGE_ERR(hxgep, "BUG: desc_required > %d!! Will cause tx_reset",HXGE_TX_DESCS_PER_PACKET); 
+               BUG();
+       }
+
+       HXGE_DBG(hxgep, "Sending through channel %d. Packet Info =>",channel);
+       for (i = 0, descp=&tx_ring->desc_ring.vaddr[hdr_index]; i < desc_required; i++)
+               HXGE_DBG(hxgep, "    SOP:%d, mark:%d, num_ptr:%d, len:%d, sad:0x%llx",
+                        descp->bits.sop, descp->bits.mark,
+                        descp->bits.num_ptr, descp->bits.tr_len,
+                        (unsigned long long)descp->bits.sad);
+
+
+       /* Update the descriptors available for use. Note that update to this
+           variable races with the reclaim thread, hence an atomic operation */
+       atomic_sub(desc_required, &tx_ring->descs_avail);
+
+       if (atomic_read(&tx_ring->descs_avail) < 0) {
+           HXGE_ERR(hxgep, "Descriptors available less than zero!!");  
+       }
+       /* Update descriptors available. Write the SOP descriptor entry and 
+           kick the number of new entries added */
+       TXDMA_UPDATE_INDEX(tx_ring);
+       hpi_txdma_desc_kick_reg_set(handle, channel, tx_ring->tail,
+                                       tx_ring->wrap);
+
+       /* Successfully queued one network packet of <skb_len> bytes */
+
+       tx_ring->stats.opackets++;
+       tx_ring->stats.obytes += skb_len;
+
+       spin_unlock(&tx_ring->lock);
+       
+       return NETDEV_TX_OK;
+}
+
+static inline int compute_tot_hdrlen(struct skb_hdr_info_t *skb_hdr, 
+                                       struct staging_info_t *si)
+{
+       int l4_hdr_len, l3_hdr_len;
+       tx_pkt_header_t *pkt_hdr = &si->pkthdr;
+
+       si->l3_offset = pkt_hdr->bits.l3start << 1;
+       si->l4_offset = pkt_hdr->bits.l4start << 1;
+       l4_hdr_len  = skb_hdr->l4_payload_offset -
+                               (pkt_hdr->bits.l4start<<1);
+       si->l4_hdr_len = l4_hdr_len;
+       l3_hdr_len = (pkt_hdr->bits.l4start-pkt_hdr->bits.l3start)<<1;
+       return ((pkt_hdr->bits.l3start<<1) + l3_hdr_len + l4_hdr_len);
+}
+
+static void free_staging_info(struct hxge_adapter *hxgep, 
+                               struct staging_info_t *si, int failure)
+{
+       if (failure) {
+               int i;
+               struct pci_dma_map_t *pci_map = &si->pci_map;
+               if (si->hdr_array.vaddr) 
+                       pci_free_consistent(hxgep->pdev, si->hdr_array.len, 
+                               si->hdr_array.vaddr, si->hdr_array.dma_addr);
+
+               if (pci_map->num_dma_mappings) {
+                       for (i = 0; i < pci_map->num_dma_mappings; i++) 
+                               pci_unmap_page(hxgep->pdev, 
+                                       pci_map->dma_map[i].dma_addr, 
+                                       pci_map->dma_map[i].len, 
+                                       PCI_DMA_TODEVICE);
+                       kfree(pci_map->dma_map);
+               }
+       }
+
+       if (si->desc) 
+               kfree(si->desc);
+
+       if (si)
+               kfree(si);
+}
+
+static struct staging_info_t *setup_staging_info(struct hxge_adapter *hxgep,
+                                       struct sk_buff *skb)
+{
+       struct staging_info_t *si;
+       struct skb_hdr_info_t *skb_hdr = (struct skb_hdr_info_t *)skb->cb;
+       int frame_cnt = SKB_GSO_SEGS(skb);
+
+       si = (struct staging_info_t *)kzalloc(sizeof(struct staging_info_t), GFP_KERNEL);
+       if (!si) {
+               HXGE_ERR(hxgep,"No space for staging structure");
+               return NULL;
+       }
+
+       memset(skb_hdr, 0, sizeof(struct skb_hdr_info_t));
+       fill_tx_hdr(&si->pkthdr, skb, 0
+#ifdef CONFIG_ERRINJECT
+       , hxgep
+#endif
+       );
+
+       si->tcpip_hdr_len = compute_tot_hdrlen(skb_hdr, 
+                                               si);
+       si->hdr_array.len = frame_cnt* sizeof(si->hdr_template);
+       si->max_frames = frame_cnt;
+       si->frame_size = SKB_IS_GSO(skb);
+       si->hdr_array.vaddr  = pci_alloc_consistent(hxgep->pdev, 
+                               si->hdr_array.len, 
+                               &si->hdr_array.dma_addr);
+       if (!si->hdr_array.vaddr)
+               goto fail;
+
+       /* do not use until we are done setting up the entire packet */
+       si->desc = kmalloc(frame_cnt*DESCS_PER_FRAME*
+                               sizeof(struct staging_desc_t), GFP_KERNEL);
+       if (!si->desc) {
+               HXGE_ERR(hxgep,"No space for staging desc");
+               goto fail;
+       }
+
+       /* This is stored so that we can free the staging structure but 
+        * keep a pointer to the  hdr array which needs to be around till
+        * the skb is done i.e entire packet has been transmitted
+        */
+       skb_hdr->hdr_array = si->hdr_array;
+
+       /* setup the hdr template with standard  values. This contains the
+           values for l3stuff, l4stuff, l3start, l4start, etc all set up
+          by the call to fill_tx_hdr and saved to si->pkthdr */
+       memcpy(si->hdr_template, (char *)&si->pkthdr, 
+                                       sizeof(tx_pkt_header_t));
+       memcpy(si->hdr_template+TX_PKT_HEADER_SIZE, skb->data,
+                       si->tcpip_hdr_len);
+
+       /* Initialize some of the fields within the template with initial
+          values from the skb */
+       do {
+               char *hdrp  = si->hdr_template;
+               struct tcphdr *tcphdrp = (struct tcphdr *)
+                       (hdrp + TX_PKT_HEADER_SIZE + si->l4_offset);
+               struct iphdr *iphdrp  = (struct iphdr *)
+                       (hdrp + TX_PKT_HEADER_SIZE + si->l3_offset);
+               si->tcp_sequence = ntohl(tcphdrp->seq);
+               si->ip_id = ntohs(iphdrp->id);
+               /* Save the initial skb state of the flags and then clear it
+                  out in the template. fixup_tcpip_hdr takes care of setting
+                  the vaues in the appropriate frame */
+               if (tcphdrp->urg) si->tcp_flags = TCP_FLAGS_URG;
+               if (tcphdrp->psh) si->tcp_flags |= TCP_FLAGS_PSH;
+               if (tcphdrp->rst) si->tcp_flags |= TCP_FLAGS_RST;
+               if (tcphdrp->fin) si->tcp_flags |= TCP_FLAGS_FIN;
+               tcphdrp->urg = tcphdrp->psh = tcphdrp->rst = 0;
+               tcphdrp->fin = 0;
+
+       } while (0);
+          
+       return si;
+fail:
+       free_staging_info(hxgep, si, 1);
+       return NULL;
+}
+
+static inline void fixup_tcpip_hdr(struct staging_info_t *sp, int frame, int len,
+                               struct tcphdr *tcphdrp, struct iphdr *iphdrp)
+{
+       tcphdrp->seq = htonl(sp->tcp_sequence);
+       iphdrp->id = htons(sp->ip_id++);
+       sp->tcp_sequence += len;
+       iphdrp->tot_len = htons(len + sp->l4_hdr_len + sp->l4_offset - 
+                                       sp->l3_offset);
+
+       /* Fix up the TCP flags; only the first and last matter. The rest of 
+          the frames have zeros for these flags */
+       if (!frame)  // first frame
+               tcphdrp->urg = (sp->tcp_flags & TCP_FLAGS_URG);
+       else if (frame == sp->max_frames-1) {
+               tcphdrp->psh = (sp->tcp_flags & TCP_FLAGS_PSH);
+               tcphdrp->rst = (sp->tcp_flags & TCP_FLAGS_RST);
+               tcphdrp->fin = (sp->tcp_flags & TCP_FLAGS_FIN);
+       }
+       /* do checksumming last after all the fields in tcp and ip
+         * headers have been fixed up properly
+        */
+       iphdrp->check = 0;
+       iphdrp->check = ip_fast_csum((uint8_t *)iphdrp, iphdrp->ihl);
+       tcphdrp->check = ~csum_tcpudp_magic(iphdrp->saddr, iphdrp->daddr, 
+                                       sp->l4_hdr_len+len, IPPROTO_TCP, 0);
+}
+
+static int setup_frame(struct hxge_adapter *hxgep, struct staging_info_t *si, 
+                               int len, int frame)
+{
+       int ngathers = 1; // alwauys one descriptor
+       char *hdrp =  si->hdr_array.vaddr+(frame*HDR_TEMPLATE_SIZE);
+       struct staging_desc_t *descp = &si->desc[si->desc_idx];
+       struct staging_desc_t *sop_descp = descp++;
+       struct tcphdr *tcphdrp;
+       struct iphdr  *iphdrp;
+       tx_pkt_header_t *pkt_hdr;
+       int loc_len = len;
+       int idx = si->dma_map_idx;
+       int off = si->dma_map_off;
+       struct dma_map_t *dma_map = si->pci_map.dma_map;
+
+               
+       memcpy(hdrp, si->hdr_template, sizeof(si->hdr_template));
+       tcphdrp = (struct tcphdr *)(hdrp + TX_PKT_HEADER_SIZE + 
+                                       si->l4_offset);
+       iphdrp  = (struct iphdr *)(hdrp + TX_PKT_HEADER_SIZE + 
+                                       si->l3_offset);
+       fixup_tcpip_hdr(si, frame, len, tcphdrp, iphdrp);
+
+       while (loc_len) {
+               dma_addr_t dma_addr = dma_map[idx].dma_addr+off;
+               int desc_len = min(loc_len, dma_map[idx].len-off);
+               if (idx >= si->pci_map.num_dma_mappings) {
+                       HXGE_ERR(hxgep,"idx (%d) > num_mappings (%d), dma_map = %p, si = %p, len=%d",idx,si->pci_map.num_dma_mappings,dma_map, si, len);
+                       BUG();
+               }
+               desc_len = min(desc_len, TX_MAX_TRANSFER_LENGTH);
+               memset(descp, 0, sizeof(struct staging_desc_t));
+               descp->entry.bits.sad = (uint64_t)dma_addr;
+               descp->entry.bits.tr_len = desc_len;
+               loc_len-= desc_len;
+               off += desc_len;
+               if (off == dma_map[idx].len) {
+                       off = 0;
+                       idx++;
+               }
+               descp++;
+               ngathers++;
+       }
+
+       si->dma_map_idx = idx;
+       si->dma_map_off = off;
+
+       /* setup the SOP descriptor; it contains the internal packet header
+        * and the TCP/IP header information
+        */
+       sop_descp->entry.bits.sop = 1;
+       sop_descp->entry.bits.num_ptr = ngathers;
+       sop_descp->entry.bits.tr_len = TX_PKT_HEADER_SIZE+si->tcpip_hdr_len;
+       sop_descp->entry.bits.sad = si->hdr_array.dma_addr+frame*HDR_TEMPLATE_SIZE;
+       pkt_hdr = (tx_pkt_header_t *)hdrp;
+       pkt_hdr->bits.tot_xfer_len = len + sop_descp->entry.bits.tr_len;
+       si->desc_idx += ngathers;
+       HXGE_DBG(hxgep, "Frame %d : %d len, %d descriptors required",frame,len,ngathers);
+       return 0;
+}
+
+static int setup_dma_mapping(struct hxge_adapter *hxgep, 
+               struct sk_buff *skb, struct staging_info_t *si)
+{
+       /* setup the buffer in the main skb structure */
+       int num_mappings = skb_shinfo(skb)->nr_frags;
+       skb_frag_t *fragp;
+       struct dma_map_t *dma_map;
+       struct skb_hdr_info_t *skb_hdr = (struct skb_hdr_info_t *)skb->cb;
+       int i = 0; /* at least one mapping */
+       int main_buf_len;
+
+       /* allocate for the main buffer + the fragments */
+       main_buf_len = skb_headlen(skb) - si->tcpip_hdr_len;
+       if (main_buf_len)
+               num_mappings++;
+
+       dma_map = kmalloc(num_mappings*sizeof(struct dma_map_t), GFP_KERNEL);
+       if (!dma_map) {
+               HXGE_ERR(hxgep, "failed to alloc dma_map");
+               return MAP_DESC_FAILED;
+       }
+
+       /* First map the main buffer in skb; odd one out */
+       if (main_buf_len) {
+               char *data = skb->data+si->tcpip_hdr_len;
+               dma_map[i].len = main_buf_len;
+               dma_map[i].vaddr = data;
+               dma_map[i].dma_addr = pci_map_page(hxgep->pdev, 
+                                       virt_to_page(data),
+                                       offset_in_page(data),
+                                       dma_map[0].len, 
+                                       PCI_DMA_TODEVICE);
+               ++i;
+       }
+
+       for (fragp = &skb_shinfo(skb)->frags[0]; i < num_mappings; 
+                                                       i++, fragp++) {
+               char *data = page_address(fragp->page);
+               dma_map[i].len = fragp->size;
+               dma_map[i].vaddr = data + fragp->page_offset;
+               dma_map[i].dma_addr  = pci_map_page(hxgep->pdev, 
+                                       virt_to_page(data), fragp->page_offset, 
+                                       fragp->size, PCI_DMA_TODEVICE);
+       }
+       si->pci_map.num_dma_mappings = i;
+       si->pci_map.dma_map = dma_map;
+       skb_hdr->pci_map = si->pci_map;
+       return 0;
+}
+
+
+static int hxge_tx_gso(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct hxge_adapter *hxgep = netdev_priv(netdev);
+       int desc_required = 0;
+       struct staging_info_t *si;
+       int i, state;
+       struct tx_ring_t *tx_ring;
+       struct staging_desc_t *desc;
+       struct tx_buf_t *tx_buf;
+       int tot_len, len;
+
+       si = setup_staging_info(hxgep, skb);
+       if (!si)
+       {
+               HXGE_ERR(hxgep, "setup_staging_info failed");
+                dev_kfree_skb_any(skb);
+                return (NETDEV_TX_OK);
+       }
+
+       if (setup_dma_mapping(hxgep, skb, si)) {
+               HXGE_ERR(hxgep, "setup_dma_mapping failed");
+               free_staging_info(hxgep, si, 1);
+               dev_kfree_skb_any(skb);
+               return (NETDEV_TX_OK);
+       }
+
+       tot_len = skb->len - si->tcpip_hdr_len;
+       for (i = 0, len = min(tot_len,si->frame_size); i < si->max_frames;
+                               i++, len = min(tot_len, si->frame_size)) {
+               if (setup_frame(hxgep, si, len, i)) {
+                               HXGE_ERR(hxgep, "setup_frame for main buffer failed");
+                               free_staging_info(hxgep, si, 1);
+                               dev_kfree_skb_any(skb);
+                               return (NETDEV_TX_OK);
+               }
+               tot_len -= len;
+       }
+
+       /* Pass in known desc_required. Success implies we have the channel
+         * lock 
+        */
+       desc_required = si->desc_idx;
+
+       if (desc_required > (DESCS_PER_FRAME*si->max_frames)) {
+               HXGE_ERR(hxgep,"BUG: Not enough space allocated for temporary descrpitors; only have %d, should have %d!",4*si->max_frames,desc_required);
+               BUG();
+       }
+
+       tx_ring = get_channel_to_transmit(hxgep, skb, &state, &desc_required);
+       if (!tx_ring) {
+                if (state == NETDEV_TX_BUSY) {
+                       if (!netif_queue_stopped(netdev))
+                               netif_stop_queue(netdev);
+               }
+               free_staging_info(hxgep,si,1);
+               return (state);
+       }
+       
+       TXDMA_GET_CURR_INDEX(tx_ring);
+       desc = si->desc;
+       tx_buf = &tx_ring->tx_buf[tx_ring->curr_index];
+       for (i = 0; i < desc_required; i++, desc++) {
+               tx_desc_t *real_desc;
+               tx_buf = &tx_ring->tx_buf[tx_ring->curr_index];
+               real_desc = &tx_ring->desc_ring.vaddr[tx_ring->curr_index];
+               tx_buf->flags = TX_FLAGS_DATA;
+               tx_buf->map.dma_addr = desc->addr;
+               tx_buf->map.len = desc->len;
+               tx_buf->skb = NULL;
+               HXGE_MEM_PIO_WRITE64(real_desc, desc->entry.value);
+               TXDMA_GET_NEXT_INDEX(tx_ring, 1);
+       }
+
+       /* We assume there is at least one descriptor. Make sure that 
+        * last tx_buf has all the requisite pointers for the reclaim thread 
+        * to be able to free the mapped header  array. It *has* to be the 
+        * last Tx descriptor to ensure that all descriptors relevant to 
+        * this skb have been sent out by the HW. No need to set the 
+        * TX_FLAGS_UNMAP; the reclaim thread knows that if the skb is
+        * valid and gso is enabled, this is the last descriptor and 
+        * consequently, there must be a header array to be unmapped and
+        * freed. Setting the unmap flag will confuse the non-gso code in
+        * reclaim_tx_thread and cause problems.
+        */
+       tx_buf->skb = skb;
+       skb_orphan(skb);
+#ifdef CONFIG_ERRINJECT
+       atomic_inc(&skb_count);
+#endif
+
+       /* Update the descriptors available for use. Note that update to this
+           variable races with the reclaim thread, hence an atomic operation */
+       atomic_sub(desc_required, &tx_ring->descs_avail);
+
+       if (atomic_read(&tx_ring->descs_avail) < 0) {
+           HXGE_ERR(hxgep, "Descriptors available less than zero!!");  
+       }
+       /* Update descriptors available. Write the SOP descriptor entry and 
+           kick the number of new entries added */
+       TXDMA_UPDATE_INDEX(tx_ring);
+       hpi_txdma_desc_kick_reg_set(hxgep->hw.hw_addr, tx_ring->tdc, 
+                               tx_ring->tail, tx_ring->wrap);
+
+       /* Successfully queued one network packet of <skb_len> bytes */
+
+       tx_ring->stats.opackets += si->max_frames;
+       tx_ring->stats.obytes += skb->len;
+       spin_unlock(&tx_ring->lock);
+
+       free_staging_info(hxgep, si, 0);
+       return NETDEV_TX_OK;
+}
+
+
+int hxge_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+       int status;
+       if (SKB_IS_GSO(skb)) {
+               status = hxge_tx_gso(skb, netdev);
+       } else 
+               status = hxge_tx_ring(skb, netdev);
+
+       return status;
+}
+
+static void update_tx_err_stats(hpi_handle_t handle, struct tx_ring_t *tx_ring)
+{
+       struct tx_ring_stats_t *stats = &tx_ring->stats;
+       tdc_drop_cnt_t drop_cnt;
+
+       TXDMA_REG_READ64(handle, TDC_DROP_CNT, tx_ring->tdc, &drop_cnt.value);
+
+       stats->hdr_error_cnt += drop_cnt.bits.hdr_size_error_count;
+       stats->abort_cnt += drop_cnt.bits.abort_count;
+       stats->runt_cnt += drop_cnt.bits.runt_count;
+
+       stats->oerrors += drop_cnt.bits.hdr_size_error_count
+               + drop_cnt.bits.abort_count
+               + drop_cnt.bits.runt_count;
+
+}
+
+static tdc_stat_t process_tx_status(struct hxge_ldv *ldvp, int ldf0, int ldf1)
+{
+       struct hxge_adapter *hxgep = ldvp->ldgp->hxgep;
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+       tdc_stat_t cs;
+       int channel = ldvp->ldv-HXGE_TDMA_LD_START;
+       struct tx_ring_t *tx_ring = &hxgep->tx_ring[channel];
+       struct tx_ring_stats_t *stats = &tx_ring->stats;
+       tdc_tdr_head_t head_reg;
+
+
+       /* If an LDF1 error, then wait till the qst bit is asserted before
+        * reading the TdcStat register. Otherwise, all the error information 
+        * for that channel may not have been updated yet
+        */
+       if (ldf1)
+               hpi_txdma_control_reset_wait(handle, channel);
+
+       if (hpi_txdma_control_status(handle, OP_GET, channel, &cs)
+               != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hpi_txdma_control_status failed");
+       }
+
+
+       if (cs.bits.marked) {
+               stats->marked++;
+               HXGE_DBG(hxgep, "Sent marked packet - kick reclaim thread");
+               wake_up_interruptible(&tx_ring->reclaim_event);
+       }
+
+       if (ldf1) {
+               HXGE_ERR(hxgep, "LDF1 on channel %d, cs 0x%llx",channel,cs.value);
+
+               if (cs.bits.peu_resp_err) {
+                       HXGE_ERR(hxgep, "peu_resp_error");
+                       stats->peu_resp_err++;
+                       stats->oerrors++;
+               }
+
+               if (cs.bits.pkt_size_hdr_err) {
+                       HXGE_ERR(hxgep, "pkt_size_hdr_err");
+                       stats->pkt_size_hdr_err++;
+                       stats->oerrors++;
+               }
+
+               if (cs.bits.runt_pkt_drop_err) {
+                       HXGE_ERR(hxgep, "runt_pkt_drop_err");
+                       stats->runt_pkt_drop_err++;
+                       stats->oerrors++;
+               }
+
+               if (cs.bits.pkt_size_err) {
+                       HXGE_ERR(hxgep, "pkt_size_err");
+                       stats->pkt_size_err++;
+                       stats->oerrors++;
+               }
+
+               if (cs.bits.tx_rng_oflow) {
+                       HXGE_ERR(hxgep, "tx_rng_oflow");
+                       stats->tx_rng_oflow++;
+                       stats->oerrors++;
+                       if (hpi_txdma_ring_head_get(handle, channel, 
+                               &head_reg) != HPI_SUCCESS)
+                       {
+                               HXGE_ERR(hxgep, "hpi_txdma_ring_head_get_failed for channel %d",tx_ring->tdc);
+                       }
+                       HXGE_ERR(hxgep, "head: 0x%x, tail : 0x%x, hwrap: %d, twrap: %d",head_reg.bits.head, tx_ring->tail, tx_ring->wrap, head_reg.bits.wrap);
+                       if (!((head_reg.bits.head == tx_ring->tail) && (
+                               tx_ring->wrap != head_reg.bits.wrap))) {
+                               HXGE_ERR(hxgep, "False overflow!");
+                       }
+               }
+                       
+               if (cs.bits.pref_par_err) {
+                       HXGE_ERR(hxgep, "pref_par_err");
+                       stats->pref_par_err++;
+                       stats->oerrors++;
+               }
+
+               if (cs.bits.tdr_pref_cpl_to) {
+                       HXGE_ERR(hxgep, "tdr_pref_cpl_to");
+                       stats->tdr_pref_cpl_to++;
+                       stats->oerrors++;
+               }
+
+               if (cs.bits.pkt_cpl_to) {
+                       HXGE_ERR(hxgep, "pkt_cpl_to");
+                       stats->pkt_cpl_to++;
+                       stats->oerrors++;
+               }
+
+               if (cs.bits.invalid_sop) {
+                       HXGE_ERR(hxgep, "invalid_sop");
+                       stats->invalid_sop++;
+                       stats->oerrors++;
+               }
+
+               if (cs.bits.unexpected_sop) {
+                       HXGE_ERR(hxgep, "unexpected_sop");
+                       stats->unexpected_sop++;
+                       stats->oerrors++;
+               }
+
+               BUG();
+               /* Update discarded-packets counts from Hydra's counters */
+               update_tx_err_stats(handle, tx_ring);
+       
+       }
+
+       /* Clear out the bits that require W1C */
+       hpi_txdma_control_status(handle, OP_SET, channel, &cs);
+
+       /* Do a reset of the channel (on call side) */
+       if (ldf1) {
+               set_bit(RESET_TX_CHANNEL_0+channel, &hxgep->work_q.command);
+               schedule_work(&hxgep->work_to_do);
+       }
+
+       return cs;
+}
+
+/* Transmit interrupt handler. The fact that we get here imples that this is
+ * a LDG with just one LDV. Otherwise, we would end up in hxge_intr. 
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+irqreturn_t hxge_tx_intr(int irq, void *data, struct pt_regs *regs)
+#else
+irqreturn_t hxge_tx_intr(int irq, void *data)
+#endif
+{
+       struct hxge_ldv *ldvp = (struct hxge_ldv *)data;
+       int got_ldf0, got_ldf1;
+       
+
+       /* Determine if we have a LDF0 or LDF1 */
+       get_ldf_flags(ldvp, &got_ldf0, &got_ldf1);
+       
+       /* Neither one. So, probably a shared interrupt? Return but don't 
+          dimiss the interrupt but let another handler have a shot at it */
+       if (!got_ldf0 && !got_ldf1)
+               return IRQ_NONE;
+       
+       /* If LDF0, then this is probably an  interrupt  indicating a 
+          transmit completed ("marked" bit was set and triggered an 
+          interrupt */
+       process_tx_status(ldvp, got_ldf0, got_ldf1);
+
+       return (IRQ_HANDLED);
+
+}
+
+
+/* Transmit error interrupt handler
+ *
+ * Called from Device Error Interrupt (ldv 31) service, not TX DMA
+ *
+ * NB: *data is Device Error ldv 31, not a TX DMA channel ldv!
+ */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+irqreturn_t hxge_tx_deverr_intr(int irq, void *data, struct pt_regs *regs)
+#else
+irqreturn_t hxge_tx_deverr_intr(int irq, void *data)
+#endif
+{
+       struct hxge_ldv *ldvp = (struct hxge_ldv *)data; /* Device Error ldv */
+       struct hxge_adapter *hxgep = ldvp->ldgp->hxgep;
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+       tdc_fifo_err_stat_t sts, clr;
+       int hard_error = 0;
+
+       if (hpi_tx_fifo_status(handle, OP_GET, &sts) 
+               != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hpi_tx_fifo_status failed");
+       }
+
+       HXGE_ERR(hxgep, "TX hardware error interrupt (0x%16.16x)!",
+                (unsigned int)sts.value);
+
+       clr.value = sts.value;
+
+       if (sts.bits.reord_buf_sec_err) {
+               HXGE_ERR(hxgep, "reord_buf_sec_err");
+               hxgep->statsp->tx_reorder_sec++;
+               hxgep->statsp->soft_errors++; /* Soft (recovered) dev error */
+               clr.bits.reord_buf_sec_err = 0;
+       }
+
+       if (sts.bits.reord_buf_ded_err) {
+               HXGE_ERR(hxgep, "reord_buf_ded_err");
+               hxgep->statsp->tx_reorder_ded++;
+               hxgep->statsp->tx_oerrors++; /* Tx summary count */
+               hxgep->statsp->hard_errors++; /* Hard device error */
+               hard_error = TRUE;
+               clr.bits.reord_buf_ded_err = 0;
+       }
+
+       if (sts.bits.reord_tbl_par_err) {
+               HXGE_ERR(hxgep, "reord_tbl_par_err");
+               hxgep->statsp->tx_rtab_parerr++;
+               hxgep->statsp->tx_oerrors++; /* Tx summary count */
+               hxgep->statsp->hard_errors++; /* Hard device error */
+               hard_error = TRUE;
+               clr.bits.reord_tbl_par_err = 0;
+       }
+
+       if (clr.value) {
+               HXGE_ERR(hxgep, "Unknown/unexpected/reserved TDC_FIFO_ERR_STAT bits 0x%16.16x", (unsigned int)clr.value);
+               hxgep->statsp->hard_errors++; /* Hard device error */
+               hard_error = TRUE; /* Unknown, hope TDC reset nails it */
+       }
+
+       /* Now that we have "logged" the errors, try to recover from
+        * whatever happened.  Note that "SEC" (Single Bit ECC) is
+        * recovered by hardware, and needs no further action here.
+        */
+
+       /* Acknowledge error status, resume processing */
+
+       hpi_tx_fifo_status(handle, OP_SET, &sts);
+
+       /* We're probably going to hang now... */
+
+       if (hxge_ok_to_continue(hxgep)) {
+               if (hard_error) {
+                       /* Hard error, data corrupt, need TDC reset */
+                       hxge_disable_tx_ints(hxgep);
+                       set_bit(RESET_TDC, &hxgep->work_q.command);
+                       schedule_work(&hxgep->work_to_do);
+               } /* Else Corrected (single-bit) error, OK to resume */
+       } else {
+               HXGE_ERR(hxgep, "Excessive hardware error rate");
+               HXGE_ERR(hxgep, "                      Taking hxge device down");
+               hxge_disable_interrupts(hxgep);
+               set_bit(SHUTDOWN_ADAPTER, &hxgep->work_q.command);
+               schedule_work(&hxgep->work_to_do);
+       }
+
+       return (IRQ_HANDLED);
+}
diff --git a/drivers/net/hxge/hxge_txdma.h b/drivers/net/hxge/hxge_txdma.h
new file mode 100644 (file)
index 0000000..3b119df
--- /dev/null
@@ -0,0 +1,252 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#ifndef        _HXGE_HXGE_TXDMA_H
+#define        _HXGE_HXGE_TXDMA_H
+
+#include "hxge_txdma_hw.h"
+#include <linux/llc.h>
+
+#define        TXDMA_RECLAIM_PENDING_DEFAULT           64
+#define        TX_FULL_MARK                            3
+
+/*
+ * Descriptor ring empty:
+ *             (1) head index is equal to tail index.
+ *             (2) wrapped around bits are the same.
+ * Descriptor ring full:
+ *             (1) head index is equal to tail index.
+ *             (2) wrapped around bits are different.
+ *
+ */
+#define        TXDMA_RING_EMPTY(head, head_wrap, tail, tail_wrap)      \
+       ((head == tail && head_wrap == tail_wrap) ? TRUE : FALSE)
+
+#define        TXDMA_RING_FULL(head, head_wrap, tail, tail_wrap)       \
+       ((head == tail && head_wrap != tail_wrap) ? TRUE: FALSE)
+
+#define        TXDMA_DESC_NEXT_INDEX(index, entries, wrap_mask) \
+                       ((index + entries) & wrap_mask)
+
+#define TXDMA_GET_CURR_INDEX(tx_ring) \
+       tx_ring->curr_index = tx_ring->tail
+
+#define TXDMA_GET_NEXT_INDEX(tx_ring, entries) \
+       tx_ring->curr_index = (tx_ring->curr_index+entries) % tx_ring->num_tdrs;
+
+#define TXDMA_DEC_INDEX(tx_ring) \
+       tx_ring->curr_index = (tx_ring->curr_index-1); \
+       if (!tx_ring->curr_index) \
+               tx_ring->curr_index = tx_ring->num_tdrs-1;
+
+#define TXDMA_UPDATE_INDEX(tx_ring) \
+       if (tx_ring->curr_index < tx_ring->tail) \
+               tx_ring->wrap = (tx_ring->wrap == TRUE) ? FALSE : TRUE; \
+       tx_ring->tail = tx_ring->curr_index;
+
+
+#define RECLAIM_TIMEOUT         5 /* 5 ms (in jiffies) */
+
+#define HXGE_TX_DESCS_MIN      32  /* 32 entries */
+#define HXGE_TX_DESCS_DEFAULT  1024 /* 1024 entries */
+#define HXGE_TX_DESCS_MAX      5120 /* 10 4K pages worth */
+
+#define HXGE_TX_DESCS_PER_PACKET       15
+
+#define HXGE_TX_BUF_SZ_MIN     256 /* in bytes */
+#define HXGE_TX_BUF_SZ_MAX     4096 /* 4KB */
+
+#define TX_FLAGS_UNUSED 0x0
+#define TX_FLAGS_HDR    0x1 /* descriptor contains only internal header */
+#define TX_FLAGS_ALL  0x2 /* small packet; internal header + skb */
+#define TX_FLAGS_DATA 0x4 /* packet only contains data */
+#define TX_FLAGS_UNMAP 0x8 /* unmap the page when skb is freed */
+#define TX_FLAGS_ALLOC 0x10 /* allocated data page dynamically */
+
+
+#define SKB_IS_GSO(skb) skb_shinfo(skb)->gso_size
+#define SKB_GSO_SEGS(skb) skb_shinfo(skb)->gso_segs
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19)
+#define SKB_CKSUM_OFFSET(skb) skb->csum_offset
+#define HXGE_CHECKSUM CHECKSUM_PARTIAL
+#else
+#define SKB_CKSUM_OFFSET(skb) skb->csum
+#define HXGE_CHECKSUM CHECKSUM_HW
+#endif
+
+/* When we are in GSO mode, the maximum possible number of Tx descriptors 
+ * required is 7. The max possible frame size is ~9KB because this is the 
+ * largest MTU possible for Hydra. Then, the math breaks down as follows
+ *     1 - for the L2/L3/L4 header (have 256 bytes of space available)
+ *     1 - fragment starting at some random offset 
+ *     2 - 4096 byte fragment (Tx descriptor can only take 4076 bytes)
+ *     2 - 4096 byte fragment (     "   )
+ *     1 - (potential) remnant left-over fragment 
+ */
+#define DESCS_PER_FRAME 7
+
+
+/* Keep a copy of the Tx descriptor and information required to unmap the dma
+ * address once we are done with it 
+ */
+struct staging_desc_t {
+       tx_desc_t       entry;
+       dma_addr_t      addr;
+       char            *vaddr;
+       int             len;
+};
+
+struct dma_map_t
+{
+       dma_addr_t      dma_addr;
+       caddr_t         vaddr;
+       int             len;
+};
+
+/* structure that tracks the dma mappings created for the various SKB 
+   fragments and the main buffer
+*/
+struct pci_dma_map_t {
+       int     num_dma_mappings;       
+       struct dma_map_t *dma_map;
+};
+       
+#define HDR_TEMPLATE_SIZE 256
+#define TCP_FLAGS_URG 1
+#define TCP_FLAGS_PSH 2
+#define TCP_FLAGS_RST 4
+#define TCP_FLAGS_FIN 8
+struct staging_info_t {
+       int     desc_idx;
+        tx_pkt_header_t  pkthdr;
+       struct staging_desc_t *desc;
+       struct dma_map_t hdr_array;
+       int     l3_offset;
+       int     l4_offset;
+       int     l4_hdr_len;
+       int     tcpip_hdr_len;
+       int     max_frames;
+       int     frame_size;
+       int     dma_map_idx;
+       int     dma_map_off;
+       struct  pci_dma_map_t pci_map;
+       uint32_t tcp_sequence;
+       uint16_t ip_id;
+       uint8_t  tcp_flags; /* urg=0, psh=1, rst=4, fin=9 */
+       char    hdr_template[HDR_TEMPLATE_SIZE];
+};
+
+struct skb_hdr_info_t {
+        struct dma_map_t        hdr_array;
+       struct pci_dma_map_t    pci_map;
+        uint8_t                 l4_payload_offset;
+};
+
+       
+struct tx_buf_t {
+       struct sk_buff          *skb;
+       struct dma_map_t        map;
+       uint32_t                flags;
+};
+       
+
+struct tx_desc_buf_t {
+       dma_addr_t      dma_addr;
+       tx_desc_t       *vaddr; /* Tx descriptor ring  */
+};
+
+struct tx_mbox_t {
+       dma_addr_t      dma_addr;
+       txdma_mailbox_t *vaddr;
+};
+
+struct tx_data_buf_t {
+       dma_addr_t dma_addr;
+       caddr_t    vaddr;
+};
+
+struct reclaim_data_t {
+       struct hxge_adapter *hxgep;
+       int channel;
+};
+
+struct tx_ring_stats_t {
+       uint64_t        opackets;
+       uint64_t        obytes;
+       uint64_t        oerrors;
+       uint64_t        txlock_acquire_failed;
+
+       /* Hydra specific from control/status */
+       uint64_t        marked;
+       uint64_t        peu_resp_err;
+       uint64_t        pkt_size_hdr_err;
+       uint64_t        runt_pkt_drop_err;
+       uint64_t        pkt_size_err;
+       uint64_t        tx_rng_oflow;
+       uint64_t        pref_par_err;
+       uint64_t        tdr_pref_cpl_to;
+       uint64_t        pkt_cpl_to;
+       uint64_t        invalid_sop;
+       uint64_t        unexpected_sop;
+       uint64_t        hdr_error_cnt;
+       uint64_t        abort_cnt;
+       uint64_t        runt_cnt;
+       uint64_t        descs_used[16];
+};
+
+struct tx_ring_t {
+       int             tdc;  /* channel no */
+       int             num_tdrs; /* number of transmit desc entries */
+       int             num_tx_buffers;
+       int             tx_buffer_size;
+       struct hxge_adapter *hxgep;
+       struct tx_desc_buf_t desc_ring;
+       spinlock_t      lock; /* per-channel lock */
+       struct tx_data_buf_t   data_buf; /* pointer to packet buffers */
+       struct tx_buf_t *tx_buf;
+       struct tx_mbox_t mbox; /* Tx mailbox */
+       int             curr_index; /* running index for free desc location */
+       int             tail; /* entry to write next packet in ring */
+       int             wrap; /* toggle every time tail wraps around */
+       atomic_t        descs_avail; /* # descs available for use */
+       unsigned long   state;
+       unsigned int    mark_ints;
+       
+
+       
+       /* reclaim unused tx buffers **/
+       wait_queue_head_t reclaim_event;
+       struct completion reclaim_complete;
+       volatile boolean_t kill_reclaim;
+       pid_t             thread_pid;
+       int               reclaim_head;
+       int               reclaim_wrap;
+
+       /* stats */
+       struct tx_ring_stats_t   stats;
+};
+       
+#endif /* _HXGE_HXGE_TXDMA_H */
diff --git a/drivers/net/hxge/hxge_txdma_hw.h b/drivers/net/hxge/hxge_txdma_hw.h
new file mode 100644 (file)
index 0000000..d5d8aed
--- /dev/null
@@ -0,0 +1,206 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#ifndef        _HXGE_HXGE_TXDMA_HW_H
+#define        _HXGE_HXGE_TXDMA_HW_H
+
+#include "hxge_defs.h"
+#include "hxge_tdc_hw.h"
+
+/*
+ * Transmit Packet Descriptor Structure
+ *     See Hydra PRM (Chapter 8, Section 8.1.1)
+ */
+typedef union _tx_desc_t {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        sop:1;
+               uint64_t        mark:1;
+               uint64_t        num_ptr:4;
+               uint64_t        rsvd:1;
+               uint64_t        tr_len:13;
+               uint64_t        sad:44;
+#else
+               uint64_t        sad:44;
+               uint64_t        tr_len:13;
+               uint64_t        rsvd:1;
+               uint64_t        num_ptr:4;
+               uint64_t        mark:1;
+               uint64_t        sop:1;
+#endif
+       } bits;
+} tx_desc_t, *p_tx_desc_t;
+
+/*
+ * TDC Ring Configuration
+ */
+#define        TDC_TDR_CFG_STADDR_SHIFT        6       /* bits 18:6 */
+#define        TDC_TDR_CFG_STADDR_MASK         0x000000000007FFC0ULL
+#define        TDC_TDR_CFG_ADDR_MASK           0x00000FFFFFFFFFC0ULL
+#define        TDC_TDR_CFG_STADDR_BASE_SHIFT   19      /* bits 43:19 */
+#define        TDC_TDR_CFG_STADDR_BASE_MASK    0x00000FFFFFF80000ULL
+#define        TDC_TDR_CFG_LEN_SHIFT           53      /* bits 63:53 */
+#define        TDC_TDR_CFG_LEN_MASK            0xFFE0000000000000ULL
+#define        TDC_TDR_RST_SHIFT               46
+#define        TDC_TDR_RST_MASK                0x0000400000000000ULL
+
+/*
+ * Transmit Event Mask
+ */
+#define        TDC_INT_MASK_MK_MASK            0x0000000000008000ULL
+
+/*
+ * Trasnmit Mailbox High
+ */
+#define        TDC_MBH_SHIFT                   0       /* bit 11:0 */
+#define        TDC_MBH_ADDR_SHIFT              32      /* bit 43:32 */
+#define        TDC_MBH_MASK                    0x0000000000000FFFULL
+
+/*
+ * Trasnmit Mailbox Low
+ */
+#define        TDC_MBL_SHIFT                   6       /* bit 31:6 */
+#define        TDC_MBL_MASK                    0x00000000FFFFFFC0ULL
+
+#define        TXDMA_MAILBOX_BYTE_LENGTH       64
+#define        TXDMA_MAILBOX_UNUSED            24
+
+typedef struct _txdma_mailbox_t {
+       tdc_stat_t              tx_cs;                  /* 8 bytes */
+       tdc_tdr_pre_head_t      tx_dma_pre_st;          /* 8 bytes */
+       tdc_tdr_head_t          tx_ring_hdl;            /* 8 bytes */
+       tdc_tdr_kick_t          tx_ring_kick;           /* 8 bytes */
+       uint32_t                tx_rng_err_logh;        /* 4 bytes */
+       uint32_t                tx_rng_err_logl;        /* 4 bytes */
+       uint8_t                 resv[TXDMA_MAILBOX_UNUSED];
+} txdma_mailbox_t, *p_txdma_mailbox_t;
+
+/*
+ * Internal Transmit Packet Format (16 bytes)
+ */
+#define        TX_PKT_HEADER_SIZE                      16
+
+
+/* A packet can be composed of no more than 15 blocks; no block can be
+ * larger than 4K in size
+ */
+
+#define        TX_MAX_GATHER_POINTERS                  15
+#define        TX_GATHER_POINTERS_THRESHOLD            8
+/*
+ * There is bugs in the hardware
+ * and max sfter len is changed from 4096 to 4076.
+ *
+ * Jumbo from 9500 to 9216
+ */
+#define        TX_MAX_TRANSFER_LENGTH                  4076
+#define        TX_JUMBO_MTU                            9216
+
+#define        TX_PKT_HEADER_PAD_SHIFT                 0       /* bit 2:0 */
+#define        TX_PKT_HEADER_PAD_MASK                  0x0000000000000007ULL
+#define        TX_PKT_HEADER_TOT_XFER_LEN_SHIFT        16      /* bit 16:29 */
+#define        TX_PKT_HEADER_TOT_XFER_LEN_MASK         0x000000000000FFF8ULL
+#define        TX_PKT_HEADER_L4STUFF_SHIFT             32      /* bit 37:32 */
+#define        TX_PKT_HEADER_L4STUFF_MASK              0x0000003F00000000ULL
+#define        TX_PKT_HEADER_L4START_SHIFT             40      /* bit 45:40 */
+#define        TX_PKT_HEADER_L4START_MASK              0x00003F0000000000ULL
+#define        TX_PKT_HEADER_L3START_SHIFT             48      /* bit 45:40 */
+#define        TX_PKT_HEADER_IHL_SHIFT                 52      /* bit 52 */
+#define        TX_PKT_HEADER_VLAN__SHIFT               56      /* bit 56 */
+#define        TX_PKT_HEADER_TCP_UDP_CRC32C_SHIFT      57      /* bit 57 */
+#define        TX_PKT_HEADER_LLC_SHIFT                 57      /* bit 57 */
+#define        TX_PKT_HEADER_TCP_UDP_CRC32C_SET        0x0200000000000000ULL
+#define        TX_PKT_HEADER_TCP_UDP_CRC32C_MASK       0x0200000000000000ULL
+#define        TX_PKT_HEADER_L4_PROTO_OP_SHIFT         2       /* bit 59:58 */
+#define        TX_PKT_HEADER_L4_PROTO_OP_MASK          0x0C00000000000000ULL
+#define        TX_PKT_HEADER_V4_HDR_CS_SHIFT           60      /* bit 60 */
+#define        TX_PKT_HEADER_V4_HDR_CS_SET             0x1000000000000000ULL
+#define        TX_PKT_HEADER_V4_HDR_CS_MASK            0x1000000000000000ULL
+#define        TX_PKT_HEADER_IP_VER_SHIFT              61      /* bit 61 */
+#define        TX_PKT_HEADER_IP_VER_MASK               0x2000000000000000ULL
+#define        TX_PKT_HEADER_PKT_TYPE_SHIFT            62      /* bit 62 */
+#define        TX_PKT_HEADER_PKT_TYPE_MASK             0x6000000000000000ULL
+
+/* L4 Prototol Operations */
+#define        TX_PKT_L4_PROTO_OP_NOP                  0x00
+#define        TX_PKT_L4_PROTO_OP_FULL_L4_CSUM         0x01
+#define        TX_PKT_L4_PROTO_OP_L4_PAYLOAD_CSUM      0x02
+#define        TX_PKT_L4_PROTO_OP_SCTP_CRC32           0x04
+
+/* Transmit Packet Types */
+#define        TX_PKT_PKT_TYPE_NOP                     0x00
+#define        TX_PKT_PKT_TYPE_TCP                     0x01
+#define        TX_PKT_PKT_TYPE_UDP                     0x02
+#define        TX_PKT_PKT_TYPE_SCTP                    0x03
+
+typedef union _tx_pkt_header_t {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        cksum_en_pkt_type:2;
+               uint64_t        ip_ver:1;
+               uint64_t        rsrvd:4;
+               uint64_t        vlan:1;
+               uint64_t        ihl:4;
+               uint64_t        l3start:4;
+               uint64_t        rsvrvd1:2;
+               uint64_t        l4start:6;
+               uint64_t        rsvrvd2:2;
+               uint64_t        l4stuff:6;
+               uint64_t        rsvrvd3:2;
+               uint64_t        tot_xfer_len:14;
+               uint64_t        rsrrvd4:13;
+               uint64_t        pad:3;
+#else
+               uint64_t        pad:3;
+               uint64_t        rsrrvd4:13;
+               uint64_t        tot_xfer_len:14;
+               uint64_t        rsvrvd3:2;
+               uint64_t        l4stuff:6;
+               uint64_t        rsvrvd2:2;
+               uint64_t        l4start:6;
+               uint64_t        rsvrvd1:2;
+               uint64_t        l3start:4;
+               uint64_t        ihl:4;
+               uint64_t        vlan:1;
+               uint64_t        rsrvd:4;
+               uint64_t        ip_ver:1;
+               uint64_t        cksum_en_pkt_type:2;
+#endif
+       } bits;
+} tx_pkt_header_t, *p_tx_pkt_header_t;
+
+
+#define INCREMENT_DESC_INDEX(tx_ring) \
+       tx_ring->tail = tx_ring->tail + 1; \
+       if (tx_ring->tail ==  tx_ring->num_tdrs)  { \
+          tx_ring->tail = 0; \
+          tx_ring->wrap ^= 0x1; \
+       } \
+       
+
+
+#endif /* _HXGE_HXGE_TXDMA_HW_H */
diff --git a/drivers/net/hxge/hxge_vmac.c b/drivers/net/hxge/hxge_vmac.c
new file mode 100644 (file)
index 0000000..cd0b006
--- /dev/null
@@ -0,0 +1,481 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+
+#include "hpi/hpi_vmac.h"
+#include "hxge_vmac.h"
+#include "hxge.h"
+
+
+int hxge_vmac_init(struct hxge_adapter * hxgep);
+int hxge_tx_vmac_init(struct hxge_adapter * hxgep);
+int hxge_rx_vmac_init(struct hxge_adapter * hxgep);
+int hxge_tx_vmac_enable(struct hxge_adapter * hxgep);
+int hxge_tx_vmac_disable(struct hxge_adapter * hxgep);
+int hxge_rx_vmac_enable(struct hxge_adapter * hxgep);
+int hxge_rx_vmac_disable(struct hxge_adapter * hxgep);
+int hxge_tx_vmac_reset(struct hxge_adapter * hxgep);
+int hxge_rx_vmac_reset(struct hxge_adapter * hxgep);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+irqreturn_t hxge_vmac_intr(int irq, void *data, struct pt_regs *regs);
+#else
+irqreturn_t hxge_vmac_intr(int irq, void *data);
+#endif
+
+int hxge_set_promisc(struct hxge_adapter * hxgep, boolean_t on);
+
+extern int hxge_get_option (const char *option_name, int *value);
+
+
+int
+hxge_vmac_init(struct hxge_adapter * hxgep)
+{
+       if (hxge_tx_vmac_reset(hxgep))
+               goto fail;
+
+       if (hxge_rx_vmac_reset(hxgep))
+               goto fail;
+
+
+       if (hxge_tx_vmac_enable(hxgep))
+               goto fail;
+
+       if (hxge_rx_vmac_enable(hxgep))
+               goto fail;
+
+       return 0;
+fail:
+       HXGE_ERR(hxgep, "hxge_vmac_init failed");       
+       return -1;
+}
+
+
+int 
+hxge_vmac_uninit(struct hxge_adapter * hxgep)
+{
+       if (hxge_tx_vmac_disable(hxgep))
+               goto fail;
+
+       if (hxge_rx_vmac_disable(hxgep))
+               goto fail;
+
+       return 0;
+fail:
+       HXGE_ERR(hxgep, "hxge_vmac_uninit failed");
+       return -1;
+}
+
+
+
+/* Initialize the TxVMAC sub-block */
+
+int
+hxge_tx_vmac_init(struct hxge_adapter * hxgep)
+{
+       int             rs;
+       uint64_t        config;
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+       struct net_device *netdev = hxgep->netdev;
+
+
+       /* When setting the size of the Tx, one must account for the
+           CRC and the internal header of 16 bytes. There are no pad bytes
+           in the internal header because we guarantee internal header is 
+           16-byte aligned and so, payload that follows has the right 2-byte
+           alignment as well */
+
+       hxgep->vmac.maxframesize = netdev->mtu + ETH_HLEN + VLAN_HLEN + 
+                                       CRC_LENGTH + TX_PKT_HEADER_SIZE;
+       hxgep->vmac.minframesize = MINIMUM_ETHERNET_FRAME_SIZE;
+
+       /* CFG_VMAC_TX_EN is done separately */
+       config = CFG_VMAC_TX_CRC_INSERT | CFG_VMAC_TX_PAD;
+
+       if ((rs = hpi_vmac_tx_config(handle, INIT, config,
+                       hxgep->vmac.maxframesize)) != HPI_SUCCESS) 
+       {
+               HXGE_ERR(hxgep, "hxge_tx_vmac_init: hpi_vmac_tx_config failed");
+               return  -1;
+       }
+
+       hxgep->vmac.tx_config = config;
+
+       if (hxgep->vmac.is_jumbo == TRUE) {
+               HXGE_DBG(hxgep, "hxge_tx_vmac_init: Jumbo enabled, MTU %d", hxgep->vmac.maxframesize);
+       } else {
+               HXGE_DBG(hxgep, "hxge_tx_vmac_init: Jumbo disabled, MTU %d",hxgep->vmac.maxframesize);
+       }
+
+       return  0;
+}
+
+/* Initialize the RxVMAC sub-block */
+
+int
+hxge_rx_vmac_init(struct hxge_adapter * hxgep)
+{
+       int             rs;
+       uint64_t        xconfig;
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+       int             stripcrc;
+       int             promisc;
+       struct net_device *netdev = hxgep->netdev;
+
+
+       hxgep->vmac.rx_max_framesize = netdev->mtu + ETH_HLEN + VLAN_HLEN +
+                                               CRC_LENGTH;
+
+       /* CFG_VMAC_RX_EN is done separately */
+       xconfig = CFG_VMAC_RX_PASS_FLOW_CTRL_FR;
+       hxge_get_option("strip_crc", &stripcrc);
+       if (stripcrc)
+               xconfig |= CFG_VMAC_RX_STRIP_CRC;
+
+       if (hxge_get_option("promiscuous",&promisc) < 0) {
+               HXGE_ERR(hxgep, "hxge_rx_vmac_init: promiscuous invalid");
+               return -1;
+       }
+
+       if (promisc || (netdev->flags & IFF_PROMISC))  {
+               HXGE_DBG(hxgep, "hxge_rx_vmac_init: Set to promiscuous mode");
+               xconfig |=  CFG_VMAC_RX_PROMISCUOUS_MODE;
+       }
+
+       if ((rs = hpi_vmac_rx_config(handle, INIT, xconfig, hxgep->vmac.rx_max_framesize))
+           != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hxge_rx_vmac_init: hpi_vmac_rx_config failed");
+               return  -1;
+       }
+
+       hxgep->vmac.rx_config = xconfig;
+
+       return  0;
+}
+int 
+hxge_vmac_rx_set_framesize(struct hxge_adapter *hxgep, uint16_t frame_size)
+{
+       if (hpi_vmac_rx_set_framesize(hxgep->hw.hw_addr, frame_size) !=
+                       HPI_SUCCESS)
+                       return -1;
+       return 0;
+}
+
+int
+hxge_vmac_promisc(struct hxge_adapter *hxgep, int enable)
+{
+       uint64_t        xconfig;
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+       config_op_t     cmd = DISABLE;
+
+       xconfig = CFG_VMAC_RX_PROMISCUOUS_MODE;
+       if (enable)
+               cmd = ENABLE;
+
+       if (hpi_vmac_rx_config(handle, cmd, xconfig, 0) != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hxge_vmac_promisc: hpi_vmac_rx_config failed");
+               return -1;
+       }
+
+       return 0;
+}
+
+
+/* Enable TxVMAC */
+
+int
+hxge_tx_vmac_enable(struct hxge_adapter * hxgep)
+{
+       hpi_status_t    rv;
+       int     status = 0;
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+       int enable;
+
+
+       rv = hxge_tx_vmac_init(hxgep);
+       if (rv != 0)
+               return (rv);
+
+       rv = hpi_vmac_tx_config(handle, ENABLE, CFG_VMAC_TX_EN, 0);
+       if (rv == HPI_SUCCESS) {
+               if (hxge_get_option("enable_vmac_ints", &enable))
+                       return -1;
+               rv = hpi_vmac_tx_ints(handle, enable);
+       }
+
+       status = (rv == HPI_SUCCESS) ? 0: -1;
+
+       
+
+       return (status);
+}
+
+/* Disable TxVMAC */
+
+int
+hxge_tx_vmac_disable(struct hxge_adapter * hxgep)
+{
+       hpi_status_t    rv;
+       int     status = 0;
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+
+
+       rv = hpi_vmac_tx_config(handle, DISABLE, CFG_VMAC_TX_EN, 0);
+
+       status = (rv == HPI_SUCCESS) ? 0 : -1;
+
+
+       return (status);
+}
+
+/* Enable RxVMAC */
+
+int
+hxge_rx_vmac_enable(struct hxge_adapter * hxgep)
+{
+       hpi_status_t    rv;
+       int     status = 0;
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+       int enable;
+
+
+       rv = hxge_rx_vmac_init(hxgep);
+       if (rv != 0)
+               return (rv);
+
+       rv = hpi_vmac_rx_config(handle, ENABLE, CFG_VMAC_RX_EN, 0);
+       if (rv == HPI_SUCCESS) {
+               if (hxge_get_option("enable_vmac_ints", &enable))
+                       return -1;
+               rv = hpi_vmac_rx_ints(handle, enable);
+       }
+
+       status = (rv == HPI_SUCCESS) ? 0 : -1;
+
+
+       return (status);
+}
+
+/* Disable RxVMAC */
+
+int
+hxge_rx_vmac_disable(struct hxge_adapter * hxgep)
+{
+       hpi_status_t    rv;
+       int     status = 0;
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+       uint64_t        xconfig;
+
+       xconfig = CFG_VMAC_RX_EN;
+       rv = hpi_vmac_rx_config(handle, DISABLE, xconfig, 0);
+
+       status = (rv == HPI_SUCCESS) ? 0 : -1;
+
+
+       return (status);
+}
+
+/* Reset TxVMAC */
+
+int
+hxge_tx_vmac_reset(struct hxge_adapter * hxgep)
+{
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+
+       hpi_tx_vmac_reset(handle);
+       hpi_tx_vmac_clear_regs(handle);
+
+       return  0;
+}
+
+/* Reset RxVMAC */
+
+int
+hxge_rx_vmac_reset(struct hxge_adapter * hxgep)
+{
+       hpi_handle_t    handle = hxgep->hw.hw_addr;
+
+       hpi_rx_vmac_reset(handle);
+       hpi_rx_vmac_clear_regs(handle);
+
+       return  0;
+}
+
+/*ARGSUSED*/
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+irqreturn_t 
+hxge_vmac_intr(int irq, void *data, struct pt_regs *regs)
+#else
+irqreturn_t 
+hxge_vmac_intr(int irq, void *data)
+#endif
+{
+       struct hxge_ldv *ldvp = (struct hxge_ldv *)data;
+       struct hxge_ldg *ldgp = ldvp->ldgp;
+       struct hxge_adapter * hxgep = ldgp->hxgep;
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+       p_hxge_stats_t statsp;
+
+       vmac_tx_stat_t          tx_stat;
+       vmac_rx_stat_t          rx_stat;
+       vmac_tx_frame_cnt_t     tx_frame_cnt;
+       vmac_tx_byte_cnt_t      tx_byte_cnt;
+       vmac_rx_frame_cnt_t     rx_frame_cnt;
+       vmac_rx_byte_cnt_t      rx_byte_cnt;
+       vmac_rx_drop_fr_cnt_t   rx_drop_fr_cnt;
+       vmac_rx_drop_byte_cnt_t rx_drop_byte_cnt;
+       vmac_rx_crc_cnt_t       rx_crc_cnt;
+       vmac_rx_pause_cnt_t     rx_pause_cnt;
+       vmac_rx_bcast_fr_cnt_t  rx_bcast_fr_cnt;
+       vmac_rx_mcast_fr_cnt_t  rx_mcast_fr_cnt;
+
+       int got_ldf0, got_ldf1;
+
+       get_ldf_flags(ldvp, &got_ldf0, &got_ldf1);
+       if (!got_ldf0 && !got_ldf1)
+               return IRQ_NONE;
+
+
+       /*
+        * This interrupt handler is for a specific mac port.
+        */
+       statsp = (p_hxge_stats_t)hxgep->statsp;
+
+       HXGE_REG_RD64(handle, VMAC_TX_STAT, &tx_stat.value);
+       HXGE_REG_RD64(handle, VMAC_TX_FRAME_CNT, &tx_frame_cnt.value);
+       HXGE_REG_RD64(handle, VMAC_TX_BYTE_CNT, &tx_byte_cnt.value);
+
+       HXGE_REG_RD64(handle, VMAC_RX_STAT, &rx_stat.value);
+       HXGE_REG_RD64(handle, VMAC_RX_FRAME_CNT, &rx_frame_cnt.value);
+       HXGE_REG_RD64(handle, VMAC_RX_BYTE_CNT, &rx_byte_cnt.value);
+       HXGE_REG_RD64(handle, VMAC_RX_DROP_FR_CNT, &rx_drop_fr_cnt.value);
+       HXGE_REG_RD64(handle, VMAC_RX_DROP_BYTE_CNT, &rx_drop_byte_cnt.value);
+       HXGE_REG_RD64(handle, VMAC_RX_CRC_CNT, &rx_crc_cnt.value);
+       HXGE_REG_RD64(handle, VMAC_RX_PAUSE_CNT, &rx_pause_cnt.value);
+       HXGE_REG_RD64(handle, VMAC_RX_BCAST_FR_CNT, &rx_bcast_fr_cnt.value);
+       HXGE_REG_RD64(handle, VMAC_RX_MCAST_FR_CNT, &rx_mcast_fr_cnt.value);
+
+       if (tx_stat.bits.tx_byte_cnt_overflow)
+               statsp->vmac_stats.tx_byte_cnt_overflow++;
+       if (tx_stat.bits.tx_frame_cnt_overflow)
+               statsp->vmac_stats.tx_frame_cnt_overflow++;
+       if (tx_stat.bits.frame_tx)
+               statsp->vmac_stats.frame_tx++;
+
+       if (rx_stat.bits.bcast_cnt_overflow)
+               statsp->vmac_stats.bcast_cnt_overflow++;
+       if (rx_stat.bits.mcast_cnt_overflow)
+               statsp->vmac_stats.mcast_cnt_overflow++;
+       if (rx_stat.bits.pause_cnt_overflow)
+               statsp->vmac_stats.pause_cnt_overflow++;
+       if (rx_stat.bits.crc_err_cnt_overflow)
+               statsp->vmac_stats.crc_err_cnt_overflow++;
+       if (rx_stat.bits.rx_drop_byte_cnt_overflow)
+               statsp->vmac_stats.rx_drop_byte_cnt_overflow++;
+       if (rx_stat.bits.rx_drop_frame_cnt_overflow)
+               statsp->vmac_stats.rx_drop_frame_cnt_overflow++;
+       if (rx_stat.bits.rx_byte_cnt_overflow)
+               statsp->vmac_stats.rx_byte_cnt_overflow++;
+       if (rx_stat.bits.rx_frame_cnt_overflow)
+               statsp->vmac_stats.rx_frame_cnt_overflow++;
+       if (rx_stat.bits.frame_rx)
+               statsp->vmac_stats.frame_rx++;
+
+       statsp->vmac_stats.tx_frame_cnt += tx_frame_cnt.bits.tx_frame_cnt;
+       statsp->vmac_stats.tx_byte_cnt += tx_byte_cnt.bits.tx_byte_cnt;
+
+       statsp->vmac_stats.rx_frame_cnt += rx_frame_cnt.bits.rx_frame_cnt;
+       statsp->vmac_stats.rx_byte_cnt += rx_byte_cnt.bits.rx_byte_cnt;
+       statsp->vmac_stats.rx_drop_frame_cnt +=
+           rx_drop_fr_cnt.bits.rx_drop_frame_cnt;
+       statsp->vmac_stats.rx_drop_byte_cnt +=
+           rx_drop_byte_cnt.bits.rx_drop_byte_cnt;
+       statsp->vmac_stats.rx_crc_cnt += rx_crc_cnt.bits.rx_crc_cnt;
+       statsp->vmac_stats.rx_pause_cnt += rx_pause_cnt.bits.rx_pause_cnt;
+       statsp->vmac_stats.rx_bcast_fr_cnt +=
+           rx_bcast_fr_cnt.bits.rx_bcast_fr_cnt;
+       statsp->vmac_stats.rx_mcast_fr_cnt +=
+           rx_mcast_fr_cnt.bits.rx_mcast_fr_cnt;
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Set promiscous mode
+ */
+
+int
+hxge_set_promisc(struct hxge_adapter * hxgep, boolean_t on)
+{
+       int status = 0;
+
+       spin_lock(&hxgep->lock);        
+       if ((status = hxge_rx_vmac_disable(hxgep)) != 0)
+               goto fail;
+       if ((status = hxge_rx_vmac_enable(hxgep)) != 0)
+               goto fail;
+
+       if (on)
+               hxgep->vmac.promisc = TRUE;
+       else
+               hxgep->vmac.promisc = FALSE;
+
+fail:
+       spin_unlock(&hxgep->lock);
+
+       return (status);
+}
+
+
+/*
+ * Set in loopback mode
+ */
+
+int
+hxge_set_loopback(struct hxge_adapter *hxgep, boolean_t enable)
+{
+       hpi_handle_t handle = hxgep->hw.hw_addr;
+       config_op_t  cmd;
+
+       spin_lock(&hxgep->lock);
+
+
+       if (enable) 
+               cmd = ENABLE;
+       else
+               cmd = DISABLE;
+
+       if (hpi_vmac_rx_config(handle, CFG_VMAC_RX_LOOP_BACK, cmd, 0) != HPI_SUCCESS) {
+               HXGE_ERR(hxgep, "hxge_set_loopback: hpi_vmac_rx_config failed");
+               return -1;
+       }
+
+       hxgep->vmac.loopback = enable;
+       spin_unlock(&hxgep->lock);
+
+       return 0;
+}
diff --git a/drivers/net/hxge/hxge_vmac.h b/drivers/net/hxge/hxge_vmac.h
new file mode 100644 (file)
index 0000000..1c2ca1f
--- /dev/null
@@ -0,0 +1,78 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#ifndef        _HXGE_HXGE_VMAC_H
+#define        _HXGE_HXGE_VMAC_H
+
+#include "hxge_vmac_hw.h"
+
+/* VMAC statistics */
+
+typedef        struct _hxge_vmac_stats {
+       /* vmac_tx_stat_t */
+       uint64_t        tx_byte_cnt_overflow;
+       uint64_t        tx_frame_cnt_overflow;
+       uint64_t        frame_tx;
+
+       /* vmac_rx_stat_t */
+       uint64_t        bcast_cnt_overflow;
+       uint64_t        mcast_cnt_overflow;
+       uint64_t        pause_cnt_overflow;
+       uint64_t        crc_err_cnt_overflow;
+       uint64_t        rx_drop_byte_cnt_overflow;
+       uint64_t        rx_drop_frame_cnt_overflow;
+       uint64_t        rx_byte_cnt_overflow;
+       uint64_t        rx_frame_cnt_overflow;
+       uint64_t        frame_rx;
+
+       uint64_t        tx_frame_cnt;           /* vmac_tx_frame_cnt_t */
+       uint64_t        tx_byte_cnt;            /* vmac_tx_byte_cnt_t */
+
+       uint64_t        rx_frame_cnt;           /* vmac_rx_frame_cnt_t */
+       uint64_t        rx_byte_cnt;            /* vmac_rx_byte_cnt_t */
+       uint64_t        rx_drop_frame_cnt;      /* vmac_rx_drop_fr_cnt_t */
+       uint64_t        rx_drop_byte_cnt;       /* vmac_rx_drop_byte_cnt_t */
+       uint64_t        rx_crc_cnt;             /* vmac_rx_crc_cnt_t */
+       uint64_t        rx_pause_cnt;           /* vmac_rx_pause_cnt_t */
+       uint64_t        rx_bcast_fr_cnt;        /* vmac_rx_bcast_fr_cnt_t */
+       uint64_t        rx_mcast_fr_cnt;        /* vmac_rx_mcast_fr_cnt_t */
+} hxge_vmac_stats_t, *p_hxge_vmac_stats_t;
+
+
+typedef        struct _hxge_vmac {
+       boolean_t               is_jumbo;
+       boolean_t               promisc;
+       boolean_t               loopback;
+       uint64_t                tx_config;
+       uint64_t                rx_config;
+       uint16_t                minframesize;
+       uint16_t                maxframesize;
+       uint16_t                maxburstsize;
+       uint16_t                rx_max_framesize;
+//     uint8_t                 mac_addr[HXGE_MAX_MAC_ADDRS];
+} hxge_vmac_t;
+
+
+#endif /* _HXGE_HXGE_VMAC_H */
diff --git a/drivers/net/hxge/hxge_vmac_hw.h b/drivers/net/hxge/hxge_vmac_hw.h
new file mode 100644 (file)
index 0000000..dd40164
--- /dev/null
@@ -0,0 +1,683 @@
+/*****************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+*
+* Copyright 2009, 2011 Oracle America, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License version 2 only, as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE.  See the GNU General Public License version 2 for
+* more details (a copy is included in the LICENSE file that accompanied this
+* code).
+*
+* You should have received a copy of the GNU General Public License version 2
+* along with this program; If not,
+* see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 or
+* visit www.oracle.com if you need additional information or have any
+* questions.
+*
+******************************************************************************/
+
+#ifndef        _HXGE_VMAC_HW_H
+#define        _HXGE_VMAC_HW_H
+
+#define        VMAC_BASE_ADDR                          0X00100000
+
+#define        VMAC_RST                                (VMAC_BASE_ADDR + 0x0)
+#define        VMAC_TX_CFG                             (VMAC_BASE_ADDR + 0x8)
+#define        VMAC_RX_CFG                             (VMAC_BASE_ADDR + 0x10)
+#define        VMAC_TX_STAT                            (VMAC_BASE_ADDR + 0x20)
+#define        VMAC_TX_MSK                             (VMAC_BASE_ADDR + 0x28)
+#define        VMAC_RX_STAT                            (VMAC_BASE_ADDR + 0x30)
+#define        VMAC_RX_MSK                             (VMAC_BASE_ADDR + 0x38)
+#define        VMAC_TX_STAT_MIRROR                     (VMAC_BASE_ADDR + 0x40)
+#define        VMAC_RX_STAT_MIRROR                     (VMAC_BASE_ADDR + 0x48)
+#define        VMAC_TX_FRAME_CNT                       (VMAC_BASE_ADDR + 0x100)
+#define        VMAC_TX_BYTE_CNT                        (VMAC_BASE_ADDR + 0x108)
+#define        VMAC_RX_FRAME_CNT                       (VMAC_BASE_ADDR + 0x120)
+#define        VMAC_RX_BYTE_CNT                        (VMAC_BASE_ADDR + 0x128)
+#define        VMAC_RX_DROP_FR_CNT                     (VMAC_BASE_ADDR + 0x130)
+#define        VMAC_RX_DROP_BYTE_CNT                   (VMAC_BASE_ADDR + 0x138)
+#define        VMAC_RX_CRC_CNT                         (VMAC_BASE_ADDR + 0x140)
+#define        VMAC_RX_PAUSE_CNT                       (VMAC_BASE_ADDR + 0x148)
+#define        VMAC_RX_BCAST_FR_CNT                    (VMAC_BASE_ADDR + 0x150)
+#define        VMAC_RX_MCAST_FR_CNT                    (VMAC_BASE_ADDR + 0x158)
+
+
+/*
+ * Register: VmacRst
+ * VMAC Software Reset Command
+ * Description:
+ * Fields:
+ *     Write a '1' to reset Rx VMAC; auto clears. This brings rx vmac
+ *     to power on reset state.
+ *     Write a '1' to reset Tx VMAC; auto clears. This brings tx vmac
+ *     to power on reset state.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:55;
+               uint64_t        rx_reset:1;
+               uint64_t        rsrvd1:7;
+               uint64_t        tx_reset:1;
+#else
+               uint64_t        tx_reset:1;
+               uint64_t        rsrvd1:7;
+               uint64_t        rx_reset:1;
+               uint64_t        rsrvd:55;
+#endif
+       } bits;
+} vmac_rst_t;
+
+
+/*
+ * Register: VmacTxCfg
+ * Tx VMAC Configuration
+ * Description:
+ * Fields:
+ *     Maximum length of any total transfer gathered by Tx VMAC,
+ *     including packet data, header, crc, transmit header and any
+ *     pad bytes. Default value of 0x2422 represents 9220 bytes of
+ *     packet data, ethernet header, and crc, 14 bytes maximum pad,
+ *     and 16 bytes transmit header = 9250 (0x2422).
+ *     Enable padding of short packet to meet minimum frame length of
+ *     64 bytes. Software should note that if txPad functionality is
+ *     used to pad runt packets to minimum length, that crcInsert
+ *     functionality (below) must also be used to provide the packet
+ *     with correct L2 crc.
+ *     1: Enable generation and appending of FCS to the packets. 0:
+ *     Disable generation and appending of FCS to the packets.
+ *     Enable Tx VMAC. Write a '1' to enable Tx VMAC; write a '0' to
+ *     disable it. This bit also propagates as vmacTdcEn to the TDC
+ *     block. In TDC, the vmacTdcEn bit disables the RTab state
+ *     machine. Hence, the transmission from that blade would be
+ *     stopped and be queued, but no packets would be dropped. Thus,
+ *     the VMAC can only be enabled/disabled at packet boundary. The
+ *     VMAC will not send out portion of a packet. The currently
+ *     processed packet will continue to be sent out when Tx VMAC is
+ *     disabled.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        tx_max_frame_length:14;
+               uint64_t        rsrvd1:15;
+               uint64_t        tx_pad:1;
+               uint64_t        crc_insert:1;
+               uint64_t        tx_en:1;
+#else
+               uint64_t        tx_en:1;
+               uint64_t        crc_insert:1;
+               uint64_t        tx_pad:1;
+               uint64_t        rsrvd1:15;
+               uint64_t        tx_max_frame_length:14;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} vmac_tx_cfg_t;
+
+
+/*
+ * Register: VmacRxCfg
+ * Rx VMAC Configuration
+ * Description: MAC address and length in Type/Length field are
+ * checked in PFC.
+ * Fields:
+ *     Maximum length of a frame accepted by Rx/Tx VMAC. Only packets
+ *     with length between 64 bytes and maxFrameLength will be
+ *     accepted by Rx/Tx VMAC. This length indicates just the packet
+ *     length excluding the packet header, crc, and any pad bytes.
+ *     Maximum value is 9K (9*1024)
+ *     enable packets from the same blade to loopback
+ *     Enable acceptance of all Unicast packets for L2 destination
+ *     address, ie, allow all Unicast packets to pass the L2
+ *     filtering.
+ *     Enable acceptance of all multi-cast packets, ie, allow all
+ *     multi-cast packets to pass the L2 filtering.
+ *     Enable the passing through of flow control frames.
+ *     Enable the stripping of FCS field in the packets.
+ *     Disable of FCS checking. When enable, packets with incorrect
+ *     FCS value are dropped by Rx VMAC.
+ *     Enable rx VMAC. Write a '1' to enable rx VMAC; write a '0' to
+ *     disable it. The VMAC will begin to accept packet at the
+ *     detection of the SOP (start of packet). When disable, the
+ *     currently processed packet will continue to be accepted.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rx_max_frame_length:14;
+               uint64_t        reserved:11;
+               uint64_t        loopback:1;
+               uint64_t        promiscuous_mode:1;
+               uint64_t        promiscuous_group:1;
+               uint64_t        pass_flow_ctrl_fr:1;
+               uint64_t        strip_crc:1;
+               uint64_t        crc_check_disable:1;
+               uint64_t        rx_en:1;
+#else
+               uint64_t        rx_en:1;
+               uint64_t        crc_check_disable:1;
+               uint64_t        strip_crc:1;
+               uint64_t        pass_flow_ctrl_fr:1;
+               uint64_t        promiscuous_group:1;
+               uint64_t        promiscuous_mode:1;
+               uint64_t        loopback:1;
+               uint64_t        reserved:11;
+               uint64_t        rx_max_frame_length:14;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} vmac_rx_cfg_t;
+
+
+/*
+ * Register: VmacTxStat
+ * Tx VMAC Status Register
+ * Description: A new interrupt will be generated only if Tx VMAC is
+ * enabled by vmacTxCfg::txEn=1. Disabling Tx VMAC does not affect
+ * currently-existing Ldf state. Writing this register affects
+ * vmacTxStatMirror register bits also the same way.
+ * Fields:
+ *     Indicates that counter of byte transmitted has exceeded the
+ *     max value.
+ *     Indicates that counter of frame transmitted has exceeded the
+ *     max value.
+ *     A frame has been successfully transmitted.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:61;
+               uint64_t        tx_byte_cnt_overflow:1;
+               uint64_t        tx_frame_cnt_overflow:1;
+               uint64_t        frame_tx:1;
+#else
+               uint64_t        frame_tx:1;
+               uint64_t        tx_frame_cnt_overflow:1;
+               uint64_t        tx_byte_cnt_overflow:1;
+               uint64_t        rsrvd:61;
+#endif
+       } bits;
+} vmac_tx_stat_t;
+
+
+/*
+ * Register: VmacTxMsk
+ * Tx VMAC Status Mask
+ * Description: masking vmacTxStat from interrupt.
+ * Fields:
+ *     1: mask interrupt due to overflow of counter of byte
+ *     transmitted
+ *     1: mask interrupt due to overflow of counter of frame
+ *     transmitted
+ *     1: mask interrupt due to successful transmition of frame.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:61;
+               uint64_t        tx_byte_cnt_overflow_msk:1;
+               uint64_t        tx_frame_cnt_overflow_msk:1;
+               uint64_t        frame_tx_msk:1;
+#else
+               uint64_t        frame_tx_msk:1;
+               uint64_t        tx_frame_cnt_overflow_msk:1;
+               uint64_t        tx_byte_cnt_overflow_msk:1;
+               uint64_t        rsrvd:61;
+#endif
+       } bits;
+} vmac_tx_msk_t;
+
+
+/*
+ * Register: VmacRxStat
+ * Rx VMAC Status Register
+ * Description: Overflow indicators are read-only registers; Read off
+ * the counters to clear. A new interrupt will be generated only if
+ * Rx VMAC is enabled by vmacRxCfg::rxEn=1. Disabling Rx VMAC does
+ * not affect currently-existing Ldf state. Writing this register
+ * affects vmacRxStatMirror register bits also the same way.
+ * Fields:
+ *     Indicates that the counter for broadcast packets has exceeded
+ *     the max value.
+ *     Indicates that the counter for multicast packets has exceeded
+ *     the max value.
+ *     Indicates that the counter for pause packets has exceeded the
+ *     max value.
+ *     Indicates that the counter for packets with mismatched FCS has
+ *     exceeded the max value.
+ *     Indicates that counter of dropped byte has exceeded the max
+ *     value.
+ *     Indicates that counter of dropped frame has exceeded the max
+ *     value.
+ *     Indicates that counter of byte received has exceeded the max
+ *     value.
+ *     Indicates that counter of frame received has exceeded the max
+ *     value.
+ *     A valid frame has been successfully received.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:55;
+               uint64_t        bcast_cnt_overflow:1;
+               uint64_t        mcast_cnt_overflow:1;
+               uint64_t        pause_cnt_overflow:1;
+               uint64_t        crc_err_cnt_overflow:1;
+               uint64_t        rx_drop_byte_cnt_overflow:1;
+               uint64_t        rx_drop_frame_cnt_overflow:1;
+               uint64_t        rx_byte_cnt_overflow:1;
+               uint64_t        rx_frame_cnt_overflow:1;
+               uint64_t        frame_rx:1;
+#else
+               uint64_t        frame_rx:1;
+               uint64_t        rx_frame_cnt_overflow:1;
+               uint64_t        rx_byte_cnt_overflow:1;
+               uint64_t        rx_drop_frame_cnt_overflow:1;
+               uint64_t        rx_drop_byte_cnt_overflow:1;
+               uint64_t        crc_err_cnt_overflow:1;
+               uint64_t        pause_cnt_overflow:1;
+               uint64_t        mcast_cnt_overflow:1;
+               uint64_t        bcast_cnt_overflow:1;
+               uint64_t        rsrvd:55;
+#endif
+       } bits;
+} vmac_rx_stat_t;
+
+
+/*
+ * Register: VmacRxMsk
+ * Rx VMAC Status Mask
+ * Description:
+ * Fields:
+ *     1: mask interrupt due to overflow of the counter for broadcast
+ *     packets
+ *     1: mask interrupt due to overflow of the counter for multicast
+ *     packets
+ *     1: mask interrupt due to overflow of the counter for pause
+ *     packets
+ *     1: mask interrupt due to overflow of the counter for packets
+ *     with mismatched FCS the max value.
+ *     1: mask interrupt due to overflow of dropped byte counter
+ *     1: mask interrupt due to overflow of dropped frame counter
+ *     1: mask interrupt due to overflow of received byte counter
+ *     1: mask interrupt due to overflow of received frame counter
+ *     1: mask interrupt due to a valid frame has been successfully
+ *     received.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:55;
+               uint64_t        bcast_cnt_overflow_msk:1;
+               uint64_t        mcast_cnt_overflow_msk:1;
+               uint64_t        pause_cnt_overflow_msk:1;
+               uint64_t        crc_err_cnt_overflow_msk:1;
+               uint64_t        rx_drop_byte_cnt_overflow_msk:1;
+               uint64_t        rx_drop_frame_cnt_overflow_msk:1;
+               uint64_t        rx_byte_cnt_overflow_msk:1;
+               uint64_t        rx_frame_cnt_overflow_msk:1;
+               uint64_t        frame_rx_msk:1;
+#else
+               uint64_t        frame_rx_msk:1;
+               uint64_t        rx_frame_cnt_overflow_msk:1;
+               uint64_t        rx_byte_cnt_overflow_msk:1;
+               uint64_t        rx_drop_frame_cnt_overflow_msk:1;
+               uint64_t        rx_drop_byte_cnt_overflow_msk:1;
+               uint64_t        crc_err_cnt_overflow_msk:1;
+               uint64_t        pause_cnt_overflow_msk:1;
+               uint64_t        mcast_cnt_overflow_msk:1;
+               uint64_t        bcast_cnt_overflow_msk:1;
+               uint64_t        rsrvd:55;
+#endif
+       } bits;
+} vmac_rx_msk_t;
+
+
+/*
+ * Register: VmacTxStatMirror
+ * Tx VMAC Status Mirror Register
+ * Description: Write a 1 to this register to force the corresponding
+ * interrupt. Reading this register returns the current Tx interrupt
+ * status which would be the same as reading the vmacTxStat register.
+ * The bits are cleared by writing 1 to the corresponding register
+ * bit in the vmacTxStat register. ie, bit 0 of this register is
+ * cleared by writing 1 to bit 0 in the vmacTxStat register.
+ *
+ * Fields:
+ *     1 : Force tx byte counter overflow interrupt generation
+ *     1 : Force tx frame counter overflow interrupt generation
+ *     1 : Force frame transmitted interrupt generation
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:61;
+               uint64_t        force_tx_byte_cnt_overflow:1;
+               uint64_t        force_tx_frame_cnt_overflow:1;
+               uint64_t        force_frame_tx:1;
+#else
+               uint64_t        force_frame_tx:1;
+               uint64_t        force_tx_frame_cnt_overflow:1;
+               uint64_t        force_tx_byte_cnt_overflow:1;
+               uint64_t        rsrvd:61;
+#endif
+       } bits;
+} vmac_tx_stat_mirror_t;
+
+
+/*
+ * Register: VmacRxStatMirror
+ * Rx VMAC Status Mirror Register
+ * Description: Write a 1 to this register to force the corresponding
+ * interrupt. Reading this register returns the current Rx interrupt
+ * status which would be the same as reading the vmacRxStat register.
+ * The bits are cleared by writing 1 to the corresponding register
+ * bit in the vmacRxStat register. ie, bit 0 of this register is
+ * cleared by writing 1 to bit 0 in the vmacRxStat register.
+ * Fields:
+ *     1 : Force broadcast frame counter overflow interrupt
+ *     generation
+ *     1 : Force multicast frame counter overflow interrupt
+ *     generation
+ *     1 : Force pause frame counter overflow interrupt generation
+ *     1 : Force crc error counter overflow interrupt generation
+ *     1 : Force dropped frames byte counter overflow interrupt
+ *     generation
+ *     1 : Force dropped frame counter overflow interrupt generation
+ *     1 : Force rx byte counter overflow interrupt generation
+ *     1 : Force rx frame counter overflow interrupt generation
+ *     1 : Force frame received interrupt generation
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:55;
+               uint64_t        force_bcast_cnt_overflow:1;
+               uint64_t        force_mcast_cnt_overflow:1;
+               uint64_t        force_pause_cnt_overflow:1;
+               uint64_t        force_crc_err_cnt_overflow:1;
+               uint64_t        force_rx_drop_byte_cnt_overflow:1;
+               uint64_t        force_rx_drop_frame_cnt_overflow:1;
+               uint64_t        force_rx_byte_cnt_overflow:1;
+               uint64_t        force_rx_frame_cnt_overflow:1;
+               uint64_t        force_frame_rx:1;
+#else
+               uint64_t        force_frame_rx:1;
+               uint64_t        force_rx_frame_cnt_overflow:1;
+               uint64_t        force_rx_byte_cnt_overflow:1;
+               uint64_t        force_rx_drop_frame_cnt_overflow:1;
+               uint64_t        force_rx_drop_byte_cnt_overflow:1;
+               uint64_t        force_crc_err_cnt_overflow:1;
+               uint64_t        force_pause_cnt_overflow:1;
+               uint64_t        force_mcast_cnt_overflow:1;
+               uint64_t        force_bcast_cnt_overflow:1;
+               uint64_t        rsrvd:55;
+#endif
+       } bits;
+} vmac_rx_stat_mirror_t;
+
+
+/*
+ * Register: VmacTxFrameCnt
+ * VMAC transmitted frame counter
+ * Description:
+ * Fields:
+ *     Indicates the number of frames transmitted by Tx VMAC. The
+ *     counter will saturate at max value. The counter is stalled
+ *     when Tx VMAC is disabled by vmacTxCfg::txEn=0
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        tx_frame_cnt:32;
+#else
+               uint64_t        tx_frame_cnt:32;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} vmac_tx_frame_cnt_t;
+
+
+/*
+ * Register: VmacTxByteCnt
+ * VMAC transmitted byte counter
+ * Description:
+ * Fields:
+ *     Indicates the number of byte (octet) of data transmitted by Tx
+ *     VMAC. This counter counts all the bytes of the incoming data
+ *     including packet header, packet data, crc, and pad bytes. The
+ *     counter will saturate at max value. The counter is stalled
+ *     when Tx VMAC is disabled by vmacTxCfg::txEn=0
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        tx_byte_cnt:32;
+#else
+               uint64_t        tx_byte_cnt:32;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} vmac_tx_byte_cnt_t;
+
+
+/*
+ * Register: VmacRxFrameCnt
+ * VMAC received frame counter
+ * Description:
+ * Fields:
+ *     Indicates the number of frame received by Rx VMAC. The counter
+ *     will saturate at max value. The counter is stalled when Rx
+ *     VMAC is disabled by vmacRxCfg::rxEn=0.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rx_frame_cnt:32;
+#else
+               uint64_t        rx_frame_cnt:32;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} vmac_rx_frame_cnt_t;
+
+
+/*
+ * Register: VmacRxByteCnt
+ * VMAC received byte counter
+ * Description:
+ * Fields:
+ *     Indicates the number of bytes (octet) of data received by Rx
+ *     VMAC including any error frames. The counter will saturate at
+ *     max value. The counter is stalled when Rx VMAC is disabled by
+ *     vmacRxCfg::rxEn=0.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rx_byte_cnt:32;
+#else
+               uint64_t        rx_byte_cnt:32;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} vmac_rx_byte_cnt_t;
+
+
+/*
+ * Register: VmacRxDropFrCnt
+ * VMAC dropped frame counter
+ * Description:
+ * Fields:
+ *     Indicates the number of frame dropped by Rx VMAC. The counter
+ *     will This counter increments for every frame dropped for the
+ *     following: - crc mismatch & crc check is enabled - failed the
+ *     L2 address match & Vmac is not in promiscuous mode - pause
+ *     packet & Vmac is not programmed to pass these frames The
+ *     counter will saturate at max value. The counter is stalled
+ *     when Rx VMAC is disabled by vmacRxCfg::rxEn=0.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rx_drop_frame_cnt:32;
+#else
+               uint64_t        rx_drop_frame_cnt:32;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} vmac_rx_drop_fr_cnt_t;
+
+
+/*
+ * Register: VmacRxDropByteCnt
+ * VMAC dropped byte counter
+ * Description:
+ * Fields:
+ *     Indicates the number of byte of data dropped by Rx VMAC.
+ *     Frames are dropped for one of the follg conditions : - crc
+ *     mismatch & crc check is enabled - failed the L2 address match
+ *     & Vmac is not in promiscuous mode - pause packet & Vmac is not
+ *     programmed to pass these frames The counter will saturate at
+ *     max value. The counter is stalled when Rx VMAC is disabled by
+ *     vmacRxCfg::rxEn=0.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rx_drop_byte_cnt:32;
+#else
+               uint64_t        rx_drop_byte_cnt:32;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} vmac_rx_drop_byte_cnt_t;
+
+
+/*
+ * Register: VmacRxCrcCnt
+ * VMAC received CRC error frame counter
+ * Description:
+ * Fields:
+ *     Indicates the number of frames with invalid CRC. When NMAC
+ *     truncates a packet, it asserts crcError indication to VMAC
+ *     which then counts it towards CRC error. Thus the VMAC crc
+ *     error counter reflects the CRC mismatches on all the packets
+ *     going out of RxMAC while the NMAC crc error counter reflects
+ *     the CRC mismatches on all the packets coming into RxMAC. The
+ *     counter will saturate at max value The counter is stalled when
+ *     Rx VMAC is disabled by vmacRxCfg::rxEn=0.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rx_crc_cnt:32;
+#else
+               uint64_t        rx_crc_cnt:32;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} vmac_rx_crc_cnt_t;
+
+
+/*
+ * Register: VmacRxPauseCnt
+ * VMAC received pause frame counter
+ * Description:
+ * Fields:
+ *     Count the number of pause frames received by Rx VMAC. The
+ *     counter is stalled when Rx VMAC is disabled by
+ *     vmacRxCfg::rxEn=0.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rx_pause_cnt:32;
+#else
+               uint64_t        rx_pause_cnt:32;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} vmac_rx_pause_cnt_t;
+
+
+/*
+ * Register: VmacRxBcastFrCnt
+ * VMAC received broadcast frame counter
+ * Description:
+ * Fields:
+ *     Indicates the number of broadcast frames received The counter
+ *     is stalled when Rx VMAC is disabled by vmacRxCfg::rxEn=0.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rx_bcast_fr_cnt:32;
+#else
+               uint64_t        rx_bcast_fr_cnt:32;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} vmac_rx_bcast_fr_cnt_t;
+
+
+/*
+ * Register: VmacRxMcastFrCnt
+ * VMAC received multicast frame counter
+ * Description:
+ * Fields:
+ *     Indicates the number of multicast frames received The counter
+ *     is stalled when Rx VMAC is disabled by vmacRxCfg::rxEn=0.
+ */
+typedef union {
+       uint64_t value;
+       struct {
+#if defined(__BIG_ENDIAN)
+               uint64_t        rsrvd:32;
+               uint64_t        rx_mcast_fr_cnt:32;
+#else
+               uint64_t        rx_mcast_fr_cnt:32;
+               uint64_t        rsrvd:32;
+#endif
+       } bits;
+} vmac_rx_mcast_fr_cnt_t;
+
+
+#endif /* _HXGE_VMAC_HW_H */
index bee9eba8a3ce5f39b2231fa20b0279992a7a0851..c0f5dbca346e4a702a02736b518a4a33706e57a4 100644 (file)
@@ -1897,6 +1897,7 @@ CONFIG_BNX2X=m
 CONFIG_QLCNIC=m
 CONFIG_QLGE=m
 CONFIG_BNA=m
+CONFIG_HXGE=m
 CONFIG_SFC=m
 CONFIG_SFC_MTD=y
 CONFIG_BE2NET=m