Patchwork Subject: [PATCH 2/6] bna: Brocade 10Gb Ethernet device driver

login
register
mail settings
Submitter Debashis Dutt
Date Dec. 19, 2009, 1:28 a.m.
Message ID <200912190128.nBJ1SZBw015434@blc-10-2.brocade.com>
Download mbox | patch
Permalink /patch/41454/
State RFC
Delegated to: David Miller
Headers show

Comments

Debashis Dutt - Dec. 19, 2009, 1:28 a.m.
From: Debashis Dutt <ddutt@brocade.com>

This is patch 2/6 which contains linux driver source for
Brocade's BR1010/BR1020 10Gb CEE capable ethernet adapter.
Source is based against net-next-2.6.

We wish this patch to be considered for inclusion in net-next-2.6

Signed-off-by: Debashis Dutt <ddutt@brocade.com>
---
 bfa_timer.c    |   91 ++
 bfad_fwimg.c   |   92 ++
 bna_fn.c       | 1862 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 bna_queue.c    |  409 ++++++++++++
 bnad_ethtool.c | 1102 +++++++++++++++++++++++++++++++++
 5 files changed, 3556 insertions(+)

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ben Hutchings - Dec. 19, 2009, 2:19 a.m.
On Fri, 2009-12-18 at 17:28 -0800, Debashis Dutt wrote:
[...]
> diff -ruP net-next-2.6-orig/drivers/net/bna/bfad_fwimg.c net-next-2.6-mod/drivers/net/bna/bfad_fwimg.c
> --- net-next-2.6-orig/drivers/net/bna/bfad_fwimg.c      1969-12-31 16:00:00.000000000 -0800
> +++ net-next-2.6-mod/drivers/net/bna/bfad_fwimg.c       2009-12-18 16:53:40.000000000 -0800
[...]
> +u32 bfi_image_ct_size;
> +u32 bfi_image_cb_size;
> +u32 *bfi_image_ct;
> +u32 *bfi_image_cb;
> +
> +#define	BFAD_FW_FILE_CT	"ctfw.bin"
> +#define	BFAD_FW_FILE_CB	"cbfw.bin"

You should also use the MODULE_FIRMWARE() macro to add references to
these files in the module.  That enables distribution scripts to tell
which firmware files need to be installed on the system or included in
an initramfs.

> +u32 *
> +bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
> +			u32 *bfi_image_size, char *fw_name)
> +{
> +	const struct firmware *fw;
> +
> +	if (request_firmware(&fw, fw_name, &pdev->dev)) {
> +		printk(KERN_ALERT "Can't locate firmware %s\n", fw_name);
> +		goto error;
> +	}
> +
> +	*bfi_image = vmalloc(fw->size);
> +	if (NULL == *bfi_image) {
> +		printk(KERN_ALERT "Fail to allocate buffer for fw image "
> +			"size=%x!\n", (u32) fw->size);
> +		goto error;
> +	}
> +
> +	memcpy(*bfi_image, fw->data, fw->size);

What is the point of making a copy?

> +	*bfi_image_size = fw->size/sizeof(u32);
> +
> +	return *bfi_image;
> +
> +error:
> +	return NULL;
> +}

Are you ever going to free any of these firmware images?

> +u32 *
> +bfad_get_firmware_buf(struct pci_dev *pdev)
> +{
> +	if (pdev->device == BFA_PCI_DEVICE_ID_CT) {
> +		if (bfi_image_ct_size == 0)
> +			bfad_read_firmware(pdev, &bfi_image_ct,
> +				&bfi_image_ct_size, BFAD_FW_FILE_CT);
> +		return bfi_image_ct;
> +	} else {
> +		if (bfi_image_cb_size == 0)
> +			bfad_read_firmware(pdev, &bfi_image_cb,
> +				&bfi_image_cb_size, BFAD_FW_FILE_CB);
> +		return bfi_image_cb;
> +	}
> +}
[...]

PCI devices can be probed in parallel, so this must use a mutex.

Ben.

Patch

diff -ruP net-next-2.6-orig/drivers/net/bna/bfad_fwimg.c net-next-2.6-mod/drivers/net/bna/bfad_fwimg.c
--- net-next-2.6-orig/drivers/net/bna/bfad_fwimg.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6-mod/drivers/net/bna/bfad_fwimg.c	2009-12-18 16:53:40.000000000 -0800
@@ -0,0 +1,92 @@ 
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 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 for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+/**
+ *  bfad_fwimg.c Linux driver PCI interface module.
+ */
+#include "cna.h"
+#include "defs/bfa_defs_pci.h"
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <asm/fcntl.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include "bfa_fwimg_priv.h"
+
+u32 bfi_image_ct_size;
+u32 bfi_image_cb_size;
+u32 *bfi_image_ct;
+u32 *bfi_image_cb;
+
+#define	BFAD_FW_FILE_CT	"ctfw.bin"
+#define	BFAD_FW_FILE_CB	"cbfw.bin"
+
+u32 *
+bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
+			u32 *bfi_image_size, char *fw_name)
+{
+	const struct firmware *fw;
+
+	if (request_firmware(&fw, fw_name, &pdev->dev)) {
+		printk(KERN_ALERT "Can't locate firmware %s\n", fw_name);
+		goto error;
+	}
+
+	*bfi_image = vmalloc(fw->size);
+	if (NULL == *bfi_image) {
+		printk(KERN_ALERT "Fail to allocate buffer for fw image "
+			"size=%x!\n", (u32) fw->size);
+		goto error;
+	}
+
+	memcpy(*bfi_image, fw->data, fw->size);
+	*bfi_image_size = fw->size/sizeof(u32);
+
+	return *bfi_image;
+
+error:
+	return NULL;
+}
+
+u32 *
+bfad_get_firmware_buf(struct pci_dev *pdev)
+{
+	if (pdev->device == BFA_PCI_DEVICE_ID_CT) {
+		if (bfi_image_ct_size == 0)
+			bfad_read_firmware(pdev, &bfi_image_ct,
+				&bfi_image_ct_size, BFAD_FW_FILE_CT);
+		return bfi_image_ct;
+	} else {
+		if (bfi_image_cb_size == 0)
+			bfad_read_firmware(pdev, &bfi_image_cb,
+				&bfi_image_cb_size, BFAD_FW_FILE_CB);
+		return bfi_image_cb;
+	}
+}
+
+u32 *
+bfi_image_ct_get_chunk(u32 off)
+{ return (u32 *)(bfi_image_ct + off); }
+
+u32 *
+bfi_image_cb_get_chunk(u32 off)
+{ return (u32 *)(bfi_image_cb + off); }
+
diff -ruP net-next-2.6-orig/drivers/net/bna/bfa_timer.c net-next-2.6-mod/drivers/net/bna/bfa_timer.c
--- net-next-2.6-orig/drivers/net/bna/bfa_timer.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6-mod/drivers/net/bna/bfa_timer.c	2009-12-18 16:53:40.000000000 -0800
@@ -0,0 +1,91 @@ 
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 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 for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#include "bfa_timer.h"
+#include "cs/bfa_debug.h"
+
+void
+bfa_timer_init(struct bfa_timer_mod *mod)
+{
+	INIT_LIST_HEAD(&mod->timer_q);
+}
+
+void
+bfa_timer_beat(struct bfa_timer_mod *mod)
+{
+	struct list_head        *qh = &mod->timer_q;
+	struct list_head        *qe, *qe_next;
+	struct bfa_timer *elem;
+	struct list_head         timedout_q;
+
+	INIT_LIST_HEAD(&timedout_q);
+
+	qe = bfa_q_next(qh);
+
+	while (qe != qh) {
+		qe_next = bfa_q_next(qe);
+
+		elem = (struct bfa_timer *) qe;
+		if (elem->timeout <= BFA_TIMER_FREQ) {
+			elem->timeout = 0;
+			list_del(&elem->qe);
+			list_add_tail(&elem->qe, &timedout_q);
+		} else {
+			elem->timeout -= BFA_TIMER_FREQ;
+		}
+
+		qe = qe_next;	/* go to next elem */
+	}
+
+	/*
+	 * Pop all the timeout entries
+	 */
+	while (!list_empty(&timedout_q)) {
+		bfa_q_deq(&timedout_q, &elem);
+		elem->timercb(elem->arg);
+	}
+}
+
+/**
+ * Should be called with lock protection
+ */
+void
+bfa_timer_begin(struct bfa_timer_mod *mod, struct bfa_timer *timer,
+		    void (*timercb) (void *), void *arg, unsigned int timeout)
+{
+
+	bfa_assert(timercb != NULL);
+	bfa_assert(!bfa_q_is_on_q(&mod->timer_q, timer));
+
+	timer->timeout = timeout;
+	timer->timercb = timercb;
+	timer->arg = arg;
+
+	list_add_tail(&timer->qe, &mod->timer_q);
+}
+
+/**
+ * Should be called with lock protection
+ */
+void
+bfa_timer_stop(struct bfa_timer *timer)
+{
+	bfa_assert(!list_empty(&timer->qe));
+
+	list_del(&timer->qe);
+}
diff -ruP net-next-2.6-orig/drivers/net/bna/bnad_ethtool.c net-next-2.6-mod/drivers/net/bna/bnad_ethtool.c
--- net-next-2.6-orig/drivers/net/bna/bnad_ethtool.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6-mod/drivers/net/bna/bnad_ethtool.c	2009-12-18 16:53:40.000000000 -0800
@@ -0,0 +1,1102 @@ 
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 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 for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+/**
+ *  bna_ethtool.c  Brocade 10G PCIe Ethernet driver.
+ */
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <linux/ethtool.h>
+#include <linux/rtnetlink.h>
+
+#include "bnad.h"
+#include "cna.h"
+#include "bna_hwreg.h"
+#include "bna_iocll.h"
+#include "bnad_defs.h"
+#include "phyport_defs.h"
+
+#define BNAD_ETHTOOL_STATS_NUM						\
+	(sizeof(struct net_device_stats) / sizeof(unsigned long) +	\
+	sizeof(struct bnad_drv_stats) / sizeof(u64) +		\
+	(offsetof(struct bna_stats, rxf_stats[0]) +			\
+	sizeof(struct bna_stats_txf)) / sizeof(u64))
+
+static char *bnad_net_stats_strings[BNAD_ETHTOOL_STATS_NUM] = {
+	"rx_packets",
+	"tx_packets",
+	"rx_bytes",
+	"tx_bytes",
+	"rx_errors",
+	"tx_errors",
+	"rx_dropped",
+	"tx_dropped",
+	"multicast",
+	"collisions",
+
+	"rx_length_errors",
+	"rx_over_errors",
+	"rx_crc_errors",
+	"rx_frame_errors",
+	"rx_fifo_errors",
+	"rx_missed_errors",
+
+	"tx_aborted_errors",
+	"tx_carrier_errors",
+	"tx_fifo_errors",
+	"tx_heartbeat_errors",
+	"tx_window_errors",
+
+	"rx_compressed",
+	"tx_compressed",
+
+	"netif_queue_stop",
+	"netif_queue_wakeup",
+	"tso4",
+	"tso6",
+	"tso_err",
+	"tcpcsum_offload",
+	"udpcsum_offload",
+	"csum_help",
+	"csum_help_err",
+	"hw_stats_updates",
+	"napi_complete",
+
+	"mac_frame_64",
+	"mac_frame_65_127",
+	"mac_frame_128_255",
+	"mac_frame_256_511",
+	"mac_frame_512_1023",
+	"mac_frame_1024_1518",
+	"mac_frame_1518_1522",
+	"mac_rx_bytes",
+	"mac_rx_packets",
+	"mac_rx_fcs_error",
+	"mac_rx_multicast",
+	"mac_rx_broadcast",
+	"mac_rx_control_frames",
+	"mac_rx_pause",
+	"mac_rx_unknown_opcode",
+	"mac_rx_alignment_error",
+	"mac_rx_frame_length_error",
+	"mac_rx_code_error",
+	"mac_rx_carrier_sense_error",
+	"mac_rx_undersize",
+	"mac_rx_oversize",
+	"mac_rx_fragments",
+	"mac_rx_jabber",
+	"mac_rx_drop",
+
+	"bpc_rx_pause_0",
+	"bpc_rx_pause_1",
+	"bpc_rx_pause_2",
+	"bpc_rx_pause_3",
+	"bpc_rx_pause_4",
+	"bpc_rx_pause_5",
+	"bpc_rx_pause_6",
+	"bpc_rx_pause_7",
+	"bpc_rx_zero_pause_0",
+	"bpc_rx_zero_pause_1",
+	"bpc_rx_zero_pause_2",
+	"bpc_rx_zero_pause_3",
+	"bpc_rx_zero_pause_4",
+	"bpc_rx_zero_pause_5",
+	"bpc_rx_zero_pause_6",
+	"bpc_rx_zero_pause_7",
+	"bpc_rx_first_pause_0",
+	"bpc_rx_first_pause_1",
+	"bpc_rx_first_pause_2",
+	"bpc_rx_first_pause_3",
+	"bpc_rx_first_pause_4",
+	"bpc_rx_first_pause_5",
+	"bpc_rx_first_pause_6",
+	"bpc_rx_first_pause_7",
+
+	"rad_rx_frames",
+	"rad_rx_octets",
+	"rad_rx_vlan_frames",
+	"rad_rx_ucast",
+	"rad_rx_ucast_octets",
+	"rad_rx_ucast_vlan",
+	"rad_rx_mcast",
+	"rad_rx_mcast_octets",
+	"rad_rx_mcast_vlan",
+	"rad_rx_bcast",
+	"rad_rx_bcast_octets",
+	"rad_rx_bcast_vlan",
+	"rad_rx_drops",
+
+	"fc_rx_ucast_octets",
+	"fc_rx_ucast",
+	"fc_rx_ucast_vlan",
+	"fc_rx_mcast_octets",
+	"fc_rx_mcast",
+	"fc_rx_mcast_vlan",
+	"fc_rx_bcast_octets",
+	"fc_rx_bcast",
+	"fc_rx_bcast_vlan",
+
+	"mac_tx_bytes",
+	"mac_tx_packets",
+	"mac_tx_multicast",
+	"mac_tx_broadcast",
+	"mac_tx_pause",
+	"mac_tx_deferral",
+	"mac_tx_excessive_deferral",
+	"mac_tx_single_collision",
+	"mac_tx_muliple_collision",
+	"mac_tx_late_collision",
+	"mac_tx_excessive_collision",
+	"mac_tx_total_collision",
+	"mac_tx_pause_honored",
+	"mac_tx_drop",
+	"mac_tx_jabber",
+	"mac_tx_fcs_error",
+	"mac_tx_control_frame",
+	"mac_tx_oversize",
+	"mac_tx_undersize",
+	"mac_tx_fragments",
+
+	"bpc_tx_pause_0",
+	"bpc_tx_pause_1",
+	"bpc_tx_pause_2",
+	"bpc_tx_pause_3",
+	"bpc_tx_pause_4",
+	"bpc_tx_pause_5",
+	"bpc_tx_pause_6",
+	"bpc_tx_pause_7",
+	"bpc_tx_zero_pause_0",
+	"bpc_tx_zero_pause_1",
+	"bpc_tx_zero_pause_2",
+	"bpc_tx_zero_pause_3",
+	"bpc_tx_zero_pause_4",
+	"bpc_tx_zero_pause_5",
+	"bpc_tx_zero_pause_6",
+	"bpc_tx_zero_pause_7",
+	"bpc_tx_first_pause_0",
+	"bpc_tx_first_pause_1",
+	"bpc_tx_first_pause_2",
+	"bpc_tx_first_pause_3",
+	"bpc_tx_first_pause_4",
+	"bpc_tx_first_pause_5",
+	"bpc_tx_first_pause_6",
+	"bpc_tx_first_pause_7",
+
+	"fc_tx_ucast_octets",
+	"fc_tx_ucast",
+	"fc_tx_ucast_vlan",
+	"fc_tx_mcast_octets",
+	"fc_tx_mcast",
+	"fc_tx_mcast_vlan",
+	"fc_tx_bcast_octets",
+	"fc_tx_bcast",
+	"fc_tx_bcast_vlan",
+	"fc_tx_parity_errors",
+	"fc_tx_timeout",
+	"fc_tx_fid_parity_errors",
+
+	"txf0_ucast_octets",
+	"txf0_ucast",
+	"txf0_ucast_vlan",
+	"txf0_mcast_octets",
+	"txf0_mcast",
+	"txf0_mcast_vlan",
+	"txf0_bcast_octets",
+	"txf0_bcast",
+	"txf0_bcast_vlan",
+	"txf0_errors",
+	"txf0_filter_vlan",
+	"txf0_filter_mac_sa"
+};
+
+static int bnad_get_regs_len(struct net_device *netdev);
+static int bnad_get_stats_count_locked(struct net_device *netdev);
+
+static int bnad_get_settings(struct net_device *netdev,
+	struct ethtool_cmd *cmd)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	struct bna_port_param port_param;
+
+	spin_lock_irq(&bnad->priv_lock);
+	bna_port_param_get(bnad->priv, &port_param);
+	spin_unlock_irq(&bnad->priv_lock);
+
+	if (port_param.speed == BNA_LINK_SPEED_10Gbps) {
+		cmd->supported = SUPPORTED_10000baseT_Full;
+		cmd->advertising = ADVERTISED_10000baseT_Full;
+	}
+
+	if (port_param.autoneg) {
+		cmd->supported |= SUPPORTED_Autoneg;
+		cmd->advertising |= ADVERTISED_Autoneg;
+		cmd->autoneg = AUTONEG_ENABLE;
+	} else
+		cmd->autoneg = AUTONEG_DISABLE;
+	cmd->supported |= SUPPORTED_FIBRE;
+	cmd->advertising |= ADVERTISED_FIBRE;
+	cmd->port = PORT_FIBRE;
+	cmd->phy_address = 0;
+
+	if (netif_carrier_ok(netdev)) {
+		cmd->speed = SPEED_10000;
+		cmd->duplex = DUPLEX_FULL;
+	} else {
+		cmd->speed = -1;
+		cmd->duplex = -1;
+	}
+	cmd->transceiver = XCVR_EXTERNAL;
+	cmd->maxtxpkt = 0;
+	cmd->maxrxpkt = 0;
+
+	return 0;
+}
+
+static int bnad_set_settings(struct net_device *netdev,
+	struct ethtool_cmd *cmd)
+{
+	/* 10G full duplex setting supported only */
+	if (cmd->autoneg == AUTONEG_ENABLE)
+		return -EOPNOTSUPP;
+	 else {
+		if ((cmd->speed == SPEED_10000) && (cmd->duplex == DUPLEX_FULL))
+			return 0;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static void bnad_get_drvinfo(struct net_device *netdev,
+	struct ethtool_drvinfo *drvinfo)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	struct bfa_ioc_attr *ioc_attr;
+
+	strcpy(drvinfo->driver, BNAD_NAME);
+	strcpy(drvinfo->version, BNAD_VERSION);
+
+	ioc_attr = kzalloc(sizeof(*ioc_attr), GFP_KERNEL);
+	if (ioc_attr) {
+		memset(ioc_attr, 0, sizeof(*ioc_attr));
+		spin_lock_irq(&bnad->priv_lock);
+		bna_iocll_getattr(bnad->priv, ioc_attr);
+		spin_unlock_irq(&bnad->priv_lock);
+
+		strncpy(drvinfo->fw_version, ioc_attr->adapter_attr.fw_ver,
+			sizeof(drvinfo->fw_version) - 1);
+		kfree(ioc_attr);
+	}
+
+	strncpy(drvinfo->bus_info, pci_name(bnad->pcidev), ETHTOOL_BUSINFO_LEN);
+}
+
+static int get_regs(struct bnad *bnad, u32 * regs)
+{
+	int num = 0, i;
+	u32 reg_addr;
+
+#define BNAD_GET_REG(addr) 					\
+do {								\
+	if (regs)						\
+		regs[num++] = readl(bnad->bar0 + (addr));      \
+	else							\
+		num++;						\
+} while (0)
+
+	spin_lock_irq(&bnad->priv_lock);
+
+	/* DMA Block Internal Registers */
+	BNAD_GET_REG(DMA_CTRL_REG0);
+	BNAD_GET_REG(DMA_CTRL_REG1);
+	BNAD_GET_REG(DMA_ERR_INT_STATUS);
+	BNAD_GET_REG(DMA_ERR_INT_ENABLE);
+	BNAD_GET_REG(DMA_ERR_INT_STATUS_SET);
+
+	/* APP Block Register Address Offset from BAR0 */
+	BNAD_GET_REG(HOSTFN0_INT_STATUS);
+	BNAD_GET_REG(HOSTFN0_INT_MASK);
+	BNAD_GET_REG(HOST_PAGE_NUM_FN0);
+	BNAD_GET_REG(HOST_MSIX_ERR_INDEX_FN0);
+	BNAD_GET_REG(FN0_PCIE_ERR_REG);
+	BNAD_GET_REG(FN0_ERR_TYPE_STATUS_REG);
+	BNAD_GET_REG(FN0_ERR_TYPE_MSK_STATUS_REG);
+
+	BNAD_GET_REG(HOSTFN1_INT_STATUS);
+	BNAD_GET_REG(HOSTFN1_INT_MASK);
+	BNAD_GET_REG(HOST_PAGE_NUM_FN1);
+	BNAD_GET_REG(HOST_MSIX_ERR_INDEX_FN1);
+	BNAD_GET_REG(FN1_PCIE_ERR_REG);
+	BNAD_GET_REG(FN1_ERR_TYPE_STATUS_REG);
+	BNAD_GET_REG(FN1_ERR_TYPE_MSK_STATUS_REG);
+
+	BNAD_GET_REG(PCIE_MISC_REG);
+
+	BNAD_GET_REG(HOST_SEM0_REG);
+	BNAD_GET_REG(HOST_SEM1_REG);
+	BNAD_GET_REG(HOST_SEM2_REG);
+	BNAD_GET_REG(HOST_SEM3_REG);
+	BNAD_GET_REG(HOST_SEM0_INFO_REG);
+	BNAD_GET_REG(HOST_SEM1_INFO_REG);
+	BNAD_GET_REG(HOST_SEM2_INFO_REG);
+	BNAD_GET_REG(HOST_SEM3_INFO_REG);
+
+	BNAD_GET_REG(TEMPSENSE_CNTL_REG);
+	BNAD_GET_REG(TEMPSENSE_STAT_REG);
+
+	BNAD_GET_REG(APP_LOCAL_ERR_STAT);
+	BNAD_GET_REG(APP_LOCAL_ERR_MSK);
+
+	BNAD_GET_REG(PCIE_LNK_ERR_STAT);
+	BNAD_GET_REG(PCIE_LNK_ERR_MSK);
+
+	BNAD_GET_REG(FCOE_FIP_ETH_TYPE);
+	BNAD_GET_REG(RESV_ETH_TYPE);
+
+	BNAD_GET_REG(HOSTFN2_INT_STATUS);
+	BNAD_GET_REG(HOSTFN2_INT_MASK);
+	BNAD_GET_REG(HOST_PAGE_NUM_FN2);
+	BNAD_GET_REG(HOST_MSIX_ERR_INDEX_FN2);
+	BNAD_GET_REG(FN2_PCIE_ERR_REG);
+	BNAD_GET_REG(FN2_ERR_TYPE_STATUS_REG);
+	BNAD_GET_REG(FN2_ERR_TYPE_MSK_STATUS_REG);
+
+	BNAD_GET_REG(HOSTFN3_INT_STATUS);
+	BNAD_GET_REG(HOSTFN3_INT_MASK);
+	BNAD_GET_REG(HOST_PAGE_NUM_FN3);
+	BNAD_GET_REG(HOST_MSIX_ERR_INDEX_FN3);
+	BNAD_GET_REG(FN3_PCIE_ERR_REG);
+	BNAD_GET_REG(FN3_ERR_TYPE_STATUS_REG);
+	BNAD_GET_REG(FN3_ERR_TYPE_MSK_STATUS_REG);
+
+	/* Host Command Status Registers */
+	reg_addr = HOST_CMDSTS0_CLR_REG;
+	for (i = 0; i < 16; i++) {
+		BNAD_GET_REG(reg_addr);
+		BNAD_GET_REG(reg_addr + 4);
+		BNAD_GET_REG(reg_addr + 8);
+		reg_addr += 0x10;
+	}
+
+	/* Function ID register */
+	BNAD_GET_REG(FNC_ID_REG);
+
+	/* Function personality register */
+	BNAD_GET_REG(FNC_PERS_REG);
+
+	/* Operation mode register */
+	BNAD_GET_REG(OP_MODE);
+
+	/* LPU0 Registers */
+	BNAD_GET_REG(LPU0_MBOX_CTL_REG);
+	BNAD_GET_REG(LPU0_MBOX_CMD_REG);
+	BNAD_GET_REG(LPU0_MBOX_LINK_0REG);
+	BNAD_GET_REG(LPU1_MBOX_LINK_0REG);
+	BNAD_GET_REG(LPU0_MBOX_STATUS_0REG);
+	BNAD_GET_REG(LPU1_MBOX_STATUS_0REG);
+	BNAD_GET_REG(LPU0_ERR_STATUS_REG);
+	BNAD_GET_REG(LPU0_ERR_SET_REG);
+
+	/* LPU1 Registers */
+	BNAD_GET_REG(LPU1_MBOX_CTL_REG);
+	BNAD_GET_REG(LPU1_MBOX_CMD_REG);
+	BNAD_GET_REG(LPU0_MBOX_LINK_1REG);
+	BNAD_GET_REG(LPU1_MBOX_LINK_1REG);
+	BNAD_GET_REG(LPU0_MBOX_STATUS_1REG);
+	BNAD_GET_REG(LPU1_MBOX_STATUS_1REG);
+	BNAD_GET_REG(LPU1_ERR_STATUS_REG);
+	BNAD_GET_REG(LPU1_ERR_SET_REG);
+
+	/* PSS Registers */
+	BNAD_GET_REG(PSS_CTL_REG);
+	BNAD_GET_REG(PSS_ERR_STATUS_REG);
+	BNAD_GET_REG(ERR_STATUS_SET);
+	BNAD_GET_REG(PSS_RAM_ERR_STATUS_REG);
+
+	/* Catapult CPQ Registers */
+	BNAD_GET_REG(HOSTFN0_LPU0_MBOX0_CMD_STAT);
+	BNAD_GET_REG(HOSTFN0_LPU1_MBOX0_CMD_STAT);
+	BNAD_GET_REG(LPU0_HOSTFN0_MBOX0_CMD_STAT);
+	BNAD_GET_REG(LPU1_HOSTFN0_MBOX0_CMD_STAT);
+
+	BNAD_GET_REG(HOSTFN0_LPU0_MBOX1_CMD_STAT);
+	BNAD_GET_REG(HOSTFN0_LPU1_MBOX1_CMD_STAT);
+	BNAD_GET_REG(LPU0_HOSTFN0_MBOX1_CMD_STAT);
+	BNAD_GET_REG(LPU1_HOSTFN0_MBOX1_CMD_STAT);
+
+	BNAD_GET_REG(HOSTFN1_LPU0_MBOX0_CMD_STAT);
+	BNAD_GET_REG(HOSTFN1_LPU1_MBOX0_CMD_STAT);
+	BNAD_GET_REG(LPU0_HOSTFN1_MBOX0_CMD_STAT);
+	BNAD_GET_REG(LPU1_HOSTFN1_MBOX0_CMD_STAT);
+
+	BNAD_GET_REG(HOSTFN1_LPU0_MBOX1_CMD_STAT);
+	BNAD_GET_REG(HOSTFN1_LPU1_MBOX1_CMD_STAT);
+	BNAD_GET_REG(LPU0_HOSTFN1_MBOX1_CMD_STAT);
+	BNAD_GET_REG(LPU1_HOSTFN1_MBOX1_CMD_STAT);
+
+	BNAD_GET_REG(HOSTFN2_LPU0_MBOX0_CMD_STAT);
+	BNAD_GET_REG(HOSTFN2_LPU1_MBOX0_CMD_STAT);
+	BNAD_GET_REG(LPU0_HOSTFN2_MBOX0_CMD_STAT);
+	BNAD_GET_REG(LPU1_HOSTFN2_MBOX0_CMD_STAT);
+
+	BNAD_GET_REG(HOSTFN2_LPU0_MBOX1_CMD_STAT);
+	BNAD_GET_REG(HOSTFN2_LPU1_MBOX1_CMD_STAT);
+	BNAD_GET_REG(LPU0_HOSTFN2_MBOX1_CMD_STAT);
+	BNAD_GET_REG(LPU1_HOSTFN2_MBOX1_CMD_STAT);
+
+	BNAD_GET_REG(HOSTFN3_LPU0_MBOX0_CMD_STAT);
+	BNAD_GET_REG(HOSTFN3_LPU1_MBOX0_CMD_STAT);
+	BNAD_GET_REG(LPU0_HOSTFN3_MBOX0_CMD_STAT);
+	BNAD_GET_REG(LPU1_HOSTFN3_MBOX0_CMD_STAT);
+
+	BNAD_GET_REG(HOSTFN3_LPU0_MBOX1_CMD_STAT);
+	BNAD_GET_REG(HOSTFN3_LPU1_MBOX1_CMD_STAT);
+	BNAD_GET_REG(LPU0_HOSTFN3_MBOX1_CMD_STAT);
+	BNAD_GET_REG(LPU1_HOSTFN3_MBOX1_CMD_STAT);
+
+	/* Host Function Force Parity Error Registers */
+	BNAD_GET_REG(HOSTFN0_LPU_FORCE_PERR);
+	BNAD_GET_REG(HOSTFN1_LPU_FORCE_PERR);
+	BNAD_GET_REG(HOSTFN2_LPU_FORCE_PERR);
+	BNAD_GET_REG(HOSTFN3_LPU_FORCE_PERR);
+
+	/* LL Port[0|1] Halt Mask Registers */
+	BNAD_GET_REG(LL_HALT_MSK_P0);
+	BNAD_GET_REG(LL_HALT_MSK_P1);
+
+	/* LL Port[0|1] Error Mask Registers */
+	BNAD_GET_REG(LL_ERR_MSK_P0);
+	BNAD_GET_REG(LL_ERR_MSK_P1);
+
+	/* EMC FLI Registers */
+	BNAD_GET_REG(FLI_CMD_REG);
+	BNAD_GET_REG(FLI_ADDR_REG);
+	BNAD_GET_REG(FLI_CTL_REG);
+	BNAD_GET_REG(FLI_WRDATA_REG);
+	BNAD_GET_REG(FLI_RDDATA_REG);
+	BNAD_GET_REG(FLI_DEV_STATUS_REG);
+	BNAD_GET_REG(FLI_SIG_WD_REG);
+
+	BNAD_GET_REG(FLI_DEV_VENDOR_REG);
+	BNAD_GET_REG(FLI_ERR_STATUS_REG);
+
+	/* RxAdm 0 Registers */
+	BNAD_GET_REG(RAD0_CTL_REG);
+	BNAD_GET_REG(RAD0_PE_PARM_REG);
+	BNAD_GET_REG(RAD0_BCN_REG);
+	BNAD_GET_REG(RAD0_DEFAULT_REG);
+	BNAD_GET_REG(RAD0_PROMISC_REG);
+	BNAD_GET_REG(RAD0_BCNQ_REG);
+	BNAD_GET_REG(RAD0_DEFAULTQ_REG);
+
+	BNAD_GET_REG(RAD0_ERR_STS);
+	BNAD_GET_REG(RAD0_SET_ERR_STS);
+	BNAD_GET_REG(RAD0_ERR_INT_EN);
+	BNAD_GET_REG(RAD0_FIRST_ERR);
+	BNAD_GET_REG(RAD0_FORCE_ERR);
+
+	BNAD_GET_REG(RAD0_MAC_MAN_1H);
+	BNAD_GET_REG(RAD0_MAC_MAN_1L);
+	BNAD_GET_REG(RAD0_MAC_MAN_2H);
+	BNAD_GET_REG(RAD0_MAC_MAN_2L);
+	BNAD_GET_REG(RAD0_MAC_MAN_3H);
+	BNAD_GET_REG(RAD0_MAC_MAN_3L);
+	BNAD_GET_REG(RAD0_MAC_MAN_4H);
+	BNAD_GET_REG(RAD0_MAC_MAN_4L);
+
+	BNAD_GET_REG(RAD0_LAST4_IP);
+
+	/* RxAdm 1 Registers */
+	BNAD_GET_REG(RAD1_CTL_REG);
+	BNAD_GET_REG(RAD1_PE_PARM_REG);
+	BNAD_GET_REG(RAD1_BCN_REG);
+	BNAD_GET_REG(RAD1_DEFAULT_REG);
+	BNAD_GET_REG(RAD1_PROMISC_REG);
+	BNAD_GET_REG(RAD1_BCNQ_REG);
+	BNAD_GET_REG(RAD1_DEFAULTQ_REG);
+
+	BNAD_GET_REG(RAD1_ERR_STS);
+	BNAD_GET_REG(RAD1_SET_ERR_STS);
+	BNAD_GET_REG(RAD1_ERR_INT_EN);
+
+	/* TxA0 Registers */
+	BNAD_GET_REG(TXA0_CTRL_REG);
+	/* TxA0 TSO Sequence # Registers (RO) */
+	for (i = 0; i < 8; i++) {
+		BNAD_GET_REG(TXA0_TSO_TCP_SEQ_REG(i));
+		BNAD_GET_REG(TXA0_TSO_IP_INFO_REG(i));
+	}
+
+	/* TxA1 Registers */
+	BNAD_GET_REG(TXA1_CTRL_REG);
+	/* TxA1 TSO Sequence # Registers (RO) */
+	for (i = 0; i < 8; i++) {
+		BNAD_GET_REG(TXA1_TSO_TCP_SEQ_REG(i));
+		BNAD_GET_REG(TXA1_TSO_IP_INFO_REG(i));
+	}
+
+	/* RxA Registers */
+	BNAD_GET_REG(RXA0_CTL_REG);
+	BNAD_GET_REG(RXA1_CTL_REG);
+
+	/* PLB0 Registers */
+	BNAD_GET_REG(PLB0_ECM_TIMER_REG);
+	BNAD_GET_REG(PLB0_RL_CTL);
+	for (i = 0; i < 8; i++)
+		BNAD_GET_REG(PLB0_RL_MAX_BC(i));
+	BNAD_GET_REG(PLB0_RL_TU_PRIO);
+	for (i = 0; i < 8; i++)
+		BNAD_GET_REG(PLB0_RL_BYTE_CNT(i));
+	BNAD_GET_REG(PLB0_RL_MIN_REG);
+	BNAD_GET_REG(PLB0_RL_MAX_REG);
+	BNAD_GET_REG(PLB0_EMS_ADD_REG);
+
+	/* PLB1 Registers */
+	BNAD_GET_REG(PLB1_ECM_TIMER_REG);
+	BNAD_GET_REG(PLB1_RL_CTL);
+	for (i = 0; i < 8; i++)
+		BNAD_GET_REG(PLB1_RL_MAX_BC(i));
+	BNAD_GET_REG(PLB1_RL_TU_PRIO);
+	for (i = 0; i < 8; i++)
+		BNAD_GET_REG(PLB1_RL_BYTE_CNT(i));
+	BNAD_GET_REG(PLB1_RL_MIN_REG);
+	BNAD_GET_REG(PLB1_RL_MAX_REG);
+	BNAD_GET_REG(PLB1_EMS_ADD_REG);
+
+	/* HQM Control Register */
+	BNAD_GET_REG(HQM0_CTL_REG);
+	BNAD_GET_REG(HQM0_RXQ_STOP_SEM);
+	BNAD_GET_REG(HQM0_TXQ_STOP_SEM);
+	BNAD_GET_REG(HQM1_CTL_REG);
+	BNAD_GET_REG(HQM1_RXQ_STOP_SEM);
+	BNAD_GET_REG(HQM1_TXQ_STOP_SEM);
+
+	/* LUT Registers */
+	BNAD_GET_REG(LUT0_ERR_STS);
+	BNAD_GET_REG(LUT0_SET_ERR_STS);
+	BNAD_GET_REG(LUT1_ERR_STS);
+	BNAD_GET_REG(LUT1_SET_ERR_STS);
+
+	/* TRC Registers */
+	BNAD_GET_REG(TRC_CTL_REG);
+	BNAD_GET_REG(TRC_MODS_REG);
+	BNAD_GET_REG(TRC_TRGC_REG);
+	BNAD_GET_REG(TRC_CNT1_REG);
+	BNAD_GET_REG(TRC_CNT2_REG);
+	BNAD_GET_REG(TRC_NXTS_REG);
+	BNAD_GET_REG(TRC_DIRR_REG);
+	for (i = 0; i < 10; i++)
+		BNAD_GET_REG(TRC_TRGM_REG(i));
+	for (i = 0; i < 10; i++)
+		BNAD_GET_REG(TRC_NXTM_REG(i));
+	for (i = 0; i < 10; i++)
+		BNAD_GET_REG(TRC_STRM_REG(i));
+
+	spin_unlock_irq(&bnad->priv_lock);
+#undef BNAD_GET_REG
+	return num;
+}
+
+static int bnad_get_regs_len(struct net_device *netdev)
+{
+	int ret = get_regs(netdev_priv(netdev), NULL) * sizeof(u32);
+	return ret;
+}
+
+static void bnad_get_regs(struct net_device *netdev, struct ethtool_regs *regs,
+	void *buf)
+{
+	memset(buf, 0, bnad_get_regs_len(netdev));
+	get_regs(netdev_priv(netdev), buf);
+}
+
+static void bnad_get_wol(struct net_device *netdev,
+	struct ethtool_wolinfo *wolinfo)
+{
+	wolinfo->supported = 0;
+	wolinfo->wolopts = 0;
+}
+
+static int bnad_get_coalesce(struct net_device *netdev,
+	struct ethtool_coalesce *coalesce)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+
+	coalesce->rx_coalesce_usecs =
+		bnad->rx_coalescing_timeo * BNAD_COALESCING_TIMER_UNIT;
+	coalesce->rx_max_coalesced_frames = bnad->rx_interpkt_count;
+	coalesce->rx_coalesce_usecs_irq = bnad->rx_interpkt_timeo;
+	coalesce->tx_coalesce_usecs =
+		bnad->tx_coalescing_timeo * BNAD_COALESCING_TIMER_UNIT;
+	coalesce->tx_max_coalesced_frames = bnad->tx_interpkt_count;
+
+	coalesce->use_adaptive_rx_coalesce = bnad->rx_dyn_coalesce_on;
+	return 0;
+}
+
+static int bnad_set_coalesce(struct net_device *netdev,
+	struct ethtool_coalesce *coalesce)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	int i, err = 0, reset = 0;
+	u16 ib_id;
+
+	if (coalesce->rx_coalesce_usecs == 0 ||
+	    coalesce->rx_coalesce_usecs >
+	    BNAD_MAX_COALESCING_TIMEO * BNAD_COALESCING_TIMER_UNIT)
+		return -EINVAL;
+	if (coalesce->rx_max_coalesced_frames > BNAD_MAX_INTERPKT_COUNT)
+		return -EINVAL;
+	if (coalesce->rx_coalesce_usecs_irq == 0 ||
+	    coalesce->rx_coalesce_usecs_irq > BNAD_MAX_INTERPKT_TIMEO)
+		return -EINVAL;
+
+	if (coalesce->tx_coalesce_usecs == 0 ||
+	    coalesce->tx_coalesce_usecs >
+	    BNAD_MAX_COALESCING_TIMEO * BNAD_COALESCING_TIMER_UNIT)
+		return -EINVAL;
+	if (coalesce->tx_max_coalesced_frames > BNAD_MAX_INTERPKT_COUNT)
+		return -EINVAL;
+
+	bnad_conf_lock();
+	spin_lock_irq(&bnad->priv_lock);
+
+	bnad->rx_dyn_coalesce_on = coalesce->use_adaptive_rx_coalesce;
+	if (bnad->rx_coalescing_timeo == 0)
+		bnad->rx_coalescing_timeo = 1;
+	if (bnad->state == BNAD_S_OPEN && !BNAD_NOT_READY(bnad)) {
+		for (i = 0; i < bnad->cq_num; i++) {
+			ib_id = bnad->cq_table[i].cq_config.ib_id;
+			bnad->ib_table[ib_id].ib_config.coalescing_timer =
+				bnad->rx_coalescing_timeo;
+			if (!bnad->rx_dyn_coalesce_on) {
+				bnad->cq_table[i].rx_coalescing_timeo =
+					bnad->rx_coalescing_timeo;
+			}
+		}
+	}
+	if (coalesce->rx_max_coalesced_frames != bnad->rx_interpkt_count) {
+		bnad->rx_interpkt_count = coalesce->rx_max_coalesced_frames;
+		reset++;
+	}
+	if (coalesce->rx_coalesce_usecs_irq != bnad->rx_interpkt_timeo) {
+		bnad->rx_interpkt_timeo = coalesce->rx_coalesce_usecs_irq;
+		reset++;
+	}
+
+	bnad->tx_coalescing_timeo =
+		coalesce->tx_coalesce_usecs / BNAD_COALESCING_TIMER_UNIT;
+	if (bnad->tx_coalescing_timeo == 0)
+		bnad->tx_coalescing_timeo = 1;
+	if (bnad->state == BNAD_S_OPEN && !BNAD_NOT_READY(bnad)) {
+		for (i = 0; i < bnad->txq_num; i++) {
+			ib_id = bnad->txq_table[i].txq_config.ib_id;
+			bnad->ib_table[ib_id].ib_config.coalescing_timer =
+				bnad->tx_coalescing_timeo;
+		}
+	}
+	if (coalesce->tx_max_coalesced_frames != bnad->tx_interpkt_count) {
+		bnad->tx_interpkt_count = coalesce->tx_max_coalesced_frames;
+		reset++;
+	}
+
+	spin_unlock_irq(&bnad->priv_lock);
+
+	if (reset)
+		err = bnad_sw_reset_locked(netdev);
+
+	bnad_conf_unlock();
+
+	return err;
+}
+
+static void bnad_get_ringparam(struct net_device *netdev,
+	struct ethtool_ringparam *ringparam)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+
+	ringparam->rx_max_pending = BNAD_MAX_Q_DEPTH / bnad_rxqs_per_cq;
+	ringparam->rx_mini_max_pending = 0;
+	ringparam->rx_jumbo_max_pending = 0;
+	ringparam->tx_max_pending = BNAD_MAX_Q_DEPTH;
+
+	ringparam->rx_pending = bnad->rxq_depth;
+	ringparam->rx_mini_max_pending = 0;
+	ringparam->rx_jumbo_max_pending = 0;
+	ringparam->tx_pending = bnad->txq_depth;
+}
+
+static int bnad_set_ringparam(struct net_device *netdev,
+	struct ethtool_ringparam *ringparam)
+{
+	int err = 0;
+	struct bnad *bnad = netdev_priv(netdev);
+
+	bnad_conf_lock();
+	if (ringparam->rx_pending == bnad->rxq_depth &&
+	    ringparam->tx_pending == bnad->txq_depth) {
+		bnad_conf_unlock();
+		return 0;
+	}
+
+	if (ringparam->rx_pending < BNAD_MIN_Q_DEPTH ||
+	    ringparam->rx_pending > BNAD_MAX_Q_DEPTH / bnad_rxqs_per_cq ||
+	    !BNA_POWER_OF_2(ringparam->rx_pending)) {
+		bnad_conf_unlock();
+		return -EINVAL;
+	}
+	if (ringparam->tx_pending < BNAD_MIN_Q_DEPTH ||
+	    ringparam->tx_pending > BNAD_MAX_Q_DEPTH ||
+	    !BNA_POWER_OF_2(ringparam->tx_pending)) {
+		bnad_conf_unlock();
+		return -EINVAL;
+	}
+
+	if (ringparam->rx_pending != bnad->rxq_depth) {
+		bnad->rxq_depth = ringparam->rx_pending;
+		bnad->config |= BNAD_CF_RXQ_DEPTH;
+	}
+	if (ringparam->tx_pending != bnad->txq_depth) {
+		bnad->txq_depth = ringparam->tx_pending;
+		bnad->config |= BNAD_CF_TXQ_DEPTH;
+	}
+
+	err = bnad_sw_reset_locked(netdev);
+
+	bnad_conf_unlock();
+	return err;
+}
+
+static void bnad_get_pauseparam(struct net_device *netdev,
+	struct ethtool_pauseparam *pauseparam)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+
+	pauseparam->autoneg = 0;
+	pauseparam->rx_pause = bnad->pause_config.rx_pause;
+	pauseparam->tx_pause = bnad->pause_config.tx_pause;
+}
+
+static int bnad_set_pauseparam(struct net_device *netdev,
+	struct ethtool_pauseparam *pauseparam)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+
+	if (pauseparam->autoneg == AUTONEG_ENABLE)
+		return -EINVAL;
+
+	bnad_conf_lock();
+	if (pauseparam->rx_pause != bnad->pause_config.rx_pause ||
+	    pauseparam->tx_pause != bnad->pause_config.tx_pause) {
+		bnad->pause_config.rx_pause = pauseparam->rx_pause;
+		bnad->pause_config.tx_pause = pauseparam->tx_pause;
+		spin_lock_irq(&bnad->priv_lock);
+		bna_set_pause_config(bnad->priv, &bnad->pause_config, bnad);
+		spin_unlock_irq(&bnad->priv_lock);
+	}
+	bnad_conf_unlock();
+	return 0;
+}
+
+static u32 bnad_get_rx_csum(struct net_device *netdev)
+{
+	u32 rx_csum;
+	struct bnad *bnad = netdev_priv(netdev);
+
+	rx_csum = bnad->rx_csum;
+	return rx_csum;
+}
+
+static int bnad_set_rx_csum(struct net_device *netdev, u32 rx_csum)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+
+	bnad_conf_lock();
+	bnad->rx_csum = rx_csum;
+	bnad_conf_unlock();
+	return 0;
+}
+
+static int bnad_set_tx_csum(struct net_device *netdev, u32 tx_csum)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+
+	bnad_conf_lock();
+	if (tx_csum) {
+		netdev->features |= NETIF_F_IP_CSUM;
+		netdev->features |= NETIF_F_IPV6_CSUM;
+	} else {
+		netdev->features &= ~NETIF_F_IP_CSUM;
+		netdev->features &= ~NETIF_F_IPV6_CSUM;
+	}
+	bnad_conf_unlock();
+	return 0;
+}
+
+static int bnad_set_tso(struct net_device *netdev, u32 tso)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+
+	bnad_conf_lock();
+	if (tso) {
+		netdev->features |= NETIF_F_TSO;
+		netdev->features |= NETIF_F_TSO6;
+	} else {
+		netdev->features &= ~NETIF_F_TSO;
+		netdev->features &= ~NETIF_F_TSO6;
+	}
+	bnad_conf_unlock();
+	return 0;
+}
+
+static void bnad_get_strings(struct net_device *netdev, u32 stringset,
+	u8 *string)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	int i;
+	bnad_conf_lock();
+
+	switch (stringset) {
+	case ETH_SS_STATS:
+		for (i = 0; i < BNAD_ETHTOOL_STATS_NUM; i++) {
+			BUG_ON(!(strlen(bnad_net_stats_strings[i])) <
+				   ETH_GSTRING_LEN);
+			memcpy(string, bnad_net_stats_strings[i],
+			       ETH_GSTRING_LEN);
+			string += ETH_GSTRING_LEN;
+		}
+
+		i = 0;
+		sprintf(string, "rxf%d_ucast_octets", i);
+		string += ETH_GSTRING_LEN;
+		sprintf(string, "rxf%d_ucast", i);
+		string += ETH_GSTRING_LEN;
+		sprintf(string, "rxf%d_ucast_vlan", i);
+		string += ETH_GSTRING_LEN;
+		sprintf(string, "rxf%d_mcast_octets", i);
+		string += ETH_GSTRING_LEN;
+		sprintf(string, "rxf%d_mcast", i);
+		string += ETH_GSTRING_LEN;
+		sprintf(string, "rxf%d_mcast_vlan", i);
+		string += ETH_GSTRING_LEN;
+		sprintf(string, "rxf%d_bcast_octets", i);
+		string += ETH_GSTRING_LEN;
+		sprintf(string, "rxf%d_bcast", i);
+		string += ETH_GSTRING_LEN;
+		sprintf(string, "rxf%d_bcast_vlan", i);
+		string += ETH_GSTRING_LEN;
+		sprintf(string, "rxf%d_frame_drops", i);
+		string += ETH_GSTRING_LEN;
+
+	sprintf(string, "netif_queue_stopped");
+	string += ETH_GSTRING_LEN;
+	sprintf(string, "bna_state");
+	string += ETH_GSTRING_LEN;
+
+	for (i = 0; i < bnad->cq_num; i++) {
+		sprintf(string, "cq%d_producer_index", i);
+		string += ETH_GSTRING_LEN;
+		sprintf(string, "cq%d_consumer_index", i);
+		string += ETH_GSTRING_LEN;
+	}
+
+	for (i = 0; i < bnad->rxq_num; i++) {
+		sprintf(string, "rxq%d_packets", i);
+		string += ETH_GSTRING_LEN;
+		sprintf(string, "rxq%d_bytes", i);
+		string += ETH_GSTRING_LEN;
+		sprintf(string, "rxq%d_packets_with_error", i);
+		string += ETH_GSTRING_LEN;
+		sprintf(string, "rxq%d_allocbuf_failed", i);
+		string += ETH_GSTRING_LEN;
+
+		sprintf(string, "rxq%d_producer_index", i);
+		string += ETH_GSTRING_LEN;
+		sprintf(string, "rxq%d_consumer_index", i);
+		string += ETH_GSTRING_LEN;
+	}
+
+	for (i = 0; i < bnad->txq_num; i++) {
+		sprintf(string, "txq%d_packets", i);
+		string += ETH_GSTRING_LEN;
+		sprintf(string, "txq%d_bytes", i);
+		string += ETH_GSTRING_LEN;
+
+		sprintf(string, "txq%d_producer_index", i);
+		string += ETH_GSTRING_LEN;
+		sprintf(string, "txq%d_consumer_index", i);
+		string += ETH_GSTRING_LEN;
+		sprintf(string, "txq%d_hw_consumer_index", i);
+		string += ETH_GSTRING_LEN;
+	}
+	break;
+
+	default:
+	break;
+}
+
+bnad_conf_unlock();
+}
+
+static void bnad_get_ethtool_stats(struct net_device *netdev,
+	struct ethtool_stats *stats, u64 *buf)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	int i, bi;
+	unsigned long *net_stats;
+	u64 *stats64;
+
+	bnad_conf_lock();
+	if (bnad_get_stats_count_locked(netdev) != stats->n_stats)
+		goto mismatch;
+
+	bi = 0;
+	memset(buf, 0, stats->n_stats * sizeof(u64));
+	bnad_get_stats(netdev);
+
+	net_stats = (unsigned long *)&bnad->net_stats;
+	for (i = 0; i < sizeof(struct net_device_stats) / sizeof(unsigned long);
+	     i++)
+		buf[bi++] = net_stats[i];
+
+	stats64 = (u64 *)&bnad->stats;
+	for (i = 0; i < sizeof(struct bnad_drv_stats) / sizeof(u64); i++)
+		buf[bi++] = stats64[i];
+
+	stats64 = (u64 *) bnad->hw_stats;
+	for (i = 0;
+	     i < offsetof(struct bna_stats, rxf_stats[0]) / sizeof(u64);
+	     i++)
+		buf[bi++] = stats64[i];
+
+	stats64 = (u64 *)&bnad->hw_stats->txf_stats[0];
+	for (i = 0; i < sizeof(struct bna_stats_txf) / sizeof(u64); i++)
+		buf[bi++] = stats64[i];
+
+	stats64 = (u64 *)&bnad->hw_stats->rxf_stats[0];
+	for (i = 0; i < sizeof(struct bna_stats_rxf) / sizeof(u64); i++)
+		buf[bi++] = stats64[i];
+
+	buf[bi++] = netif_queue_stopped(netdev);
+	buf[bi++] = bnad->state;
+
+	if (bnad->cq_table && bnad->rxq_table && bnad->txq_table) {
+		for (i = 0; i < bnad->cq_num; i++) {
+			buf[bi++] = bnad->cq_table[i].cq.q.producer_index;
+			buf[bi++] = bnad->cq_table[i].cq.q.consumer_index;
+		}
+
+		for (i = 0; i < bnad->rxq_num; i++) {
+			buf[bi++] = bnad->rxq_table[i].rx_packets;
+			buf[bi++] = bnad->rxq_table[i].rx_bytes;
+			buf[bi++] = bnad->rxq_table[i].rx_packets_with_error;
+			buf[bi++] = bnad->rxq_table[i].rxbuf_alloc_failed;
+
+			buf[bi++] = bnad->rxq_table[i].rxq.q.producer_index;
+			buf[bi++] = bnad->rxq_table[i].rxq.q.consumer_index;
+		}
+		for (i = 0; i < bnad->txq_num; i++) {
+			buf[bi++] = bnad->txq_table[i].tx_packets;
+			buf[bi++] = bnad->txq_table[i].tx_bytes;
+
+			buf[bi++] = bnad->txq_table[i].txq.q.producer_index;
+			buf[bi++] = bnad->txq_table[i].txq.q.consumer_index;
+			buf[bi++] = *(bnad->txq_table[i].hw_consumer_index);
+		}
+	}
+
+mismatch:
+	bnad_conf_unlock();
+}
+
+static int bnad_get_stats_count_locked(struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	int count;
+
+	count = BNAD_ETHTOOL_STATS_NUM + 10 + bnad->rxq_num * 4
+		+ bnad->txq_num * 2;
+
+	/* netif_queue_stopped, state */
+	count += 2;
+
+	/* CQ producer_index, consumer_index */
+	count += bnad->cq_num * 2;
+
+	/* RxQ producer_index, consumer_index */
+	count += bnad->rxq_num * 2;
+
+	/* TxQ producer_index, consumer_index, hw_consumer_index */
+	count += bnad->txq_num * 3;
+	return count;
+}
+
+static int
+bnad_get_sset_count(struct net_device *netdev, int stringset)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	int count;
+
+	switch (stringset) {
+	case ETH_SS_STATS:
+		bnad_conf_lock();
+		count = bnad_get_stats_count_locked(netdev);
+		bnad_conf_unlock();
+		return count;
+	default:
+		return -EINVAL;
+	}
+}
+
+static struct ethtool_ops bnad_ethtool_ops = {
+	.get_settings = bnad_get_settings,
+	.set_settings = bnad_set_settings,
+	.get_drvinfo = bnad_get_drvinfo,
+	.get_regs_len = bnad_get_regs_len,
+	.get_regs = bnad_get_regs,
+	.get_wol = bnad_get_wol,
+	.get_msglevel = bnad_get_msglevel,
+	.set_msglevel = bnad_set_msglevel,
+	.get_link = ethtool_op_get_link,
+	.get_coalesce = bnad_get_coalesce,
+	.set_coalesce = bnad_set_coalesce,
+	.get_ringparam = bnad_get_ringparam,
+	.set_ringparam = bnad_set_ringparam,
+	.get_pauseparam = bnad_get_pauseparam,
+	.set_pauseparam = bnad_set_pauseparam,
+	.get_rx_csum = bnad_get_rx_csum,
+	.set_rx_csum = bnad_set_rx_csum,
+	.get_tx_csum = ethtool_op_get_tx_csum,
+	.set_tx_csum = bnad_set_tx_csum,
+	.get_sg = ethtool_op_get_sg,
+	.set_sg = ethtool_op_set_sg,
+	.get_tso = ethtool_op_get_tso,
+	.set_tso = bnad_set_tso,
+	.get_strings = bnad_get_strings,
+	.get_ethtool_stats = bnad_get_ethtool_stats,
+	.get_sset_count = bnad_get_sset_count
+};
+
+void bnad_set_ethtool_ops(struct net_device *netdev)
+{
+	SET_ETHTOOL_OPS(netdev, &bnad_ethtool_ops);
+}
diff -ruP net-next-2.6-orig/drivers/net/bna/bna_fn.c net-next-2.6-mod/drivers/net/bna/bna_fn.c
--- net-next-2.6-orig/drivers/net/bna/bna_fn.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6-mod/drivers/net/bna/bna_fn.c	2009-12-18 16:53:40.000000000 -0800
@@ -0,0 +1,1862 @@ 
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 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 for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ *    @file bna_fn.c BNA Rx and Tx Function Management
+ */
+
+#include "cna.h"
+#include "bna.h"
+#include "bna_hwreg.h"
+#include "bna_priv.h"
+#include "bfi/bfi_ll.h"
+#include "bfi/bfi_cee.h"
+
+/*
+ * 12 bit Max VLAN Id mask used to
+ * wrap overflowing VLANs wraps around the
+ * max value of 4095
+ */
+#define BNA_MAX_VLAN_ID_MASK	0x00000fff
+
+const struct bna_chip_regs_offset reg_offset[] =
+	{ {HOST_PAGE_NUM_FN0, HOSTFN0_INT_STATUS,
+	   HOSTFN0_INT_MASK, HOST_MSIX_ERR_INDEX_FN0},
+{HOST_PAGE_NUM_FN1, HOSTFN1_INT_STATUS,
+	HOSTFN1_INT_MASK, HOST_MSIX_ERR_INDEX_FN1},
+{HOST_PAGE_NUM_FN2, HOSTFN2_INT_STATUS,
+	HOSTFN2_INT_MASK, HOST_MSIX_ERR_INDEX_FN2},
+{HOST_PAGE_NUM_FN3, HOSTFN3_INT_STATUS,
+	HOSTFN3_INT_MASK, HOST_MSIX_ERR_INDEX_FN3},
+};
+const struct mac bna_bcast_addr = { {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} };
+const struct mac bna_zero_addr = { {0x0, 0x0, 0x0, 0x0, 0x0, 0x0} };
+
+/**
+ * bna_init()
+ *
+ *   Called by the driver during initialization. The driver is
+ *   expected to allocate struct bna_dev structure for the BNA layer.
+ *
+ * @return void
+ */
+void bna_init(struct bna_dev *dev, void *bar0, void *stats,
+	 struct bna_dma_addr stats_dma, struct bfa_trc_mod *trcmod,
+	 struct bfa_log_mod *logmod)
+{
+	u32 pcifn;
+
+	memset(dev, 0, sizeof(struct bna_dev));
+
+	dev->trcmod = trcmod;
+	dev->logmod = logmod;
+
+	dev->bar0 = (u8 *) bar0;
+	dev->hw_stats = (struct bfi_ll_stats *)stats;
+	dev->hw_stats_dma.msb = stats_dma.msb;
+	dev->hw_stats_dma.lsb = stats_dma.lsb;
+
+	dev->rxf_promiscuous_id = BNA_RXF_ID_NONE;
+	dev->rxf_default_id = BNA_RXF_ID_NONE;
+
+	pcifn = readl(dev->bar0 + FNC_ID_REG);
+	pcifn = readl(dev->bar0 + FNC_ID_REG);
+	BUG_ON(!(pcifn <= 3));
+
+	dev->regs.page_addr = dev->bar0 + reg_offset[pcifn].page_addr;
+	dev->regs.fn_int_status = dev->bar0 + reg_offset[pcifn].fn_int_status;
+	dev->regs.fn_int_mask = dev->bar0 + reg_offset[pcifn].fn_int_mask;
+
+	if (pcifn < 3)
+		dev->port = 0;
+	else
+		dev->port = 1;
+
+	dev->pci_fn = pcifn;
+
+	dev->ioc_disable_pending = 0;
+}
+
+/**
+ *  bna_rit_config_set()
+ *
+ *  Loads RIT entries "rit" into RIT starting from RIT index "rit_id".
+ *  Care must be taken not to overlap regions within the RIT.
+ *
+ * @param[in]  dev          - pointer to BNA device structure
+ * @param[in]  rit_offset   - offset into the RIT
+ * @param[in]  rit          - RIT entry
+ * @param[in]  rit_size     - size of RIT entry
+ *
+ * @return void
+ */
+void bna_rit_config_set(struct bna_dev *dev, unsigned int rit_offset,
+	const struct bna_rit_entry rit[], unsigned int rit_size)
+{
+	int i;
+
+	struct bna_rit_mem *rit_mem;
+
+	BUG_ON(!(BNA_POWER_OF_2(rit_size)));
+	BUG_ON(!((rit_offset + rit_size) < BNA_RIT_SIZE));
+
+	rit_mem = (struct bna_rit_mem *)
+		BNA_GET_MEM_BASE_ADDR(dev->bar0, FUNCTION_TO_RXQ_TRANSLATE);
+
+	dev->rit_size[rit_offset] = rit_size;
+
+	writel(BNA_GET_PAGE_NUM(RXA0_MEM_BLK_BASE_PG_NUM + dev->port,
+				FUNCTION_TO_RXQ_TRANSLATE),
+				dev->regs.page_addr);
+
+	for (i = 0; i < rit_size; i++) {
+		writel(rit[i].large_rxq_id << 6 | rit[i].small_rxq_id,
+			&rit_mem[i + rit_offset]);
+	}
+}
+
+/**
+ * bna_rxf_config_set()
+ *
+ *   For RxF "rxf_id", it configures RxF based on "cfg_ptr", and indicates
+ *   to the statistics collector to collect statistics for this Rx-Function.
+ *
+ * @param[in]  dev     - pointer to BNA device structure
+ * @param[in]  rxf_id  - rx-function ID.
+ * @param[in]  cfg_ptr - pointer to rx-function configuration.
+ *
+ * @return BNA_OK   - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status bna_rxf_config_set(struct bna_dev *dev,
+	unsigned int rxf_id, const struct bna_rxf_config *cfg_ptr)
+{
+	u32 i;
+
+	struct bna_rss_mem *rss_mem;
+	struct bna_rx_fndb_ram *rx_fndb_ram;
+
+	BUG_ON(!(rxf_id < BNA_RXF_ID_MAX));
+
+	rss_mem = (struct bna_rss_mem *)
+		BNA_GET_MEM_BASE_ADDR(dev->bar0, RSS_TABLE_BASE_OFFSET);
+	rx_fndb_ram = (struct bna_rx_fndb_ram *)
+		BNA_GET_MEM_BASE_ADDR(dev->bar0, RX_FNDB_RAM_BASE_OFFSET);
+
+	if (((cfg_ptr->flags & BNA_RXF_CF_SM_LG_RXQ)) &&
+	    (cfg_ptr->hds.type == 1)) {
+		/* HDS and small-large RxQs are mutually exclusive */
+		return BNA_FAIL;
+	}
+
+	if (cfg_ptr->flags & BNA_RXF_CF_RSS_ENABLE) {
+		BUG_ON((cfg_ptr->rss.hash_mask !=
+			   dev->rit_size[cfg_ptr->rit_offset] - 1));
+
+		/* configure RSS Table */
+		writel(BNA_GET_PAGE_NUM(RAD0_MEM_BLK_BASE_PG_NUM +
+						dev->port,
+						RSS_TABLE_BASE_OFFSET),
+						dev->regs.page_addr);
+
+		/* temporarily disable RSS, while hash value is being written */
+		writel(0, &rss_mem[0].type_n_hash);
+
+		for (i = 0; i < BNA_RSS_HASH_KEY_LEN; i++) {
+			writel(htonl(cfg_ptr->rss.toeplitz_hash_key[i]),
+				&rss_mem[0].
+				hash_key[(BNA_RSS_HASH_KEY_LEN - 1) - i]);
+		}
+
+		writel(cfg_ptr->rss.type | cfg_ptr->rss.hash_mask,
+				&rss_mem[0].type_n_hash);
+
+	}
+	/* configure RxF based on "cfg_ptr" */
+	writel(BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+			(dev->port * 2),
+			RX_FNDB_RAM_BASE_OFFSET),
+			dev->regs.page_addr);
+
+	/* we always use RSS table 0 */
+	writel(cfg_ptr->flags & BNA_RXF_CF_RSS_ENABLE,
+			&rx_fndb_ram[rxf_id].rss_prop);
+
+	/* small large buffer enable/disable */
+	writel((cfg_ptr->flags & BNA_RXF_CF_SM_LG_RXQ) | 0x80,
+			&rx_fndb_ram[rxf_id].size_routing_props);
+
+	/* RIT offset, HDS forced offset, multicast RxQ Id */
+	writel((cfg_ptr->rit_offset << 16) | (cfg_ptr->hds.
+		       forced_offset << 8) |
+		       (cfg_ptr->hds.type & BNA_HDS_FORCED) | cfg_ptr->
+		       mcast_rxq_id, &rx_fndb_ram[rxf_id].rit_hds_mcastq);
+
+	/*
+	 * Default vlan tag, default function enable, strip vlan bytes,
+	 * HDS type, header size
+	 */
+	writel((cfg_ptr->default_vlan << 16) |
+			(cfg_ptr->flags &
+			(BNA_RXF_CF_DEFAULT_VLAN |
+			BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE |
+			BNA_RXF_CF_VLAN_STRIP)) |
+			(cfg_ptr->hds.type & ~BNA_HDS_FORCED) | cfg_ptr->hds.
+			header_size, &rx_fndb_ram[rxf_id].control_flags);
+
+	/* turn on statistics collection for this RxF */
+	dev->rxf_active |= ((u64) 1 << rxf_id);
+	return BNA_OK;
+}
+
+/**
+ * bna_rxf_config_clear()
+ *
+ *   For RxF "rxf_id", it clear its configuration and indicates to the
+ *   statistics collector to stop collecting statistics for this
+ *   Rx-Function.
+ *
+ * @param[in]  dev     - pointer to BNA device structure
+ * @param[in]  rxf_id  - rx-function ID.
+ *
+ * @return void
+ */
+void
+bna_rxf_config_clear(struct bna_dev *dev, unsigned int rxf_id)
+{
+	struct bna_rx_fndb_ram *rx_fndb_ram;
+
+	BUG_ON(!(rxf_id < BNA_RXF_ID_MAX));
+
+	rx_fndb_ram = (struct bna_rx_fndb_ram *)
+		BNA_GET_MEM_BASE_ADDR(dev->bar0, RX_FNDB_RAM_BASE_OFFSET);
+
+	/* clear configuration of RxF base */
+	writel(BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+				       (dev->port * 2),
+				       RX_FNDB_RAM_BASE_OFFSET),
+					dev->regs.page_addr);
+
+	/* we always use RSS table 0 */
+	writel(0, &rx_fndb_ram[rxf_id].rss_prop);
+
+	/* small large buffer enable/disable */
+	writel(0x80, &rx_fndb_ram[rxf_id].size_routing_props);
+
+	/* RIT offset, HDS forced offset, multicast RxQ Id */
+	writel(0, &rx_fndb_ram[rxf_id].rit_hds_mcastq);
+
+	/*
+	 * default vlan tag, default function enable, strip vlan bytes,
+	 * HDS type, header size
+	 */
+	writel(0, &rx_fndb_ram[rxf_id].control_flags);
+
+	/* turn off statistics collection for this RxF */
+	dev->rxf_active &= ~((u64) 1 << rxf_id);
+}
+
+/**
+ * bna_rxf_disable()
+ *
+ *  Disables the Rx Function without clearing the configuration
+ *  Also disables collection of statistics.
+ *
+ * @param[in] dev   	- Pointer to BNA device handle
+ * @param[in] rxf_id    - Id of the Rx Function to be disabled
+ *
+ * @return    BNA_OK if mbox command succeeded, else BNA_FAIL
+ */
+enum bna_status
+bna_rxf_disable(struct bna_dev *dev, unsigned int rxf_id)
+{
+	struct bfi_ll_rxf_multi_req ll_req;
+	u64 bit_mask = 1 << rxf_id;
+	enum bna_status status;
+
+	bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_RX_REQ, 0);
+	ll_req.rxf_id_mask[0] = htonl(lower_32_bits(bit_mask));
+	ll_req.rxf_id_mask[1] = htonl(upper_32_bits(bit_mask));
+	ll_req.enable = 0;
+
+	status = bna_mbox_send(dev, &ll_req, sizeof(ll_req), dev->cbarg);
+	if (!status)
+		dev->rxf_active &= ~bit_mask;
+
+	return status;
+}
+
+/**
+ * bna_rxf_enable()
+ *
+ *  Enables the Rx Function
+ *
+ * @param[in] dev   	- Pointer to BNA device handle
+ * @param[in] rxf_id    - Id of the Rx Function to be disabled
+ *
+ * @return    BNA_OK if mbox command succeeded, else BNA_FAIL
+ */
+enum bna_status
+bna_rxf_enable(struct bna_dev *dev, unsigned int rxf_id)
+{
+	struct bfi_ll_rxf_multi_req ll_req;
+	u64 bit_mask = 1 << rxf_id;
+	enum bna_status status;
+
+	bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_RX_REQ, 0);
+	ll_req.rxf_id_mask[0] = htonl(lower_32_bits(bit_mask));
+	ll_req.rxf_id_mask[1] = htonl(upper_32_bits(bit_mask));
+	ll_req.enable = 1;
+
+	status = bna_mbox_send(dev, &ll_req, sizeof(ll_req), dev->cbarg);
+	if (!status)
+		dev->rxf_active |= bit_mask;
+
+	return status;
+}
+
+enum bna_status bna_multi_rxf_active(struct bna_dev *dev,
+	u64 rxf_id_mask, u8 enable)
+{
+	struct bfi_ll_rxf_multi_req ll_req;
+	enum bna_status status;
+
+	bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_RX_REQ, 0);
+	ll_req.rxf_id_mask[0] = htonl(lower_32_bits(rxf_id_mask));
+	ll_req.rxf_id_mask[1] = htonl(upper_32_bits(rxf_id_mask));
+	ll_req.enable = enable;
+
+	status = bna_mbox_send(dev, &ll_req, sizeof(ll_req), dev->cbarg);
+	if (!status) {
+		if (enable)
+			dev->rxf_active |= rxf_id_mask;
+		else
+			dev->rxf_active &= ~rxf_id_mask;
+
+	}
+	return status;
+}
+
+/**
+ * bna_rxf_ucast_mac_get()
+ *
+ *  For RxF "rxf_id", it overwrites the burnt-in unicast MAC with
+ *  the one specified by "mac_ptr".
+ *
+ * @param[in]  dev     - pointer to BNA device structure
+ * @param[in]  rxf_id  - rx-function ID
+ * @param[in]  entry   - offset into UCAM to read
+ * @param[in]  mac_addr_ptr - pointer to mac adddress to set
+ *
+ * @return 	void
+ */
+void bna_rxf_ucast_mac_get(struct bna_dev *dev, unsigned int *rxf_id,
+	unsigned int entry, const struct mac *mac_addr_ptr)
+{
+	u32 mac_47_32, mac_31_0;
+	u8 *mac_ptr = (u8 *) mac_addr_ptr;
+	struct bna_cam *ucam;
+	struct bna_ucast_mem *ucam_ram;
+
+	ucam = (struct bna_cam *)
+		BNA_GET_MEM_BASE_ADDR(dev->bar0, UCAST_CAM_BASE_OFFSET);
+	ucam_ram = (struct bna_ucast_mem *)
+		BNA_GET_MEM_BASE_ADDR(dev->bar0, UCAST_RAM_BASE_OFFSET);
+
+	writel(BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+				       (dev->port * 2), UCAST_RAM_BASE_OFFSET),
+				       dev->regs.page_addr);
+
+	/* turn on the bit corresponding to the given RxF */
+	*rxf_id = (readl(&ucam_ram[entry]) & 0x3f);
+
+	writel(BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+				       (dev->port * 2), UCAST_CAM_BASE_OFFSET),
+				       dev->regs.page_addr);
+
+	/* add unicast MAC */
+	mac_47_32 = (readl(&ucam[entry].cam_mac_addr_47_32) & 0xffff);
+	mac_31_0 = readl(&ucam[entry].cam_mac_addr_31_0);
+
+	mac_ptr[0] = mac_47_32 >> 8;
+	mac_ptr[1] = mac_47_32 & 0xff;
+
+	mac_ptr[2] = mac_31_0 >> 24;
+	mac_ptr[3] = (mac_31_0 >> 16) & 0xff;
+	mac_ptr[4] = (mac_31_0 >> 8) & 0xff;
+	mac_ptr[5] = mac_31_0 & 0xff;
+}
+
+static enum bna_status bna_rxf_mac_mbox_cmd(struct bna_dev *dev,
+	unsigned int rxf_id, u8 cmd, const struct mac *mac_addr)
+{
+	struct bfi_ll_mac_addr_req req;
+
+	bfi_h2i_set(req.mh, BFI_MC_LL, cmd, 0);
+
+	req.rxf_id = rxf_id;
+	req.mac_addr = *mac_addr;
+
+	/* send command to firmware */
+	return bna_mbox_send(dev, &req, sizeof(req), dev->cbarg);
+}
+
+/**
+ * bna_rxf_ucast_mac_set()
+ *
+ *  For RxF "rxf_id", it overwrites the burnt-in unicast MAC with
+ *  the one specified by "mac_ptr".
+ *
+ * @param[in]  dev     - pointer to BNA device structure
+ * @param[in]  rxf_id  - rx-function ID.
+ * @param[in]  mac_addr_ptr - pointer to mac adddress to set
+ *
+ * @return BNA_OK   - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status bna_rxf_ucast_mac_set(struct bna_dev *dev,
+	unsigned int rxf_id, const struct mac *mac_addr_ptr)
+{
+
+	BUG_ON(!(rxf_id < BNA_RXF_ID_MAX));
+
+	/* we are supposed to set MAC adresses for default RxF only */
+	if (dev->rxf_default_id == BNA_RXF_ID_NONE) {
+		if (rxf_id != BNA_DEFAULT_RXF_ID)
+			return BNA_FAIL;
+	} else {
+		if (rxf_id != dev->rxf_default_id)
+			return BNA_FAIL;
+
+	}
+
+	return bna_rxf_mac_mbox_cmd(dev, rxf_id, BFI_LL_H2I_MAC_UCAST_SET_REQ,
+				    mac_addr_ptr);
+}
+
+/**
+ * bna_rxf_ucast_mac_add()
+ *
+ *  For RxF "rxf_id", it adds the unicast MAC specified by "mac_ptr".
+ *
+ * @param[in]  dev     - pointer to BNA device structure
+ * @param[in]  rxf_id  - rx-function ID.
+ * @param[in]  mac_addr_ptr - pointer to mac adddress to add
+ *
+ * @return BNA_OK   - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status bna_rxf_ucast_mac_add(struct bna_dev *dev,
+	unsigned int rxf_id, const struct mac *mac_addr_ptr)
+{
+
+	BUG_ON(!(rxf_id < BNA_RXF_ID_MAX));
+	/* we are not supposed to add MAC adresses to default RxF */
+	if (rxf_id == dev->rxf_default_id)
+		return BNA_FAIL;
+
+
+	return bna_rxf_mac_mbox_cmd(dev, rxf_id, BFI_LL_H2I_MAC_UCAST_ADD_REQ,
+				    mac_addr_ptr);
+}
+
+/**
+ * bna_rxf_ucast_mac_del()
+ *
+ *  For RxF "rxf_id", it deletes the unicast MAC specified by "mac_ptr".
+ *
+ * @param[in]  dev     - pointer to BNA device structure
+ * @param[in]  rxf_id  - rx-function ID.
+ * @param[in]  mac_addr_ptr - pointer to mac adddress to add
+ *
+ * @return BNA_OK   - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status bna_rxf_ucast_mac_del(struct bna_dev *dev,
+	unsigned int rxf_id, const struct mac *mac_addr_ptr)
+{
+
+	BUG_ON(!(rxf_id < BNA_RXF_ID_MAX));
+
+	/* we are not supposed to delete MAC adresses from default RxF */
+	if (rxf_id == dev->rxf_default_id)
+		return BNA_FAIL;
+
+
+	return bna_rxf_mac_mbox_cmd(dev, rxf_id, BFI_LL_H2I_MAC_UCAST_DEL_REQ,
+				    mac_addr_ptr);
+}
+
+/**
+ * bna_rxf_mcast_mac_add()
+ *
+ *  For RxF "rxf_id", it adds the multicast MAC specified by
+ *  "mac_ptr".
+ *
+ * @param[in]  dev     - pointer to BNA device structure
+ * @param[in]  rxf_id  - rx-function ID.
+ * @param[in]  mac_addr_ptr - pointer to mac adddress to add
+ *
+ * @return BNA_OK   - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status bna_rxf_mcast_mac_add(struct bna_dev *dev,
+	unsigned int rxf_id, const struct mac *mac_addr_ptr)
+{
+	u32 i;
+
+	BUG_ON(!(rxf_id < BNA_RXF_ID_MAX));
+
+	for (i = 0; i < BNA_MCAST_TABLE_SIZE; i++) {
+		if (BNA_MAC_IS_EQUAL(&dev->mcast_addr[i], mac_addr_ptr))
+			break;
+	}
+
+	if (i == BNA_MCAST_TABLE_SIZE) {
+		/*
+		 * no existing entry found we need to find the
+		 * first unused entry
+		 */
+		for (i = 0; i < BNA_MCAST_TABLE_SIZE; i++) {
+			/* unused entry found, stop and use it */
+			if (BNA_MAC_IS_EQUAL
+			    (&dev->mcast_addr[i], &bna_zero_addr))
+				break;
+		}
+	}
+
+	if (i == BNA_MCAST_TABLE_SIZE) {
+		/* no entry available, table full */
+		return BNA_FAIL;
+	}
+
+	dev->mcast_addr[i] = *mac_addr_ptr;
+
+	return bna_rxf_mac_mbox_cmd(dev, rxf_id, BFI_LL_H2I_MAC_MCAST_ADD_REQ,
+				    mac_addr_ptr);
+}
+
+/**
+ * bna_rxf_mcast_mac_del()
+ *
+ *  For RxF "rxf_id", it deletes the multicast MAC specified by
+ *  "mac_ptr".
+ *
+ * @param[in]  dev     - pointer to BNA device structure
+ * @param[in]  rxf_id  - rx-function ID.
+ * @param[in]  mac_addr_ptr - pointer to mac adddress to add
+ *
+ * @return BNA_OK   - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status bna_rxf_mcast_mac_del(struct bna_dev *dev,
+	unsigned int rxf_id, const struct mac *mac_addr_ptr)
+{
+	u32 i;
+
+	BUG_ON(!(rxf_id < BNA_RXF_ID_MAX));
+
+	for (i = 0; i < BNA_MCAST_TABLE_SIZE; i++) {
+		if (BNA_MAC_IS_EQUAL(&dev->mcast_addr[i], mac_addr_ptr))
+			break;
+	}
+
+	if (i == BNA_MCAST_TABLE_SIZE) {
+		/* no existing entry found */
+		return BNA_FAIL;
+	}
+	dev->mcast_addr[i] = bna_zero_addr;
+
+	return bna_rxf_mac_mbox_cmd(dev, rxf_id, BFI_LL_H2I_MAC_MCAST_DEL_REQ,
+				    mac_addr_ptr);
+}
+
+/**
+ * bna_rxf_mcast_mac_set_list()
+ *
+ *  For RxF "rxf_id", it sets the multicast MAC addresses
+ *  specified by "mac_addr_ptr". The function first deletes the MAC addresses in
+ *  the existing list that is not found in the new list. It then adds the new
+ *  addresses that are in the new list but not in the old list. It then replaces
+ *  the old list with the new list in the bna_dev structure.
+ *
+ * @param[in]  dev     - pointer to BNA device structure
+ * @param[in]  rxf_id  - rx-function ID.
+ * @param[in]  mac_addr_ptr - pointer to the list of mac
+ *       adddresses to set
+ * @param[in]  mac_addr_num - number of mac addresses in the
+ *       list
+ *
+ * @return BNA_OK   - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status bna_rxf_mcast_mac_set_list(struct bna_dev *dev,
+	unsigned int rxf_id, const struct mac *mac_addr_ptr,
+	unsigned int mac_addr_num)
+{
+	u32 i, j;
+	int found;
+	char message[BNA_MESSAGE_SIZE];
+
+	BUG_ON(!(rxf_id < BNA_RXF_ID_MAX));
+
+	if (mac_addr_num > BNA_MCAST_TABLE_SIZE) {
+		sprintf(message, "Too many Multicast Addresses [%d]",
+			       mac_addr_num);
+		pr_info("%s", message);
+		return BNA_FAIL;
+	}
+
+	/* find MAC addresses to delete */
+	for (i = 0; i < BNA_MCAST_TABLE_SIZE; i++) {
+		if (BNA_MAC_IS_EQUAL(&dev->mcast_addr[i], &bna_zero_addr))
+			continue;
+		found = 0;
+		for (j = 0; j < mac_addr_num; j++) {
+			if (BNA_MAC_IS_EQUAL
+			    (&mac_addr_ptr[j], &dev->mcast_addr[i])) {
+				found = 1;
+				break;
+			}
+		}
+		if (!found) {
+			if (BNA_FAIL ==
+			    bna_rxf_mac_mbox_cmd(dev, rxf_id,
+						 BFI_LL_H2I_MAC_MCAST_DEL_REQ,
+						 &dev->mcast_addr[i])) {
+				return BNA_FAIL;
+			}
+		}
+	}
+
+	/* find MAC addresses to add */
+	for (i = 0; i < mac_addr_num; i++) {
+		found = 0;
+		for (j = 0; j < BNA_MCAST_TABLE_SIZE; j++) {
+			if (BNA_MAC_IS_EQUAL
+			    (&mac_addr_ptr[i], &dev->mcast_addr[j])) {
+				found = 1;
+				break;
+			}
+		}
+		if (!found) {
+			if (BNA_FAIL ==
+			    bna_rxf_mac_mbox_cmd(dev, rxf_id,
+						 BFI_LL_H2I_MAC_MCAST_ADD_REQ,
+						 &mac_addr_ptr[i])) {
+				return BNA_FAIL;
+			}
+		}
+	}
+
+	memset(&dev->mcast_addr[0], 0, sizeof(dev->mcast_addr));
+	memcpy(&dev->mcast_addr[0], mac_addr_ptr,
+		      mac_addr_num * sizeof(struct mac));
+
+	return BNA_OK;
+}
+
+/**
+ * bna_mcast_mac_reset_list()
+ *
+ *  Resets the multicast MAC address list kept by driver.
+ *  Called when the hw gets reset.
+ *
+ * @param[in]  dev  - pointer to BNA device structure
+ *
+ * @return void
+ */
+void
+bna_mcast_mac_reset_list(struct bna_dev *dev)
+{
+	memset(&dev->mcast_addr[0], 0, sizeof(dev->mcast_addr));
+}
+
+/**
+ *  bna_rxf_broadcast()
+ *
+ *  For RxF "rxf_id", it enables/disables the broadcast address.
+ *
+ * @param[in]  dev    - pointer to BNA device structure
+ * @param[in]  rxf_id - rx-function ID.
+ * @param[in]  enable - enable/disable broadcast address
+ *
+ * @return BNA_OK   - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status bna_rxf_broadcast(struct bna_dev *dev,
+	unsigned int rxf_id, enum bna_enable enable)
+{
+	if (enable)
+		return bna_rxf_mcast_mac_add(dev, rxf_id, &bna_bcast_addr);
+
+	return bna_rxf_mcast_mac_del(dev, rxf_id, &bna_bcast_addr);
+}
+
+/**
+ *  bna_rxf_vlan_add()
+ *
+ *  For RxF "rxf_id", it adds this function as a member of the
+ *  specified "vlan_id".
+ *
+ * @param[in]  dev    - pointer to BNA device structure
+ * @param[in]  rxf_id - rx-function ID.
+ * @param[in]  vlan_id - VLAN id to be added
+ *
+ * @return void
+ */
+void bna_rxf_vlan_add(struct bna_dev *dev, unsigned int rxf_id,
+						unsigned int vlan_id)
+{
+
+	u32 new_vlan_id;
+
+	BUG_ON(!((rxf_id <= BNA_RXF_ID_MAX)));
+
+	/*
+	 * wrap the vlan_id around in case it
+	 * overflows the max limit
+	 */
+	new_vlan_id = vlan_id & BNA_VLAN_ID_MAX;
+	BNA_BIT_TABLE_SET(dev->vlan_table[rxf_id], new_vlan_id);
+
+	if (dev->vlan_filter_enable[rxf_id] &&
+	    (dev->rxf_active & ((u64) 1 << rxf_id))) {
+		/* add VLAN ID on this function */
+		writel(BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+					(dev->port * 2),
+					VLAN_RAM_BASE_OFFSET),
+					dev->regs.page_addr);
+		writel(dev->vlan_table[rxf_id][new_vlan_id / 32],
+				BNA_GET_VLAN_MEM_ENTRY_ADDR
+			       (dev->bar0, rxf_id, new_vlan_id));
+	}
+}
+
+/**
+ *  bna_rxf_vlan_del()
+ *
+ *  For RxF "rxf_id", it removes this function as a member of the
+ *  specified "vlan_id".
+ *
+ * @param[in]  dev    - pointer to BNA device structure
+ * @param[in]  rxf_id - rx-function ID.
+ * @param[in]  vlan_id - VLAN id to be removed
+ *
+ * @return void
+ */
+void bna_rxf_vlan_del(struct bna_dev *dev, unsigned int rxf_id,
+						unsigned int vlan_id)
+{
+
+	u32 new_vlan_id;
+	BUG_ON(!(rxf_id < BNA_RXF_ID_MAX));
+
+	new_vlan_id = vlan_id & BNA_VLAN_ID_MAX;
+	BNA_BIT_TABLE_CLEAR(dev->vlan_table[rxf_id], new_vlan_id);
+
+	if (dev->vlan_filter_enable[rxf_id] &&
+	    (dev->rxf_active & ((u64) 1 << rxf_id))) {
+		writel(BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+					       (dev->port * 2),
+					       VLAN_RAM_BASE_OFFSET),
+						dev->regs.page_addr);
+		writel(dev->vlan_table[rxf_id][new_vlan_id / 32],
+				BNA_GET_VLAN_MEM_ENTRY_ADDR
+			       (dev->bar0, rxf_id, new_vlan_id));
+	}
+}
+
+/**
+ *  bna_rxf_vlan_filter()
+ *
+ *   For RxF "rxf_id", it enables/disables the VLAN filter.
+ *   Disabling the VLAN Filter allows reception of any VLAN-tagged frame.
+ *
+ * @param[in]  dev    - pointer to BNA device structure
+ * @param[in]  rxf_id - rx-function ID.
+ * @param[in]  enable - enable/disable VLAN Filtering.
+ *
+ * @return void
+ */
+void bna_rxf_vlan_filter(struct bna_dev *dev, unsigned int rxf_id,
+	enum bna_enable enable)
+{
+	u32 i;
+
+	BUG_ON(!(rxf_id < BNA_RXF_ID_MAX));
+
+	dev->vlan_filter_enable[rxf_id] = enable;
+
+	writel(BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+				       (dev->port * 2), VLAN_RAM_BASE_OFFSET),
+					dev->regs.page_addr);
+
+	if (enable) {
+		/* enable VLAN filtering on this function */
+		for (i = 0; i <= BNA_VLAN_ID_MAX / 32; i++) {
+			writel(dev->vlan_table[rxf_id][i],
+					BNA_GET_VLAN_MEM_ENTRY_ADDR
+				       (dev->bar0, rxf_id, i * 32));
+		}
+	} else {
+		/* disable VLAN filtering on this function */
+		for (i = 0; i <= BNA_VLAN_ID_MAX / 32; i++) {
+			writel(0xffffffff, BNA_GET_VLAN_MEM_ENTRY_ADDR
+				       (dev->bar0, rxf_id, i * 32));
+		}
+	}
+}
+
+/**
+ * bna_rxf_vlan_del_all()
+ *
+ *   For RxF "rxf_id", it clears all the VLANs.
+ *
+ * @param[in]  dev    - pointer to BNA device structure
+ * @param[in]  rxf_id - rx-function ID.
+ *
+ * @return void
+ */
+void
+bna_rxf_vlan_del_all(struct bna_dev *dev, unsigned int rxf_id)
+{
+	u32 i;
+
+	BUG_ON(!(rxf_id < BNA_RXF_ID_MAX));
+
+	writel(BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+				       (dev->port * 2), VLAN_RAM_BASE_OFFSET),
+					 dev->regs.page_addr);
+
+	/* clear all VLANs for this function */
+	for (i = 0; i <= BNA_VLAN_ID_MAX / 32; i++) {
+		writel(0, BNA_GET_VLAN_MEM_ENTRY_ADDR
+			       (dev->bar0, rxf_id, i * 32));
+	}
+}
+
+/**
+ *  bna_rxf_mcast_filter()
+ *
+ *   For RxF "rxf_id", it enables/disables the multicast filter.
+ *   Disabling the multicast filter allows reception of any
+ *   multicast frame.
+ *
+ * @param[in]  dev      - pointer to BNA device structure
+ * @param[in]  rxf_id - rx-function ID.
+ * @param[in]  enable - enable/disable multicast Filtering.
+ *
+ * @return BNA_OK   - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status bna_rxf_mcast_filter(struct bna_dev *dev,
+	unsigned int rxf_id, enum bna_enable enable)
+{
+
+	struct bfi_ll_mcast_filter_req cmd;
+
+	BUG_ON(!(rxf_id < BNA_RXF_ID_MAX));
+
+	bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_MAC_MCAST_FILTER_REQ, 0);
+
+	cmd.rxf_id = rxf_id;
+	cmd.enable = enable;
+
+	/* send command to firmware */
+	return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ * bna_rxf_mcast_del_all()
+ *
+ *   For RxF "rxf_id", it clears the MCAST cam and MVT.
+ *   This functionality is required by some of the drivers.
+ *
+ * @param[in]  dev     - pointer to BNA device structure
+ * @param[in]  rxf_id - rx-function ID.
+ *
+ * @return BNA_OK   - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status bna_rxf_mcast_del_all(struct bna_dev *dev,
+	unsigned int rxf_id)
+{
+	struct bfi_ll_mcast_del_all_req cmd;
+
+	BUG_ON(!(rxf_id < BNA_RXF_ID_MAX));
+
+	bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_MAC_MCAST_DEL_ALL_REQ, 0);
+
+	cmd.rxf_id = rxf_id;
+
+	/* send command to firmware */
+	return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ *  bna_rxf_promiscuous()
+ *
+ *  For RxF "rxf_id", it enables/disables promiscuous mode.
+ *
+ * @param[in]  dev    - pointer to BNA device structure
+ * @param[in]  rxf_id - rx-function ID.
+ * @param[in]  enable - enable/disable promiscious mode
+ *
+ * @return BNA_OK   - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status bna_rxf_promiscuous(struct bna_dev *dev,
+	unsigned int rxf_id, enum bna_enable enable)
+{
+	struct bfi_ll_rxf_req cmd;
+
+	BUG_ON(!(rxf_id < BNA_RXF_ID_MAX));
+
+	bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ, 0);
+
+	cmd.rxf_id = rxf_id;
+	cmd.enable = enable;
+
+	if (enable &&
+	    ((dev->rxf_promiscuous_id == BNA_RXF_ID_NONE) ||
+	     (dev->rxf_promiscuous_id == rxf_id))) {
+		dev->rxf_promiscuous_id = rxf_id;
+
+		/* allow all VLANs */
+		bna_rxf_vlan_filter(dev, rxf_id, BNA_DISABLE);
+
+		return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+	} else if (!enable && (dev->rxf_promiscuous_id == rxf_id)) {
+		dev->rxf_promiscuous_id = BNA_RXF_ID_NONE;
+
+		/* Revert VLAN filtering */
+		bna_rxf_vlan_filter(dev, rxf_id, BNA_ENABLE);
+
+		return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+	}
+
+	return BNA_FAIL;
+}
+
+/**
+ *  bna_rxf_default_mode()
+ *
+ *  For RxF "rxf_id", it enables/disables default mode.
+ *  Must be called after the RxF has been configured.
+ *  Must remove all unicast MAC associated to this RxF.
+ *
+ * @param[in]  dev    - pointer to BNA device structure
+ * @param[in]  rxf_id - rx-function ID.
+ * @param[in]  enable - enable/disable default mode
+ *
+ * @return BNA_OK   - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status bna_rxf_default_mode(struct bna_dev *dev,
+	unsigned int rxf_id, enum bna_enable enable)
+{
+	struct bna_rx_fndb_ram *rx_fndb_ram;
+	u32 i, ctl_flags;
+	struct bfi_ll_rxf_req cmd;
+
+	BUG_ON(!(rxf_id < BNA_RXF_ID_MAX));
+
+	rx_fndb_ram = (struct bna_rx_fndb_ram *)
+		BNA_GET_MEM_BASE_ADDR(dev->bar0, RX_FNDB_RAM_BASE_OFFSET);
+
+	bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_RXF_DEFAULT_SET_REQ, 0);
+
+	cmd.rxf_id = rxf_id;
+	cmd.enable = enable;
+
+	if (enable &&
+	    ((dev->rxf_default_id == BNA_RXF_ID_NONE) ||
+	     (dev->rxf_default_id == rxf_id))) {
+		dev->rxf_default_id = rxf_id;
+
+		/* allow all VLANs */
+		bna_rxf_vlan_filter(dev, rxf_id, BNA_DISABLE);
+
+		writel(BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+					       (dev->port * 2),
+					       RX_FNDB_RAM_BASE_OFFSET),
+						dev->regs.page_addr);
+
+		for (i = 0; i < BNA_RXF_ID_MAX; i++) {
+			if (i == rxf_id)
+				continue;
+
+			ctl_flags =
+				readl(&rx_fndb_ram[i].control_flags);
+			ctl_flags |= BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE;
+			writel(ctl_flags, &rx_fndb_ram[i].control_flags);
+		}
+		return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+	} else if (!enable && (dev->rxf_default_id == rxf_id)) {
+		dev->rxf_default_id = BNA_RXF_ID_NONE;
+
+		/* Revert  VLAN filtering */
+		bna_rxf_vlan_filter(dev, rxf_id,
+				    dev->vlan_filter_enable[rxf_id]);
+
+		writel(BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+					       (dev->port * 2),
+					       RX_FNDB_RAM_BASE_OFFSET),
+						dev->regs.page_addr);
+
+		for (i = 0; i < BNA_RXF_ID_MAX; i++) {
+			ctl_flags = readl(&rx_fndb_ram[i].control_flags);
+			ctl_flags &= ~BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE;
+			writel(ctl_flags, &rx_fndb_ram[i].control_flags);
+		}
+		return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+	}
+	return BNA_FAIL;
+}
+
+/**
+ *  bna_rxf_frame_stats_get()
+ *
+ *  For RxF "rxf_id", it loads frame statistics into "stats_ptr".
+ *
+ * @param[in]  dev     - pointer to BNA device structure
+ * @param[in]  rxf_id  - rx-function ID.
+ * @param[out]  stats_ptr - pointer to stats structure to fill
+ *
+ * @return void
+ */
+void bna_rxf_frame_stats_get(struct bna_dev *dev, unsigned int rxf_id,
+	struct bna_stats_rxf **stats_ptr)
+{
+
+	BUG_ON(!(rxf_id < BNA_RXF_ID_MAX));
+
+	*stats_ptr = &dev->stats.rxf_stats[rxf_id];
+}
+
+/**
+ * bna_txf_frame_stats_get()
+ *
+ *   For TxF "txf_id", it loads frame statistics into "stats_ptr".
+ *
+ * @param[in]  dev     - pointer to BNA device structure
+ * @param[in]  txf_id    - tx-function ID.
+ * @param[out] stats_ptr - pointer to tx-function statistics.
+ *
+ * @return void
+ */
+void bna_txf_frame_stats_get(struct bna_dev *dev, unsigned int txf_id,
+	struct bna_stats_txf **stats_ptr)
+{
+
+	BUG_ON(!(txf_id < BNA_TXF_ID_MAX));
+
+	*stats_ptr = &dev->stats.txf_stats[txf_id];
+}
+
+/**
+ *  bna_mac_rx_stats_get()
+ *
+ *  Loads MAC Rx statistics into "stats_ptr".
+ *
+ * @param[in]  dev       - pointer to BNA device structure
+
+ * @param[out]  stats_ptr - pointer to stats structure to fill
+ *
+ * @return void
+ */
+void bna_mac_rx_stats_get(struct bna_dev *dev,
+	struct cna_stats_mac_rx **stats_ptr)
+{
+	*stats_ptr = &dev->stats.mac_rx_stats;
+}
+
+/**
+ *  bna_mac_tx_stats_get()
+ *
+ *  Loads MAC Tx statistics into "stats_ptr".
+ *
+ * @param[in]  dev       - pointer to BNA device structure
+
+ * @param[out]  stats_ptr - pointer to stats structure to fill
+ *
+ * @return void
+ */
+void bna_mac_tx_stats_get(struct bna_dev *dev,
+	struct cna_stats_mac_tx **stats_ptr)
+{
+	*stats_ptr = &dev->stats.mac_tx_stats;
+}
+
+/**
+ *  bna_all_stats_get()
+ *
+ *  Loads all statistics into "stats_ptr".
+ *
+ * @param[in]  dev       - pointer to BNA device structure
+
+ * @param[out]  stats_ptr - pointer to stats structure
+ *
+ * @return void
+ */
+void
+bna_all_stats_get(struct bna_dev *dev, struct bna_stats **stats_ptr)
+{
+	*stats_ptr = &dev->stats;
+}
+
+/**
+ * bna_stats_get()
+ *
+ *   Get the statistics from the device. This function needs to
+ *   be scheduled every second to get periodic update of the
+ *   statistics data from hardware.
+ *
+ * @param[in]   dev       - pointer to BNA device structure.
+ *
+ * @return BNA_OK   - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status
+bna_stats_get(struct bna_dev *dev)
+{
+	struct bfi_ll_stats_req cmd;
+
+	bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_STATS_GET_REQ, 0);
+
+	cmd.stats_mask = htons(BFI_LL_STATS_ALL);
+	cmd.rxf_id_mask[0] =
+		htonl((u32) (dev->rxf_active & 0xffffffff));
+	cmd.rxf_id_mask[1] = htonl((u32) (dev->rxf_active >> 32));
+
+	cmd.txf_id_mask[0] =
+		htonl((u32) (dev->txf_active & 0xffffffff));
+	cmd.txf_id_mask[1] = htonl((u32) (dev->txf_active >> 32));
+
+	cmd.host_buffer.a32.addr_hi = dev->hw_stats_dma.msb;
+	cmd.host_buffer.a32.addr_lo = dev->hw_stats_dma.lsb;
+
+	dev->rxf_active_last = dev->rxf_active;
+	dev->txf_active_last = dev->txf_active;
+
+	/* send command to firmware */
+	return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ * bna_stats_clear()
+ *
+ *   Clear the statistics in the device.
+ *
+ * @param[in]   dev       - pointer to BNA device structure.
+ *
+ * @return BNA_OK   - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status bna_stats_clear(struct bna_dev *dev,
+	u64 txf_id_mask, u64 rxf_id_mask)
+{
+	struct bfi_ll_stats_req cmd;
+
+	bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_STATS_CLEAR_REQ, 0);
+
+	cmd.stats_mask = htons(BFI_LL_STATS_ALL);
+	cmd.rxf_id_mask[0] = htonl(lower_32_bits(rxf_id_mask));
+	cmd.rxf_id_mask[1] = htonl(upper_32_bits(rxf_id_mask));
+
+	cmd.txf_id_mask[0] = htonl(lower_32_bits(txf_id_mask));
+	cmd.txf_id_mask[1] = htonl(upper_32_bits(txf_id_mask));
+
+	/* send command to firmware */
+	return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ * bna_rxf_stats_clear()
+ *
+ *   Clear the statistics for specified txf.
+ *
+ * @param[in]   dev        - pointer to BNA device structure.
+ * @param[in]  rxf_id      - rx-function ID.
+ *
+ * @return BNA_OK   - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status bna_rxf_stats_clear(struct bna_dev *dev,
+	unsigned int rxf_id)
+{
+	struct bfi_ll_stats_req cmd;
+
+	BUG_ON(!(rxf_id < BNA_RXF_ID_MAX));
+
+	bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_STATS_CLEAR_REQ, 0);
+
+	cmd.stats_mask = 0;
+
+	if (rxf_id < 32) {
+		cmd.rxf_id_mask[0] = htonl((u32) (1 << rxf_id));
+		cmd.rxf_id_mask[1] = 0;
+	} else {
+		cmd.rxf_id_mask[0] = 0;
+		cmd.rxf_id_mask[1] =
+			htonl((u32) (1 << (rxf_id - 32)));
+	}
+
+	cmd.txf_id_mask[0] = 0;
+	cmd.txf_id_mask[1] = 0;
+
+	/* send command to firmware */
+	return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ * bna_lldp_stats_clear()
+ *
+ *   Clear the DCBCX-LLDP statistics in the f/w.
+ *
+ * @param[in]   dev       - pointer to BNA device structure.
+ *
+ * @return BNA_OK   - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status
+bna_lldp_stats_clear(struct bna_dev *dev)
+{
+	struct bfi_lldp_reset_stats cmd;
+
+	bfi_h2i_set(cmd.mh, BFI_MC_CEE, BFI_CEE_H2I_RESET_STATS, 0);
+
+	/* send command to firmware */
+	return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ * bna_get_cfg_req()
+ *
+ *   Request to get the LLDP-DCBCX Config.
+ *
+ * @param[in]   dev       - pointer to BNA device structure.
+ * @param[in]   dma_ddr   - dma address in "bna_dma_addr_t" format.
+ *
+ * @return BNA_OK   - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status bna_get_cfg_req(struct bna_dev *dev,
+	struct bna_dma_addr *dma_addr)
+{
+	struct bfi_cee_get_req cmd;
+
+	bfi_h2i_set(cmd.mh, BFI_MC_CEE, BFI_CEE_H2I_GET_CFG_REQ, 0);
+	cmd.dma_addr.a32.addr_lo = dma_addr->lsb;
+	cmd.dma_addr.a32.addr_hi = dma_addr->msb;
+	/* send command to firmware */
+	return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ * bna_get_cee_stats_req()
+ *
+ *   Request to get the LLDP-DCBCX stats.
+ *
+ * @param[in]   dev       - pointer to BNA device structure.
+ * @param[in]   dma_ddr   - dma address in "bna_dma_addr_t" format.
+ *
+ * @return BNA_OK   - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status bna_get_cee_stats_req(struct bna_dev *dev,
+	struct bna_dma_addr *dma_addr)
+{
+	struct bfi_cee_get_req cmd;
+
+	bfi_h2i_set(cmd.mh, BFI_MC_CEE, BFI_CEE_H2I_GET_STATS_REQ, 0);
+	cmd.dma_addr.a32.addr_lo = dma_addr->lsb;
+	cmd.dma_addr.a32.addr_hi = dma_addr->msb;
+	/* send command to firmware */
+	return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ * bna_stats_process()
+ *
+ *   Process the statistics data DMAed from the device. This
+ *   function needs to be scheduled upon getting an asynchronous
+ *   notification from the firmware.
+ *
+ * @param[in]   dev       - pointer to BNA device structure.
+ *
+ * @return void
+ */
+void
+bna_stats_process(struct bna_dev *dev)
+{
+	u32 i, j;
+	struct bna_stats_rxf *rxf_hw_stats;
+	struct bna_stats_txf *txf_hw_stats;
+
+	dev->stats.fc_tx_stats.txf_ucast_octets =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_tx_stats.
+				      txf_ucast_octets);
+	dev->stats.fc_tx_stats.txf_ucast =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_tx_stats.txf_ucast);
+	dev->stats.fc_tx_stats.txf_ucast_vlan =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_tx_stats.
+				      txf_ucast_vlan);
+
+	dev->stats.fc_tx_stats.txf_mcast_octets =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_tx_stats.
+				      txf_mcast_octets);
+	dev->stats.fc_tx_stats.txf_mcast =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_tx_stats.txf_mcast);
+	dev->stats.fc_tx_stats.txf_mcast_vlan =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_tx_stats.
+				      txf_mcast_vlan);
+
+	dev->stats.fc_tx_stats.txf_bcast_octets =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_tx_stats.
+				      txf_bcast_octets);
+	dev->stats.fc_tx_stats.txf_bcast =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_tx_stats.txf_bcast);
+	dev->stats.fc_tx_stats.txf_bcast_vlan =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_tx_stats.
+				      txf_bcast_vlan);
+
+	dev->stats.fc_tx_stats.txf_parity_errors =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_tx_stats.
+				      txf_parity_errors);
+	dev->stats.fc_tx_stats.txf_timeout =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_tx_stats.txf_timeout);
+	dev->stats.fc_tx_stats.txf_fid_parity_errors =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_tx_stats.
+				      txf_fid_parity_errors);
+
+	for (i = 0; i < 8; i++) {
+		dev->stats.bpc_tx_stats.tx_pause[i] =
+			bna_hw_stats_to_stats(dev->hw_stats->bpc_stats.
+					      tx_pause[i]);
+		dev->stats.bpc_tx_stats.tx_zero_pause[i] =
+			bna_hw_stats_to_stats(dev->hw_stats->bpc_stats.
+					      tx_zero_pause[i]);
+		dev->stats.bpc_tx_stats.tx_first_pause[i] =
+			bna_hw_stats_to_stats(dev->hw_stats->bpc_stats.
+					      tx_first_pause[i]);
+	}
+
+	dev->stats.mac_tx_stats.tx_bytes =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.tx_bytes);
+	dev->stats.mac_tx_stats.tx_packets =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.tx_packets);
+	dev->stats.mac_tx_stats.tx_multicast =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.tx_multicast);
+	dev->stats.mac_tx_stats.tx_broadcast =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.tx_broadcast);
+	dev->stats.mac_tx_stats.tx_pause =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.tx_pause);
+	dev->stats.mac_tx_stats.tx_deferral =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.tx_deferral);
+	dev->stats.mac_tx_stats.tx_excessive_deferral =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.
+				      tx_excessive_deferral);
+	dev->stats.mac_tx_stats.tx_single_collision =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.
+				      tx_single_collision);
+	dev->stats.mac_tx_stats.tx_muliple_collision =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.
+				      tx_muliple_collision);
+	dev->stats.mac_tx_stats.tx_late_collision =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.
+				      tx_late_collision);
+	dev->stats.mac_tx_stats.tx_excessive_collision =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.
+				      tx_excessive_collision);
+	dev->stats.mac_tx_stats.tx_total_collision =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.
+				      tx_total_collision);
+	dev->stats.mac_tx_stats.tx_pause_honored =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.
+				      tx_pause_honored);
+	dev->stats.mac_tx_stats.tx_drop =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.tx_drop);
+	dev->stats.mac_tx_stats.tx_jabber =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.tx_jabber);
+	dev->stats.mac_tx_stats.tx_fcs_error =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.tx_fcs_error);
+	dev->stats.mac_tx_stats.tx_control_frame =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.
+				      tx_control_frame);
+	dev->stats.mac_tx_stats.tx_oversize =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.tx_oversize);
+	dev->stats.mac_tx_stats.tx_undersize =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.tx_undersize);
+	dev->stats.mac_tx_stats.tx_fragments =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.tx_fragments);
+
+	dev->stats.fc_rx_stats.rxf_ucast_octets =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_rx_stats.
+				      rxf_ucast_octets);
+	dev->stats.fc_rx_stats.rxf_ucast =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_rx_stats.rxf_ucast);
+	dev->stats.fc_rx_stats.rxf_ucast_vlan =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_rx_stats.
+				      rxf_ucast_vlan);
+
+	dev->stats.fc_rx_stats.rxf_mcast_octets =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_rx_stats.
+				      rxf_mcast_octets);
+	dev->stats.fc_rx_stats.rxf_mcast =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_rx_stats.rxf_mcast);
+	dev->stats.fc_rx_stats.rxf_mcast_vlan =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_rx_stats.
+				      rxf_mcast_vlan);
+
+	dev->stats.fc_rx_stats.rxf_bcast_octets =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_rx_stats.
+				      rxf_bcast_octets);
+	dev->stats.fc_rx_stats.rxf_bcast =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_rx_stats.rxf_bcast);
+	dev->stats.fc_rx_stats.rxf_bcast_vlan =
+		bna_hw_stats_to_stats(dev->hw_stats->fc_rx_stats.
+				      rxf_bcast_vlan);
+
+	for (i = 0; i < 8; i++) {
+		dev->stats.bpc_rx_stats.rx_pause[i] =
+			bna_hw_stats_to_stats(dev->hw_stats->bpc_stats.
+					      rx_pause[i]);
+		dev->stats.bpc_rx_stats.rx_zero_pause[i] =
+			bna_hw_stats_to_stats(dev->hw_stats->bpc_stats.
+					      rx_zero_pause[i]);
+		dev->stats.bpc_rx_stats.rx_first_pause[i] =
+			bna_hw_stats_to_stats(dev->hw_stats->bpc_stats.
+					      rx_first_pause[i]);
+	}
+
+	dev->stats.rad_stats.rx_frames =
+		bna_hw_stats_to_stats(dev->hw_stats->rad_stats.rx_frames);
+	dev->stats.rad_stats.rx_octets =
+		bna_hw_stats_to_stats(dev->hw_stats->rad_stats.rx_octets);
+	dev->stats.rad_stats.rx_vlan_frames =
+		bna_hw_stats_to_stats(dev->hw_stats->rad_stats.rx_vlan_frames);
+
+	dev->stats.rad_stats.rx_ucast =
+		bna_hw_stats_to_stats(dev->hw_stats->rad_stats.rx_ucast);
+	dev->stats.rad_stats.rx_ucast_octets =
+		bna_hw_stats_to_stats(dev->hw_stats->rad_stats.rx_ucast_octets);
+	dev->stats.rad_stats.rx_ucast_vlan =
+		bna_hw_stats_to_stats(dev->hw_stats->rad_stats.rx_ucast_vlan);
+
+	dev->stats.rad_stats.rx_mcast =
+		bna_hw_stats_to_stats(dev->hw_stats->rad_stats.rx_mcast);
+	dev->stats.rad_stats.rx_mcast_octets =
+		bna_hw_stats_to_stats(dev->hw_stats->rad_stats.rx_mcast_octets);
+	dev->stats.rad_stats.rx_mcast_vlan =
+		bna_hw_stats_to_stats(dev->hw_stats->rad_stats.rx_mcast_vlan);
+
+	dev->stats.rad_stats.rx_bcast =
+		bna_hw_stats_to_stats(dev->hw_stats->rad_stats.rx_bcast);
+	dev->stats.rad_stats.rx_bcast_octets =
+		bna_hw_stats_to_stats(dev->hw_stats->rad_stats.rx_bcast_octets);
+	dev->stats.rad_stats.rx_bcast_vlan =
+		bna_hw_stats_to_stats(dev->hw_stats->rad_stats.rx_bcast_vlan);
+
+	dev->stats.rad_stats.rx_drops =
+		bna_hw_stats_to_stats(dev->hw_stats->rad_stats.rx_drops);
+
+	dev->stats.mac_rx_stats.frame_64 =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.frame_64);
+	dev->stats.mac_rx_stats.frame_65_127 =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.frame_65_127);
+	dev->stats.mac_rx_stats.frame_128_255 =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.frame_128_255);
+	dev->stats.mac_rx_stats.frame_256_511 =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.frame_256_511);
+	dev->stats.mac_rx_stats.frame_512_1023 =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.frame_512_1023);
+	dev->stats.mac_rx_stats.frame_1024_1518 =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.frame_1024_1518);
+	dev->stats.mac_rx_stats.frame_1518_1522 =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.frame_1519_1522);
+	dev->stats.mac_rx_stats.rx_bytes =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.rx_bytes);
+	dev->stats.mac_rx_stats.rx_packets =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.rx_packets);
+	dev->stats.mac_rx_stats.rx_fcs_error =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.rx_fcs_error);
+	dev->stats.mac_rx_stats.rx_multicast =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.rx_multicast);
+	dev->stats.mac_rx_stats.rx_broadcast =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.rx_broadcast);
+	dev->stats.mac_rx_stats.rx_control_frames =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.
+				      rx_control_frames);
+	dev->stats.mac_rx_stats.rx_pause =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.rx_pause);
+	dev->stats.mac_rx_stats.rx_unknown_opcode =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.
+				      rx_unknown_opcode);
+	dev->stats.mac_rx_stats.rx_alignment_error =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.
+				      rx_alignment_error);
+	dev->stats.mac_rx_stats.rx_frame_length_error =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.
+				      rx_frame_length_error);
+	dev->stats.mac_rx_stats.rx_code_error =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.rx_code_error);
+	dev->stats.mac_rx_stats.rx_carrier_sense_error =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.
+				      rx_carrier_sense_error);
+	dev->stats.mac_rx_stats.rx_undersize =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.rx_undersize);
+	dev->stats.mac_rx_stats.rx_oversize =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.rx_oversize);
+	dev->stats.mac_rx_stats.rx_fragments =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.rx_jabber);
+	dev->stats.mac_rx_stats.rx_jabber =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.rx_jabber);
+	dev->stats.mac_rx_stats.rx_drop =
+		bna_hw_stats_to_stats(dev->hw_stats->mac_stats.rx_drop);
+
+	rxf_hw_stats = (struct bna_stats_rxf *)&dev->hw_stats->rxf_stats[0];
+	j = 0;
+
+	for (i = 0; i < BNA_RXF_ID_MAX; i++) {
+		if (dev->rxf_active_last & ((u64) 1 << i)) {
+			dev->stats.rxf_stats[i].ucast_octets =
+				bna_hw_stats_to_stats(rxf_hw_stats[j].
+						      ucast_octets);
+			dev->stats.rxf_stats[i].ucast =
+				bna_hw_stats_to_stats(rxf_hw_stats[j].ucast);
+			dev->stats.rxf_stats[i].ucast_vlan =
+				bna_hw_stats_to_stats(rxf_hw_stats[j].
+						      ucast_vlan);
+
+			dev->stats.rxf_stats[i].mcast_octets =
+				bna_hw_stats_to_stats(rxf_hw_stats[j].
+						      mcast_octets);
+			dev->stats.rxf_stats[i].mcast =
+				bna_hw_stats_to_stats(rxf_hw_stats[j].mcast);
+			dev->stats.rxf_stats[i].mcast_vlan =
+				bna_hw_stats_to_stats(rxf_hw_stats[j].
+						      mcast_vlan);
+
+			dev->stats.rxf_stats[i].bcast_octets =
+				bna_hw_stats_to_stats(rxf_hw_stats[j].
+						      bcast_octets);
+			dev->stats.rxf_stats[i].bcast =
+				bna_hw_stats_to_stats(rxf_hw_stats[j].bcast);
+			dev->stats.rxf_stats[i].bcast_vlan =
+				bna_hw_stats_to_stats(rxf_hw_stats[j].
+						      bcast_vlan);
+
+			dev->stats.rxf_stats[i].frame_drops =
+				bna_hw_stats_to_stats(rxf_hw_stats[j].
+						      frame_drops);
+
+			j++;
+		}
+	}
+
+	txf_hw_stats = (struct bna_stats_txf *)&rxf_hw_stats[j];
+	j = 0;
+
+	for (i = 0; i < BNA_TXF_ID_MAX; i++) {
+		if (dev->txf_active_last & ((u64) 1 << i)) {
+			dev->stats.txf_stats[i].ucast_octets =
+				bna_hw_stats_to_stats(txf_hw_stats[j].
+						      ucast_octets);
+			dev->stats.txf_stats[i].ucast =
+				bna_hw_stats_to_stats(txf_hw_stats[j].ucast);
+			dev->stats.txf_stats[i].ucast_vlan =
+				bna_hw_stats_to_stats(txf_hw_stats[j].
+						      ucast_vlan);
+
+			dev->stats.txf_stats[i].mcast_octets =
+				bna_hw_stats_to_stats(txf_hw_stats[j].
+						      mcast_octets);
+			dev->stats.txf_stats[i].mcast =
+				bna_hw_stats_to_stats(txf_hw_stats[j].mcast);
+			dev->stats.txf_stats[i].mcast_vlan =
+				bna_hw_stats_to_stats(txf_hw_stats[j].
+						      mcast_vlan);
+
+			dev->stats.txf_stats[i].bcast_octets =
+				bna_hw_stats_to_stats(txf_hw_stats[j].
+						      bcast_octets);
+			dev->stats.txf_stats[i].bcast =
+				bna_hw_stats_to_stats(txf_hw_stats[j].bcast);
+			dev->stats.txf_stats[i].bcast_vlan =
+				bna_hw_stats_to_stats(txf_hw_stats[j].
+						      bcast_vlan);
+
+			dev->stats.txf_stats[i].errors =
+				bna_hw_stats_to_stats(txf_hw_stats[j].errors);
+			dev->stats.txf_stats[i].filter_vlan =
+				bna_hw_stats_to_stats(txf_hw_stats[j].
+						      filter_vlan);
+			dev->stats.txf_stats[i].filter_mac_sa =
+				bna_hw_stats_to_stats(txf_hw_stats[j].
+						      filter_mac_sa);
+
+			j++;
+		}
+	}
+}
+
+/**
+ * bna_txf_config_set()
+ *
+ *   For TxF "txf_id", it configures the TxF specified by "cfg_ptr" and
+ *   indicates to the statistics collector to collect statistics for this
+ *   Tx-Function.
+ *
+ * @param[in]  dev     - pointer to BNA device structure
+ * @param[in]  txf_id  - tx-function ID.
+ * @param[in]  cfg_ptr - pointer to tx-function configuration.
+ *
+ * @return void
+ */
+void bna_txf_config_set(struct bna_dev *dev, unsigned int txf_id,
+	const struct bna_txf_config *cfg_ptr)
+{
+
+	struct bna_tx_fndb_ram *tx_fndb;
+
+	BUG_ON(!(txf_id < BNA_TXF_ID_MAX));
+
+	tx_fndb = (struct bna_tx_fndb_ram *)
+		BNA_GET_MEM_BASE_ADDR(dev->bar0, TX_FNDB_RAM_BASE_OFFSET);
+
+	writel(BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+				       (dev->port * 2),
+				       TX_FNDB_RAM_BASE_OFFSET),
+					dev->regs.page_addr);
+
+	writel((cfg_ptr->vlan << 16) | cfg_ptr->flags, &tx_fndb[txf_id]);
+
+	/* turn on statistics collection */
+	dev->txf_active |= ((u64) 1 << txf_id);
+}
+
+/**
+ * bna_txf_config_clear()
+ *
+ *   For TxF "txf_id", it clears its configuration and indicates to the
+ *   statistics collector to stop collecting statistics for this
+ *   Tx-Function.
+ *
+ * @param[in]  dev     - pointer to BNA device structure
+ * @param[in]  txf_id  - tx-function ID.
+ *
+ * @return void
+ */
+void
+bna_txf_config_clear(struct bna_dev *dev, unsigned int txf_id)
+{
+
+	struct bna_tx_fndb_ram *tx_fndb;
+
+	BUG_ON(!(txf_id < BNA_TXF_ID_MAX));
+
+	tx_fndb = (struct bna_tx_fndb_ram *)
+		BNA_GET_MEM_BASE_ADDR(dev->bar0,
+		TX_FNDB_RAM_BASE_OFFSET);
+
+	writel(BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+				       (dev->port * 2),
+				       TX_FNDB_RAM_BASE_OFFSET),
+					dev->regs.page_addr);
+
+	writel(0, &tx_fndb[txf_id]);
+
+	/* turn off statistics collection */
+	dev->txf_active &= ~((u64) 1 << txf_id);
+}
+
+/**
+ * bna_txf_disable()
+ *
+ *  Disables the Tx Function without clearing the configuration
+ *  Also disables collection of statistics.
+ *
+ * @param[in] bna_dev   - Pointer to BNA device handle
+ * @param[in] txf_id    - Id of the Tx Function to be disabled
+ *
+ * @return void
+ */
+void
+bna_txf_disable(struct bna_dev *dev, unsigned int txf_id)
+{
+	struct bna_tx_fndb_ram *tx_fndb;
+	u32 page_num, ctl_flags;
+
+	BUG_ON(!(txf_id < BNA_TXF_ID_MAX));
+
+	tx_fndb = (struct bna_tx_fndb_ram *)
+		BNA_GET_MEM_BASE_ADDR(dev->bar0, TX_FNDB_RAM_BASE_OFFSET);
+
+	/* Write the page number register */
+	page_num =
+		BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM + (dev->port * 2),
+				 TX_FNDB_RAM_BASE_OFFSET);
+	writel(page_num, dev->regs.page_addr);
+
+	ctl_flags = readl(&tx_fndb[txf_id].vlan_n_ctrl_flags);
+
+	ctl_flags &= ~BNA_TXF_CF_ENABLE;
+
+	writel(ctl_flags, &tx_fndb[txf_id].vlan_n_ctrl_flags);
+
+	/* turn off statistics collection */
+	dev->txf_active &= ~((u64) 1 << txf_id);
+}
+
+/**
+ * bna_txf_enable()
+ *
+ *  Enables the Tx Function without reconfiguring.
+ *  Also disables collection of statistics.
+ *
+ * @param[in] bna_dev   - Pointer to BNA device handle
+ * @param[in] txf_id    - Id of the Tx Function to be disabled
+ *
+ * @return void
+ */
+void
+bna_txf_enable(struct bna_dev *dev, unsigned int txf_id)
+{
+	struct bna_tx_fndb_ram *tx_fndb;
+	u32 page_num, ctl_flags;
+
+	BUG_ON(!(txf_id < BNA_TXF_ID_MAX));
+
+	tx_fndb = (struct bna_tx_fndb_ram *)
+		BNA_GET_MEM_BASE_ADDR(dev->bar0, TX_FNDB_RAM_BASE_OFFSET);
+
+	/* Write the page number register */
+	page_num =
+		BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM + (dev->port * 2),
+				 TX_FNDB_RAM_BASE_OFFSET);
+	writel(page_num, dev->regs.page_addr);
+
+	ctl_flags = readl(&tx_fndb[txf_id].vlan_n_ctrl_flags);
+
+	ctl_flags |= BNA_TXF_CF_ENABLE;
+
+	writel(ctl_flags, &tx_fndb[txf_id].vlan_n_ctrl_flags);
+
+	/* turn on statistics collection */
+	dev->txf_active |= ((u64) 1 << txf_id);
+}
+
+/**
+ * bna_set_pause_config()
+ *
+ *   Enable/disable Tx/Rx pause through F/W
+ *
+ * @param[in]   dev	  - pointer to BNA device structure
+ * @param[in]   pause	  - pointer to struct bna_pause_config
+ *
+ * @return BNA_OK in case of success BNA_FAIL otherwise.
+ */
+enum bna_status bna_set_pause_config(struct bna_dev *dev,
+	struct bna_pause_config *pause, void *cbarg)
+{
+	struct bfi_ll_set_pause_req ll_req;
+
+	bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_SET_PAUSE_REQ, 0);
+
+	ll_req.tx_pause = pause->tx_pause;
+	ll_req.rx_pause = pause->rx_pause;
+
+	/* send to f/w */
+	return bna_mbox_send(dev, &ll_req, sizeof(ll_req), cbarg);
+}
+
+/**
+ * bna_mtu_info()
+ *
+ *   Send MTU information to F/W.
+ *   This is required to do PAUSE efficiently.
+ *
+ * @param[in]   dev	  - pointer to BNA device structure
+ * @param[in]   mtu	  - current mtu size
+ * @param[in]   cbarg	  - argument for the callback function
+ *
+ * @return BNA_OK in case of success BNA_FAIL otherwise.
+ */
+enum bna_status bna_mtu_info(struct bna_dev *dev, u16 mtu,
+	void *cbarg)
+{
+	struct bfi_ll_mtu_info_req ll_req;
+
+	bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_MTU_INFO_REQ, 0);
+	ll_req.mtu = htons(mtu);
+
+	/* send to f/w */
+	return bna_mbox_send(dev, &ll_req, sizeof(ll_req), cbarg);
+}
+
+/* Currently we assume just 2 columns, col 0 = small, col 1 = large */
+static const u32 intr_mod_vector[BNA_LOAD_TYPES + 1][BNA_BIAS_TYPES] = {
+	{12, 12},
+	{6, 10},
+	{5, 10},
+	{4, 8},
+	{3, 6},
+	{3, 6},
+	{2, 4},
+	{1, 2},
+};
+
+/**
+ * Returns the coalescing timer value
+ */
+u8 bna_calc_coalescing_timer(struct bna_dev *dev,
+	struct bna_pkt_rate *pkt)
+{
+	u32 load, bias;
+	u32 pkt_rt = 0, small_rt, large_rt;
+
+	small_rt = pkt->small_pkt_cnt;
+	large_rt = pkt->large_pkt_cnt;
+
+	pkt_rt = small_rt + large_rt;
+
+	if (pkt_rt < BNA_10K_PKT_RATE)
+		load = BNA_LOW_LOAD_4;
+	else if (pkt_rt < BNA_20K_PKT_RATE)
+		load = BNA_LOW_LOAD_3;
+	else if (pkt_rt < BNA_30K_PKT_RATE)
+		load = BNA_LOW_LOAD_2;
+	else if (pkt_rt < BNA_40K_PKT_RATE)
+		load = BNA_LOW_LOAD_1;
+	else if (pkt_rt < BNA_50K_PKT_RATE)
+		load = BNA_HIGH_LOAD_1;
+	else if (pkt_rt < BNA_60K_PKT_RATE)
+		load = BNA_HIGH_LOAD_2;
+	else if (pkt_rt < BNA_80K_PKT_RATE)
+		load = BNA_HIGH_LOAD_3;
+	else
+		load = BNA_HIGH_LOAD_4;
+
+	if (small_rt > (large_rt << 1))
+		bias = 0;
+	else
+		bias = 1;
+
+	pkt->small_pkt_cnt = pkt->large_pkt_cnt = 0;
+	return intr_mod_vector[load][bias];
+}
diff -ruP net-next-2.6-orig/drivers/net/bna/bna_queue.c net-next-2.6-mod/drivers/net/bna/bna_queue.c
--- net-next-2.6-orig/drivers/net/bna/bna_queue.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6-mod/drivers/net/bna/bna_queue.c	2009-12-18 16:53:40.000000000 -0800
@@ -0,0 +1,409 @@ 
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 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 for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ *    @file bna_queue.c BNA Queues
+ */
+
+#include "cna.h"
+#include "bna.h"
+#include "bna_hwreg.h"
+#include "bna_priv.h"
+#include "bfi/bfi_ll.h"
+
+#define BNA_Q_IDLE_STATE	0x00008001
+/*
+ *-----------------------------------------------------------------------------
+ *  bna_txq_config()
+ *
+ *  For TxQ "txq_id", it configures the Tx-Queue as specified by "cfg_ptr".
+ *-----------------------------------------------------------------------------
+ */
+void bna_txq_config(struct bna_dev *dev, struct bna_txq *q_ptr,
+	unsigned int txq_id, const struct bna_txq_config *cfg_ptr)
+{
+	struct bna_rxtx_q_mem *q_mem;
+	struct bna_txq_mem txq_cfg, *txq_mem;
+	const struct bna_qpt *qpt = &cfg_ptr->qpt;
+	struct bna_dma_addr cur_q_addr;
+	struct bna_doorbell_qset *qset;
+	u32 pg_num;
+
+	BUG_ON(!(txq_id < BNA_TXQ_ID_MAX));
+	/* Check if the depth is a power of 2 */
+	BUG_ON(!(BNA_POWER_OF_2(q_ptr->q.q_depth)));
+
+	cur_q_addr = *((struct bna_dma_addr *)(qpt->kv_qpt_ptr));
+
+	/*
+	 * Fill out structure, to be subsequently written
+	 * to hardware
+	 */
+	txq_cfg.pg_tbl_addr_lo = qpt->hw_qpt_ptr.lsb;
+	txq_cfg.pg_tbl_addr_hi = qpt->hw_qpt_ptr.msb;
+
+	txq_cfg.cur_q_entry_lo = cur_q_addr.lsb;
+	txq_cfg.cur_q_entry_hi = cur_q_addr.msb;
+
+	txq_cfg.pg_cnt_n_prd_ptr = (qpt->page_count << 16) | 0x0;
+
+	txq_cfg.entry_n_pg_size =
+		((BNA_TXQ_ENTRY_SIZE >> 2) << 16) | (qpt->page_size >> 2);
+	txq_cfg.int_blk_n_cns_ptr =
+		((((u8) cfg_ptr->
+		   ib_seg_index) << 24) | (((u8) cfg_ptr->
+					    ib_id) << 16) | 0x0);
+	txq_cfg.cns_ptr2_n_q_state = BNA_Q_IDLE_STATE;
+	txq_cfg.nxt_qid_n_fid_n_pri =
+		(((cfg_ptr->txf_id & 0x3f) << 3) | (cfg_ptr->priority & 0x3));
+	txq_cfg.wvc_n_cquota_n_rquota =
+		(((cfg_ptr->wrr_quota & 0xfff) << 12) | (cfg_ptr->
+							 wrr_quota & 0xfff));
+
+	pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + dev->port,
+				  HQM_RXTX_Q_RAM_BASE_OFFSET);
+
+	writel(pg_num, dev->regs.page_addr);
+	/* Write to h/w */
+	q_mem = (struct bna_rxtx_q_mem *)
+		BNA_GET_MEM_BASE_ADDR(dev->bar0, HQM_RXTX_Q_RAM_BASE_OFFSET);
+
+	txq_mem = &q_mem[txq_id].txq;
+
+	writel(htonl(txq_cfg.pg_tbl_addr_lo), &txq_mem->pg_tbl_addr_lo);
+	writel(htonl(txq_cfg.pg_tbl_addr_hi), &txq_mem->pg_tbl_addr_hi);
+	writel(htonl(txq_cfg.cur_q_entry_lo), &txq_mem->cur_q_entry_lo);
+	writel(htonl(txq_cfg.cur_q_entry_hi), &txq_mem->cur_q_entry_hi);
+
+	writel(txq_cfg.pg_cnt_n_prd_ptr, &txq_mem->pg_cnt_n_prd_ptr);
+	writel(txq_cfg.entry_n_pg_size, &txq_mem->entry_n_pg_size);
+	writel(txq_cfg.int_blk_n_cns_ptr, &txq_mem->int_blk_n_cns_ptr);
+	writel(txq_cfg.cns_ptr2_n_q_state, &txq_mem->cns_ptr2_n_q_state);
+	writel(txq_cfg.nxt_qid_n_fid_n_pri, &txq_mem->nxt_qid_n_fid_n_pri);
+	writel(txq_cfg.wvc_n_cquota_n_rquota, &txq_mem->wvc_n_cquota_n_rquota);
+
+	qset = (struct bna_doorbell_qset *)
+		BNA_GET_DOORBELL_BASE_ADDR(dev->bar0);
+	q_ptr->doorbell = &qset[txq_id].txq[0];
+
+	q_ptr->q.producer_index = 0;
+	q_ptr->q.consumer_index = 0;
+}
+
+/**
+ * bna_txq_stop()
+ *
+ * 	Stops the TxQ identified by the TxQ Id.
+ *	Should be called with a lock held
+ *	The driver should wait for the response to
+ *	conclude if the Q stop is successful or not.
+ *
+ * @param[in] q_id	- Id of the TxQ
+ *
+ * @return    BNA_OK in case of success, else BNA_FAIL
+ */
+enum bna_status
+bna_txq_stop(struct bna_dev *dev, u32 txq_id)
+{
+	struct bfi_ll_q_stop_req ll_req;
+	u64 bit_mask = 1 << txq_id;
+
+	ll_req.mh.msg_class = BFI_MC_LL;
+	ll_req.mh.msg_id = BFI_LL_H2I_TXQ_STOP_REQ;
+	ll_req.mh.mtag.i2htok = 0;
+
+	ll_req.q_id_mask[0] = htonl(lower_32_bits(bit_mask));
+	ll_req.q_id_mask[1] = htonl(upper_32_bits(bit_mask));
+
+	/* send to f/w */
+	return bna_mbox_send(dev, &ll_req, sizeof(ll_req), dev->cbarg);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *  bna_rxq_config()
+ *
+ *  For RxQ "rxq_id", it configures the Rx-Queue as specified by "cfg_ptr".
+ *-----------------------------------------------------------------------------
+ */
+void bna_rxq_config(struct bna_dev *dev, struct bna_rxq *q_ptr,
+	unsigned int rxq_id, const struct bna_rxq_config *cfg_ptr)
+{
+	struct bna_rxtx_q_mem *q_mem;
+	struct bna_rxq_mem rxq_cfg, *rxq_mem;
+	const struct bna_qpt *qpt = &cfg_ptr->qpt;
+	struct bna_dma_addr cur_q_addr;
+	struct bna_doorbell_qset *qset;
+	u32 pg_num;
+
+	BUG_ON(!(rxq_id < BNA_RXQ_ID_MAX));
+
+	/* Check if the depth is a power of 2 */
+	BUG_ON(!(BNA_POWER_OF_2(q_ptr->q.q_depth)));
+
+	cur_q_addr = *((struct bna_dma_addr *)(qpt->kv_qpt_ptr));
+	/*
+	 * Fill out structure, to be subsequently written
+	 * to hardware
+	 */
+	rxq_cfg.pg_tbl_addr_lo = qpt->hw_qpt_ptr.lsb;
+	rxq_cfg.pg_tbl_addr_hi = qpt->hw_qpt_ptr.msb;
+	rxq_cfg.cur_q_entry_lo = cur_q_addr.lsb;
+	rxq_cfg.cur_q_entry_hi = cur_q_addr.msb;
+
+	rxq_cfg.pg_cnt_n_prd_ptr = (qpt->page_count << 16) | 0x0;
+	rxq_cfg.entry_n_pg_size =
+		((BNA_RXQ_ENTRY_SIZE >> 2) << 16) | (qpt->page_size >> 2);
+	rxq_cfg.sg_n_cq_n_cns_ptr = (((u8) cfg_ptr->cq_id) << 16) | 0x0;
+	rxq_cfg.buf_sz_n_q_state =
+		(cfg_ptr->buffer_size << 16) | BNA_Q_IDLE_STATE;
+	rxq_cfg.next_qid = 0x0 | (0x3 << 8);
+
+	/* Write the page number register */
+	pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + dev->port,
+				  HQM_RXTX_Q_RAM_BASE_OFFSET);
+	writel(pg_num, dev->regs.page_addr);
+
+	/* Write to h/w */
+	q_mem = (struct bna_rxtx_q_mem *)
+		BNA_GET_MEM_BASE_ADDR(dev->bar0, HQM_RXTX_Q_RAM_BASE_OFFSET);
+	rxq_mem = &q_mem[rxq_id].rxq;
+
+	writel(htonl(rxq_cfg.pg_tbl_addr_lo), &rxq_mem->pg_tbl_addr_lo);
+	writel(htonl(rxq_cfg.pg_tbl_addr_hi), &rxq_mem->pg_tbl_addr_hi);
+	writel(htonl(rxq_cfg.cur_q_entry_lo), &rxq_mem->cur_q_entry_lo);
+	writel(htonl(rxq_cfg.cur_q_entry_hi), &rxq_mem->cur_q_entry_hi);
+
+	writel(rxq_cfg.pg_cnt_n_prd_ptr, &rxq_mem->pg_cnt_n_prd_ptr);
+	writel(rxq_cfg.entry_n_pg_size, &rxq_mem->entry_n_pg_size);
+	writel(rxq_cfg.sg_n_cq_n_cns_ptr, &rxq_mem->sg_n_cq_n_cns_ptr);
+	writel(rxq_cfg.buf_sz_n_q_state, &rxq_mem->buf_sz_n_q_state);
+	writel(rxq_cfg.next_qid, &rxq_mem->next_qid);
+
+	qset = (struct bna_doorbell_qset *)
+		BNA_GET_DOORBELL_BASE_ADDR(dev->bar0);
+	q_ptr->doorbell = &qset[rxq_id].rxq[0];
+
+	q_ptr->q.producer_index = 0;
+	q_ptr->q.consumer_index = 0;
+}
+
+/**
+ * bna_rxq_stop()
+ *
+ * 	Stops the RxQ identified by the RxQ Id.
+ *	Should be called with a lock held
+ *	The driver should wait for the response to
+ *	conclude if the Q stop is successful or not.
+ *
+ * @param[in] q_id	- Id of the RxQ
+ *
+ * @return    BNA_OK in case of success, else BNA_FAIL
+ */
+enum bna_status
+bna_rxq_stop(struct bna_dev *dev, u32 rxq_id)
+{
+	struct bfi_ll_q_stop_req ll_req;
+	u64 bit_mask = 1 << rxq_id;
+
+	ll_req.mh.msg_class = BFI_MC_LL;
+	ll_req.mh.msg_id = BFI_LL_H2I_RXQ_STOP_REQ;
+	ll_req.mh.mtag.i2htok = 0;
+
+	ll_req.q_id_mask[0] = htonl(lower_32_bits(bit_mask));
+	ll_req.q_id_mask[1] = htonl(upper_32_bits(bit_mask));
+
+	/* send to f/w */
+	return bna_mbox_send(dev, &ll_req, sizeof(ll_req), dev->cbarg);
+}
+
+enum bna_status bna_multi_rxq_stop(struct bna_dev *dev,
+	u64 rxq_id_mask)
+{
+	struct bfi_ll_q_stop_req ll_req;
+
+	bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_RXQ_STOP_REQ, 0);
+
+	ll_req.q_id_mask[0] = htonl(lower_32_bits(rxq_id_mask));
+	ll_req.q_id_mask[1] = htonl(upper_32_bits(rxq_id_mask));
+
+	/* send to f/w */
+	return bna_mbox_send(dev, &ll_req, sizeof(ll_req), dev->cbarg);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *  bna_cq_config()
+ *
+ *  For CQ "cq_id", it configures the Rx-Completion Queue as specified by
+ *  "cfg_ptr".
+ *-----------------------------------------------------------------------------
+ */
+void bna_cq_config(struct bna_dev *dev, struct bna_cq *q_ptr,
+	unsigned int cq_id, const struct bna_cq_config *cfg_ptr)
+{
+	struct bna_cq_mem cq_cfg, *cq_mem;
+	const struct bna_qpt *qpt = &cfg_ptr->qpt;
+	struct bna_dma_addr cur_q_addr;
+	u32 pg_num;
+
+	BUG_ON(!(cq_id < BNA_CQ_ID_MAX));
+
+	BUG_ON(!(BNA_POWER_OF_2(q_ptr->q.q_depth)));
+
+	cur_q_addr = *((struct bna_dma_addr *)(qpt->kv_qpt_ptr));
+
+	/*
+	 * Fill out structure, to be subsequently written
+	 * to hardware
+	 */
+	cq_cfg.pg_tbl_addr_lo = qpt->hw_qpt_ptr.lsb;
+	cq_cfg.pg_tbl_addr_hi = qpt->hw_qpt_ptr.msb;
+	cq_cfg.cur_q_entry_lo = cur_q_addr.lsb;
+	cq_cfg.cur_q_entry_hi = cur_q_addr.msb;
+
+	cq_cfg.pg_cnt_n_prd_ptr = (qpt->page_count << 16) | 0x0;
+	cq_cfg.entry_n_pg_size =
+		((BNA_CQ_ENTRY_SIZE >> 2) << 16) | (qpt->page_size >> 2);
+	cq_cfg.int_blk_n_cns_ptr =
+		((((u8) cfg_ptr->
+		   ib_seg_index) << 24) | (((u8) cfg_ptr->
+					    ib_id) << 16) | 0x0);
+	cq_cfg.q_state = BNA_Q_IDLE_STATE;
+
+	/* Write the page number register */
+	pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + dev->port,
+				  HQM_CQ_RAM_BASE_OFFSET);
+
+	writel(pg_num, dev->regs.page_addr);
+	/* H/W write */
+	cq_mem = (struct bna_cq_mem *)
+		BNA_GET_MEM_BASE_ADDR(dev->bar0, HQM_CQ_RAM_BASE_OFFSET);
+	writel(htonl(cq_cfg.pg_tbl_addr_lo), &cq_mem[cq_id].pg_tbl_addr_lo);
+	writel(htonl(cq_cfg.pg_tbl_addr_hi), &cq_mem[cq_id].pg_tbl_addr_hi);
+	writel(htonl(cq_cfg.cur_q_entry_lo), &cq_mem[cq_id].cur_q_entry_lo);
+	writel(htonl(cq_cfg.cur_q_entry_hi), &cq_mem[cq_id].cur_q_entry_hi);
+
+	writel(cq_cfg.pg_cnt_n_prd_ptr, &cq_mem[cq_id].pg_cnt_n_prd_ptr);
+	writel(cq_cfg.entry_n_pg_size, &cq_mem[cq_id].entry_n_pg_size);
+	writel(cq_cfg.int_blk_n_cns_ptr, &cq_mem[cq_id].int_blk_n_cns_ptr);
+	writel(cq_cfg.q_state, &cq_mem[cq_id].q_state);
+
+	q_ptr->q.producer_index = 0;
+	q_ptr->q.consumer_index = 0;
+
+}
+
+/*
+ * bna_ib_idx_reset()
+ *
+ *   For the specified IB, it clears the IB index
+ *
+ * @param[in] cfg_ptr - pointer to IB Configuration Structure.
+ *
+ * @return void
+ */
+void
+bna_ib_idx_reset(struct bna_dev *dev,
+	const struct bna_ib_config *cfg_ptr)
+{
+	u32 i, pg_num, *ib_idx;
+
+	pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + dev->port,
+				  HQM_INDX_TBL_RAM_BASE_OFFSET);
+	writel(pg_num, dev->regs.page_addr);
+
+	ib_idx = (u32 *)
+		BNA_GET_MEM_BASE_ADDR(dev->bar0, HQM_INDX_TBL_RAM_BASE_OFFSET);
+	ib_idx += cfg_ptr->index_table_offset;
+	for (i = 0; i < cfg_ptr->seg_size; i++)
+		*ib_idx++ = 0;
+}
+
+/*
+ * bna_ib_config_set()
+ *
+ *   For IB "ib_id", it configures the Interrupt Block specified by "cfg_ptr".
+ *
+ * @param[in] ib_ptr  - pointer to IB Data Structure.
+ * @param[in] ib_id   - interrupt-block ID
+ * @param[in] cfg_ptr - pointer to IB Configuration Structure.
+ *
+ * @return void
+ */
+void bna_ib_config_set(struct bna_dev *dev, struct bna_ib *ib_ptr,
+	unsigned int ib_id, const struct bna_ib_config *cfg_ptr)
+{
+	struct bna_ib_blk_mem ib_cfg, *ib_mem;
+	u32 pg_num;
+	struct bna_doorbell_qset *qset;
+
+	BUG_ON(!(ib_id < BNA_IB_ID_MAX));
+
+	ib_cfg.host_addr_lo = (u32) (cfg_ptr->ib_seg_addr.lsb);
+	ib_cfg.host_addr_hi = (u32) (cfg_ptr->ib_seg_addr.msb);
+
+	ib_cfg.clsc_n_ctrl_n_msix =
+		((cfg_ptr->coalescing_timer << 16) | (cfg_ptr->
+		control_flags << 8) |
+		(cfg_ptr->msix_vector));
+	ib_cfg.ipkt_n_ent_n_idxof =
+		((cfg_ptr->interpkt_timer & 0xf) << 16) | (cfg_ptr->
+		seg_size << 8) |
+		(cfg_ptr->index_table_offset);
+	ib_cfg.ipkt_cnt_cfg_n_unacked = (cfg_ptr->interpkt_count << 24);
+
+	/* Write the page number register */
+	pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + dev->port,
+				  HQM_IB_RAM_BASE_OFFSET);
+	writel(pg_num, dev->regs.page_addr);
+
+	ib_mem = (struct bna_ib_blk_mem *)
+		BNA_GET_MEM_BASE_ADDR(dev->bar0, HQM_IB_RAM_BASE_OFFSET);
+
+	writel(htonl(ib_cfg.host_addr_lo), &ib_mem[ib_id].host_addr_lo);
+	writel(htonl(ib_cfg.host_addr_hi), &ib_mem[ib_id].host_addr_hi);
+
+	writel(ib_cfg.clsc_n_ctrl_n_msix, &ib_mem[ib_id].clsc_n_ctrl_n_msix);
+	writel(ib_cfg.ipkt_n_ent_n_idxof, &ib_mem[ib_id].ipkt_n_ent_n_idxof);
+	writel(ib_cfg.ipkt_cnt_cfg_n_unacked,
+				&ib_mem[ib_id].ipkt_cnt_cfg_n_unacked);
+
+	qset = (struct bna_doorbell_qset *)
+		BNA_GET_DOORBELL_BASE_ADDR(dev->bar0);
+	ib_ptr->doorbell_addr =
+		(&qset[ib_id >> 1].ib0[(ib_id & 0x1) * (0x20 >> 2)]);
+
+	ib_ptr->doorbell_ack =
+		BNA_DOORBELL_IB_INT_ACK(cfg_ptr->coalescing_timer, 0);
+
+	bna_ib_idx_reset(dev, cfg_ptr);
+}
+
+/*
+ * bna_ib_disable()
+ *
+ *   Disables the Interrupt Block "ib_id".
+ *
+ * @param[in] ib_ptr  - pointer to IB Data Structure.
+ *
+ * @return void
+ */
+void
+bna_ib_disable(struct bna_dev *bna_dev, const struct bna_ib *ib_ptr)
+{
+	writel(BNA_DOORBELL_IB_INT_DISABLE, ib_ptr->doorbell_addr);
+}