Netdev List
 help / color / mirror / Atom feed
* [PATCH 3/6] bna: Brocade 10Gb Ethernet device driver
From: Rasesh Mody @ 2010-08-11  4:36 UTC (permalink / raw)
  To: netdev; +Cc: adapter_linux_open_src_team

From: Rasesh Mody <rmody@brocade.com>

This is patch 3/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: Rasesh Mody <rmody@brocade.com>
---
 bfa_cee.c   |  407 +++++
 bna_txrx.c  | 4209 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 cna_fwimg.c |   64 
 3 files changed, 4680 insertions(+)

diff -ruP net-next-2.6.35-rc1-orig/drivers/net/bna/bfa_cee.c net-next-2.6.35-rc1-mod/drivers/net/bna/bfa_cee.c
--- net-next-2.6.35-rc1-orig/drivers/net/bna/bfa_cee.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.35-rc1-mod/drivers/net/bna/bfa_cee.c	2010-08-10 12:23:09.427214000 -0700
@@ -0,0 +1,407 @@
+/*
+ * 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) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#include "bfa_defs_cna.h"
+#include "cna.h"
+#include "bfa_cee.h"
+#include "bfi_cna.h"
+#include "bfa_ioc.h"
+
+#define bfa_ioc_portid(__ioc) ((__ioc)->port_id)
+#define bfa_lpuid(__arg) bfa_ioc_portid(&(__arg)->ioc)
+
+static void bfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg *lldp_cfg);
+static void bfa_cee_format_cee_cfg(void *buffer);
+
+static void
+bfa_cee_format_cee_cfg(void *buffer)
+{
+	struct bfa_cee_attr *cee_cfg = buffer;
+	bfa_cee_format_lldp_cfg(&cee_cfg->lldp_remote);
+}
+
+static void
+bfa_cee_stats_swap(struct bfa_cee_stats *stats)
+{
+	u32 *buffer = (u32 *)stats;
+	int i;
+
+	for (i = 0; i < (sizeof(struct bfa_cee_stats) / sizeof(u32));
+		i++) {
+		buffer[i] = ntohl(buffer[i]);
+	}
+}
+
+static void
+bfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg *lldp_cfg)
+{
+	lldp_cfg->time_to_live =
+			ntohs(lldp_cfg->time_to_live);
+	lldp_cfg->enabled_system_cap =
+			ntohs(lldp_cfg->enabled_system_cap);
+}
+
+/**
+ * bfa_cee_attr_meminfo()
+ *
+ * @brief Returns the size of the DMA memory needed by CEE attributes
+ *
+ * @param[in] void
+ *
+ * @return Size of DMA region
+ */
+static u32
+bfa_cee_attr_meminfo(void)
+{
+	return roundup(sizeof(struct bfa_cee_attr), BFA_DMA_ALIGN_SZ);
+}
+/**
+ * bfa_cee_stats_meminfo()
+ *
+ * @brief Returns the size of the DMA memory needed by CEE stats
+ *
+ * @param[in] void
+ *
+ * @return Size of DMA region
+ */
+static u32
+bfa_cee_stats_meminfo(void)
+{
+	return roundup(sizeof(struct bfa_cee_stats), BFA_DMA_ALIGN_SZ);
+}
+
+/**
+ * bfa_cee_get_attr_isr()
+ *
+ * @brief CEE ISR for get-attributes responses from f/w
+ *
+ * @param[in] cee - Pointer to the CEE module
+ *            status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_cee_get_attr_isr(struct bfa_cee *cee, enum bfa_status status)
+{
+	cee->get_attr_status = status;
+	if (status == BFA_STATUS_OK) {
+		memcpy(cee->attr, cee->attr_dma.kva,
+		    sizeof(struct bfa_cee_attr));
+		bfa_cee_format_cee_cfg(cee->attr);
+	}
+	cee->get_attr_pending = false;
+	if (cee->cbfn.get_attr_cbfn)
+		cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg, status);
+}
+
+/**
+ * bfa_cee_get_attr_isr()
+ *
+ * @brief CEE ISR for get-stats responses from f/w
+ *
+ * @param[in] cee - Pointer to the CEE module
+ *            status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_cee_get_stats_isr(struct bfa_cee *cee, enum bfa_status status)
+{
+	cee->get_stats_status = status;
+	if (status == BFA_STATUS_OK) {
+		memcpy(cee->stats, cee->stats_dma.kva,
+			sizeof(struct bfa_cee_stats));
+		bfa_cee_stats_swap(cee->stats);
+	}
+	cee->get_stats_pending = false;
+	if (cee->cbfn.get_stats_cbfn)
+		cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg, status);
+}
+
+/**
+ * bfa_cee_get_attr_isr()
+ *
+ * @brief CEE ISR for reset-stats responses from f/w
+ *
+ * @param[in] cee - Pointer to the CEE module
+ *            status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_cee_reset_stats_isr(struct bfa_cee *cee, enum bfa_status status)
+{
+	cee->reset_stats_status = status;
+	cee->reset_stats_pending = false;
+	if (cee->cbfn.reset_stats_cbfn)
+		cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg, status);
+}
+/**
+ * bfa_cee_meminfo()
+ *
+ * @brief Returns the size of the DMA memory needed by CEE module
+ *
+ * @param[in] void
+ *
+ * @return Size of DMA region
+ */
+u32
+bfa_cee_meminfo(void)
+{
+	return bfa_cee_attr_meminfo() + bfa_cee_stats_meminfo();
+}
+
+/**
+ * bfa_cee_mem_claim()
+ *
+ * @brief Initialized CEE DMA Memory
+ *
+ * @param[in] cee CEE module pointer
+ *	      dma_kva Kernel Virtual Address of CEE DMA Memory
+ *	      dma_pa  Physical Address of CEE DMA Memory
+ *
+ * @return void
+ */
+void
+bfa_cee_mem_claim(struct bfa_cee *cee, u8 *dma_kva, u64 dma_pa)
+{
+	cee->attr_dma.kva = dma_kva;
+	cee->attr_dma.pa = dma_pa;
+	cee->stats_dma.kva = dma_kva + bfa_cee_attr_meminfo();
+	cee->stats_dma.pa = dma_pa + bfa_cee_attr_meminfo();
+	cee->attr = (struct bfa_cee_attr *) dma_kva;
+	cee->stats = (struct bfa_cee_stats *)
+		(dma_kva + bfa_cee_attr_meminfo());
+}
+
+/**
+ * bfa_cee_get_attr()
+ *
+ * @brief
+ *   Send the request to the f/w to fetch CEE attributes.
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return Status
+ */
+
+enum bfa_status
+bfa_cee_get_attr(struct bfa_cee *cee, struct bfa_cee_attr *attr,
+		     bfa_cee_get_attr_cbfn_t cbfn, void *cbarg)
+{
+	struct bfi_cee_get_req *cmd;
+
+	BUG_ON(!((cee != NULL) && (cee->ioc != NULL)));
+	if (!bfa_ioc_is_operational(cee->ioc))
+		return BFA_STATUS_IOC_FAILURE;
+	if (cee->get_attr_pending == true)
+		return 	BFA_STATUS_DEVBUSY;
+	cee->get_attr_pending = true;
+	cmd = (struct bfi_cee_get_req *) cee->get_cfg_mb.msg;
+	cee->attr = attr;
+	cee->cbfn.get_attr_cbfn = cbfn;
+	cee->cbfn.get_attr_cbarg = cbarg;
+	bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_CFG_REQ,
+	    bfa_ioc_portid(cee->ioc));
+	bfa_dma_be_addr_set(cmd->dma_addr, cee->attr_dma.pa);
+	bfa_ioc_mbox_queue(cee->ioc, &cee->get_cfg_mb);
+
+	return BFA_STATUS_OK;
+}
+
+/**
+ * bfa_cee_get_stats()
+ *
+ * @brief
+ *   Send the request to the f/w to fetch CEE statistics.
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return Status
+ */
+
+enum bfa_status
+bfa_cee_get_stats(struct bfa_cee *cee, struct bfa_cee_stats *stats,
+		      bfa_cee_get_stats_cbfn_t cbfn, void *cbarg)
+{
+	struct bfi_cee_get_req *cmd;
+
+	BUG_ON(!((cee != NULL) && (cee->ioc != NULL)));
+
+	if (!bfa_ioc_is_operational(cee->ioc))
+		return BFA_STATUS_IOC_FAILURE;
+	if (cee->get_stats_pending == true)
+		return 	BFA_STATUS_DEVBUSY;
+	cee->get_stats_pending = true;
+	cmd = (struct bfi_cee_get_req *) cee->get_stats_mb.msg;
+	cee->stats = stats;
+	cee->cbfn.get_stats_cbfn = cbfn;
+	cee->cbfn.get_stats_cbarg = cbarg;
+	bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_STATS_REQ,
+	    bfa_ioc_portid(cee->ioc));
+	bfa_dma_be_addr_set(cmd->dma_addr, cee->stats_dma.pa);
+	bfa_ioc_mbox_queue(cee->ioc, &cee->get_stats_mb);
+
+	return BFA_STATUS_OK;
+}
+
+/**
+ * bfa_cee_reset_stats()
+ *
+ * @brief Clears CEE Stats in the f/w.
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return Status
+ */
+
+enum bfa_status
+bfa_cee_reset_stats(struct bfa_cee *cee, bfa_cee_reset_stats_cbfn_t cbfn,
+			void *cbarg)
+{
+	struct bfi_cee_reset_stats *cmd;
+
+	BUG_ON(!((cee != NULL) && (cee->ioc != NULL)));
+	if (!bfa_ioc_is_operational(cee->ioc))
+		return BFA_STATUS_IOC_FAILURE;
+	if (cee->reset_stats_pending == true)
+		return 	BFA_STATUS_DEVBUSY;
+	cee->reset_stats_pending = true;
+	cmd = (struct bfi_cee_reset_stats *) cee->reset_stats_mb.msg;
+	cee->cbfn.reset_stats_cbfn = cbfn;
+	cee->cbfn.reset_stats_cbarg = cbarg;
+	bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_RESET_STATS,
+	    bfa_ioc_portid(cee->ioc));
+	bfa_ioc_mbox_queue(cee->ioc, &cee->reset_stats_mb);
+	return BFA_STATUS_OK;
+}
+
+/**
+ * bfa_cee_isrs()
+ *
+ * @brief Handles Mail-box interrupts for CEE module.
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return void
+ */
+
+void
+bfa_cee_isr(void *cbarg, struct bfi_mbmsg *m)
+{
+	union bfi_cee_i2h_msg_u *msg;
+	struct bfi_cee_get_rsp *get_rsp;
+	struct bfa_cee *cee = (struct bfa_cee *) cbarg;
+	msg = (union bfi_cee_i2h_msg_u *) m;
+	get_rsp = (struct bfi_cee_get_rsp *) m;
+	switch (msg->mh.msg_id) {
+	case BFI_CEE_I2H_GET_CFG_RSP:
+		bfa_cee_get_attr_isr(cee, get_rsp->cmd_status);
+		break;
+	case BFI_CEE_I2H_GET_STATS_RSP:
+		bfa_cee_get_stats_isr(cee, get_rsp->cmd_status);
+		break;
+	case BFI_CEE_I2H_RESET_STATS_RSP:
+		bfa_cee_reset_stats_isr(cee, get_rsp->cmd_status);
+		break;
+	default:
+		BUG_ON(1);
+	}
+}
+
+/**
+ * bfa_cee_hbfail()
+ *
+ * @brief CEE module heart-beat failure handler.
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return void
+ */
+
+void
+bfa_cee_hbfail(void *arg)
+{
+	struct bfa_cee *cee;
+	cee = (struct bfa_cee *) arg;
+
+	if (cee->get_attr_pending == true) {
+		cee->get_attr_status = BFA_STATUS_FAILED;
+		cee->get_attr_pending  = false;
+		if (cee->cbfn.get_attr_cbfn) {
+			cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg,
+			    BFA_STATUS_FAILED);
+		}
+	}
+	if (cee->get_stats_pending == true) {
+		cee->get_stats_status = BFA_STATUS_FAILED;
+		cee->get_stats_pending  = false;
+		if (cee->cbfn.get_stats_cbfn) {
+			cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg,
+			    BFA_STATUS_FAILED);
+		}
+	}
+	if (cee->reset_stats_pending == true) {
+		cee->reset_stats_status = BFA_STATUS_FAILED;
+		cee->reset_stats_pending  = false;
+		if (cee->cbfn.reset_stats_cbfn) {
+			cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg,
+			    BFA_STATUS_FAILED);
+		}
+	}
+}
+
+/**
+ * bfa_cee_attach()
+ *
+ * @brief CEE module-attach API
+ *
+ * @param[in] cee - Pointer to the CEE module data structure
+ *            ioc - Pointer to the ioc module data structure
+ *            dev - Pointer to the device driver module data structure
+ *                  The device driver specific mbox ISR functions have
+ *                  this pointer as one of the parameters.
+ *
+ * @return void
+ */
+void
+bfa_cee_attach(struct bfa_cee *cee, struct bfa_ioc *ioc,
+		void *dev)
+{
+	BUG_ON(!(cee != NULL));
+	cee->dev = dev;
+	cee->ioc = ioc;
+
+	bfa_ioc_mbox_regisr(cee->ioc, BFI_MC_CEE, bfa_cee_isr, cee);
+	bfa_ioc_hbfail_init(&cee->hbfail, bfa_cee_hbfail, cee);
+	bfa_ioc_hbfail_register(cee->ioc, &cee->hbfail);
+}
+
+/**
+ * bfa_cee_detach()
+ *
+ * @brief CEE module-detach API
+ *
+ * @param[in] cee - Pointer to the CEE module data structure
+ *
+ * @return void
+ */
+void
+bfa_cee_detach(struct bfa_cee *cee)
+{
+}
diff -ruP net-next-2.6.35-rc1-orig/drivers/net/bna/bna_txrx.c net-next-2.6.35-rc1-mod/drivers/net/bna/bna_txrx.c
--- net-next-2.6.35-rc1-orig/drivers/net/bna/bna_txrx.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.35-rc1-mod/drivers/net/bna/bna_txrx.c	2010-08-10 12:23:09.409220000 -0700
@@ -0,0 +1,4209 @@
+/*
+ * 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) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#include "bna.h"
+#include "bfa_sm.h"
+#include "bfi.h"
+
+/**
+ * IB
+ */
+#define bna_ib_find_free_ibidx(_mask, _pos)\
+do {\
+	(_pos) = 0;\
+	while (((_pos) < (BFI_IBIDX_MAX_SEGSIZE)) &&\
+		((1 << (_pos)) & (_mask)))\
+		(_pos)++;\
+} while (0)
+
+#define bna_ib_count_ibidx(_mask, _count)\
+do {\
+	int pos = 0;\
+	(_count) = 0;\
+	while (pos < (BFI_IBIDX_MAX_SEGSIZE)) {\
+		if ((1 << pos) & (_mask))\
+			(_count) = pos + 1;\
+		pos++;\
+	} \
+} while (0)
+
+#define bna_ib_select_segpool(_count, _q_idx)\
+do {\
+	int i;\
+	(_q_idx) = -1;\
+	for (i = 0; i < BFI_IBIDX_TOTAL_POOLS; i++) {\
+		if ((_count <= ibidx_pool[i].pool_entry_size)) {\
+			(_q_idx) = i;\
+			break;\
+		} \
+	} \
+} while (0)
+
+struct bna_ibidx_pool {
+	int	pool_size;
+	int	pool_entry_size;
+};
+init_ibidx_pool(ibidx_pool);
+
+static struct bna_intr *
+bna_intr_get(struct bna_ib_mod *ib_mod, enum bna_intr_type intr_type,
+		int vector)
+{
+	struct bna_intr *intr;
+	struct list_head *qe;
+
+	list_for_each(qe, &ib_mod->intr_active_q) {
+		intr = (struct bna_intr *)qe;
+
+		if ((intr->intr_type == intr_type) &&
+			(intr->vector == vector)) {
+			intr->ref_count++;
+			return intr;
+		}
+	}
+
+	if (list_empty(&ib_mod->intr_free_q))
+		return NULL;
+
+	bfa_q_deq(&ib_mod->intr_free_q, &intr);
+	bfa_q_qe_init(&intr->qe);
+
+	intr->ref_count = 1;
+	intr->intr_type = intr_type;
+	intr->vector = vector;
+
+	list_add_tail(&intr->qe, &ib_mod->intr_active_q);
+
+	return intr;
+}
+
+static void
+bna_intr_put(struct bna_ib_mod *ib_mod,
+		struct bna_intr *intr)
+{
+	intr->ref_count--;
+
+	if (intr->ref_count == 0) {
+		intr->ib = NULL;
+		list_del(&intr->qe);
+		bfa_q_qe_init(&intr->qe);
+		list_add_tail(&intr->qe, &ib_mod->intr_free_q);
+	}
+}
+
+void
+bna_ib_mod_init(struct bna_ib_mod *ib_mod, struct bna *bna,
+		struct bna_res_info *res_info)
+{
+	int i;
+	int j;
+	int count;
+	u8 offset;
+	struct bna_doorbell_qset *qset;
+	unsigned long off;
+
+	ib_mod->bna = bna;
+
+	ib_mod->ib = (struct bna_ib *)
+		res_info[BNA_RES_MEM_T_IB_ARRAY].res_u.mem_info.mdl[0].kva;
+	ib_mod->intr = (struct bna_intr *)
+		res_info[BNA_RES_MEM_T_INTR_ARRAY].res_u.mem_info.mdl[0].kva;
+	ib_mod->idx_seg = (struct bna_ibidx_seg *)
+		res_info[BNA_RES_MEM_T_IDXSEG_ARRAY].res_u.mem_info.mdl[0].kva;
+
+	INIT_LIST_HEAD(&ib_mod->ib_free_q);
+	INIT_LIST_HEAD(&ib_mod->intr_free_q);
+	INIT_LIST_HEAD(&ib_mod->intr_active_q);
+
+	for (i = 0; i < BFI_IBIDX_TOTAL_POOLS; i++)
+		INIT_LIST_HEAD(&ib_mod->ibidx_seg_pool[i]);
+
+	for (i = 0; i < BFI_MAX_IB; i++) {
+		ib_mod->ib[i].ib_id = i;
+
+		ib_mod->ib[i].ib_seg_host_addr_kva =
+		res_info[BNA_RES_MEM_T_IBIDX].res_u.mem_info.mdl[i].kva;
+		ib_mod->ib[i].ib_seg_host_addr.lsb =
+		res_info[BNA_RES_MEM_T_IBIDX].res_u.mem_info.mdl[i].dma.lsb;
+		ib_mod->ib[i].ib_seg_host_addr.msb =
+		res_info[BNA_RES_MEM_T_IBIDX].res_u.mem_info.mdl[i].dma.msb;
+
+		qset = (struct bna_doorbell_qset *)0;
+		off = (unsigned long)(&qset[i >> 1].ib0[(i & 0x1)
+					* (0x20 >> 2)]);
+		ib_mod->ib[i].door_bell.doorbell_addr = off +
+			BNA_GET_DOORBELL_BASE_ADDR(bna->pcidev.pci_bar_kva);
+
+		bfa_q_qe_init(&ib_mod->ib[i].qe);
+		list_add_tail(&ib_mod->ib[i].qe, &ib_mod->ib_free_q);
+
+		bfa_q_qe_init(&ib_mod->intr[i].qe);
+		list_add_tail(&ib_mod->intr[i].qe, &ib_mod->intr_free_q);
+	}
+
+	count = 0;
+	offset = 0;
+	for (i = 0; i < BFI_IBIDX_TOTAL_POOLS; i++) {
+		for (j = 0; j < ibidx_pool[i].pool_size; j++) {
+			bfa_q_qe_init(&ib_mod->idx_seg[count]);
+			ib_mod->idx_seg[count].ib_seg_size =
+					ibidx_pool[i].pool_entry_size;
+			ib_mod->idx_seg[count].ib_idx_tbl_offset = offset;
+			list_add_tail(&ib_mod->idx_seg[count].qe,
+				&ib_mod->ibidx_seg_pool[i]);
+			count++;
+			offset += ibidx_pool[i].pool_entry_size;
+		}
+	}
+}
+
+void
+bna_ib_mod_uninit(struct bna_ib_mod *ib_mod)
+{
+	int i;
+	int j;
+	struct list_head *qe;
+
+	i = 0;
+	list_for_each(qe, &ib_mod->ib_free_q)
+		i++;
+
+	i = 0;
+	list_for_each(qe, &ib_mod->intr_free_q)
+		i++;
+
+	for (i = 0; i < BFI_IBIDX_TOTAL_POOLS; i++) {
+		j = 0;
+		list_for_each(qe, &ib_mod->ibidx_seg_pool[i])
+			j++;
+	}
+
+	ib_mod->bna = NULL;
+}
+
+struct bna_ib *
+bna_ib_get(struct bna_ib_mod *ib_mod,
+		enum bna_intr_type intr_type,
+		int vector)
+{
+	struct bna_ib *ib;
+	struct bna_intr *intr;
+
+	if (intr_type == BNA_INTR_T_INTX)
+		vector = (1 << vector);
+
+	intr = bna_intr_get(ib_mod, intr_type, vector);
+	if (intr == NULL)
+		return NULL;
+
+	if (intr->ib) {
+		if (intr->ib->ref_count == BFI_IBIDX_MAX_SEGSIZE) {
+			bna_intr_put(ib_mod, intr);
+			return NULL;
+		}
+		intr->ib->ref_count++;
+		return intr->ib;
+	}
+
+	if (list_empty(&ib_mod->ib_free_q)) {
+		bna_intr_put(ib_mod, intr);
+		return NULL;
+	}
+
+	bfa_q_deq(&ib_mod->ib_free_q, &ib);
+	bfa_q_qe_init(&ib->qe);
+
+	ib->ref_count = 1;
+	ib->start_count = 0;
+	ib->idx_mask = 0;
+
+	ib->intr = intr;
+	ib->idx_seg = NULL;
+	intr->ib = ib;
+
+	ib->bna = ib_mod->bna;
+
+	return ib;
+}
+
+void
+bna_ib_put(struct bna_ib_mod *ib_mod, struct bna_ib *ib)
+{
+	bna_intr_put(ib_mod, ib->intr);
+
+	ib->ref_count--;
+
+	if (ib->ref_count == 0) {
+		ib->intr = NULL;
+		ib->bna = NULL;
+		list_add_tail(&ib->qe, &ib_mod->ib_free_q);
+	}
+}
+
+/* Returns index offset - starting from 0 */
+int
+bna_ib_reserve_idx(struct bna_ib *ib)
+{
+	struct bna_ib_mod *ib_mod = &ib->bna->ib_mod;
+	struct bna_ibidx_seg *idx_seg;
+	int idx;
+	int num_idx;
+	int q_idx;
+
+	/* Find the first free index position */
+	bna_ib_find_free_ibidx(ib->idx_mask, idx);
+	if (idx == BFI_IBIDX_MAX_SEGSIZE)
+		return -1;
+
+	/*
+	 * Calculate the total number of indexes held by this IB,
+	 * including the index newly reserved above.
+	 */
+	bna_ib_count_ibidx((ib->idx_mask | (1 << idx)), num_idx);
+
+	/* See if there is a free space in the index segment held by this IB */
+	if (ib->idx_seg && (num_idx <= ib->idx_seg->ib_seg_size)) {
+		ib->idx_mask |= (1 << idx);
+		return idx;
+	}
+
+	if (ib->start_count)
+		return -1;
+
+	/* Allocate a new segment */
+	bna_ib_select_segpool(num_idx, q_idx);
+	while (1) {
+		if (q_idx == BFI_IBIDX_TOTAL_POOLS)
+			return -1;
+		if (!list_empty(&ib_mod->ibidx_seg_pool[q_idx]))
+			break;
+		q_idx++;
+	}
+	bfa_q_deq(&ib_mod->ibidx_seg_pool[q_idx], &idx_seg);
+	bfa_q_qe_init(&idx_seg->qe);
+
+	/* Free the old segment */
+	if (ib->idx_seg) {
+		bna_ib_select_segpool(ib->idx_seg->ib_seg_size, q_idx);
+		list_add_tail(&ib->idx_seg->qe, &ib_mod->ibidx_seg_pool[q_idx]);
+	}
+
+	ib->idx_seg = idx_seg;
+
+	ib->idx_mask |= (1 << idx);
+
+	return idx;
+}
+
+void
+bna_ib_release_idx(struct bna_ib *ib, int idx)
+{
+	struct bna_ib_mod *ib_mod = &ib->bna->ib_mod;
+	struct bna_ibidx_seg *idx_seg;
+	int num_idx;
+	int cur_q_idx;
+	int new_q_idx;
+
+	ib->idx_mask &= ~(1 << idx);
+
+	if (ib->start_count)
+		return;
+
+	bna_ib_count_ibidx(ib->idx_mask, num_idx);
+
+	/*
+	 * Free the segment, if there are no more indexes in the segment
+	 * held by this IB
+	 */
+	if (!num_idx) {
+		bna_ib_select_segpool(ib->idx_seg->ib_seg_size, cur_q_idx);
+		list_add_tail(&ib->idx_seg->qe,
+			&ib_mod->ibidx_seg_pool[cur_q_idx]);
+		ib->idx_seg = NULL;
+		return;
+	}
+
+	/* See if we can move to a smaller segment */
+	bna_ib_select_segpool(num_idx, new_q_idx);
+	bna_ib_select_segpool(ib->idx_seg->ib_seg_size, cur_q_idx);
+	while (new_q_idx < cur_q_idx) {
+		if (!list_empty(&ib_mod->ibidx_seg_pool[new_q_idx]))
+			break;
+		new_q_idx++;
+	}
+	if (new_q_idx < cur_q_idx) {
+		/* Select the new smaller segment */
+		bfa_q_deq(&ib_mod->ibidx_seg_pool[new_q_idx], &idx_seg);
+		bfa_q_qe_init(&idx_seg->qe);
+		/* Free the old segment */
+		list_add_tail(&ib->idx_seg->qe,
+			&ib_mod->ibidx_seg_pool[cur_q_idx]);
+		ib->idx_seg = idx_seg;
+	}
+}
+
+int
+bna_ib_config(struct bna_ib *ib, struct bna_ib_config *ib_config)
+{
+	if (ib->start_count)
+		return -1;
+
+	ib->ib_config.coalescing_timeo = ib_config->coalescing_timeo;
+	ib->ib_config.interpkt_timeo = ib_config->interpkt_timeo;
+	ib->ib_config.interpkt_count = ib_config->interpkt_count;
+	ib->ib_config.ctrl_flags = ib_config->ctrl_flags;
+
+	ib->ib_config.ctrl_flags |= BFI_IB_CF_MASTER_ENABLE;
+	if (ib->intr->intr_type == BNA_INTR_T_MSIX)
+		ib->ib_config.ctrl_flags |= BFI_IB_CF_MSIX_MODE;
+
+	return 0;
+}
+
+void
+bna_ib_start(struct bna_ib *ib)
+{
+	struct bna_ib_blk_mem ib_cfg;
+	struct bna_ib_blk_mem *ib_mem;
+	u32 pg_num;
+	u32 intx_mask;
+	int i;
+	void __iomem *base_addr;
+	unsigned long off;
+
+	ib->start_count++;
+
+	if (ib->start_count > 1)
+		return;
+
+	ib_cfg.host_addr_lo = (u32)(ib->ib_seg_host_addr.lsb);
+	ib_cfg.host_addr_hi = (u32)(ib->ib_seg_host_addr.msb);
+
+	ib_cfg.clsc_n_ctrl_n_msix = (((u32)
+				     ib->ib_config.coalescing_timeo << 16) |
+				((u32)ib->ib_config.ctrl_flags << 8) |
+				(ib->intr->vector));
+	ib_cfg.ipkt_n_ent_n_idxof =
+				((u32)
+				 (ib->ib_config.interpkt_timeo & 0xf) << 16) |
+				((u32)ib->idx_seg->ib_seg_size << 8) |
+				(ib->idx_seg->ib_idx_tbl_offset);
+	ib_cfg.ipkt_cnt_cfg_n_unacked = ((u32)
+					 ib->ib_config.interpkt_count << 24);
+
+	pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + ib->bna->port_num,
+				HQM_IB_RAM_BASE_OFFSET);
+	writel(pg_num, ib->bna->regs.page_addr);
+
+	base_addr = BNA_GET_MEM_BASE_ADDR(ib->bna->pcidev.pci_bar_kva,
+					HQM_IB_RAM_BASE_OFFSET);
+
+	ib_mem = (struct bna_ib_blk_mem *)0;
+	off = (unsigned long)&ib_mem[ib->ib_id].host_addr_lo;
+	writel(htonl(ib_cfg.host_addr_lo), base_addr + off);
+
+	off = (unsigned long)&ib_mem[ib->ib_id].host_addr_hi;
+	writel(htonl(ib_cfg.host_addr_hi), base_addr + off);
+
+	off = (unsigned long)&ib_mem[ib->ib_id].clsc_n_ctrl_n_msix;
+	writel(ib_cfg.clsc_n_ctrl_n_msix, base_addr + off);
+
+	off = (unsigned long)&ib_mem[ib->ib_id].ipkt_n_ent_n_idxof;
+	writel(ib_cfg.ipkt_n_ent_n_idxof, base_addr + off);
+
+	off = (unsigned long)&ib_mem[ib->ib_id].ipkt_cnt_cfg_n_unacked;
+	writel(ib_cfg.ipkt_cnt_cfg_n_unacked, base_addr + off);
+
+	ib->door_bell.doorbell_ack = BNA_DOORBELL_IB_INT_ACK(
+				(u32)ib->ib_config.coalescing_timeo, 0);
+
+	pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + ib->bna->port_num,
+				HQM_INDX_TBL_RAM_BASE_OFFSET);
+	writel(pg_num, ib->bna->regs.page_addr);
+
+	base_addr = BNA_GET_MEM_BASE_ADDR(ib->bna->pcidev.pci_bar_kva,
+					HQM_INDX_TBL_RAM_BASE_OFFSET);
+	for (i = 0; i < ib->idx_seg->ib_seg_size; i++) {
+		off = (unsigned long)
+		((ib->idx_seg->ib_idx_tbl_offset + i) * BFI_IBIDX_SIZE);
+		writel(0, base_addr + off);
+	}
+
+	if (ib->intr->intr_type == BNA_INTR_T_INTX) {
+		bna_intx_disable(ib->bna, intx_mask);
+		intx_mask &= ~(ib->intr->vector);
+		bna_intx_enable(ib->bna, intx_mask);
+	}
+}
+
+void
+bna_ib_stop(struct bna_ib *ib)
+{
+	u32 intx_mask;
+
+	ib->start_count--;
+
+	if (ib->start_count == 0) {
+		writel(BNA_DOORBELL_IB_INT_DISABLE,
+				ib->door_bell.doorbell_addr);
+		if (ib->intr->intr_type == BNA_INTR_T_INTX) {
+			bna_intx_disable(ib->bna, intx_mask);
+			intx_mask |= (ib->intr->vector);
+			bna_intx_enable(ib->bna, intx_mask);
+		}
+	}
+}
+
+void
+bna_ib_fail(struct bna_ib *ib)
+{
+	ib->start_count = 0;
+}
+
+/**
+ * RXF
+ */
+static void rxf_enable(struct bna_rxf *rxf);
+static void rxf_disable(struct bna_rxf *rxf);
+static void __rxf_config_set(struct bna_rxf *rxf);
+static void __rxf_rit_set(struct bna_rxf *rxf);
+static void __bna_rxf_stat_clr(struct bna_rxf *rxf);
+static int rxf_process_packet_filter(struct bna_rxf *rxf);
+static int rxf_clear_packet_filter(struct bna_rxf *rxf);
+static void rxf_reset_packet_filter(struct bna_rxf *rxf);
+static void rxf_cb_enabled(void *arg, int status);
+static void rxf_cb_disabled(void *arg, int status);
+static void bna_rxf_cb_stats_cleared(void *arg, int status);
+static void __rxf_enable(struct bna_rxf *rxf);
+static void __rxf_disable(struct bna_rxf *rxf);
+
+bfa_fsm_state_decl(bna_rxf, stopped, struct bna_rxf,
+			enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, start_wait, struct bna_rxf,
+			enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, cam_fltr_mod_wait, struct bna_rxf,
+			enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, started, struct bna_rxf,
+			enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, cam_fltr_clr_wait, struct bna_rxf,
+			enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, stop_wait, struct bna_rxf,
+			enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, pause_wait, struct bna_rxf,
+			enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, resume_wait, struct bna_rxf,
+			enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, stat_clr_wait, struct bna_rxf,
+			enum bna_rxf_event);
+
+static struct bfa_sm_table rxf_sm_table[] = {
+	{BFA_SM(bna_rxf_sm_stopped), BNA_RXF_STOPPED},
+	{BFA_SM(bna_rxf_sm_start_wait), BNA_RXF_START_WAIT},
+	{BFA_SM(bna_rxf_sm_cam_fltr_mod_wait), BNA_RXF_CAM_FLTR_MOD_WAIT},
+	{BFA_SM(bna_rxf_sm_started), BNA_RXF_STARTED},
+	{BFA_SM(bna_rxf_sm_cam_fltr_clr_wait), BNA_RXF_CAM_FLTR_CLR_WAIT},
+	{BFA_SM(bna_rxf_sm_stop_wait), BNA_RXF_STOP_WAIT},
+	{BFA_SM(bna_rxf_sm_pause_wait), BNA_RXF_PAUSE_WAIT},
+	{BFA_SM(bna_rxf_sm_resume_wait), BNA_RXF_RESUME_WAIT},
+	{BFA_SM(bna_rxf_sm_stat_clr_wait), BNA_RXF_STAT_CLR_WAIT}
+};
+
+static void
+bna_rxf_sm_stopped_entry(struct bna_rxf *rxf)
+{
+	call_rxf_stop_cbfn(rxf, BNA_CB_SUCCESS);
+}
+
+static void
+bna_rxf_sm_stopped(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+	switch (event) {
+	case RXF_E_START:
+		bfa_fsm_set_state(rxf, bna_rxf_sm_start_wait);
+		break;
+
+	case RXF_E_STOP:
+		bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+		break;
+
+	case RXF_E_FAIL:
+		/* No-op */
+		break;
+
+	case RXF_E_CAM_FLTR_MOD:
+		call_rxf_cam_fltr_cbfn(rxf, BNA_CB_SUCCESS);
+		break;
+
+	case RXF_E_STARTED:
+	case RXF_E_STOPPED:
+	case RXF_E_CAM_FLTR_RESP:
+		/**
+		 * These events are received due to flushing of mbox
+		 * when device fails
+		 */
+		/* No-op */
+		break;
+
+	case RXF_E_PAUSE:
+		rxf->rxf_oper_state = BNA_RXF_OPER_STATE_PAUSED;
+		call_rxf_pause_cbfn(rxf, BNA_CB_SUCCESS);
+		break;
+
+	case RXF_E_RESUME:
+		rxf->rxf_oper_state = BNA_RXF_OPER_STATE_RUNNING;
+		call_rxf_resume_cbfn(rxf, BNA_CB_SUCCESS);
+		break;
+
+	default:
+		bfa_sm_fault(rxf->rx->bna, event);
+	}
+}
+
+static void
+bna_rxf_sm_start_wait_entry(struct bna_rxf *rxf)
+{
+	__rxf_config_set(rxf);
+	__rxf_rit_set(rxf);
+	rxf_enable(rxf);
+}
+
+static void
+bna_rxf_sm_start_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+	switch (event) {
+	case RXF_E_STOP:
+		/**
+		 * STOP is originated from bnad. When this happens,
+		 * it can not be waiting for filter update
+		 */
+		call_rxf_start_cbfn(rxf, BNA_CB_INTERRUPT);
+		bfa_fsm_set_state(rxf, bna_rxf_sm_stop_wait);
+		break;
+
+	case RXF_E_FAIL:
+		call_rxf_cam_fltr_cbfn(rxf, BNA_CB_SUCCESS);
+		call_rxf_start_cbfn(rxf, BNA_CB_FAIL);
+		bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+		break;
+
+	case RXF_E_CAM_FLTR_MOD:
+		/* No-op */
+		break;
+
+	case RXF_E_STARTED:
+		/**
+		 * Force rxf_process_filter() to go through initial
+		 * config
+		 */
+		if ((rxf->ucast_active_mac != NULL) &&
+			(rxf->ucast_pending_set == 0))
+			rxf->ucast_pending_set = 1;
+
+		if (rxf->rss_status == BNA_STATUS_T_ENABLED)
+			rxf->rxf_flags |= BNA_RXF_FL_RSS_CONFIG_PENDING;
+
+		rxf->rxf_flags |= BNA_RXF_FL_VLAN_CONFIG_PENDING;
+
+		bfa_fsm_set_state(rxf, bna_rxf_sm_cam_fltr_mod_wait);
+		break;
+
+	case RXF_E_PAUSE:
+	case RXF_E_RESUME:
+		rxf->rxf_flags |= BNA_RXF_FL_OPERSTATE_CHANGED;
+		break;
+
+	default:
+		bfa_sm_fault(rxf->rx->bna, event);
+	}
+}
+
+static void
+bna_rxf_sm_cam_fltr_mod_wait_entry(struct bna_rxf *rxf)
+{
+	if (!rxf_process_packet_filter(rxf)) {
+		/* No more pending CAM entries to update */
+		bfa_fsm_set_state(rxf, bna_rxf_sm_started);
+	}
+}
+
+static void
+bna_rxf_sm_cam_fltr_mod_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+	switch (event) {
+	case RXF_E_STOP:
+		/**
+		 * STOP is originated from bnad. When this happens,
+		 * it can not be waiting for filter update
+		 */
+		call_rxf_start_cbfn(rxf, BNA_CB_INTERRUPT);
+		bfa_fsm_set_state(rxf, bna_rxf_sm_cam_fltr_clr_wait);
+		break;
+
+	case RXF_E_FAIL:
+		rxf_reset_packet_filter(rxf);
+		call_rxf_cam_fltr_cbfn(rxf, BNA_CB_SUCCESS);
+		call_rxf_start_cbfn(rxf, BNA_CB_FAIL);
+		bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+		break;
+
+	case RXF_E_CAM_FLTR_MOD:
+		/* No-op */
+		break;
+
+	case RXF_E_CAM_FLTR_RESP:
+		if (!rxf_process_packet_filter(rxf)) {
+			/* No more pending CAM entries to update */
+			call_rxf_cam_fltr_cbfn(rxf, BNA_CB_SUCCESS);
+			bfa_fsm_set_state(rxf, bna_rxf_sm_started);
+		}
+		break;
+
+	case RXF_E_PAUSE:
+	case RXF_E_RESUME:
+		rxf->rxf_flags |= BNA_RXF_FL_OPERSTATE_CHANGED;
+		break;
+
+	default:
+		bfa_sm_fault(rxf->rx->bna, event);
+	}
+}
+
+static void
+bna_rxf_sm_started_entry(struct bna_rxf *rxf)
+{
+	call_rxf_start_cbfn(rxf, BNA_CB_SUCCESS);
+
+	if (rxf->rxf_flags & BNA_RXF_FL_OPERSTATE_CHANGED) {
+		if (rxf->rxf_oper_state == BNA_RXF_OPER_STATE_PAUSED)
+			bfa_fsm_send_event(rxf, RXF_E_PAUSE);
+		else
+			bfa_fsm_send_event(rxf, RXF_E_RESUME);
+	}
+
+}
+
+static void
+bna_rxf_sm_started(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+	switch (event) {
+	case RXF_E_STOP:
+		bfa_fsm_set_state(rxf, bna_rxf_sm_cam_fltr_clr_wait);
+		/* Hack to get FSM start clearing CAM entries */
+		bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_RESP);
+		break;
+
+	case RXF_E_FAIL:
+		rxf_reset_packet_filter(rxf);
+		bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+		break;
+
+	case RXF_E_CAM_FLTR_MOD:
+		bfa_fsm_set_state(rxf, bna_rxf_sm_cam_fltr_mod_wait);
+		break;
+
+	case RXF_E_PAUSE:
+		bfa_fsm_set_state(rxf, bna_rxf_sm_pause_wait);
+		break;
+
+	case RXF_E_RESUME:
+		bfa_fsm_set_state(rxf, bna_rxf_sm_resume_wait);
+		break;
+
+	default:
+		bfa_sm_fault(rxf->rx->bna, event);
+	}
+}
+
+static void
+bna_rxf_sm_cam_fltr_clr_wait_entry(struct bna_rxf *rxf)
+{
+	/**
+	 *  Note: Do not add rxf_clear_packet_filter here.
+	 * It will overstep mbox when this transition happens:
+	 * 	cam_fltr_mod_wait -> cam_fltr_clr_wait on RXF_E_STOP event
+	 */
+}
+
+static void
+bna_rxf_sm_cam_fltr_clr_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+	switch (event) {
+	case RXF_E_FAIL:
+		/**
+		 * FSM was in the process of stopping, initiated by
+		 * bnad. When this happens, no one can be waiting for
+		 * start or filter update
+		 */
+		rxf_reset_packet_filter(rxf);
+		bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+		break;
+
+	case RXF_E_CAM_FLTR_RESP:
+		if (!rxf_clear_packet_filter(rxf)) {
+			/* No more pending CAM entries to clear */
+			bfa_fsm_set_state(rxf, bna_rxf_sm_stop_wait);
+			rxf_disable(rxf);
+		}
+		break;
+
+	default:
+		bfa_sm_fault(rxf->rx->bna, event);
+	}
+}
+
+static void
+bna_rxf_sm_stop_wait_entry(struct bna_rxf *rxf)
+{
+	/**
+	 * NOTE: Do not add  rxf_disable here.
+	 * It will overstep mbox when this transition happens:
+	 * 	start_wait -> stop_wait on RXF_E_STOP event
+	 */
+}
+
+static void
+bna_rxf_sm_stop_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+	switch (event) {
+	case RXF_E_FAIL:
+		/**
+		 * FSM was in the process of stopping, initiated by
+		 * bnad. When this happens, no one can be waiting for
+		 * start or filter update
+		 */
+		bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+		break;
+
+	case RXF_E_STARTED:
+		/**
+		 * This event is received due to abrupt transition from
+		 * bna_rxf_sm_start_wait state on receiving
+		 * RXF_E_STOP event
+		 */
+		rxf_disable(rxf);
+		break;
+
+	case RXF_E_STOPPED:
+		/**
+		 * FSM was in the process of stopping, initiated by
+		 * bnad. When this happens, no one can be waiting for
+		 * start or filter update
+		 */
+		bfa_fsm_set_state(rxf, bna_rxf_sm_stat_clr_wait);
+		break;
+
+	case RXF_E_PAUSE:
+		rxf->rxf_oper_state = BNA_RXF_OPER_STATE_PAUSED;
+		break;
+
+	case RXF_E_RESUME:
+		rxf->rxf_oper_state = BNA_RXF_OPER_STATE_RUNNING;
+		break;
+
+	default:
+		bfa_sm_fault(rxf->rx->bna, event);
+	}
+}
+
+static void
+bna_rxf_sm_pause_wait_entry(struct bna_rxf *rxf)
+{
+	rxf->rxf_flags &=
+		~(BNA_RXF_FL_OPERSTATE_CHANGED | BNA_RXF_FL_RXF_ENABLED);
+	__rxf_disable(rxf);
+}
+
+static void
+bna_rxf_sm_pause_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+	switch (event) {
+	case RXF_E_FAIL:
+		/**
+		 * FSM was in the process of disabling rxf, initiated by
+		 * bnad.
+		 */
+		call_rxf_pause_cbfn(rxf, BNA_CB_FAIL);
+		bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+		break;
+
+	case RXF_E_STOPPED:
+		rxf->rxf_oper_state = BNA_RXF_OPER_STATE_PAUSED;
+		call_rxf_pause_cbfn(rxf, BNA_CB_SUCCESS);
+		bfa_fsm_set_state(rxf, bna_rxf_sm_started);
+		break;
+
+	/*
+	 * Since PAUSE/RESUME can only be sent by bnad, we don't expect
+	 * any other event during these states
+	 */
+	default:
+		bfa_sm_fault(rxf->rx->bna, event);
+	}
+}
+
+static void
+bna_rxf_sm_resume_wait_entry(struct bna_rxf *rxf)
+{
+	rxf->rxf_flags &= ~(BNA_RXF_FL_OPERSTATE_CHANGED);
+	rxf->rxf_flags |= BNA_RXF_FL_RXF_ENABLED;
+	__rxf_enable(rxf);
+}
+
+static void
+bna_rxf_sm_resume_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+	switch (event) {
+	case RXF_E_FAIL:
+		/**
+		 * FSM was in the process of disabling rxf, initiated by
+		 * bnad.
+		 */
+		call_rxf_resume_cbfn(rxf, BNA_CB_FAIL);
+		bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+		break;
+
+	case RXF_E_STARTED:
+		rxf->rxf_oper_state = BNA_RXF_OPER_STATE_RUNNING;
+		call_rxf_resume_cbfn(rxf, BNA_CB_SUCCESS);
+		bfa_fsm_set_state(rxf, bna_rxf_sm_started);
+		break;
+
+	/*
+	 * Since PAUSE/RESUME can only be sent by bnad, we don't expect
+	 * any other event during these states
+	 */
+	default:
+		bfa_sm_fault(rxf->rx->bna, event);
+	}
+}
+
+static void
+bna_rxf_sm_stat_clr_wait_entry(struct bna_rxf *rxf)
+{
+	__bna_rxf_stat_clr(rxf);
+}
+
+static void
+bna_rxf_sm_stat_clr_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+	switch (event) {
+	case RXF_E_FAIL:
+	case RXF_E_STAT_CLEARED:
+		bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+		break;
+
+	default:
+		bfa_sm_fault(rxf->rx->bna, event);
+	}
+}
+
+static void
+__rxf_enable(struct bna_rxf *rxf)
+{
+	struct bfi_ll_rxf_multi_req ll_req;
+	u32 bm[2] = {0, 0};
+
+	if (rxf->rxf_id < 32)
+		bm[0] = 1 << rxf->rxf_id;
+	else
+		bm[1] = 1 << (rxf->rxf_id - 32);
+
+	bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_RX_REQ, 0);
+	ll_req.rxf_id_mask[0] = htonl(bm[0]);
+	ll_req.rxf_id_mask[1] = htonl(bm[1]);
+	ll_req.enable = 1;
+
+	bna_mbox_qe_fill(&rxf->mbox_qe, &ll_req, sizeof(ll_req),
+			rxf_cb_enabled, rxf);
+
+	bna_mbox_send(rxf->rx->bna, &rxf->mbox_qe);
+}
+
+static void
+__rxf_disable(struct bna_rxf *rxf)
+{
+	struct bfi_ll_rxf_multi_req ll_req;
+	u32 bm[2] = {0, 0};
+
+	if (rxf->rxf_id < 32)
+		bm[0] = 1 << rxf->rxf_id;
+	else
+		bm[1] = 1 << (rxf->rxf_id - 32);
+
+	bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_RX_REQ, 0);
+	ll_req.rxf_id_mask[0] = htonl(bm[0]);
+	ll_req.rxf_id_mask[1] = htonl(bm[1]);
+	ll_req.enable = 0;
+
+	bna_mbox_qe_fill(&rxf->mbox_qe, &ll_req, sizeof(ll_req),
+			rxf_cb_disabled, rxf);
+
+	bna_mbox_send(rxf->rx->bna, &rxf->mbox_qe);
+}
+
+static void
+__rxf_config_set(struct bna_rxf *rxf)
+{
+	u32 i;
+	struct bna_rss_mem *rss_mem;
+	struct bna_rx_fndb_ram *rx_fndb_ram;
+	struct bna *bna = rxf->rx->bna;
+	void __iomem *base_addr;
+	unsigned long off;
+
+	base_addr = BNA_GET_MEM_BASE_ADDR(bna->pcidev.pci_bar_kva,
+			RSS_TABLE_BASE_OFFSET);
+
+	rss_mem = (struct bna_rss_mem *)0;
+
+	/* Configure RSS if required */
+	if (rxf->ctrl_flags & BNA_RXF_CF_RSS_ENABLE) {
+		/* configure RSS Table */
+		writel(BNA_GET_PAGE_NUM(RAD0_MEM_BLK_BASE_PG_NUM +
+			bna->port_num, RSS_TABLE_BASE_OFFSET),
+					bna->regs.page_addr);
+
+		/* temporarily disable RSS, while hash value is written */
+		off = (unsigned long)&rss_mem[0].type_n_hash;
+		writel(0, base_addr + off);
+
+		for (i = 0; i < BFI_RSS_HASH_KEY_LEN; i++) {
+			off = (unsigned long)
+			&rss_mem[0].hash_key[(BFI_RSS_HASH_KEY_LEN - 1) - i];
+			writel(htonl(rxf->rss_cfg.toeplitz_hash_key[i]),
+			base_addr + off);
+		}
+
+		off = (unsigned long)&rss_mem[0].type_n_hash;
+		writel(rxf->rss_cfg.hash_type | rxf->rss_cfg.hash_mask,
+			base_addr + off);
+	}
+
+	/* Configure RxF */
+	writel(BNA_GET_PAGE_NUM(
+		LUT0_MEM_BLK_BASE_PG_NUM + (bna->port_num * 2),
+		RX_FNDB_RAM_BASE_OFFSET),
+		bna->regs.page_addr);
+
+	base_addr = BNA_GET_MEM_BASE_ADDR(bna->pcidev.pci_bar_kva,
+		RX_FNDB_RAM_BASE_OFFSET);
+
+	rx_fndb_ram = (struct bna_rx_fndb_ram *)0;
+
+	/* We always use RSS table 0 */
+	off = (unsigned long)&rx_fndb_ram[rxf->rxf_id].rss_prop;
+	writel(rxf->ctrl_flags & BNA_RXF_CF_RSS_ENABLE,
+		base_addr + off);
+
+	/* small large buffer enable/disable */
+	off = (unsigned long)&rx_fndb_ram[rxf->rxf_id].size_routing_props;
+	writel((rxf->ctrl_flags & BNA_RXF_CF_SM_LG_RXQ) | 0x80,
+		base_addr + off);
+
+	/* RIT offset,  HDS forced offset, multicast RxQ Id */
+	off = (unsigned long)&rx_fndb_ram[rxf->rxf_id].rit_hds_mcastq;
+	writel((rxf->rit_segment->rit_offset << 16) |
+		(rxf->forced_offset << 8) |
+		(rxf->hds_cfg.hdr_type & BNA_HDS_FORCED) | rxf->mcast_rxq_id,
+		base_addr + off);
+
+	/*
+	 * default vlan tag, default function enable, strip vlan bytes,
+	 * HDS type, header size
+	 */
+
+	off = (unsigned long)&rx_fndb_ram[rxf->rxf_id].control_flags;
+	 writel(((u32)rxf->default_vlan_tag << 16) |
+		(rxf->ctrl_flags &
+			(BNA_RXF_CF_DEFAULT_VLAN |
+			BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE |
+			BNA_RXF_CF_VLAN_STRIP)) |
+		(rxf->hds_cfg.hdr_type & ~BNA_HDS_FORCED) |
+		rxf->hds_cfg.header_size,
+		base_addr + off);
+}
+
+void
+__rxf_vlan_filter_set(struct bna_rxf *rxf, enum bna_status status)
+{
+	struct bna *bna = rxf->rx->bna;
+	int i;
+
+	writel(BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+			(bna->port_num * 2), VLAN_RAM_BASE_OFFSET),
+			bna->regs.page_addr);
+
+	if (status == BNA_STATUS_T_ENABLED) {
+		/* enable VLAN filtering on this function */
+		for (i = 0; i <= BFI_MAX_VLAN / 32; i++) {
+			writel(rxf->vlan_filter_table[i],
+					BNA_GET_VLAN_MEM_ENTRY_ADDR
+					(bna->pcidev.pci_bar_kva, rxf->rxf_id,
+						i * 32));
+		}
+	} else {
+		/* disable VLAN filtering on this function */
+		for (i = 0; i <= BFI_MAX_VLAN / 32; i++) {
+			writel(0xffffffff,
+					BNA_GET_VLAN_MEM_ENTRY_ADDR
+					(bna->pcidev.pci_bar_kva, rxf->rxf_id,
+						i * 32));
+		}
+	}
+}
+
+static void
+__rxf_rit_set(struct bna_rxf *rxf)
+{
+	struct bna *bna = rxf->rx->bna;
+	struct bna_rit_mem *rit_mem;
+	int i;
+	void __iomem *base_addr;
+	unsigned long off;
+
+	base_addr = BNA_GET_MEM_BASE_ADDR(bna->pcidev.pci_bar_kva,
+			FUNCTION_TO_RXQ_TRANSLATE);
+
+	rit_mem = (struct bna_rit_mem *)0;
+
+	writel(BNA_GET_PAGE_NUM(RXA0_MEM_BLK_BASE_PG_NUM + bna->port_num,
+		FUNCTION_TO_RXQ_TRANSLATE),
+		bna->regs.page_addr);
+
+	for (i = 0; i < rxf->rit_segment->rit_size; i++) {
+		off = (unsigned long)&rit_mem[i + rxf->rit_segment->rit_offset];
+		writel(rxf->rit_segment->rit[i].large_rxq_id << 6 |
+			rxf->rit_segment->rit[i].small_rxq_id,
+			base_addr + off);
+	}
+}
+
+static void
+__bna_rxf_stat_clr(struct bna_rxf *rxf)
+{
+	struct bfi_ll_stats_req ll_req;
+	u32 bm[2] = {0, 0};
+
+	if (rxf->rxf_id < 32)
+		bm[0] = 1 << rxf->rxf_id;
+	else
+		bm[1] = 1 << (rxf->rxf_id - 32);
+
+	bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_STATS_CLEAR_REQ, 0);
+	ll_req.stats_mask = 0;
+	ll_req.txf_id_mask[0] = 0;
+	ll_req.txf_id_mask[1] =	0;
+
+	ll_req.rxf_id_mask[0] = htonl(bm[0]);
+	ll_req.rxf_id_mask[1] = htonl(bm[1]);
+
+	bna_mbox_qe_fill(&rxf->mbox_qe, &ll_req, sizeof(ll_req),
+			bna_rxf_cb_stats_cleared, rxf);
+	bna_mbox_send(rxf->rx->bna, &rxf->mbox_qe);
+}
+
+static void
+rxf_enable(struct bna_rxf *rxf)
+{
+	if (rxf->rxf_oper_state == BNA_RXF_OPER_STATE_PAUSED)
+		bfa_fsm_send_event(rxf, RXF_E_STARTED);
+	else {
+		rxf->rxf_flags |= BNA_RXF_FL_RXF_ENABLED;
+		__rxf_enable(rxf);
+	}
+}
+
+static void
+rxf_cb_enabled(void *arg, int status)
+{
+	struct bna_rxf *rxf = (struct bna_rxf *)arg;
+
+	bfa_q_qe_init(&rxf->mbox_qe.qe);
+	bfa_fsm_send_event(rxf, RXF_E_STARTED);
+}
+
+static void
+rxf_disable(struct bna_rxf *rxf)
+{
+	if (rxf->rxf_oper_state == BNA_RXF_OPER_STATE_PAUSED)
+		bfa_fsm_send_event(rxf, RXF_E_STOPPED);
+	else
+		rxf->rxf_flags &= ~BNA_RXF_FL_RXF_ENABLED;
+		__rxf_disable(rxf);
+}
+
+static void
+rxf_cb_disabled(void *arg, int status)
+{
+	struct bna_rxf *rxf = (struct bna_rxf *)arg;
+
+	bfa_q_qe_init(&rxf->mbox_qe.qe);
+	bfa_fsm_send_event(rxf, RXF_E_STOPPED);
+}
+
+void
+rxf_cb_cam_fltr_mbox_cmd(void *arg, int status)
+{
+	struct bna_rxf *rxf = (struct bna_rxf *)arg;
+
+	bfa_q_qe_init(&rxf->mbox_qe.qe);
+
+	bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_RESP);
+}
+
+static void
+bna_rxf_cb_stats_cleared(void *arg, int status)
+{
+	struct bna_rxf *rxf = (struct bna_rxf *)arg;
+
+	bfa_q_qe_init(&rxf->mbox_qe.qe);
+	bfa_fsm_send_event(rxf, RXF_E_STAT_CLEARED);
+}
+
+void
+rxf_cam_mbox_cmd(struct bna_rxf *rxf, u8 cmd,
+		const struct bna_mac *mac_addr)
+{
+	struct bfi_ll_mac_addr_req req;
+
+	bfi_h2i_set(req.mh, BFI_MC_LL, cmd, 0);
+
+	req.rxf_id = rxf->rxf_id;
+	memcpy(&req.mac_addr, (void *)&mac_addr->addr, ETH_ALEN);
+
+	bna_mbox_qe_fill(&rxf->mbox_qe, &req, sizeof(req),
+				rxf_cb_cam_fltr_mbox_cmd, rxf);
+
+	bna_mbox_send(rxf->rx->bna, &rxf->mbox_qe);
+}
+
+static int
+rxf_process_packet_filter_mcast(struct bna_rxf *rxf)
+{
+	struct bna_mac *mac = NULL;
+	struct list_head *qe;
+
+	/* Add multicast entries */
+	if (!list_empty(&rxf->mcast_pending_add_q)) {
+		bfa_q_deq(&rxf->mcast_pending_add_q, &qe);
+		bfa_q_qe_init(qe);
+		mac = (struct bna_mac *)qe;
+		rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_ADD_REQ, mac);
+		list_add_tail(&mac->qe, &rxf->mcast_active_q);
+		return 1;
+	}
+
+	/* Delete multicast entries previousely added */
+	if (!list_empty(&rxf->mcast_pending_del_q)) {
+		bfa_q_deq(&rxf->mcast_pending_del_q, &qe);
+		bfa_q_qe_init(qe);
+		mac = (struct bna_mac *)qe;
+		rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_DEL_REQ, mac);
+		bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int
+rxf_process_packet_filter_vlan(struct bna_rxf *rxf)
+{
+	/* Apply the VLAN filter */
+	if (rxf->rxf_flags & BNA_RXF_FL_VLAN_CONFIG_PENDING) {
+		rxf->rxf_flags &= ~BNA_RXF_FL_VLAN_CONFIG_PENDING;
+		if (!(rxf->rxmode_active & BNA_RXMODE_PROMISC) &&
+			!(rxf->rxmode_active & BNA_RXMODE_DEFAULT))
+			__rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
+	}
+
+	/* Apply RSS configuration */
+	if (rxf->rxf_flags & BNA_RXF_FL_RSS_CONFIG_PENDING) {
+		rxf->rxf_flags &= ~BNA_RXF_FL_RSS_CONFIG_PENDING;
+		if (rxf->rss_status == BNA_STATUS_T_DISABLED) {
+			/* RSS is being disabled */
+			rxf->ctrl_flags &= ~BNA_RXF_CF_RSS_ENABLE;
+			__rxf_rit_set(rxf);
+			__rxf_config_set(rxf);
+		} else {
+			/* RSS is being enabled or reconfigured */
+			rxf->ctrl_flags |= BNA_RXF_CF_RSS_ENABLE;
+			__rxf_rit_set(rxf);
+			__rxf_config_set(rxf);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Processes pending ucast, mcast entry addition/deletion and issues mailbox
+ * command. Also processes pending filter configuration - promiscuous mode,
+ * default mode, allmutli mode and issues mailbox command or directly applies
+ * to h/w
+ */
+static int
+rxf_process_packet_filter(struct bna_rxf *rxf)
+{
+	/* Set the default MAC first */
+	if (rxf->ucast_pending_set > 0) {
+		rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_UCAST_SET_REQ,
+				rxf->ucast_active_mac);
+		rxf->ucast_pending_set--;
+		return 1;
+	}
+
+	if (rxf_process_packet_filter_ucast(rxf))
+		return 1;
+
+	if (rxf_process_packet_filter_mcast(rxf))
+		return 1;
+
+	if (rxf_process_packet_filter_promisc(rxf))
+		return 1;
+
+	if (rxf_process_packet_filter_default(rxf))
+		return 1;
+
+	if (rxf_process_packet_filter_allmulti(rxf))
+		return 1;
+
+	if (rxf_process_packet_filter_vlan(rxf))
+		return 1;
+
+	return 0;
+}
+
+static int
+rxf_clear_packet_filter_mcast(struct bna_rxf *rxf)
+{
+	struct bna_mac *mac = NULL;
+	struct list_head *qe;
+
+	/* 3. delete pending mcast entries */
+	if (!list_empty(&rxf->mcast_pending_del_q)) {
+		bfa_q_deq(&rxf->mcast_pending_del_q, &qe);
+		bfa_q_qe_init(qe);
+		mac = (struct bna_mac *)qe;
+		rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_DEL_REQ, mac);
+		bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+		return 1;
+	}
+
+	/* 4. clear active mcast entries; move them to pending_add_q */
+	if (!list_empty(&rxf->mcast_active_q)) {
+		bfa_q_deq(&rxf->mcast_active_q, &qe);
+		bfa_q_qe_init(qe);
+		mac = (struct bna_mac *)qe;
+		rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_DEL_REQ, mac);
+		list_add_tail(&mac->qe, &rxf->mcast_pending_add_q);
+		return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * In the rxf stop path, processes pending ucast/mcast delete queue and issues
+ * the mailbox command. Moves the active ucast/mcast entries to pending add q,
+ * so that they are added to CAM again in the rxf start path. Moves the current
+ * filter settings - promiscuous, default, allmutli - to pending filter
+ * configuration
+ */
+static int
+rxf_clear_packet_filter(struct bna_rxf *rxf)
+{
+	if (rxf_clear_packet_filter_ucast(rxf))
+		return 1;
+
+	if (rxf_clear_packet_filter_mcast(rxf))
+		return 1;
+
+	/* 5. clear active default MAC in the CAM */
+	if (rxf->ucast_pending_set > 0)
+		rxf->ucast_pending_set = 0;
+
+	if (rxf_clear_packet_filter_promisc(rxf))
+		return 1;
+
+	if (rxf_clear_packet_filter_default(rxf))
+		return 1;
+
+	if (rxf_clear_packet_filter_allmulti(rxf))
+		return 1;
+
+	return 0;
+}
+
+static void
+rxf_reset_packet_filter_mcast(struct bna_rxf *rxf)
+{
+	struct list_head *qe;
+	struct bna_mac *mac;
+
+	/* 3. Move active mcast entries to pending_add_q */
+	while (!list_empty(&rxf->mcast_active_q)) {
+		bfa_q_deq(&rxf->mcast_active_q, &qe);
+		bfa_q_qe_init(qe);
+		list_add_tail(qe, &rxf->mcast_pending_add_q);
+	}
+
+	/* 4. Throw away delete pending mcast entries */
+	while (!list_empty(&rxf->mcast_pending_del_q)) {
+		bfa_q_deq(&rxf->mcast_pending_del_q, &qe);
+		bfa_q_qe_init(qe);
+		mac = (struct bna_mac *)qe;
+		bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+	}
+}
+
+/**
+ * In the rxf fail path, throws away the ucast/mcast entries pending for
+ * deletion, moves all active ucast/mcast entries to pending queue so that
+ * they are added back to CAM in the rxf start path. Also moves the current
+ * filter configuration to pending filter configuration.
+ */
+static void
+rxf_reset_packet_filter(struct bna_rxf *rxf)
+{
+	rxf_reset_packet_filter_ucast(rxf);
+
+	rxf_reset_packet_filter_mcast(rxf);
+
+	/* 5. Turn off ucast set flag */
+	rxf->ucast_pending_set = 0;
+
+	rxf_reset_packet_filter_promisc(rxf);
+
+	rxf_reset_packet_filter_default(rxf);
+
+	rxf_reset_packet_filter_allmulti(rxf);
+}
+
+void
+bna_rxf_init(struct bna_rxf *rxf,
+		struct bna_rx *rx,
+		struct bna_rx_config *q_config)
+{
+	struct list_head *qe;
+	struct bna_rxp *rxp;
+
+	/* rxf_id is initialized during rx_mod init */
+	rxf->rx = rx;
+
+	INIT_LIST_HEAD(&rxf->ucast_pending_add_q);
+	INIT_LIST_HEAD(&rxf->ucast_pending_del_q);
+	rxf->ucast_pending_set = 0;
+	INIT_LIST_HEAD(&rxf->ucast_active_q);
+	rxf->ucast_active_mac = NULL;
+
+	INIT_LIST_HEAD(&rxf->mcast_pending_add_q);
+	INIT_LIST_HEAD(&rxf->mcast_pending_del_q);
+	INIT_LIST_HEAD(&rxf->mcast_active_q);
+
+	bfa_q_qe_init(&rxf->mbox_qe.qe);
+
+	if (q_config->vlan_strip_status == BNA_STATUS_T_ENABLED)
+		rxf->ctrl_flags |= BNA_RXF_CF_VLAN_STRIP;
+
+	rxf->rxf_oper_state = (q_config->paused) ?
+		BNA_RXF_OPER_STATE_PAUSED : BNA_RXF_OPER_STATE_RUNNING;
+
+	bna_rxf_adv_init(rxf, rx, q_config);
+
+	rxf->rit_segment = bna_rit_mod_seg_get(&rxf->rx->bna->rit_mod,
+					q_config->num_paths);
+
+	list_for_each(qe, &rx->rxp_q) {
+		rxp = (struct bna_rxp *)qe;
+		if (q_config->rxp_type == BNA_RXP_SINGLE)
+			rxf->mcast_rxq_id = rxp->rxq.single.only->rxq_id;
+		else
+			rxf->mcast_rxq_id = rxp->rxq.slr.large->rxq_id;
+		break;
+	}
+
+	rxf->vlan_filter_status = BNA_STATUS_T_DISABLED;
+	memset(rxf->vlan_filter_table, 0,
+			(sizeof(u32) * ((BFI_MAX_VLAN + 1) / 32)));
+
+	bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+}
+
+void
+bna_rxf_uninit(struct bna_rxf *rxf)
+{
+	struct bna_mac *mac;
+
+	bna_rit_mod_seg_put(&rxf->rx->bna->rit_mod, rxf->rit_segment);
+	rxf->rit_segment = NULL;
+
+	rxf->ucast_pending_set = 0;
+
+	while (!list_empty(&rxf->ucast_pending_add_q)) {
+		bfa_q_deq(&rxf->ucast_pending_add_q, &mac);
+		bfa_q_qe_init(&mac->qe);
+		bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod, mac);
+	}
+
+	if (rxf->ucast_active_mac) {
+		bfa_q_qe_init(&rxf->ucast_active_mac->qe);
+		bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod,
+			rxf->ucast_active_mac);
+		rxf->ucast_active_mac = NULL;
+	}
+
+	while (!list_empty(&rxf->mcast_pending_add_q)) {
+		bfa_q_deq(&rxf->mcast_pending_add_q, &mac);
+		bfa_q_qe_init(&mac->qe);
+		bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+	}
+
+	rxf->rx = NULL;
+}
+
+void
+bna_rxf_start(struct bna_rxf *rxf)
+{
+	rxf->start_cbfn = bna_rx_cb_rxf_started;
+	rxf->start_cbarg = rxf->rx;
+	rxf->rxf_flags &= ~BNA_RXF_FL_FAILED;
+	bfa_fsm_send_event(rxf, RXF_E_START);
+}
+
+void
+bna_rxf_stop(struct bna_rxf *rxf)
+{
+	rxf->stop_cbfn = bna_rx_cb_rxf_stopped;
+	rxf->stop_cbarg = rxf->rx;
+	bfa_fsm_send_event(rxf, RXF_E_STOP);
+}
+
+void
+bna_rxf_fail(struct bna_rxf *rxf)
+{
+	rxf->rxf_flags |= BNA_RXF_FL_FAILED;
+	bfa_fsm_send_event(rxf, RXF_E_FAIL);
+}
+
+int
+bna_rxf_state_get(struct bna_rxf *rxf)
+{
+	return bfa_sm_to_state(rxf_sm_table, rxf->fsm);
+}
+
+enum bna_cb_status
+bna_rx_ucast_set(struct bna_rx *rx, u8 *ucmac,
+		 void (*cbfn)(struct bnad *, struct bna_rx *,
+			      enum bna_cb_status))
+{
+	struct bna_rxf *rxf = &rx->rxf;
+
+	if (rxf->ucast_active_mac == NULL) {
+		rxf->ucast_active_mac =
+				bna_ucam_mod_mac_get(&rxf->rx->bna->ucam_mod);
+		if (rxf->ucast_active_mac == NULL)
+			return BNA_CB_UCAST_CAM_FULL;
+		bfa_q_qe_init(&rxf->ucast_active_mac->qe);
+	}
+
+	memcpy(rxf->ucast_active_mac->addr, ucmac, ETH_ALEN);
+	rxf->ucast_pending_set++;
+	rxf->cam_fltr_cbfn = cbfn;
+	rxf->cam_fltr_cbarg = rx->bna->bnad;
+
+	bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+
+	return BNA_CB_SUCCESS;
+}
+
+enum bna_cb_status
+bna_rx_mcast_add(struct bna_rx *rx, u8 *addr,
+		 void (*cbfn)(struct bnad *, struct bna_rx *,
+			      enum bna_cb_status))
+{
+	struct bna_rxf *rxf = &rx->rxf;
+	struct list_head	*qe;
+	struct bna_mac *mac;
+
+	/* Check if already added */
+	list_for_each(qe, &rxf->mcast_active_q) {
+		mac = (struct bna_mac *)qe;
+		if (BNA_MAC_IS_EQUAL(mac->addr, addr)) {
+			if (cbfn)
+				(*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+			return BNA_CB_SUCCESS;
+		}
+	}
+
+	/* Check if pending addition */
+	list_for_each(qe, &rxf->mcast_pending_add_q) {
+		mac = (struct bna_mac *)qe;
+		if (BNA_MAC_IS_EQUAL(mac->addr, addr)) {
+			if (cbfn)
+				(*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+			return BNA_CB_SUCCESS;
+		}
+	}
+
+	mac = bna_mcam_mod_mac_get(&rxf->rx->bna->mcam_mod);
+	if (mac == NULL)
+		return BNA_CB_MCAST_LIST_FULL;
+	bfa_q_qe_init(&mac->qe);
+	memcpy(mac->addr, addr, ETH_ALEN);
+	list_add_tail(&mac->qe, &rxf->mcast_pending_add_q);
+
+	rxf->cam_fltr_cbfn = cbfn;
+	rxf->cam_fltr_cbarg = rx->bna->bnad;
+
+	bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+
+	return BNA_CB_SUCCESS;
+}
+
+enum bna_cb_status
+bna_rx_mcast_del(struct bna_rx *rx, u8 *addr,
+		 void (*cbfn)(struct bnad *, struct bna_rx *,
+			      enum bna_cb_status))
+{
+	struct bna_rxf *rxf = &rx->rxf;
+	struct list_head *qe;
+	struct bna_mac *mac;
+
+	list_for_each(qe, &rxf->mcast_pending_add_q) {
+		mac = (struct bna_mac *)qe;
+		if (BNA_MAC_IS_EQUAL(mac->addr, addr)) {
+			list_del(qe);
+			bfa_q_qe_init(qe);
+			bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+			if (cbfn)
+				(*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+			return BNA_CB_SUCCESS;
+		}
+	}
+
+	list_for_each(qe, &rxf->mcast_active_q) {
+		mac = (struct bna_mac *)qe;
+		if (BNA_MAC_IS_EQUAL(mac->addr, addr)) {
+			list_del(qe);
+			bfa_q_qe_init(qe);
+			list_add_tail(qe, &rxf->mcast_pending_del_q);
+			rxf->cam_fltr_cbfn = cbfn;
+			rxf->cam_fltr_cbarg = rx->bna->bnad;
+			bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+			return BNA_CB_SUCCESS;
+		}
+	}
+
+	return BNA_CB_INVALID_MAC;
+}
+
+enum bna_cb_status
+bna_rx_mcast_listset(struct bna_rx *rx, int count, u8 *mclist,
+		     void (*cbfn)(struct bnad *, struct bna_rx *,
+				  enum bna_cb_status))
+{
+	struct bna_rxf *rxf = &rx->rxf;
+	struct list_head list_head;
+	struct list_head *qe;
+	u8 *mcaddr;
+	struct bna_mac *mac;
+	struct bna_mac *mac1;
+	int skip;
+	int delete;
+	int need_hw_config = 0;
+	int i;
+
+	/* Allocate nodes */
+	INIT_LIST_HEAD(&list_head);
+	for (i = 0, mcaddr = mclist; i < count; i++) {
+		mac = bna_mcam_mod_mac_get(&rxf->rx->bna->mcam_mod);
+		if (mac == NULL)
+			goto err_return;
+		bfa_q_qe_init(&mac->qe);
+		memcpy(mac->addr, mcaddr, ETH_ALEN);
+		list_add_tail(&mac->qe, &list_head);
+
+		mcaddr += ETH_ALEN;
+	}
+
+	/* Schedule for addition */
+	while (!list_empty(&list_head)) {
+		bfa_q_deq(&list_head, &qe);
+		mac = (struct bna_mac *)qe;
+		bfa_q_qe_init(&mac->qe);
+
+		skip = 0;
+
+		/* Skip if already added */
+		list_for_each(qe, &rxf->mcast_active_q) {
+			mac1 = (struct bna_mac *)qe;
+			if (BNA_MAC_IS_EQUAL(mac1->addr, mac->addr)) {
+				bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod,
+							mac);
+				skip = 1;
+				break;
+			}
+		}
+
+		if (skip)
+			continue;
+
+		/* Skip if pending addition */
+		list_for_each(qe, &rxf->mcast_pending_add_q) {
+			mac1 = (struct bna_mac *)qe;
+			if (BNA_MAC_IS_EQUAL(mac1->addr, mac->addr)) {
+				bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod,
+							mac);
+				skip = 1;
+				break;
+			}
+		}
+
+		if (skip)
+			continue;
+
+		need_hw_config = 1;
+		list_add_tail(&mac->qe, &rxf->mcast_pending_add_q);
+	}
+
+	/**
+	 * Delete the entries that are in the pending_add_q but not
+	 * in the new list
+	 */
+	while (!list_empty(&rxf->mcast_pending_add_q)) {
+		bfa_q_deq(&rxf->mcast_pending_add_q, &qe);
+		mac = (struct bna_mac *)qe;
+		bfa_q_qe_init(&mac->qe);
+		for (i = 0, mcaddr = mclist, delete = 1; i < count; i++) {
+			if (BNA_MAC_IS_EQUAL(mcaddr, mac->addr)) {
+				delete = 0;
+				break;
+			}
+			mcaddr += ETH_ALEN;
+		}
+		if (delete)
+			bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+		else
+			list_add_tail(&mac->qe, &list_head);
+	}
+	while (!list_empty(&list_head)) {
+		bfa_q_deq(&list_head, &qe);
+		mac = (struct bna_mac *)qe;
+		bfa_q_qe_init(&mac->qe);
+		list_add_tail(&mac->qe, &rxf->mcast_pending_add_q);
+	}
+
+	/**
+	 * Schedule entries for deletion that are in the active_q but not
+	 * in the new list
+	 */
+	while (!list_empty(&rxf->mcast_active_q)) {
+		bfa_q_deq(&rxf->mcast_active_q, &qe);
+		mac = (struct bna_mac *)qe;
+		bfa_q_qe_init(&mac->qe);
+		for (i = 0, mcaddr = mclist, delete = 1; i < count; i++) {
+			if (BNA_MAC_IS_EQUAL(mcaddr, mac->addr)) {
+				delete = 0;
+				break;
+			}
+			mcaddr += ETH_ALEN;
+		}
+		if (delete) {
+			list_add_tail(&mac->qe, &rxf->mcast_pending_del_q);
+			need_hw_config = 1;
+		} else {
+			list_add_tail(&mac->qe, &list_head);
+		}
+	}
+	while (!list_empty(&list_head)) {
+		bfa_q_deq(&list_head, &qe);
+		mac = (struct bna_mac *)qe;
+		bfa_q_qe_init(&mac->qe);
+		list_add_tail(&mac->qe, &rxf->mcast_active_q);
+	}
+
+	if (need_hw_config) {
+		rxf->cam_fltr_cbfn = cbfn;
+		rxf->cam_fltr_cbarg = rx->bna->bnad;
+		bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+	} else if (cbfn)
+		(*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+
+	return BNA_CB_SUCCESS;
+
+err_return:
+	while (!list_empty(&list_head)) {
+		bfa_q_deq(&list_head, &qe);
+		mac = (struct bna_mac *)qe;
+		bfa_q_qe_init(&mac->qe);
+		bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+	}
+
+	return BNA_CB_MCAST_LIST_FULL;
+}
+
+void
+bna_rx_vlan_add(struct bna_rx *rx, int vlan_id)
+{
+	struct bna_rxf *rxf = &rx->rxf;
+	int index = (vlan_id >> 5);
+	int bit = (1 << (vlan_id & 0x1F));
+
+	rxf->vlan_filter_table[index] |= bit;
+	if (rxf->vlan_filter_status == BNA_STATUS_T_ENABLED) {
+		rxf->rxf_flags |= BNA_RXF_FL_VLAN_CONFIG_PENDING;
+		bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+	}
+}
+
+void
+bna_rx_vlan_del(struct bna_rx *rx, int vlan_id)
+{
+	struct bna_rxf *rxf = &rx->rxf;
+	int index = (vlan_id >> 5);
+	int bit = (1 << (vlan_id & 0x1F));
+
+	rxf->vlan_filter_table[index] &= ~bit;
+	if (rxf->vlan_filter_status == BNA_STATUS_T_ENABLED) {
+		rxf->rxf_flags |= BNA_RXF_FL_VLAN_CONFIG_PENDING;
+		bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+	}
+}
+
+/**
+ * RX
+ */
+#define	RXQ_RCB_INIT(q, rxp, qdepth, bna, _id, unmapq_mem)	do {	\
+	struct bna_doorbell_qset *_qset;				\
+	unsigned long off;						\
+	(q)->rcb->producer_index = (q)->rcb->consumer_index = 0;	\
+	(q)->rcb->q_depth = (qdepth);					\
+	(q)->rcb->unmap_q = unmapq_mem;					\
+	(q)->rcb->rxq = (q);						\
+	(q)->rcb->cq = &(rxp)->cq;					\
+	(q)->rcb->bnad = (bna)->bnad;					\
+	_qset = (struct bna_doorbell_qset *)0;			\
+	off = (unsigned long)&_qset[(q)->rxq_id].rxq[0];		\
+	(q)->rcb->q_dbell = off +					\
+		BNA_GET_DOORBELL_BASE_ADDR((bna)->pcidev.pci_bar_kva);	\
+	(q)->rcb->id = _id;						\
+} while (0)
+
+#define	BNA_GET_RXQS(qcfg)	(((qcfg)->rxp_type == BNA_RXP_SINGLE) ?	\
+	(qcfg)->num_paths : ((qcfg)->num_paths * 2))
+
+#define	SIZE_TO_PAGES(size)	(((size) >> PAGE_SHIFT) + ((((size) &\
+	(PAGE_SIZE - 1)) + (PAGE_SIZE - 1)) >> PAGE_SHIFT))
+
+#define	call_rx_stop_callback(rx, status)				\
+	if ((rx)->stop_cbfn) {						\
+		(*(rx)->stop_cbfn)((rx)->stop_cbarg, rx, (status));	\
+		(rx)->stop_cbfn = NULL;					\
+		(rx)->stop_cbarg = NULL;				\
+	}
+
+/*
+ * Since rx_enable is synchronous callback, there is no start_cbfn required.
+ * Instead, we'll call bnad_rx_post(rxp) so that bnad can post the buffers
+ * for each rxpath.
+ */
+
+#define	call_rx_disable_cbfn(rx, status)				\
+		if ((rx)->disable_cbfn)	{				\
+			(*(rx)->disable_cbfn)((rx)->disable_cbarg,	\
+					status);			\
+			(rx)->disable_cbfn = NULL;			\
+			(rx)->disable_cbarg = NULL;			\
+		}							\
+
+#define	rxqs_reqd(type, num_rxqs)					\
+	(((type) == BNA_RXP_SINGLE) ? (num_rxqs) : ((num_rxqs) * 2))
+
+#define rx_ib_fail(rx)						\
+do {								\
+	struct bna_rxp *rxp;					\
+	struct list_head *qe;						\
+	list_for_each(qe, &(rx)->rxp_q) {				\
+		rxp = (struct bna_rxp *)qe;			\
+		bna_ib_fail(rxp->cq.ib);			\
+	}							\
+} while (0)
+
+static void __bna_multi_rxq_stop(struct bna_rxp *, u32 *);
+static void __bna_rxq_start(struct bna_rxq *rxq);
+static void __bna_cq_start(struct bna_cq *cq);
+static void bna_rit_create(struct bna_rx *rx);
+static void bna_rx_cb_multi_rxq_stopped(void *arg, int status);
+static void bna_rx_cb_rxq_stopped_all(void *arg);
+
+bfa_fsm_state_decl(bna_rx, stopped,
+	struct bna_rx, enum bna_rx_event);
+bfa_fsm_state_decl(bna_rx, rxf_start_wait,
+	struct bna_rx, enum bna_rx_event);
+bfa_fsm_state_decl(bna_rx, started,
+	struct bna_rx, enum bna_rx_event);
+bfa_fsm_state_decl(bna_rx, rxf_stop_wait,
+	struct bna_rx, enum bna_rx_event);
+bfa_fsm_state_decl(bna_rx, rxq_stop_wait,
+	struct bna_rx, enum bna_rx_event);
+
+static struct bfa_sm_table rx_sm_table[] = {
+	{BFA_SM(bna_rx_sm_stopped), BNA_RX_STOPPED},
+	{BFA_SM(bna_rx_sm_rxf_start_wait), BNA_RX_RXF_START_WAIT},
+	{BFA_SM(bna_rx_sm_started), BNA_RX_STARTED},
+	{BFA_SM(bna_rx_sm_rxf_stop_wait), BNA_RX_RXF_STOP_WAIT},
+	{BFA_SM(bna_rx_sm_rxq_stop_wait), BNA_RX_RXQ_STOP_WAIT},
+};
+
+static void bna_rx_sm_stopped_entry(struct bna_rx *rx)
+{
+	struct bna_rxp *rxp;
+	struct list_head *qe_rxp;
+
+	list_for_each(qe_rxp, &rx->rxp_q) {
+		rxp = (struct bna_rxp *)qe_rxp;
+		rx->rx_cleanup_cbfn(rx->bna->bnad, rxp->cq.ccb);
+	}
+
+	call_rx_stop_callback(rx, BNA_CB_SUCCESS);
+}
+
+static void bna_rx_sm_stopped(struct bna_rx *rx,
+				enum bna_rx_event event)
+{
+	switch (event) {
+	case RX_E_START:
+		bfa_fsm_set_state(rx, bna_rx_sm_rxf_start_wait);
+		break;
+	case RX_E_STOP:
+		call_rx_stop_callback(rx, BNA_CB_SUCCESS);
+		break;
+	case RX_E_FAIL:
+		/* no-op */
+		break;
+	default:
+		bfa_sm_fault(rx->bna, event);
+		break;
+	}
+
+}
+
+static void bna_rx_sm_rxf_start_wait_entry(struct bna_rx *rx)
+{
+	struct bna_rxp *rxp;
+	struct list_head *qe_rxp;
+	struct bna_rxq *q0 = NULL, *q1 = NULL;
+
+	/* Setup the RIT */
+	bna_rit_create(rx);
+
+	list_for_each(qe_rxp, &rx->rxp_q) {
+		rxp = (struct bna_rxp *)qe_rxp;
+		bna_ib_start(rxp->cq.ib);
+		GET_RXQS(rxp, q0, q1);
+		q0->buffer_size = bna_port_mtu_get(&rx->bna->port);
+		__bna_rxq_start(q0);
+		rx->rx_post_cbfn(rx->bna->bnad, q0->rcb);
+		if (q1)  {
+			__bna_rxq_start(q1);
+			rx->rx_post_cbfn(rx->bna->bnad, q1->rcb);
+		}
+		__bna_cq_start(&rxp->cq);
+	}
+
+	bna_rxf_start(&rx->rxf);
+}
+
+static void bna_rx_sm_rxf_start_wait(struct bna_rx *rx,
+				enum bna_rx_event event)
+{
+	switch (event) {
+	case RX_E_STOP:
+		bfa_fsm_set_state(rx, bna_rx_sm_rxf_stop_wait);
+		break;
+	case RX_E_FAIL:
+		bfa_fsm_set_state(rx, bna_rx_sm_stopped);
+		rx_ib_fail(rx);
+		bna_rxf_fail(&rx->rxf);
+		break;
+	case RX_E_RXF_STARTED:
+		bfa_fsm_set_state(rx, bna_rx_sm_started);
+		break;
+	default:
+		bfa_sm_fault(rx->bna, event);
+		break;
+	}
+}
+
+void
+bna_rx_sm_started_entry(struct bna_rx *rx)
+{
+	struct bna_rxp *rxp;
+	struct list_head *qe_rxp;
+
+	/* Start IB */
+	list_for_each(qe_rxp, &rx->rxp_q) {
+		rxp = (struct bna_rxp *)qe_rxp;
+		bna_ib_ack(&rxp->cq.ib->door_bell, 0);
+	}
+
+	bna_llport_admin_up(&rx->bna->port.llport);
+}
+
+void
+bna_rx_sm_started(struct bna_rx *rx, enum bna_rx_event event)
+{
+	switch (event) {
+	case RX_E_FAIL:
+		bna_llport_admin_down(&rx->bna->port.llport);
+		bfa_fsm_set_state(rx, bna_rx_sm_stopped);
+		rx_ib_fail(rx);
+		bna_rxf_fail(&rx->rxf);
+		break;
+	case RX_E_STOP:
+		bna_llport_admin_down(&rx->bna->port.llport);
+		bfa_fsm_set_state(rx, bna_rx_sm_rxf_stop_wait);
+		break;
+	default:
+		bfa_sm_fault(rx->bna, event);
+		break;
+	}
+}
+
+void
+bna_rx_sm_rxf_stop_wait_entry(struct bna_rx *rx)
+{
+	bna_rxf_stop(&rx->rxf);
+}
+
+void
+bna_rx_sm_rxf_stop_wait(struct bna_rx *rx, enum bna_rx_event event)
+{
+	switch (event) {
+	case RX_E_RXF_STOPPED:
+		bfa_fsm_set_state(rx, bna_rx_sm_rxq_stop_wait);
+		break;
+	case RX_E_RXF_STARTED:
+		/**
+		 * RxF was in the process of starting up when
+		 * RXF_E_STOP was issued. Ignore this event
+		 */
+		break;
+	case RX_E_FAIL:
+		bfa_fsm_set_state(rx, bna_rx_sm_stopped);
+		rx_ib_fail(rx);
+		bna_rxf_fail(&rx->rxf);
+		break;
+	default:
+		bfa_sm_fault(rx->bna, event);
+		break;
+	}
+
+}
+
+void
+bna_rx_sm_rxq_stop_wait_entry(struct bna_rx *rx)
+{
+	struct bna_rxp *rxp = NULL;
+	struct bna_rxq *q0 = NULL;
+	struct bna_rxq *q1 = NULL;
+	struct list_head	*qe;
+	u32 rxq_mask[2] = {0, 0};
+
+	/* Only one call to multi-rxq-stop for all RXPs in this RX */
+	bfa_wc_up(&rx->rxq_stop_wc);
+	list_for_each(qe, &rx->rxp_q) {
+		rxp = (struct bna_rxp *)qe;
+		GET_RXQS(rxp, q0, q1);
+		if (q0->rxq_id < 32)
+			rxq_mask[0] |= ((u32)1 << q0->rxq_id);
+		else
+			rxq_mask[1] |= ((u32)1 << (q0->rxq_id - 32));
+		if (q1) {
+			if (q1->rxq_id < 32)
+				rxq_mask[0] |= ((u32)1 << q1->rxq_id);
+			else
+				rxq_mask[1] |= ((u32)
+						1 << (q1->rxq_id - 32));
+		}
+	}
+
+	__bna_multi_rxq_stop(rxp, rxq_mask);
+}
+
+void
+bna_rx_sm_rxq_stop_wait(struct bna_rx *rx, enum bna_rx_event event)
+{
+	struct bna_rxp *rxp = NULL;
+	struct list_head	*qe;
+
+	switch (event) {
+	case RX_E_RXQ_STOPPED:
+		list_for_each(qe, &rx->rxp_q) {
+			rxp = (struct bna_rxp *)qe;
+			bna_ib_stop(rxp->cq.ib);
+		}
+		/* Fall through */
+	case RX_E_FAIL:
+		bfa_fsm_set_state(rx, bna_rx_sm_stopped);
+		break;
+	default:
+		bfa_sm_fault(rx->bna, event);
+		break;
+	}
+}
+
+void
+__bna_multi_rxq_stop(struct bna_rxp *rxp, u32 * 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(rxq_id_mask[0]);
+	ll_req.q_id_mask[1] = htonl(rxq_id_mask[1]);
+	bna_mbox_qe_fill(&rxp->mbox_qe, &ll_req, sizeof(ll_req),
+		bna_rx_cb_multi_rxq_stopped, rxp);
+	bna_mbox_send(rxp->rx->bna, &rxp->mbox_qe);
+}
+
+void
+__bna_rxq_start(struct bna_rxq *rxq)
+{
+	struct bna_rxtx_q_mem *q_mem;
+	struct bna_rxq_mem rxq_cfg, *rxq_mem;
+	struct bna_dma_addr cur_q_addr;
+	/* struct bna_doorbell_qset *qset; */
+	struct bna_qpt *qpt;
+	u32 pg_num;
+	struct bna *bna = rxq->rx->bna;
+	void __iomem *base_addr;
+	unsigned long off;
+
+	qpt = &rxq->qpt;
+	cur_q_addr = *((struct bna_dma_addr *)(qpt->kv_qpt_ptr));
+
+	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 = ((u32)qpt->page_count << 16) | 0x0;
+	rxq_cfg.entry_n_pg_size = ((u32)(BFI_RXQ_WI_SIZE >> 2) << 16) |
+		(qpt->page_size >> 2);
+	rxq_cfg.sg_n_cq_n_cns_ptr =
+		((u32)(rxq->rxp->cq.cq_id & 0xff) << 16) | 0x0;
+	rxq_cfg.buf_sz_n_q_state = ((u32)rxq->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 + bna->port_num,
+			HQM_RXTX_Q_RAM_BASE_OFFSET);
+	writel(pg_num, bna->regs.page_addr);
+
+	/* Write to h/w */
+	base_addr = BNA_GET_MEM_BASE_ADDR(bna->pcidev.pci_bar_kva,
+					HQM_RXTX_Q_RAM_BASE_OFFSET);
+
+	q_mem = (struct bna_rxtx_q_mem *)0;
+	rxq_mem = &q_mem[rxq->rxq_id].rxq;
+
+	off = (unsigned long)&rxq_mem->pg_tbl_addr_lo;
+	writel(htonl(rxq_cfg.pg_tbl_addr_lo), base_addr + off);
+
+	off = (unsigned long)&rxq_mem->pg_tbl_addr_hi;
+	writel(htonl(rxq_cfg.pg_tbl_addr_hi), base_addr + off);
+
+	off = (unsigned long)&rxq_mem->cur_q_entry_lo;
+	writel(htonl(rxq_cfg.cur_q_entry_lo), base_addr + off);
+
+	off = (unsigned long)&rxq_mem->cur_q_entry_hi;
+	writel(htonl(rxq_cfg.cur_q_entry_hi), base_addr + off);
+
+	off = (unsigned long)&rxq_mem->pg_cnt_n_prd_ptr;
+	writel(rxq_cfg.pg_cnt_n_prd_ptr, base_addr + off);
+
+	off = (unsigned long)&rxq_mem->entry_n_pg_size;
+	writel(rxq_cfg.entry_n_pg_size, base_addr + off);
+
+	off = (unsigned long)&rxq_mem->sg_n_cq_n_cns_ptr;
+	writel(rxq_cfg.sg_n_cq_n_cns_ptr, base_addr + off);
+
+	off = (unsigned long)&rxq_mem->buf_sz_n_q_state;
+	writel(rxq_cfg.buf_sz_n_q_state, base_addr + off);
+
+	off = (unsigned long)&rxq_mem->next_qid;
+	writel(rxq_cfg.next_qid, base_addr + off);
+
+	rxq->rcb->producer_index = 0;
+	rxq->rcb->consumer_index = 0;
+}
+
+void
+__bna_cq_start(struct bna_cq *cq)
+{
+	struct bna_cq_mem cq_cfg, *cq_mem;
+	const struct bna_qpt *qpt;
+	struct bna_dma_addr cur_q_addr;
+	u32 pg_num;
+	struct bna *bna = cq->rx->bna;
+	void __iomem *base_addr;
+	unsigned long off;
+
+	qpt = &cq->qpt;
+	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 =
+		((u32)(BFI_CQ_WI_SIZE >> 2) << 16) | (qpt->page_size >> 2);
+	cq_cfg.int_blk_n_cns_ptr = ((((u32)cq->ib_seg_offset) << 24) |
+			((u32)(cq->ib->ib_id & 0xff)  << 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 + bna->port_num,
+				  HQM_CQ_RAM_BASE_OFFSET);
+
+	writel(pg_num, bna->regs.page_addr);
+
+	/* H/W write */
+	base_addr = BNA_GET_MEM_BASE_ADDR(bna->pcidev.pci_bar_kva,
+					HQM_CQ_RAM_BASE_OFFSET);
+
+	cq_mem = (struct bna_cq_mem *)0;
+
+	off = (unsigned long)&cq_mem[cq->cq_id].pg_tbl_addr_lo;
+	writel(htonl(cq_cfg.pg_tbl_addr_lo), base_addr + off);
+
+	off = (unsigned long)&cq_mem[cq->cq_id].pg_tbl_addr_hi;
+	writel(htonl(cq_cfg.pg_tbl_addr_hi), base_addr + off);
+
+	off = (unsigned long)&cq_mem[cq->cq_id].cur_q_entry_lo;
+	writel(htonl(cq_cfg.cur_q_entry_lo), base_addr + off);
+
+	off = (unsigned long)&cq_mem[cq->cq_id].cur_q_entry_hi;
+	writel(htonl(cq_cfg.cur_q_entry_hi), base_addr + off);
+
+	off = (unsigned long)&cq_mem[cq->cq_id].pg_cnt_n_prd_ptr;
+	writel(cq_cfg.pg_cnt_n_prd_ptr, base_addr + off);
+
+	off = (unsigned long)&cq_mem[cq->cq_id].entry_n_pg_size;
+	writel(cq_cfg.entry_n_pg_size, base_addr + off);
+
+	off = (unsigned long)&cq_mem[cq->cq_id].int_blk_n_cns_ptr;
+	writel(cq_cfg.int_blk_n_cns_ptr, base_addr + off);
+
+	off = (unsigned long)&cq_mem[cq->cq_id].q_state;
+	writel(cq_cfg.q_state, base_addr + off);
+
+	cq->ccb->producer_index = 0;
+	*(cq->ccb->hw_producer_index) = 0;
+}
+
+void
+bna_rit_create(struct bna_rx *rx)
+{
+	struct list_head	*qe_rxp;
+	struct bna *bna;
+	struct bna_rxp *rxp;
+	struct bna_rxq *q0 = NULL;
+	struct bna_rxq *q1 = NULL;
+	int offset;
+
+	bna = rx->bna;
+
+	offset = 0;
+	list_for_each(qe_rxp, &rx->rxp_q) {
+		rxp = (struct bna_rxp *)qe_rxp;
+		GET_RXQS(rxp, q0, q1);
+		rx->rxf.rit_segment->rit[offset].large_rxq_id = q0->rxq_id;
+		rx->rxf.rit_segment->rit[offset].small_rxq_id =
+						(q1 ? q1->rxq_id : 0);
+		offset++;
+	}
+}
+
+int
+_rx_can_satisfy(struct bna_rx_mod *rx_mod,
+		struct bna_rx_config *rx_cfg)
+{
+	if ((rx_mod->rx_free_count == 0) ||
+		(rx_mod->rxp_free_count == 0) ||
+		(rx_mod->rxq_free_count == 0))
+		return 0;
+
+	if (rx_cfg->rxp_type == BNA_RXP_SINGLE) {
+		if ((rx_mod->rxp_free_count < rx_cfg->num_paths) ||
+			(rx_mod->rxq_free_count < rx_cfg->num_paths))
+				return 0;
+	} else {
+		if ((rx_mod->rxp_free_count < rx_cfg->num_paths) ||
+			(rx_mod->rxq_free_count < (2 * rx_cfg->num_paths)))
+			return 0;
+	}
+
+	if (!bna_rit_mod_can_satisfy(&rx_mod->bna->rit_mod, rx_cfg->num_paths))
+		return 0;
+
+	return 1;
+}
+
+struct bna_rxq *
+_get_free_rxq(struct bna_rx_mod *rx_mod)
+{
+	struct bna_rxq *rxq = NULL;
+	struct list_head	*qe = NULL;
+
+	bfa_q_deq(&rx_mod->rxq_free_q, &qe);
+	if (qe) {
+		rx_mod->rxq_free_count--;
+		rxq = (struct bna_rxq *)qe;
+	}
+	return rxq;
+}
+
+void
+_put_free_rxq(struct bna_rx_mod *rx_mod, struct bna_rxq *rxq)
+{
+	bfa_q_qe_init(&rxq->qe);
+	list_add_tail(&rxq->qe, &rx_mod->rxq_free_q);
+	rx_mod->rxq_free_count++;
+}
+
+struct bna_rxp *
+_get_free_rxp(struct bna_rx_mod *rx_mod)
+{
+	struct list_head	*qe = NULL;
+	struct bna_rxp *rxp = NULL;
+
+	bfa_q_deq(&rx_mod->rxp_free_q, &qe);
+	if (qe) {
+		rx_mod->rxp_free_count--;
+
+		rxp = (struct bna_rxp *)qe;
+	}
+
+	return rxp;
+}
+
+void
+_put_free_rxp(struct bna_rx_mod *rx_mod, struct bna_rxp *rxp)
+{
+	bfa_q_qe_init(&rxp->qe);
+	list_add_tail(&rxp->qe, &rx_mod->rxp_free_q);
+	rx_mod->rxp_free_count++;
+}
+
+struct bna_rx *
+_get_free_rx(struct bna_rx_mod *rx_mod)
+{
+	struct list_head	*qe = NULL;
+	struct bna_rx *rx = NULL;
+
+	bfa_q_deq(&rx_mod->rx_free_q, &qe);
+	if (qe) {
+		rx_mod->rx_free_count--;
+
+		rx = (struct bna_rx *)qe;
+		bfa_q_qe_init(qe);
+		list_add_tail(&rx->qe, &rx_mod->rx_active_q);
+	}
+
+	return rx;
+}
+
+void
+_put_free_rx(struct bna_rx_mod *rx_mod, struct bna_rx *rx)
+{
+	bfa_q_qe_init(&rx->qe);
+	list_add_tail(&rx->qe, &rx_mod->rx_free_q);
+	rx_mod->rx_free_count++;
+}
+
+void
+_rx_init(struct bna_rx *rx, struct bna *bna)
+{
+	rx->bna = bna;
+	rx->rx_flags = 0;
+
+	INIT_LIST_HEAD(&rx->rxp_q);
+
+	rx->rxq_stop_wc.wc_resume = bna_rx_cb_rxq_stopped_all;
+	rx->rxq_stop_wc.wc_cbarg = rx;
+	rx->rxq_stop_wc.wc_count = 0;
+
+	rx->stop_cbfn = NULL;
+	rx->stop_cbarg = NULL;
+}
+
+void
+_rxp_add_rxqs(struct bna_rxp *rxp,
+		struct bna_rxq *q0,
+		struct bna_rxq *q1)
+{
+	switch (rxp->type) {
+	case BNA_RXP_SINGLE:
+		rxp->rxq.single.only = q0;
+		rxp->rxq.single.reserved = NULL;
+		break;
+	case BNA_RXP_SLR:
+		rxp->rxq.slr.large = q0;
+		rxp->rxq.slr.small = q1;
+		break;
+	case BNA_RXP_HDS:
+		rxp->rxq.hds.data = q0;
+		rxp->rxq.hds.hdr = q1;
+		break;
+	default:
+		break;
+	}
+}
+
+void
+_rxq_qpt_init(struct bna_rxq *rxq,
+		struct bna_rxp *rxp,
+		u32 page_count,
+		u32 page_size,
+		struct bna_mem_descr *qpt_mem,
+		struct bna_mem_descr *swqpt_mem,
+		struct bna_mem_descr *page_mem)
+{
+	int	i;
+
+	rxq->qpt.hw_qpt_ptr.lsb = qpt_mem->dma.lsb;
+	rxq->qpt.hw_qpt_ptr.msb = qpt_mem->dma.msb;
+	rxq->qpt.kv_qpt_ptr = qpt_mem->kva;
+	rxq->qpt.page_count = page_count;
+	rxq->qpt.page_size = page_size;
+
+	rxq->rcb->sw_qpt = (void **) swqpt_mem->kva;
+
+	for (i = 0; i < rxq->qpt.page_count; i++) {
+		rxq->rcb->sw_qpt[i] = page_mem[i].kva;
+		((struct bna_dma_addr *)rxq->qpt.kv_qpt_ptr)[i].lsb =
+			page_mem[i].dma.lsb;
+		((struct bna_dma_addr *)rxq->qpt.kv_qpt_ptr)[i].msb =
+			page_mem[i].dma.msb;
+
+	}
+}
+
+void
+_rxp_cqpt_setup(struct bna_rxp *rxp,
+		u32 page_count,
+		u32 page_size,
+		struct bna_mem_descr *qpt_mem,
+		struct bna_mem_descr *swqpt_mem,
+		struct bna_mem_descr *page_mem)
+{
+	int	i;
+
+	rxp->cq.qpt.hw_qpt_ptr.lsb = qpt_mem->dma.lsb;
+	rxp->cq.qpt.hw_qpt_ptr.msb = qpt_mem->dma.msb;
+	rxp->cq.qpt.kv_qpt_ptr = qpt_mem->kva;
+	rxp->cq.qpt.page_count = page_count;
+	rxp->cq.qpt.page_size = page_size;
+
+	rxp->cq.ccb->sw_qpt = (void **) swqpt_mem->kva;
+
+	for (i = 0; i < rxp->cq.qpt.page_count; i++) {
+		rxp->cq.ccb->sw_qpt[i] = page_mem[i].kva;
+
+		((struct bna_dma_addr *)rxp->cq.qpt.kv_qpt_ptr)[i].lsb =
+			page_mem[i].dma.lsb;
+		((struct bna_dma_addr *)rxp->cq.qpt.kv_qpt_ptr)[i].msb =
+			page_mem[i].dma.msb;
+
+	}
+}
+
+void
+_rx_add_rxp(struct bna_rx *rx, struct bna_rxp *rxp)
+{
+	list_add_tail(&rxp->qe, &rx->rxp_q);
+}
+
+void
+_init_rxmod_queues(struct bna_rx_mod *rx_mod)
+{
+	INIT_LIST_HEAD(&rx_mod->rx_free_q);
+	INIT_LIST_HEAD(&rx_mod->rxq_free_q);
+	INIT_LIST_HEAD(&rx_mod->rxp_free_q);
+	INIT_LIST_HEAD(&rx_mod->rx_active_q);
+
+	rx_mod->rx_free_count = 0;
+	rx_mod->rxq_free_count = 0;
+	rx_mod->rxp_free_count = 0;
+}
+
+void
+_rx_ctor(struct bna_rx *rx, int id)
+{
+	bfa_q_qe_init(&rx->qe);
+	INIT_LIST_HEAD(&rx->rxp_q);
+	rx->bna = NULL;
+
+	rx->rxf.rxf_id = id;
+
+	/* FIXME: mbox_qe ctor()?? */
+	bfa_q_qe_init(&rx->mbox_qe.qe);
+
+	rx->stop_cbfn = NULL;
+	rx->stop_cbarg = NULL;
+}
+
+void
+bna_rx_cb_multi_rxq_stopped(void *arg, int status)
+{
+	struct bna_rxp *rxp = (struct bna_rxp *)arg;
+
+	bfa_wc_down(&rxp->rx->rxq_stop_wc);
+}
+
+void
+bna_rx_cb_rxq_stopped_all(void *arg)
+{
+	struct bna_rx *rx = (struct bna_rx *)arg;
+
+	bfa_fsm_send_event(rx, RX_E_RXQ_STOPPED);
+}
+
+void
+bna_rx_mod_cb_rx_stopped(void *arg, struct bna_rx *rx,
+			 enum bna_cb_status status)
+{
+	struct bna_rx_mod *rx_mod = (struct bna_rx_mod *)arg;
+
+	bfa_wc_down(&rx_mod->rx_stop_wc);
+}
+
+void
+bna_rx_mod_cb_rx_stopped_all(void *arg)
+{
+	struct bna_rx_mod *rx_mod = (struct bna_rx_mod *)arg;
+
+	if (rx_mod->stop_cbfn)
+		rx_mod->stop_cbfn(&rx_mod->bna->port, BNA_CB_SUCCESS);
+	rx_mod->stop_cbfn = NULL;
+}
+
+void
+bna_rx_start(struct bna_rx *rx)
+{
+	rx->rx_flags |= BNA_RX_F_PORT_ENABLED;
+	if (rx->rx_flags & BNA_RX_F_ENABLE)
+		bfa_fsm_send_event(rx, RX_E_START);
+}
+
+void
+bna_rx_stop(struct bna_rx *rx)
+{
+	rx->rx_flags &= ~BNA_RX_F_PORT_ENABLED;
+	if (rx->fsm == (bfa_fsm_t) bna_rx_sm_stopped)
+		bna_rx_mod_cb_rx_stopped(&rx->bna->rx_mod, rx, BNA_CB_SUCCESS);
+	else {
+		rx->stop_cbfn = bna_rx_mod_cb_rx_stopped;
+		rx->stop_cbarg = &rx->bna->rx_mod;
+		bfa_fsm_send_event(rx, RX_E_STOP);
+	}
+}
+
+void
+bna_rx_fail(struct bna_rx *rx)
+{
+	/* Indicate port is not enabled, and failed */
+	rx->rx_flags &= ~BNA_RX_F_PORT_ENABLED;
+	rx->rx_flags |= BNA_RX_F_PORT_FAILED;
+	bfa_fsm_send_event(rx, RX_E_FAIL);
+}
+
+void
+bna_rx_cb_rxf_started(struct bna_rx *rx, enum bna_cb_status status)
+{
+	bfa_fsm_send_event(rx, RX_E_RXF_STARTED);
+	if (rx->rxf.rxf_id < 32)
+		rx->bna->rx_mod.rxf_bmap[0] |= ((u32)1 << rx->rxf.rxf_id);
+	else
+		rx->bna->rx_mod.rxf_bmap[1] |= ((u32)
+				1 << (rx->rxf.rxf_id - 32));
+}
+
+void
+bna_rx_cb_rxf_stopped(struct bna_rx *rx, enum bna_cb_status status)
+{
+	bfa_fsm_send_event(rx, RX_E_RXF_STOPPED);
+	if (rx->rxf.rxf_id < 32)
+		rx->bna->rx_mod.rxf_bmap[0] &= ~(u32)1 << rx->rxf.rxf_id;
+	else
+		rx->bna->rx_mod.rxf_bmap[1] &= ~(u32)
+				1 << (rx->rxf.rxf_id - 32);
+}
+
+void
+bna_rx_mod_start(struct bna_rx_mod *rx_mod, enum bna_rx_type type)
+{
+	struct bna_rx *rx;
+	struct list_head *qe;
+
+	rx_mod->flags |= BNA_RX_MOD_F_PORT_STARTED;
+	if (type == BNA_RX_T_LOOPBACK)
+		rx_mod->flags |= BNA_RX_MOD_F_PORT_LOOPBACK;
+
+	list_for_each(qe, &rx_mod->rx_active_q) {
+		rx = (struct bna_rx *)qe;
+		if (rx->type == type)
+			bna_rx_start(rx);
+	}
+}
+
+void
+bna_rx_mod_stop(struct bna_rx_mod *rx_mod, enum bna_rx_type type)
+{
+	struct bna_rx *rx;
+	struct list_head *qe;
+
+	rx_mod->flags &= ~BNA_RX_MOD_F_PORT_STARTED;
+	rx_mod->flags &= ~BNA_RX_MOD_F_PORT_LOOPBACK;
+
+	rx_mod->stop_cbfn = bna_port_cb_rx_stopped;
+
+	/**
+	 * Before calling bna_rx_stop(), increment rx_stop_wc as many times
+	 * as we are going to call bna_rx_stop
+	 */
+	list_for_each(qe, &rx_mod->rx_active_q) {
+		rx = (struct bna_rx *)qe;
+		if (rx->type == type)
+			bfa_wc_up(&rx_mod->rx_stop_wc);
+	}
+
+	if (rx_mod->rx_stop_wc.wc_count == 0) {
+		rx_mod->stop_cbfn(&rx_mod->bna->port, BNA_CB_SUCCESS);
+		rx_mod->stop_cbfn = NULL;
+		return;
+	}
+
+	list_for_each(qe, &rx_mod->rx_active_q) {
+		rx = (struct bna_rx *)qe;
+		if (rx->type == type)
+			bna_rx_stop(rx);
+	}
+}
+
+void
+bna_rx_mod_fail(struct bna_rx_mod *rx_mod)
+{
+	struct bna_rx *rx;
+	struct list_head *qe;
+
+	rx_mod->flags &= ~BNA_RX_MOD_F_PORT_STARTED;
+	rx_mod->flags &= ~BNA_RX_MOD_F_PORT_LOOPBACK;
+
+	list_for_each(qe, &rx_mod->rx_active_q) {
+		rx = (struct bna_rx *)qe;
+		bna_rx_fail(rx);
+	}
+}
+
+void bna_rx_mod_init(struct bna_rx_mod *rx_mod, struct bna *bna,
+			struct bna_res_info *res_info)
+{
+	int	index;
+	struct bna_rx *rx_ptr;
+	struct bna_rxp *rxp_ptr;
+	struct bna_rxq *rxq_ptr;
+
+	rx_mod->bna = bna;
+	rx_mod->flags = 0;
+
+	rx_mod->rx = (struct bna_rx *)
+		res_info[BNA_RES_MEM_T_RX_ARRAY].res_u.mem_info.mdl[0].kva;
+	rx_mod->rxp = (struct bna_rxp *)
+		res_info[BNA_RES_MEM_T_RXP_ARRAY].res_u.mem_info.mdl[0].kva;
+	rx_mod->rxq = (struct bna_rxq *)
+		res_info[BNA_RES_MEM_T_RXQ_ARRAY].res_u.mem_info.mdl[0].kva;
+
+	/* Initialize the queues */
+	_init_rxmod_queues(rx_mod);
+
+	/* Build RX queues */
+	for (index = 0; index < BFI_MAX_RXQ; index++) {
+		rx_ptr = &rx_mod->rx[index];
+		_rx_ctor(rx_ptr, index);
+		list_add_tail(&rx_ptr->qe, &rx_mod->rx_free_q);
+		rx_mod->rx_free_count++;
+	}
+
+	/* build RX-path queue */
+	for (index = 0; index < BFI_MAX_RXQ; index++) {
+		rxp_ptr = &rx_mod->rxp[index];
+		rxp_ptr->cq.cq_id = index;
+		bfa_q_qe_init(&rxp_ptr->qe);
+		list_add_tail(&rxp_ptr->qe, &rx_mod->rxp_free_q);
+		rx_mod->rxp_free_count++;
+	}
+
+	/* build RXQ queue */
+	for (index = 0; index < BFI_MAX_RXQ; index++) {
+		rxq_ptr = &rx_mod->rxq[index];
+		rxq_ptr->rxq_id = index;
+
+		bfa_q_qe_init(&rxq_ptr->qe);
+		list_add_tail(&rxq_ptr->qe, &rx_mod->rxq_free_q);
+		rx_mod->rxq_free_count++;
+	}
+
+	rx_mod->rx_stop_wc.wc_resume = bna_rx_mod_cb_rx_stopped_all;
+	rx_mod->rx_stop_wc.wc_cbarg = rx_mod;
+	rx_mod->rx_stop_wc.wc_count = 0;
+}
+
+void
+bna_rx_mod_uninit(struct bna_rx_mod *rx_mod)
+{
+	struct list_head		*qe;
+	int i;
+
+	i = 0;
+	list_for_each(qe, &rx_mod->rx_free_q)
+		i++;
+
+	i = 0;
+	list_for_each(qe, &rx_mod->rxp_free_q)
+		i++;
+
+	i = 0;
+	list_for_each(qe, &rx_mod->rxq_free_q)
+		i++;
+
+	rx_mod->bna = NULL;
+}
+
+int
+bna_rx_state_get(struct bna_rx *rx)
+{
+	return bfa_sm_to_state(rx_sm_table, rx->fsm);
+}
+
+void
+bna_rx_res_req(struct bna_rx_config *q_cfg, struct bna_res_info *res_info)
+{
+	u32 cq_size, hq_size, dq_size;
+	u32 cpage_count, hpage_count, dpage_count;
+	struct bna_mem_info *mem_info;
+	u32 cq_depth;
+	u32 hq_depth;
+	u32 dq_depth;
+
+	dq_depth = q_cfg->q_depth;
+	hq_depth = ((q_cfg->rxp_type == BNA_RXP_SINGLE) ? 0 : q_cfg->q_depth);
+	cq_depth = dq_depth + hq_depth;
+
+	BNA_TO_POWER_OF_2_HIGH(cq_depth);
+	cq_size = cq_depth * BFI_CQ_WI_SIZE;
+	cq_size = ALIGN(cq_size, PAGE_SIZE);
+	cpage_count = SIZE_TO_PAGES(cq_size);
+
+	BNA_TO_POWER_OF_2_HIGH(dq_depth);
+	dq_size = dq_depth * BFI_RXQ_WI_SIZE;
+	dq_size = ALIGN(dq_size, PAGE_SIZE);
+	dpage_count = SIZE_TO_PAGES(dq_size);
+
+	if (BNA_RXP_SINGLE != q_cfg->rxp_type) {
+		BNA_TO_POWER_OF_2_HIGH(hq_depth);
+		hq_size = hq_depth * BFI_RXQ_WI_SIZE;
+		hq_size = ALIGN(hq_size, PAGE_SIZE);
+		hpage_count = SIZE_TO_PAGES(hq_size);
+	} else {
+		hpage_count = 0;
+	}
+
+	/* CCB structures */
+	res_info[BNA_RX_RES_MEM_T_CCB].res_type = BNA_RES_T_MEM;
+	mem_info = &res_info[BNA_RX_RES_MEM_T_CCB].res_u.mem_info;
+	mem_info->mem_type = BNA_MEM_T_KVA;
+	mem_info->len = sizeof(struct bna_ccb);
+	mem_info->num = q_cfg->num_paths;
+
+	/* RCB structures */
+	res_info[BNA_RX_RES_MEM_T_RCB].res_type = BNA_RES_T_MEM;
+	mem_info = &res_info[BNA_RX_RES_MEM_T_RCB].res_u.mem_info;
+	mem_info->mem_type = BNA_MEM_T_KVA;
+	mem_info->len = sizeof(struct bna_rcb);
+	mem_info->num = BNA_GET_RXQS(q_cfg);
+
+	/* Completion QPT */
+	res_info[BNA_RX_RES_MEM_T_CQPT].res_type = BNA_RES_T_MEM;
+	mem_info = &res_info[BNA_RX_RES_MEM_T_CQPT].res_u.mem_info;
+	mem_info->mem_type = BNA_MEM_T_DMA;
+	mem_info->len = cpage_count * sizeof(struct bna_dma_addr);
+	mem_info->num = q_cfg->num_paths;
+
+	/* Completion s/w QPT */
+	res_info[BNA_RX_RES_MEM_T_CSWQPT].res_type = BNA_RES_T_MEM;
+	mem_info = &res_info[BNA_RX_RES_MEM_T_CSWQPT].res_u.mem_info;
+	mem_info->mem_type = BNA_MEM_T_KVA;
+	mem_info->len = cpage_count * sizeof(void *);
+	mem_info->num = q_cfg->num_paths;
+
+	/* Completion QPT pages */
+	res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_type = BNA_RES_T_MEM;
+	mem_info = &res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_u.mem_info;
+	mem_info->mem_type = BNA_MEM_T_DMA;
+	mem_info->len = PAGE_SIZE;
+	mem_info->num = cpage_count * q_cfg->num_paths;
+
+	/* Data QPTs */
+	res_info[BNA_RX_RES_MEM_T_DQPT].res_type = BNA_RES_T_MEM;
+	mem_info = &res_info[BNA_RX_RES_MEM_T_DQPT].res_u.mem_info;
+	mem_info->mem_type = BNA_MEM_T_DMA;
+	mem_info->len = dpage_count * sizeof(struct bna_dma_addr);
+	mem_info->num = q_cfg->num_paths;
+
+	/* Data s/w QPTs */
+	res_info[BNA_RX_RES_MEM_T_DSWQPT].res_type = BNA_RES_T_MEM;
+	mem_info = &res_info[BNA_RX_RES_MEM_T_DSWQPT].res_u.mem_info;
+	mem_info->mem_type = BNA_MEM_T_KVA;
+	mem_info->len = dpage_count * sizeof(void *);
+	mem_info->num = q_cfg->num_paths;
+
+	/* Data QPT pages */
+	res_info[BNA_RX_RES_MEM_T_DPAGE].res_type = BNA_RES_T_MEM;
+	mem_info = &res_info[BNA_RX_RES_MEM_T_DPAGE].res_u.mem_info;
+	mem_info->mem_type = BNA_MEM_T_DMA;
+	mem_info->len = PAGE_SIZE;
+	mem_info->num = dpage_count * q_cfg->num_paths;
+
+	/* Hdr QPTs */
+	res_info[BNA_RX_RES_MEM_T_HQPT].res_type = BNA_RES_T_MEM;
+	mem_info = &res_info[BNA_RX_RES_MEM_T_HQPT].res_u.mem_info;
+	mem_info->mem_type = BNA_MEM_T_DMA;
+	mem_info->len = hpage_count * sizeof(struct bna_dma_addr);
+	mem_info->num = (hpage_count ? q_cfg->num_paths : 0);
+
+	/* Hdr s/w QPTs */
+	res_info[BNA_RX_RES_MEM_T_HSWQPT].res_type = BNA_RES_T_MEM;
+	mem_info = &res_info[BNA_RX_RES_MEM_T_HSWQPT].res_u.mem_info;
+	mem_info->mem_type = BNA_MEM_T_KVA;
+	mem_info->len = hpage_count * sizeof(void *);
+	mem_info->num = (hpage_count ? q_cfg->num_paths : 0);
+
+	/* Hdr QPT pages */
+	res_info[BNA_RX_RES_MEM_T_HPAGE].res_type = BNA_RES_T_MEM;
+	mem_info = &res_info[BNA_RX_RES_MEM_T_HPAGE].res_u.mem_info;
+	mem_info->mem_type = BNA_MEM_T_DMA;
+	mem_info->len = (hpage_count ? PAGE_SIZE : 0);
+	mem_info->num = (hpage_count ? (hpage_count * q_cfg->num_paths) : 0);
+
+	/* RX Interrupts */
+	res_info[BNA_RX_RES_T_INTR].res_type = BNA_RES_T_INTR;
+	res_info[BNA_RX_RES_T_INTR].res_u.intr_info.intr_type = BNA_INTR_T_MSIX;
+	res_info[BNA_RX_RES_T_INTR].res_u.intr_info.num = q_cfg->num_paths;
+}
+
+struct bna_rx *
+bna_rx_create(struct bna *bna, struct bnad *bnad,
+		struct bna_rx_config *rx_cfg,
+		struct bna_rx_event_cbfn *rx_cbfn,
+		struct bna_res_info *res_info,
+		void *priv)
+{
+	struct bna_rx_mod *rx_mod = &bna->rx_mod;
+	struct bna_rx *rx;
+	struct bna_rxp *rxp;
+	struct bna_rxq *q0;
+	struct bna_rxq *q1;
+	struct bna_intr_info *intr_info;
+	u32 page_count;
+	struct bna_mem_descr *ccb_mem;
+	struct bna_mem_descr *rcb_mem;
+	struct bna_mem_descr *unmapq_mem;
+	struct bna_mem_descr *cqpt_mem;
+	struct bna_mem_descr *cswqpt_mem;
+	struct bna_mem_descr *cpage_mem;
+	struct bna_mem_descr *hqpt_mem;	/* Header/Small Q qpt */
+	struct bna_mem_descr *dqpt_mem;	/* Data/Large Q qpt */
+	struct bna_mem_descr *hsqpt_mem;	/* s/w qpt for hdr */
+	struct bna_mem_descr *dsqpt_mem;	/* s/w qpt for data */
+	struct bna_mem_descr *hpage_mem;	/* hdr page mem */
+	struct bna_mem_descr *dpage_mem;	/* data page mem */
+	int i, cpage_idx = 0, dpage_idx = 0, hpage_idx = 0, ret;
+	int dpage_count, hpage_count, rcb_idx;
+	struct bna_ib_config ibcfg;
+	/* Fail if we don't have enough RXPs, RXQs */
+	if (!_rx_can_satisfy(rx_mod, rx_cfg))
+		return NULL;
+
+	/* Initialize resource pointers */
+	intr_info = &res_info[BNA_RX_RES_T_INTR].res_u.intr_info;
+	ccb_mem = &res_info[BNA_RX_RES_MEM_T_CCB].res_u.mem_info.mdl[0];
+	rcb_mem = &res_info[BNA_RX_RES_MEM_T_RCB].res_u.mem_info.mdl[0];
+	unmapq_mem = &res_info[BNA_RX_RES_MEM_T_UNMAPQ].res_u.mem_info.mdl[0];
+	cqpt_mem = &res_info[BNA_RX_RES_MEM_T_CQPT].res_u.mem_info.mdl[0];
+	cswqpt_mem = &res_info[BNA_RX_RES_MEM_T_CSWQPT].res_u.mem_info.mdl[0];
+	cpage_mem = &res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_u.mem_info.mdl[0];
+	hqpt_mem = &res_info[BNA_RX_RES_MEM_T_HQPT].res_u.mem_info.mdl[0];
+	dqpt_mem = &res_info[BNA_RX_RES_MEM_T_DQPT].res_u.mem_info.mdl[0];
+	hsqpt_mem = &res_info[BNA_RX_RES_MEM_T_HSWQPT].res_u.mem_info.mdl[0];
+	dsqpt_mem = &res_info[BNA_RX_RES_MEM_T_DSWQPT].res_u.mem_info.mdl[0];
+	hpage_mem = &res_info[BNA_RX_RES_MEM_T_HPAGE].res_u.mem_info.mdl[0];
+	dpage_mem = &res_info[BNA_RX_RES_MEM_T_DPAGE].res_u.mem_info.mdl[0];
+
+	/* Compute q depth & page count */
+	page_count = res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_u.mem_info.num /
+			rx_cfg->num_paths;
+
+	dpage_count = res_info[BNA_RX_RES_MEM_T_DPAGE].res_u.mem_info.num /
+			rx_cfg->num_paths;
+
+	hpage_count = res_info[BNA_RX_RES_MEM_T_HPAGE].res_u.mem_info.num /
+			rx_cfg->num_paths;
+	/* Get RX pointer */
+	rx = _get_free_rx(rx_mod);
+	_rx_init(rx, bna);
+	rx->priv = priv;
+	rx->type = rx_cfg->rx_type;
+
+	rx->rcb_setup_cbfn = rx_cbfn->rcb_setup_cbfn;
+	rx->rcb_destroy_cbfn = rx_cbfn->rcb_destroy_cbfn;
+	rx->ccb_setup_cbfn = rx_cbfn->ccb_setup_cbfn;
+	rx->ccb_destroy_cbfn = rx_cbfn->ccb_destroy_cbfn;
+	/* Following callbacks are mandatory */
+	rx->rx_cleanup_cbfn = rx_cbfn->rx_cleanup_cbfn;
+	rx->rx_post_cbfn = rx_cbfn->rx_post_cbfn;
+
+	if (rx->bna->rx_mod.flags & BNA_RX_MOD_F_PORT_STARTED) {
+		switch (rx->type) {
+		case BNA_RX_T_REGULAR:
+			if (!(rx->bna->rx_mod.flags &
+				BNA_RX_MOD_F_PORT_LOOPBACK))
+				rx->rx_flags |= BNA_RX_F_PORT_ENABLED;
+			break;
+		case BNA_RX_T_LOOPBACK:
+			if (rx->bna->rx_mod.flags & BNA_RX_MOD_F_PORT_LOOPBACK)
+				rx->rx_flags |= BNA_RX_F_PORT_ENABLED;
+			break;
+		}
+	}
+
+	for (i = 0, rcb_idx = 0; i < rx_cfg->num_paths; i++) {
+		rxp = _get_free_rxp(rx_mod);
+		rxp->type = rx_cfg->rxp_type;
+		rxp->rx = rx;
+		rxp->cq.rx = rx;
+
+		/* Get required RXQs, and queue them to rx-path */
+		q0 = _get_free_rxq(rx_mod);
+		if (BNA_RXP_SINGLE == rx_cfg->rxp_type)
+			q1 = NULL;
+		else
+			q1 = _get_free_rxq(rx_mod);
+
+		/* Initialize IB */
+		if (1 == intr_info->num) {
+			rxp->cq.ib = bna_ib_get(&bna->ib_mod,
+					intr_info->intr_type,
+					intr_info->idl[0].vector);
+			rxp->vector = intr_info->idl[0].vector;
+		} else {
+			rxp->cq.ib = bna_ib_get(&bna->ib_mod,
+					intr_info->intr_type,
+					intr_info->idl[i].vector);
+
+			/* Map the MSI-x vector used for this RXP */
+			rxp->vector = intr_info->idl[i].vector;
+		}
+
+		rxp->cq.ib_seg_offset = bna_ib_reserve_idx(rxp->cq.ib);
+
+		ibcfg.coalescing_timeo = BFI_RX_COALESCING_TIMEO;
+		ibcfg.interpkt_count = BFI_RX_INTERPKT_COUNT;
+		ibcfg.interpkt_timeo = BFI_RX_INTERPKT_TIMEO;
+		ibcfg.ctrl_flags = BFI_IB_CF_INT_ENABLE;
+
+		ret = bna_ib_config(rxp->cq.ib, &ibcfg);
+
+		/* Link rxqs to rxp */
+		_rxp_add_rxqs(rxp, q0, q1);
+
+		/* Link rxp to rx */
+		_rx_add_rxp(rx, rxp);
+
+		q0->rx = rx;
+		q0->rxp = rxp;
+
+		/* Initialize RCB for the large / data q */
+		q0->rcb = (struct bna_rcb *) rcb_mem[rcb_idx].kva;
+		RXQ_RCB_INIT(q0, rxp, rx_cfg->q_depth, bna, 0,
+			(void *)unmapq_mem[rcb_idx].kva);
+		rcb_idx++;
+		(q0)->rx_packets = (q0)->rx_bytes = 0;
+		(q0)->rx_packets_with_error = (q0)->rxbuf_alloc_failed = 0;
+
+		/* Initialize RXQs */
+		_rxq_qpt_init(q0, rxp, dpage_count, PAGE_SIZE,
+			&dqpt_mem[i], &dsqpt_mem[i], &dpage_mem[dpage_idx]);
+		q0->rcb->page_idx = dpage_idx;
+		q0->rcb->page_count = dpage_count;
+		dpage_idx += dpage_count;
+
+		/* Call bnad to complete rcb setup */
+		if (rx->rcb_setup_cbfn)
+			rx->rcb_setup_cbfn(bnad, q0->rcb);
+
+		if (q1) {
+			q1->rx = rx;
+			q1->rxp = rxp;
+
+			q1->rcb = (struct bna_rcb *) rcb_mem[rcb_idx].kva;
+			RXQ_RCB_INIT(q1, rxp, rx_cfg->q_depth, bna, 1,
+				(void *)unmapq_mem[rcb_idx].kva);
+			rcb_idx++;
+			(q1)->buffer_size = (rx_cfg)->small_buff_size;
+			(q1)->rx_packets = (q1)->rx_bytes = 0;
+			(q1)->rx_packets_with_error =
+				(q1)->rxbuf_alloc_failed = 0;
+
+			_rxq_qpt_init(q1, rxp, hpage_count, PAGE_SIZE,
+				&hqpt_mem[i], &hsqpt_mem[i],
+				&hpage_mem[hpage_idx]);
+			q1->rcb->page_idx = hpage_idx;
+			q1->rcb->page_count = hpage_count;
+			hpage_idx += hpage_count;
+
+			/* Call bnad to complete rcb setup */
+			if (rx->rcb_setup_cbfn)
+				rx->rcb_setup_cbfn(bnad, q1->rcb);
+		}
+		/* Setup RXP::CQ */
+		rxp->cq.ccb = (struct bna_ccb *) ccb_mem[i].kva;
+		_rxp_cqpt_setup(rxp, page_count, PAGE_SIZE,
+			&cqpt_mem[i], &cswqpt_mem[i], &cpage_mem[cpage_idx]);
+		rxp->cq.ccb->page_idx = cpage_idx;
+		rxp->cq.ccb->page_count = page_count;
+		cpage_idx += page_count;
+
+		rxp->cq.ccb->pkt_rate.small_pkt_cnt = 0;
+		rxp->cq.ccb->pkt_rate.large_pkt_cnt = 0;
+
+		rxp->cq.ccb->producer_index = 0;
+		rxp->cq.ccb->q_depth =	rx_cfg->q_depth +
+					((rx_cfg->rxp_type == BNA_RXP_SINGLE) ?
+					0 : rx_cfg->q_depth);
+		rxp->cq.ccb->i_dbell = &rxp->cq.ib->door_bell;
+		rxp->cq.ccb->rcb[0] = q0->rcb;
+		if (q1)
+			rxp->cq.ccb->rcb[1] = q1->rcb;
+		rxp->cq.ccb->cq = &rxp->cq;
+		rxp->cq.ccb->bnad = bna->bnad;
+		rxp->cq.ccb->hw_producer_index =
+			((volatile u32 *)rxp->cq.ib->ib_seg_host_addr_kva +
+				      (rxp->cq.ib_seg_offset * BFI_IBIDX_SIZE));
+		*(rxp->cq.ccb->hw_producer_index) = 0;
+		rxp->cq.ccb->intr_type = intr_info->intr_type;
+		rxp->cq.ccb->intr_vector = (intr_info->num == 1) ?
+						intr_info->idl[0].vector :
+						intr_info->idl[i].vector;
+		rxp->cq.ccb->rx_coalescing_timeo =
+					rxp->cq.ib->ib_config.coalescing_timeo;
+		rxp->cq.ccb->id = i;
+
+		/* Call bnad to complete CCB setup */
+		if (rx->ccb_setup_cbfn)
+			rx->ccb_setup_cbfn(bnad, rxp->cq.ccb);
+
+	} /* for each rx-path */
+
+	bna_rxf_init(&rx->rxf, rx, rx_cfg);
+
+	bfa_fsm_set_state(rx, bna_rx_sm_stopped);
+
+	return rx;
+}
+
+void
+bna_rx_destroy(struct bna_rx *rx)
+{
+	struct bna_rx_mod *rx_mod = &rx->bna->rx_mod;
+	struct bna_ib_mod *ib_mod = &rx->bna->ib_mod;
+	struct bna_rxq *q0 = NULL;
+	struct bna_rxq *q1 = NULL;
+	struct bna_rxp *rxp;
+	struct list_head *qe;
+
+	bna_rxf_uninit(&rx->rxf);
+
+	while (!list_empty(&rx->rxp_q)) {
+		bfa_q_deq(&rx->rxp_q, &rxp);
+		GET_RXQS(rxp, q0, q1);
+		/* Callback to bnad for destroying RCB */
+		if (rx->rcb_destroy_cbfn)
+			rx->rcb_destroy_cbfn(rx->bna->bnad, q0->rcb);
+		q0->rcb = NULL;
+		q0->rxp = NULL;
+		q0->rx = NULL;
+		_put_free_rxq(rx_mod, q0);
+		if (q1) {
+			/* Callback to bnad for destroying RCB */
+			if (rx->rcb_destroy_cbfn)
+				rx->rcb_destroy_cbfn(rx->bna->bnad, q1->rcb);
+			q1->rcb = NULL;
+			q1->rxp = NULL;
+			q1->rx = NULL;
+			_put_free_rxq(rx_mod, q1);
+		}
+		rxp->rxq.slr.large = NULL;
+		rxp->rxq.slr.small = NULL;
+		if (rxp->cq.ib) {
+			if (rxp->cq.ib_seg_offset != 0xff)
+				bna_ib_release_idx(rxp->cq.ib,
+						rxp->cq.ib_seg_offset);
+			bna_ib_put(ib_mod, rxp->cq.ib);
+			rxp->cq.ib = NULL;
+		}
+		/* Callback to bnad for destroying CCB */
+		if (rx->ccb_destroy_cbfn)
+			rx->ccb_destroy_cbfn(rx->bna->bnad, rxp->cq.ccb);
+		rxp->cq.ccb = NULL;
+		rxp->rx = NULL;
+		_put_free_rxp(rx_mod, rxp);
+	}
+
+	list_for_each(qe, &rx_mod->rx_active_q) {
+		if (qe == &rx->qe) {
+			list_del(&rx->qe);
+			bfa_q_qe_init(&rx->qe);
+			break;
+		}
+	}
+
+	rx->bna = NULL;
+	rx->priv = NULL;
+	_put_free_rx(rx_mod, rx);
+}
+
+void
+bna_rx_enable(struct bna_rx *rx)
+{
+	if (rx->fsm != (bfa_sm_t)bna_rx_sm_stopped)
+		return;
+
+	rx->rx_flags |= BNA_RX_F_ENABLE;
+	if (rx->rx_flags & BNA_RX_F_PORT_ENABLED)
+		bfa_fsm_send_event(rx, RX_E_START);
+}
+
+void
+bna_rx_disable(struct bna_rx *rx, enum bna_cleanup_type type,
+		void (*cbfn)(void *, struct bna_rx *,
+				enum bna_cb_status))
+{
+	if (type == BNA_SOFT_CLEANUP) {
+		/* h/w should not be accessed. Treat we're stopped */
+		(*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+	} else {
+		rx->stop_cbfn = cbfn;
+		rx->stop_cbarg = rx->bna->bnad;
+
+		rx->rx_flags &= ~BNA_RX_F_ENABLE;
+
+		bfa_fsm_send_event(rx, RX_E_STOP);
+	}
+}
+
+/**
+ * TX
+ */
+#define call_tx_stop_cbfn(tx, status)\
+do {\
+	if ((tx)->stop_cbfn)\
+		(tx)->stop_cbfn((tx)->stop_cbarg, (tx), status);\
+	(tx)->stop_cbfn = NULL;\
+	(tx)->stop_cbarg = NULL;\
+} while (0)
+
+#define call_tx_prio_change_cbfn(tx, status)\
+do {\
+	if ((tx)->prio_change_cbfn)\
+		(tx)->prio_change_cbfn((tx)->bna->bnad, (tx), status);\
+	(tx)->prio_change_cbfn = NULL;\
+} while (0)
+
+static void bna_tx_mod_cb_tx_stopped(void *tx_mod, struct bna_tx *tx,
+					enum bna_cb_status status);
+static void bna_tx_cb_txq_stopped(void *arg, int status);
+static void bna_tx_cb_stats_cleared(void *arg, int status);
+static void __bna_tx_stop(struct bna_tx *tx);
+static void __bna_tx_start(struct bna_tx *tx);
+static void __bna_txf_stat_clr(struct bna_tx *tx);
+
+enum bna_tx_event {
+	TX_E_START			= 1,
+	TX_E_STOP			= 2,
+	TX_E_FAIL			= 3,
+	TX_E_TXQ_STOPPED		= 4,
+	TX_E_PRIO_CHANGE		= 5,
+	TX_E_STAT_CLEARED		= 6,
+};
+
+enum bna_tx_state {
+	BNA_TX_STOPPED			= 1,
+	BNA_TX_STARTED			= 2,
+	BNA_TX_TXQ_STOP_WAIT		= 3,
+	BNA_TX_PRIO_STOP_WAIT		= 4,
+	BNA_TX_STAT_CLR_WAIT		= 5,
+};
+
+bfa_fsm_state_decl(bna_tx, stopped, struct bna_tx,
+			enum bna_tx_event);
+bfa_fsm_state_decl(bna_tx, started, struct bna_tx,
+			enum bna_tx_event);
+bfa_fsm_state_decl(bna_tx, txq_stop_wait, struct bna_tx,
+			enum bna_tx_event);
+bfa_fsm_state_decl(bna_tx, prio_stop_wait, struct bna_tx,
+			enum bna_tx_event);
+bfa_fsm_state_decl(bna_tx, stat_clr_wait, struct bna_tx,
+			enum bna_tx_event);
+
+static struct bfa_sm_table tx_sm_table[] = {
+	{BFA_SM(bna_tx_sm_stopped), BNA_TX_STOPPED},
+	{BFA_SM(bna_tx_sm_started), BNA_TX_STARTED},
+	{BFA_SM(bna_tx_sm_txq_stop_wait), BNA_TX_TXQ_STOP_WAIT},
+	{BFA_SM(bna_tx_sm_prio_stop_wait), BNA_TX_PRIO_STOP_WAIT},
+	{BFA_SM(bna_tx_sm_stat_clr_wait), BNA_TX_STAT_CLR_WAIT},
+};
+
+static void
+bna_tx_sm_stopped_entry(struct bna_tx *tx)
+{
+	struct bna_txq *txq;
+	struct list_head		 *qe;
+
+	list_for_each(qe, &tx->txq_q) {
+		txq = (struct bna_txq *)qe;
+		(tx->tx_cleanup_cbfn)(tx->bna->bnad, txq->tcb);
+	}
+
+	call_tx_stop_cbfn(tx, BNA_CB_SUCCESS);
+}
+
+static void
+bna_tx_sm_stopped(struct bna_tx *tx, enum bna_tx_event event)
+{
+	switch (event) {
+	case TX_E_START:
+		bfa_fsm_set_state(tx, bna_tx_sm_started);
+		break;
+
+	case TX_E_STOP:
+		bfa_fsm_set_state(tx, bna_tx_sm_stopped);
+		break;
+
+	case TX_E_FAIL:
+		/* No-op */
+		break;
+
+	case TX_E_PRIO_CHANGE:
+		call_tx_prio_change_cbfn(tx, BNA_CB_SUCCESS);
+		break;
+
+	case TX_E_TXQ_STOPPED:
+		/**
+		 * This event is received due to flushing of mbox when
+		 * device fails
+		 */
+		/* No-op */
+		break;
+
+	default:
+		bfa_sm_fault(tx->bna, event);
+	}
+}
+
+static void
+bna_tx_sm_started_entry(struct bna_tx *tx)
+{
+	struct bna_txq *txq;
+	struct list_head		 *qe;
+
+	__bna_tx_start(tx);
+
+	/* Start IB */
+	list_for_each(qe, &tx->txq_q) {
+		txq = (struct bna_txq *)qe;
+		bna_ib_ack(&txq->ib->door_bell, 0);
+	}
+}
+
+static void
+bna_tx_sm_started(struct bna_tx *tx, enum bna_tx_event event)
+{
+	struct bna_txq *txq;
+	struct list_head		 *qe;
+
+	switch (event) {
+	case TX_E_STOP:
+		bfa_fsm_set_state(tx, bna_tx_sm_txq_stop_wait);
+		__bna_tx_stop(tx);
+		break;
+
+	case TX_E_FAIL:
+		list_for_each(qe, &tx->txq_q) {
+			txq = (struct bna_txq *)qe;
+			bna_ib_fail(txq->ib);
+			(tx->tx_stall_cbfn)(tx->bna->bnad, txq->tcb);
+		}
+		bfa_fsm_set_state(tx, bna_tx_sm_stopped);
+		break;
+
+	case TX_E_PRIO_CHANGE:
+		bfa_fsm_set_state(tx, bna_tx_sm_prio_stop_wait);
+		break;
+
+	default:
+		bfa_sm_fault(tx->bna, event);
+	}
+}
+
+static void
+bna_tx_sm_txq_stop_wait_entry(struct bna_tx *tx)
+{
+}
+
+static void
+bna_tx_sm_txq_stop_wait(struct bna_tx *tx, enum bna_tx_event event)
+{
+	struct bna_txq *txq;
+	struct list_head		 *qe;
+
+	switch (event) {
+	case TX_E_FAIL:
+		bfa_fsm_set_state(tx, bna_tx_sm_stopped);
+		break;
+
+	case TX_E_TXQ_STOPPED:
+		list_for_each(qe, &tx->txq_q) {
+			txq = (struct bna_txq *)qe;
+			bna_ib_stop(txq->ib);
+		}
+		bfa_fsm_set_state(tx, bna_tx_sm_stat_clr_wait);
+		break;
+
+	case TX_E_PRIO_CHANGE:
+		/* No-op */
+		break;
+
+	default:
+		bfa_sm_fault(tx->bna, event);
+	}
+}
+
+static void
+bna_tx_sm_prio_stop_wait_entry(struct bna_tx *tx)
+{
+	__bna_tx_stop(tx);
+}
+
+static void
+bna_tx_sm_prio_stop_wait(struct bna_tx *tx, enum bna_tx_event event)
+{
+	struct bna_txq *txq;
+	struct list_head		 *qe;
+
+	switch (event) {
+	case TX_E_STOP:
+		bfa_fsm_set_state(tx, bna_tx_sm_txq_stop_wait);
+		break;
+
+	case TX_E_FAIL:
+		call_tx_prio_change_cbfn(tx, BNA_CB_FAIL);
+		bfa_fsm_set_state(tx, bna_tx_sm_stopped);
+		break;
+
+	case TX_E_TXQ_STOPPED:
+		list_for_each(qe, &tx->txq_q) {
+			txq = (struct bna_txq *)qe;
+			bna_ib_stop(txq->ib);
+			(tx->tx_cleanup_cbfn)(tx->bna->bnad, txq->tcb);
+		}
+		call_tx_prio_change_cbfn(tx, BNA_CB_SUCCESS);
+		bfa_fsm_set_state(tx, bna_tx_sm_started);
+		break;
+
+	case TX_E_PRIO_CHANGE:
+		/* No-op */
+		break;
+
+	default:
+		bfa_sm_fault(tx->bna, event);
+	}
+}
+
+static void
+bna_tx_sm_stat_clr_wait_entry(struct bna_tx *tx)
+{
+	__bna_txf_stat_clr(tx);
+}
+
+static void
+bna_tx_sm_stat_clr_wait(struct bna_tx *tx, enum bna_tx_event event)
+{
+	switch (event) {
+	case TX_E_FAIL:
+	case TX_E_STAT_CLEARED:
+		bfa_fsm_set_state(tx, bna_tx_sm_stopped);
+		break;
+
+	default:
+		bfa_sm_fault(tx->bna, event);
+	}
+}
+
+static void
+__bna_txq_start(struct bna_tx *tx, struct bna_txq *txq)
+{
+	struct bna_rxtx_q_mem *q_mem;
+	struct bna_txq_mem txq_cfg;
+	struct bna_txq_mem *txq_mem;
+	struct bna_dma_addr cur_q_addr;
+	u32 pg_num;
+	void __iomem *base_addr;
+	unsigned long off;
+
+	/* Fill out structure, to be subsequently written to hardware */
+	txq_cfg.pg_tbl_addr_lo = txq->qpt.hw_qpt_ptr.lsb;
+	txq_cfg.pg_tbl_addr_hi = txq->qpt.hw_qpt_ptr.msb;
+	cur_q_addr = *((struct bna_dma_addr *)(txq->qpt.kv_qpt_ptr));
+	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 = (txq->qpt.page_count << 16) | 0x0;
+
+	txq_cfg.entry_n_pg_size = ((u32)(BFI_TXQ_WI_SIZE >> 2) << 16) |
+			(txq->qpt.page_size >> 2);
+	txq_cfg.int_blk_n_cns_ptr = ((((u32)txq->ib_seg_offset) << 24) |
+			((u32)(txq->ib->ib_id & 0xff) << 16) | 0x0);
+
+	txq_cfg.cns_ptr2_n_q_state = BNA_Q_IDLE_STATE;
+	txq_cfg.nxt_qid_n_fid_n_pri = (((tx->txf.txf_id & 0x3f) << 3) |
+			(txq->priority & 0x3));
+	txq_cfg.wvc_n_cquota_n_rquota =
+			((((u32)BFI_TX_MAX_WRR_QUOTA & 0xfff) << 12) |
+			(BFI_TX_MAX_WRR_QUOTA & 0xfff));
+
+	/* Setup the page and write to H/W */
+
+	pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + tx->bna->port_num,
+			HQM_RXTX_Q_RAM_BASE_OFFSET);
+	writel(pg_num, tx->bna->regs.page_addr);
+
+	base_addr = BNA_GET_MEM_BASE_ADDR(tx->bna->pcidev.pci_bar_kva,
+					HQM_RXTX_Q_RAM_BASE_OFFSET);
+	q_mem = (struct bna_rxtx_q_mem *)0;
+	txq_mem = &q_mem[txq->txq_id].txq;
+
+	/*
+	 * The following 4 lines, is a hack b'cos the H/W needs to read
+	 * these DMA addresses as little endian
+	 */
+
+	off = (unsigned long)&txq_mem->pg_tbl_addr_lo;
+	writel(htonl(txq_cfg.pg_tbl_addr_lo), base_addr + off);
+
+	off = (unsigned long)&txq_mem->pg_tbl_addr_hi;
+	writel(htonl(txq_cfg.pg_tbl_addr_hi), base_addr + off);
+
+	off = (unsigned long)&txq_mem->cur_q_entry_lo;
+	writel(htonl(txq_cfg.cur_q_entry_lo), base_addr + off);
+
+	off = (unsigned long)&txq_mem->cur_q_entry_hi;
+	writel(htonl(txq_cfg.cur_q_entry_hi), base_addr + off);
+
+	off = (unsigned long)&txq_mem->pg_cnt_n_prd_ptr;
+	writel(txq_cfg.pg_cnt_n_prd_ptr, base_addr + off);
+
+	off = (unsigned long)&txq_mem->entry_n_pg_size;
+	writel(txq_cfg.entry_n_pg_size, base_addr + off);
+
+	off = (unsigned long)&txq_mem->int_blk_n_cns_ptr;
+	writel(txq_cfg.int_blk_n_cns_ptr, base_addr + off);
+
+	off = (unsigned long)&txq_mem->cns_ptr2_n_q_state;
+	writel(txq_cfg.cns_ptr2_n_q_state, base_addr + off);
+
+	off = (unsigned long)&txq_mem->nxt_qid_n_fid_n_pri;
+	writel(txq_cfg.nxt_qid_n_fid_n_pri, base_addr + off);
+
+	off = (unsigned long)&txq_mem->wvc_n_cquota_n_rquota;
+	writel(txq_cfg.wvc_n_cquota_n_rquota, base_addr + off);
+
+	txq->tcb->producer_index = 0;
+	txq->tcb->consumer_index = 0;
+	*(txq->tcb->hw_consumer_index) = 0;
+
+}
+
+static void
+__bna_txq_stop(struct bna_tx *tx, struct bna_txq *txq)
+{
+	struct bfi_ll_q_stop_req ll_req;
+	u32 bit_mask[2] = {0, 0};
+	if (txq->txq_id < 32)
+		bit_mask[0] = (u32)1 << txq->txq_id;
+	else
+		bit_mask[1] = (u32)1 << (txq->txq_id - 32);
+
+	memset(&ll_req, 0, sizeof(ll_req));
+	ll_req.mh.msg_class = BFI_MC_LL;
+	ll_req.mh.msg_id = BFI_LL_H2I_TXQ_STOP_REQ;
+	ll_req.mh.mtag.h2i.lpu_id = 0;
+	ll_req.q_id_mask[0] = htonl(bit_mask[0]);
+	ll_req.q_id_mask[1] = htonl(bit_mask[1]);
+
+	bna_mbox_qe_fill(&tx->mbox_qe, &ll_req, sizeof(ll_req),
+			bna_tx_cb_txq_stopped, tx);
+
+	bna_mbox_send(tx->bna, &tx->mbox_qe);
+}
+
+static void
+__bna_txf_start(struct bna_tx *tx)
+{
+	struct bna_tx_fndb_ram *tx_fndb;
+	struct bna_txf *txf = &tx->txf;
+	void __iomem *base_addr;
+	unsigned long off;
+
+	writel(BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+			(tx->bna->port_num * 2), TX_FNDB_RAM_BASE_OFFSET),
+			tx->bna->regs.page_addr);
+
+	base_addr = BNA_GET_MEM_BASE_ADDR(tx->bna->pcidev.pci_bar_kva,
+					TX_FNDB_RAM_BASE_OFFSET);
+
+	tx_fndb = (struct bna_tx_fndb_ram *)0;
+	off = (unsigned long)&tx_fndb[txf->txf_id].vlan_n_ctrl_flags;
+
+	writel(((u32)txf->vlan << 16) | txf->ctrl_flags,
+			base_addr + off);
+
+	if (tx->txf.txf_id < 32)
+		tx->bna->tx_mod.txf_bmap[0] |= ((u32)1 << tx->txf.txf_id);
+	else
+		tx->bna->tx_mod.txf_bmap[1] |= ((u32)
+						 1 << (tx->txf.txf_id - 32));
+}
+
+static void
+__bna_txf_stop(struct bna_tx *tx)
+{
+	struct bna_tx_fndb_ram *tx_fndb;
+	u32 page_num;
+	u32 ctl_flags;
+	struct bna_txf *txf = &tx->txf;
+	void __iomem *base_addr;
+	unsigned long off;
+
+	/* retrieve the running txf_flags & turn off enable bit */
+	page_num = BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+			(tx->bna->port_num * 2), TX_FNDB_RAM_BASE_OFFSET);
+	writel(page_num, tx->bna->regs.page_addr);
+
+	base_addr = BNA_GET_MEM_BASE_ADDR(tx->bna->pcidev.pci_bar_kva,
+					TX_FNDB_RAM_BASE_OFFSET);
+	tx_fndb = (struct bna_tx_fndb_ram *)0;
+	off = (unsigned long)&tx_fndb[txf->txf_id].vlan_n_ctrl_flags;
+
+	ctl_flags = readl(base_addr + off);
+	ctl_flags &= ~BFI_TXF_CF_ENABLE;
+
+	writel(ctl_flags, base_addr + off);
+
+	if (tx->txf.txf_id < 32)
+		tx->bna->tx_mod.txf_bmap[0] &= ~((u32)1 << tx->txf.txf_id);
+	else
+		tx->bna->tx_mod.txf_bmap[0] &= ~((u32)
+						 1 << (tx->txf.txf_id - 32));
+}
+
+static void
+__bna_txf_stat_clr(struct bna_tx *tx)
+{
+	struct bfi_ll_stats_req ll_req;
+	u32 txf_bmap[2] = {0, 0};
+	if (tx->txf.txf_id < 32)
+		txf_bmap[0] = ((u32)1 << tx->txf.txf_id);
+	else
+		txf_bmap[1] = ((u32)1 << (tx->txf.txf_id - 32));
+	bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_STATS_CLEAR_REQ, 0);
+	ll_req.stats_mask = 0;
+	ll_req.rxf_id_mask[0] = 0;
+	ll_req.rxf_id_mask[1] =	0;
+	ll_req.txf_id_mask[0] =	htonl(txf_bmap[0]);
+	ll_req.txf_id_mask[1] =	htonl(txf_bmap[1]);
+
+	bna_mbox_qe_fill(&tx->mbox_qe, &ll_req, sizeof(ll_req),
+			bna_tx_cb_stats_cleared, tx);
+	bna_mbox_send(tx->bna, &tx->mbox_qe);
+}
+
+static void
+__bna_tx_start(struct bna_tx *tx)
+{
+	struct bna_txq *txq;
+	struct list_head		 *qe;
+
+	list_for_each(qe, &tx->txq_q) {
+		txq = (struct bna_txq *)qe;
+		bna_ib_start(txq->ib);
+		__bna_txq_start(tx, txq);
+	}
+
+	__bna_txf_start(tx);
+
+	list_for_each(qe, &tx->txq_q) {
+		txq = (struct bna_txq *)qe;
+		txq->tcb->priority = txq->priority;
+		(tx->tx_resume_cbfn)(tx->bna->bnad, txq->tcb);
+	}
+}
+
+static void
+__bna_tx_stop(struct bna_tx *tx)
+{
+	struct bna_txq *txq;
+	struct list_head		 *qe;
+
+	list_for_each(qe, &tx->txq_q) {
+		txq = (struct bna_txq *)qe;
+		(tx->tx_stall_cbfn)(tx->bna->bnad, txq->tcb);
+	}
+
+	__bna_txf_stop(tx);
+
+	list_for_each(qe, &tx->txq_q) {
+		txq = (struct bna_txq *)qe;
+		bfa_wc_up(&tx->txq_stop_wc);
+	}
+
+	list_for_each(qe, &tx->txq_q) {
+		txq = (struct bna_txq *)qe;
+		__bna_txq_stop(tx, txq);
+	}
+}
+
+static void
+bna_txq_qpt_setup(struct bna_txq *txq, int page_count, int page_size,
+		struct bna_mem_descr *qpt_mem,
+		struct bna_mem_descr *swqpt_mem,
+		struct bna_mem_descr *page_mem)
+{
+	int i;
+
+	txq->qpt.hw_qpt_ptr.lsb = qpt_mem->dma.lsb;
+	txq->qpt.hw_qpt_ptr.msb = qpt_mem->dma.msb;
+	txq->qpt.kv_qpt_ptr = qpt_mem->kva;
+	txq->qpt.page_count = page_count;
+	txq->qpt.page_size = page_size;
+
+	txq->tcb->sw_qpt = (void **) swqpt_mem->kva;
+
+	for (i = 0; i < page_count; i++) {
+		txq->tcb->sw_qpt[i] = page_mem[i].kva;
+
+		((struct bna_dma_addr *)txq->qpt.kv_qpt_ptr)[i].lsb =
+			page_mem[i].dma.lsb;
+		((struct bna_dma_addr *)txq->qpt.kv_qpt_ptr)[i].msb =
+			page_mem[i].dma.msb;
+
+	}
+}
+
+static void
+bna_tx_free(struct bna_tx *tx)
+{
+	struct bna_tx_mod *tx_mod = &tx->bna->tx_mod;
+	struct bna_txq *txq;
+	struct bna_ib_mod *ib_mod = &tx->bna->ib_mod;
+	struct list_head *qe;
+
+	while (!list_empty(&tx->txq_q)) {
+		bfa_q_deq(&tx->txq_q, &txq);
+		bfa_q_qe_init(&txq->qe);
+		if (txq->ib) {
+			if (txq->ib_seg_offset != -1)
+				bna_ib_release_idx(txq->ib,
+						txq->ib_seg_offset);
+			bna_ib_put(ib_mod, txq->ib);
+			txq->ib = NULL;
+		}
+		txq->tcb = NULL;
+		txq->tx = NULL;
+		list_add_tail(&txq->qe, &tx_mod->txq_free_q);
+	}
+
+	list_for_each(qe, &tx_mod->tx_active_q) {
+		if (qe == &tx->qe) {
+			list_del(&tx->qe);
+			bfa_q_qe_init(&tx->qe);
+			break;
+		}
+	}
+
+	tx->bna = NULL;
+	tx->priv = NULL;
+	list_add_tail(&tx->qe, &tx_mod->tx_free_q);
+}
+
+static void
+bna_tx_cb_txq_stopped(void *arg, int status)
+{
+	struct bna_tx *tx = (struct bna_tx *)arg;
+
+	bfa_q_qe_init(&tx->mbox_qe.qe);
+	bfa_wc_down(&tx->txq_stop_wc);
+}
+
+static void
+bna_tx_cb_txq_stopped_all(void *arg)
+{
+	struct bna_tx *tx = (struct bna_tx *)arg;
+
+	bfa_fsm_send_event(tx, TX_E_TXQ_STOPPED);
+}
+
+static void
+bna_tx_cb_stats_cleared(void *arg, int status)
+{
+	struct bna_tx *tx = (struct bna_tx *)arg;
+
+	bfa_q_qe_init(&tx->mbox_qe.qe);
+
+	bfa_fsm_send_event(tx, TX_E_STAT_CLEARED);
+}
+
+static void
+bna_tx_start(struct bna_tx *tx)
+{
+	tx->flags |= BNA_TX_F_PORT_STARTED;
+	if (tx->flags & BNA_TX_F_ENABLED)
+		bfa_fsm_send_event(tx, TX_E_START);
+}
+
+static void
+bna_tx_stop(struct bna_tx *tx)
+{
+	tx->stop_cbfn = bna_tx_mod_cb_tx_stopped;
+	tx->stop_cbarg = &tx->bna->tx_mod;
+
+	tx->flags &= ~BNA_TX_F_PORT_STARTED;
+	bfa_fsm_send_event(tx, TX_E_STOP);
+}
+
+static void
+bna_tx_fail(struct bna_tx *tx)
+{
+	tx->flags &= ~BNA_TX_F_PORT_STARTED;
+	bfa_fsm_send_event(tx, TX_E_FAIL);
+}
+
+void
+bna_tx_prio_changed(struct bna_tx *tx, int prio)
+{
+	struct bna_txq *txq;
+	struct list_head		 *qe;
+
+	list_for_each(qe, &tx->txq_q) {
+		txq = (struct bna_txq *)qe;
+		txq->priority = prio;
+	}
+
+	bfa_fsm_send_event(tx, TX_E_PRIO_CHANGE);
+}
+
+static void
+bna_tx_cee_link_status(struct bna_tx *tx, int cee_link)
+{
+	if (cee_link)
+		tx->flags |= BNA_TX_F_PRIO_LOCK;
+	else
+		tx->flags &= ~BNA_TX_F_PRIO_LOCK;
+}
+
+static void
+bna_tx_mod_cb_tx_stopped(void *arg, struct bna_tx *tx,
+			enum bna_cb_status status)
+{
+	struct bna_tx_mod *tx_mod = (struct bna_tx_mod *)arg;
+
+	bfa_wc_down(&tx_mod->tx_stop_wc);
+}
+
+static void
+bna_tx_mod_cb_tx_stopped_all(void *arg)
+{
+	struct bna_tx_mod *tx_mod = (struct bna_tx_mod *)arg;
+
+	if (tx_mod->stop_cbfn)
+		tx_mod->stop_cbfn(&tx_mod->bna->port, BNA_CB_SUCCESS);
+	tx_mod->stop_cbfn = NULL;
+}
+
+void
+bna_tx_res_req(int num_txq, int txq_depth, struct bna_res_info *res_info)
+{
+	u32 q_size;
+	u32 page_count;
+	struct bna_mem_info *mem_info;
+
+	res_info[BNA_TX_RES_MEM_T_TCB].res_type = BNA_RES_T_MEM;
+	mem_info = &res_info[BNA_TX_RES_MEM_T_TCB].res_u.mem_info;
+	mem_info->mem_type = BNA_MEM_T_KVA;
+	mem_info->len = sizeof(struct bna_tcb);
+	mem_info->num = num_txq;
+
+	q_size = txq_depth * BFI_TXQ_WI_SIZE;
+	q_size = ALIGN(q_size, PAGE_SIZE);
+	page_count = q_size >> PAGE_SHIFT;
+
+	res_info[BNA_TX_RES_MEM_T_QPT].res_type = BNA_RES_T_MEM;
+	mem_info = &res_info[BNA_TX_RES_MEM_T_QPT].res_u.mem_info;
+	mem_info->mem_type = BNA_MEM_T_DMA;
+	mem_info->len = page_count * sizeof(struct bna_dma_addr);
+	mem_info->num = num_txq;
+
+	res_info[BNA_TX_RES_MEM_T_SWQPT].res_type = BNA_RES_T_MEM;
+	mem_info = &res_info[BNA_TX_RES_MEM_T_SWQPT].res_u.mem_info;
+	mem_info->mem_type = BNA_MEM_T_KVA;
+	mem_info->len = page_count * sizeof(void *);
+	mem_info->num = num_txq;
+
+	res_info[BNA_TX_RES_MEM_T_PAGE].res_type = BNA_RES_T_MEM;
+	mem_info = &res_info[BNA_TX_RES_MEM_T_PAGE].res_u.mem_info;
+	mem_info->mem_type = BNA_MEM_T_DMA;
+	mem_info->len = PAGE_SIZE;
+	mem_info->num = num_txq * page_count;
+
+	res_info[BNA_TX_RES_INTR_T_TXCMPL].res_type = BNA_RES_T_INTR;
+	res_info[BNA_TX_RES_INTR_T_TXCMPL].res_u.intr_info.intr_type =
+			BNA_INTR_T_MSIX;
+	res_info[BNA_TX_RES_INTR_T_TXCMPL].res_u.intr_info.num = num_txq;
+}
+
+struct bna_tx *
+bna_tx_create(struct bna *bna, struct bnad *bnad,
+		struct bna_tx_config *tx_cfg,
+		struct bna_tx_event_cbfn *tx_cbfn,
+		struct bna_res_info *res_info, void *priv)
+{
+	struct bna_intr_info *intr_info;
+	struct bna_tx_mod *tx_mod = &bna->tx_mod;
+	struct bna_tx *tx;
+	struct bna_txq *txq;
+	struct list_head *qe;
+	struct bna_ib_mod *ib_mod = &bna->ib_mod;
+	struct bna_doorbell_qset *qset;
+	struct bna_ib_config ib_config;
+	int page_count;
+	int page_size;
+	int page_idx;
+	int i;
+	unsigned long off;
+
+	intr_info = &res_info[BNA_TX_RES_INTR_T_TXCMPL].res_u.intr_info;
+	page_count = (res_info[BNA_TX_RES_MEM_T_PAGE].res_u.mem_info.num) /
+			tx_cfg->num_txq;
+	page_size = res_info[BNA_TX_RES_MEM_T_PAGE].res_u.mem_info.len;
+
+	/**
+	 * Get resources
+	 */
+
+	if ((intr_info->num != 1) && (intr_info->num != tx_cfg->num_txq))
+		return NULL;
+
+	/* Tx */
+
+	if (list_empty(&tx_mod->tx_free_q))
+		return NULL;
+	bfa_q_deq(&tx_mod->tx_free_q, &tx);
+	bfa_q_qe_init(&tx->qe);
+
+	/* TxQs */
+
+	INIT_LIST_HEAD(&tx->txq_q);
+	for (i = 0; i < tx_cfg->num_txq; i++) {
+		if (list_empty(&tx_mod->txq_free_q))
+			goto err_return;
+
+		bfa_q_deq(&tx_mod->txq_free_q, &txq);
+		bfa_q_qe_init(&txq->qe);
+		list_add_tail(&txq->qe, &tx->txq_q);
+		txq->ib = NULL;
+		txq->ib_seg_offset = -1;
+		txq->tx = tx;
+	}
+
+	/* IBs */
+	i = 0;
+	list_for_each(qe, &tx->txq_q) {
+		txq = (struct bna_txq *)qe;
+
+		if (intr_info->num == 1)
+			txq->ib = bna_ib_get(ib_mod, intr_info->intr_type,
+						intr_info->idl[0].vector);
+		else
+			txq->ib = bna_ib_get(ib_mod, intr_info->intr_type,
+						intr_info->idl[i].vector);
+
+		if (txq->ib == NULL)
+			goto err_return;
+
+		txq->ib_seg_offset = bna_ib_reserve_idx(txq->ib);
+		if (txq->ib_seg_offset == -1)
+			goto err_return;
+
+		i++;
+	}
+
+	/*
+	 * Initialize
+	 */
+
+	/* Tx */
+
+	tx->tcb_setup_cbfn = tx_cbfn->tcb_setup_cbfn;
+	tx->tcb_destroy_cbfn = tx_cbfn->tcb_destroy_cbfn;
+	/* Following callbacks are mandatory */
+	tx->tx_stall_cbfn = tx_cbfn->tx_stall_cbfn;
+	tx->tx_resume_cbfn = tx_cbfn->tx_resume_cbfn;
+	tx->tx_cleanup_cbfn = tx_cbfn->tx_cleanup_cbfn;
+
+	list_add_tail(&tx->qe, &tx_mod->tx_active_q);
+	tx->bna = bna;
+	tx->priv = priv;
+	tx->txq_stop_wc.wc_resume = bna_tx_cb_txq_stopped_all;
+	tx->txq_stop_wc.wc_cbarg = tx;
+	tx->txq_stop_wc.wc_count = 0;
+
+	tx->type = tx_cfg->tx_type;
+
+	tx->flags = 0;
+	if (tx->bna->tx_mod.flags & BNA_TX_MOD_F_PORT_STARTED) {
+		switch (tx->type) {
+		case BNA_TX_T_REGULAR:
+			if (!(tx->bna->tx_mod.flags &
+				BNA_TX_MOD_F_PORT_LOOPBACK))
+				tx->flags |= BNA_TX_F_PORT_STARTED;
+			break;
+		case BNA_TX_T_LOOPBACK:
+			if (tx->bna->tx_mod.flags & BNA_TX_MOD_F_PORT_LOOPBACK)
+				tx->flags |= BNA_TX_F_PORT_STARTED;
+			break;
+		}
+	}
+	if (tx->bna->tx_mod.cee_link)
+		tx->flags |= BNA_TX_F_PRIO_LOCK;
+
+	/* TxQ */
+
+	i = 0;
+	page_idx = 0;
+	list_for_each(qe, &tx->txq_q) {
+		txq = (struct bna_txq *)qe;
+		txq->priority = tx_mod->priority;
+		txq->tcb = (struct bna_tcb *)
+		  res_info[BNA_TX_RES_MEM_T_TCB].res_u.mem_info.mdl[i].kva;
+		txq->tx_packets = 0;
+		txq->tx_bytes = 0;
+
+		/* IB */
+
+		ib_config.coalescing_timeo = BFI_TX_COALESCING_TIMEO;
+		ib_config.interpkt_timeo = 0; /* Not used */
+		ib_config.interpkt_count = BFI_TX_INTERPKT_COUNT;
+		ib_config.ctrl_flags = (BFI_IB_CF_INTER_PKT_DMA |
+					BFI_IB_CF_INT_ENABLE |
+					BFI_IB_CF_COALESCING_MODE);
+		bna_ib_config(txq->ib, &ib_config);
+
+		/* TCB */
+
+		txq->tcb->producer_index = 0;
+		txq->tcb->consumer_index = 0;
+		txq->tcb->hw_consumer_index = (volatile u32 *)
+			((volatile u8 *)txq->ib->ib_seg_host_addr_kva +
+			 (txq->ib_seg_offset * BFI_IBIDX_SIZE));
+		*(txq->tcb->hw_consumer_index) = 0;
+		txq->tcb->q_depth = tx_cfg->txq_depth;
+		txq->tcb->unmap_q = (void *)
+		res_info[BNA_TX_RES_MEM_T_UNMAPQ].res_u.mem_info.mdl[i].kva;
+		qset = (struct bna_doorbell_qset *)0;
+		off = (unsigned long)&qset[txq->txq_id].txq[0];
+		txq->tcb->q_dbell = off +
+			BNA_GET_DOORBELL_BASE_ADDR(bna->pcidev.pci_bar_kva);
+		txq->tcb->i_dbell = &txq->ib->door_bell;
+		txq->tcb->intr_type = intr_info->intr_type;
+		txq->tcb->intr_vector = (intr_info->num == 1) ?
+					intr_info->idl[0].vector :
+					intr_info->idl[i].vector;
+		txq->tcb->txq = txq;
+		txq->tcb->bnad = bnad;
+		txq->tcb->id = i;
+
+		/* QPT, SWQPT, Pages */
+		bna_txq_qpt_setup(txq, page_count, page_size,
+			&res_info[BNA_TX_RES_MEM_T_QPT].res_u.mem_info.mdl[i],
+			&res_info[BNA_TX_RES_MEM_T_SWQPT].res_u.mem_info.mdl[i],
+			&res_info[BNA_TX_RES_MEM_T_PAGE].
+				  res_u.mem_info.mdl[page_idx]);
+		txq->tcb->page_idx = page_idx;
+		txq->tcb->page_count = page_count;
+		page_idx += page_count;
+
+		/* Callback to bnad for setting up TCB */
+		if (tx->tcb_setup_cbfn)
+			(tx->tcb_setup_cbfn)(bna->bnad, txq->tcb);
+
+		i++;
+	}
+
+	/* TxF */
+
+	tx->txf.ctrl_flags = BFI_TXF_CF_ENABLE | BFI_TXF_CF_VLAN_WI_BASED;
+	tx->txf.vlan = 0;
+
+	/* Mbox element */
+	bfa_q_qe_init(&tx->mbox_qe.qe);
+
+	bfa_fsm_set_state(tx, bna_tx_sm_stopped);
+
+	return tx;
+
+err_return:
+	bna_tx_free(tx);
+	return NULL;
+}
+
+void
+bna_tx_destroy(struct bna_tx *tx)
+{
+	/* Callback to bnad for destroying TCB */
+	if (tx->tcb_destroy_cbfn) {
+		struct bna_txq *txq;
+		struct list_head *qe;
+
+		list_for_each(qe, &tx->txq_q) {
+			txq = (struct bna_txq *)qe;
+			(tx->tcb_destroy_cbfn)(tx->bna->bnad, txq->tcb);
+		}
+	}
+
+	bna_tx_free(tx);
+}
+
+void
+bna_tx_enable(struct bna_tx *tx)
+{
+	if (tx->fsm != (bfa_sm_t)bna_tx_sm_stopped)
+		return;
+
+	tx->flags |= BNA_TX_F_ENABLED;
+
+	if (tx->flags & BNA_TX_F_PORT_STARTED)
+		bfa_fsm_send_event(tx, TX_E_START);
+}
+
+void
+bna_tx_disable(struct bna_tx *tx, enum bna_cleanup_type type,
+		void (*cbfn)(void *, struct bna_tx *, enum bna_cb_status))
+{
+	if (type == BNA_SOFT_CLEANUP) {
+		(*cbfn)(tx->bna->bnad, tx, BNA_CB_SUCCESS);
+		return;
+	}
+
+	tx->stop_cbfn = cbfn;
+	tx->stop_cbarg = tx->bna->bnad;
+
+	tx->flags &= ~BNA_TX_F_ENABLED;
+
+	bfa_fsm_send_event(tx, TX_E_STOP);
+}
+
+int
+bna_tx_state_get(struct bna_tx *tx)
+{
+	return bfa_sm_to_state(tx_sm_table, tx->fsm);
+}
+
+void
+bna_tx_mod_init(struct bna_tx_mod *tx_mod, struct bna *bna,
+		struct bna_res_info *res_info)
+{
+	int i;
+
+	tx_mod->bna = bna;
+	tx_mod->flags = 0;
+
+	tx_mod->tx = (struct bna_tx *)
+		res_info[BNA_RES_MEM_T_TX_ARRAY].res_u.mem_info.mdl[0].kva;
+	tx_mod->txq = (struct bna_txq *)
+		res_info[BNA_RES_MEM_T_TXQ_ARRAY].res_u.mem_info.mdl[0].kva;
+
+	INIT_LIST_HEAD(&tx_mod->tx_free_q);
+	INIT_LIST_HEAD(&tx_mod->tx_active_q);
+
+	INIT_LIST_HEAD(&tx_mod->txq_free_q);
+
+	for (i = 0; i < BFI_MAX_TXQ; i++) {
+		tx_mod->tx[i].txf.txf_id = i;
+		bfa_q_qe_init(&tx_mod->tx[i].qe);
+		list_add_tail(&tx_mod->tx[i].qe, &tx_mod->tx_free_q);
+
+		tx_mod->txq[i].txq_id = i;
+		bfa_q_qe_init(&tx_mod->txq[i].qe);
+		list_add_tail(&tx_mod->txq[i].qe, &tx_mod->txq_free_q);
+	}
+
+	tx_mod->tx_stop_wc.wc_resume = bna_tx_mod_cb_tx_stopped_all;
+	tx_mod->tx_stop_wc.wc_cbarg = tx_mod;
+	tx_mod->tx_stop_wc.wc_count = 0;
+}
+
+void
+bna_tx_mod_uninit(struct bna_tx_mod *tx_mod)
+{
+	struct list_head		*qe;
+	int i;
+
+	i = 0;
+	list_for_each(qe, &tx_mod->tx_free_q)
+		i++;
+
+	i = 0;
+	list_for_each(qe, &tx_mod->txq_free_q)
+		i++;
+
+	tx_mod->bna = NULL;
+}
+
+void
+bna_tx_mod_start(struct bna_tx_mod *tx_mod, enum bna_tx_type type)
+{
+	struct bna_tx *tx;
+	struct list_head		*qe;
+
+	tx_mod->flags |= BNA_TX_MOD_F_PORT_STARTED;
+	if (type == BNA_TX_T_LOOPBACK)
+		tx_mod->flags |= BNA_TX_MOD_F_PORT_LOOPBACK;
+
+	list_for_each(qe, &tx_mod->tx_active_q) {
+		tx = (struct bna_tx *)qe;
+		if (tx->type == type)
+			bna_tx_start(tx);
+	}
+}
+
+void
+bna_tx_mod_stop(struct bna_tx_mod *tx_mod, enum bna_tx_type type)
+{
+	struct bna_tx *tx;
+	struct list_head		*qe;
+
+	tx_mod->flags &= ~BNA_TX_MOD_F_PORT_STARTED;
+	tx_mod->flags &= ~BNA_TX_MOD_F_PORT_LOOPBACK;
+
+	tx_mod->stop_cbfn = bna_port_cb_tx_stopped;
+
+	/**
+	 * Before calling bna_tx_stop(), increment tx_stop_wc as many times
+	 * as we are going to call bna_tx_stop
+	 */
+	list_for_each(qe, &tx_mod->tx_active_q) {
+		tx = (struct bna_tx *)qe;
+		if (tx->type == type)
+			bfa_wc_up(&tx_mod->tx_stop_wc);
+	}
+
+	if (tx_mod->tx_stop_wc.wc_count == 0) {
+		tx_mod->stop_cbfn(&tx_mod->bna->port, BNA_CB_SUCCESS);
+		tx_mod->stop_cbfn = NULL;
+		return;
+	}
+
+	list_for_each(qe, &tx_mod->tx_active_q) {
+		tx = (struct bna_tx *)qe;
+		if (tx->type == type)
+			bna_tx_stop(tx);
+	}
+}
+
+void
+bna_tx_mod_fail(struct bna_tx_mod *tx_mod)
+{
+	struct bna_tx *tx;
+	struct list_head		*qe;
+
+	tx_mod->flags &= ~BNA_TX_MOD_F_PORT_STARTED;
+	tx_mod->flags &= ~BNA_TX_MOD_F_PORT_LOOPBACK;
+
+	list_for_each(qe, &tx_mod->tx_active_q) {
+		tx = (struct bna_tx *)qe;
+		bna_tx_fail(tx);
+	}
+}
+
+void
+bna_tx_mod_prio_changed(struct bna_tx_mod *tx_mod, int prio)
+{
+	struct bna_tx *tx;
+	struct list_head		*qe;
+
+	if (prio != tx_mod->priority) {
+		tx_mod->priority = prio;
+
+		list_for_each(qe, &tx_mod->tx_active_q) {
+			tx = (struct bna_tx *)qe;
+			bna_tx_prio_changed(tx, prio);
+		}
+	}
+}
+
+void
+bna_tx_mod_cee_link_status(struct bna_tx_mod *tx_mod, int cee_link)
+{
+	struct bna_tx *tx;
+	struct list_head		*qe;
+
+	tx_mod->cee_link = cee_link;
+
+	list_for_each(qe, &tx_mod->tx_active_q) {
+		tx = (struct bna_tx *)qe;
+		bna_tx_cee_link_status(tx, cee_link);
+	}
+}
diff -ruP net-next-2.6.35-rc1-orig/drivers/net/bna/cna_fwimg.c net-next-2.6.35-rc1-mod/drivers/net/bna/cna_fwimg.c
--- net-next-2.6.35-rc1-orig/drivers/net/bna/cna_fwimg.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.35-rc1-mod/drivers/net/bna/cna_fwimg.c	2010-08-10 12:23:09.435212000 -0700
@@ -0,0 +1,64 @@
+/*
+ * 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) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#include <linux/firmware.h>
+#include "cna.h"
+
+const struct firmware *bfi_fw;
+static u32 *bfi_image_ct_cna;
+static u32 bfi_image_ct_cna_size;
+
+u32 *
+cna_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 = (u32 *)fw->data;
+	*bfi_image_size = fw->size/sizeof(u32);
+	bfi_fw = fw;
+
+	return *bfi_image;
+error:
+	return NULL;
+}
+
+u32 *
+cna_get_firmware_buf(struct pci_dev *pdev)
+{
+	if (bfi_image_ct_cna_size == 0)
+		cna_read_firmware(pdev, &bfi_image_ct_cna,
+			&bfi_image_ct_cna_size, CNA_FW_FILE_CT);
+	return bfi_image_ct_cna;
+}
+
+u32 *
+bfa_cb_image_get_chunk(int type, u32 off)
+{
+	return (u32 *)(bfi_image_ct_cna + off);
+}
+
+u32
+bfa_cb_image_get_size(int type)
+{
+	return bfi_image_ct_cna_size;
+}

^ permalink raw reply

* [PATCH 2/6] bna: Brocade 10Gb Ethernet device driver
From: Rasesh Mody @ 2010-08-11  4:30 UTC (permalink / raw)
  To: netdev; +Cc: adapter_linux_open_src_team

From: Rasesh Mody <rmody@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: Rasesh Mody <rmody@brocade.com>
---
 bfa_ioc_ct.c |  391 ++++++
 bna_ctrl.c   | 3627 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 4018 insertions(+)

diff -ruP net-next-2.6.35-rc1-orig/drivers/net/bna/bfa_ioc_ct.c net-next-2.6.35-rc1-mod/drivers/net/bna/bfa_ioc_ct.c
--- net-next-2.6.35-rc1-orig/drivers/net/bna/bfa_ioc_ct.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.35-rc1-mod/drivers/net/bna/bfa_ioc_ct.c	2010-08-10 12:23:09.306214000 -0700
@@ -0,0 +1,391 @@
+/*
+ * 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) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#include "bfa_ioc.h"
+#include "cna.h"
+#include "bfi.h"
+#include "bfi_ctreg.h"
+#include "bfa_defs.h"
+
+/*
+ * forward declarations
+ */
+static bool bfa_ioc_ct_firmware_lock(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_firmware_unlock(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_reg_init(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_map_port(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc *ioc, bool msix);
+static void bfa_ioc_ct_notify_hbfail(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc);
+
+struct bfa_ioc_hwif hwif_ct;
+
+/**
+ * Called from bfa_ioc_attach() to map asic specific calls.
+ */
+void
+bfa_ioc_set_ct_hwif(struct bfa_ioc *ioc)
+{
+	hwif_ct.ioc_pll_init = bfa_ioc_ct_pll_init;
+	hwif_ct.ioc_firmware_lock = bfa_ioc_ct_firmware_lock;
+	hwif_ct.ioc_firmware_unlock = bfa_ioc_ct_firmware_unlock;
+	hwif_ct.ioc_reg_init = bfa_ioc_ct_reg_init;
+	hwif_ct.ioc_map_port = bfa_ioc_ct_map_port;
+	hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set;
+	hwif_ct.ioc_notify_hbfail = bfa_ioc_ct_notify_hbfail;
+	hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset;
+
+	ioc->ioc_hwif = &hwif_ct;
+}
+
+/**
+ * Return true if firmware of current driver matches the running firmware.
+ */
+static bool
+bfa_ioc_ct_firmware_lock(struct bfa_ioc *ioc)
+{
+	enum bfi_ioc_state ioc_fwstate;
+	u32 usecnt;
+	struct bfi_ioc_image_hdr fwhdr;
+
+	/**
+	 * Firmware match check is relevant only for CNA.
+	 */
+	if (!ioc->cna)
+		return true;
+
+	/**
+	 * If bios boot (flash based) -- do not increment usage count
+	 */
+	if (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) <
+						BFA_IOC_FWIMG_MINSZ)
+		return true;
+
+	bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
+	usecnt = readl(ioc->ioc_regs.ioc_usage_reg);
+
+	/**
+	 * If usage count is 0, always return TRUE.
+	 */
+	if (usecnt == 0) {
+		writel(1, ioc->ioc_regs.ioc_usage_reg);
+		bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+		return true;
+	}
+
+	ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate);
+
+	/**
+	 * Use count cannot be non-zero and chip in uninitialized state.
+	 */
+	BUG_ON(!(ioc_fwstate != BFI_IOC_UNINIT));
+
+	/**
+	 * Check if another driver with a different firmware is active
+	 */
+	bfa_ioc_fwver_get(ioc, &fwhdr);
+	if (!bfa_ioc_fwver_cmp(ioc, &fwhdr)) {
+		bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+		return false;
+	}
+
+	/**
+	 * Same firmware version. Increment the reference count.
+	 */
+	usecnt++;
+	writel(usecnt, ioc->ioc_regs.ioc_usage_reg);
+	bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+	return true;
+}
+
+static void
+bfa_ioc_ct_firmware_unlock(struct bfa_ioc *ioc)
+{
+	u32 usecnt;
+
+	/**
+	 * Firmware lock is relevant only for CNA.
+	 */
+	if (!ioc->cna)
+		return;
+
+	/**
+	 * If bios boot (flash based) -- do not decrement usage count
+	 */
+	if (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) <
+						BFA_IOC_FWIMG_MINSZ)
+		return;
+
+	/**
+	 * decrement usage count
+	 */
+	bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
+	usecnt = readl(ioc->ioc_regs.ioc_usage_reg);
+	BUG_ON(!(usecnt > 0));
+
+	usecnt--;
+	writel(usecnt, ioc->ioc_regs.ioc_usage_reg);
+
+	bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+}
+
+/**
+ * Notify other functions on HB failure.
+ */
+static void
+bfa_ioc_ct_notify_hbfail(struct bfa_ioc *ioc)
+{
+	if (ioc->cna) {
+		writel(__FW_INIT_HALT_P, ioc->ioc_regs.ll_halt);
+		/* Wait for halt to take effect */
+		readl(ioc->ioc_regs.ll_halt);
+	} else {
+		writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set);
+		readl(ioc->ioc_regs.err_set);
+	}
+}
+
+/**
+ * Host to LPU mailbox message addresses
+ */
+static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = {
+	{ HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0 },
+	{ HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1 },
+	{ HOSTFN2_LPU_MBOX0_0, LPU_HOSTFN2_MBOX0_0, HOST_PAGE_NUM_FN2 },
+	{ HOSTFN3_LPU_MBOX0_8, LPU_HOSTFN3_MBOX0_8, HOST_PAGE_NUM_FN3 }
+};
+
+/**
+ * Host <-> LPU mailbox command/status registers - port 0
+ */
+static struct { u32 hfn, lpu; } iocreg_mbcmd_p0[] = {
+	{ HOSTFN0_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN0_MBOX0_CMD_STAT },
+	{ HOSTFN1_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN1_MBOX0_CMD_STAT },
+	{ HOSTFN2_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN2_MBOX0_CMD_STAT },
+	{ HOSTFN3_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN3_MBOX0_CMD_STAT }
+};
+
+/**
+ * Host <-> LPU mailbox command/status registers - port 1
+ */
+static struct { u32 hfn, lpu; } iocreg_mbcmd_p1[] = {
+	{ HOSTFN0_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN0_MBOX0_CMD_STAT },
+	{ HOSTFN1_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN1_MBOX0_CMD_STAT },
+	{ HOSTFN2_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN2_MBOX0_CMD_STAT },
+	{ HOSTFN3_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN3_MBOX0_CMD_STAT }
+};
+
+static void
+bfa_ioc_ct_reg_init(struct bfa_ioc *ioc)
+{
+	void __iomem *rb;
+	int		pcifn = bfa_ioc_pcifn(ioc);
+
+	rb = bfa_ioc_bar0(ioc);
+
+	ioc->ioc_regs.hfn_mbox = rb + iocreg_fnreg[pcifn].hfn_mbox;
+	ioc->ioc_regs.lpu_mbox = rb + iocreg_fnreg[pcifn].lpu_mbox;
+	ioc->ioc_regs.host_page_num_fn = rb + iocreg_fnreg[pcifn].hfn_pgn;
+
+	if (ioc->port_id == 0) {
+		ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG;
+		ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG;
+		ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn;
+		ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu;
+		ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0;
+	} else {
+		ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG);
+		ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG);
+		ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn;
+		ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu;
+		ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1;
+	}
+
+	/*
+	 * PSS control registers
+	 */
+	ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG);
+	ioc->ioc_regs.pss_err_status_reg = (rb + PSS_ERR_STATUS_REG);
+	ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_425_CTL_REG);
+	ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_312_CTL_REG);
+
+	/*
+	 * IOC semaphore registers and serialization
+	 */
+	ioc->ioc_regs.ioc_sem_reg = (rb + HOST_SEM0_REG);
+	ioc->ioc_regs.ioc_usage_sem_reg = (rb + HOST_SEM1_REG);
+	ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG);
+	ioc->ioc_regs.ioc_usage_reg = (rb + BFA_FW_USE_COUNT);
+
+	/**
+	 * sram memory access
+	 */
+	ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START);
+	ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CT;
+
+	/*
+	 * err set reg : for notification of hb failure in fcmode
+	 */
+	ioc->ioc_regs.err_set = (rb + ERR_SET_REG);
+}
+
+/**
+ * Initialize IOC to port mapping.
+ */
+
+#define FNC_PERS_FN_SHIFT(__fn)	((__fn) * 8)
+static void
+bfa_ioc_ct_map_port(struct bfa_ioc *ioc)
+{
+	void __iomem *rb = ioc->pcidev.pci_bar_kva;
+	u32	r32;
+
+	/**
+	 * For catapult, base port id on personality register and IOC type
+	 */
+	r32 = readl(rb + FNC_PERS_REG);
+	r32 >>= FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc));
+	ioc->port_id = (r32 & __F0_PORT_MAP_MK) >> __F0_PORT_MAP_SH;
+
+}
+
+/**
+ * Set interrupt mode for a function: INTX or MSIX
+ */
+static void
+bfa_ioc_ct_isr_mode_set(struct bfa_ioc *ioc, bool msix)
+{
+	void __iomem *rb = ioc->pcidev.pci_bar_kva;
+	u32	r32, mode;
+
+	r32 = readl(rb + FNC_PERS_REG);
+
+	mode = (r32 >> FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))) &
+		__F0_INTX_STATUS;
+
+	/**
+	 * If already in desired mode, do not change anything
+	 */
+	if (!msix && mode)
+		return;
+
+	if (msix)
+		mode = __F0_INTX_STATUS_MSIX;
+	else
+		mode = __F0_INTX_STATUS_INTA;
+
+	r32 &= ~(__F0_INTX_STATUS << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)));
+	r32 |= (mode << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)));
+
+	writel(r32, rb + FNC_PERS_REG);
+}
+
+/**
+ * Cleanup hw semaphore and usecnt registers
+ */
+static void
+bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc)
+{
+	if (ioc->cna) {
+		bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
+		writel(0, ioc->ioc_regs.ioc_usage_reg);
+		bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+	}
+
+	/*
+	 * Read the hw sem reg to make sure that it is locked
+	 * before we clear it. If it is not locked, writing 1
+	 * will lock it instead of clearing it.
+	 */
+	readl(ioc->ioc_regs.ioc_sem_reg);
+	bfa_ioc_hw_sem_release(ioc);
+}
+
+enum bfa_status
+bfa_ioc_ct_pll_init(void __iomem *rb, bool fcmode)
+{
+	u32	pll_sclk, pll_fclk, r32;
+
+	pll_sclk = __APP_PLL_312_LRESETN | __APP_PLL_312_ENARST |
+		__APP_PLL_312_RSEL200500 | __APP_PLL_312_P0_1(3U) |
+		__APP_PLL_312_JITLMT0_1(3U) |
+		__APP_PLL_312_CNTLMT0_1(1U);
+	pll_fclk = __APP_PLL_425_LRESETN | __APP_PLL_425_ENARST |
+		__APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(3U) |
+		__APP_PLL_425_JITLMT0_1(3U) |
+		__APP_PLL_425_CNTLMT0_1(1U);
+	if (fcmode) {
+		writel(0, (rb + OP_MODE));
+		writel(__APP_EMS_CMLCKSEL |
+				__APP_EMS_REFCKBUFEN2 |
+				__APP_EMS_CHANNEL_SEL,
+				(rb + ETH_MAC_SER_REG));
+	} else {
+		writel(__GLOBAL_FCOE_MODE, (rb + OP_MODE));
+		writel(__APP_EMS_REFCKBUFEN1,
+				(rb + ETH_MAC_SER_REG));
+	}
+	writel(BFI_IOC_UNINIT, (rb + BFA_IOC0_STATE_REG));
+	writel(BFI_IOC_UNINIT, (rb + BFA_IOC1_STATE_REG));
+	writel(0xffffffffU, (rb + HOSTFN0_INT_MSK));
+	writel(0xffffffffU, (rb + HOSTFN1_INT_MSK));
+	writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS));
+	writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS));
+	writel(0xffffffffU, (rb + HOSTFN0_INT_MSK));
+	writel(0xffffffffU, (rb + HOSTFN1_INT_MSK));
+	writel(pll_sclk |
+		__APP_PLL_312_LOGIC_SOFT_RESET,
+		rb + APP_PLL_312_CTL_REG);
+	writel(pll_fclk |
+		__APP_PLL_425_LOGIC_SOFT_RESET,
+		rb + APP_PLL_425_CTL_REG);
+	writel(pll_sclk |
+		__APP_PLL_312_LOGIC_SOFT_RESET | __APP_PLL_312_ENABLE,
+		rb + APP_PLL_312_CTL_REG);
+	writel(pll_fclk |
+		__APP_PLL_425_LOGIC_SOFT_RESET | __APP_PLL_425_ENABLE,
+		rb + APP_PLL_425_CTL_REG);
+	readl(rb + HOSTFN0_INT_MSK);
+	udelay(2000);
+	writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS));
+	writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS));
+	writel(pll_sclk |
+		__APP_PLL_312_ENABLE,
+		rb + APP_PLL_312_CTL_REG);
+	writel(pll_fclk |
+		__APP_PLL_425_ENABLE,
+		rb + APP_PLL_425_CTL_REG);
+	if (!fcmode) {
+		writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P0));
+		writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P1));
+	}
+	r32 = readl((rb + PSS_CTL_REG));
+	r32 &= ~__PSS_LMEM_RESET;
+	writel(r32, (rb + PSS_CTL_REG));
+	udelay(1000);
+	if (!fcmode) {
+		writel(0, (rb + PMM_1T_RESET_REG_P0));
+		writel(0, (rb + PMM_1T_RESET_REG_P1));
+	}
+
+	writel(__EDRAM_BISTR_START, (rb + MBIST_CTL_REG));
+	udelay(1000);
+	r32 = readl((rb + MBIST_STAT_REG));
+	writel(0, (rb + MBIST_CTL_REG));
+	return BFA_STATUS_OK;
+}
diff -ruP net-next-2.6.35-rc1-orig/drivers/net/bna/bna_ctrl.c net-next-2.6.35-rc1-mod/drivers/net/bna/bna_ctrl.c
--- net-next-2.6.35-rc1-orig/drivers/net/bna/bna_ctrl.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.35-rc1-mod/drivers/net/bna/bna_ctrl.c	2010-08-10 12:23:09.297213000 -0700
@@ -0,0 +1,3627 @@
+/*
+ * 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) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#include "bna.h"
+#include "bfa_sm.h"
+#include "bfa_wc.h"
+
+/**
+ * MBOX
+ */
+static int
+bna_is_aen(u8 msg_id)
+{
+	return (msg_id == BFI_LL_I2H_LINK_DOWN_AEN ||
+		msg_id == BFI_LL_I2H_LINK_UP_AEN);
+}
+
+static void
+bna_mbox_aen_callback(struct bna *bna, struct bfi_mbmsg *msg)
+{
+	struct bfi_ll_aen *aen = (struct bfi_ll_aen *)(msg);
+
+	switch (aen->mh.msg_id) {
+	case BFI_LL_I2H_LINK_UP_AEN:
+		bna_port_cb_link_up(&bna->port, aen, aen->reason);
+		break;
+	case BFI_LL_I2H_LINK_DOWN_AEN:
+		bna_port_cb_link_down(&bna->port, aen->reason);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+bna_ll_isr(void *llarg, struct bfi_mbmsg *msg)
+{
+	struct bna *bna = (struct bna *)(llarg);
+	struct bfi_ll_rsp *mb_rsp = (struct bfi_ll_rsp *)(msg);
+	struct bfi_mhdr *cmd_h, *rsp_h;
+	struct bna_mbox_qe *mb_qe = NULL;
+	int to_post = 0;
+	u8 aen = 0;
+	char message[BNA_MESSAGE_SIZE];
+
+	aen = bna_is_aen(mb_rsp->mh.msg_id);
+
+	if (!aen) {
+		mb_qe = bfa_q_first(&bna->mbox_mod.posted_q);
+		cmd_h = (struct bfi_mhdr *)(&mb_qe->cmd.msg[0]);
+		rsp_h = (struct bfi_mhdr *)(&mb_rsp->mh);
+
+		if ((BFA_I2HM(cmd_h->msg_id) == rsp_h->msg_id) &&
+		    (cmd_h->mtag.i2htok == rsp_h->mtag.i2htok)) {
+			/* Remove the request from posted_q, update state  */
+			list_del(&mb_qe->qe);
+			bna->mbox_mod.msg_pending--;
+			if (list_empty(&bna->mbox_mod.posted_q))
+				bna->mbox_mod.state = BNA_MBOX_FREE;
+			else
+				to_post = 1;
+
+			/* Dispatch the cbfn */
+			if (mb_qe->cbfn)
+				mb_qe->cbfn(mb_qe->cbarg, mb_rsp->error);
+
+			/* Post the next entry, if needed */
+			if (to_post) {
+				mb_qe = bfa_q_first(&bna->mbox_mod.posted_q);
+				bfa_ioc_mbox_queue(&bna->device.ioc,
+							&mb_qe->cmd);
+			}
+		} else {
+			snprintf(message, BNA_MESSAGE_SIZE,
+				       "No matching rsp for [%d:%d:%d]\n",
+				       mb_rsp->mh.msg_class, mb_rsp->mh.msg_id,
+				       mb_rsp->mh.mtag.i2htok);
+		pr_info("%s", message);
+		}
+
+	} else
+		bna_mbox_aen_callback(bna, msg);
+}
+
+void
+bna_err_handler(struct bna *bna, u32 intr_status)
+{
+	u32 init_halt;
+
+	if (intr_status & __HALT_STATUS_BITS) {
+		init_halt = readl(bna->device.ioc.ioc_regs.ll_halt);
+		init_halt &= ~__FW_INIT_HALT_P;
+		writel(init_halt, bna->device.ioc.ioc_regs.ll_halt);
+	}
+
+	bfa_ioc_error_isr(&bna->device.ioc);
+}
+
+void
+bna_mbox_handler(struct bna *bna, u32 intr_status)
+{
+	if (BNA_IS_ERR_INTR(intr_status)) {
+		bna_err_handler(bna, intr_status);
+		return;
+	}
+	if (BNA_IS_MBOX_INTR(intr_status))
+		bfa_ioc_mbox_isr(&bna->device.ioc);
+}
+
+void
+bna_mbox_send(struct bna *bna, struct bna_mbox_qe *mbox_qe)
+{
+	struct bfi_mhdr *mh;
+
+	mh = (struct bfi_mhdr *)(&mbox_qe->cmd.msg[0]);
+
+	mh->mtag.i2htok = htons(bna->mbox_mod.msg_ctr);
+	bna->mbox_mod.msg_ctr++;
+	bna->mbox_mod.msg_pending++;
+	if (bna->mbox_mod.state == BNA_MBOX_FREE) {
+		list_add_tail(&mbox_qe->qe, &bna->mbox_mod.posted_q);
+		bfa_ioc_mbox_queue(&bna->device.ioc, &mbox_qe->cmd);
+		bna->mbox_mod.state = BNA_MBOX_POSTED;
+	} else {
+		list_add_tail(&mbox_qe->qe, &bna->mbox_mod.posted_q);
+	}
+}
+
+void
+bna_mbox_flush_q(struct bna *bna, struct list_head *q)
+{
+	struct bna_mbox_qe *mb_qe = NULL;
+	struct bfi_mhdr *cmd_h;
+	struct list_head			*mb_q;
+	void 			(*cbfn)(void *arg, int status);
+	void 			*cbarg;
+
+	mb_q = &bna->mbox_mod.posted_q;
+
+	while (!list_empty(mb_q)) {
+		bfa_q_deq(mb_q, &mb_qe);
+		cbfn = mb_qe->cbfn;
+		cbarg = mb_qe->cbarg;
+		bfa_q_qe_init(mb_qe);
+		bna->mbox_mod.msg_pending--;
+
+		cmd_h = (struct bfi_mhdr *)(&mb_qe->cmd.msg[0]);
+		if (cbfn)
+			cbfn(cbarg, BNA_CB_NOT_EXEC);
+	}
+
+	bna->mbox_mod.state = BNA_MBOX_FREE;
+}
+
+void
+bna_mbox_mod_start(struct bna_mbox_mod *mbox_mod)
+{
+}
+
+void
+bna_mbox_mod_stop(struct bna_mbox_mod *mbox_mod)
+{
+	bna_mbox_flush_q(mbox_mod->bna, &mbox_mod->posted_q);
+}
+
+void
+bna_mbox_mod_init(struct bna_mbox_mod *mbox_mod, struct bna *bna)
+{
+	bfa_ioc_mbox_regisr(&bna->device.ioc, BFI_MC_LL, bna_ll_isr, bna);
+	mbox_mod->state = BNA_MBOX_FREE;
+	mbox_mod->msg_ctr = mbox_mod->msg_pending = 0;
+	INIT_LIST_HEAD(&mbox_mod->posted_q);
+	mbox_mod->bna = bna;
+}
+
+void
+bna_mbox_mod_uninit(struct bna_mbox_mod *mbox_mod)
+{
+	mbox_mod->bna = NULL;
+}
+
+/**
+ * LLPORT
+ */
+#define call_llport_stop_cbfn(llport, status)\
+do {\
+	if ((llport)->stop_cbfn)\
+		(llport)->stop_cbfn(&(llport)->bna->port, status);\
+	(llport)->stop_cbfn = NULL;\
+} while (0)
+
+static void bna_fw_llport_up(struct bna_llport *llport);
+static void bna_fw_cb_llport_up(void *arg, int status);
+static void bna_fw_llport_down(struct bna_llport *llport);
+static void bna_fw_cb_llport_down(void *arg, int status);
+static void bna_llport_start(struct bna_llport *llport);
+static void bna_llport_stop(struct bna_llport *llport);
+static void bna_llport_fail(struct bna_llport *llport);
+
+enum bna_llport_event {
+	LLPORT_E_START			= 1,
+	LLPORT_E_STOP			= 2,
+	LLPORT_E_FAIL			= 3,
+	LLPORT_E_UP			= 4,
+	LLPORT_E_DOWN			= 5,
+	LLPORT_E_FWRESP_UP		= 6,
+	LLPORT_E_FWRESP_DOWN		= 7
+};
+
+enum bna_llport_state {
+	BNA_LLPORT_STOPPED		= 1,
+	BNA_LLPORT_DOWN			= 2,
+	BNA_LLPORT_UP_RESP_WAIT		= 3,
+	BNA_LLPORT_DOWN_RESP_WAIT	= 4,
+	BNA_LLPORT_UP			= 5,
+	BNA_LLPORT_LAST_RESP_WAIT 	= 6
+};
+
+bfa_fsm_state_decl(bna_llport, stopped, struct bna_llport,
+			enum bna_llport_event);
+bfa_fsm_state_decl(bna_llport, down, struct bna_llport,
+			enum bna_llport_event);
+bfa_fsm_state_decl(bna_llport, up_resp_wait, struct bna_llport,
+			enum bna_llport_event);
+bfa_fsm_state_decl(bna_llport, down_resp_wait, struct bna_llport,
+			enum bna_llport_event);
+bfa_fsm_state_decl(bna_llport, up, struct bna_llport,
+			enum bna_llport_event);
+bfa_fsm_state_decl(bna_llport, last_resp_wait, struct bna_llport,
+			enum bna_llport_event);
+
+static struct bfa_sm_table llport_sm_table[] = {
+	{BFA_SM(bna_llport_sm_stopped), BNA_LLPORT_STOPPED},
+	{BFA_SM(bna_llport_sm_down), BNA_LLPORT_DOWN},
+	{BFA_SM(bna_llport_sm_up_resp_wait), BNA_LLPORT_UP_RESP_WAIT},
+	{BFA_SM(bna_llport_sm_down_resp_wait), BNA_LLPORT_DOWN_RESP_WAIT},
+	{BFA_SM(bna_llport_sm_up), BNA_LLPORT_UP},
+	{BFA_SM(bna_llport_sm_last_resp_wait), BNA_LLPORT_LAST_RESP_WAIT}
+};
+
+static void
+bna_llport_sm_stopped_entry(struct bna_llport *llport)
+{
+	llport->bna->port.link_cbfn((llport)->bna->bnad, BNA_LINK_DOWN);
+	call_llport_stop_cbfn(llport, BNA_CB_SUCCESS);
+}
+
+static void
+bna_llport_sm_stopped(struct bna_llport *llport,
+			enum bna_llport_event event)
+{
+	switch (event) {
+	case LLPORT_E_START:
+		bfa_fsm_set_state(llport, bna_llport_sm_down);
+		break;
+
+	case LLPORT_E_STOP:
+		call_llport_stop_cbfn(llport, BNA_CB_SUCCESS);
+		break;
+
+	case LLPORT_E_FAIL:
+		break;
+
+	case LLPORT_E_DOWN:
+		/* This event is received due to Rx objects failing */
+		/* No-op */
+		break;
+
+	case LLPORT_E_FWRESP_UP:
+	case LLPORT_E_FWRESP_DOWN:
+		/**
+		 * These events are received due to flushing of mbox when
+		 * device fails
+		 */
+		/* No-op */
+		break;
+
+	default:
+		bfa_sm_fault(llport->bna, event);
+	}
+}
+
+static void
+bna_llport_sm_down_entry(struct bna_llport *llport)
+{
+	bnad_cb_port_link_status((llport)->bna->bnad, BNA_LINK_DOWN);
+}
+
+static void
+bna_llport_sm_down(struct bna_llport *llport,
+			enum bna_llport_event event)
+{
+	switch (event) {
+	case LLPORT_E_STOP:
+		bfa_fsm_set_state(llport, bna_llport_sm_stopped);
+		break;
+
+	case LLPORT_E_FAIL:
+		bfa_fsm_set_state(llport, bna_llport_sm_stopped);
+		break;
+
+	case LLPORT_E_UP:
+		bfa_fsm_set_state(llport, bna_llport_sm_up_resp_wait);
+		bna_fw_llport_up(llport);
+		break;
+
+	default:
+		bfa_sm_fault(llport->bna, event);
+	}
+}
+
+static void
+bna_llport_sm_up_resp_wait_entry(struct bna_llport *llport)
+{
+	/**
+	 * NOTE: Do not call bna_fw_llport_up() here. That will over step
+	 * mbox due to down_resp_wait -> up_resp_wait transition on event
+	 * LLPORT_E_UP
+	 */
+}
+
+static void
+bna_llport_sm_up_resp_wait(struct bna_llport *llport,
+			enum bna_llport_event event)
+{
+	switch (event) {
+	case LLPORT_E_STOP:
+		bfa_fsm_set_state(llport, bna_llport_sm_last_resp_wait);
+		break;
+
+	case LLPORT_E_FAIL:
+		bfa_fsm_set_state(llport, bna_llport_sm_stopped);
+		break;
+
+	case LLPORT_E_DOWN:
+		bfa_fsm_set_state(llport, bna_llport_sm_down_resp_wait);
+		break;
+
+	case LLPORT_E_FWRESP_UP:
+		bfa_fsm_set_state(llport, bna_llport_sm_up);
+		break;
+
+	case LLPORT_E_FWRESP_DOWN:
+		/* down_resp_wait -> up_resp_wait transition on LLPORT_E_UP */
+		bna_fw_llport_up(llport);
+		break;
+
+	default:
+		bfa_sm_fault(llport->bna, event);
+	}
+}
+
+static void
+bna_llport_sm_down_resp_wait_entry(struct bna_llport *llport)
+{
+	/**
+	 * NOTE: Do not call bna_fw_llport_down() here. That will over step
+	 * mbox due to up_resp_wait -> down_resp_wait transition on event
+	 * LLPORT_E_DOWN
+	 */
+}
+
+static void
+bna_llport_sm_down_resp_wait(struct bna_llport *llport,
+			enum bna_llport_event event)
+{
+	switch (event) {
+	case LLPORT_E_STOP:
+		bfa_fsm_set_state(llport, bna_llport_sm_last_resp_wait);
+		break;
+
+	case LLPORT_E_FAIL:
+		bfa_fsm_set_state(llport, bna_llport_sm_stopped);
+		break;
+
+	case LLPORT_E_UP:
+		bfa_fsm_set_state(llport, bna_llport_sm_up_resp_wait);
+		break;
+
+	case LLPORT_E_FWRESP_UP:
+		/* up_resp_wait->down_resp_wait transition on LLPORT_E_DOWN */
+		bna_fw_llport_down(llport);
+		break;
+
+	case LLPORT_E_FWRESP_DOWN:
+		bfa_fsm_set_state(llport, bna_llport_sm_down);
+		break;
+
+	default:
+		bfa_sm_fault(llport->bna, event);
+	}
+}
+
+static void
+bna_llport_sm_up_entry(struct bna_llport *llport)
+{
+}
+
+static void
+bna_llport_sm_up(struct bna_llport *llport,
+			enum bna_llport_event event)
+{
+	switch (event) {
+	case LLPORT_E_STOP:
+		bfa_fsm_set_state(llport, bna_llport_sm_last_resp_wait);
+		bna_fw_llport_down(llport);
+		break;
+
+	case LLPORT_E_FAIL:
+		bfa_fsm_set_state(llport, bna_llport_sm_stopped);
+		break;
+
+	case LLPORT_E_DOWN:
+		bfa_fsm_set_state(llport, bna_llport_sm_down_resp_wait);
+		bna_fw_llport_down(llport);
+		break;
+
+	default:
+		bfa_sm_fault(llport->bna, event);
+	}
+}
+
+static void
+bna_llport_sm_last_resp_wait_entry(struct bna_llport *llport)
+{
+}
+
+static void
+bna_llport_sm_last_resp_wait(struct bna_llport *llport,
+			enum bna_llport_event event)
+{
+	switch (event) {
+	case LLPORT_E_FAIL:
+		bfa_fsm_set_state(llport, bna_llport_sm_stopped);
+		break;
+
+	case LLPORT_E_DOWN:
+		/**
+		 * This event is received due to Rx objects stopping in
+		 * parallel to llport
+		 */
+		/* No-op */
+		break;
+
+	case LLPORT_E_FWRESP_UP:
+		/* up_resp_wait->last_resp_wait transition on LLPORT_T_STOP */
+		bna_fw_llport_down(llport);
+		break;
+
+	case LLPORT_E_FWRESP_DOWN:
+		bfa_fsm_set_state(llport, bna_llport_sm_stopped);
+		break;
+
+	default:
+		bfa_sm_fault(llport->bna, event);
+	}
+}
+
+static void
+bna_fw_llport_admin_up(struct bna_llport *llport)
+{
+	struct bfi_ll_port_admin_req ll_req;
+
+	memset(&ll_req, 0, sizeof(ll_req));
+	ll_req.mh.msg_class = BFI_MC_LL;
+	ll_req.mh.msg_id = BFI_LL_H2I_PORT_ADMIN_REQ;
+	ll_req.mh.mtag.h2i.lpu_id = 0;
+
+	ll_req.up = BNA_STATUS_T_ENABLED;
+
+	bna_mbox_qe_fill(&llport->mbox_qe, &ll_req, sizeof(ll_req),
+			bna_fw_cb_llport_up, llport);
+
+	bna_mbox_send(llport->bna, &llport->mbox_qe);
+}
+
+static void
+bna_fw_llport_up(struct bna_llport *llport)
+{
+	if (llport->type == BNA_PORT_T_REGULAR)
+		bna_fw_llport_admin_up(llport);
+}
+
+static void
+bna_fw_cb_llport_up(void *arg, int status)
+{
+	struct bna_llport *llport = (struct bna_llport *)arg;
+
+	bfa_q_qe_init(&llport->mbox_qe.qe);
+	bfa_fsm_send_event(llport, LLPORT_E_FWRESP_UP);
+}
+
+static void
+bna_fw_llport_admin_down(struct bna_llport *llport)
+{
+	struct bfi_ll_port_admin_req ll_req;
+
+	memset(&ll_req, 0, sizeof(ll_req));
+	ll_req.mh.msg_class = BFI_MC_LL;
+	ll_req.mh.msg_id = BFI_LL_H2I_PORT_ADMIN_REQ;
+	ll_req.mh.mtag.h2i.lpu_id = 0;
+
+	ll_req.up = BNA_STATUS_T_DISABLED;
+
+	bna_mbox_qe_fill(&llport->mbox_qe, &ll_req, sizeof(ll_req),
+			bna_fw_cb_llport_down, llport);
+
+	bna_mbox_send(llport->bna, &llport->mbox_qe);
+}
+
+static void
+bna_fw_llport_down(struct bna_llport *llport)
+{
+	if (llport->type == BNA_PORT_T_REGULAR)
+		bna_fw_llport_admin_down(llport);
+}
+
+static void
+bna_fw_cb_llport_down(void *arg, int status)
+{
+	struct bna_llport *llport = (struct bna_llport *)arg;
+
+	bfa_q_qe_init(&llport->mbox_qe.qe);
+	bfa_fsm_send_event(llport, LLPORT_E_FWRESP_DOWN);
+}
+
+void
+bna_port_cb_llport_stopped(struct bna_port *port,
+				enum bna_cb_status status)
+{
+	bfa_wc_down(&port->chld_stop_wc);
+}
+
+static void
+bna_llport_init(struct bna_llport *llport, struct bna *bna)
+{
+	llport->flags |= BNA_LLPORT_F_ENABLED;
+	llport->type = BNA_PORT_T_REGULAR;
+	llport->bna = bna;
+
+	llport->link_status = BNA_LINK_DOWN;
+
+	llport->admin_up_count = 0;
+
+	llport->stop_cbfn = NULL;
+
+	bfa_q_qe_init(&llport->mbox_qe.qe);
+
+	bfa_fsm_set_state(llport, bna_llport_sm_stopped);
+}
+
+static void
+bna_llport_uninit(struct bna_llport *llport)
+{
+	llport->flags &= ~BNA_LLPORT_F_ENABLED;
+
+	llport->bna = NULL;
+}
+
+static void
+bna_llport_start(struct bna_llport *llport)
+{
+	bfa_fsm_send_event(llport, LLPORT_E_START);
+}
+
+static void
+bna_llport_stop(struct bna_llport *llport)
+{
+	llport->stop_cbfn = bna_port_cb_llport_stopped;
+
+	bfa_fsm_send_event(llport, LLPORT_E_STOP);
+}
+
+static void
+bna_llport_fail(struct bna_llport *llport)
+{
+	bfa_fsm_send_event(llport, LLPORT_E_FAIL);
+}
+
+int
+bna_llport_state_get(struct bna_llport *llport)
+{
+	return bfa_sm_to_state(llport_sm_table, llport->fsm);
+}
+
+void
+bna_llport_admin_up(struct bna_llport *llport)
+{
+	llport->admin_up_count++;
+
+	if (llport->admin_up_count == 1) {
+		llport->flags |= BNA_LLPORT_F_RX_ENABLED;
+		if (llport->flags & BNA_LLPORT_F_ENABLED)
+			bfa_fsm_send_event(llport, LLPORT_E_UP);
+	}
+}
+
+void
+bna_llport_admin_down(struct bna_llport *llport)
+{
+	llport->admin_up_count--;
+
+	if (llport->admin_up_count == 0) {
+		llport->flags &= ~BNA_LLPORT_F_RX_ENABLED;
+		if (llport->flags & BNA_LLPORT_F_ENABLED)
+			bfa_fsm_send_event(llport, LLPORT_E_DOWN);
+	}
+}
+
+/**
+ * PORT
+ */
+#define bna_port_chld_start(port)\
+do {\
+	enum bna_tx_type tx_type = ((port)->type == BNA_PORT_T_REGULAR) ?\
+					BNA_TX_T_REGULAR : BNA_TX_T_LOOPBACK;\
+	enum bna_rx_type rx_type = ((port)->type == BNA_PORT_T_REGULAR) ?\
+					BNA_RX_T_REGULAR : BNA_RX_T_LOOPBACK;\
+	bna_llport_start(&(port)->llport);\
+	bna_tx_mod_start(&(port)->bna->tx_mod, tx_type);\
+	bna_rx_mod_start(&(port)->bna->rx_mod, rx_type);\
+} while (0)
+
+#define bna_port_chld_stop(port)\
+do {\
+	enum bna_tx_type tx_type = ((port)->type == BNA_PORT_T_REGULAR) ?\
+					BNA_TX_T_REGULAR : BNA_TX_T_LOOPBACK;\
+	enum bna_rx_type rx_type = ((port)->type == BNA_PORT_T_REGULAR) ?\
+					BNA_RX_T_REGULAR : BNA_RX_T_LOOPBACK;\
+	bfa_wc_up(&(port)->chld_stop_wc);\
+	bfa_wc_up(&(port)->chld_stop_wc);\
+	bfa_wc_up(&(port)->chld_stop_wc);\
+	bna_llport_stop(&(port)->llport);\
+	bna_tx_mod_stop(&(port)->bna->tx_mod, tx_type);\
+	bna_rx_mod_stop(&(port)->bna->rx_mod, rx_type);\
+} while (0)
+
+#define bna_port_chld_fail(port)\
+do {\
+	bna_llport_fail(&(port)->llport);\
+	bna_tx_mod_fail(&(port)->bna->tx_mod);\
+	bna_rx_mod_fail(&(port)->bna->rx_mod);\
+} while (0)
+
+#define bna_port_rx_start(port)\
+do {\
+	enum bna_rx_type rx_type = ((port)->type == BNA_PORT_T_REGULAR) ?\
+					BNA_RX_T_REGULAR : BNA_RX_T_LOOPBACK;\
+	bna_rx_mod_start(&(port)->bna->rx_mod, rx_type);\
+} while (0)
+
+#define bna_port_rx_stop(port)\
+do {\
+	enum bna_rx_type rx_type = ((port)->type == BNA_PORT_T_REGULAR) ?\
+					BNA_RX_T_REGULAR : BNA_RX_T_LOOPBACK;\
+	bfa_wc_up(&(port)->chld_stop_wc);\
+	bna_rx_mod_stop(&(port)->bna->rx_mod, rx_type);\
+} while (0)
+
+#define call_port_stop_cbfn(port, status)\
+do {\
+	if ((port)->stop_cbfn)\
+		(port)->stop_cbfn((port)->stop_cbarg, status);\
+	(port)->stop_cbfn = NULL;\
+	(port)->stop_cbarg = NULL;\
+} while (0)
+
+#define call_port_pause_cbfn(port, status)\
+do {\
+	if ((port)->pause_cbfn)\
+		(port)->pause_cbfn((port)->bna->bnad, status);\
+	(port)->pause_cbfn = NULL;\
+} while (0)
+
+#define call_port_mtu_cbfn(port, status)\
+do {\
+	if ((port)->mtu_cbfn)\
+		(port)->mtu_cbfn((port)->bna->bnad, status);\
+	(port)->mtu_cbfn = NULL;\
+} while (0)
+
+static void bna_fw_pause_set(struct bna_port *port);
+static void bna_fw_cb_pause_set(void *arg, int status);
+static void bna_fw_mtu_set(struct bna_port *port);
+static void bna_fw_cb_mtu_set(void *arg, int status);
+
+enum bna_port_event {
+	PORT_E_START			= 1,
+	PORT_E_STOP			= 2,
+	PORT_E_FAIL			= 3,
+	PORT_E_PAUSE_CFG		= 4,
+	PORT_E_MTU_CFG			= 5,
+	PORT_E_CHLD_STOPPED		= 6,
+	PORT_E_FWRESP_PAUSE		= 7,
+	PORT_E_FWRESP_MTU		= 8
+};
+
+enum bna_port_state {
+	BNA_PORT_STOPPED		= 1,
+	BNA_PORT_MTU_INIT_WAIT		= 2,
+	BNA_PORT_PAUSE_INIT_WAIT	= 3,
+	BNA_PORT_LAST_RESP_WAIT		= 4,
+	BNA_PORT_STARTED		= 5,
+	BNA_PORT_PAUSE_CFG_WAIT		= 6,
+	BNA_PORT_RX_STOP_WAIT		= 7,
+	BNA_PORT_MTU_CFG_WAIT 		= 8,
+	BNA_PORT_CHLD_STOP_WAIT		= 9
+};
+
+bfa_fsm_state_decl(bna_port, stopped, struct bna_port,
+			enum bna_port_event);
+bfa_fsm_state_decl(bna_port, mtu_init_wait, struct bna_port,
+			enum bna_port_event);
+bfa_fsm_state_decl(bna_port, pause_init_wait, struct bna_port,
+			enum bna_port_event);
+bfa_fsm_state_decl(bna_port, last_resp_wait, struct bna_port,
+			enum bna_port_event);
+bfa_fsm_state_decl(bna_port, started, struct bna_port,
+			enum bna_port_event);
+bfa_fsm_state_decl(bna_port, pause_cfg_wait, struct bna_port,
+			enum bna_port_event);
+bfa_fsm_state_decl(bna_port, rx_stop_wait, struct bna_port,
+			enum bna_port_event);
+bfa_fsm_state_decl(bna_port, mtu_cfg_wait, struct bna_port,
+			enum bna_port_event);
+bfa_fsm_state_decl(bna_port, chld_stop_wait, struct bna_port,
+			enum bna_port_event);
+
+static struct bfa_sm_table port_sm_table[] = {
+	{BFA_SM(bna_port_sm_stopped), BNA_PORT_STOPPED},
+	{BFA_SM(bna_port_sm_mtu_init_wait), BNA_PORT_MTU_INIT_WAIT},
+	{BFA_SM(bna_port_sm_pause_init_wait), BNA_PORT_PAUSE_INIT_WAIT},
+	{BFA_SM(bna_port_sm_last_resp_wait), BNA_PORT_LAST_RESP_WAIT},
+	{BFA_SM(bna_port_sm_started), BNA_PORT_STARTED},
+	{BFA_SM(bna_port_sm_pause_cfg_wait), BNA_PORT_PAUSE_CFG_WAIT},
+	{BFA_SM(bna_port_sm_rx_stop_wait), BNA_PORT_RX_STOP_WAIT},
+	{BFA_SM(bna_port_sm_mtu_cfg_wait), BNA_PORT_MTU_CFG_WAIT},
+	{BFA_SM(bna_port_sm_chld_stop_wait), BNA_PORT_CHLD_STOP_WAIT}
+};
+
+static void
+bna_port_sm_stopped_entry(struct bna_port *port)
+{
+	call_port_pause_cbfn(port, BNA_CB_SUCCESS);
+	call_port_mtu_cbfn(port, BNA_CB_SUCCESS);
+	call_port_stop_cbfn(port, BNA_CB_SUCCESS);
+}
+
+static void
+bna_port_sm_stopped(struct bna_port *port, enum bna_port_event event)
+{
+	switch (event) {
+	case PORT_E_START:
+		bfa_fsm_set_state(port, bna_port_sm_mtu_init_wait);
+		break;
+
+	case PORT_E_STOP:
+		call_port_stop_cbfn(port, BNA_CB_SUCCESS);
+		break;
+
+	case PORT_E_FAIL:
+		/* No-op */
+		break;
+
+	case PORT_E_PAUSE_CFG:
+		call_port_pause_cbfn(port, BNA_CB_SUCCESS);
+		break;
+
+	case PORT_E_MTU_CFG:
+		call_port_mtu_cbfn(port, BNA_CB_SUCCESS);
+		break;
+
+	case PORT_E_CHLD_STOPPED:
+		/**
+		 * This event is received due to LLPort, Tx and Rx objects
+		 * failing
+		 */
+		/* No-op */
+		break;
+
+	case PORT_E_FWRESP_PAUSE:
+	case PORT_E_FWRESP_MTU:
+		/**
+		 * These events are received due to flushing of mbox when
+		 * device fails
+		 */
+		/* No-op */
+		break;
+
+	default:
+		bfa_sm_fault(port->bna, event);
+	}
+}
+
+static void
+bna_port_sm_mtu_init_wait_entry(struct bna_port *port)
+{
+	bna_fw_mtu_set(port);
+}
+
+static void
+bna_port_sm_mtu_init_wait(struct bna_port *port, enum bna_port_event event)
+{
+	switch (event) {
+	case PORT_E_STOP:
+		bfa_fsm_set_state(port, bna_port_sm_last_resp_wait);
+		break;
+
+	case PORT_E_FAIL:
+		bfa_fsm_set_state(port, bna_port_sm_stopped);
+		break;
+
+	case PORT_E_PAUSE_CFG:
+		/* No-op */
+		break;
+
+	case PORT_E_MTU_CFG:
+		port->flags |= BNA_PORT_F_MTU_CHANGED;
+		break;
+
+	case PORT_E_FWRESP_MTU:
+		if (port->flags & BNA_PORT_F_MTU_CHANGED) {
+			port->flags &= ~BNA_PORT_F_MTU_CHANGED;
+			bna_fw_mtu_set(port);
+		} else {
+			bfa_fsm_set_state(port, bna_port_sm_pause_init_wait);
+		}
+		break;
+
+	default:
+		bfa_sm_fault(port->bna, event);
+	}
+}
+
+static void
+bna_port_sm_pause_init_wait_entry(struct bna_port *port)
+{
+	bna_fw_pause_set(port);
+}
+
+static void
+bna_port_sm_pause_init_wait(struct bna_port *port,
+				enum bna_port_event event)
+{
+	switch (event) {
+	case PORT_E_STOP:
+		bfa_fsm_set_state(port, bna_port_sm_last_resp_wait);
+		break;
+
+	case PORT_E_FAIL:
+		bfa_fsm_set_state(port, bna_port_sm_stopped);
+		break;
+
+	case PORT_E_PAUSE_CFG:
+		port->flags |= BNA_PORT_F_PAUSE_CHANGED;
+		break;
+
+	case PORT_E_MTU_CFG:
+		port->flags |= BNA_PORT_F_MTU_CHANGED;
+		break;
+
+	case PORT_E_FWRESP_PAUSE:
+		if (port->flags & BNA_PORT_F_PAUSE_CHANGED) {
+			port->flags &= ~BNA_PORT_F_PAUSE_CHANGED;
+			bna_fw_pause_set(port);
+		} else if (port->flags & BNA_PORT_F_MTU_CHANGED) {
+			port->flags &= ~BNA_PORT_F_MTU_CHANGED;
+			bfa_fsm_set_state(port, bna_port_sm_mtu_init_wait);
+		} else {
+			bfa_fsm_set_state(port, bna_port_sm_started);
+			bna_port_chld_start(port);
+		}
+		break;
+
+	default:
+		bfa_sm_fault(port->bna, event);
+	}
+}
+
+static void
+bna_port_sm_last_resp_wait_entry(struct bna_port *port)
+{
+}
+
+static void
+bna_port_sm_last_resp_wait(struct bna_port *port,
+				enum bna_port_event event)
+{
+	switch (event) {
+	case PORT_E_FAIL:
+	case PORT_E_FWRESP_PAUSE:
+	case PORT_E_FWRESP_MTU:
+		bfa_fsm_set_state(port, bna_port_sm_stopped);
+		break;
+
+	default:
+		bfa_sm_fault(port->bna, event);
+	}
+}
+
+static void
+bna_port_sm_started_entry(struct bna_port *port)
+{
+	/**
+	 * NOTE: Do not call bna_port_chld_start() here, since it will be
+	 * inadvertently called during pause_cfg_wait->started transition
+	 * as well
+	 */
+	call_port_pause_cbfn(port, BNA_CB_SUCCESS);
+	call_port_mtu_cbfn(port, BNA_CB_SUCCESS);
+}
+
+static void
+bna_port_sm_started(struct bna_port *port,
+			enum bna_port_event event)
+{
+	switch (event) {
+	case PORT_E_STOP:
+		bfa_fsm_set_state(port, bna_port_sm_chld_stop_wait);
+		break;
+
+	case PORT_E_FAIL:
+		bfa_fsm_set_state(port, bna_port_sm_stopped);
+		bna_port_chld_fail(port);
+		break;
+
+	case PORT_E_PAUSE_CFG:
+		bfa_fsm_set_state(port, bna_port_sm_pause_cfg_wait);
+		break;
+
+	case PORT_E_MTU_CFG:
+		bfa_fsm_set_state(port, bna_port_sm_rx_stop_wait);
+		break;
+
+	default:
+		bfa_sm_fault(port->bna, event);
+	}
+}
+
+static void
+bna_port_sm_pause_cfg_wait_entry(struct bna_port *port)
+{
+	bna_fw_pause_set(port);
+}
+
+static void
+bna_port_sm_pause_cfg_wait(struct bna_port *port,
+				enum bna_port_event event)
+{
+	switch (event) {
+	case PORT_E_FAIL:
+		bfa_fsm_set_state(port, bna_port_sm_stopped);
+		bna_port_chld_fail(port);
+		break;
+
+	case PORT_E_FWRESP_PAUSE:
+		bfa_fsm_set_state(port, bna_port_sm_started);
+		break;
+
+	default:
+		bfa_sm_fault(port->bna, event);
+	}
+}
+
+static void
+bna_port_sm_rx_stop_wait_entry(struct bna_port *port)
+{
+	bna_port_rx_stop(port);
+}
+
+static void
+bna_port_sm_rx_stop_wait(struct bna_port *port,
+				enum bna_port_event event)
+{
+	switch (event) {
+	case PORT_E_FAIL:
+		bfa_fsm_set_state(port, bna_port_sm_stopped);
+		bna_port_chld_fail(port);
+		break;
+
+	case PORT_E_CHLD_STOPPED:
+		bfa_fsm_set_state(port, bna_port_sm_mtu_cfg_wait);
+		break;
+
+	default:
+		bfa_sm_fault(port->bna, event);
+	}
+}
+
+static void
+bna_port_sm_mtu_cfg_wait_entry(struct bna_port *port)
+{
+	bna_fw_mtu_set(port);
+}
+
+static void
+bna_port_sm_mtu_cfg_wait(struct bna_port *port, enum bna_port_event event)
+{
+	switch (event) {
+	case PORT_E_FAIL:
+		bfa_fsm_set_state(port, bna_port_sm_stopped);
+		bna_port_chld_fail(port);
+		break;
+
+	case PORT_E_FWRESP_MTU:
+		bfa_fsm_set_state(port, bna_port_sm_started);
+		bna_port_rx_start(port);
+		break;
+
+	default:
+		bfa_sm_fault(port->bna, event);
+	}
+}
+
+static void
+bna_port_sm_chld_stop_wait_entry(struct bna_port *port)
+{
+	bna_port_chld_stop(port);
+}
+
+static void
+bna_port_sm_chld_stop_wait(struct bna_port *port,
+				enum bna_port_event event)
+{
+	switch (event) {
+	case PORT_E_FAIL:
+		bfa_fsm_set_state(port, bna_port_sm_stopped);
+		bna_port_chld_fail(port);
+		break;
+
+	case PORT_E_CHLD_STOPPED:
+		bfa_fsm_set_state(port, bna_port_sm_stopped);
+		break;
+
+	default:
+		bfa_sm_fault(port->bna, event);
+	}
+}
+
+static void
+bna_fw_pause_set(struct bna_port *port)
+{
+	struct bfi_ll_set_pause_req ll_req;
+
+	memset(&ll_req, 0, sizeof(ll_req));
+	ll_req.mh.msg_class = BFI_MC_LL;
+	ll_req.mh.msg_id = BFI_LL_H2I_SET_PAUSE_REQ;
+	ll_req.mh.mtag.h2i.lpu_id = 0;
+
+	ll_req.tx_pause = port->pause_config.tx_pause;
+	ll_req.rx_pause = port->pause_config.rx_pause;
+
+	bna_mbox_qe_fill(&port->mbox_qe, &ll_req, sizeof(ll_req),
+			bna_fw_cb_pause_set, port);
+
+	bna_mbox_send(port->bna, &port->mbox_qe);
+}
+
+static void
+bna_fw_cb_pause_set(void *arg, int status)
+{
+	struct bna_port *port = (struct bna_port *)arg;
+
+	bfa_q_qe_init(&port->mbox_qe.qe);
+	bfa_fsm_send_event(port, PORT_E_FWRESP_PAUSE);
+}
+
+void
+bna_fw_mtu_set(struct bna_port *port)
+{
+	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((u16)port->mtu);
+
+	bna_mbox_qe_fill(&port->mbox_qe, &ll_req, sizeof(ll_req),
+				bna_fw_cb_mtu_set, port);
+	bna_mbox_send(port->bna, &port->mbox_qe);
+}
+
+void
+bna_fw_cb_mtu_set(void *arg, int status)
+{
+	struct bna_port *port = (struct bna_port *)arg;
+
+	bfa_q_qe_init(&port->mbox_qe.qe);
+	bfa_fsm_send_event(port, PORT_E_FWRESP_MTU);
+}
+
+static void
+bna_port_cb_chld_stopped(void *arg)
+{
+	struct bna_port *port = (struct bna_port *)arg;
+
+	bfa_fsm_send_event(port, PORT_E_CHLD_STOPPED);
+}
+
+void
+bna_port_init(struct bna_port *port, struct bna *bna)
+{
+	port->bna = bna;
+	port->flags = 0;
+	port->mtu = 0;
+	port->type = BNA_PORT_T_REGULAR;
+
+	port->link_cbfn = bnad_cb_port_link_status;
+
+	port->chld_stop_wc.wc_resume = bna_port_cb_chld_stopped;
+	port->chld_stop_wc.wc_cbarg = port;
+	port->chld_stop_wc.wc_count = 0;
+
+	port->stop_cbfn = NULL;
+	port->stop_cbarg = NULL;
+
+	port->pause_cbfn = NULL;
+
+	port->mtu_cbfn = NULL;
+
+	bfa_q_qe_init(&port->mbox_qe.qe);
+
+	bfa_fsm_set_state(port, bna_port_sm_stopped);
+
+	bna_llport_init(&port->llport, bna);
+}
+
+void
+bna_port_uninit(struct bna_port *port)
+{
+	bna_llport_uninit(&port->llport);
+
+	port->flags = 0;
+
+	port->bna = NULL;
+}
+
+int
+bna_port_state_get(struct bna_port *port)
+{
+	return bfa_sm_to_state(port_sm_table, port->fsm);
+}
+
+void
+bna_port_start(struct bna_port *port)
+{
+	port->flags |= BNA_PORT_F_DEVICE_READY;
+	if (port->flags & BNA_PORT_F_ENABLED)
+		bfa_fsm_send_event(port, PORT_E_START);
+}
+
+void
+bna_port_stop(struct bna_port *port)
+{
+	port->stop_cbfn = bna_device_cb_port_stopped;
+	port->stop_cbarg = &port->bna->device;
+
+	port->flags &= ~BNA_PORT_F_DEVICE_READY;
+	bfa_fsm_send_event(port, PORT_E_STOP);
+}
+
+void
+bna_port_fail(struct bna_port *port)
+{
+	port->flags &= ~BNA_PORT_F_DEVICE_READY;
+	bfa_fsm_send_event(port, PORT_E_FAIL);
+}
+
+void
+bna_port_cb_tx_stopped(struct bna_port *port, enum bna_cb_status status)
+{
+	bfa_wc_down(&port->chld_stop_wc);
+}
+
+void
+bna_port_cb_rx_stopped(struct bna_port *port, enum bna_cb_status status)
+{
+	bfa_wc_down(&port->chld_stop_wc);
+}
+
+void
+bna_port_cb_link_up(struct bna_port *port, struct bfi_ll_aen *aen,
+			int status)
+{
+	int i;
+	u8 prio_map;
+
+	port->llport.link_status = BNA_LINK_UP;
+	if (aen->cee_linkup)
+		port->llport.link_status = BNA_CEE_UP;
+
+	/* Compute the priority */
+	prio_map = aen->prio_map;
+	if (prio_map) {
+		for (i = 0; i < 8; i++) {
+			if ((prio_map >> i) & 0x1)
+				break;
+		}
+		port->priority = i;
+	} else
+		port->priority = 0;
+
+	/* Dispatch events */
+	bna_tx_mod_cee_link_status(&port->bna->tx_mod, aen->cee_linkup);
+	bna_tx_mod_prio_changed(&port->bna->tx_mod, port->priority);
+	port->link_cbfn(port->bna->bnad, port->llport.link_status);
+}
+
+void
+bna_port_cb_link_down(struct bna_port *port, int status)
+{
+	port->llport.link_status = BNA_LINK_DOWN;
+
+	/* Dispatch events */
+	bna_tx_mod_cee_link_status(&port->bna->tx_mod, BNA_LINK_DOWN);
+	port->link_cbfn(port->bna->bnad, BNA_LINK_DOWN);
+}
+
+int
+bna_port_mtu_get(struct bna_port *port)
+{
+	return port->mtu;
+}
+
+void
+bna_port_enable(struct bna_port *port)
+{
+	if (port->fsm != (bfa_sm_t)bna_port_sm_stopped)
+		return;
+
+	port->flags |= BNA_PORT_F_ENABLED;
+
+	if (port->flags & BNA_PORT_F_DEVICE_READY)
+		bfa_fsm_send_event(port, PORT_E_START);
+}
+
+void
+bna_port_disable(struct bna_port *port, enum bna_cleanup_type type,
+		 void (*cbfn)(void *, enum bna_cb_status))
+{
+	if (type == BNA_SOFT_CLEANUP) {
+		(*cbfn)(port->bna->bnad, BNA_CB_SUCCESS);
+		return;
+	}
+
+	port->stop_cbfn = cbfn;
+	port->stop_cbarg = port->bna->bnad;
+
+	port->flags &= ~BNA_PORT_F_ENABLED;
+
+	bfa_fsm_send_event(port, PORT_E_STOP);
+}
+
+void
+bna_port_pause_config(struct bna_port *port,
+		      struct bna_pause_config *pause_config,
+		      void (*cbfn)(struct bnad *, enum bna_cb_status))
+{
+	port->pause_config = *pause_config;
+
+	port->pause_cbfn = cbfn;
+
+	bfa_fsm_send_event(port, PORT_E_PAUSE_CFG);
+}
+
+void
+bna_port_mtu_set(struct bna_port *port, int mtu,
+		 void (*cbfn)(struct bnad *, enum bna_cb_status))
+{
+	port->mtu = mtu;
+
+	port->mtu_cbfn = cbfn;
+
+	bfa_fsm_send_event(port, PORT_E_MTU_CFG);
+}
+
+void
+bna_port_mac_get(struct bna_port *port, mac_t *mac)
+{
+	*mac = bfa_ioc_get_mac(&port->bna->device.ioc);
+}
+
+/**
+ * Should be called only when port is disabled
+ */
+void
+bna_port_type_set(struct bna_port *port, enum bna_port_type type)
+{
+	port->type = type;
+	port->llport.type = type;
+}
+
+/**
+ * Should be called only when port is disabled
+ */
+void
+bna_port_linkcbfn_set(struct bna_port *port,
+		      void (*linkcbfn)(struct bnad *, enum bna_link_status))
+{
+	port->link_cbfn = linkcbfn;
+}
+
+void
+bna_port_admin_up(struct bna_port *port)
+{
+	struct bna_llport *llport = &port->llport;
+
+	if (llport->flags & BNA_LLPORT_F_ENABLED)
+		return;
+
+	llport->flags |= BNA_LLPORT_F_ENABLED;
+
+	if (llport->flags & BNA_LLPORT_F_RX_ENABLED)
+		bfa_fsm_send_event(llport, LLPORT_E_UP);
+}
+
+void
+bna_port_admin_down(struct bna_port *port)
+{
+	struct bna_llport *llport = &port->llport;
+
+	if (!(llport->flags & BNA_LLPORT_F_ENABLED))
+		return;
+
+	llport->flags &= ~BNA_LLPORT_F_ENABLED;
+
+	if (llport->flags & BNA_LLPORT_F_RX_ENABLED)
+		bfa_fsm_send_event(llport, LLPORT_E_DOWN);
+}
+
+/**
+ * DEVICE
+ */
+#define enable_mbox_intr(_device)\
+do {\
+	u32 intr_status;\
+	bna_intr_status_get((_device)->bna, intr_status);\
+	bnad_cb_device_enable_mbox_intr((_device)->bna->bnad);\
+	bna_mbox_intr_enable((_device)->bna);\
+} while (0)
+
+#define disable_mbox_intr(_device)\
+do {\
+	bna_mbox_intr_disable((_device)->bna);\
+	bnad_cb_device_disable_mbox_intr((_device)->bna->bnad);\
+} while (0)
+
+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},
+};
+
+enum bna_device_event {
+	DEVICE_E_ENABLE			= 1,
+	DEVICE_E_DISABLE		= 2,
+	DEVICE_E_IOC_READY		= 3,
+	DEVICE_E_IOC_FAILED		= 4,
+	DEVICE_E_IOC_DISABLED		= 5,
+	DEVICE_E_IOC_RESET		= 6,
+	DEVICE_E_PORT_STOPPED		= 7,
+};
+
+enum bna_device_state {
+	BNA_DEVICE_STOPPED		= 1,
+	BNA_DEVICE_IOC_READY_WAIT 	= 2,
+	BNA_DEVICE_READY		= 3,
+	BNA_DEVICE_PORT_STOP_WAIT 	= 4,
+	BNA_DEVICE_IOC_DISABLE_WAIT 	= 5,
+	BNA_DEVICE_FAILED		= 6
+};
+
+bfa_fsm_state_decl(bna_device, stopped, struct bna_device,
+			enum bna_device_event);
+bfa_fsm_state_decl(bna_device, ioc_ready_wait, struct bna_device,
+			enum bna_device_event);
+bfa_fsm_state_decl(bna_device, ready, struct bna_device,
+			enum bna_device_event);
+bfa_fsm_state_decl(bna_device, port_stop_wait, struct bna_device,
+			enum bna_device_event);
+bfa_fsm_state_decl(bna_device, ioc_disable_wait, struct bna_device,
+			enum bna_device_event);
+bfa_fsm_state_decl(bna_device, failed, struct bna_device,
+			enum bna_device_event);
+
+static struct bfa_sm_table device_sm_table[] = {
+	{BFA_SM(bna_device_sm_stopped), BNA_DEVICE_STOPPED},
+	{BFA_SM(bna_device_sm_ioc_ready_wait), BNA_DEVICE_IOC_READY_WAIT},
+	{BFA_SM(bna_device_sm_ready), BNA_DEVICE_READY},
+	{BFA_SM(bna_device_sm_port_stop_wait), BNA_DEVICE_PORT_STOP_WAIT},
+	{BFA_SM(bna_device_sm_ioc_disable_wait), BNA_DEVICE_IOC_DISABLE_WAIT},
+	{BFA_SM(bna_device_sm_failed), BNA_DEVICE_FAILED},
+};
+
+static void
+bna_device_sm_stopped_entry(struct bna_device *device)
+{
+	if (device->stop_cbfn)
+		device->stop_cbfn(device->stop_cbarg, BNA_CB_SUCCESS);
+
+	device->stop_cbfn = NULL;
+	device->stop_cbarg = NULL;
+}
+
+static void
+bna_device_sm_stopped(struct bna_device *device,
+			enum bna_device_event event)
+{
+	switch (event) {
+	case DEVICE_E_ENABLE:
+		if (device->intr_type == BNA_INTR_T_MSIX)
+			bna_mbox_msix_idx_set(device);
+		bfa_ioc_enable(&device->ioc);
+		bfa_fsm_set_state(device, bna_device_sm_ioc_ready_wait);
+		break;
+
+	case DEVICE_E_DISABLE:
+		bfa_fsm_set_state(device, bna_device_sm_stopped);
+		break;
+
+	case DEVICE_E_IOC_RESET:
+		enable_mbox_intr(device);
+		break;
+
+	case DEVICE_E_IOC_FAILED:
+		bfa_fsm_set_state(device, bna_device_sm_failed);
+		break;
+
+	default:
+		bfa_sm_fault(device->bna, event);
+	}
+}
+
+static void
+bna_device_sm_ioc_ready_wait_entry(struct bna_device *device)
+{
+	/**
+	 * Do not call bfa_ioc_enable() here. It must be called in the
+	 * previous state due to failed -> ioc_ready_wait transition.
+	 */
+}
+
+static void
+bna_device_sm_ioc_ready_wait(struct bna_device *device,
+				enum bna_device_event event)
+{
+	switch (event) {
+	case DEVICE_E_DISABLE:
+		if (device->ready_cbfn)
+			device->ready_cbfn(device->ready_cbarg,
+						BNA_CB_INTERRUPT);
+		device->ready_cbfn = NULL;
+		device->ready_cbarg = NULL;
+		bfa_fsm_set_state(device, bna_device_sm_ioc_disable_wait);
+		break;
+
+	case DEVICE_E_IOC_READY:
+		bfa_fsm_set_state(device, bna_device_sm_ready);
+		break;
+
+	case DEVICE_E_IOC_FAILED:
+		bfa_fsm_set_state(device, bna_device_sm_failed);
+		break;
+
+	case DEVICE_E_IOC_RESET:
+		enable_mbox_intr(device);
+		break;
+
+	default:
+		bfa_sm_fault(device->bna, event);
+	}
+}
+
+static void
+bna_device_sm_ready_entry(struct bna_device *device)
+{
+	bna_mbox_mod_start(&device->bna->mbox_mod);
+	bna_port_start(&device->bna->port);
+
+	if (device->ready_cbfn)
+		device->ready_cbfn(device->ready_cbarg,
+					BNA_CB_SUCCESS);
+	device->ready_cbfn = NULL;
+	device->ready_cbarg = NULL;
+}
+
+static void
+bna_device_sm_ready(struct bna_device *device, enum bna_device_event event)
+{
+	switch (event) {
+	case DEVICE_E_DISABLE:
+		bfa_fsm_set_state(device, bna_device_sm_port_stop_wait);
+		break;
+
+	case DEVICE_E_IOC_FAILED:
+		bfa_fsm_set_state(device, bna_device_sm_failed);
+		break;
+
+	default:
+		bfa_sm_fault(device->bna, event);
+	}
+}
+
+static void
+bna_device_sm_port_stop_wait_entry(struct bna_device *device)
+{
+	bna_port_stop(&device->bna->port);
+}
+
+static void
+bna_device_sm_port_stop_wait(struct bna_device *device,
+				enum bna_device_event event)
+{
+	switch (event) {
+	case DEVICE_E_PORT_STOPPED:
+		bna_mbox_mod_stop(&device->bna->mbox_mod);
+		bfa_fsm_set_state(device, bna_device_sm_ioc_disable_wait);
+		break;
+
+	case DEVICE_E_IOC_FAILED:
+		disable_mbox_intr(device);
+		bna_port_fail(&device->bna->port);
+		break;
+
+	default:
+		bfa_sm_fault(device->bna, event);
+	}
+}
+
+static void
+bna_device_sm_ioc_disable_wait_entry(struct bna_device *device)
+{
+	bfa_ioc_disable(&device->ioc);
+}
+
+static void
+bna_device_sm_ioc_disable_wait(struct bna_device *device,
+				enum bna_device_event event)
+{
+	switch (event) {
+	case DEVICE_E_IOC_DISABLED:
+		disable_mbox_intr(device);
+		bfa_fsm_set_state(device, bna_device_sm_stopped);
+		break;
+
+	default:
+		bfa_sm_fault(device->bna, event);
+	}
+}
+
+static void
+bna_device_sm_failed_entry(struct bna_device *device)
+{
+	disable_mbox_intr(device);
+	bna_port_fail(&device->bna->port);
+	bna_mbox_mod_stop(&device->bna->mbox_mod);
+
+	if (device->ready_cbfn)
+		device->ready_cbfn(device->ready_cbarg,
+					BNA_CB_FAIL);
+	device->ready_cbfn = NULL;
+	device->ready_cbarg = NULL;
+}
+
+static void
+bna_device_sm_failed(struct bna_device *device,
+			enum bna_device_event event)
+{
+	switch (event) {
+	case DEVICE_E_DISABLE:
+		bfa_fsm_set_state(device, bna_device_sm_ioc_disable_wait);
+		break;
+
+	case DEVICE_E_IOC_RESET:
+		enable_mbox_intr(device);
+		bfa_fsm_set_state(device, bna_device_sm_ioc_ready_wait);
+		break;
+
+	default:
+		bfa_sm_fault(device->bna, event);
+	}
+}
+
+/* IOC callback functions */
+
+static void
+bna_device_cb_iocll_ready(void *dev, enum bfa_status error)
+{
+	struct bna_device *device = (struct bna_device *)dev;
+
+	if (error)
+		bfa_fsm_send_event(device, DEVICE_E_IOC_FAILED);
+	else
+		bfa_fsm_send_event(device, DEVICE_E_IOC_READY);
+}
+
+static void
+bna_device_cb_iocll_disabled(void *dev)
+{
+	struct bna_device *device = (struct bna_device *)dev;
+
+	bfa_fsm_send_event(device, DEVICE_E_IOC_DISABLED);
+}
+
+static void
+bna_device_cb_iocll_failed(void *dev)
+{
+	struct bna_device *device = (struct bna_device *)dev;
+
+	bfa_fsm_send_event(device, DEVICE_E_IOC_FAILED);
+}
+
+static void
+bna_device_cb_iocll_reset(void *dev)
+{
+	struct bna_device *device = (struct bna_device *)dev;
+
+	bfa_fsm_send_event(device, DEVICE_E_IOC_RESET);
+}
+
+static struct bfa_ioc_cbfn bfa_iocll_cbfn = {
+	bna_device_cb_iocll_ready,
+	bna_device_cb_iocll_disabled,
+	bna_device_cb_iocll_failed,
+	bna_device_cb_iocll_reset
+};
+
+void
+bna_device_init(struct bna_device *device, struct bna *bna,
+		struct bna_res_info *res_info)
+{
+	u64 dma;
+
+	device->bna = bna;
+
+	/**
+	 * Attach IOC and claim:
+	 *	1. DMA memory for IOC attributes
+	 *	2. Kernel memory for FW trace
+	 */
+	bfa_ioc_attach(&device->ioc, device, &bfa_iocll_cbfn);
+	bfa_ioc_pci_init(&device->ioc, &bna->pcidev, BFI_MC_LL);
+
+	BNA_GET_DMA_ADDR(
+		&res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.mdl[0].dma, dma);
+	bfa_ioc_mem_claim(&device->ioc,
+		res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.mdl[0].kva,
+			  dma);
+
+	bna_adv_device_init(device, bna, res_info);
+	/*
+	 * Initialize mbox_mod only after IOC, so that mbox handler
+	 * registration goes through
+	 */
+	device->intr_type =
+		res_info[BNA_RES_INTR_T_MBOX].res_u.intr_info.intr_type;
+	device->vector =
+		res_info[BNA_RES_INTR_T_MBOX].res_u.intr_info.idl[0].vector;
+	bna_mbox_mod_init(&bna->mbox_mod, bna);
+
+	device->ready_cbfn = device->stop_cbfn = NULL;
+	device->ready_cbarg = device->stop_cbarg = NULL;
+
+	bfa_fsm_set_state(device, bna_device_sm_stopped);
+}
+
+void
+bna_device_uninit(struct bna_device *device)
+{
+	bna_mbox_mod_uninit(&device->bna->mbox_mod);
+
+	bfa_cee_detach(&device->bna->cee);
+
+	bfa_ioc_detach(&device->ioc);
+
+	device->bna = NULL;
+}
+
+void
+bna_device_cb_port_stopped(void *arg, enum bna_cb_status status)
+{
+	struct bna_device *device = (struct bna_device *)arg;
+
+	bfa_fsm_send_event(device, DEVICE_E_PORT_STOPPED);
+}
+
+int
+bna_device_status_get(struct bna_device *device)
+{
+	return (device->fsm == (bfa_fsm_t)bna_device_sm_ready);
+}
+
+void
+bna_device_enable(struct bna_device *device)
+{
+	if (device->fsm != (bfa_fsm_t)bna_device_sm_stopped) {
+		bnad_cb_device_enabled(device->bna->bnad, BNA_CB_BUSY);
+		return;
+	}
+
+	device->ready_cbfn = bnad_cb_device_enabled;
+	device->ready_cbarg = device->bna->bnad;
+
+	bfa_fsm_send_event(device, DEVICE_E_ENABLE);
+}
+
+void
+bna_device_disable(struct bna_device *device, enum bna_cleanup_type type)
+{
+	if (type == BNA_SOFT_CLEANUP) {
+		bnad_cb_device_disabled(device->bna->bnad, BNA_CB_SUCCESS);
+		return;
+	}
+
+	device->stop_cbfn = bnad_cb_device_disabled;
+	device->stop_cbarg = device->bna->bnad;
+
+	bfa_fsm_send_event(device, DEVICE_E_DISABLE);
+}
+
+int
+bna_device_state_get(struct bna_device *device)
+{
+	return bfa_sm_to_state(device_sm_table, device->fsm);
+}
+
+u32 bna_dim_vector[BNA_LOAD_T_MAX][BNA_BIAS_T_MAX] = {
+	{12, 20},
+	{10, 18},
+	{8, 16},
+	{6, 12},
+	{4, 8},
+	{3, 6},
+	{2, 4},
+	{1, 2},
+};
+
+u32 bna_napi_dim_vector[BNA_LOAD_T_MAX][BNA_BIAS_T_MAX] = {
+	{12, 12},
+	{6, 10},
+	{5, 10},
+	{4, 8},
+	{3, 6},
+	{3, 6},
+	{2, 4},
+	{1, 2},
+};
+
+/* device */
+void
+bna_adv_device_init(struct bna_device *device, struct bna *bna,
+		struct bna_res_info *res_info)
+{
+	u8 *kva;
+	u64 dma;
+
+	device->bna = bna;
+
+	kva = res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.mdl[0].kva;
+
+	/**
+	 * Attach common modules (Diag, SFP, CEE, Port) and claim respective
+	 * DMA memory.
+	 */
+	BNA_GET_DMA_ADDR(
+		&res_info[BNA_RES_MEM_T_COM].res_u.mem_info.mdl[0].dma, dma);
+	kva = res_info[BNA_RES_MEM_T_COM].res_u.mem_info.mdl[0].kva;
+
+	bfa_cee_attach(&bna->cee, &device->ioc, bna);
+	bfa_cee_mem_claim(&bna->cee, kva, dma);
+	kva += bfa_cee_meminfo();
+	dma += bfa_cee_meminfo();
+
+}
+
+/* utils */
+
+void
+bna_adv_res_req(struct bna_res_info *res_info)
+{
+	/* DMA memory for COMMON_MODULE */
+	res_info[BNA_RES_MEM_T_COM].res_type = BNA_RES_T_MEM;
+	res_info[BNA_RES_MEM_T_COM].res_u.mem_info.mem_type = BNA_MEM_T_DMA;
+	res_info[BNA_RES_MEM_T_COM].res_u.mem_info.num = 1;
+	res_info[BNA_RES_MEM_T_COM].res_u.mem_info.len = ALIGN(
+				bfa_cee_meminfo(), PAGE_SIZE);
+
+	/* Virtual memory for retreiving fw_trc */
+	res_info[BNA_RES_MEM_T_FWTRC].res_type = BNA_RES_T_MEM;
+	res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.mem_type = BNA_MEM_T_KVA;
+	res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.num = 0;
+	res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.len = 0;
+
+	/* DMA memory for retreiving stats */
+	res_info[BNA_RES_MEM_T_STATS].res_type = BNA_RES_T_MEM;
+	res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.mem_type = BNA_MEM_T_DMA;
+	res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.num = 1;
+	res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.len =
+				ALIGN(BFI_HW_STATS_SIZE, PAGE_SIZE);
+
+	/* Virtual memory for soft stats */
+	res_info[BNA_RES_MEM_T_SWSTATS].res_type = BNA_RES_T_MEM;
+	res_info[BNA_RES_MEM_T_SWSTATS].res_u.mem_info.mem_type = BNA_MEM_T_KVA;
+	res_info[BNA_RES_MEM_T_SWSTATS].res_u.mem_info.num = 1;
+	res_info[BNA_RES_MEM_T_SWSTATS].res_u.mem_info.len =
+				sizeof(struct bna_sw_stats);
+}
+
+static void
+bna_sw_stats_get(struct bna *bna, struct bna_sw_stats *sw_stats)
+{
+	struct bna_tx *tx;
+	struct bna_txq *txq;
+	struct bna_rx *rx;
+	struct bna_rxp *rxp;
+	struct list_head *qe;
+	struct list_head *txq_qe;
+	struct list_head *rxp_qe;
+	struct list_head *mac_qe;
+	int i;
+
+	sw_stats->device_state = bna_device_state_get(&bna->device);
+	sw_stats->port_state = bna_port_state_get(&bna->port);
+	sw_stats->port_flags = bna->port.flags;
+	sw_stats->llport_state = bna_llport_state_get(&bna->port.llport);
+	sw_stats->priority = bna->port.priority;
+
+	i = 0;
+	list_for_each(qe, &bna->tx_mod.tx_active_q) {
+		tx = (struct bna_tx *)qe;
+		sw_stats->tx_stats[i].tx_state = bna_tx_state_get(tx);
+		sw_stats->tx_stats[i].tx_flags = tx->flags;
+
+		sw_stats->tx_stats[i].num_txqs = 0;
+		sw_stats->tx_stats[i].txq_bmap[0] = 0;
+		sw_stats->tx_stats[i].txq_bmap[1] = 0;
+		list_for_each(txq_qe, &tx->txq_q) {
+			txq = (struct bna_txq *)txq_qe;
+			if (txq->txq_id < 32)
+				sw_stats->tx_stats[i].txq_bmap[0] |=
+						((u32)1 << txq->txq_id);
+			else
+				sw_stats->tx_stats[i].txq_bmap[1] |=
+						((u32)
+						 1 << (txq->txq_id - 32));
+			sw_stats->tx_stats[i].num_txqs++;
+		}
+
+		sw_stats->tx_stats[i].txf_id = tx->txf.txf_id;
+
+		i++;
+	}
+	sw_stats->num_active_tx = i;
+
+	i = 0;
+	list_for_each(qe, &bna->rx_mod.rx_active_q) {
+		rx = (struct bna_rx *)qe;
+		sw_stats->rx_stats[i].rx_state = bna_rx_state_get(rx);
+		sw_stats->rx_stats[i].rx_flags = rx->rx_flags;
+
+		sw_stats->rx_stats[i].num_rxps = 0;
+		sw_stats->rx_stats[i].num_rxqs = 0;
+		sw_stats->rx_stats[i].rxq_bmap[0] = 0;
+		sw_stats->rx_stats[i].rxq_bmap[1] = 0;
+		sw_stats->rx_stats[i].cq_bmap[0] = 0;
+		sw_stats->rx_stats[i].cq_bmap[1] = 0;
+		list_for_each(rxp_qe, &rx->rxp_q) {
+			rxp = (struct bna_rxp *)rxp_qe;
+
+			sw_stats->rx_stats[i].num_rxqs += 1;
+
+			if (rxp->type == BNA_RXP_SINGLE) {
+				if (rxp->rxq.single.only->rxq_id < 32) {
+					sw_stats->rx_stats[i].rxq_bmap[0] |=
+					((u32)1 <<
+					rxp->rxq.single.only->rxq_id);
+				} else {
+					sw_stats->rx_stats[i].rxq_bmap[1] |=
+					((u32)1 <<
+					(rxp->rxq.single.only->rxq_id - 32));
+				}
+			} else {
+				if (rxp->rxq.slr.large->rxq_id < 32) {
+					sw_stats->rx_stats[i].rxq_bmap[0] |=
+					((u32)1 <<
+					rxp->rxq.slr.large->rxq_id);
+				} else {
+					sw_stats->rx_stats[i].rxq_bmap[1] |=
+					((u32)1 <<
+					(rxp->rxq.slr.large->rxq_id - 32));
+				}
+
+				if (rxp->rxq.slr.small->rxq_id < 32) {
+					sw_stats->rx_stats[i].rxq_bmap[0] |=
+					((u32)1 <<
+					rxp->rxq.slr.small->rxq_id);
+				} else {
+					sw_stats->rx_stats[i].rxq_bmap[1] |=
+				((u32)1 <<
+				 (rxp->rxq.slr.small->rxq_id - 32));
+				}
+				sw_stats->rx_stats[i].num_rxqs += 1;
+			}
+
+			if (rxp->cq.cq_id < 32)
+				sw_stats->rx_stats[i].cq_bmap[0] |=
+					(1 << rxp->cq.cq_id);
+			else
+				sw_stats->rx_stats[i].cq_bmap[1] |=
+					(1 << (rxp->cq.cq_id - 32));
+
+			sw_stats->rx_stats[i].num_rxps++;
+		}
+
+		sw_stats->rx_stats[i].rxf_id = rx->rxf.rxf_id;
+		sw_stats->rx_stats[i].rxf_state = bna_rxf_state_get(&rx->rxf);
+		sw_stats->rx_stats[i].rxf_oper_state = rx->rxf.rxf_oper_state;
+
+		sw_stats->rx_stats[i].num_active_ucast = 0;
+		if (rx->rxf.ucast_active_mac)
+			sw_stats->rx_stats[i].num_active_ucast++;
+		list_for_each(mac_qe, &rx->rxf.ucast_active_q)
+			sw_stats->rx_stats[i].num_active_ucast++;
+
+		sw_stats->rx_stats[i].num_active_mcast = 0;
+		list_for_each(mac_qe, &rx->rxf.mcast_active_q)
+			sw_stats->rx_stats[i].num_active_mcast++;
+
+		sw_stats->rx_stats[i].rxmode_active = rx->rxf.rxmode_active;
+		sw_stats->rx_stats[i].vlan_filter_status =
+						rx->rxf.vlan_filter_status;
+		memcpy(sw_stats->rx_stats[i].vlan_filter_table,
+				rx->rxf.vlan_filter_table,
+				sizeof(u32) * ((BFI_MAX_VLAN + 1) / 32));
+
+		sw_stats->rx_stats[i].rss_status = rx->rxf.rss_status;
+		sw_stats->rx_stats[i].hds_status = rx->rxf.hds_status;
+
+		i++;
+	}
+	sw_stats->num_active_rx = i;
+}
+
+static void
+bna_fw_cb_stats_get(void *arg, int status)
+{
+	struct bna *bna = (struct bna *)arg;
+	u64 *p_stats;
+	int i, count;
+	int rxf_count, txf_count;
+	u64 rxf_bmap, txf_bmap;
+
+	bfa_q_qe_init(&bna->mbox_qe.qe);
+
+	if (status == 0) {
+		p_stats = (u64 *)bna->stats.hw_stats;
+		count = sizeof(struct bfi_ll_stats) / sizeof(u64);
+		for (i = 0; i < count; i++)
+			p_stats[i] = cpu_to_be64(p_stats[i]);
+
+		rxf_count = 0;
+		rxf_bmap = (u64)bna->stats.rxf_bmap[0] |
+			((u64)bna->stats.rxf_bmap[1] << 32);
+		for (i = 0; i < BFI_LL_RXF_ID_MAX; i++)
+			if (rxf_bmap & ((u64)1 << i))
+				rxf_count++;
+
+		txf_count = 0;
+		txf_bmap = (u64)bna->stats.txf_bmap[0] |
+			((u64)bna->stats.txf_bmap[1] << 32);
+		for (i = 0; i < BFI_LL_TXF_ID_MAX; i++)
+			if (txf_bmap & ((u64)1 << i))
+				txf_count++;
+
+		p_stats = (u64 *)&bna->stats.hw_stats->rxf_stats[0] +
+				((rxf_count * sizeof(struct bfi_ll_stats_rxf) +
+				txf_count * sizeof(struct bfi_ll_stats_txf))/
+				sizeof(u64));
+
+		/* Populate the TXF stats from the firmware DMAed copy */
+		for (i = (BFI_LL_TXF_ID_MAX - 1); i >= 0; i--)
+			if (txf_bmap & ((u64)1 << i)) {
+				p_stats -= sizeof(struct bfi_ll_stats_txf)/
+						sizeof(u64);
+				memcpy(&bna->stats.hw_stats->txf_stats[i],
+					p_stats,
+					sizeof(struct bfi_ll_stats_txf));
+			}
+
+		/* Populate the RXF stats from the firmware DMAed copy */
+		for (i = (BFI_LL_RXF_ID_MAX - 1); i >= 0; i--)
+			if (rxf_bmap & ((u64)1 << i)) {
+				p_stats -= sizeof(struct bfi_ll_stats_rxf)/
+						sizeof(u64);
+				memcpy(&bna->stats.hw_stats->rxf_stats[i],
+					p_stats,
+					sizeof(struct bfi_ll_stats_rxf));
+			}
+
+		bna_sw_stats_get(bna, bna->stats.sw_stats);
+		bnad_cb_stats_get(bna->bnad, BNA_CB_SUCCESS, &bna->stats);
+	} else
+		bnad_cb_stats_get(bna->bnad, BNA_CB_FAIL, &bna->stats);
+}
+
+static void
+bna_fw_stats_get(struct bna *bna)
+{
+	struct bfi_ll_stats_req ll_req;
+
+	bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_STATS_GET_REQ, 0);
+	ll_req.stats_mask = htons(BFI_LL_STATS_ALL);
+
+	ll_req.rxf_id_mask[0] = htonl(bna->rx_mod.rxf_bmap[0]);
+	ll_req.rxf_id_mask[1] =	htonl(bna->rx_mod.rxf_bmap[1]);
+	ll_req.txf_id_mask[0] =	htonl(bna->tx_mod.txf_bmap[0]);
+	ll_req.txf_id_mask[1] =	htonl(bna->tx_mod.txf_bmap[1]);
+
+	ll_req.host_buffer.a32.addr_hi = bna->hw_stats_dma.msb;
+	ll_req.host_buffer.a32.addr_lo = bna->hw_stats_dma.lsb;
+
+	bna_mbox_qe_fill(&bna->mbox_qe, &ll_req, sizeof(ll_req),
+				bna_fw_cb_stats_get, bna);
+	bna_mbox_send(bna, &bna->mbox_qe);
+
+	bna->stats.rxf_bmap[0] = bna->rx_mod.rxf_bmap[0];
+	bna->stats.rxf_bmap[1] = bna->rx_mod.rxf_bmap[1];
+	bna->stats.txf_bmap[0] = bna->tx_mod.txf_bmap[0];
+	bna->stats.txf_bmap[1] = bna->tx_mod.txf_bmap[1];
+}
+
+static void
+bna_fw_cb_stats_clr(void *arg, int status)
+{
+	struct bna *bna = (struct bna *)arg;
+
+	bfa_q_qe_init(&bna->mbox_qe.qe);
+
+	memset(bna->stats.sw_stats, 0, sizeof(struct bna_sw_stats));
+	memset(bna->stats.hw_stats, 0, sizeof(struct bfi_ll_stats));
+
+	bnad_cb_stats_clr(bna->bnad);
+}
+
+static void
+bna_fw_stats_clr(struct bna *bna)
+{
+	struct bfi_ll_stats_req ll_req;
+
+	bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_STATS_CLEAR_REQ, 0);
+	ll_req.stats_mask = htons(BFI_LL_STATS_ALL);
+	ll_req.rxf_id_mask[0] = htonl(0xffffffff);
+	ll_req.rxf_id_mask[1] =	htonl(0xffffffff);
+	ll_req.txf_id_mask[0] =	htonl(0xffffffff);
+	ll_req.txf_id_mask[1] =	htonl(0xffffffff);
+
+	bna_mbox_qe_fill(&bna->mbox_qe, &ll_req, sizeof(ll_req),
+				bna_fw_cb_stats_clr, bna);
+	bna_mbox_send(bna, &bna->mbox_qe);
+}
+
+void
+bna_stats_get(struct bna *bna)
+{
+	if (bna_device_status_get(&bna->device))
+		bna_fw_stats_get(bna);
+	else
+		bnad_cb_stats_get(bna->bnad, BNA_CB_FAIL, &bna->stats);
+}
+
+void
+bna_stats_clr(struct bna *bna)
+{
+	if (bna_device_status_get(&bna->device))
+		bna_fw_stats_clr(bna);
+	else {
+		memset(&bna->stats.sw_stats, 0,
+				sizeof(struct bna_sw_stats));
+		memset(bna->stats.hw_stats, 0,
+				sizeof(struct bfi_ll_stats));
+		bnad_cb_stats_clr(bna->bnad);
+	}
+}
+
+/* IB */
+void
+bna_ib_coalescing_timeo_set(struct bna_ib *ib, u8 coalescing_timeo)
+{
+	ib->ib_config.coalescing_timeo = coalescing_timeo;
+
+	if (ib->start_count)
+		ib->door_bell.doorbell_ack = BNA_DOORBELL_IB_INT_ACK(
+				(u32)ib->ib_config.coalescing_timeo, 0);
+}
+
+/* RxF */
+void
+bna_rxf_adv_init(struct bna_rxf *rxf,
+		struct bna_rx *rx,
+		struct bna_rx_config *q_config)
+{
+	switch (q_config->rxp_type) {
+	case BNA_RXP_SINGLE:
+		/* No-op */
+		break;
+	case BNA_RXP_SLR:
+		rxf->ctrl_flags |= BNA_RXF_CF_SM_LG_RXQ;
+		break;
+	case BNA_RXP_HDS:
+		rxf->hds_cfg.hdr_type = q_config->hds_config.hdr_type;
+		rxf->hds_cfg.header_size =
+				q_config->hds_config.header_size;
+		rxf->forced_offset = 0;
+		break;
+	default:
+		break;
+	}
+
+	if (q_config->rss_status == BNA_STATUS_T_ENABLED) {
+		rxf->ctrl_flags |= BNA_RXF_CF_RSS_ENABLE;
+		rxf->rss_cfg.hash_type = q_config->rss_config.hash_type;
+		rxf->rss_cfg.hash_mask = q_config->rss_config.hash_mask;
+		memcpy(&rxf->rss_cfg.toeplitz_hash_key[0],
+			&q_config->rss_config.toeplitz_hash_key[0],
+			sizeof(rxf->rss_cfg.toeplitz_hash_key));
+	}
+}
+
+static void
+rxf_fltr_mbox_cmd(struct bna_rxf *rxf, u8 cmd, enum bna_status status)
+{
+	struct bfi_ll_rxf_req req;
+
+	bfi_h2i_set(req.mh, BFI_MC_LL, cmd, 0);
+
+	req.rxf_id = rxf->rxf_id;
+	req.enable = status;
+
+	bna_mbox_qe_fill(&rxf->mbox_qe, &req, sizeof(req),
+			rxf_cb_cam_fltr_mbox_cmd, rxf);
+
+	bna_mbox_send(rxf->rx->bna, &rxf->mbox_qe);
+}
+
+void
+__rxf_default_function_config(struct bna_rxf *rxf, enum bna_status status)
+{
+	struct bna_rx_fndb_ram *rx_fndb_ram;
+	u32 ctrl_flags;
+	int i;
+
+	rx_fndb_ram = (struct bna_rx_fndb_ram *)
+			BNA_GET_MEM_BASE_ADDR(rxf->rx->bna->pcidev.pci_bar_kva,
+			RX_FNDB_RAM_BASE_OFFSET);
+
+	for (i = 0; i < BFI_MAX_RXF; i++) {
+		if (status == BNA_STATUS_T_ENABLED) {
+			if (i == rxf->rxf_id)
+				continue;
+
+			ctrl_flags =
+				readl(&rx_fndb_ram[i].control_flags);
+			ctrl_flags |= BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE;
+			writel(ctrl_flags,
+						&rx_fndb_ram[i].control_flags);
+		} else {
+			ctrl_flags =
+				readl(&rx_fndb_ram[i].control_flags);
+			ctrl_flags &= ~BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE;
+			writel(ctrl_flags,
+						&rx_fndb_ram[i].control_flags);
+		}
+	}
+}
+
+int
+rxf_process_packet_filter_ucast(struct bna_rxf *rxf)
+{
+	struct bna_mac *mac = NULL;
+	struct list_head *qe;
+
+	/* Add additional MAC entries */
+	if (!list_empty(&rxf->ucast_pending_add_q)) {
+		bfa_q_deq(&rxf->ucast_pending_add_q, &qe);
+		bfa_q_qe_init(qe);
+		mac = (struct bna_mac *)qe;
+		rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_UCAST_ADD_REQ, mac);
+		list_add_tail(&mac->qe, &rxf->ucast_active_q);
+		return 1;
+	}
+
+	/* Delete MAC addresses previousely added */
+	if (!list_empty(&rxf->ucast_pending_del_q)) {
+		bfa_q_deq(&rxf->ucast_pending_del_q, &qe);
+		bfa_q_qe_init(qe);
+		mac = (struct bna_mac *)qe;
+		rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_UCAST_DEL_REQ, mac);
+		bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod, mac);
+		return 1;
+	}
+
+	return 0;
+}
+
+int
+rxf_process_packet_filter_promisc(struct bna_rxf *rxf)
+{
+	struct bna *bna = rxf->rx->bna;
+
+	/* Enable/disable promiscuous mode */
+	if (is_promisc_enable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask)) {
+		/* move promisc configuration from pending -> active */
+		promisc_inactive(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		rxf->rxmode_active |= BNA_RXMODE_PROMISC;
+
+		/* Disable VLAN filter to allow all VLANs */
+		__rxf_vlan_filter_set(rxf, BNA_STATUS_T_DISABLED);
+		rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ,
+				BNA_STATUS_T_ENABLED);
+		return 1;
+	} else if (is_promisc_disable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask)) {
+		/* move promisc configuration from pending -> active */
+		promisc_inactive(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		rxf->rxmode_active &= ~BNA_RXMODE_PROMISC;
+		bna->rxf_promisc_id = BFI_MAX_RXF;
+
+		/* Revert VLAN filter */
+		__rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
+		rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ,
+				BNA_STATUS_T_DISABLED);
+		return 1;
+	}
+
+	return 0;
+}
+
+int
+rxf_process_packet_filter_default(struct bna_rxf *rxf)
+{
+	struct bna *bna = rxf->rx->bna;
+
+	/* Enable/disable default mode */
+	if (is_default_enable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask)) {
+		/* move default configuration from pending -> active */
+		default_inactive(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		rxf->rxmode_active |= BNA_RXMODE_DEFAULT;
+
+		/* Disable VLAN filter to allow all VLANs */
+		__rxf_vlan_filter_set(rxf, BNA_STATUS_T_DISABLED);
+		/* Redirect all other RxF vlan filtering to this one */
+		__rxf_default_function_config(rxf, BNA_STATUS_T_ENABLED);
+		rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_DEFAULT_SET_REQ,
+				BNA_STATUS_T_ENABLED);
+		return 1;
+	} else if (is_default_disable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask)) {
+		/* move default configuration from pending -> active */
+		default_inactive(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
+		bna->rxf_default_id = BFI_MAX_RXF;
+
+		/* Revert VLAN filter */
+		__rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
+		/* Stop RxF vlan filter table redirection */
+		__rxf_default_function_config(rxf, BNA_STATUS_T_DISABLED);
+		rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_DEFAULT_SET_REQ,
+				BNA_STATUS_T_DISABLED);
+		return 1;
+	}
+
+	return 0;
+}
+
+int
+rxf_process_packet_filter_allmulti(struct bna_rxf *rxf)
+{
+	/* Enable/disable allmulti mode */
+	if (is_allmulti_enable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask)) {
+		/* move allmulti configuration from pending -> active */
+		allmulti_inactive(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		rxf->rxmode_active |= BNA_RXMODE_ALLMULTI;
+
+		rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_FILTER_REQ,
+				BNA_STATUS_T_ENABLED);
+		return 1;
+	} else if (is_allmulti_disable(rxf->rxmode_pending,
+					rxf->rxmode_pending_bitmask)) {
+		/* move allmulti configuration from pending -> active */
+		allmulti_inactive(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		rxf->rxmode_active &= ~BNA_RXMODE_ALLMULTI;
+
+		rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_FILTER_REQ,
+				BNA_STATUS_T_DISABLED);
+		return 1;
+	}
+
+	return 0;
+}
+
+int
+rxf_clear_packet_filter_ucast(struct bna_rxf *rxf)
+{
+	struct bna_mac *mac = NULL;
+	struct list_head *qe;
+
+	/* 1. delete pending ucast entries */
+	if (!list_empty(&rxf->ucast_pending_del_q)) {
+		bfa_q_deq(&rxf->ucast_pending_del_q, &qe);
+		bfa_q_qe_init(qe);
+		mac = (struct bna_mac *)qe;
+		rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_UCAST_DEL_REQ, mac);
+		bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod, mac);
+		return 1;
+	}
+
+	/* 2. clear active ucast entries; move them to pending_add_q */
+	if (!list_empty(&rxf->ucast_active_q)) {
+		bfa_q_deq(&rxf->ucast_active_q, &qe);
+		bfa_q_qe_init(qe);
+		mac = (struct bna_mac *)qe;
+		rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_UCAST_DEL_REQ, mac);
+		list_add_tail(&mac->qe, &rxf->ucast_pending_add_q);
+		return 1;
+	}
+
+	return 0;
+}
+
+int
+rxf_clear_packet_filter_promisc(struct bna_rxf *rxf)
+{
+	struct bna *bna = rxf->rx->bna;
+
+	/* 6. Execute pending promisc mode disable command */
+	if (is_promisc_disable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask)) {
+		/* move promisc configuration from pending -> active */
+		promisc_inactive(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		rxf->rxmode_active &= ~BNA_RXMODE_PROMISC;
+		bna->rxf_promisc_id = BFI_MAX_RXF;
+
+		/* Revert VLAN filter */
+		__rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
+		rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ,
+				BNA_STATUS_T_DISABLED);
+		return 1;
+	}
+
+	/* 7. Clear active promisc mode; move it to pending enable */
+	if (rxf->rxmode_active & BNA_RXMODE_PROMISC) {
+		/* move promisc configuration from active -> pending */
+		promisc_enable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		rxf->rxmode_active &= ~BNA_RXMODE_PROMISC;
+
+		/* Revert VLAN filter */
+		__rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
+		rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ,
+				BNA_STATUS_T_DISABLED);
+		return 1;
+	}
+
+	return 0;
+}
+
+int
+rxf_clear_packet_filter_default(struct bna_rxf *rxf)
+{
+	struct bna *bna = rxf->rx->bna;
+
+	/* 8. Execute pending default mode disable command */
+	if (is_default_disable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask)) {
+		/* move default configuration from pending -> active */
+		default_inactive(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
+		bna->rxf_default_id = BFI_MAX_RXF;
+
+		/* Revert VLAN filter */
+		__rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
+		/* Stop RxF vlan filter table redirection */
+		__rxf_default_function_config(rxf, BNA_STATUS_T_DISABLED);
+		rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_DEFAULT_SET_REQ,
+				BNA_STATUS_T_DISABLED);
+		return 1;
+	}
+
+	/* 9. Clear active default mode; move it to pending enable */
+	if (rxf->rxmode_active & BNA_RXMODE_DEFAULT) {
+		/* move default configuration from active -> pending */
+		default_enable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
+
+		/* Revert VLAN filter */
+		__rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
+		/* Stop RxF vlan filter table redirection */
+		__rxf_default_function_config(rxf, BNA_STATUS_T_DISABLED);
+		rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_DEFAULT_SET_REQ,
+				BNA_STATUS_T_DISABLED);
+		return 1;
+	}
+
+	return 0;
+}
+
+int
+rxf_clear_packet_filter_allmulti(struct bna_rxf *rxf)
+{
+	/* 10. Execute pending allmulti mode disable command */
+	if (is_allmulti_disable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask)) {
+		/* move allmulti configuration from pending -> active */
+		allmulti_inactive(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		rxf->rxmode_active &= ~BNA_RXMODE_ALLMULTI;
+		rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_FILTER_REQ,
+				BNA_STATUS_T_DISABLED);
+		return 1;
+	}
+
+	/* 11. Clear active allmulti mode; move it to pending enable */
+	if (rxf->rxmode_active & BNA_RXMODE_ALLMULTI) {
+		/* move allmulti configuration from active -> pending */
+		allmulti_enable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		rxf->rxmode_active &= ~BNA_RXMODE_ALLMULTI;
+		rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_FILTER_REQ,
+				BNA_STATUS_T_DISABLED);
+		return 1;
+	}
+
+	return 0;
+}
+
+void
+rxf_reset_packet_filter_ucast(struct bna_rxf *rxf)
+{
+	struct list_head *qe;
+	struct bna_mac *mac;
+
+	/* 1. Move active ucast entries to pending_add_q */
+	while (!list_empty(&rxf->ucast_active_q)) {
+		bfa_q_deq(&rxf->ucast_active_q, &qe);
+		bfa_q_qe_init(qe);
+		list_add_tail(qe, &rxf->ucast_pending_add_q);
+	}
+
+	/* 2. Throw away delete pending ucast entries */
+	while (!list_empty(&rxf->ucast_pending_del_q)) {
+		bfa_q_deq(&rxf->ucast_pending_del_q, &qe);
+		bfa_q_qe_init(qe);
+		mac = (struct bna_mac *)qe;
+		bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod, mac);
+	}
+}
+
+void
+rxf_reset_packet_filter_promisc(struct bna_rxf *rxf)
+{
+	struct bna *bna = rxf->rx->bna;
+
+	/* 6. Clear pending promisc mode disable */
+	if (is_promisc_disable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask)) {
+		promisc_inactive(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		rxf->rxmode_active &= ~BNA_RXMODE_PROMISC;
+		bna->rxf_promisc_id = BFI_MAX_RXF;
+	}
+
+	/* 7. Move promisc mode config from active -> pending */
+	if (rxf->rxmode_active & BNA_RXMODE_PROMISC) {
+		promisc_enable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		rxf->rxmode_active &= ~BNA_RXMODE_PROMISC;
+	}
+
+}
+
+void
+rxf_reset_packet_filter_default(struct bna_rxf *rxf)
+{
+	struct bna *bna = rxf->rx->bna;
+
+	/* 8. Clear pending default mode disable */
+	if (is_default_disable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask)) {
+		default_inactive(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
+		bna->rxf_default_id = BFI_MAX_RXF;
+	}
+
+	/* 9. Move default mode config from active -> pending */
+	if (rxf->rxmode_active & BNA_RXMODE_DEFAULT) {
+		default_enable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
+	}
+}
+
+void
+rxf_reset_packet_filter_allmulti(struct bna_rxf *rxf)
+{
+	/* 10. Clear pending allmulti mode disable */
+	if (is_allmulti_disable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask)) {
+		allmulti_inactive(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		rxf->rxmode_active &= ~BNA_RXMODE_ALLMULTI;
+	}
+
+	/* 11. Move allmulti mode config from active -> pending */
+	if (rxf->rxmode_active & BNA_RXMODE_ALLMULTI) {
+		allmulti_enable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		rxf->rxmode_active &= ~BNA_RXMODE_ALLMULTI;
+	}
+}
+
+/**
+ * Should only be called by bna_rxf_mode_set.
+ * Helps deciding if h/w configuration is needed or not.
+ *  Returns:
+ *	0 = no h/w change
+ *	1 = need h/w change
+ */
+int
+rxf_promisc_enable(struct bna_rxf *rxf)
+{
+	struct bna *bna = rxf->rx->bna;
+	int ret = 0;
+
+	/* There can not be any pending disable command */
+
+	/* Do nothing if pending enable or already enabled */
+	if (is_promisc_enable(rxf->rxmode_pending,
+			rxf->rxmode_pending_bitmask) ||
+			(rxf->rxmode_active & BNA_RXMODE_PROMISC)) {
+		/* Schedule enable */
+	} else {
+		/* Promisc mode should not be active in the system */
+		promisc_enable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		bna->rxf_promisc_id = rxf->rxf_id;
+		ret = 1;
+	}
+
+	return ret;
+}
+
+/**
+ * Should only be called by bna_rxf_mode_set.
+ * Helps deciding if h/w configuration is needed or not.
+ *  Returns:
+ *	0 = no h/w change
+ *	1 = need h/w change
+ */
+int
+rxf_promisc_disable(struct bna_rxf *rxf)
+{
+	struct bna *bna = rxf->rx->bna;
+	int ret = 0;
+
+	/* There can not be any pending disable */
+
+	/* Turn off pending enable command , if any */
+	if (is_promisc_enable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask)) {
+		/* Promisc mode should not be active */
+		/* system promisc state should be pending */
+		promisc_inactive(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		/* Remove the promisc state from the system */
+		bna->rxf_promisc_id = BFI_MAX_RXF;
+
+		/* Schedule disable */
+	} else if (rxf->rxmode_active & BNA_RXMODE_PROMISC) {
+		/* Promisc mode should be active in the system */
+		promisc_disable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		ret = 1;
+
+	/* Do nothing if already disabled */
+	} else {
+	}
+
+	return ret;
+}
+
+/**
+ * Should only be called by bna_rxf_mode_set.
+ * Helps deciding if h/w configuration is needed or not.
+ *  Returns:
+ *	0 = no h/w change
+ *	1 = need h/w change
+ */
+int
+rxf_default_enable(struct bna_rxf *rxf)
+{
+	struct bna *bna = rxf->rx->bna;
+	int ret = 0;
+
+	/* There can not be any pending disable command */
+
+	/* Do nothing if pending enable or already enabled */
+	if (is_default_enable(rxf->rxmode_pending,
+		rxf->rxmode_pending_bitmask) ||
+		(rxf->rxmode_active & BNA_RXMODE_DEFAULT)) {
+		/* Schedule enable */
+	} else {
+		/* Default mode should not be active in the system */
+		default_enable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		bna->rxf_default_id = rxf->rxf_id;
+		ret = 1;
+	}
+
+	return ret;
+}
+
+/**
+ * Should only be called by bna_rxf_mode_set.
+ * Helps deciding if h/w configuration is needed or not.
+ *  Returns:
+ *	0 = no h/w change
+ *	1 = need h/w change
+ */
+int
+rxf_default_disable(struct bna_rxf *rxf)
+{
+	struct bna *bna = rxf->rx->bna;
+	int ret = 0;
+
+	/* There can not be any pending disable */
+
+	/* Turn off pending enable command , if any */
+	if (is_default_enable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask)) {
+		/* Promisc mode should not be active */
+		/* system default state should be pending */
+		default_inactive(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		/* Remove the default state from the system */
+		bna->rxf_default_id = BFI_MAX_RXF;
+
+	/* Schedule disable */
+	} else if (rxf->rxmode_active & BNA_RXMODE_DEFAULT) {
+		/* Default mode should be active in the system */
+		default_disable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		ret = 1;
+
+	/* Do nothing if already disabled */
+	} else {
+	}
+
+	return ret;
+}
+
+/**
+ * Should only be called by bna_rxf_mode_set.
+ * Helps deciding if h/w configuration is needed or not.
+ *  Returns:
+ *	0 = no h/w change
+ *	1 = need h/w change
+ */
+int
+rxf_allmulti_enable(struct bna_rxf *rxf)
+{
+	int ret = 0;
+
+	/* There can not be any pending disable command */
+
+	/* Do nothing if pending enable or already enabled */
+	if (is_allmulti_enable(rxf->rxmode_pending,
+			rxf->rxmode_pending_bitmask) ||
+			(rxf->rxmode_active & BNA_RXMODE_ALLMULTI)) {
+		/* Schedule enable */
+	} else {
+		allmulti_enable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		ret = 1;
+	}
+
+	return ret;
+}
+
+/**
+ * Should only be called by bna_rxf_mode_set.
+ * Helps deciding if h/w configuration is needed or not.
+ *  Returns:
+ *	0 = no h/w change
+ *	1 = need h/w change
+ */
+int
+rxf_allmulti_disable(struct bna_rxf *rxf)
+{
+	int ret = 0;
+
+	/* There can not be any pending disable */
+
+	/* Turn off pending enable command , if any */
+	if (is_allmulti_enable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask)) {
+		/* Allmulti mode should not be active */
+		allmulti_inactive(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+
+	/* Schedule disable */
+	} else if (rxf->rxmode_active & BNA_RXMODE_ALLMULTI) {
+		allmulti_disable(rxf->rxmode_pending,
+				rxf->rxmode_pending_bitmask);
+		ret = 1;
+	}
+
+	return ret;
+}
+
+/* RxF <- bnad */
+void
+bna_rx_mcast_delall(struct bna_rx *rx,
+		    void (*cbfn)(struct bnad *, struct bna_rx *,
+				 enum bna_cb_status))
+{
+	struct bna_rxf *rxf = &rx->rxf;
+	struct list_head *qe;
+	struct bna_mac *mac;
+	int need_hw_config = 0;
+
+	/* Purge all entries from pending_add_q */
+	while (!list_empty(&rxf->mcast_pending_add_q)) {
+		bfa_q_deq(&rxf->mcast_pending_add_q, &qe);
+		mac = (struct bna_mac *)qe;
+		bfa_q_qe_init(&mac->qe);
+		bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+	}
+
+	/* Schedule all entries in active_q for deletion */
+	while (!list_empty(&rxf->mcast_active_q)) {
+		bfa_q_deq(&rxf->mcast_active_q, &qe);
+		mac = (struct bna_mac *)qe;
+		bfa_q_qe_init(&mac->qe);
+		list_add_tail(&mac->qe, &rxf->mcast_pending_del_q);
+		need_hw_config = 1;
+	}
+
+	if (need_hw_config) {
+		rxf->cam_fltr_cbfn = cbfn;
+		rxf->cam_fltr_cbarg = rx->bna->bnad;
+		bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+		return;
+	}
+
+	if (cbfn)
+		(*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+}
+
+/* RxF <- Rx */
+void
+bna_rx_receive_resume(struct bna_rx *rx,
+		      void (*cbfn)(struct bnad *, struct bna_rx *,
+				   enum bna_cb_status))
+{
+	struct bna_rxf *rxf = &rx->rxf;
+
+	if (rxf->rxf_oper_state == BNA_RXF_OPER_STATE_PAUSED) {
+		rxf->oper_state_cbfn = cbfn;
+		rxf->oper_state_cbarg = rx->bna->bnad;
+		bfa_fsm_send_event(rxf, RXF_E_RESUME);
+	} else if (cbfn)
+		(*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+}
+
+void
+bna_rx_receive_pause(struct bna_rx *rx,
+		     void (*cbfn)(struct bnad *, struct bna_rx *,
+				  enum bna_cb_status))
+{
+	struct bna_rxf *rxf = &rx->rxf;
+
+	if (rxf->rxf_oper_state == BNA_RXF_OPER_STATE_RUNNING) {
+		rxf->oper_state_cbfn = cbfn;
+		rxf->oper_state_cbarg = rx->bna->bnad;
+		bfa_fsm_send_event(rxf, RXF_E_PAUSE);
+	} else if (cbfn)
+		(*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+}
+
+/* RxF <- bnad */
+enum bna_cb_status
+bna_rx_ucast_add(struct bna_rx *rx, u8 *addr,
+		 void (*cbfn)(struct bnad *, struct bna_rx *,
+			      enum bna_cb_status))
+{
+	struct bna_rxf *rxf = &rx->rxf;
+	struct list_head *qe;
+	struct bna_mac *mac;
+
+	/* Check if already added */
+	list_for_each(qe, &rxf->ucast_active_q) {
+		mac = (struct bna_mac *)qe;
+		if (BNA_MAC_IS_EQUAL(mac->addr, addr)) {
+			if (cbfn)
+				(*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+			return BNA_CB_SUCCESS;
+		}
+	}
+
+	/* Check if pending addition */
+	list_for_each(qe, &rxf->ucast_pending_add_q) {
+		mac = (struct bna_mac *)qe;
+		if (BNA_MAC_IS_EQUAL(mac->addr, addr)) {
+			if (cbfn)
+				(*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+			return BNA_CB_SUCCESS;
+		}
+	}
+
+	mac = bna_ucam_mod_mac_get(&rxf->rx->bna->ucam_mod);
+	if (mac == NULL)
+		return BNA_CB_UCAST_CAM_FULL;
+	bfa_q_qe_init(&mac->qe);
+	memcpy(mac->addr, addr, ETH_ALEN);
+	list_add_tail(&mac->qe, &rxf->ucast_pending_add_q);
+
+	rxf->cam_fltr_cbfn = cbfn;
+	rxf->cam_fltr_cbarg = rx->bna->bnad;
+
+	bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+
+	return BNA_CB_SUCCESS;
+}
+
+/* RxF <- bnad */
+enum bna_cb_status
+bna_rx_ucast_del(struct bna_rx *rx, u8 *addr,
+		 void (*cbfn)(struct bnad *, struct bna_rx *,
+			      enum bna_cb_status))
+{
+	struct bna_rxf *rxf = &rx->rxf;
+	struct list_head *qe;
+	struct bna_mac *mac;
+
+	list_for_each(qe, &rxf->ucast_pending_add_q) {
+		mac = (struct bna_mac *)qe;
+		if (BNA_MAC_IS_EQUAL(mac->addr, addr)) {
+			list_del(qe);
+			bfa_q_qe_init(qe);
+			bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod, mac);
+			if (cbfn)
+				(*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+			return BNA_CB_SUCCESS;
+		}
+	}
+
+	list_for_each(qe, &rxf->ucast_active_q) {
+		mac = (struct bna_mac *)qe;
+		if (BNA_MAC_IS_EQUAL(mac->addr, addr)) {
+			list_del(qe);
+			bfa_q_qe_init(qe);
+			list_add_tail(qe, &rxf->ucast_pending_del_q);
+			rxf->cam_fltr_cbfn = cbfn;
+			rxf->cam_fltr_cbarg = rx->bna->bnad;
+			bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+			return BNA_CB_SUCCESS;
+		}
+	}
+
+	return BNA_CB_INVALID_MAC;
+}
+
+/* RxF <- bnad */
+enum bna_cb_status
+bna_rx_mode_set(struct bna_rx *rx, enum bna_rxmode new_mode,
+		enum bna_rxmode bitmask,
+		void (*cbfn)(struct bnad *, struct bna_rx *,
+			     enum bna_cb_status))
+{
+	struct bna_rxf *rxf = &rx->rxf;
+	int need_hw_config = 0;
+
+	/* Error checks */
+
+	if (is_promisc_enable(new_mode, bitmask)) {
+		/* If promisc mode is already enabled elsewhere in the system */
+		if ((rx->bna->rxf_promisc_id != BFI_MAX_RXF) &&
+			(rx->bna->rxf_promisc_id != rxf->rxf_id))
+			goto err_return;
+
+		/* If default mode is already enabled in the system */
+		if (rx->bna->rxf_default_id != BFI_MAX_RXF)
+			goto err_return;
+
+		/* Trying to enable promiscuous and default mode together */
+		if (is_default_enable(new_mode, bitmask))
+			goto err_return;
+	}
+
+	if (is_default_enable(new_mode, bitmask)) {
+		/* If default mode is already enabled elsewhere in the system */
+		if ((rx->bna->rxf_default_id != BFI_MAX_RXF) &&
+			(rx->bna->rxf_default_id != rxf->rxf_id)) {
+				goto err_return;
+		}
+
+		/* If promiscuous mode is already enabled in the system */
+		if (rx->bna->rxf_promisc_id != BFI_MAX_RXF)
+			goto err_return;
+	}
+
+	/* Process the commands */
+
+	if (is_promisc_enable(new_mode, bitmask)) {
+		if (rxf_promisc_enable(rxf))
+			need_hw_config = 1;
+	} else if (is_promisc_disable(new_mode, bitmask)) {
+		if (rxf_promisc_disable(rxf))
+			need_hw_config = 1;
+	}
+
+	if (is_default_enable(new_mode, bitmask)) {
+		if (rxf_default_enable(rxf))
+			need_hw_config = 1;
+	} else if (is_default_disable(new_mode, bitmask)) {
+		if (rxf_default_disable(rxf))
+			need_hw_config = 1;
+	}
+
+	if (is_allmulti_enable(new_mode, bitmask)) {
+		if (rxf_allmulti_enable(rxf))
+			need_hw_config = 1;
+	} else if (is_allmulti_disable(new_mode, bitmask)) {
+		if (rxf_allmulti_disable(rxf))
+			need_hw_config = 1;
+	}
+
+	/* Trigger h/w if needed */
+
+	if (need_hw_config) {
+		rxf->cam_fltr_cbfn = cbfn;
+		rxf->cam_fltr_cbarg = rx->bna->bnad;
+		bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+	} else if (cbfn)
+		(*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+
+	return BNA_CB_SUCCESS;
+
+err_return:
+	return BNA_CB_FAIL;
+}
+
+/* RxF <- bnad */
+void
+bna_rx_rss_enable(struct bna_rx *rx)
+{
+	struct bna_rxf *rxf = &rx->rxf;
+
+	rxf->rxf_flags |= BNA_RXF_FL_RSS_CONFIG_PENDING;
+	rxf->rss_status = BNA_STATUS_T_ENABLED;
+	bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+}
+
+/* RxF <- bnad */
+void
+bna_rx_rss_disable(struct bna_rx *rx)
+{
+	struct bna_rxf *rxf = &rx->rxf;
+
+	rxf->rxf_flags |= BNA_RXF_FL_RSS_CONFIG_PENDING;
+	rxf->rss_status = BNA_STATUS_T_DISABLED;
+	bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+}
+
+/* RxF <- bnad */
+void
+bna_rx_rss_reconfig(struct bna_rx *rx, struct bna_rxf_rss *rss_config)
+{
+	struct bna_rxf *rxf = &rx->rxf;
+	rxf->rxf_flags |= BNA_RXF_FL_RSS_CONFIG_PENDING;
+	rxf->rss_status = BNA_STATUS_T_ENABLED;
+	rxf->rss_cfg = *rss_config;
+	bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+}
+
+void
+/* RxF <- bnad */
+bna_rx_vlanfilter_enable(struct bna_rx *rx)
+{
+	struct bna_rxf *rxf = &rx->rxf;
+
+	if (rxf->vlan_filter_status == BNA_STATUS_T_DISABLED) {
+		rxf->rxf_flags |= BNA_RXF_FL_VLAN_CONFIG_PENDING;
+		rxf->vlan_filter_status = BNA_STATUS_T_ENABLED;
+		bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+	}
+}
+
+/* RxF <- bnad */
+void
+bna_rx_vlanfilter_disable(struct bna_rx *rx)
+{
+	struct bna_rxf *rxf = &rx->rxf;
+
+	if (rxf->vlan_filter_status == BNA_STATUS_T_ENABLED) {
+		rxf->rxf_flags |= BNA_RXF_FL_VLAN_CONFIG_PENDING;
+		rxf->vlan_filter_status = BNA_STATUS_T_DISABLED;
+		bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+	}
+}
+
+/* Rx */
+
+struct bna_rxp *
+bna_rx_get_rxp(struct bna_rx *rx, int vector)
+{
+	struct bna_rxp *rxp;
+	struct list_head *qe;
+
+	list_for_each(qe, &rx->rxp_q) {
+		rxp = (struct bna_rxp *)qe;
+		if (rxp->vector == vector)
+			return rxp;
+	}
+	return NULL;
+}
+
+/*
+ * bna_rx_rss_rit_set()
+ * Sets the Q ids for the specified msi-x vectors in the RIT.
+ * Maximum rit size supported is 64, which should be the max size of the
+ * vectors array.
+ */
+
+void
+bna_rx_rss_rit_set(struct bna_rx *rx, unsigned int *vectors, int nvectors)
+{
+	int i;
+	struct bna_rxp *rxp;
+	struct bna_rxq *q0 = NULL, *q1 = NULL;
+	struct bna *bna;
+	struct bna_rxf *rxf;
+
+	/* Build the RIT contents for this RX */
+	bna = rx->bna;
+
+	rxf = &rx->rxf;
+	for (i = 0; i < nvectors; i++) {
+		rxp = bna_rx_get_rxp(rx, vectors[i]);
+
+		GET_RXQS(rxp, q0, q1);
+		rxf->rit_segment->rit[i].large_rxq_id = q0->rxq_id;
+		rxf->rit_segment->rit[i].small_rxq_id = (q1 ? q1->rxq_id : 0);
+	}
+
+	rxf->rit_segment->rit_size = nvectors;
+
+	/* Subsequent call to enable/reconfig RSS will update the RIT in h/w */
+}
+
+/* Rx <- bnad */
+void
+bna_rx_coalescing_timeo_set(struct bna_rx *rx, int coalescing_timeo)
+{
+	struct bna_rxp *rxp;
+	struct list_head *qe;
+
+	list_for_each(qe, &rx->rxp_q) {
+		rxp = (struct bna_rxp *)qe;
+		rxp->cq.ccb->rx_coalescing_timeo = coalescing_timeo;
+		bna_ib_coalescing_timeo_set(rxp->cq.ib, coalescing_timeo);
+	}
+}
+
+/* Rx <- bnad */
+void
+bna_rx_dim_reconfig(struct bna *bna, u32 vector[][BNA_BIAS_T_MAX])
+{
+	int i, j;
+
+	for (i = 0; i < BNA_LOAD_T_MAX; i++)
+		for (j = 0; j < BNA_BIAS_T_MAX; j++)
+			bna->rx_mod.dim_vector[i][j] = vector[i][j];
+}
+
+/* Rx <- bnad */
+void
+bna_rx_dim_update(struct bna_ccb *ccb)
+{
+	struct bna *bna = ccb->cq->rx->bna;
+	u32 load, bias;
+	u32 pkt_rt, small_rt, large_rt;
+	u8 coalescing_timeo;
+
+	if ((ccb->pkt_rate.small_pkt_cnt == 0) &&
+		(ccb->pkt_rate.large_pkt_cnt == 0))
+		return;
+
+	/* Arrive at preconfigured coalescing timeo value based on pkt rate */
+
+	small_rt = ccb->pkt_rate.small_pkt_cnt;
+	large_rt = ccb->pkt_rate.large_pkt_cnt;
+
+	pkt_rt = small_rt + large_rt;
+
+	if (pkt_rt < BNA_PKT_RATE_10K)
+		load = BNA_LOAD_T_LOW_4;
+	else if (pkt_rt < BNA_PKT_RATE_20K)
+		load = BNA_LOAD_T_LOW_3;
+	else if (pkt_rt < BNA_PKT_RATE_30K)
+		load = BNA_LOAD_T_LOW_2;
+	else if (pkt_rt < BNA_PKT_RATE_40K)
+		load = BNA_LOAD_T_LOW_1;
+	else if (pkt_rt < BNA_PKT_RATE_50K)
+		load = BNA_LOAD_T_HIGH_1;
+	else if (pkt_rt < BNA_PKT_RATE_60K)
+		load = BNA_LOAD_T_HIGH_2;
+	else if (pkt_rt < BNA_PKT_RATE_80K)
+		load = BNA_LOAD_T_HIGH_3;
+	else
+		load = BNA_LOAD_T_HIGH_4;
+
+	if (small_rt > (large_rt << 1))
+		bias = 0;
+	else
+		bias = 1;
+
+	ccb->pkt_rate.small_pkt_cnt = 0;
+	ccb->pkt_rate.large_pkt_cnt = 0;
+
+	coalescing_timeo = bna->rx_mod.dim_vector[load][bias];
+	ccb->rx_coalescing_timeo = coalescing_timeo;
+
+	/* Set it to IB */
+	bna_ib_coalescing_timeo_set(ccb->cq->ib, coalescing_timeo);
+}
+
+/* Tx */
+/* TX <- bnad */
+enum bna_cb_status
+bna_tx_prio_set(struct bna_tx *tx, int prio,
+		void (*cbfn)(struct bnad *, struct bna_tx *,
+			     enum bna_cb_status))
+{
+	if (tx->flags & BNA_TX_F_PRIO_LOCK)
+		return BNA_CB_FAIL;
+	else {
+		tx->prio_change_cbfn = cbfn;
+		bna_tx_prio_changed(tx, prio);
+	}
+
+	return BNA_CB_SUCCESS;
+}
+
+/* TX <- bnad */
+void
+bna_tx_coalescing_timeo_set(struct bna_tx *tx, int coalescing_timeo)
+{
+	struct bna_txq *txq;
+	struct list_head *qe;
+
+	list_for_each(qe, &tx->txq_q) {
+		txq = (struct bna_txq *)qe;
+		bna_ib_coalescing_timeo_set(txq->ib, coalescing_timeo);
+	}
+}
+
+/*
+ * Private data
+ */
+
+struct bna_ritseg_pool_cfg {
+	u32	pool_size;
+	u32	pool_entry_size;
+};
+init_ritseg_pool(ritseg_pool_cfg);
+
+/*
+ * Private functions
+ */
+static void
+bna_ucam_mod_init(struct bna_ucam_mod *ucam_mod, struct bna *bna,
+		  struct bna_res_info *res_info)
+{
+	int i;
+
+	ucam_mod->ucmac = (struct bna_mac *)
+		res_info[BNA_RES_MEM_T_UCMAC_ARRAY].res_u.mem_info.mdl[0].kva;
+
+	INIT_LIST_HEAD(&ucam_mod->free_q);
+	for (i = 0; i < BFI_MAX_UCMAC; i++) {
+		bfa_q_qe_init(&ucam_mod->ucmac[i].qe);
+		list_add_tail(&ucam_mod->ucmac[i].qe, &ucam_mod->free_q);
+	}
+
+	ucam_mod->bna = bna;
+}
+
+static void
+bna_ucam_mod_uninit(struct bna_ucam_mod *ucam_mod)
+{
+	struct list_head *qe;
+	int i = 0;
+
+	list_for_each(qe, &ucam_mod->free_q)
+		i++;
+
+	ucam_mod->bna = NULL;
+}
+
+static void
+bna_mcam_mod_init(struct bna_mcam_mod *mcam_mod, struct bna *bna,
+		  struct bna_res_info *res_info)
+{
+	int i;
+
+	mcam_mod->mcmac = (struct bna_mac *)
+		res_info[BNA_RES_MEM_T_MCMAC_ARRAY].res_u.mem_info.mdl[0].kva;
+
+	INIT_LIST_HEAD(&mcam_mod->free_q);
+	for (i = 0; i < BFI_MAX_MCMAC; i++) {
+		bfa_q_qe_init(&mcam_mod->mcmac[i].qe);
+		list_add_tail(&mcam_mod->mcmac[i].qe, &mcam_mod->free_q);
+	}
+
+	mcam_mod->bna = bna;
+}
+
+static void
+bna_mcam_mod_uninit(struct bna_mcam_mod *mcam_mod)
+{
+	struct list_head *qe;
+	int i = 0;
+
+	list_for_each(qe, &mcam_mod->free_q)
+		i++;
+
+	mcam_mod->bna = NULL;
+}
+
+static void
+bna_rit_mod_init(struct bna_rit_mod *rit_mod,
+		struct bna_res_info *res_info)
+{
+	int i;
+	int j;
+	int count;
+	int offset;
+
+	rit_mod->rit = (struct bna_rit_entry *)
+		res_info[BNA_RES_MEM_T_RIT_ENTRY].res_u.mem_info.mdl[0].kva;
+	rit_mod->rit_segment = (struct bna_rit_segment *)
+		res_info[BNA_RES_MEM_T_RIT_SEGMENT].res_u.mem_info.mdl[0].kva;
+
+	count = 0;
+	offset = 0;
+	for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) {
+		INIT_LIST_HEAD(&rit_mod->rit_seg_pool[i]);
+		for (j = 0; j < ritseg_pool_cfg[i].pool_size; j++) {
+			bfa_q_qe_init(&rit_mod->rit_segment[count].qe);
+			rit_mod->rit_segment[count].max_rit_size =
+					ritseg_pool_cfg[i].pool_entry_size;
+			rit_mod->rit_segment[count].rit_offset = offset;
+			rit_mod->rit_segment[count].rit =
+					&rit_mod->rit[offset];
+			list_add_tail(&rit_mod->rit_segment[count].qe,
+				&rit_mod->rit_seg_pool[i]);
+			count++;
+			offset += ritseg_pool_cfg[i].pool_entry_size;
+		}
+	}
+}
+
+static void
+bna_rit_mod_uninit(struct bna_rit_mod *rit_mod)
+{
+	struct bna_rit_segment *rit_segment;
+	struct list_head *qe;
+	int i;
+	int j;
+
+	for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) {
+		j = 0;
+		list_for_each(qe, &rit_mod->rit_seg_pool[i]) {
+			rit_segment = (struct bna_rit_segment *)qe;
+			j++;
+		}
+	}
+}
+
+/*
+ * Public functions
+ */
+
+/* Called during probe(), before calling bna_init() */
+void
+bna_res_req(struct bna_res_info *res_info)
+{
+	bna_adv_res_req(res_info);
+
+	/* DMA memory for retrieving IOC attributes */
+	res_info[BNA_RES_MEM_T_ATTR].res_type = BNA_RES_T_MEM;
+	res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.mem_type = BNA_MEM_T_DMA;
+	res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.num = 1;
+	res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.len =
+				ALIGN(bfa_ioc_meminfo(), PAGE_SIZE);
+
+	/* DMA memory for index segment of an IB */
+	res_info[BNA_RES_MEM_T_IBIDX].res_type = BNA_RES_T_MEM;
+	res_info[BNA_RES_MEM_T_IBIDX].res_u.mem_info.mem_type = BNA_MEM_T_DMA;
+	res_info[BNA_RES_MEM_T_IBIDX].res_u.mem_info.len =
+				BFI_IBIDX_SIZE * BFI_IBIDX_MAX_SEGSIZE;
+	res_info[BNA_RES_MEM_T_IBIDX].res_u.mem_info.num = BFI_MAX_IB;
+
+	/* Virtual memory for IB objects - stored by IB module */
+	res_info[BNA_RES_MEM_T_IB_ARRAY].res_type = BNA_RES_T_MEM;
+	res_info[BNA_RES_MEM_T_IB_ARRAY].res_u.mem_info.mem_type =
+								BNA_MEM_T_KVA;
+	res_info[BNA_RES_MEM_T_IB_ARRAY].res_u.mem_info.num = 1;
+	res_info[BNA_RES_MEM_T_IB_ARRAY].res_u.mem_info.len =
+				BFI_MAX_IB * sizeof(struct bna_ib);
+
+	/* Virtual memory for intr objects - stored by IB module */
+	res_info[BNA_RES_MEM_T_INTR_ARRAY].res_type = BNA_RES_T_MEM;
+	res_info[BNA_RES_MEM_T_INTR_ARRAY].res_u.mem_info.mem_type =
+								BNA_MEM_T_KVA;
+	res_info[BNA_RES_MEM_T_INTR_ARRAY].res_u.mem_info.num = 1;
+	res_info[BNA_RES_MEM_T_INTR_ARRAY].res_u.mem_info.len =
+				BFI_MAX_IB * sizeof(struct bna_intr);
+
+	/* Virtual memory for idx_seg objects - stored by IB module */
+	res_info[BNA_RES_MEM_T_IDXSEG_ARRAY].res_type = BNA_RES_T_MEM;
+	res_info[BNA_RES_MEM_T_IDXSEG_ARRAY].res_u.mem_info.mem_type =
+								BNA_MEM_T_KVA;
+	res_info[BNA_RES_MEM_T_IDXSEG_ARRAY].res_u.mem_info.num = 1;
+	res_info[BNA_RES_MEM_T_IDXSEG_ARRAY].res_u.mem_info.len =
+			BFI_IBIDX_TOTAL_SEGS * sizeof(struct bna_ibidx_seg);
+
+	/* Virtual memory for Tx objects - stored by Tx module */
+	res_info[BNA_RES_MEM_T_TX_ARRAY].res_type = BNA_RES_T_MEM;
+	res_info[BNA_RES_MEM_T_TX_ARRAY].res_u.mem_info.mem_type =
+								BNA_MEM_T_KVA;
+	res_info[BNA_RES_MEM_T_TX_ARRAY].res_u.mem_info.num = 1;
+	res_info[BNA_RES_MEM_T_TX_ARRAY].res_u.mem_info.len =
+			BFI_MAX_TXQ * sizeof(struct bna_tx);
+
+	/* Virtual memory for TxQ - stored by Tx module */
+	res_info[BNA_RES_MEM_T_TXQ_ARRAY].res_type = BNA_RES_T_MEM;
+	res_info[BNA_RES_MEM_T_TXQ_ARRAY].res_u.mem_info.mem_type =
+								BNA_MEM_T_KVA;
+	res_info[BNA_RES_MEM_T_TXQ_ARRAY].res_u.mem_info.num = 1;
+	res_info[BNA_RES_MEM_T_TXQ_ARRAY].res_u.mem_info.len =
+			BFI_MAX_TXQ * sizeof(struct bna_txq);
+
+	/* Virtual memory for Rx objects - stored by Rx module */
+	res_info[BNA_RES_MEM_T_RX_ARRAY].res_type = BNA_RES_T_MEM;
+	res_info[BNA_RES_MEM_T_RX_ARRAY].res_u.mem_info.mem_type =
+								BNA_MEM_T_KVA;
+	res_info[BNA_RES_MEM_T_RX_ARRAY].res_u.mem_info.num = 1;
+	res_info[BNA_RES_MEM_T_RX_ARRAY].res_u.mem_info.len =
+			BFI_MAX_RXQ * sizeof(struct bna_rx);
+
+	/* Virtual memory for RxPath - stored by Rx module */
+	res_info[BNA_RES_MEM_T_RXP_ARRAY].res_type = BNA_RES_T_MEM;
+	res_info[BNA_RES_MEM_T_RXP_ARRAY].res_u.mem_info.mem_type =
+								BNA_MEM_T_KVA;
+	res_info[BNA_RES_MEM_T_RXP_ARRAY].res_u.mem_info.num = 1;
+	res_info[BNA_RES_MEM_T_RXP_ARRAY].res_u.mem_info.len =
+			BFI_MAX_RXQ * sizeof(struct bna_rxp);
+
+	/* Virtual memory for RxQ - stored by Rx module */
+	res_info[BNA_RES_MEM_T_RXQ_ARRAY].res_type = BNA_RES_T_MEM;
+	res_info[BNA_RES_MEM_T_RXQ_ARRAY].res_u.mem_info.mem_type =
+								BNA_MEM_T_KVA;
+	res_info[BNA_RES_MEM_T_RXQ_ARRAY].res_u.mem_info.num = 1;
+	res_info[BNA_RES_MEM_T_RXQ_ARRAY].res_u.mem_info.len =
+			BFI_MAX_RXQ * sizeof(struct bna_rxq);
+
+	/* Virtual memory for Unicast MAC address - stored by ucam module */
+	res_info[BNA_RES_MEM_T_UCMAC_ARRAY].res_type = BNA_RES_T_MEM;
+	res_info[BNA_RES_MEM_T_UCMAC_ARRAY].res_u.mem_info.mem_type =
+								BNA_MEM_T_KVA;
+	res_info[BNA_RES_MEM_T_UCMAC_ARRAY].res_u.mem_info.num = 1;
+	res_info[BNA_RES_MEM_T_UCMAC_ARRAY].res_u.mem_info.len =
+			BFI_MAX_UCMAC * sizeof(struct bna_mac);
+
+	/* Virtual memory for Multicast MAC address - stored by mcam module */
+	res_info[BNA_RES_MEM_T_MCMAC_ARRAY].res_type = BNA_RES_T_MEM;
+	res_info[BNA_RES_MEM_T_MCMAC_ARRAY].res_u.mem_info.mem_type =
+								BNA_MEM_T_KVA;
+	res_info[BNA_RES_MEM_T_MCMAC_ARRAY].res_u.mem_info.num = 1;
+	res_info[BNA_RES_MEM_T_MCMAC_ARRAY].res_u.mem_info.len =
+			BFI_MAX_MCMAC * sizeof(struct bna_mac);
+
+	/* Virtual memory for RIT entries */
+	res_info[BNA_RES_MEM_T_RIT_ENTRY].res_type = BNA_RES_T_MEM;
+	res_info[BNA_RES_MEM_T_RIT_ENTRY].res_u.mem_info.mem_type =
+								BNA_MEM_T_KVA;
+	res_info[BNA_RES_MEM_T_RIT_ENTRY].res_u.mem_info.num = 1;
+	res_info[BNA_RES_MEM_T_RIT_ENTRY].res_u.mem_info.len =
+			BFI_MAX_RIT_SIZE * sizeof(struct bna_rit_entry);
+
+	/* Virtual memory for RIT segment table */
+	res_info[BNA_RES_MEM_T_RIT_SEGMENT].res_type = BNA_RES_T_MEM;
+	res_info[BNA_RES_MEM_T_RIT_SEGMENT].res_u.mem_info.mem_type =
+								BNA_MEM_T_KVA;
+	res_info[BNA_RES_MEM_T_RIT_SEGMENT].res_u.mem_info.num = 1;
+	res_info[BNA_RES_MEM_T_RIT_SEGMENT].res_u.mem_info.len =
+			BFI_RIT_TOTAL_SEGS * sizeof(struct bna_rit_segment);
+
+	/* Interrupt resource for mailbox interrupt */
+	res_info[BNA_RES_INTR_T_MBOX].res_type = BNA_RES_T_INTR;
+	res_info[BNA_RES_INTR_T_MBOX].res_u.intr_info.intr_type =
+							BNA_INTR_T_MSIX;
+	res_info[BNA_RES_INTR_T_MBOX].res_u.intr_info.num = 1;
+}
+
+/* Called during probe() */
+void
+bna_init(struct bna *bna, struct bnad *bnad, struct bna_ident *ident,
+		struct bfa_pcidev *pcidev, struct bna_res_info *res_info)
+{
+	bna->bnad = bnad;
+	bna->ident = *ident;
+	bna->pcidev = *pcidev;
+
+	bna->stats.hw_stats = (struct bfi_ll_stats *)
+		res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.mdl[0].kva;
+	bna->hw_stats_dma.msb =
+		res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.mdl[0].dma.msb;
+	bna->hw_stats_dma.lsb =
+		res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.mdl[0].dma.lsb;
+	bna->stats.sw_stats = (struct bna_sw_stats *)
+		res_info[BNA_RES_MEM_T_SWSTATS].res_u.mem_info.mdl[0].kva;
+
+	bna->regs.page_addr = bna->pcidev.pci_bar_kva +
+				reg_offset[bna->pcidev.pci_func].page_addr;
+	bna->regs.fn_int_status = bna->pcidev.pci_bar_kva +
+				reg_offset[bna->pcidev.pci_func].fn_int_status;
+	bna->regs.fn_int_mask = bna->pcidev.pci_bar_kva +
+				reg_offset[bna->pcidev.pci_func].fn_int_mask;
+
+	if (bna->pcidev.pci_func < 3)
+		bna->port_num = 0;
+	else
+		bna->port_num = 1;
+
+	/* Also initializes diag, cee, sfp, phy_port and mbox_mod */
+	bna_device_init(&bna->device, bna, res_info);
+
+	bna_port_init(&bna->port, bna);
+
+	bna_tx_mod_init(&bna->tx_mod, bna, res_info);
+
+	bna_rx_mod_init(&bna->rx_mod, bna, res_info);
+
+	bna_ib_mod_init(&bna->ib_mod, bna, res_info);
+
+	bna_rit_mod_init(&bna->rit_mod, res_info);
+
+	bna_ucam_mod_init(&bna->ucam_mod, bna, res_info);
+
+	bna_mcam_mod_init(&bna->mcam_mod, bna, res_info);
+
+	bna->rxf_default_id = BFI_MAX_RXF;
+	bna->rxf_promisc_id = BFI_MAX_RXF;
+
+	/* Mbox q element for posting stat request to f/w */
+	bfa_q_qe_init(&bna->mbox_qe.qe);
+}
+
+void
+bna_uninit(struct bna *bna)
+{
+	bna_mcam_mod_uninit(&bna->mcam_mod);
+
+	bna_ucam_mod_uninit(&bna->ucam_mod);
+
+	bna_rit_mod_uninit(&bna->rit_mod);
+
+	bna_ib_mod_uninit(&bna->ib_mod);
+
+	bna_rx_mod_uninit(&bna->rx_mod);
+
+	bna_tx_mod_uninit(&bna->tx_mod);
+
+	bna_port_uninit(&bna->port);
+
+	bna_device_uninit(&bna->device);
+
+	bna->bnad = NULL;
+}
+
+struct bna_mac *
+bna_ucam_mod_mac_get(struct bna_ucam_mod *ucam_mod)
+{
+	struct list_head *qe;
+
+	if (list_empty(&ucam_mod->free_q))
+		return NULL;
+
+	bfa_q_deq(&ucam_mod->free_q, &qe);
+
+	return (struct bna_mac *)qe;
+}
+
+void
+bna_ucam_mod_mac_put(struct bna_ucam_mod *ucam_mod, struct bna_mac *mac)
+{
+	list_add_tail(&mac->qe, &ucam_mod->free_q);
+}
+
+struct bna_mac *
+bna_mcam_mod_mac_get(struct bna_mcam_mod *mcam_mod)
+{
+	struct list_head *qe;
+
+	if (list_empty(&mcam_mod->free_q))
+		return NULL;
+
+	bfa_q_deq(&mcam_mod->free_q, &qe);
+
+	return (struct bna_mac *)qe;
+}
+
+void
+bna_mcam_mod_mac_put(struct bna_mcam_mod *mcam_mod, struct bna_mac *mac)
+{
+	list_add_tail(&mac->qe, &mcam_mod->free_q);
+}
+
+/**
+ * Note: This should be called in the same locking context as the call to
+ * bna_rit_mod_seg_get()
+ */
+int
+bna_rit_mod_can_satisfy(struct bna_rit_mod *rit_mod, int seg_size)
+{
+	int i;
+
+	/* Select the pool for seg_size */
+	for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) {
+		if (seg_size <= ritseg_pool_cfg[i].pool_entry_size)
+			break;
+	}
+
+	if (i == BFI_RIT_SEG_TOTAL_POOLS)
+		return 0;
+
+	if (list_empty(&rit_mod->rit_seg_pool[i]))
+		return 0;
+
+	return 1;
+}
+
+struct bna_rit_segment *
+bna_rit_mod_seg_get(struct bna_rit_mod *rit_mod, int seg_size)
+{
+	struct bna_rit_segment *seg;
+	struct list_head *qe;
+	int i;
+
+	/* Select the pool for seg_size */
+	for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) {
+		if (seg_size <= ritseg_pool_cfg[i].pool_entry_size)
+			break;
+	}
+
+	if (i == BFI_RIT_SEG_TOTAL_POOLS)
+		return NULL;
+
+	if (list_empty(&rit_mod->rit_seg_pool[i]))
+		return NULL;
+
+	bfa_q_deq(&rit_mod->rit_seg_pool[i], &qe);
+	seg = (struct bna_rit_segment *)qe;
+	bfa_q_qe_init(&seg->qe);
+	seg->rit_size = seg_size;
+
+	return seg;
+}
+
+void
+bna_rit_mod_seg_put(struct bna_rit_mod *rit_mod,
+			struct bna_rit_segment *seg)
+{
+	int i;
+
+	/* Select the pool for seg->max_rit_size */
+	for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) {
+		if (seg->max_rit_size == ritseg_pool_cfg[i].pool_entry_size)
+			break;
+	}
+
+	seg->rit_size = 0;
+	list_add_tail(&seg->qe, &rit_mod->rit_seg_pool[i]);
+}

^ permalink raw reply

* [PATCH 1/6] bna: Brocade 10Gb Ethernet device driver
From: Rasesh Mody @ 2010-08-11  4:24 UTC (permalink / raw)
  To: netdev; +Cc: adapter_linux_open_src_team

From: Rasesh Mody <rmody@brocade.com>

This is patch 1/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: Rasesh Mody <rmody@brocade.com>
---
 bnad.c         | 3300 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 bnad.h         |  339 +++++
 bnad_ethtool.c | 1282 ++++++++++++++++++++++
 3 files changed, 4921 insertions(+)

diff -ruP net-next-2.6.35-rc1-orig/drivers/net/bna/bnad.c net-next-2.6.35-rc1-mod/drivers/net/bna/bnad.c
--- net-next-2.6.35-rc1-orig/drivers/net/bna/bnad.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.35-rc1-mod/drivers/net/bna/bnad.c	2010-08-10 12:23:09.162215000 -0700
@@ -0,0 +1,3300 @@
+/*
+ * 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) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/in.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+
+#include "bnad.h"
+#include "bna.h"
+#include "cna.h"
+
+DEFINE_MUTEX(bnad_fwimg_mutex);
+
+/*
+ * Module params
+ */
+static uint bnad_msix_disable;
+module_param(bnad_msix_disable, uint, 0444);
+MODULE_PARM_DESC(bnad_msix_disable, "Disable MSIX mode");
+
+static uint bnad_ioc_auto_recover = 1;
+module_param(bnad_ioc_auto_recover, uint, 0444);
+MODULE_PARM_DESC(bnad_ioc_auto_recover, "Enable / Disable auto recovery");
+
+/*
+ * Global variables
+ */
+u32 bna_id;
+u32 bnad_rxqs_per_cq = 2;
+
+DECLARE_MUTEX(bnad_list_sem);
+LIST_HEAD(bnad_list);
+
+const u8 bnad_bcast_addr[] =  {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+/*
+ * Local MACROS
+ */
+#define BNAD_TX_UNMAPQ_DEPTH (bnad->txq_depth * 2)
+
+#define BNAD_RX_UNMAPQ_DEPTH (bnad->rxq_depth)
+
+#define BNAD_GET_MBOX_IRQ(_bnad)				\
+	(((_bnad)->cfg_flags & BNAD_CF_MSIX) ?			\
+	 ((_bnad)->msix_table[(_bnad)->msix_num - 1].vector) : 	\
+	 ((_bnad)->pcidev->irq))
+
+#define BNAD_FILL_UNMAPQ_MEM_REQ(_res_info, _num, _depth)	\
+do {								\
+	(_res_info)->res_type = BNA_RES_T_MEM;			\
+	(_res_info)->res_u.mem_info.mem_type = BNA_MEM_T_KVA;	\
+	(_res_info)->res_u.mem_info.num = (_num);		\
+	(_res_info)->res_u.mem_info.len =			\
+	sizeof(struct bnad_unmap_q) +				\
+	(sizeof(struct bnad_skb_unmap) * ((_depth) - 1));	\
+} while (0)
+
+/*
+ * Reinitialize completions in CQ, once Rx is taken down
+ */
+static void
+bnad_cq_cmpl_init(struct bnad *bnad, struct bna_ccb *ccb)
+{
+	struct bna_cq_entry *cmpl, *next_cmpl;
+	unsigned int wi_range, wis = 0, ccb_prod = 0;
+	int i;
+
+	BNA_CQ_QPGE_PTR_GET(ccb_prod, ccb->sw_qpt, cmpl,
+			    wi_range);
+
+	for (i = 0; i < ccb->q_depth; i++) {
+		wis++;
+		if (likely(--wi_range))
+			next_cmpl = cmpl + 1;
+		else {
+			BNA_QE_INDX_ADD(ccb_prod, wis, ccb->q_depth);
+			wis = 0;
+			BNA_CQ_QPGE_PTR_GET(ccb_prod, ccb->sw_qpt,
+						next_cmpl, wi_range);
+		}
+		cmpl->valid = 0;
+		cmpl = next_cmpl;
+	}
+}
+
+/*
+ * Frees all pending Tx Bufs
+ * At this point no activity is expected on the Q,
+ * so DMA unmap & freeing is fine.
+ */
+static void
+bnad_free_all_txbufs(struct bnad *bnad,
+		 struct bna_tcb *tcb)
+{
+	u16 		unmap_cons;
+	struct bnad_unmap_q *unmap_q = tcb->unmap_q;
+	struct bnad_skb_unmap *unmap_array;
+	struct sk_buff 		*skb = NULL;
+	int			i;
+
+	unmap_array = unmap_q->unmap_array;
+
+	unmap_cons = 0;
+	while (unmap_cons < unmap_q->q_depth) {
+		skb = unmap_array[unmap_cons].skb;
+		if (!skb) {
+			unmap_cons++;
+			continue;
+		}
+		unmap_array[unmap_cons].skb = NULL;
+
+		pci_unmap_single(bnad->pcidev,
+				 pci_unmap_addr(&unmap_array[unmap_cons],
+						dma_addr), skb_headlen(skb),
+						PCI_DMA_TODEVICE);
+
+		pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr, 0);
+		unmap_cons++;
+		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+			pci_unmap_page(bnad->pcidev,
+				       pci_unmap_addr(&unmap_array[unmap_cons],
+						      dma_addr),
+				       skb_shinfo(skb)->frags[i].size,
+				       PCI_DMA_TODEVICE);
+			pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr,
+					   0);
+			unmap_cons++;
+		}
+		dev_kfree_skb_any(skb);
+	}
+}
+
+/* Data Path Handlers */
+
+/*
+ * bnad_free_txbufs : Frees the Tx bufs on Tx completion
+ * Can be called in a) Interrupt context
+ *		    b) Sending context
+ *		    c) Tasklet context
+ */
+static u32
+bnad_free_txbufs(struct bnad *bnad,
+		 struct bna_tcb *tcb)
+{
+	u32 		sent_packets = 0, sent_bytes = 0;
+	u16 		wis, unmap_cons, updated_hw_cons;
+	struct bnad_unmap_q *unmap_q = tcb->unmap_q;
+	struct bnad_skb_unmap *unmap_array;
+	struct sk_buff 		*skb;
+	int i;
+
+	/*
+	 * Just return if TX is stopped. This check is useful
+	 * when bnad_free_txbufs() runs out of a tasklet scheduled
+	 * before bnad_cb_tx_cleanup() cleared BNAD_RF_TX_STARTED bit
+	 * but this routine runs actually after the cleanup has been
+	 * executed.
+	 */
+	if (!test_bit(BNAD_RF_TX_STARTED, &bnad->run_flags))
+		return 0;
+
+	updated_hw_cons = *(tcb->hw_consumer_index);
+
+	wis = BNA_Q_INDEX_CHANGE(tcb->consumer_index,
+				  updated_hw_cons, tcb->q_depth);
+
+	BUG_ON(!(wis <= BNA_QE_IN_USE_CNT(tcb, tcb->q_depth)));
+
+	unmap_array = unmap_q->unmap_array;
+	unmap_cons = unmap_q->consumer_index;
+
+	prefetch(&unmap_array[unmap_cons + 1]);
+	while (wis) {
+		skb = unmap_array[unmap_cons].skb;
+
+		unmap_array[unmap_cons].skb = NULL;
+
+		sent_packets++;
+		sent_bytes += skb->len;
+		wis -= BNA_TXQ_WI_NEEDED(1 + skb_shinfo(skb)->nr_frags);
+
+		pci_unmap_single(bnad->pcidev,
+				 pci_unmap_addr(&unmap_array[unmap_cons],
+						dma_addr), skb_headlen(skb),
+				 PCI_DMA_TODEVICE);
+		pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr, 0);
+		BNA_QE_INDX_ADD(unmap_cons, 1, unmap_q->q_depth);
+
+		prefetch(&unmap_array[unmap_cons + 1]);
+		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+			prefetch(&unmap_array[unmap_cons + 1]);
+
+			pci_unmap_page(bnad->pcidev,
+				       pci_unmap_addr(&unmap_array[unmap_cons],
+						      dma_addr),
+				       skb_shinfo(skb)->frags[i].size,
+				       PCI_DMA_TODEVICE);
+			pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr,
+					   0);
+			BNA_QE_INDX_ADD(unmap_cons, 1, unmap_q->q_depth);
+		}
+		dev_kfree_skb_any(skb);
+	}
+
+	/* Update consumer pointers. */
+	tcb->consumer_index = updated_hw_cons;
+	unmap_q->consumer_index = unmap_cons;
+
+	tcb->txq->tx_packets += sent_packets;
+	tcb->txq->tx_bytes += sent_bytes;
+
+	return sent_packets;
+}
+
+/* Tx Free Tasklet function */
+/* Frees for all the tcb's in all the Tx's */
+/*
+ * Scheduled from sending context, so that
+ * the fat Tx lock is not held for too long
+ * in the sending context.
+ */
+static void
+bnad_tx_free_tasklet(unsigned long bnad_ptr)
+{
+	struct bnad *bnad = (struct bnad *)bnad_ptr;
+	struct bna_tcb *tcb;
+	u32 		acked;
+	int			i, j;
+
+	for (i = 0; i < bnad->num_tx; i++) {
+		for (j = 0; j < bnad->num_txq_per_tx; j++) {
+			tcb = bnad->tx_info[i].tcb[j];
+			if (!tcb)
+				continue;
+			if (((u16) (*tcb->hw_consumer_index) !=
+				tcb->consumer_index) &&
+				(!test_and_set_bit(BNAD_TXQ_FREE_SENT,
+						  &tcb->flags))) {
+				acked = bnad_free_txbufs(bnad, tcb);
+				bna_ib_ack(tcb->i_dbell, acked);
+				smp_mb__before_clear_bit();
+				clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
+			}
+		}
+	}
+}
+
+static u32
+bnad_tx(struct bnad *bnad, struct bna_tcb *tcb)
+{
+	struct net_device *netdev = bnad->netdev;
+	u32 sent;
+
+	if (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags))
+		return 0;
+
+	sent = bnad_free_txbufs(bnad, tcb);
+	if (sent) {
+		if (netif_queue_stopped(netdev) &&
+		    netif_carrier_ok(netdev) &&
+		    BNA_QE_FREE_CNT(tcb, tcb->q_depth) >=
+				    BNAD_NETIF_WAKE_THRESHOLD) {
+			netif_wake_queue(netdev);
+			BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
+		}
+		bna_ib_ack(tcb->i_dbell, sent);
+	} else
+		bna_ib_ack(tcb->i_dbell, 0);
+
+	smp_mb__before_clear_bit();
+	clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
+
+	return sent;
+}
+
+/* MSIX Tx Completion Handler */
+static irqreturn_t
+bnad_msix_tx(int irq, void *data)
+{
+	struct bna_tcb *tcb = (struct bna_tcb *)data;
+	struct bnad *bnad = tcb->bnad;
+
+	bnad_tx(bnad, tcb);
+
+	return IRQ_HANDLED;
+}
+
+static void
+bnad_reset_rcb(struct bnad *bnad, struct bna_rcb *rcb)
+{
+	struct bnad_unmap_q *unmap_q = rcb->unmap_q;
+
+	rcb->producer_index = 0;
+	rcb->consumer_index = 0;
+
+	unmap_q->producer_index = 0;
+	unmap_q->consumer_index = 0;
+}
+
+static void
+bnad_free_rxbufs(struct bnad *bnad, struct bna_rcb *rcb)
+{
+	struct bnad_unmap_q *unmap_q;
+	struct sk_buff *skb;
+
+	unmap_q = rcb->unmap_q;
+	while (BNA_QE_IN_USE_CNT(unmap_q, unmap_q->q_depth)) {
+		skb = unmap_q->unmap_array[unmap_q->consumer_index].skb;
+		BUG_ON(!(skb));
+		unmap_q->unmap_array[unmap_q->consumer_index].skb = NULL;
+		pci_unmap_single(bnad->pcidev, pci_unmap_addr(&unmap_q->
+					unmap_array[unmap_q->consumer_index],
+					dma_addr), rcb->rxq->buffer_size +
+					NET_IP_ALIGN, PCI_DMA_FROMDEVICE);
+		dev_kfree_skb(skb);
+		BNA_QE_INDX_ADD(unmap_q->consumer_index, 1, unmap_q->q_depth);
+		BNA_QE_INDX_ADD(rcb->consumer_index, 1, rcb->q_depth);
+	}
+
+	bnad_reset_rcb(bnad, rcb);
+}
+
+static void
+bnad_alloc_n_post_rxbufs(struct bnad *bnad, struct bna_rcb *rcb)
+{
+	u16 to_alloc, alloced, unmap_prod, wi_range;
+	struct bnad_unmap_q *unmap_q = rcb->unmap_q;
+	struct bnad_skb_unmap *unmap_array;
+	struct bna_rxq_entry *rxent;
+	struct sk_buff *skb;
+	dma_addr_t dma_addr;
+
+	alloced = 0;
+	to_alloc =
+		BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth);
+
+	unmap_array = unmap_q->unmap_array;
+	unmap_prod = unmap_q->producer_index;
+
+	BNA_RXQ_QPGE_PTR_GET(unmap_prod, rcb->sw_qpt, rxent, wi_range);
+
+	while (to_alloc--) {
+		if (!wi_range) {
+			BNA_RXQ_QPGE_PTR_GET(unmap_prod, rcb->sw_qpt, rxent,
+					     wi_range);
+		}
+		skb = alloc_skb(rcb->rxq->buffer_size + NET_IP_ALIGN,
+				     GFP_ATOMIC);
+		if (unlikely(!skb)) {
+			BNAD_UPDATE_CTR(bnad, rxbuf_alloc_failed);
+			goto finishing;
+		}
+		skb->dev = bnad->netdev;
+		skb_reserve(skb, NET_IP_ALIGN);
+		unmap_array[unmap_prod].skb = skb;
+		dma_addr = pci_map_single(bnad->pcidev, skb->data,
+			rcb->rxq->buffer_size, PCI_DMA_FROMDEVICE);
+		pci_unmap_addr_set(&unmap_array[unmap_prod], dma_addr,
+				   dma_addr);
+		BNA_SET_DMA_ADDR(dma_addr, &rxent->host_addr);
+		BNA_QE_INDX_ADD(unmap_prod, 1, unmap_q->q_depth);
+
+		rxent++;
+		wi_range--;
+		alloced++;
+	}
+
+finishing:
+	if (likely(alloced)) {
+		unmap_q->producer_index = unmap_prod;
+		rcb->producer_index = unmap_prod;
+		smp_mb();
+		bna_rxq_prod_indx_doorbell(rcb);
+	}
+}
+
+/*
+ * Locking is required in the enable path
+ * because it is called from a napi poll
+ * context, where the bna_lock is not held
+ * unlike the IRQ context.
+ */
+static void
+bnad_enable_txrx_irqs(struct bnad *bnad)
+{
+	struct bna_tcb *tcb;
+	struct bna_ccb *ccb;
+	int i, j;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	for (i = 0; i < bnad->num_tx; i++) {
+		for (j = 0; j < bnad->num_txq_per_tx; j++) {
+			tcb = bnad->tx_info[i].tcb[j];
+			bna_ib_coalescing_timer_set(tcb->i_dbell,
+				tcb->txq->ib->ib_config.coalescing_timeo);
+			bna_ib_ack(tcb->i_dbell, 0);
+		}
+	}
+
+	for (i = 0; i < bnad->num_rx; i++) {
+		for (j = 0; j < bnad->num_rxp_per_rx; j++) {
+			ccb = bnad->rx_info[i].rx_ctrl[j].ccb;
+			bnad_enable_rx_irq_unsafe(ccb);
+		}
+	}
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+static inline void
+bnad_refill_rxq(struct bnad *bnad, struct bna_rcb *rcb)
+{
+	struct bnad_unmap_q *unmap_q = rcb->unmap_q;
+
+	if (!test_and_set_bit(BNAD_RXQ_REFILL, &rcb->flags)) {
+		if (BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth)
+			 >> BNAD_RXQ_REFILL_THRESHOLD_SHIFT)
+			bnad_alloc_n_post_rxbufs(bnad, rcb);
+		smp_mb__before_clear_bit();
+		clear_bit(BNAD_RXQ_REFILL, &rcb->flags);
+	}
+}
+
+static u32
+bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget)
+{
+	struct bna_cq_entry *cmpl, *next_cmpl;
+	struct bna_rcb *rcb = NULL;
+	unsigned int wi_range, packets = 0, wis = 0;
+	struct bnad_unmap_q *unmap_q;
+	struct sk_buff *skb;
+	u32 flags;
+	u32 qid0 = ccb->rcb[0]->rxq->rxq_id;
+	struct bna_pkt_rate *pkt_rt = &ccb->pkt_rate;
+
+	prefetch(bnad->netdev);
+	BNA_CQ_QPGE_PTR_GET(ccb->producer_index, ccb->sw_qpt, cmpl,
+			    wi_range);
+	BUG_ON(!(wi_range <= ccb->q_depth));
+	while (cmpl->valid && packets < budget) {
+		packets++;
+		BNA_UPDATE_PKT_CNT(pkt_rt, ntohs(cmpl->length));
+
+		if (qid0 == cmpl->rxq_id)
+			rcb = ccb->rcb[0];
+		else
+			rcb = ccb->rcb[1];
+
+		unmap_q = rcb->unmap_q;
+
+		skb = unmap_q->unmap_array[unmap_q->consumer_index].skb;
+		BUG_ON(!(skb));
+		unmap_q->unmap_array[unmap_q->consumer_index].skb = NULL;
+		pci_unmap_single(bnad->pcidev,
+				 pci_unmap_addr(&unmap_q->
+						unmap_array[unmap_q->
+							    consumer_index],
+						dma_addr),
+						rcb->rxq->buffer_size,
+						PCI_DMA_FROMDEVICE);
+		BNA_QE_INDX_ADD(unmap_q->consumer_index, 1, unmap_q->q_depth);
+
+		/* Should be more efficient ? Performance ? */
+		BNA_QE_INDX_ADD(rcb->consumer_index, 1, rcb->q_depth);
+
+		wis++;
+		if (likely(--wi_range))
+			next_cmpl = cmpl + 1;
+		else {
+			BNA_QE_INDX_ADD(ccb->producer_index, wis, ccb->q_depth);
+			wis = 0;
+			BNA_CQ_QPGE_PTR_GET(ccb->producer_index, ccb->sw_qpt,
+						next_cmpl, wi_range);
+			BUG_ON(!(wi_range <= ccb->q_depth));
+		}
+		prefetch(next_cmpl);
+
+		flags = ntohl(cmpl->flags);
+		if (unlikely
+		    (flags &
+		     (BNA_CQ_EF_MAC_ERROR | BNA_CQ_EF_FCS_ERROR |
+		      BNA_CQ_EF_TOO_LONG))) {
+			dev_kfree_skb_any(skb);
+			rcb->rxq->rx_packets_with_error++;
+			goto next;
+		}
+
+		skb_put(skb, ntohs(cmpl->length));
+		if (likely
+		    (bnad->rx_csum &&
+		     (((flags & BNA_CQ_EF_IPV4) &&
+		      (flags & BNA_CQ_EF_L3_CKSUM_OK)) ||
+		      (flags & BNA_CQ_EF_IPV6)) &&
+		      (flags & (BNA_CQ_EF_TCP | BNA_CQ_EF_UDP)) &&
+		      (flags & BNA_CQ_EF_L4_CKSUM_OK)))
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		else
+			skb->ip_summed = CHECKSUM_NONE;
+
+		rcb->rxq->rx_packets++;
+		rcb->rxq->rx_bytes += skb->len;
+		skb->protocol = eth_type_trans(skb, bnad->netdev);
+
+		if (bnad->vlan_grp && (flags & BNA_CQ_EF_VLAN)) {
+			struct bnad_rx_ctrl *rx_ctrl =
+				(struct bnad_rx_ctrl *)ccb->ctrl;
+			if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+				vlan_gro_receive(&rx_ctrl->napi, bnad->vlan_grp,
+						ntohs(cmpl->vlan_tag), skb);
+			else
+				vlan_hwaccel_receive_skb(skb,
+							 bnad->vlan_grp,
+							 ntohs(cmpl->vlan_tag));
+
+		} else { /* Not VLAN tagged/stripped */
+			struct bnad_rx_ctrl *rx_ctrl =
+				(struct bnad_rx_ctrl *)ccb->ctrl;
+			if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+				napi_gro_receive(&rx_ctrl->napi, skb);
+			else
+				netif_receive_skb(skb);
+		}
+
+next:
+		cmpl->valid = 0;
+		cmpl = next_cmpl;
+	}
+
+	BNA_QE_INDX_ADD(ccb->producer_index, wis, ccb->q_depth);
+
+	if (likely(ccb)) {
+		bna_ib_ack(ccb->i_dbell, packets);
+		bnad_refill_rxq(bnad, ccb->rcb[0]);
+		if (ccb->rcb[1])
+			bnad_refill_rxq(bnad, ccb->rcb[1]);
+	} else
+		bna_ib_ack(ccb->i_dbell, 0);
+
+	return packets;
+}
+
+static void
+bnad_disable_rx_irq(struct bnad *bnad, struct bna_ccb *ccb)
+{
+	bna_ib_coalescing_timer_set(ccb->i_dbell, 0);
+	bna_ib_ack(ccb->i_dbell, 0);
+}
+
+static void
+bnad_enable_rx_irq(struct bnad *bnad, struct bna_ccb *ccb)
+{
+	spin_lock_irq(&bnad->bna_lock); /* Because of polling context */
+	bnad_enable_rx_irq_unsafe(ccb);
+	spin_unlock_irq(&bnad->bna_lock);
+}
+
+static void
+bnad_netif_rx_schedule_poll(struct bnad *bnad, struct bna_ccb *ccb)
+{
+	struct bnad_rx_ctrl *rx_ctrl = (struct bnad_rx_ctrl *)(ccb->ctrl);
+	if (likely(napi_schedule_prep((&rx_ctrl->napi)))) {
+		bnad_disable_rx_irq(bnad, ccb);
+		__napi_schedule((&rx_ctrl->napi));
+	}
+	BNAD_UPDATE_CTR(bnad, netif_rx_schedule);
+}
+
+/* MSIX Rx Path Handler */
+static irqreturn_t
+bnad_msix_rx(int irq, void *data)
+{
+	struct bna_ccb *ccb = (struct bna_ccb *)data;
+	struct bnad *bnad = ccb->bnad;
+
+	bnad_netif_rx_schedule_poll(bnad, ccb);
+
+	return IRQ_HANDLED;
+}
+
+/* Interrupt handlers */
+
+/* Mbox Interrupt Handlers */
+static irqreturn_t
+bnad_msix_mbox_handler(int irq, void *data)
+{
+	u32 intr_status;
+	unsigned long  flags;
+	struct net_device *netdev = data;
+	struct bnad *bnad;
+
+	bnad = netdev_priv(netdev);
+
+	/* BNA_ISR_GET(bnad); Inc Ref count */
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+
+	bna_intr_status_get(&bnad->bna, intr_status);
+
+	if (BNA_IS_MBOX_ERR_INTR(intr_status))
+		bna_mbox_handler(&bnad->bna, intr_status);
+
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	/* BNAD_ISR_PUT(bnad); Dec Ref count */
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t
+bnad_isr(int irq, void *data)
+{
+	int i, j;
+	u32 intr_status;
+	unsigned long flags;
+	struct net_device *netdev = data;
+	struct bnad *bnad = netdev_priv(netdev);
+	struct bnad_rx_info *rx_info;
+	struct bnad_rx_ctrl *rx_ctrl;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+
+	bna_intr_status_get(&bnad->bna, intr_status);
+	if (!intr_status) {
+		spin_unlock_irqrestore(&bnad->bna_lock, flags);
+		return IRQ_NONE;
+	}
+
+	if (BNA_IS_MBOX_ERR_INTR(intr_status)) {
+		bna_mbox_handler(&bnad->bna, intr_status);
+		if (!BNA_IS_INTX_DATA_INTR(intr_status)) {
+			spin_unlock_irqrestore(&bnad->bna_lock, flags);
+			goto done;
+		}
+	}
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	/* Process data interrupts */
+	for (i = 0; i < bnad->num_rx; i++) {
+		rx_info = &bnad->rx_info[i];
+		if (!rx_info->rx)
+			continue;
+		for (j = 0; j < bnad->num_rxp_per_rx; j++) {
+			rx_ctrl = &rx_info->rx_ctrl[j];
+			if (rx_ctrl->ccb)
+				bnad_netif_rx_schedule_poll(bnad,
+							    rx_ctrl->ccb);
+		}
+	}
+done:
+	return IRQ_HANDLED;
+}
+
+/*
+ * Called in interrupt / callback context
+ * with bna_lock held, so cfg_flags access is OK
+ */
+static void
+bnad_enable_mbox_irq(struct bnad *bnad)
+{
+	int irq = BNAD_GET_MBOX_IRQ(bnad);
+
+	if (!(bnad->cfg_flags & BNAD_CF_MSIX))
+		return;
+
+	if (test_and_clear_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags))
+		enable_irq(irq);
+	BNAD_UPDATE_CTR(bnad, mbox_intr_enabled);
+}
+
+/*
+ * Called with bnad->bna_lock held b'cos of
+ * bnad->cfg_flags access.
+ */
+void
+bnad_disable_mbox_irq(struct bnad *bnad)
+{
+	int irq = BNAD_GET_MBOX_IRQ(bnad);
+
+	if (!(bnad->cfg_flags & BNAD_CF_MSIX))
+		return;
+
+	if (!test_and_set_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags))
+		disable_irq_nosync(irq);
+	BNAD_UPDATE_CTR(bnad, mbox_intr_disabled);
+}
+
+/* Control Path Handlers */
+
+/* Callbacks */
+void
+bnad_cb_device_enable_mbox_intr(struct bnad *bnad)
+{
+	bnad_enable_mbox_irq(bnad);
+}
+
+void
+bnad_cb_device_disable_mbox_intr(struct bnad *bnad)
+{
+	bnad_disable_mbox_irq(bnad);
+}
+
+void
+bnad_cb_device_enabled(struct bnad *bnad, enum bna_cb_status status)
+{
+	complete(&bnad->bnad_completions.ioc_comp);
+	bnad->bnad_completions.ioc_comp_status = status;
+}
+
+void
+bnad_cb_device_disabled(struct bnad *bnad, enum bna_cb_status status)
+{
+	complete(&bnad->bnad_completions.ioc_comp);
+	bnad->bnad_completions.ioc_comp_status = status;
+}
+
+static void
+bnad_cb_port_disabled(void *arg, enum bna_cb_status status)
+{
+	struct bnad *bnad = (struct bnad *)arg;
+
+	complete(&bnad->bnad_completions.port_comp);
+
+	netif_carrier_off(bnad->netdev);
+}
+
+void
+bnad_cb_port_link_status(struct bnad *bnad,
+			enum bna_link_status link_status)
+{
+	bool link_up = 0;
+
+	link_up = (link_status == BNA_LINK_UP) || (link_status == BNA_CEE_UP);
+
+	if (link_status == BNA_CEE_UP) {
+		set_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags);
+		BNAD_UPDATE_CTR(bnad, cee_up);
+	} else
+		clear_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags);
+
+	if (link_up) {
+		if (!netif_carrier_ok(bnad->netdev)) {
+			printk(KERN_WARNING "bna: %s link up\n",
+				bnad->netdev->name);
+			netif_carrier_on(bnad->netdev);
+			BNAD_UPDATE_CTR(bnad, link_toggle);
+			if (test_bit(BNAD_RF_TX_STARTED, &bnad->run_flags)) {
+				/* Force an immediate Transmit Schedule */
+				printk(KERN_INFO "bna: %s TX_STARTED\n",
+					bnad->netdev->name);
+				netif_wake_queue(bnad->netdev);
+				BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
+			} else {
+				netif_stop_queue(bnad->netdev);
+				BNAD_UPDATE_CTR(bnad, netif_queue_stop);
+			}
+		}
+	} else {
+		if (netif_carrier_ok(bnad->netdev)) {
+			printk(KERN_WARNING "bna: %s link down\n",
+				bnad->netdev->name);
+			netif_carrier_off(bnad->netdev);
+			BNAD_UPDATE_CTR(bnad, link_toggle);
+		}
+	}
+}
+
+static void
+bnad_cb_tx_disabled(void *arg, struct bna_tx *tx,
+			enum bna_cb_status status)
+{
+	struct bnad *bnad = (struct bnad *)arg;
+
+	complete(&bnad->bnad_completions.tx_comp);
+}
+
+static void
+bnad_cb_tcb_setup(struct bnad *bnad, struct bna_tcb *tcb)
+{
+	struct bnad_tx_info *tx_info =
+			(struct bnad_tx_info *)tcb->txq->tx->priv;
+	struct bnad_unmap_q *unmap_q = tcb->unmap_q;
+
+	tx_info->tcb[tcb->id] = tcb;
+	unmap_q->producer_index = 0;
+	unmap_q->consumer_index = 0;
+	unmap_q->q_depth = BNAD_TX_UNMAPQ_DEPTH;
+}
+
+static void
+bnad_cb_tcb_destroy(struct bnad *bnad, struct bna_tcb *tcb)
+{
+	struct bnad_tx_info *tx_info =
+			(struct bnad_tx_info *)tcb->txq->tx->priv;
+
+	tx_info->tcb[tcb->id] = NULL;
+}
+
+static void
+bnad_cb_rcb_setup(struct bnad *bnad, struct bna_rcb *rcb)
+{
+	struct bnad_unmap_q *unmap_q = rcb->unmap_q;
+
+	unmap_q->producer_index = 0;
+	unmap_q->consumer_index = 0;
+	unmap_q->q_depth = BNAD_RX_UNMAPQ_DEPTH;
+}
+
+static void
+bnad_cb_ccb_setup(struct bnad *bnad, struct bna_ccb *ccb)
+{
+	struct bnad_rx_info *rx_info =
+			(struct bnad_rx_info *)ccb->cq->rx->priv;
+
+	rx_info->rx_ctrl[ccb->id].ccb = ccb;
+	ccb->ctrl = &rx_info->rx_ctrl[ccb->id];
+}
+
+static void
+bnad_cb_ccb_destroy(struct bnad *bnad, struct bna_ccb *ccb)
+{
+	struct bnad_rx_info *rx_info =
+			(struct bnad_rx_info *)ccb->cq->rx->priv;
+
+	rx_info->rx_ctrl[ccb->id].ccb = NULL;
+}
+
+static void
+bnad_cb_tx_stall(struct bnad *bnad, struct bna_tcb *tcb)
+{
+	struct bnad_tx_info *tx_info =
+			(struct bnad_tx_info *)tcb->txq->tx->priv;
+
+	if (tx_info != &bnad->tx_info[0])
+		return;
+
+	clear_bit(BNAD_RF_TX_STARTED, &bnad->run_flags);
+	netif_stop_queue(bnad->netdev);
+	printk(KERN_INFO "bna: %s TX_STOPPED\n", bnad->netdev->name);
+}
+
+static void
+bnad_cb_tx_resume(struct bnad *bnad, struct bna_tcb *tcb)
+{
+	if (test_and_set_bit(BNAD_RF_TX_STARTED, &bnad->run_flags))
+		return;
+
+	if (netif_carrier_ok(bnad->netdev)) {
+		printk(KERN_INFO "bna: %s TX_STARTED\n", bnad->netdev->name);
+		netif_wake_queue(bnad->netdev);
+		BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
+	}
+}
+
+static void
+bnad_cb_tx_cleanup(struct bnad *bnad, struct bna_tcb *tcb)
+{
+	struct bnad_unmap_q *unmap_q = tcb->unmap_q;
+
+	if (!tcb || (!tcb->unmap_q))
+		return;
+
+	if (!unmap_q->unmap_array)
+		return;
+
+	if (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags))
+		return;
+
+	bnad_free_all_txbufs(bnad, tcb);
+
+	unmap_q->producer_index = 0;
+	unmap_q->consumer_index = 0;
+
+	smp_mb__before_clear_bit();
+	clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
+}
+
+static void
+bnad_cb_rx_cleanup(struct bnad *bnad,
+			struct bna_ccb *ccb)
+{
+	bnad_cq_cmpl_init(bnad, ccb);
+
+	bnad_free_rxbufs(bnad, ccb->rcb[0]);
+	clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags);
+
+	if (ccb->rcb[1]) {
+		bnad_free_rxbufs(bnad, ccb->rcb[1]);
+		clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[1]->flags);
+	}
+}
+
+static void
+bnad_cb_rx_post(struct bnad *bnad, struct bna_rcb *rcb)
+{
+	struct bnad_unmap_q *unmap_q = rcb->unmap_q;
+
+	set_bit(BNAD_RXQ_STARTED, &rcb->flags);
+
+	/* Now allocate & post buffers for this RCB */
+	/* !!Allocation in callback context */
+	if (!test_and_set_bit(BNAD_RXQ_REFILL, &rcb->flags)) {
+		if (BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth)
+			 >> BNAD_RXQ_REFILL_THRESHOLD_SHIFT)
+			bnad_alloc_n_post_rxbufs(bnad, rcb);
+		smp_mb__before_clear_bit();
+		clear_bit(BNAD_RXQ_REFILL, &rcb->flags);
+	}
+}
+
+static void
+bnad_cb_rx_disabled(void *arg, struct bna_rx *rx,
+			enum bna_cb_status status)
+{
+	struct bnad *bnad = (struct bnad *)arg;
+
+	complete(&bnad->bnad_completions.rx_comp);
+}
+
+static void
+bnad_cb_rx_mcast_add(struct bnad *bnad, struct bna_rx *rx,
+				enum bna_cb_status status)
+{
+	bnad->bnad_completions.mcast_comp_status = status;
+	complete(&bnad->bnad_completions.mcast_comp);
+}
+
+void
+bnad_cb_stats_get(struct bnad *bnad, enum bna_cb_status status,
+		       struct bna_stats *stats)
+{
+	if (status == BNA_CB_SUCCESS)
+		BNAD_UPDATE_CTR(bnad, hw_stats_updates);
+
+	if (!netif_running(bnad->netdev) ||
+		!test_bit(BNAD_RF_STATS_TIMER_RUNNING, &bnad->run_flags))
+		return;
+
+	mod_timer(&bnad->stats_timer,
+		  jiffies + msecs_to_jiffies(BNAD_STATS_TIMER_FREQ));
+}
+
+void
+bnad_cb_stats_clr(struct bnad *bnad)
+{
+}
+
+/* Resource allocation, free functions */
+
+static void
+bnad_mem_free(struct bnad *bnad,
+	      struct bna_mem_info *mem_info)
+{
+	int i;
+	dma_addr_t dma_pa;
+
+	if (mem_info->mdl == NULL)
+		return;
+
+	for (i = 0; i < mem_info->num; i++) {
+		if (mem_info->mdl[i].kva != NULL) {
+			if (mem_info->mem_type == BNA_MEM_T_DMA) {
+				BNA_GET_DMA_ADDR(&(mem_info->mdl[i].dma),
+						dma_pa);
+				pci_free_consistent(bnad->pcidev,
+						mem_info->mdl[i].len,
+						mem_info->mdl[i].kva, dma_pa);
+			} else
+				kfree(mem_info->mdl[i].kva);
+		}
+	}
+	kfree(mem_info->mdl);
+	mem_info->mdl = NULL;
+}
+
+static int
+bnad_mem_alloc(struct bnad *bnad,
+	       struct bna_mem_info *mem_info)
+{
+	int i;
+	dma_addr_t dma_pa;
+
+	if ((mem_info->num == 0) || (mem_info->len == 0)) {
+		mem_info->mdl = NULL;
+		return 0;
+	}
+
+	mem_info->mdl = kcalloc(mem_info->num, sizeof(struct bna_mem_descr),
+				GFP_KERNEL);
+	if (mem_info->mdl == NULL)
+		return -ENOMEM;
+
+	if (mem_info->mem_type == BNA_MEM_T_DMA) {
+		for (i = 0; i < mem_info->num; i++) {
+			mem_info->mdl[i].len = mem_info->len;
+			mem_info->mdl[i].kva =
+				pci_alloc_consistent(bnad->pcidev,
+						mem_info->len, &dma_pa);
+
+			if (mem_info->mdl[i].kva == NULL)
+				goto err_return;
+
+			BNA_SET_DMA_ADDR(dma_pa,
+					 &(mem_info->mdl[i].dma));
+		}
+	} else {
+		for (i = 0; i < mem_info->num; i++) {
+			mem_info->mdl[i].len = mem_info->len;
+			mem_info->mdl[i].kva = kzalloc(mem_info->len,
+							GFP_KERNEL);
+			if (mem_info->mdl[i].kva == NULL)
+				goto err_return;
+		}
+	}
+
+	return 0;
+
+err_return:
+	bnad_mem_free(bnad, mem_info);
+	return -ENOMEM;
+}
+
+/* Free IRQ for Mailbox */
+static void
+bnad_mbox_irq_free(struct bnad *bnad,
+		   struct bna_intr_info *intr_info)
+{
+	int irq;
+	unsigned long flags;
+
+	if (intr_info->idl == NULL)
+		return;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+
+	bnad_disable_mbox_irq(bnad);
+
+	irq = BNAD_GET_MBOX_IRQ(bnad);
+	free_irq(irq, bnad->netdev);
+
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	kfree(intr_info->idl);
+}
+
+/*
+ * Allocates IRQ for Mailbox, but keep it disabled
+ * This will be enabled once we get the mbox enable callback
+ * from bna
+ */
+static int
+bnad_mbox_irq_alloc(struct bnad *bnad,
+		    struct bna_intr_info *intr_info)
+{
+	int 		err;
+	unsigned long 	flags;
+	u32	irq;
+	irq_handler_t 	irq_handler;
+
+	/* Mbox should use only 1 vector */
+
+	intr_info->idl = kzalloc(sizeof(*(intr_info->idl)), GFP_KERNEL);
+	if (!intr_info->idl)
+		return -ENOMEM;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	if (bnad->cfg_flags & BNAD_CF_MSIX) {
+		irq_handler = (irq_handler_t)bnad_msix_mbox_handler;
+		irq = bnad->msix_table[bnad->msix_num - 1].vector;
+		flags = 0;
+		intr_info->intr_type = BNA_INTR_T_MSIX;
+		intr_info->idl[0].vector = bnad->msix_num - 1;
+	} else {
+		irq_handler = (irq_handler_t)bnad_isr;
+		irq = bnad->pcidev->irq;
+		flags = IRQF_SHARED;
+		intr_info->intr_type = BNA_INTR_T_INTX;
+		/* intr_info->idl.vector = 0 ? */
+	}
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	sprintf(bnad->mbox_irq_name, "%s%d", BNAD_NAME, bna_id);
+
+	err = request_irq(irq, irq_handler, flags,
+			  bnad->mbox_irq_name, bnad->netdev);
+	if (err) {
+		kfree(intr_info->idl);
+		intr_info->idl = NULL;
+		return err;
+	}
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bnad_disable_mbox_irq(bnad);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+	return 0;
+}
+
+static void
+bnad_txrx_irq_free(struct bnad *bnad, struct bna_intr_info *intr_info)
+{
+	kfree(intr_info->idl);
+	intr_info->idl = NULL;
+}
+
+/* Allocates Interrupt Descriptor List for MSIX/INT-X vectors */
+static int
+bnad_txrx_irq_alloc(struct bnad *bnad, enum bnad_intr_source src,
+		    uint txrx_id, struct bna_intr_info *intr_info)
+{
+	int i, vector_start = 0;
+	u32 cfg_flags;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	cfg_flags = bnad->cfg_flags;
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	if (cfg_flags & BNAD_CF_MSIX) {
+		intr_info->intr_type = BNA_INTR_T_MSIX;
+		intr_info->idl = kcalloc(intr_info->num,
+					sizeof(struct bna_intr_descr),
+					GFP_KERNEL);
+		if (!intr_info->idl)
+			return -ENOMEM;
+
+		switch (src) {
+		case BNAD_INTR_TX:
+			vector_start = txrx_id;
+			break;
+
+		case BNAD_INTR_RX:
+			vector_start = bnad->num_tx * bnad->num_txq_per_tx +
+					txrx_id;
+			break;
+
+		default:
+			BUG();
+		}
+
+		for (i = 0; i < intr_info->num; i++)
+			intr_info->idl[i].vector = vector_start + i;
+	} else {
+		intr_info->intr_type = BNA_INTR_T_INTX;
+		intr_info->num = 1;
+		intr_info->idl = kcalloc(intr_info->num,
+					sizeof(struct bna_intr_descr),
+					GFP_KERNEL);
+		if (!intr_info->idl)
+			return -ENOMEM;
+
+		switch (src) {
+		case BNAD_INTR_TX:
+			intr_info->idl[0].vector = 0x1; /* Bit mask : Tx IB */
+			break;
+
+		case BNAD_INTR_RX:
+			intr_info->idl[0].vector = 0x2; /* Bit mask : Rx IB */
+			break;
+		}
+	}
+	return 0;
+}
+
+/**
+ * NOTE: Should be called for MSIX only
+ * Unregisters Tx MSIX vector(s) from the kernel
+ */
+static void
+bnad_tx_msix_unregister(struct bnad *bnad, struct bnad_tx_info *tx_info,
+			int num_txqs)
+{
+	int i;
+	int vector_num;
+
+	for (i = 0; i < num_txqs; i++) {
+		if (tx_info->tcb[i] == NULL)
+			continue;
+
+		vector_num = tx_info->tcb[i]->intr_vector;
+		free_irq(bnad->msix_table[vector_num].vector, tx_info->tcb[i]);
+	}
+}
+
+/**
+ * NOTE: Should be called for MSIX only
+ * Registers Tx MSIX vector(s) and ISR(s), cookie with the kernel
+ */
+static int
+bnad_tx_msix_register(struct bnad *bnad, struct bnad_tx_info *tx_info,
+			uint tx_id, int num_txqs)
+{
+	int i;
+	int err;
+	int vector_num;
+
+	for (i = 0; i < num_txqs; i++) {
+		vector_num = tx_info->tcb[i]->intr_vector;
+		sprintf(tx_info->tcb[i]->name, "%s TXQ %d", bnad->netdev->name,
+				tx_id + tx_info->tcb[i]->id);
+		err = request_irq(bnad->msix_table[vector_num].vector,
+				  (irq_handler_t)bnad_msix_tx, 0,
+				  tx_info->tcb[i]->name,
+				  tx_info->tcb[i]);
+		if (err)
+			goto err_return;
+	}
+
+	return 0;
+
+err_return:
+	if (i > 0)
+		bnad_tx_msix_unregister(bnad, tx_info, (i - 1));
+	return -1;
+}
+
+/**
+ * NOTE: Should be called for MSIX only
+ * Unregisters Rx MSIX vector(s) from the kernel
+ */
+static void
+bnad_rx_msix_unregister(struct bnad *bnad, struct bnad_rx_info *rx_info,
+			int num_rxps)
+{
+	int i;
+	int vector_num;
+
+	for (i = 0; i < num_rxps; i++) {
+		if (rx_info->rx_ctrl[i].ccb == NULL)
+			continue;
+
+		vector_num = rx_info->rx_ctrl[i].ccb->intr_vector;
+		free_irq(bnad->msix_table[vector_num].vector,
+			 rx_info->rx_ctrl[i].ccb);
+	}
+}
+
+/**
+ * NOTE: Should be called for MSIX only
+ * Registers Tx MSIX vector(s) and ISR(s), cookie with the kernel
+ */
+static int
+bnad_rx_msix_register(struct bnad *bnad, struct bnad_rx_info *rx_info,
+			uint rx_id, int num_rxps)
+{
+	int i;
+	int err;
+	int vector_num;
+
+	for (i = 0; i < num_rxps; i++) {
+		vector_num = rx_info->rx_ctrl[i].ccb->intr_vector;
+		sprintf(rx_info->rx_ctrl[i].ccb->name, "%s CQ %d",
+			bnad->netdev->name,
+			rx_id + rx_info->rx_ctrl[i].ccb->id);
+		err = request_irq(bnad->msix_table[vector_num].vector,
+				  (irq_handler_t)bnad_msix_rx, 0,
+				  rx_info->rx_ctrl[i].ccb->name,
+				  rx_info->rx_ctrl[i].ccb);
+		if (err)
+			goto err_return;
+	}
+
+	return 0;
+
+err_return:
+	if (i > 0)
+		bnad_rx_msix_unregister(bnad, rx_info, (i - 1));
+	return -1;
+}
+
+/* Free Tx object Resources */
+static void
+bnad_tx_res_free(struct bnad *bnad, struct bna_res_info *res_info)
+{
+	int i;
+
+	for (i = 0; i < BNA_TX_RES_T_MAX; i++) {
+		if (res_info[i].res_type == BNA_RES_T_MEM)
+			bnad_mem_free(bnad, &res_info[i].res_u.mem_info);
+		else if (res_info[i].res_type == BNA_RES_T_INTR)
+			bnad_txrx_irq_free(bnad, &res_info[i].res_u.intr_info);
+	}
+}
+
+/* Allocates memory and interrupt resources for Tx object */
+static int
+bnad_tx_res_alloc(struct bnad *bnad, struct bna_res_info *res_info,
+		  uint tx_id)
+{
+	int i, err = 0;
+
+	for (i = 0; i < BNA_TX_RES_T_MAX; i++) {
+		if (res_info[i].res_type == BNA_RES_T_MEM)
+			err = bnad_mem_alloc(bnad,
+					&res_info[i].res_u.mem_info);
+		else if (res_info[i].res_type == BNA_RES_T_INTR)
+			err = bnad_txrx_irq_alloc(bnad, BNAD_INTR_TX, tx_id,
+					&res_info[i].res_u.intr_info);
+		if (err)
+			goto err_return;
+	}
+	return 0;
+
+err_return:
+	bnad_tx_res_free(bnad, res_info);
+	return err;
+}
+
+/* Free Rx object Resources */
+static void
+bnad_rx_res_free(struct bnad *bnad, struct bna_res_info *res_info)
+{
+	int i;
+
+	for (i = 0; i < BNA_RX_RES_T_MAX; i++) {
+		if (res_info[i].res_type == BNA_RES_T_MEM)
+			bnad_mem_free(bnad, &res_info[i].res_u.mem_info);
+		else if (res_info[i].res_type == BNA_RES_T_INTR)
+			bnad_txrx_irq_free(bnad, &res_info[i].res_u.intr_info);
+	}
+}
+
+/* Allocates memory and interrupt resources for Rx object */
+static int
+bnad_rx_res_alloc(struct bnad *bnad, struct bna_res_info *res_info,
+		  uint rx_id)
+{
+	int i, err = 0;
+
+	/* All memory needs to be allocated before setup_ccbs */
+	for (i = 0; i < BNA_RX_RES_T_MAX; i++) {
+		if (res_info[i].res_type == BNA_RES_T_MEM)
+			err = bnad_mem_alloc(bnad,
+					&res_info[i].res_u.mem_info);
+		else if (res_info[i].res_type == BNA_RES_T_INTR)
+			err = bnad_txrx_irq_alloc(bnad, BNAD_INTR_RX, rx_id,
+					&res_info[i].res_u.intr_info);
+		if (err)
+			goto err_return;
+	}
+	return 0;
+
+err_return:
+	bnad_rx_res_free(bnad, res_info);
+	return err;
+}
+
+/* Timer callbacks */
+/* a) IOC timer */
+static void
+bnad_ioc_timeout(unsigned long data)
+{
+	struct bnad *bnad = (struct bnad *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bfa_ioc_timeout((void *) &bnad->bna.device.ioc);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+static void
+bnad_ioc_hb_check(unsigned long data)
+{
+	struct bnad *bnad = (struct bnad *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bfa_ioc_hb_check((void *) &bnad->bna.device.ioc);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+static void
+bnad_ioc_sem_timeout(unsigned long data)
+{
+	struct bnad *bnad = (struct bnad *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bfa_ioc_sem_timeout((void *) &bnad->bna.device.ioc);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+/*
+ * All timer routines use bnad->bna_lock to protect against
+ * the following race, which may occur in case of no locking:
+ * 	Time	CPU m  		CPU n
+ *	0       1 = test_bit
+ *	1			clear_bit
+ *	2			del_timer_sync
+ *	3	mod_timer
+ */
+
+/* b) Dynamic Interrupt Moderation Timer */
+static void
+bnad_dim_timeout(unsigned long data)
+{
+	struct bnad *bnad = (struct bnad *)data;
+	struct bnad_rx_info *rx_info;
+	struct bnad_rx_ctrl *rx_ctrl;
+	int i, j;
+	unsigned long flags;
+
+	if (!netif_carrier_ok(bnad->netdev))
+		return;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	for (i = 0; i < bnad->num_rx; i++) {
+		rx_info = &bnad->rx_info[i];
+		if (!rx_info->rx)
+			continue;
+		for (j = 0; j < bnad->num_rxp_per_rx; j++) {
+			rx_ctrl = &rx_info->rx_ctrl[j];
+			if (!rx_ctrl->ccb)
+				continue;
+			bna_rx_dim_update(rx_ctrl->ccb);
+		}
+	}
+
+	/* Check for BNAD_CF_DIM_ENABLED, does not eleminate a race */
+	if (test_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags))
+		mod_timer(&bnad->dim_timer,
+			  jiffies + msecs_to_jiffies(BNAD_DIM_TIMER_FREQ));
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+/* c)  Statistics Timer */
+static void
+bnad_stats_timeout(unsigned long data)
+{
+	struct bnad *bnad = (struct bnad *)data;
+	unsigned long flags;
+
+	if (!netif_running(bnad->netdev) ||
+		!test_bit(BNAD_RF_STATS_TIMER_RUNNING, &bnad->run_flags))
+		return;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_stats_get(&bnad->bna);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+/*
+ * Set up timer for DIM
+ * Called with bnad->bna_lock held
+ */
+void
+bnad_dim_timer_start(struct bnad *bnad)
+{
+	if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED &&
+	    !test_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags)) {
+		setup_timer(&bnad->dim_timer, bnad_dim_timeout,
+			    (unsigned long)bnad);
+		set_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags);
+		mod_timer(&bnad->dim_timer,
+			  jiffies + msecs_to_jiffies(BNAD_DIM_TIMER_FREQ));
+	}
+}
+
+#if 0
+/*
+ * Stops the DIM timer
+ * Called with bnad->bna_lock held
+ */
+void
+bnad_dim_timer_stop(struct bnad *bnad)
+{
+	int to_del = 0;
+	unsigned long flags = 0;
+
+	if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED &&
+	    test_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags)) {
+		clear_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags);
+		to_del = 1;
+	}
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+	if (to_del)
+		del_timer_sync(&bnad->dim_timer);
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+}
+#endif
+
+/*
+ * Set up timer for statistics
+ * Called with mutex_lock(&bnad->conf_mutex) held
+ */
+static void
+bnad_stats_timer_start(struct bnad *bnad)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	if (!test_and_set_bit(BNAD_RF_STATS_TIMER_RUNNING, &bnad->run_flags)) {
+		setup_timer(&bnad->stats_timer, bnad_stats_timeout,
+			    (unsigned long)bnad);
+		mod_timer(&bnad->stats_timer,
+			  jiffies + msecs_to_jiffies(BNAD_STATS_TIMER_FREQ));
+	}
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+}
+
+/*
+ * Stops the stats timer
+ * Called with mutex_lock(&bnad->conf_mutex) held
+ */
+static void
+bnad_stats_timer_stop(struct bnad *bnad)
+{
+	int to_del = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	if (test_and_clear_bit(BNAD_RF_STATS_TIMER_RUNNING, &bnad->run_flags))
+		to_del = 1;
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+	if (to_del)
+		del_timer_sync(&bnad->stats_timer);
+}
+
+/* Utilities */
+
+static void
+bnad_netdev_mc_list_get(struct net_device *netdev, u8 *mc_list)
+{
+	int i = 1; /* Index 0 has broadcast address */
+	struct netdev_hw_addr *mc_addr;
+
+	netdev_for_each_mc_addr(mc_addr, netdev) {
+		memcpy(&mc_list[i * ETH_ALEN], &mc_addr->addr[0],
+							ETH_ALEN);
+		i++;
+	}
+}
+
+static int
+bnad_napi_poll_rx(struct napi_struct *napi, int budget)
+{
+	struct bnad_rx_ctrl *rx_ctrl =
+		container_of(napi, struct bnad_rx_ctrl, napi);
+	struct bna_ccb *ccb;
+	struct bnad *bnad;
+	int rcvd = 0;
+
+	ccb = rx_ctrl->ccb;
+
+	bnad = ccb->bnad;
+
+	if (!netif_carrier_ok(bnad->netdev))
+		goto poll_exit;
+
+	rcvd = bnad_poll_cq(bnad, ccb, budget);
+	if (rcvd == budget)
+		return rcvd;
+
+poll_exit:
+	napi_complete((napi));
+
+	BNAD_UPDATE_CTR(bnad, netif_rx_complete);
+
+	bnad_enable_rx_irq(bnad, ccb);
+	return rcvd;
+}
+
+static int
+bnad_napi_poll_txrx(struct napi_struct *napi, int budget)
+{
+	struct bnad_rx_ctrl *rx_ctrl =
+		container_of(napi, struct bnad_rx_ctrl, napi);
+	struct bna_ccb *ccb;
+	struct bnad *bnad;
+	int 			rcvd = 0;
+	int			i, j;
+
+	ccb = rx_ctrl->ccb;
+
+	bnad = ccb->bnad;
+
+	if (!netif_carrier_ok(bnad->netdev))
+		goto poll_exit;
+
+	/* Handle Tx Completions, if any */
+	for (i = 0; i < bnad->num_tx; i++) {
+		for (j = 0; j < bnad->num_txq_per_tx; j++)
+			bnad_tx(bnad, bnad->tx_info[i].tcb[j]);
+	}
+
+	/* Handle Rx Completions */
+	rcvd = bnad_poll_cq(bnad, ccb, budget);
+	if (rcvd == budget)
+		return rcvd;
+poll_exit:
+	napi_complete((napi));
+
+	BNAD_UPDATE_CTR(bnad, netif_rx_complete);
+
+	bnad_enable_txrx_irqs(bnad);
+	return rcvd;
+}
+
+static void
+bnad_napi_enable(struct bnad *bnad, u32 rx_id)
+{
+	int (*napi_poll) (struct napi_struct *, int);
+	struct bnad_rx_ctrl *rx_ctrl;
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	if (bnad->cfg_flags & BNAD_CF_MSIX)
+		napi_poll = bnad_napi_poll_rx;
+	else
+		napi_poll = bnad_napi_poll_txrx;
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	/* Initialize & enable NAPI */
+	for (i = 0; i <	bnad->num_rxp_per_rx; i++) {
+		rx_ctrl = &bnad->rx_info[rx_id].rx_ctrl[i];
+		netif_napi_add(bnad->netdev, &rx_ctrl->napi,
+			       napi_poll, 64);
+		napi_enable(&rx_ctrl->napi);
+	}
+}
+
+static void
+bnad_napi_disable(struct bnad *bnad, u32 rx_id)
+{
+	int i;
+
+	/* First disable and then clean up */
+	for (i = 0; i < bnad->num_rxp_per_rx; i++) {
+		napi_disable(&bnad->rx_info[rx_id].rx_ctrl[i].napi);
+		netif_napi_del(&bnad->rx_info[rx_id].rx_ctrl[i].napi);
+	}
+}
+
+/* Should be held with conf_lock held */
+void
+bnad_cleanup_tx(struct bnad *bnad, uint tx_id)
+{
+	struct bnad_tx_info *tx_info = &bnad->tx_info[tx_id];
+	struct bna_res_info *res_info = &bnad->tx_res_info[tx_id].res_info[0];
+	unsigned long flags;
+
+	if (!tx_info->tx)
+		return;
+
+	init_completion(&bnad->bnad_completions.tx_comp);
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_tx_disable(tx_info->tx, BNA_HARD_CLEANUP, bnad_cb_tx_disabled);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+	wait_for_completion(&bnad->bnad_completions.tx_comp);
+
+	if (tx_info->tcb[0]->intr_type == BNA_INTR_T_MSIX)
+		bnad_tx_msix_unregister(bnad, tx_info,
+			bnad->num_txq_per_tx);
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_tx_destroy(tx_info->tx);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	tx_info->tx = NULL;
+
+	if (0 == tx_id)
+		tasklet_kill(&bnad->tx_free_tasklet);
+
+	bnad_tx_res_free(bnad, res_info);
+}
+
+/* Should be held with conf_lock held */
+int
+bnad_setup_tx(struct bnad *bnad, uint tx_id)
+{
+	int err;
+	struct bnad_tx_info *tx_info = &bnad->tx_info[tx_id];
+	struct bna_res_info *res_info = &bnad->tx_res_info[tx_id].res_info[0];
+	struct bna_intr_info *intr_info =
+			&res_info[BNA_TX_RES_INTR_T_TXCMPL].res_u.intr_info;
+	struct bna_tx_config *tx_config = &bnad->tx_config[tx_id];
+	struct bna_tx_event_cbfn tx_cbfn;
+	struct bna_tx *tx;
+	unsigned long flags;
+
+	/* Initialize the Tx object configuration */
+	tx_config->num_txq = bnad->num_txq_per_tx;
+	tx_config->txq_depth = bnad->txq_depth;
+	tx_config->tx_type = BNA_TX_T_REGULAR;
+
+	/* Initialize the tx event handlers */
+	tx_cbfn.tcb_setup_cbfn = bnad_cb_tcb_setup;
+	tx_cbfn.tcb_destroy_cbfn = bnad_cb_tcb_destroy;
+	tx_cbfn.tx_stall_cbfn = bnad_cb_tx_stall;
+	tx_cbfn.tx_resume_cbfn = bnad_cb_tx_resume;
+	tx_cbfn.tx_cleanup_cbfn = bnad_cb_tx_cleanup;
+
+	/* Get BNA's resource requirement for one tx object */
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_tx_res_req(bnad->num_txq_per_tx,
+		bnad->txq_depth, res_info);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	/* Fill Unmap Q memory requirements */
+	BNAD_FILL_UNMAPQ_MEM_REQ(
+			&res_info[BNA_TX_RES_MEM_T_UNMAPQ],
+			bnad->num_txq_per_tx,
+			BNAD_TX_UNMAPQ_DEPTH);
+
+	/* Allocate resources */
+	err = bnad_tx_res_alloc(bnad, res_info, tx_id);
+	if (err)
+		return err;
+
+	/* Ask BNA to create one Tx object, supplying required resources */
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	tx = bna_tx_create(&bnad->bna, bnad, tx_config, &tx_cbfn, res_info,
+			tx_info);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+	if (!tx)
+		goto err_return;
+	tx_info->tx = tx;
+
+	/* Register ISR for the Tx object */
+	if (intr_info->intr_type == BNA_INTR_T_MSIX) {
+		err = bnad_tx_msix_register(bnad, tx_info,
+			tx_id, bnad->num_txq_per_tx);
+		if (err)
+			goto err_return;
+	}
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_tx_enable(tx);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	return 0;
+
+err_return:
+	bnad_tx_res_free(bnad, res_info);
+	return err;
+}
+
+/* Setup the rx config for bna_rx_create */
+/* bnad decides the configuration */
+static void
+bnad_init_rx_config(struct bnad *bnad, struct bna_rx_config *rx_config)
+{
+	rx_config->rx_type = BNA_RX_T_REGULAR;
+	rx_config->num_paths = bnad->num_rxp_per_rx;
+
+	if (bnad->num_rxp_per_rx > 1) {
+		rx_config->rss_status = BNA_STATUS_T_ENABLED;
+		rx_config->rss_config.hash_type =
+				(BFI_RSS_T_V4_TCP |
+				 BFI_RSS_T_V6_TCP |
+				 BFI_RSS_T_V4_IP  |
+				 BFI_RSS_T_V6_IP);
+		rx_config->rss_config.hash_mask =
+				bnad->num_rxp_per_rx - 1;
+		get_random_bytes(rx_config->rss_config.toeplitz_hash_key,
+			sizeof(rx_config->rss_config.toeplitz_hash_key));
+	} else {
+		rx_config->rss_status = BNA_STATUS_T_DISABLED;
+		memset(&rx_config->rss_config, 0,
+		       sizeof(rx_config->rss_config));
+	}
+	rx_config->rxp_type = BNA_RXP_SLR;
+	rx_config->q_depth = bnad->rxq_depth;
+
+	rx_config->small_buff_size = BFI_SMALL_RXBUF_SIZE;
+
+	rx_config->vlan_strip_status = BNA_STATUS_T_ENABLED;
+}
+
+/* Called with mutex_lock(&bnad->conf_mutex) held */
+void
+bnad_cleanup_rx(struct bnad *bnad, uint rx_id)
+{
+	struct bnad_rx_info *rx_info = &bnad->rx_info[rx_id];
+	struct bna_rx_config *rx_config = &bnad->rx_config[rx_id];
+	struct bna_res_info *res_info = &bnad->rx_res_info[rx_id].res_info[0];
+	unsigned long flags;
+	int dim_timer_del = 0;
+
+	if (!rx_info->rx)
+		return;
+
+	if (0 == rx_id) {
+		spin_lock_irqsave(&bnad->bna_lock, flags);
+		dim_timer_del = bnad_dim_timer_running(bnad);
+		if (dim_timer_del)
+			clear_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags);
+		spin_unlock_irqrestore(&bnad->bna_lock, flags);
+		if (dim_timer_del)
+			del_timer_sync(&bnad->dim_timer);
+	}
+
+	bnad_napi_disable(bnad, rx_id);
+
+	init_completion(&bnad->bnad_completions.rx_comp);
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_rx_disable(rx_info->rx, BNA_HARD_CLEANUP, bnad_cb_rx_disabled);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+	wait_for_completion(&bnad->bnad_completions.rx_comp);
+
+	if (rx_info->rx_ctrl[0].ccb->intr_type == BNA_INTR_T_MSIX)
+		bnad_rx_msix_unregister(bnad, rx_info, rx_config->num_paths);
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_rx_destroy(rx_info->rx);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	rx_info->rx = NULL;
+
+	bnad_rx_res_free(bnad, res_info);
+}
+
+/* Called with mutex_lock(&bnad->conf_mutex) held */
+int
+bnad_setup_rx(struct bnad *bnad, uint rx_id)
+{
+	int err;
+	struct bnad_rx_info *rx_info = &bnad->rx_info[rx_id];
+	struct bna_res_info *res_info = &bnad->rx_res_info[rx_id].res_info[0];
+	struct bna_intr_info *intr_info =
+			&res_info[BNA_RX_RES_T_INTR].res_u.intr_info;
+	struct bna_rx_config *rx_config = &bnad->rx_config[rx_id];
+	struct bna_rx_event_cbfn rx_cbfn;
+	struct bna_rx *rx;
+	unsigned long flags;
+
+	/* Initialize the Rx object configuration */
+	bnad_init_rx_config(bnad, rx_config);
+
+	/* Initialize the Rx event handlers */
+	rx_cbfn.rcb_setup_cbfn = bnad_cb_rcb_setup;
+	rx_cbfn.rcb_destroy_cbfn = NULL;
+	rx_cbfn.ccb_setup_cbfn = bnad_cb_ccb_setup;
+	rx_cbfn.ccb_destroy_cbfn = bnad_cb_ccb_destroy;
+	rx_cbfn.rx_cleanup_cbfn = bnad_cb_rx_cleanup;
+	rx_cbfn.rx_post_cbfn = bnad_cb_rx_post;
+
+	/* Get BNA's resource requirement for one Rx object */
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_rx_res_req(rx_config, res_info);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	/* Fill Unmap Q memory requirements */
+	BNAD_FILL_UNMAPQ_MEM_REQ(
+			&res_info[BNA_RX_RES_MEM_T_UNMAPQ],
+			rx_config->num_paths +
+			((rx_config->rxp_type == BNA_RXP_SINGLE) ? 0 :
+				rx_config->num_paths), BNAD_RX_UNMAPQ_DEPTH);
+
+	/* Allocate resource */
+	err = bnad_rx_res_alloc(bnad, res_info, rx_id);
+	if (err)
+		return err;
+
+	/* Ask BNA to create one Rx object, supplying required resources */
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	rx = bna_rx_create(&bnad->bna, bnad, rx_config, &rx_cbfn, res_info,
+			rx_info);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+	if (!rx)
+		goto err_return;
+	rx_info->rx = rx;
+
+	/* Register ISR for the Rx object */
+	if (intr_info->intr_type == BNA_INTR_T_MSIX) {
+		err = bnad_rx_msix_register(bnad, rx_info, rx_id,
+						rx_config->num_paths);
+		if (err)
+			goto err_return;
+	}
+
+	/* Enable NAPI */
+	bnad_napi_enable(bnad, rx_id);
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	if (0 == rx_id) {
+		/* Set up Dynamic Interrupt Moderation Vector */
+		if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED)
+			bna_rx_dim_reconfig(&bnad->bna, bna_napi_dim_vector);
+
+		/* Enable VLAN filtering only on the default Rx */
+		bna_rx_vlanfilter_enable(rx);
+
+		/* Start the DIM timer */
+		bnad_dim_timer_start(bnad);
+	}
+
+	bna_rx_enable(rx);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	return 0;
+
+err_return:
+	bnad_cleanup_rx(bnad, rx_id);
+	return err;
+}
+
+/* Called with conf_lock & bnad->bna_lock held */
+void
+bnad_tx_coalescing_timeo_set(struct bnad *bnad)
+{
+	struct bnad_tx_info *tx_info;
+
+	tx_info = &bnad->tx_info[0];
+	if (!tx_info->tx)
+		return;
+
+	bna_tx_coalescing_timeo_set(tx_info->tx, bnad->tx_coalescing_timeo);
+}
+
+/* Called with conf_lock & bnad->bna_lock held */
+void
+bnad_rx_coalescing_timeo_set(struct bnad *bnad)
+{
+	struct bnad_rx_info *rx_info;
+	int 	i;
+
+	for (i = 0; i < bnad->num_rx; i++) {
+		rx_info = &bnad->rx_info[i];
+		if (!rx_info->rx)
+			continue;
+		bna_rx_coalescing_timeo_set(rx_info->rx,
+				bnad->rx_coalescing_timeo);
+	}
+}
+
+/*
+ * Called with bnad->bna_lock held
+ */
+static int
+bnad_mac_addr_set_locked(struct bnad *bnad, u8 *mac_addr)
+{
+	int ret;
+
+	if (!is_valid_ether_addr(mac_addr))
+		return -EADDRNOTAVAIL;
+
+	/* If datapath is down, pretend everything went through */
+	if (!bnad->rx_info[0].rx)
+		return 0;
+
+	ret = bna_rx_ucast_set(bnad->rx_info[0].rx, mac_addr, NULL);
+	if (ret != BNA_CB_SUCCESS)
+		return -EADDRNOTAVAIL;
+
+	return 0;
+}
+
+/* Should be called with conf_lock held */
+static int
+bnad_enable_default_bcast(struct bnad *bnad)
+{
+	struct bnad_rx_info *rx_info = &bnad->rx_info[0];
+	int ret;
+	unsigned long flags;
+
+	init_completion(&bnad->bnad_completions.mcast_comp);
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	ret = bna_rx_mcast_add(rx_info->rx, (u8 *)bnad_bcast_addr,
+				bnad_cb_rx_mcast_add);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	if (ret == BNA_CB_SUCCESS)
+		wait_for_completion(&bnad->bnad_completions.mcast_comp);
+	else
+		return -ENODEV;
+
+	if (bnad->bnad_completions.mcast_comp_status != BNA_CB_SUCCESS)
+		return -ENODEV;
+
+	return 0;
+}
+
+/* Statistics utilities */
+void
+bnad_netdev_qstats_fill(struct bnad *bnad)
+{
+	struct net_device_stats *net_stats = &bnad->net_stats;
+	int i, j;
+
+	for (i = 0; i < bnad->num_rx; i++) {
+		for (j = 0; j < bnad->num_rxp_per_rx; j++) {
+			if (bnad->rx_info[i].rx_ctrl[j].ccb) {
+				net_stats->rx_packets += bnad->rx_info[i].
+				rx_ctrl[j].ccb->rcb[0]->rxq->rx_packets;
+				net_stats->rx_bytes += bnad->rx_info[i].
+					rx_ctrl[j].ccb->rcb[0]->rxq->rx_bytes;
+				if (bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] &&
+					bnad->rx_info[i].rx_ctrl[j].ccb->
+					rcb[1]->rxq) {
+					net_stats->rx_packets +=
+						bnad->rx_info[i].rx_ctrl[j].
+						ccb->rcb[1]->rxq->rx_packets;
+					net_stats->rx_bytes +=
+						bnad->rx_info[i].rx_ctrl[j].
+						ccb->rcb[1]->rxq->rx_bytes;
+				}
+			}
+		}
+	}
+	for (i = 0; i < bnad->num_tx; i++) {
+		for (j = 0; j < bnad->num_txq_per_tx; j++) {
+			if (bnad->tx_info[i].tcb[j]) {
+				net_stats->tx_packets +=
+				bnad->tx_info[i].tcb[j]->txq->tx_packets;
+				net_stats->tx_bytes +=
+					bnad->tx_info[i].tcb[j]->txq->tx_bytes;
+			}
+		}
+	}
+}
+
+/*
+ * Must be called with the bna_lock held.
+ */
+void
+bnad_netdev_hwstats_fill(struct bnad *bnad)
+{
+	struct bfi_ll_stats_mac *mac_stats;
+	struct net_device_stats *net_stats = &bnad->net_stats;
+	u64 bmap;
+	int i;
+
+	mac_stats = &bnad->stats.bna_stats->hw_stats->mac_stats;
+	net_stats->rx_errors =
+		mac_stats->rx_fcs_error + mac_stats->rx_alignment_error +
+		mac_stats->rx_frame_length_error + mac_stats->rx_code_error +
+		mac_stats->rx_undersize;
+	net_stats->tx_errors = mac_stats->tx_fcs_error +
+					mac_stats->tx_undersize;
+	net_stats->rx_dropped = mac_stats->rx_drop;
+	net_stats->tx_dropped = mac_stats->tx_drop;
+	net_stats->multicast = mac_stats->rx_multicast;
+	net_stats->collisions = mac_stats->tx_total_collision;
+
+	net_stats->rx_length_errors = mac_stats->rx_frame_length_error;
+
+	/* receive ring buffer overflow  ?? */
+
+	net_stats->rx_crc_errors = mac_stats->rx_fcs_error;
+	net_stats->rx_frame_errors = mac_stats->rx_alignment_error;
+	/* recv'r fifo overrun */
+	bmap = (u64)bnad->stats.bna_stats->rxf_bmap[0] |
+		((u64)bnad->stats.bna_stats->rxf_bmap[1] << 32);
+	for (i = 0; bmap && (i < BFI_LL_RXF_ID_MAX); i++) {
+		if (bmap & 1) {
+			net_stats->rx_fifo_errors =
+				bnad->stats.bna_stats->
+					hw_stats->rxf_stats[i].frame_drops;
+			break;
+		}
+		bmap >>= 1;
+	}
+}
+
+static void
+bnad_mbox_irq_sync(struct bnad *bnad)
+{
+	u32 irq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	if (bnad->cfg_flags & BNAD_CF_MSIX)
+		irq = bnad->msix_table[bnad->msix_num - 1].vector;
+	else
+		irq = bnad->pcidev->irq;
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	synchronize_irq(irq);
+}
+
+/* Utility used by bnad_start_xmit, for doing TSO */
+static int
+bnad_tso_prepare(struct bnad *bnad, struct sk_buff *skb)
+{
+	int err;
+
+	/* SKB_GSO_TCPV4 and SKB_GSO_TCPV6 is defined since 2.6.18. */
+	BUG_ON(!(skb_shinfo(skb)->gso_type == SKB_GSO_TCPV4 ||
+		   skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6));
+	if (skb_header_cloned(skb)) {
+		err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+		if (err) {
+			BNAD_UPDATE_CTR(bnad, tso_err);
+			return err;
+		}
+	}
+
+	/*
+	 * For TSO, the TCP checksum field is seeded with pseudo-header sum
+	 * excluding the length field.
+	 */
+	if (skb->protocol == htons(ETH_P_IP)) {
+		struct iphdr *iph = ip_hdr(skb);
+
+		/* Do we really need these? */
+		iph->tot_len = 0;
+		iph->check = 0;
+
+		tcp_hdr(skb)->check =
+			~csum_tcpudp_magic(iph->saddr, iph->daddr, 0,
+					   IPPROTO_TCP, 0);
+		BNAD_UPDATE_CTR(bnad, tso4);
+	} else {
+		struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+
+		BUG_ON(!(skb->protocol == htons(ETH_P_IPV6)));
+		ipv6h->payload_len = 0;
+		tcp_hdr(skb)->check =
+			~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, 0,
+					 IPPROTO_TCP, 0);
+		BNAD_UPDATE_CTR(bnad, tso6);
+	}
+
+	return 0;
+}
+
+/*
+ * Initialize Q numbers depending on Rx Paths
+ * Called with bnad->bna_lock held, because of cfg_flags
+ * access.
+ */
+static void
+bnad_q_num_init(struct bnad *bnad)
+{
+	int rxps;
+
+	rxps = min((uint)num_online_cpus(),
+			(uint)(BNAD_MAX_RXS * BNAD_MAX_RXPS_PER_RX));
+
+	if (!(bnad->cfg_flags & BNAD_CF_MSIX))
+		rxps = 1;	/* INTx */
+
+	bnad->num_rx = 1;
+	bnad->num_tx = 1;
+	bnad->num_rxp_per_rx = rxps;
+	bnad->num_txq_per_tx = BNAD_TXQ_NUM;
+}
+
+/*
+ * Adjusts the Q numbers, given a number of msix vectors
+ * Give preference to RSS as opposed to Tx priority Queues,
+ * in such a case, just use 1 Tx Q
+ * Called with bnad->bna_lock held b'cos of cfg_flags access
+ */
+static void
+bnad_q_num_adjust(struct bnad *bnad, int msix_vectors)
+{
+	bnad->num_txq_per_tx = 1;
+	if ((msix_vectors >= (bnad->num_tx * bnad->num_txq_per_tx)  +
+	     bnad_rxqs_per_cq + BNAD_MAILBOX_MSIX_VECTORS) &&
+	    (bnad->cfg_flags & BNAD_CF_MSIX)) {
+		bnad->num_rxp_per_rx = msix_vectors -
+			(bnad->num_tx * bnad->num_txq_per_tx) -
+			BNAD_MAILBOX_MSIX_VECTORS;
+	} else
+		bnad->num_rxp_per_rx = 1;
+}
+
+static void
+bnad_set_netdev_perm_addr(struct bnad *bnad)
+{
+	struct net_device *netdev = bnad->netdev;
+
+	memcpy(netdev->perm_addr, &bnad->perm_addr, netdev->addr_len);
+	if (is_zero_ether_addr(netdev->dev_addr))
+		memcpy(netdev->dev_addr, &bnad->perm_addr, netdev->addr_len);
+}
+
+/* Enable / disable device */
+static void
+bnad_device_disable(struct bnad *bnad)
+{
+	unsigned long flags;
+
+	init_completion(&bnad->bnad_completions.ioc_comp);
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_device_disable(&bnad->bna.device, BNA_HARD_CLEANUP);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	wait_for_completion(&bnad->bnad_completions.ioc_comp);
+
+}
+
+static int
+bnad_device_enable(struct bnad *bnad)
+{
+	int err = 0;
+	unsigned long flags;
+
+	init_completion(&bnad->bnad_completions.ioc_comp);
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_device_enable(&bnad->bna.device);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	wait_for_completion(&bnad->bnad_completions.ioc_comp);
+
+	if (bnad->bnad_completions.ioc_comp_status)
+		err = bnad->bnad_completions.ioc_comp_status;
+
+	return err;
+}
+
+/* Free BNA resources */
+static void
+bnad_res_free(struct bnad *bnad)
+{
+	int i;
+	struct bna_res_info *res_info = &bnad->res_info[0];
+
+	for (i = 0; i < BNA_RES_T_MAX; i++) {
+		if (res_info[i].res_type == BNA_RES_T_MEM)
+			bnad_mem_free(bnad, &res_info[i].res_u.mem_info);
+		else
+			bnad_mbox_irq_free(bnad, &res_info[i].res_u.intr_info);
+	}
+}
+
+/* Allocates memory and interrupt resources for BNA */
+static int
+bnad_res_alloc(struct bnad *bnad)
+{
+	int i, err;
+	struct bna_res_info *res_info = &bnad->res_info[0];
+
+	for (i = 0; i < BNA_RES_T_MAX; i++) {
+		if (res_info[i].res_type == BNA_RES_T_MEM)
+			err = bnad_mem_alloc(bnad, &res_info[i].res_u.mem_info);
+		else
+			err = bnad_mbox_irq_alloc(bnad,
+						  &res_info[i].res_u.intr_info);
+		if (err)
+			goto err_return;
+	}
+	return 0;
+
+err_return:
+	bnad_res_free(bnad);
+	return err;
+}
+
+/* Interrupt enable / disable */
+static void
+bnad_enable_msix(struct bnad *bnad)
+{
+	int i, ret;
+	u32 tot_msix_num;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	if (!(bnad->cfg_flags & BNAD_CF_MSIX)) {
+		spin_unlock_irqrestore(&bnad->bna_lock, flags);
+		return;
+	}
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	if (bnad->msix_table)
+		return;
+
+	tot_msix_num = bnad->msix_num + bnad->msix_diag_num;
+
+	bnad->msix_table =
+		kcalloc(tot_msix_num, sizeof(struct msix_entry), GFP_KERNEL);
+
+	if (!bnad->msix_table)
+		goto intx_mode;
+
+	for (i = 0; i < tot_msix_num; i++)
+		bnad->msix_table[i].entry = i;
+
+	ret = pci_enable_msix(bnad->pcidev, bnad->msix_table, tot_msix_num);
+	if (ret > 0) {
+		/* Not enough MSI-X vectors. */
+
+		spin_lock_irqsave(&bnad->bna_lock, flags);
+		/* ret = #of vectors that we got */
+		bnad_q_num_adjust(bnad, ret);
+		spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+		bnad->msix_num = (bnad->num_tx * bnad->num_txq_per_tx)
+			+ (bnad->num_rx
+			* bnad->num_rxp_per_rx) +
+			 BNAD_MAILBOX_MSIX_VECTORS;
+		tot_msix_num = bnad->msix_num + bnad->msix_diag_num;
+
+		/* Try once more with adjusted numbers */
+		/* If this fails, fall back to INTx */
+		ret = pci_enable_msix(bnad->pcidev, bnad->msix_table,
+				      tot_msix_num);
+		if (ret)
+			goto intx_mode;
+
+	} else if (ret < 0)
+		goto intx_mode;
+	return;
+
+intx_mode:
+
+	kfree(bnad->msix_table);
+	bnad->msix_table = NULL;
+	bnad->msix_num = 0;
+	bnad->msix_diag_num = 0;
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bnad->cfg_flags &= ~BNAD_CF_MSIX;
+	bnad_q_num_init(bnad);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+static void
+bnad_disable_msix(struct bnad *bnad)
+{
+	u32 cfg_flags;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	cfg_flags = bnad->cfg_flags;
+	if (bnad->cfg_flags & BNAD_CF_MSIX)
+		bnad->cfg_flags &= ~BNAD_CF_MSIX;
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	if (cfg_flags & BNAD_CF_MSIX) {
+		pci_disable_msix(bnad->pcidev);
+		kfree(bnad->msix_table);
+		bnad->msix_table = NULL;
+	}
+}
+
+/* Netdev entry points */
+static int
+bnad_open(struct net_device *netdev)
+{
+	int err;
+	struct bnad *bnad = netdev_priv(netdev);
+	struct bna_pause_config pause_config;
+	int mtu;
+	unsigned long flags;
+
+	mutex_lock(&bnad->conf_mutex);
+
+	/* Tx */
+	err = bnad_setup_tx(bnad, 0);
+	if (err)
+		goto err_return;
+
+	/* Rx */
+	err = bnad_setup_rx(bnad, 0);
+	if (err)
+		goto cleanup_tx;
+
+	/* Port */
+	pause_config.tx_pause = 0;
+	pause_config.rx_pause = 0;
+
+	mtu = ETH_HLEN + bnad->netdev->mtu + ETH_FCS_LEN;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_port_mtu_set(&bnad->bna.port, mtu, NULL);
+	bna_port_pause_config(&bnad->bna.port, &pause_config, NULL);
+	bna_port_enable(&bnad->bna.port);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	/* Enable broadcast */
+	bnad_enable_default_bcast(bnad);
+
+	/* Set the UCAST address */
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bnad_mac_addr_set_locked(bnad, netdev->dev_addr);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	/* Start the stats timer */
+	bnad_stats_timer_start(bnad);
+
+	mutex_unlock(&bnad->conf_mutex);
+
+	return 0;
+
+cleanup_tx:
+	bnad_cleanup_tx(bnad, 0);
+
+err_return:
+	mutex_unlock(&bnad->conf_mutex);
+	return err;
+}
+
+static int
+bnad_stop(struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	unsigned long flags;
+
+	mutex_lock(&bnad->conf_mutex);
+
+	/* Stop the stats timer */
+	bnad_stats_timer_stop(bnad);
+
+	init_completion(&bnad->bnad_completions.port_comp);
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_port_disable(&bnad->bna.port, BNA_HARD_CLEANUP,
+			bnad_cb_port_disabled);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	wait_for_completion(&bnad->bnad_completions.port_comp);
+
+	bnad_cleanup_tx(bnad, 0);
+	bnad_cleanup_rx(bnad, 0);
+
+	/* Synchronize mailbox IRQ */
+	bnad_mbox_irq_sync(bnad);
+
+	mutex_unlock(&bnad->conf_mutex);
+
+	return 0;
+}
+
+/* TX */
+/*
+ * bnad_start_xmit : Netdev entry point for Transmit
+ *		     Called under lock held by net_device
+ */
+static netdev_tx_t
+bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+
+	u16 		txq_prod, vlan_tag = 0;
+	u32 		unmap_prod, wis, wis_used, wi_range;
+	u32 		vectors, vect_id, i, acked;
+	u32		tx_id;
+	int 			err;
+
+	struct bnad_tx_info *tx_info;
+	struct bna_tcb *tcb;
+	struct bnad_unmap_q *unmap_q;
+	dma_addr_t 		dma_addr;
+	struct bna_txq_entry *txqent;
+	bna_txq_wi_ctrl_flag_t 	flags;
+
+	if (unlikely
+	    (skb->len <= ETH_HLEN || skb->len > BFI_TX_MAX_DATA_PER_PKT)) {
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	/*
+	 * Takes care of the Tx that is scheduled between clearing the flag
+	 * and the netif_stop_queue() call.
+	 */
+	if (unlikely(!test_bit(BNAD_RF_TX_STARTED, &bnad->run_flags))) {
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	tx_id = 0;
+
+	tx_info = &bnad->tx_info[tx_id];
+	tcb = tx_info->tcb[tx_id];
+	unmap_q = tcb->unmap_q;
+
+	vectors = 1 + skb_shinfo(skb)->nr_frags;
+	if (vectors > BFI_TX_MAX_VECTORS_PER_PKT) {
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+	wis = BNA_TXQ_WI_NEEDED(vectors);	/* 4 vectors per work item */
+	acked = 0;
+	if (unlikely
+	    (wis > BNA_QE_FREE_CNT(tcb, tcb->q_depth) ||
+	     vectors > BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth))) {
+		if ((u16) (*tcb->hw_consumer_index) !=
+		    tcb->consumer_index &&
+		    !test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags)) {
+			acked = bnad_free_txbufs(bnad, tcb);
+			bna_ib_ack(tcb->i_dbell, acked);
+			smp_mb__before_clear_bit();
+			clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
+		} else {
+			netif_stop_queue(netdev);
+			BNAD_UPDATE_CTR(bnad, netif_queue_stop);
+		}
+
+		smp_mb();
+		/*
+		 * Check again to deal with race condition between
+		 * netif_stop_queue here, and netif_wake_queue in
+		 * interrupt handler which is not inside netif tx lock.
+		 */
+		if (likely
+		    (wis > BNA_QE_FREE_CNT(tcb, tcb->q_depth) ||
+		     vectors > BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth))) {
+			BNAD_UPDATE_CTR(bnad, netif_queue_stop);
+			return NETDEV_TX_BUSY;
+		} else {
+			netif_wake_queue(netdev);
+			BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
+		}
+	}
+
+	unmap_prod = unmap_q->producer_index;
+	wis_used = 1;
+	vect_id = 0;
+	flags = 0;
+
+	txq_prod = tcb->producer_index;
+	BNA_TXQ_QPGE_PTR_GET(txq_prod, tcb->sw_qpt, txqent, wi_range);
+	BUG_ON(!(wi_range <= tcb->q_depth));
+	txqent->hdr.wi.reserved = 0;
+	txqent->hdr.wi.num_vectors = vectors;
+	txqent->hdr.wi.opcode =
+		htons((skb_is_gso(skb) ? BNA_TXQ_WI_SEND_LSO :
+		       BNA_TXQ_WI_SEND));
+
+	if (bnad->vlan_grp && vlan_tx_tag_present(skb)) {
+		vlan_tag = (u16) vlan_tx_tag_get(skb);
+		flags |= (BNA_TXQ_WI_CF_INS_PRIO | BNA_TXQ_WI_CF_INS_VLAN);
+	}
+	if (test_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags)) {
+		vlan_tag =
+			(tcb->priority & 0x7) << 13 | (vlan_tag & 0x1fff);
+		flags |= (BNA_TXQ_WI_CF_INS_PRIO | BNA_TXQ_WI_CF_INS_VLAN);
+	}
+
+	txqent->hdr.wi.vlan_tag = htons(vlan_tag);
+
+	if (skb_is_gso(skb)) {
+		err = bnad_tso_prepare(bnad, skb);
+		if (err) {
+			dev_kfree_skb(skb);
+			return NETDEV_TX_OK;
+		}
+		txqent->hdr.wi.lso_mss = htons(skb_is_gso(skb));
+		flags |= (BNA_TXQ_WI_CF_IP_CKSUM | BNA_TXQ_WI_CF_TCP_CKSUM);
+		txqent->hdr.wi.l4_hdr_size_n_offset =
+			htons(BNA_TXQ_WI_L4_HDR_N_OFFSET
+			      (tcp_hdrlen(skb) >> 2,
+			       skb_transport_offset(skb)));
+	} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		u8 proto = 0;
+
+		txqent->hdr.wi.lso_mss = 0;
+
+		if (skb->protocol == htons(ETH_P_IP))
+			proto = ip_hdr(skb)->protocol;
+		else if (skb->protocol == htons(ETH_P_IPV6)) {
+			/* nexthdr may not be TCP immediately. */
+			proto = ipv6_hdr(skb)->nexthdr;
+		}
+		if (proto == IPPROTO_TCP) {
+			flags |= BNA_TXQ_WI_CF_TCP_CKSUM;
+			txqent->hdr.wi.l4_hdr_size_n_offset =
+				htons(BNA_TXQ_WI_L4_HDR_N_OFFSET
+				      (0, skb_transport_offset(skb)));
+
+			BNAD_UPDATE_CTR(bnad, tcpcsum_offload);
+
+			BUG_ON(!(skb_headlen(skb) >=
+				skb_transport_offset(skb) + tcp_hdrlen(skb)));
+
+		} else if (proto == IPPROTO_UDP) {
+			flags |= BNA_TXQ_WI_CF_UDP_CKSUM;
+			txqent->hdr.wi.l4_hdr_size_n_offset =
+				htons(BNA_TXQ_WI_L4_HDR_N_OFFSET
+				      (0, skb_transport_offset(skb)));
+
+			BNAD_UPDATE_CTR(bnad, udpcsum_offload);
+
+			BUG_ON(!(skb_headlen(skb) >=
+				   skb_transport_offset(skb) +
+				   sizeof(struct udphdr)));
+		} else {
+			err = skb_checksum_help(skb);
+			BNAD_UPDATE_CTR(bnad, csum_help);
+			if (err) {
+				dev_kfree_skb(skb);
+				BNAD_UPDATE_CTR(bnad, csum_help_err);
+				return NETDEV_TX_OK;
+			}
+		}
+	} else {
+		txqent->hdr.wi.lso_mss = 0;
+		txqent->hdr.wi.l4_hdr_size_n_offset = 0;
+	}
+
+	txqent->hdr.wi.flags = htons(flags);
+
+	txqent->hdr.wi.frame_length = htonl(skb->len);
+
+	unmap_q->unmap_array[unmap_prod].skb = skb;
+	BUG_ON(!(skb_headlen(skb) <= BFI_TX_MAX_DATA_PER_VECTOR));
+	txqent->vector[vect_id].length = htons(skb_headlen(skb));
+	dma_addr = pci_map_single(bnad->pcidev, skb->data, skb_headlen(skb),
+		PCI_DMA_TODEVICE);
+	pci_unmap_addr_set(&unmap_q->unmap_array[unmap_prod], dma_addr,
+			   dma_addr);
+
+	BNA_SET_DMA_ADDR(dma_addr, &txqent->vector[vect_id].host_addr);
+	BNA_QE_INDX_ADD(unmap_prod, 1, unmap_q->q_depth);
+
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+		struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
+		u32		size = frag->size;
+
+		if (++vect_id == BFI_TX_MAX_VECTORS_PER_WI) {
+			vect_id = 0;
+			if (--wi_range)
+				txqent++;
+			else {
+				BNA_QE_INDX_ADD(txq_prod, wis_used,
+						tcb->q_depth);
+				wis_used = 0;
+				BNA_TXQ_QPGE_PTR_GET(txq_prod, tcb->sw_qpt,
+						     txqent, wi_range);
+				BUG_ON(!(wi_range <= tcb->q_depth));
+			}
+			wis_used++;
+			txqent->hdr.wi_ext.opcode = htons(BNA_TXQ_WI_EXTENSION);
+		}
+
+		BUG_ON(!(size <= BFI_TX_MAX_DATA_PER_VECTOR));
+		txqent->vector[vect_id].length = htons(size);
+		dma_addr =
+			pci_map_page(bnad->pcidev, frag->page,
+				     frag->page_offset, size,
+				     PCI_DMA_TODEVICE);
+		pci_unmap_addr_set(&unmap_q->unmap_array[unmap_prod], dma_addr,
+				   dma_addr);
+		BNA_SET_DMA_ADDR(dma_addr, &txqent->vector[vect_id].host_addr);
+		BNA_QE_INDX_ADD(unmap_prod, 1, unmap_q->q_depth);
+	}
+
+	unmap_q->producer_index = unmap_prod;
+	BNA_QE_INDX_ADD(txq_prod, wis_used, tcb->q_depth);
+	tcb->producer_index = txq_prod;
+
+	smp_mb();
+	bna_txq_prod_indx_doorbell(tcb);
+
+	if ((u16) (*tcb->hw_consumer_index) != tcb->consumer_index)
+		tasklet_schedule(&bnad->tx_free_tasklet);
+
+	return NETDEV_TX_OK;
+}
+
+/*
+ * Used spin_lock to synchronize reading of stats structures, which
+ * is written by BNA under the same lock.
+ */
+static struct net_device_stats *
+bnad_get_netdev_stats(struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+
+	memset(&bnad->net_stats, 0, sizeof(struct net_device_stats));
+
+	bnad_netdev_qstats_fill(bnad);
+	bnad_netdev_hwstats_fill(bnad);
+
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	return &bnad->net_stats;
+}
+
+static void
+bnad_set_rx_mode(struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	u32	new_mask, valid_mask;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+
+	new_mask = valid_mask = 0;
+
+	if (netdev->flags & IFF_PROMISC) {
+		if (!(bnad->cfg_flags & BNAD_CF_PROMISC)) {
+			new_mask = BNAD_RXMODE_PROMISC_DEFAULT;
+			valid_mask = BNAD_RXMODE_PROMISC_DEFAULT;
+			bnad->cfg_flags |= BNAD_CF_PROMISC;
+		}
+	} else {
+		if (bnad->cfg_flags & BNAD_CF_PROMISC) {
+			new_mask = ~BNAD_RXMODE_PROMISC_DEFAULT;
+			valid_mask = BNAD_RXMODE_PROMISC_DEFAULT;
+			bnad->cfg_flags &= ~BNAD_CF_PROMISC;
+		}
+	}
+
+	if (netdev->flags & IFF_ALLMULTI) {
+		if (!(bnad->cfg_flags & BNAD_CF_ALLMULTI)) {
+			new_mask |= BNA_RXMODE_ALLMULTI;
+			valid_mask |= BNA_RXMODE_ALLMULTI;
+			bnad->cfg_flags |= BNAD_CF_ALLMULTI;
+		}
+	} else {
+		if (bnad->cfg_flags & BNAD_CF_ALLMULTI) {
+			new_mask &= ~BNA_RXMODE_ALLMULTI;
+			valid_mask |= BNA_RXMODE_ALLMULTI;
+			bnad->cfg_flags &= ~BNAD_CF_ALLMULTI;
+		}
+	}
+
+	bna_rx_mode_set(bnad->rx_info[0].rx, new_mask, valid_mask, NULL);
+
+	if (!netdev_mc_empty(netdev)) {
+		u8 *mcaddr_list;
+		int mc_count = netdev_mc_count(netdev);
+
+		/* Index 0 holds the broadcast address */
+		mcaddr_list =
+			kzalloc((mc_count + 1) * ETH_ALEN,
+				GFP_ATOMIC);
+		if (!mcaddr_list)
+			return;
+
+		memcpy(&mcaddr_list[0], &bnad_bcast_addr[0], ETH_ALEN);
+
+		/* Copy rest of the MC addresses */
+		bnad_netdev_mc_list_get(netdev, mcaddr_list);
+
+		bna_rx_mcast_listset(bnad->rx_info[0].rx, mc_count + 1,
+					mcaddr_list, NULL);
+
+		/* Should we enable BNAD_CF_ALLMULTI for err != 0 ? */
+		kfree(mcaddr_list);
+	}
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+/*
+ * bna_lock is used to sync writes to netdev->addr
+ * conf_lock cannot be used since this call may be made
+ * in a non-blocking context.
+ */
+static int
+bnad_set_mac_address(struct net_device *netdev, void *mac_addr)
+{
+	int err;
+	struct bnad *bnad = netdev_priv(netdev);
+	struct sockaddr *sa = (struct sockaddr *)mac_addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+
+	err = bnad_mac_addr_set_locked(bnad, sa->sa_data);
+
+	if (!err)
+		memcpy(netdev->dev_addr, sa->sa_data, netdev->addr_len);
+
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	return err;
+}
+
+static int
+bnad_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	int mtu, err = 0;
+	unsigned long flags;
+
+	struct bnad *bnad = netdev_priv(netdev);
+
+	if (new_mtu + ETH_HLEN < ETH_ZLEN || new_mtu > BNAD_JUMBO_MTU)
+		return -EINVAL;
+
+	mutex_lock(&bnad->conf_mutex);
+
+	netdev->mtu = new_mtu;
+
+	mtu = ETH_HLEN + new_mtu + ETH_FCS_LEN;
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_port_mtu_set(&bnad->bna.port, mtu, NULL);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	mutex_unlock(&bnad->conf_mutex);
+	return err;
+}
+
+static void
+bnad_vlan_rx_register(struct net_device *netdev,
+				  struct vlan_group *vlan_grp)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+
+	mutex_lock(&bnad->conf_mutex);
+	bnad->vlan_grp = vlan_grp;
+	mutex_unlock(&bnad->conf_mutex);
+}
+
+static void
+bnad_vlan_rx_add_vid(struct net_device *netdev,
+				 unsigned short vid)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	unsigned long flags;
+
+	if (!bnad->rx_info[0].rx)
+		return;
+
+	mutex_lock(&bnad->conf_mutex);
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_rx_vlan_add(bnad->rx_info[0].rx, vid);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	mutex_unlock(&bnad->conf_mutex);
+}
+
+static void
+bnad_vlan_rx_kill_vid(struct net_device *netdev,
+				  unsigned short vid)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	unsigned long flags;
+
+	if (!bnad->rx_info[0].rx)
+		return;
+
+	mutex_lock(&bnad->conf_mutex);
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_rx_vlan_del(bnad->rx_info[0].rx, vid);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	mutex_unlock(&bnad->conf_mutex);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void
+bnad_netpoll(struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	struct bnad_rx_info *rx_info;
+	struct bnad_rx_ctrl *rx_ctrl;
+	u32 curr_mask;
+	int i, j;
+
+	if (!(bnad->cfg_flags & BNAD_CF_MSIX)) {
+		bna_intx_disable(&bnad->bna, curr_mask);
+		bnad_isr(bnad->pcidev->irq, netdev);
+		bna_intx_enable(&bnad->bna, curr_mask);
+	} else {
+		for (i = 0; i < bnad->num_rx; i++) {
+			rx_info = &bnad->rx_info[i];
+			if (!rx_info->rx)
+				continue;
+			for (j = 0; j < bnad->num_rxp_per_rx; j++) {
+				rx_ctrl = &rx_info->rx_ctrl[j];
+				if (rx_ctrl->ccb) {
+					bnad_disable_rx_irq(bnad,
+							    rx_ctrl->ccb);
+					bnad_netif_rx_schedule_poll(bnad,
+							    rx_ctrl->ccb);
+				}
+			}
+		}
+	}
+}
+#endif
+
+static const struct net_device_ops bnad_netdev_ops = {
+	.ndo_open		= bnad_open,
+	.ndo_stop		= bnad_stop,
+	.ndo_start_xmit		= bnad_start_xmit,
+	.ndo_get_stats		= bnad_get_netdev_stats,
+	.ndo_set_rx_mode	= bnad_set_rx_mode,
+	.ndo_set_multicast_list = bnad_set_rx_mode,
+	.ndo_validate_addr      = eth_validate_addr,
+	.ndo_set_mac_address    = bnad_set_mac_address,
+	.ndo_change_mtu		= bnad_change_mtu,
+	.ndo_vlan_rx_register   = bnad_vlan_rx_register,
+	.ndo_vlan_rx_add_vid    = bnad_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid   = bnad_vlan_rx_kill_vid,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller    = bnad_netpoll
+#endif
+};
+
+static void
+bnad_netdev_init(struct bnad *bnad, bool using_dac)
+{
+	struct net_device *netdev = bnad->netdev;
+
+	netdev->features |= NETIF_F_IPV6_CSUM;
+	netdev->features |= NETIF_F_TSO;
+	netdev->features |= NETIF_F_TSO6;
+
+	netdev->features |= NETIF_F_GRO;
+	printk(KERN_WARNING
+	       "bna: GRO enabled, using kernel stack GRO\n");
+
+	netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+
+	if (using_dac)
+		netdev->features |= NETIF_F_HIGHDMA;
+
+	netdev->features |=
+		NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
+		NETIF_F_HW_VLAN_FILTER;
+
+	netdev->vlan_features = netdev->features;
+	netdev->mem_start = bnad->mmio_start;
+	netdev->mem_end = bnad->mmio_start + bnad->mmio_len - 1;
+
+	netdev->netdev_ops = &bnad_netdev_ops;
+	bnad_set_ethtool_ops(netdev);
+}
+
+/*
+ * 1. Initialize the bnad structure
+ * 2. Setup netdev pointer in pci_dev
+ * 3. Initialze Tx free tasklet
+ * 4. Initialize no. of TxQ & CQs & MSIX vectors
+ */
+static int
+bnad_init(struct bnad *bnad,
+	  struct pci_dev *pdev, struct net_device *netdev)
+{
+	unsigned long flags;
+
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+	pci_set_drvdata(pdev, netdev);
+
+	bnad->netdev = netdev;
+	bnad->pcidev = pdev;
+	bnad->mmio_start = pci_resource_start(pdev, 0);
+	bnad->mmio_len = pci_resource_len(pdev, 0);
+	bnad->bar0 = ioremap_nocache(bnad->mmio_start, bnad->mmio_len);
+	if (!bnad->bar0) {
+		dev_err(&pdev->dev, "ioremap for bar0 failed\n");
+		pci_set_drvdata(pdev, NULL);
+		return -ENOMEM;
+	}
+	printk(KERN_INFO "bar0 mapped to %p, len %llu\n", bnad->bar0,
+	       (unsigned long long) bnad->mmio_len);
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	if (!bnad_msix_disable)
+		bnad->cfg_flags = BNAD_CF_MSIX;
+
+	bnad->cfg_flags |= BNAD_CF_DIM_ENABLED;
+
+	bnad_q_num_init(bnad);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	bnad->msix_num = (bnad->num_tx * bnad->num_txq_per_tx) +
+		(bnad->num_rx * bnad->num_rxp_per_rx) +
+			 BNAD_MAILBOX_MSIX_VECTORS;
+	bnad->msix_diag_num = 2;	/* 1 for Tx, 1 for Rx */
+
+	bnad->txq_depth = BNAD_TXQ_DEPTH;
+	bnad->rxq_depth = BNAD_RXQ_DEPTH;
+	bnad->rx_csum = true;
+
+	bnad->tx_coalescing_timeo = BFI_TX_COALESCING_TIMEO;
+	bnad->rx_coalescing_timeo = BFI_RX_COALESCING_TIMEO;
+
+	tasklet_init(&bnad->tx_free_tasklet, bnad_tx_free_tasklet,
+		     (unsigned long)bnad);
+
+	return 0;
+}
+
+/*
+ * Must be called after bnad_pci_uninit()
+ * so that iounmap() and pci_set_drvdata(NULL)
+ * happens only after PCI uninitialization.
+ */
+static void
+bnad_uninit(struct bnad *bnad)
+{
+	if (bnad->bar0)
+		iounmap(bnad->bar0);
+	pci_set_drvdata(bnad->pcidev, NULL);
+}
+
+/*
+ * Initialize locks
+	a) Per device mutes used for serializing configuration
+	   changes from OS interface
+	b) spin lock used to protect bna state machine
+ */
+static void
+bnad_lock_init(struct bnad *bnad)
+{
+	spin_lock_init(&bnad->bna_lock);
+	mutex_init(&bnad->conf_mutex);
+}
+
+static void
+bnad_lock_uninit(struct bnad *bnad)
+{
+	mutex_destroy(&bnad->conf_mutex);
+}
+
+/* PCI Initialization */
+static int
+bnad_pci_init(struct bnad *bnad,
+	      struct pci_dev *pdev, bool *using_dac)
+{
+	int err;
+
+	err = pci_enable_device(pdev);
+	if (err)
+		return err;
+	err = pci_request_regions(pdev, BNAD_NAME);
+	if (err)
+		goto disable_device;
+	if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
+	    !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
+		*using_dac = 1;
+	} else {
+		err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+		if (err) {
+			err = pci_set_consistent_dma_mask(pdev,
+						DMA_BIT_MASK(32));
+			if (err)
+				goto release_regions;
+		}
+		*using_dac = 0;
+	}
+	pci_set_master(pdev);
+	return 0;
+
+release_regions:
+	pci_release_regions(pdev);
+disable_device:
+	pci_disable_device(pdev);
+
+	return err;
+}
+
+static void
+bnad_pci_uninit(struct pci_dev *pdev)
+{
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+}
+
+static int __devinit
+bnad_pci_probe(struct pci_dev *pdev,
+		const struct pci_device_id *pcidev_id)
+{
+	bool 	using_dac;
+	int 	err;
+	struct bnad *bnad;
+	struct bna *bna;
+	struct net_device *netdev;
+	struct bfa_pcidev pcidev_info;
+	unsigned long flags;
+
+	printk(KERN_INFO "bnad_pci_probe : (0x%p, 0x%p) PCI Func : (%d)\n",
+	       pdev, pcidev_id, PCI_FUNC(pdev->devfn));
+
+	mutex_lock(&bnad_fwimg_mutex);
+	if (!cna_get_firmware_buf(pdev)) {
+		mutex_unlock(&bnad_fwimg_mutex);
+		printk(KERN_WARNING "Failed to load Firmware Image!\n");
+		return -ENODEV;
+	}
+	mutex_unlock(&bnad_fwimg_mutex);
+
+	/*
+	 * Allocates sizeof(struct net_device + struct bnad)
+	 * bnad = netdev->priv
+	 */
+	netdev = alloc_etherdev(sizeof(struct bnad));
+	if (!netdev) {
+		dev_err(&pdev->dev, "alloc_etherdev failed\n");
+		err = -ENOMEM;
+		return err;
+	}
+	bnad = netdev_priv(netdev);
+
+	bnad->ident.id = bna_id;
+
+	/*
+	 * PCI initialization
+	 * 	Output : using_dac = 1 for 64 bit DMA
+	 *		           = 0 for 32 bit DMA
+	 */
+	err = bnad_pci_init(bnad, pdev, &using_dac);
+	if (err)
+		goto free_netdev;
+
+	bnad_lock_init(bnad);
+	/*
+	 * Initialize bnad structure
+	 * Setup relation between pci_dev & netdev
+	 * Init Tx free tasklet
+	 */
+	err = bnad_init(bnad, pdev, netdev);
+	if (err)
+		goto pci_uninit;
+	/* Initialize netdev structure, set up ethtool ops */
+	bnad_netdev_init(bnad, using_dac);
+
+	bnad_enable_msix(bnad);
+
+	/* Get resource requirement form bna */
+	bna_res_req(&bnad->res_info[0]);
+
+	/* Allocate resources from bna */
+	err = bnad_res_alloc(bnad);
+	if (err)
+		goto free_netdev;
+
+	bna = &bnad->bna;
+
+	/* Setup pcidev_info for bna_init() */
+	pcidev_info.pci_slot = PCI_SLOT(bnad->pcidev->devfn);
+	pcidev_info.pci_func = PCI_FUNC(bnad->pcidev->devfn);
+	pcidev_info.device_id = bnad->pcidev->device;
+	pcidev_info.pci_bar_kva = bnad->bar0;
+
+	mutex_lock(&bnad->conf_mutex);
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_init(bna, bnad, &bnad->ident, &pcidev_info, &bnad->res_info[0]);
+
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	bnad->stats.bna_stats = &bna->stats;
+
+	/* Set up timers */
+	setup_timer(&bnad->bna.device.ioc.ioc_timer, bnad_ioc_timeout,
+				((unsigned long)bnad));
+	setup_timer(&bnad->bna.device.ioc.hb_timer, bnad_ioc_hb_check,
+				((unsigned long)bnad));
+	setup_timer(&bnad->bna.device.ioc.sem_timer, bnad_ioc_sem_timeout,
+				((unsigned long)bnad));
+
+	/* Now start the timer before calling IOC */
+	mod_timer(&bnad->bna.device.ioc.ioc_timer,
+		  jiffies + msecs_to_jiffies(BNA_IOC_TIMER_FREQ));
+
+	/*
+	 * Start the chip
+	 * Don't care even if err != 0, bna state machine will
+	 * deal with it
+	 */
+	err = bnad_device_enable(bnad);
+
+	/* Get the burnt-in mac */
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_port_mac_get(&bna->port, &bnad->perm_addr);
+	bnad_set_netdev_perm_addr(bnad);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	mutex_unlock(&bnad->conf_mutex);
+
+	/*
+	 * Make sure the link appears down to the stack
+	 */
+	netif_carrier_off(netdev);
+
+	/* Finally, reguister with net_device layer */
+	err = register_netdev(netdev);
+	if (err) {
+		printk(KERN_ERR "BNA[%d] : Registering with netdev failed\n",
+		       bnad->ident.id);
+		goto disable_device;
+	}
+
+	return 0;
+
+disable_device:
+	mutex_lock(&bnad->conf_mutex);
+	bnad_device_disable(bnad);
+	del_timer_sync(&bnad->bna.device.ioc.ioc_timer);
+	del_timer_sync(&bnad->bna.device.ioc.sem_timer);
+	del_timer_sync(&bnad->bna.device.ioc.hb_timer);
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_uninit(bna);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+	mutex_unlock(&bnad->conf_mutex);
+
+	bnad_res_free(bnad);
+	bnad_disable_msix(bnad);
+pci_uninit:
+	bnad_pci_uninit(pdev);
+	bnad_lock_uninit(bnad);
+	bnad_uninit(bnad);
+free_netdev:
+	free_netdev(netdev);
+	return err;
+}
+
+static void __devexit
+bnad_pci_remove(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct bnad *bnad;
+	struct bna *bna;
+	unsigned long flags;
+
+	if (!netdev)
+		return;
+
+	printk(KERN_INFO "%s bnad_pci_remove\n", netdev->name);
+	bnad = netdev_priv(netdev);
+	bna = &bnad->bna;
+
+	unregister_netdev(netdev);
+
+	mutex_lock(&bnad->conf_mutex);
+	bnad_device_disable(bnad);
+	del_timer_sync(&bnad->bna.device.ioc.ioc_timer);
+	del_timer_sync(&bnad->bna.device.ioc.sem_timer);
+	del_timer_sync(&bnad->bna.device.ioc.hb_timer);
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bna_uninit(bna);
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+	mutex_unlock(&bnad->conf_mutex);
+
+	bnad_res_free(bnad);
+	bnad_disable_msix(bnad);
+	bnad_pci_uninit(pdev);
+	bnad_lock_uninit(bnad);
+	bnad_uninit(bnad);
+	free_netdev(netdev);
+}
+
+const struct pci_device_id bnad_pci_id_table[] = {
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_BROCADE,
+			PCI_DEVICE_ID_BROCADE_CT),
+		.class = PCI_CLASS_NETWORK_ETHERNET << 8,
+		.class_mask =  0xffff00
+	}, {0,  }
+};
+
+MODULE_DEVICE_TABLE(pci, bnad_pci_id_table);
+
+static struct pci_driver bnad_pci_driver = {
+	.name = BNAD_NAME,
+	.id_table = bnad_pci_id_table,
+	.probe = bnad_pci_probe,
+	.remove = __devexit_p(bnad_pci_remove),
+};
+
+static int __init
+bnad_module_init(void)
+{
+	int err;
+
+	printk(KERN_INFO "Brocade 10G Ethernet driver\n");
+
+	bfa_ioc_auto_recover(bnad_ioc_auto_recover);
+
+	err = pci_register_driver(&bnad_pci_driver);
+	if (err < 0) {
+		printk(KERN_ERR "bna : PCI registration failed in module init "
+		       "(%d)\n", err);
+		return err;
+	}
+
+	return 0;
+}
+
+static void __exit
+bnad_module_exit(void)
+{
+	pci_unregister_driver(&bnad_pci_driver);
+
+	if (bfi_fw)
+		release_firmware(bfi_fw);
+}
+
+module_init(bnad_module_init);
+module_exit(bnad_module_exit);
+
+MODULE_AUTHOR("Brocade");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Brocade 10G PCIe Ethernet driver");
+MODULE_VERSION(BNAD_VERSION);
+MODULE_FIRMWARE(CNA_FW_FILE_CT);
diff -ruP net-next-2.6.35-rc1-orig/drivers/net/bna/bnad.h net-next-2.6.35-rc1-mod/drivers/net/bna/bnad.h
--- net-next-2.6.35-rc1-orig/drivers/net/bna/bnad.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.35-rc1-mod/drivers/net/bna/bnad.h	2010-08-10 12:23:09.184216000 -0700
@@ -0,0 +1,339 @@
+/*
+ * 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) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#ifndef __BNAD_H__
+#define __BNAD_H__
+
+#include <linux/rtnetlink.h>
+#include <linux/workqueue.h>
+#include <linux/ipv6.h>
+#include <linux/etherdevice.h>
+#include <linux/mutex.h>
+#include <linux/firmware.h>
+
+/* Fix for IA64 */
+#include <asm/checksum.h>
+#include <net/ip6_checksum.h>
+
+#include <net/ip.h>
+#include <net/tcp.h>
+
+#include "bna.h"
+
+#define BNAD_TXQ_DEPTH		2048
+#define BNAD_RXQ_DEPTH		2048
+
+#define BNAD_MAX_TXS		1
+#define BNAD_MAX_TXQ_PER_TX	8	/* 8 priority queues */
+#define BNAD_TXQ_NUM		1
+
+#define BNAD_MAX_RXS		1
+#define BNAD_MAX_RXPS_PER_RX	16
+
+/*
+ * Control structure pointed to ccb->ctrl, which
+ * determines the NAPI / LRO behavior CCB
+ * There is 1:1 corres. between ccb & ctrl
+ */
+struct bnad_rx_ctrl {
+	struct bna_ccb *ccb;
+	struct napi_struct	napi;
+};
+
+#define BNAD_RXMODE_PROMISC_DEFAULT	BNA_RXMODE_PROMISC
+
+#define BNAD_GET_TX_ID(_skb)	(0)
+
+/*
+ * GLOBAL #defines (CONSTANTS)
+ */
+#define BNAD_NAME			"bna"
+#define BNAD_NAME_LEN			64
+
+#define BNAD_VERSION			"2.3.2.0"
+
+#define BNAD_MAILBOX_MSIX_VECTORS	1
+
+#define BNAD_STATS_TIMER_FREQ		1000 	/* in msecs */
+#define BNAD_DIM_TIMER_FREQ		1000 	/* in msecs */
+
+#define BNAD_MAX_Q_DEPTH		0x10000
+#define BNAD_MIN_Q_DEPTH		0x200
+
+#define BNAD_JUMBO_MTU			9000
+
+#define BNAD_NETIF_WAKE_THRESHOLD	8
+
+#define BNAD_RXQ_REFILL_THRESHOLD_SHIFT	3
+
+/* Bit positions for tcb->flags */
+#define BNAD_TXQ_FREE_SENT		0
+
+/* Bit positions for rcb->flags */
+#define BNAD_RXQ_REFILL			0
+#define BNAD_RXQ_STARTED		1
+
+/*
+ * DATA STRUCTURES
+ */
+
+/* enums */
+enum bnad_intr_source {
+	BNAD_INTR_TX		= 1,
+	BNAD_INTR_RX		= 2
+};
+
+enum bnad_link_state {
+	BNAD_LS_DOWN		= 0,
+	BNAD_LS_UP 		= 1
+};
+
+struct bnad_completion {
+	struct completion 	ioc_comp;
+	struct completion 	ucast_comp;
+	struct completion	mcast_comp;
+	struct completion	tx_comp;
+	struct completion	rx_comp;
+	struct completion	stats_comp;
+	struct completion	port_comp;
+
+	u8			ioc_comp_status;
+	u8			ucast_comp_status;
+	u8			mcast_comp_status;
+	u8			tx_comp_status;
+	u8			rx_comp_status;
+	u8			stats_comp_status;
+	u8			port_comp_status;
+};
+
+/* Tx Rx Control Stats */
+struct bnad_drv_stats {
+	u64 		netif_queue_stop;
+	u64		netif_queue_wakeup;
+	u64		tso4;
+	u64		tso6;
+	u64		tso_err;
+	u64		tcpcsum_offload;
+	u64		udpcsum_offload;
+	u64		csum_help;
+	u64		csum_help_err;
+
+	u64		hw_stats_updates;
+	u64		netif_rx_schedule;
+	u64		netif_rx_complete;
+	u64		netif_rx_dropped;
+
+	u64		link_toggle;
+	u64		cee_up;
+
+	u64		rxp_info_alloc_failed;
+	u64		mbox_intr_disabled;
+	u64		mbox_intr_enabled;
+	u64		tx_unmap_q_alloc_failed;
+	u64		rx_unmap_q_alloc_failed;
+
+	u64		rxbuf_alloc_failed;
+};
+
+/* Complete driver stats */
+struct bnad_stats {
+	struct bnad_drv_stats drv_stats;
+	struct bna_stats *bna_stats;
+};
+
+/* Tx / Rx Resources */
+struct bnad_tx_res_info {
+	struct bna_res_info res_info[BNA_TX_RES_T_MAX];
+};
+
+struct bnad_rx_res_info {
+	struct bna_res_info res_info[BNA_RX_RES_T_MAX];
+};
+
+struct bnad_tx_info {
+	struct bna_tx *tx; /* 1:1 between tx_info & tx */
+	struct bna_tcb *tcb[BNAD_MAX_TXQ_PER_TX];
+} ____cacheline_aligned;
+
+struct bnad_rx_info {
+	struct bna_rx *rx; /* 1:1 between rx_info & rx */
+
+	struct bnad_rx_ctrl rx_ctrl[BNAD_MAX_RXPS_PER_RX];
+} ____cacheline_aligned;
+
+/* Unmap queues for Tx / Rx cleanup */
+struct bnad_skb_unmap {
+	struct sk_buff		*skb;
+	DECLARE_PCI_UNMAP_ADDR(dma_addr)
+};
+
+struct bnad_unmap_q {
+	u32		producer_index;
+	u32		consumer_index;
+	u32 		q_depth;
+	/* This should be the last one */
+	struct bnad_skb_unmap unmap_array[1];
+};
+
+/* Bit mask values for bnad->cfg_flags */
+#define	BNAD_CF_DIM_ENABLED		0x01	/* DIM */
+#define	BNAD_CF_PROMISC			0x02
+#define BNAD_CF_ALLMULTI		0x04
+#define	BNAD_CF_MSIX			0x08	/* If in MSIx mode */
+
+/* Defines for run_flags bit-mask */
+/* Set, tested & cleared using xxx_bit() functions */
+/* Values indicated bit positions */
+#define	BNAD_RF_CEE_RUNNING		1
+#define BNAD_RF_HW_ERROR 		2
+#define BNAD_RF_MBOX_IRQ_DISABLED	3
+#define BNAD_RF_TX_STARTED		4
+#define BNAD_RF_RX_STARTED		5
+#define BNAD_RF_DIM_TIMER_RUNNING	6
+#define BNAD_RF_STATS_TIMER_RUNNING	7
+
+struct bnad {
+	struct net_device 	*netdev;
+
+	/* Data path */
+	struct bnad_tx_info tx_info[BNAD_MAX_TXS];
+	struct bnad_rx_info rx_info[BNAD_MAX_RXS];
+
+	struct vlan_group	*vlan_grp;
+	/*
+	 * These q numbers are global only because
+	 * they are used to calculate MSIx vectors.
+	 * Actually the exact # of queues are per Tx/Rx
+	 * object.
+	 */
+	u32		num_tx;
+	u32		num_rx;
+	u32		num_txq_per_tx;
+	u32		num_rxp_per_rx;
+
+	u32		txq_depth;
+	u32		rxq_depth;
+
+	u8			tx_coalescing_timeo;
+	u8			rx_coalescing_timeo;
+
+	struct bna_rx_config rx_config[BNAD_MAX_RXS];
+	struct bna_tx_config tx_config[BNAD_MAX_TXS];
+
+	u32		rx_csum;
+
+	void __iomem		*bar0;	/* BAR0 address */
+
+	struct bna bna;
+
+	u32		cfg_flags;
+	unsigned long		run_flags;
+
+	struct pci_dev 		*pcidev;
+	u64		mmio_start;
+	u64		mmio_len;
+
+	u32		msix_num;
+	u32		msix_diag_num;
+	struct msix_entry	*msix_table;
+
+	struct mutex		conf_mutex;
+	spinlock_t		bna_lock ____cacheline_aligned;
+
+	/* Timers */
+	struct timer_list	ioc_timer;
+	struct timer_list	dim_timer;
+	struct timer_list	stats_timer;
+
+	/* Control path resources, memory & irq */
+	struct bna_res_info res_info[BNA_RES_T_MAX];
+	struct bnad_tx_res_info tx_res_info[BNAD_MAX_TXS];
+	struct bnad_rx_res_info rx_res_info[BNAD_MAX_RXS];
+
+	struct bnad_completion bnad_completions;
+
+	/* Burnt in MAC address */
+	mac_t			perm_addr;
+
+	struct tasklet_struct	tx_free_tasklet;
+
+	/* Statistics */
+	struct bnad_stats stats;
+	struct net_device_stats net_stats;
+
+	struct bnad_diag *diag;
+
+	char			adapter_name[BNAD_NAME_LEN];
+	char 			port_name[BNAD_NAME_LEN];
+	char			mbox_irq_name[BNAD_NAME_LEN];
+
+	struct bna_ident ident;
+};
+
+/*
+ * EXTERN VARIABLES
+ */
+extern struct firmware *bfi_fw;
+extern struct semaphore 	bnad_list_sem;
+extern struct list_head 	bnad_list;
+extern u32 		bna_id; /* Driver Instance Id */
+extern u32 		bnad_rxqs_per_cq;
+
+/*
+ * EXTERN PROTOTYPES
+ */
+extern u32 *cna_get_firmware_buf(struct pci_dev *pdev);
+/* Netdev entry point prototypes */
+extern void bnad_set_ethtool_ops(struct net_device *netdev);
+
+/* Configuration & setup */
+extern void bnad_tx_coalescing_timeo_set(struct bnad *bnad);
+extern void bnad_rx_coalescing_timeo_set(struct bnad *bnad);
+
+extern int bnad_setup_rx(struct bnad *bnad, uint rx_id);
+extern int bnad_setup_tx(struct bnad *bnad, uint tx_id);
+extern void bnad_cleanup_tx(struct bnad *bnad, uint tx_id);
+extern void bnad_cleanup_rx(struct bnad *bnad, uint rx_id);
+
+/* Timer start/stop protos */
+extern void bnad_dim_timer_start(struct bnad *bnad);
+
+/* Statistics */
+extern void bnad_netdev_qstats_fill(struct bnad *bnad);
+extern void bnad_netdev_hwstats_fill(struct bnad *bnad);
+
+/**
+ * MACROS
+ */
+/* To set & get the stats counters */
+#define BNAD_UPDATE_CTR(_bnad, _ctr)				\
+				(((_bnad)->stats.drv_stats._ctr)++)
+
+#define BNAD_GET_CTR(_bnad, _ctr) ((_bnad)->stats.drv_stats._ctr)
+
+#define bnad_enable_rx_irq_unsafe(_ccb)			\
+{							\
+	bna_ib_coalescing_timer_set((_ccb)->i_dbell,	\
+		(_ccb)->rx_coalescing_timeo);		\
+	bna_ib_ack((_ccb)->i_dbell, 0);			\
+}
+
+#define bnad_dim_timer_running(_bnad)				\
+	(((_bnad)->cfg_flags & BNAD_CF_DIM_ENABLED) && 		\
+	(test_bit(BNAD_RF_DIM_TIMER_RUNNING, &((_bnad)->run_flags))))
+
+#endif /* __BNAD_H__ */
diff -ruP net-next-2.6.35-rc1-orig/drivers/net/bna/bnad_ethtool.c net-next-2.6.35-rc1-mod/drivers/net/bna/bnad_ethtool.c
--- net-next-2.6.35-rc1-orig/drivers/net/bna/bnad_ethtool.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.35-rc1-mod/drivers/net/bna/bnad_ethtool.c	2010-08-10 12:23:09.175218000 -0700
@@ -0,0 +1,1282 @@
+/*
+ * 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) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#include "cna.h"
+
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/rtnetlink.h>
+
+#include "bna.h"
+
+#include "bnad.h"
+
+#define BNAD_NUM_TXF_COUNTERS 12
+#define BNAD_NUM_RXF_COUNTERS 10
+#define BNAD_NUM_CQ_COUNTERS 3
+#define BNAD_NUM_RXQ_COUNTERS 6
+#define BNAD_NUM_TXQ_COUNTERS 5
+
+#define BNAD_ETHTOOL_STATS_NUM						\
+	(sizeof(struct net_device_stats) / sizeof(unsigned long) +	\
+	sizeof(struct bnad_drv_stats) / sizeof(u64) +		\
+	offsetof(struct bfi_ll_stats, rxf_stats[0]) / 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",
+	"netif_rx_schedule",
+	"netif_rx_complete",
+	"netif_rx_dropped",
+
+	"link_toggle",
+	"cee_up",
+
+	"rxp_info_alloc_failed",
+	"mbox_intr_disabled",
+	"mbox_intr_enabled",
+	"tx_unmap_q_alloc_failed",
+	"rx_unmap_q_alloc_failed",
+	"rxbuf_alloc_failed",
+
+	"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",
+
+	"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",
+
+	"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",
+
+	"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",
+};
+
+static int
+bnad_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
+{
+	cmd->supported = SUPPORTED_10000baseT_Full;
+	cmd->advertising = ADVERTISED_10000baseT_Full;
+	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;
+	unsigned long flags;
+
+	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_irqsave(&bnad->bna_lock, flags);
+		bfa_ioc_get_attr(&bnad->bna.device.ioc, ioc_attr);
+		spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+		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;
+	unsigned long flags;
+
+#define BNAD_GET_REG(addr) 					\
+do {								\
+	if (regs)						\
+		regs[num++] = readl(bnad->bar0 + (addr));	\
+	else							\
+		num++;						\
+} while (0)
+
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+
+	/* 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_irqrestore(&bnad->bna_lock, flags);
+#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);
+	unsigned long flags;
+
+	/* Lock rqd. to access bnad->bna_lock */
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	coalesce->use_adaptive_rx_coalesce =
+		(bnad->cfg_flags & BNAD_CF_DIM_ENABLED) ? true : false;
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	coalesce->rx_coalesce_usecs = bnad->rx_coalescing_timeo *
+					BFI_COALESCING_TIMER_UNIT;
+	coalesce->tx_coalesce_usecs = bnad->tx_coalescing_timeo *
+					BFI_COALESCING_TIMER_UNIT;
+	coalesce->tx_max_coalesced_frames = BFI_TX_INTERPKT_COUNT;
+
+	return 0;
+}
+
+static int
+bnad_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	unsigned long flags;
+	int dim_timer_del = 0;
+
+	if (coalesce->rx_coalesce_usecs == 0 ||
+	    coalesce->rx_coalesce_usecs >
+	    BFI_MAX_COALESCING_TIMEO * BFI_COALESCING_TIMER_UNIT)
+		return -EINVAL;
+
+	if (coalesce->tx_coalesce_usecs == 0 ||
+	    coalesce->tx_coalesce_usecs >
+	    BFI_MAX_COALESCING_TIMEO * BFI_COALESCING_TIMER_UNIT)
+		return -EINVAL;
+
+	mutex_lock(&bnad->conf_mutex);
+	/*
+	 * Do not need to store rx_coalesce_usecs here
+	 * Every time DIM is disabled, we can get it from the
+	 * stack.
+	 */
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	if (coalesce->use_adaptive_rx_coalesce) {
+		if (!(bnad->cfg_flags & BNAD_CF_DIM_ENABLED)) {
+			bnad->cfg_flags |= BNAD_CF_DIM_ENABLED;
+			bnad_dim_timer_start(bnad);
+		}
+	} else {
+		if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED) {
+			bnad->cfg_flags &= ~BNAD_CF_DIM_ENABLED;
+			dim_timer_del = bnad_dim_timer_running(bnad);
+			if (dim_timer_del) {
+				clear_bit(BNAD_RF_DIM_TIMER_RUNNING,
+							&bnad->run_flags);
+				spin_unlock_irqrestore(&bnad->bna_lock, flags);
+				del_timer_sync(&bnad->dim_timer);
+				spin_lock_irqsave(&bnad->bna_lock, flags);
+			}
+			bnad_rx_coalescing_timeo_set(bnad);
+		}
+	}
+	if (bnad->tx_coalescing_timeo != coalesce->tx_coalesce_usecs /
+					BFI_COALESCING_TIMER_UNIT) {
+		bnad->tx_coalescing_timeo = coalesce->tx_coalesce_usecs /
+						BFI_COALESCING_TIMER_UNIT;
+		bnad_tx_coalescing_timeo_set(bnad);
+	}
+
+	if (bnad->rx_coalescing_timeo != coalesce->rx_coalesce_usecs /
+					BFI_COALESCING_TIMER_UNIT) {
+		bnad->rx_coalescing_timeo = coalesce->rx_coalesce_usecs /
+						BFI_COALESCING_TIMER_UNIT;
+
+		if (!(bnad->cfg_flags & BNAD_CF_DIM_ENABLED))
+			bnad_rx_coalescing_timeo_set(bnad);
+
+	}
+
+	/* Add Tx Inter-pkt DMA count?  */
+
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	mutex_unlock(&bnad->conf_mutex);
+	return 0;
+}
+
+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 i, current_err, err = 0;
+	struct bnad *bnad = netdev_priv(netdev);
+
+	mutex_lock(&bnad->conf_mutex);
+	if (ringparam->rx_pending == bnad->rxq_depth &&
+	    ringparam->tx_pending == bnad->txq_depth) {
+		mutex_unlock(&bnad->conf_mutex);
+		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)) {
+		mutex_unlock(&bnad->conf_mutex);
+		return -EINVAL;
+	}
+	if (ringparam->tx_pending < BNAD_MIN_Q_DEPTH ||
+	    ringparam->tx_pending > BNAD_MAX_Q_DEPTH ||
+	    !BNA_POWER_OF_2(ringparam->tx_pending)) {
+		mutex_unlock(&bnad->conf_mutex);
+		return -EINVAL;
+	}
+
+	if (ringparam->rx_pending != bnad->rxq_depth) {
+		bnad->rxq_depth = ringparam->rx_pending;
+		for (i = 0; i < bnad->num_rx; i++) {
+			if (!bnad->rx_info[i].rx)
+				continue;
+			bnad_cleanup_rx(bnad, i);
+			current_err = bnad_setup_rx(bnad, i);
+			if (current_err && !err)
+				err = current_err;
+		}
+	}
+	if (ringparam->tx_pending != bnad->txq_depth) {
+		bnad->txq_depth = ringparam->tx_pending;
+		for (i = 0; i < bnad->num_tx; i++) {
+			if (!bnad->tx_info[i].tx)
+				continue;
+			bnad_cleanup_tx(bnad, i);
+			current_err = bnad_setup_tx(bnad, i);
+			if (current_err && !err)
+				err = current_err;
+		}
+	}
+
+	mutex_unlock(&bnad->conf_mutex);
+	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->bna.port.pause_config.rx_pause;
+	pauseparam->tx_pause = bnad->bna.port.pause_config.tx_pause;
+}
+
+static int
+bnad_set_pauseparam(struct net_device *netdev,
+		    struct ethtool_pauseparam *pauseparam)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	struct bna_pause_config pause_config;
+	unsigned long flags;
+
+	if (pauseparam->autoneg == AUTONEG_ENABLE)
+		return -EINVAL;
+
+	mutex_lock(&bnad->conf_mutex);
+	if (pauseparam->rx_pause != bnad->bna.port.pause_config.rx_pause ||
+	    pauseparam->tx_pause != bnad->bna.port.pause_config.tx_pause) {
+		pause_config.rx_pause = pauseparam->rx_pause;
+		pause_config.tx_pause = pauseparam->tx_pause;
+		spin_lock_irqsave(&bnad->bna_lock, flags);
+		bna_port_pause_config(&bnad->bna.port, &pause_config, NULL);
+		spin_unlock_irqrestore(&bnad->bna_lock, flags);
+	}
+	mutex_unlock(&bnad->conf_mutex);
+	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);
+
+	mutex_lock(&bnad->conf_mutex);
+	bnad->rx_csum = rx_csum;
+	mutex_unlock(&bnad->conf_mutex);
+	return 0;
+}
+
+static int
+bnad_set_tx_csum(struct net_device *netdev, u32 tx_csum)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+
+	mutex_lock(&bnad->conf_mutex);
+	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;
+	}
+	mutex_unlock(&bnad->conf_mutex);
+	return 0;
+}
+
+static int
+bnad_set_tso(struct net_device *netdev, u32 tso)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+
+	mutex_lock(&bnad->conf_mutex);
+	if (tso) {
+		netdev->features |= NETIF_F_TSO;
+		netdev->features |= NETIF_F_TSO6;
+	} else {
+		netdev->features &= ~NETIF_F_TSO;
+		netdev->features &= ~NETIF_F_TSO6;
+	}
+	mutex_unlock(&bnad->conf_mutex);
+	return 0;
+}
+
+static void
+bnad_get_strings(struct net_device *netdev, u32 stringset, u8 * string)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	int i, j, q_num;
+	u64 bmap;
+
+	mutex_lock(&bnad->conf_mutex);
+
+	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;
+		}
+		bmap = (u64)bnad->bna.tx_mod.txf_bmap[0] |
+			((u64)bnad->bna.tx_mod.txf_bmap[1] << 32);
+		for (i = 0; bmap && (i < BFI_LL_TXF_ID_MAX); i++) {
+			if (bmap & 1) {
+				sprintf(string, "txf%d_ucast_octets", i);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "txf%d_ucast", i);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "txf%d_ucast_vlan", i);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "txf%d_mcast_octets", i);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "txf%d_mcast", i);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "txf%d_mcast_vlan", i);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "txf%d_bcast_octets", i);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "txf%d_bcast", i);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "txf%d_bcast_vlan", i);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "txf%d_errors", i);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "txf%d_filter_vlan", i);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "txf%d_filter_mac_sa", i);
+				string += ETH_GSTRING_LEN;
+			}
+			bmap >>= 1;
+		}
+
+		bmap = (u64)bnad->bna.rx_mod.rxf_bmap[0] |
+			((u64)bnad->bna.rx_mod.rxf_bmap[1] << 32);
+		for (i = 0; bmap && (i < BFI_LL_RXF_ID_MAX); i++) {
+			if (bmap & 1) {
+				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;
+			}
+			bmap >>= 1;
+		}
+
+		q_num = 0;
+		for (i = 0; i < bnad->num_rx; i++) {
+			if (!bnad->rx_info[i].rx)
+				continue;
+			for (j = 0; j < bnad->num_rxp_per_rx; j++) {
+				sprintf(string, "cq%d_producer_index", q_num);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "cq%d_consumer_index", q_num);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "cq%d_hw_producer_index",
+					q_num);
+				string += ETH_GSTRING_LEN;
+				q_num++;
+			}
+		}
+
+		q_num = 0;
+		for (i = 0; i < bnad->num_rx; i++) {
+			if (!bnad->rx_info[i].rx)
+				continue;
+			for (j = 0; j < bnad->num_rxp_per_rx; j++) {
+				sprintf(string, "rxq%d_packets", q_num);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "rxq%d_bytes", q_num);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "rxq%d_packets_with_error",
+								q_num);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "rxq%d_allocbuf_failed", q_num);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "rxq%d_producer_index", q_num);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "rxq%d_consumer_index", q_num);
+				string += ETH_GSTRING_LEN;
+				q_num++;
+				if (bnad->rx_info[i].rx_ctrl[j].ccb &&
+					bnad->rx_info[i].rx_ctrl[j].ccb->
+					rcb[1] &&
+					bnad->rx_info[i].rx_ctrl[j].ccb->
+					rcb[1]->rxq) {
+					sprintf(string, "rxq%d_packets", q_num);
+					string += ETH_GSTRING_LEN;
+					sprintf(string, "rxq%d_bytes", q_num);
+					string += ETH_GSTRING_LEN;
+					sprintf(string,
+					"rxq%d_packets_with_error", q_num);
+					string += ETH_GSTRING_LEN;
+					sprintf(string, "rxq%d_allocbuf_failed",
+								q_num);
+					string += ETH_GSTRING_LEN;
+					sprintf(string, "rxq%d_producer_index",
+								q_num);
+					string += ETH_GSTRING_LEN;
+					sprintf(string, "rxq%d_consumer_index",
+								q_num);
+					string += ETH_GSTRING_LEN;
+					q_num++;
+				}
+			}
+		}
+
+		q_num = 0;
+		for (i = 0; i < bnad->num_tx; i++) {
+			if (!bnad->tx_info[i].tx)
+				continue;
+			for (j = 0; j < bnad->num_txq_per_tx; j++) {
+				sprintf(string, "txq%d_packets", q_num);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "txq%d_bytes", q_num);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "txq%d_producer_index", q_num);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "txq%d_consumer_index", q_num);
+				string += ETH_GSTRING_LEN;
+				sprintf(string, "txq%d_hw_consumer_index",
+									q_num);
+				string += ETH_GSTRING_LEN;
+				q_num++;
+			}
+		}
+
+		break;
+
+	default:
+		break;
+	}
+
+	mutex_unlock(&bnad->conf_mutex);
+}
+
+static int
+bnad_get_stats_count_locked(struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	int i, j, count, rxf_active_num = 0, txf_active_num = 0;
+	u64 bmap;
+
+	bmap = (u64)bnad->bna.tx_mod.txf_bmap[0] |
+			((u64)bnad->bna.tx_mod.txf_bmap[1] << 32);
+	for (i = 0; bmap && (i < BFI_LL_TXF_ID_MAX); i++) {
+		if (bmap & 1)
+			txf_active_num++;
+		bmap >>= 1;
+	}
+	bmap = (u64)bnad->bna.rx_mod.rxf_bmap[0] |
+			((u64)bnad->bna.rx_mod.rxf_bmap[1] << 32);
+	for (i = 0; bmap && (i < BFI_LL_RXF_ID_MAX); i++) {
+		if (bmap & 1)
+			rxf_active_num++;
+		bmap >>= 1;
+	}
+	count = BNAD_ETHTOOL_STATS_NUM +
+		txf_active_num * BNAD_NUM_TXF_COUNTERS +
+		rxf_active_num * BNAD_NUM_RXF_COUNTERS;
+
+	for (i = 0; i < bnad->num_rx; i++) {
+		if (!bnad->rx_info[i].rx)
+			continue;
+		count += bnad->num_rxp_per_rx * BNAD_NUM_CQ_COUNTERS;
+		count += bnad->num_rxp_per_rx * BNAD_NUM_RXQ_COUNTERS;
+		for (j = 0; j < bnad->num_rxp_per_rx; j++)
+			if (bnad->rx_info[i].rx_ctrl[j].ccb &&
+				bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] &&
+				bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1]->rxq)
+				count +=  BNAD_NUM_RXQ_COUNTERS;
+	}
+
+	for (i = 0; i < bnad->num_tx; i++) {
+		if (!bnad->tx_info[i].tx)
+			continue;
+		count += bnad->num_txq_per_tx * BNAD_NUM_TXQ_COUNTERS;
+	}
+	return count;
+}
+
+static int
+bnad_per_q_stats_fill(struct bnad *bnad, u64 *buf, int bi)
+{
+	int i, j;
+	struct bna_rcb *rcb = NULL;
+	struct bna_tcb *tcb = NULL;
+
+	for (i = 0; i < bnad->num_rx; i++) {
+		if (!bnad->rx_info[i].rx)
+			continue;
+		for (j = 0; j < bnad->num_rxp_per_rx; j++)
+			if (bnad->rx_info[i].rx_ctrl[j].ccb &&
+				bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0] &&
+				bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0]->rxq) {
+				buf[bi++] = bnad->rx_info[i].rx_ctrl[j].
+						ccb->producer_index;
+				buf[bi++] = 0; /* ccb->consumer_index */
+				buf[bi++] = *(bnad->rx_info[i].rx_ctrl[j].
+						ccb->hw_producer_index);
+			}
+	}
+	for (i = 0; i < bnad->num_rx; i++) {
+		if (!bnad->rx_info[i].rx)
+			continue;
+		for (j = 0; j < bnad->num_rxp_per_rx; j++)
+			if (bnad->rx_info[i].rx_ctrl[j].ccb) {
+				if (bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0] &&
+					bnad->rx_info[i].rx_ctrl[j].ccb->
+					rcb[0]->rxq) {
+					rcb = bnad->rx_info[i].rx_ctrl[j].
+							ccb->rcb[0];
+					buf[bi++] = rcb->rxq->rx_packets;
+					buf[bi++] = rcb->rxq->rx_bytes;
+					buf[bi++] = rcb->rxq->
+							rx_packets_with_error;
+					buf[bi++] = rcb->rxq->
+							rxbuf_alloc_failed;
+					buf[bi++] = rcb->producer_index;
+					buf[bi++] = rcb->consumer_index;
+				}
+				if (bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] &&
+					bnad->rx_info[i].rx_ctrl[j].ccb->
+					rcb[1]->rxq) {
+					rcb = bnad->rx_info[i].rx_ctrl[j].
+								ccb->rcb[1];
+					buf[bi++] = rcb->rxq->rx_packets;
+					buf[bi++] = rcb->rxq->rx_bytes;
+					buf[bi++] = rcb->rxq->
+							rx_packets_with_error;
+					buf[bi++] = rcb->rxq->
+							rxbuf_alloc_failed;
+					buf[bi++] = rcb->producer_index;
+					buf[bi++] = rcb->consumer_index;
+				}
+			}
+	}
+
+	for (i = 0; i < bnad->num_tx; i++) {
+		if (!bnad->tx_info[i].tx)
+			continue;
+		for (j = 0; j < bnad->num_txq_per_tx; j++)
+			if (bnad->tx_info[i].tcb[j] &&
+				bnad->tx_info[i].tcb[j]->txq) {
+				tcb = bnad->tx_info[i].tcb[j];
+				buf[bi++] = tcb->txq->tx_packets;
+				buf[bi++] = tcb->txq->tx_bytes;
+				buf[bi++] = tcb->producer_index;
+				buf[bi++] = tcb->consumer_index;
+				buf[bi++] = *(tcb->hw_consumer_index);
+			}
+	}
+
+	return bi;
+}
+
+static void
+bnad_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats,
+		       u64 *buf)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	int i, j, bi;
+	unsigned long *net_stats, flags;
+	u64 *stats64;
+	u64 bmap;
+
+	mutex_lock(&bnad->conf_mutex);
+	if (bnad_get_stats_count_locked(netdev) != stats->n_stats) {
+		mutex_unlock(&bnad->conf_mutex);
+		return;
+	}
+
+	/*
+	 * Used bna_lock to sync reads from bna_stats, which is written
+	 * under the same lock
+	 */
+	spin_lock_irqsave(&bnad->bna_lock, flags);
+	bi = 0;
+	memset(buf, 0, stats->n_stats * sizeof(u64));
+	memset(&bnad->net_stats, 0, sizeof(struct net_device_stats));
+
+	bnad_netdev_qstats_fill(bnad);
+	bnad_netdev_hwstats_fill(bnad);
+
+	/* Fill net_stats into ethtool buffers */
+	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];
+
+	/* Fill driver stats into ethtool buffers */
+	stats64 = (u64 *)&bnad->stats.drv_stats;
+	for (i = 0; i < sizeof(struct bnad_drv_stats) / sizeof(u64); i++)
+		buf[bi++] = stats64[i];
+
+	/* Fill hardware stats excluding the rxf/txf into ethtool bufs */
+	stats64 = (u64 *) bnad->stats.bna_stats->hw_stats;
+	for (i = 0;
+	     i < offsetof(struct bfi_ll_stats, rxf_stats[0]) / sizeof(u64);
+	     i++)
+		buf[bi++] = stats64[i];
+
+	/* Fill txf stats into ethtool buffers */
+	bmap = (u64)bnad->bna.tx_mod.txf_bmap[0] |
+			((u64)bnad->bna.tx_mod.txf_bmap[1] << 32);
+	for (i = 0; bmap && (i < BFI_LL_TXF_ID_MAX); i++) {
+		if (bmap & 1) {
+			stats64 = (u64 *)&bnad->stats.bna_stats->
+						hw_stats->txf_stats[i];
+			for (j = 0; j < sizeof(struct bfi_ll_stats_txf) /
+					sizeof(u64); j++)
+				buf[bi++] = stats64[j];
+		}
+		bmap >>= 1;
+	}
+
+	/*  Fill rxf stats into ethtool buffers */
+	bmap = (u64)bnad->bna.rx_mod.rxf_bmap[0] |
+			((u64)bnad->bna.rx_mod.rxf_bmap[1] << 32);
+	for (i = 0; bmap && (i < BFI_LL_RXF_ID_MAX); i++) {
+		if (bmap & 1) {
+			stats64 = (u64 *)&bnad->stats.bna_stats->
+						hw_stats->rxf_stats[i];
+			for (j = 0; j < sizeof(struct bfi_ll_stats_rxf) /
+					sizeof(u64); j++)
+				buf[bi++] = stats64[j];
+		}
+		bmap >>= 1;
+	}
+
+	/* Fill per Q stats into ethtool buffers */
+	bi = bnad_per_q_stats_fill(bnad, buf, bi);
+
+	spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+	mutex_unlock(&bnad->conf_mutex);
+}
+
+static int
+bnad_get_sset_count(struct net_device *netdev, int sset)
+{
+	switch (sset) {
+	case ETH_SS_STATS:
+		return bnad_get_stats_count_locked(netdev);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+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_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_flags = ethtool_op_get_flags,
+	.set_flags = ethtool_op_set_flags,
+	.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);
+}

^ permalink raw reply

* [PATCH 0/6] bna: Brocade 10Gb Ethernet device driver
From: Rasesh Mody @ 2010-08-11  4:18 UTC (permalink / raw)
  To: netdev; +Cc: adapter_linux_open_src_team

From: Rasesh Mody <rmody@brocade.com>

This is patch 0/6 which contains the summary of changes we've
done in this particular submission for Brocade's BR1010/BR1020
10Gb CEE capable ethernet adapter. Source is based against
net-next-2.6.

The changes are as follows:

- Minimized the scope of some APIs as per the comments

- Converted spin_lock _irq()/spin_unlock_irq() to safer spin_lock_irqsave()/spin_lock_irqrestore() respectively

We wish these patches to be considered for inclusion in net-next-2.6.

Signed-off-by: Rasesh Mody <rmody@brocade.com>
---
 0 files changed



^ permalink raw reply

* Performance problem OpenWRT Routing
From: Sol Kavy @ 2010-08-11  1:59 UTC (permalink / raw)
  To: netdev

To Netdev Developers:

Linux: 2.6.28 (untested but appears the similiar in 2.6.35).
Arch: Ubicom32 <not yet pushed>
Distro: OpenWRT

While  working on a response time problem in OpenWRT when the router is fully flooded with packets,  I found that do_softirq() was spending up to 56 milliseconds in execution.   This function is called from both irq_exit() and from ksoftirqd().    

do_softirq() is designed to drain the softirq_pending work.  It executes in a loop up to 
MAX_SOFTIRQ_RESTART (10) times.  As long as one of the softirqs has pending work, all of the softirqs will have a chance to run 10 times.

Inside of net/core/dev.c, net_rx_action() attempts to "limit" the amount of data that it processes in one "call".  It tries to limit things to 1 or 2 jiffies worth of work with a budget of 300 packets.  Reading the code one is left with the feeling that the author believed that returning (would enable the rest of the system to continue).  However, this is not true if do_softirq() is going to call net_rx_action() 10 times before giving up.

The result of do_softirq() re-invoking net_rx_action() is that both packet budget and jiffies budget are reset.   The current values result in a maximum of 10 x 300 or 3,000 packets processed in one do_softirq() sequence.   

By setting the value to 30, the processing is reduced to the 10 millisecond range and most of the packet processing is moved to ksoftirqd.  The value of this is that one can then prioritize ksoftirqd with other threads.   Irq_exit() cannot be prioritized since it is executing on the back side of the interrupt.

Questions:
1) Is my analysis correct?
2) Are there any negative side effects of this change besides slowing the work a bit since it is now moved to ksoftirqd?
3) Is there a better knob to tweak?
4) Should net_rx_action() use in_irq() and have different budget's based on the calling context?

Thanks in advance for any feedback,

Sol Kavy

diff --git a/net/core/dev.c b/net/core/dev.c
index 144184c..9e4fb4f 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1905,7 +1905,7 @@ out:
   =======================================================================*/

 int netdev_max_backlog __read_mostly = 1000;
-int netdev_budget __read_mostly = 300;
+int netdev_budget __read_mostly = 30;
int weight_p __read_mostly = 64;            /* old backlog weight */

 DEFINE_PER_CPU(struct netif_rx_stats, netdev_rx_stat) = { 0, };



^ permalink raw reply related

* Re: [RFC PATCH v8 00/16] Provide a zero-copy method on KVM virtio-net.
From: Shirley Ma @ 2010-08-11  3:28 UTC (permalink / raw)
  To: Avi Kivity
  Cc: xiaohui.xin, netdev, kvm, linux-kernel, mst, mingo, davem,
	herbert, jdike
In-Reply-To: <4C56F318.7030409@redhat.com>

Hello Avi,

On Mon, 2010-08-02 at 19:32 +0300, Avi Kivity wrote:
> When are you seeing gup_fast() fall back to gup()?  It should be at
> most 
> once per page (when a guest starts up none of its pages are mapped,
> it 
> faults them in on demand). 

netperf/netserver latency results are pretty good for message size
between 1 bytes and 512 bytes when I have 64 bytes small copy.

However if I don't have any small copy , the ping RTT time is
unreasonable huge. Since we think it's better to have small message with
copy, so there will be no issue.

Thanks
Shirley

^ permalink raw reply

* Re: [RFC PATCH v9 00/16] Provide a zero-copy method on KVM virtio-net.
From: Shirley Ma @ 2010-08-11  1:43 UTC (permalink / raw)
  To: xiaohui.xin; +Cc: netdev, kvm, linux-kernel, mst, mingo, davem, herbert, jdike
In-Reply-To: <1281489804.3391.23.camel@localhost.localdomain>

On Tue, 2010-08-10 at 18:23 -0700, Shirley Ma wrote:
> Also I found some vhost performance regression on the new
> kernel with tuning. I used to get 9.4Gb/s, now I couldn't get it. 

I forgot to mention the kernel I used 2.6.36 one. And I found the native
host BW is limited to 8.0Gb/s, so the regression might come from the
device driver not vhost.

Shirley




^ permalink raw reply

* Re: [RFC PATCH v9 00/16] Provide a zero-copy method on KVM virtio-net.
From: Shirley Ma @ 2010-08-11  1:23 UTC (permalink / raw)
  To: xiaohui.xin; +Cc: netdev, kvm, linux-kernel, mst, mingo, davem, herbert, jdike
In-Reply-To: <1281086624-5765-1-git-send-email-xiaohui.xin@intel.com>

Hello Xiaohui,

On Fri, 2010-08-06 at 17:23 +0800, xiaohui.xin@intel.com wrote:
> Our goal is to improve the bandwidth and reduce the CPU usage.
> Exact performance data will be provided later. 

Have you had any performance data to share here? I tested my
experimental macvtap zero copy for TX only. The performance I have seen
as below without any tuning, (default setting):

Before: netperf 16K message size results with 60 secs run is 7.5Gb/s
over ixgbe 10GbE card. perf top shows:

2103.00 12.9% copy_user_generic_string
1541.00  9.4% handle_tx
1490.00  9.1% _raw_spin_unlock_irqrestore
1361.00  8.3% _raw_spin_lock_irqsave
1288.00  7.9% _raw_spin_lock
924.00  5.7% vhost_worker

After: netperf results with 60 secs run is 8.1Gb/s, perf output:

1093.00  9.9% _raw_spin_unlock_irqrestore
1048.00  9.5% handle_tx
934.00  8.5% _raw_spin_lock_irqsave
864.00  7.9% _raw_spin_lock
644.00  5.9% vhost_worker
387.00  3.5% use_mm 

I am still working on collecting more data (latency, cpu
utilization...). I will let you know once I get all data for macvtap TX
zero copy. Also I found some vhost performance regression on the new
kernel with tuning. I used to get 9.4Gb/s, now I couldn't get it.

Shirley
 


^ permalink raw reply

* Re: [PATCH] 3c59x: fix deadlock when using netconsole with 3c59x
From: Neil Horman @ 2010-08-11  1:16 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, klassert
In-Reply-To: <20100810.164803.13754555.davem@davemloft.net>

On Tue, Aug 10, 2010 at 04:48:03PM -0700, David Miller wrote:
> From: Neil Horman <nhorman@tuxdriver.com>
> Date: Mon, 9 Aug 2010 12:32:10 -0400
> 
> > When using netpoll, its possible to deadlock the 3c59x driver.  Since it takes
> > an internal spinlock (vp->lock) that serializes boomerang_interrupt and parts
> > of boomerang_start_xmit, if we call pr_debug in the former, we can go through
> > the tx path on the same cpu, and recurse into the same driver again, deadlocking
> > in the transmit routine.
> > 
> > This patch fixes that problem by stopping the queues during interrupt
> > processing, so that subsequent transmits will get queued until a later point.
> > Its not a great solution, but we need to find some way to serialize access to
> > the register file on the card without enforcing a deadlock.  I think the queue
> > stop is the best way to do that.  And since we only print things in
> > boomerang_interrupt when we have debug enabled, we can mitigate the impact of
> > this change to only stop the queues when debug is on.
> > 
> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> 
> Nothing serialized changes to "vortex_debug" with the tests you're
> making here.  Simply turning it off when a packet arrives can deadlock
> the send queue of the device.
> 
> Even if proper serializatio did exist, I still see this as an awful
> solution.
> 
> And the default value of this thing is "1" so it's always going to be
> doing this send queue state flipping for effectively everyone.
> 
> Please find another way to solve this problem.
> 

Crap-spackle, you're right.  I was thinking the module_param defaulted it to
zero, but it doesn't.  Regardless, sysfs would let us change this value and
deadlock it all to heck.

Recinded.  I'll find a better way to fix this.  Sorry for the noise
Neil


^ permalink raw reply

* Re: [RFC PATCH 1/2] pci: add function reset call that can be used inside of probe
From: Kenji Kaneshige @ 2010-08-11  0:44 UTC (permalink / raw)
  To: Alexander Duyck
  Cc: Kirsher, Jeffrey T, davem@davemloft.net, jbarnes@virtuousgeek.org,
	netdev@vger.kernel.org, linux-pci@vger.kernel.org
In-Reply-To: <4C61DD57.5030208@intel.com>

(2010/08/11 8:14), Alexander Duyck wrote:
> Kenji Kaneshige wrote:
>> (2010/07/31 9:58), Jeff Kirsher wrote:
>>> From: Alexander Duyck<alexander.h.duyck@intel.com>
>>> + /*
>>> + * both INTx and MSI are disabled after the Interrupt Disable bit
>>> + * is set and the Bus Master bit is cleared.
>>> + */
>>> + pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
>>> +
>>> + rc = __pci_dev_reset(dev, 0);
>>
>> Could you tell me why you need to program command register before reset?
>>
>> "MSI enable" and "Bus Master" bits are cleared by the reset. Furthermore,
>> resetting the device clears the "Interrupt Disable bit", even though it
>> was set just before the rest. So I'm a little confused.
>>
>> Thanks,
>> Kenji Kaneshige
>>
>
> The point is to prevent any pending transactions from being on the bus
> while we are doing the reset. By writing only the INTX disable bit we
> are disabling all interrupts from being generated, and also disabling
> all DMA and MSI interrupts since the bus master enable bit is not set.
>
> Without this change the device might be in the middle of a transaction
> or sending an interrupt while we are doing the reset which may lead to
> other issues after the reset.
>

Thank you for clarification. I understood.

Thanks,
Kenji Kaneshige

^ permalink raw reply

* [MeeGo-Dev][PATCH] Topcliff: Update PCH_CAN driver to 2.6.35
From: Masayuki Ohtak @ 2010-08-11  0:25 UTC (permalink / raw)
  To: meego-dev-WXzIur8shnEAvxtiuMwx3w, Wolfgang Grandegger,
	socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
	netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: andrew.chih.howe.khor-ral2JQCrhuEAvxtiuMwx3w


[-- Attachment #1.1: Type: text/plain, Size: 124239 bytes --]

CAN driver of Topcliff PCH

Topcliff PCH is the platform controller hub that is going to be used in
Intel's upcoming general embedded platform. All IO peripherals in
Topcliff PCH are actually devices sitting on AMBA bus. 
Topcliff PCH has CAN I/F. This driver enables CAN function.

Signed-off-by: Masayuki Ohtake <masa-korg-ECg8zkTtlr0C6LszWs/t0g@public.gmane.org>

---
 drivers/net/can/Kconfig   |    8 +
 drivers/net/can/Makefile  |    1 +
 drivers/net/can/pch_can.c | 4076 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/can/pch_can.h |  435 +++++
 4 files changed, 4520 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/can/pch_can.c
 create mode 100644 drivers/net/can/pch_can.h

diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 2c5227c..5c98a20 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -73,6 +73,14 @@ config CAN_JANZ_ICAN3
 	  This driver can also be built as a module. If so, the module will be
 	  called janz-ican3.ko.
 
+config PCH_CAN
+	tristate "PCH CAN"
+	depends on  CAN_DEV
+	---help---
+	  This driver is for PCH CAN of Topcliff which is an IOH for x86
+	  embedded processor.
+	  This driver can access CAN bus.
+
 source "drivers/net/can/mscan/Kconfig"
 
 source "drivers/net/can/sja1000/Kconfig"
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 9047cd0..3ddc6a7 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -16,5 +16,6 @@ obj-$(CONFIG_CAN_TI_HECC)	+= ti_hecc.o
 obj-$(CONFIG_CAN_MCP251X)	+= mcp251x.o
 obj-$(CONFIG_CAN_BFIN)		+= bfin_can.o
 obj-$(CONFIG_CAN_JANZ_ICAN3)	+= janz-ican3.o
+obj-$(CONFIG_PCH_CAN)		+= pch_can.o
 
 ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c
new file mode 100644
index 0000000..3f4fb5e
--- /dev/null
+++ b/drivers/net/can/pch_can.c
@@ -0,0 +1,4076 @@
+/*
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+
+#include "pch_can.h"
+
+static unsigned int pch_can_clock = 50000;
+static unsigned int pch_can_rx_buf_size = 16;	/* The number of message objects
+						that has to be configured as
+						receive objects.
+						*/
+
+static unsigned int pch_can_tx_buf_size = 16;	/* The number of message objects
+						that has to be configured as
+						transmit objects.
+						*/
+
+static struct pch_can_os can_os[MAX_CAN_DEVICES];
+
+static enum pch_can_auto_restart restat_mode = CAN_MANUAL; /* The variable used
+							      to store the
+							      restart mode. */
+
+static struct can_bittiming_const pch_can_bittiming_const = {
+	.name = MODULE_NAME,
+	.tseg1_min = 1,
+	.tseg1_max = 16,
+	.tseg2_min = 1,
+	.tseg2_max = 8,
+	.sjw_max = 4,
+	.brp_min = 1,
+	.brp_max = 1024, /* 6bit + extended 4bit */
+	.brp_inc = 1,
+};
+
+static const struct pci_device_id pch_can_pcidev_id[] __devinitdata = {
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PCH1_CAN)},
+	{}
+};
+
+/*
+This variable is used to store the configuration (receive /transmit) of the
+available message objects.
+This variable is used for storing the message object configuration related
+information. It includes the information about which message object is used as
+Receiver and Transmitter.
+*/
+static unsigned int pch_msg_obj_conf[MAX_MSG_OBJ] = {
+	3, 3, 3, 3,
+	3, 3, 3, 3,
+	3, 3, 3, 3,
+	3, 3, 3, 3,
+	3, 3, 3, 3,
+	3, 3, 3, 3,
+	3, 3, 3, 3,
+	3, 3, 3, 3
+};
+
+/* Array to store the timing settings. */
+static struct pch_can_timing can_rec_timing[] = {
+	/* <Baud rate>   <BRP>   <TS1>   <TS2>   <SJW> */
+	/* settings for 62.5MHz */
+	{0xa, 0x250, 0x7, 0x0, 0x0, 0x0, 0x0},	/* < 10 kbits/s */
+	{0x14, 0x8D, 0xB, 0x5, 0x0, 0x0, 0x0},	/* < 20 kbits/s */
+	{0x32, 0x5C, 0x7, 0x0, 0x0, 0x0, 0x0},	/* < 50 kbits/s */
+	{0x7d, 0x18, 0xC, 0x5, 0x0, 0x0, 0x0},	/* < 125 kbits/s */
+	{0xfa, 0x18, 0x7, 0x0, 0x0, 0x0, 0x0},	/* < 250 kbits/s */
+	{0x1f4, 0x8, 0x9, 0x2, 0x0, 0x0, 0x0},	/* < 500 kbits/s */
+	{0x320, 0x5, 0x8, 0x2, 0x0, 0x0, 0x0},	/* < 800 kbits/s  */
+	{0x3e8, 0x2, 0xC, 0x6, 0x0, 0x0, 0x0},	/* < 1000 kbits/s */
+
+	/* settings for 24MHz */
+	{0xa, 0xCF, 0x7, 0x0, 0x0, 0x0, 0x0},	/* < 10 kbits/s */
+	{0x14, 0x57, 0x7, 0x0, 0x0, 0x0, 0x0},	/* < 20 kbits/s */
+	{0x32, 0xF, 0x7, 0x0, 0x0, 0x0, 0x0},	/* < 50 kbits/s */
+	{0x7d, 0xF, 0x8, 0x1, 0x0, 0x0, 0x0},	/* < 125 kbits/s */
+	{0xfa, 0x7, 0x8, 0x1, 0x0, 0x0, 0x0},	/* < 250 kbits/s */
+	{0x1f4, 0x3, 0x8, 0x1, 0x0, 0x0, 0x0},	/* < 500 kbits/s */
+	{0x320, 0x2, 0x7, 0x0, 0x0, 0x0, 0x0},	/* < 800 kbits/s  */
+	{0x3e8, 0x1, 0x8, 0x1, 0x0, 0x0, 0x0},	/* < 1000 kbits/s */
+
+	/* settings for 50MHz */
+	{0xa, 0xFA, 0xC, 0x5, 0x1, 0x0, 0x0},	/* < 10 kbits/s */
+	{0x14, 0x7D, 0xC, 0x5, 0x1, 0x0, 0x0},	/* < 20 kbits/s */
+	{0x32, 0x32, 0xF, 0x2, 0x0, 0x0, 0x0},	/* < 50 kbits/s */
+	{0x7d, 0x19, 0xC, 0x1, 0x0, 0x0, 0x0},	/* < 125 kbits/s */
+	{0xfa, 0xA, 0xF, 0x2, 0x0, 0x0, 0x0},	/* < 250 kbits/s */
+	{0x1f4, 0x5, 0xF, 0x2, 0x0, 0x0, 0x0},	/* < 500 kbits/s */
+	{0x320, 0x5, 0x8, 0x2, 0x1, 0x0, 0x0},	/* < 800 kbits/s  */
+	{0x3e8, 0x2, 0xF, 0x7, 0x0, 0x0, 0x0}	/* < 1000 kbits/s */
+	/* Add the new clock settings here. */
+};
+
+static DEFINE_MUTEX(pch_can_mutex);
+
+#ifdef PCH_CAN_FIFO_MODE
+static int check_can_fifo_status(int handle)
+{
+	int ret_val;
+	struct can_fifo *f = (struct can_fifo *) handle;
+
+	if (f->head == f->tail)
+		ret_val = PCH_CAN_FIFO_EMPTY;
+	else if (f->head->next == f->tail)
+		ret_val = PCH_CAN_FIFO_FULL;
+	else
+		ret_val = PCH_CAN_FIFO_NOT_EMPTY;
+
+	return ret_val;
+}
+
+static int
+read_can_fifo(int handle, struct pch_can_msg *msg, struct net_device *ndev)
+{
+	int i;
+	int retval = 0;
+	struct can_fifo *f = (struct can_fifo *) handle;
+	struct pch_can_msg msg_tmp;
+
+	if ((handle == 0) || (msg == NULL)) {
+		dev_err(&ndev->dev, "%s -> Invalid parameter.\n", __func__);
+		retval = -EPERM;
+	} else if (f->head == f->tail) {	/* Buffer Empty */
+		dev_dbg(&ndev->dev, "%s -> FIFO empty.\n", __func__);
+		retval = -EPERM;
+	} else {
+		/* Accessing the msg object in the FIFO. */
+		msg_tmp = f->tail->msg;
+
+		/* Filling in the msg object. */
+		msg->ide = msg_tmp.ide;
+		msg->id = msg_tmp.id;
+		msg->dlc = msg_tmp.dlc;
+		msg->rtr = msg_tmp.rtr;
+
+		for (i = 0; i < PCH_CAN_MSG_DATA_LEN; i++)
+			msg->data[i] = msg_tmp.data[i];
+
+		/* Proceeding the FIFO read pointer. */
+		f->tail = f->tail->next;
+		dev_dbg(&ndev->dev, "%s successful.\n", __func__);
+	}
+
+	dev_dbg(&ndev->dev, "%s returns %d.\n", __func__, retval);
+	return retval;
+}
+
+static int
+write_can_fifo(int handle, struct pch_can_msg *msg, struct net_device *ndev)
+{
+	int i;
+	int retval = 0;
+	struct can_fifo *f = (struct can_fifo *) handle;
+	struct pch_can_msg *msg_tmp;
+
+	if ((handle == 0) || (msg == NULL)) {
+		dev_err(&ndev->dev, "%s -> Invalid parameters.\n", __func__);
+		retval = -EPERM;
+	} else if (f->head->next == f->tail) {
+		dev_dbg(&ndev->dev, "%s -> FIFO Full.\n", __func__);
+		retval = -EPERM;
+	} else {
+		/* Accessing the write node in the FIFO */
+		msg_tmp = &(f->head->msg);
+
+		/* Filling in the FIFO node. */
+		msg_tmp->ide = msg->ide;
+		msg_tmp->rtr = msg->rtr;
+		msg_tmp->id = msg->id;
+		msg_tmp->dlc = msg->dlc;
+
+		for (i = 0; i < PCH_CAN_MSG_DATA_LEN; i++)
+			msg_tmp->data[i] = msg->data[i];
+
+		/* Proceeding the write node. */
+		f->head = f->head->next;
+		dev_dbg(&ndev->dev, "%s successful.\n", __func__);
+	}
+
+	dev_dbg(&ndev->dev, "%s returns %d.\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_get_error_stats(int handle, struct pch_can_error *error)
+{
+	u32 reg_val;
+	int retval = 0;
+
+	if ((handle == 0) || (error == NULL)) {
+		retval = -EPERM;
+	} else {
+		/* Obtaining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		/* Reading the error count register. */
+		reg_val = ioread32(can->io_base + CAN_ERRC_OFFSET);
+
+		error->rxgte96 = 0;
+		error->txgte96 = 0;
+
+		error->rx_err_cnt =
+		    (reg_val & MSK_ES_RXERRCNT) >> BIT_ES_RXERRCNT;
+		error->tx_err_cnt =
+		    (reg_val & MSK_ES_TXERRCNT) >> BIT_ES_TXERRCNT;
+
+		/* receive error count > 96 */
+		if (error->rx_err_cnt >= ERROR_COUNT)
+			error->rxgte96 = 1;
+		/* transmit error count > 96. */
+		if (error->tx_err_cnt >= ERROR_COUNT)
+			error->txgte96 = 1;
+
+		/* Reading the Can status register. */
+		reg_val = ioread32(can->io_base + CAN_STAT_OFFSET);
+
+		/* EPass */
+		if ((reg_val & (1 << BIT_SHIFT_FIVE)) != 0)
+			error->error_stat = 1;
+		/* Buss Off */
+		else if ((reg_val & (1 << BIT_SHIFT_SEVEN)) != 0)
+			error->error_stat = 3;
+		else
+			error->error_stat = 0;
+	}
+
+	return retval;
+}
+#endif
+
+static void delete_can_fifo(int handle, struct net_device *ndev)
+{
+	unsigned int i;
+	struct can_fifo_item *curr = NULL;
+	struct can_fifo_item *next = NULL;
+	struct can_fifo *f = (struct can_fifo *) handle;
+
+	if (handle != 0) {
+		curr = f->head;
+		if (f->head != NULL) {
+			next = curr->next;
+
+			/* Freeing individual node. */
+			for (i = 0; i < f->size; i++) {
+				kfree(curr);
+				curr = next;
+				next = (struct can_fifo_item *) curr->next;
+			}
+		}
+
+		/* Free the START node. */
+		kfree(f);
+	} else {
+		dev_err(&ndev->dev, "%s -> Invalid handle.\n", __func__);
+	}
+
+	dev_dbg(&ndev->dev, "%s successful.\n", __func__);
+}
+
+static int create_can_fifo(unsigned int fifo_entries, struct net_device *ndev)
+{
+	unsigned int i;
+	struct can_fifo_item *curr;
+	struct can_fifo *f;
+	int retval;
+
+	/* Allocating the Main start node. */
+	f = kmalloc(sizeof(struct can_fifo), GFP_KERNEL);
+
+	if (f == NULL) {
+		dev_err(&ndev->dev,
+			"%s -> msg queue allocation failed.\n", __func__);
+		retval = (int) PCH_CAN_NULL;
+	} else {
+		/* Allocating the first node. */
+		f->head = kmalloc(sizeof(struct can_fifo_item), GFP_KERNEL);
+		if ((f->head == NULL)) {
+			kfree(f);
+			retval = (int) PCH_CAN_NULL;
+		} else {
+			/* Initially empty. */
+			f->tail = f->head;
+			curr = f->head;
+
+			/* Rest of the nod ecreation Node creation. */
+			for (i = 1; i <= fifo_entries; i++) {
+				curr->next =
+					kmalloc(sizeof(struct can_fifo_item),
+								GFP_KERNEL);
+				/* If allocation failed. */
+				if ((curr->next == NULL)) {
+					dev_err(&ndev->dev,
+						"%s -> Allocation failed.\n",
+						__func__);
+					i = (i - 1);
+					/* Freeing the already allocated
+					   nodes. */
+					while (i > 0) {
+						curr = f->head;
+						f->head = curr->next;
+						kfree(curr);
+
+						i--;
+					}
+
+					/* Freeing the main start node. */
+					kfree(f);
+					f = NULL;
+					retval =
+					    (int) PCH_CAN_NULL;
+					break;
+				}
+
+				curr = curr->next;
+			}
+
+			if (f != NULL) {
+				/* Making it circular. */
+				curr->next = f->head;
+				f->size = fifo_entries;
+
+				retval = (int) f;
+				dev_dbg(&ndev->dev,
+						"%s sucessful.\n", __func__);
+			}
+		}
+	}
+
+	dev_dbg(&ndev->dev, "%s returns %u.\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_create(u8 *io_base, struct net_device *ndev)
+{
+	struct can_hw *can = NULL;
+	int retval = (int) PCH_CAN_NULL;
+
+	if (io_base == NULL) {
+		dev_err(&ndev->dev, "%s -> Invalid IO Base\n", __func__);
+	}
+
+	else {
+		/* Allocates memory for the handle. */
+		can = kmalloc(sizeof(struct can_hw), GFP_KERNEL);
+		if (can == NULL) {	/* Allocation failed */
+			dev_err(&ndev->dev,
+			    "%s -> CAN Memory allocation failed\n", __func__);
+		} else {	/* Allocation successful */
+
+			can->io_base = io_base;
+			retval = (int) can;
+			dev_dbg(&ndev->dev,
+			    "%s -> Handle Creation successful.\n", __func__);
+		}
+	}
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %x\n", __func__, retval);
+	return retval;
+}
+
+static void pch_can_destroy(int handle, struct net_device *ndev)
+{
+	struct can_hw *can = (struct can_hw *) handle;
+
+	if (handle !=  0) {
+		/* Free the memory for the handle. */
+		kfree(can);
+		dev_dbg(&ndev->dev, "%s -> Free successful.\n", __func__);
+	} else {
+		dev_err(&ndev->dev, "%s-> Invalid handle.\n", __func__);
+	}
+}
+
+static int pch_can_set_run_mode(int handle, enum pch_can_run_mode mode,
+				struct net_device *ndev)
+{
+	int retval = 0;
+	struct can_hw *can;
+	if (handle == 0) {
+		dev_err(&ndev->dev, "%s -> Invalid Handle\n", __func__);
+		retval = -EPERM;
+	} else {
+		/* Retrieving base address for access. */
+		can = (struct can_hw *) handle;
+
+		switch (mode) {
+		case PCH_CAN_RUN:
+			PCH_CAN_BIT_CLEAR((can->io_base + CAN_CONT_OFFSET),
+					  CAN_CTRL_INIT);
+			dev_dbg(&ndev->dev,
+			    "%s -> Can set to RUN Mode.\n", __func__);
+			break;
+
+		case PCH_CAN_STOP:
+			PCH_CAN_BIT_SET((can->io_base + CAN_CONT_OFFSET),
+					CAN_CTRL_INIT);
+			dev_dbg(&ndev->dev,
+			    "%s -> Can set to STOP Mode.\n", __func__);
+			break;
+
+		default:
+			dev_err(&ndev->dev,
+				"%s -> Invalid run mode.\n", __func__);
+			retval = -EPERM;
+			break;
+		}
+	}
+
+	dev_dbg(&ndev->dev,
+			"%s -> Return value: %d\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_get_run_mode(int handle, enum pch_can_run_mode *mode,
+				struct net_device *ndev)
+{
+	u32 reg_val;
+	struct can_hw *can;
+	int retval = 0;
+
+	if ((handle ==  0) || (mode == NULL)) {
+		dev_err(&ndev->dev,
+			"%s -> Invalid parameter.\n", __func__);
+		retval = -EPERM;
+	} else {
+		/* Obtaining the remap address for access. */
+		can = (struct can_hw *) handle;
+
+		reg_val = ioread32(can->io_base + CAN_CONT_OFFSET);
+
+		/* Checking the Init bit of Can Control Register.
+		   Init Bit 1 -> Stop
+		   Init Bit 0 -> Run
+		 */
+		if ((reg_val & CAN_CTRL_INIT) != 0) {
+			*mode = PCH_CAN_STOP;
+			dev_dbg(&ndev->dev,
+			    "%s -> Mode is PCH_CAN_STOP\n", __func__);
+		} else {
+			*mode = PCH_CAN_RUN;
+			dev_dbg(&ndev->dev,
+			    "%s -> Mode is PCH_CAN_RUN\n", __func__);
+		}
+	}
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_set_arbiter_mode(int handle, enum pch_can_arbiter mode,
+				    struct net_device *ndev)
+{
+	int retval = 0;
+
+	if (handle == 0) {
+		dev_err(&ndev->dev,
+			"%s -> Invalid Handle\n", __func__);
+		retval = -EPERM;
+	} else {
+		/* PCH CAN Controller supports only PCH_CAN_FIXED_PRIORITY
+		   arbiter mode.
+		 */
+		switch (mode) {
+		case PCH_CAN_FIXED_PRIORITY:
+			dev_dbg(&ndev->dev,
+			    "%s -> FIXED PRIORITY is set for Arbiter mode\n",
+			    __func__);
+			break;
+
+		case PCH_CAN_ROUND_ROBIN:
+		default:
+			dev_dbg(&ndev->dev,
+				"%s -> Invalid arbiter mode\n", __func__);
+			retval = -EPERM;
+			break;
+		}
+	}
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_get_arbiter_mode(int handle, enum pch_can_arbiter *mode,
+				    struct net_device *ndev)
+{
+	int retval = 0;
+
+	if ((handle == 0) || (mode == NULL)) {
+		dev_err(&ndev->dev,
+			"%s -> Invalid parameter\n", __func__);
+		retval = -EPERM;
+	}
+
+	else {
+		/* PCH CAN Controller supports only PCH_CAN_FIXED_PRIORITY
+		   arbiter mode.
+		 */
+		*mode = PCH_CAN_FIXED_PRIORITY;
+		dev_dbg(&ndev->dev,
+		    "%s -> Arbiter Mode is PCH_CAN_FIXED_PRIORITY\n", __func__);
+	}
+
+	dev_dbg(&ndev->dev, "%s returns %d\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_set_restart_mode(int handle,	enum pch_can_auto_restart mode,
+				    struct net_device *ndev)
+{
+	int retval = 0;
+
+	if (handle == 0) {
+		dev_err(&ndev->dev, "%s -> Invalid Handle\n", __func__);
+		retval = -EPERM;
+	} else {
+		switch (mode) {
+		case CAN_MANUAL:
+			restat_mode = CAN_MANUAL;
+			dev_dbg(&ndev->dev, "%s -> Value of variable "
+			     " restat_mode = 0. CAN_MANUAL mode set.\n",
+				__func__);
+			break;
+
+		case CAN_AUTO:
+			restat_mode = CAN_AUTO;
+			dev_dbg(&ndev->dev, "%s -> Value of variable "
+			     " restat_mode = 1. CAN_AUTO mode set.\n",
+			    __func__);
+			break;
+
+		default:
+			dev_dbg(&ndev->dev,
+				"%s -> Invalid restart mode\n", __func__);
+			retval = -EPERM;
+			break;
+		}
+	}
+
+	dev_dbg(&ndev->dev, "%s returns %d\n", __func__,
+								 retval);
+	return retval;
+}
+
+static int pch_can_get_restart_mode(int handle, enum pch_can_auto_restart *mode,
+				    struct net_device *ndev)
+{
+	int retval = 0;
+
+	if ((handle == 0) || (mode == NULL)) {
+		dev_err(&ndev->dev, "%s -> Invalid parameter.\n", __func__);
+		retval = -EPERM;
+	} else {
+		if (CAN_AUTO == restat_mode) {
+			*mode = CAN_AUTO;
+			dev_dbg(&ndev->dev,
+					"%s -> Mode CAN_AUTO.\n", __func__);
+		} else {
+			*mode = CAN_MANUAL;
+			dev_dbg(&ndev->dev,
+					"%s -> Mode CAN_MANUAL.\n", __func__);
+		}
+	}
+
+	dev_dbg(&ndev->dev, "%s returns: %d\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_set_listen_mode(int handle, enum pch_can_listen_mode mode,
+				   struct net_device *ndev)
+{
+	int retval = 0;
+
+	if (handle == 0) {
+		dev_err(&ndev->dev, "%s -> Invalid Handle\n", __func__);
+		retval = -EPERM;
+	} else {
+		/* Obtaining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		/* Setting for Bit3 of Can Extended function register for
+		   appropriate mode.
+		   Silent bit = 0 (Active mode)
+		   Silent bit = 1 (Silent mode)
+		 */
+		switch (mode) {
+		case PCH_CAN_LISTEN:
+			PCH_CAN_BIT_SET((can->io_base + CAN_CONT_OFFSET),
+					CAN_CTRL_OPT);
+			PCH_CAN_BIT_SET((can->io_base + CAN_OPT_OFFSET),
+					CAN_OPT_SILENT);
+			dev_dbg(&ndev->dev,
+				"%s -> PCH_CAN_LISTEN mode set.\n", __func__);
+			break;
+
+		case PCH_CAN_ACTIVE:
+			PCH_CAN_BIT_SET((can->io_base + CAN_CONT_OFFSET),
+					CAN_CTRL_OPT);
+			PCH_CAN_BIT_CLEAR((can->io_base + CAN_OPT_OFFSET),
+					  CAN_OPT_SILENT);
+			dev_dbg(&ndev->dev,
+				"%s ->PCH_CAN_ACTIVE mode set.\n", __func__);
+			break;
+
+		default:
+			dev_dbg(&ndev->dev,
+					"%s ->Invalid listen mode\n", __func__);
+			retval = -EPERM;
+			break;
+		}
+	}
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_get_listen_mode(int handle, enum pch_can_listen_mode *mode,
+				   struct net_device *ndev)
+{
+	u32 reg_val;
+	int retval = 0;
+
+	if ((handle == 0) || (mode == NULL)) {
+		dev_err(&ndev->dev, "%s -> Invalid Parameter\n", __func__);
+		retval = -EPERM;
+	} else {
+		/* Attaining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		reg_val = ioread32(can->io_base + CAN_OPT_OFFSET);
+
+		/*      Checking for Bit3 of Can Extended function register
+			 for silent mode
+		   Silent bit = 0 (Active mode)
+		   Silent bit = 1 (Silent mode)
+		 */
+
+		if ((reg_val & CAN_OPT_SILENT) != 0) {
+			*mode = PCH_CAN_LISTEN;
+			dev_dbg(&ndev->dev,
+					"%s -> Mode is listen\n", __func__);
+		} else {
+			*mode = PCH_CAN_ACTIVE;
+			dev_dbg(&ndev->dev, "%s -> Mode is active\n", __func__);
+		}
+	}
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_set_int_custom(int handle, u32 interrupts)
+{
+	int retval = 0;
+
+	if (handle == 0) {
+		retval = -EPERM;
+	} else {
+		/* Obtaining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		/* Clearing the IE, SIE and EIE bits of Can control register. */
+		PCH_CAN_BIT_CLEAR((can->io_base + CAN_CONT_OFFSET),
+				  CAN_CTRL_IE_SIE_EIE);
+
+		/* Appropriately setting them. */
+		PCH_CAN_BIT_SET((can->io_base + CAN_CONT_OFFSET),
+				((interrupts & MSK_CTRL_IE_SIE_EIE) <<
+				 BIT_SHIFT_ONE));
+	}
+
+	return retval;
+}
+
+/* This function retrieves interrupt enabled for the CAN device. */
+static int pch_can_get_int_enables(int handle, u32 *enables)
+{
+	u32 reg_ctrl_val;
+	int retval = 0;
+
+	if ((handle == 0) || (enables == NULL)) {
+		retval = -EPERM;
+	} else {
+		/* Obtaining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		/* Reading the Can control register. */
+		reg_ctrl_val = ioread32(can->io_base + CAN_CONT_OFFSET);
+
+		/* Obtaining the status of IE, SIE and EIE interrupt bits. */
+		*enables =
+		    (((reg_ctrl_val & CAN_CTRL_IE_SIE_EIE) >> BIT_SHIFT_ONE));
+	}
+
+	return retval;
+}
+
+static int pch_can_set_int_enables(int handle,
+				   enum pch_can_interrupt interrupt_no,
+				   struct net_device *ndev)
+{
+	int retval = 0;
+
+	if (handle == 0) {
+		dev_err(&ndev->dev, "%s -> Invalid Handle.\n", __func__);
+		retval = -EPERM;
+	} else {
+
+		/* Obatining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		/*
+		   Appropriately setting the IE, SIE and EIE bits of Can control
+			 register.
+		 */
+		switch (interrupt_no) {
+		case CAN_ENABLE:
+			PCH_CAN_BIT_SET((can->io_base + CAN_CONT_OFFSET),
+					CAN_CTRL_IE);
+			dev_dbg(&ndev->dev,
+			    "%s -> CAN_ENABLE (IE) interrupt set.\n", __func__);
+			break;
+
+		case CAN_DISABLE:
+			PCH_CAN_BIT_CLEAR((can->io_base + CAN_CONT_OFFSET),
+					  CAN_CTRL_IE);
+			dev_dbg(&ndev->dev,
+			  "%s -> CAN_DIABLE (IE) interrupt reset.\n", __func__);
+			break;
+
+		case CAN_ALL:
+			PCH_CAN_BIT_SET((can->io_base + CAN_CONT_OFFSET),
+					CAN_CTRL_IE_SIE_EIE);
+			dev_dbg(&ndev->dev,
+				"%s -> CAN_ALL (IE,SIE,EIE) interrupt set.\n",
+				__func__);
+			break;
+
+		case CAN_NONE:
+			PCH_CAN_BIT_CLEAR((can->io_base + CAN_CONT_OFFSET),
+					  CAN_CTRL_IE_SIE_EIE);
+			dev_dbg(&ndev->dev,
+			    "%s -> CAN_NONE (IE,SIE,EIE) interrupt reset.\n",
+			    __func__);
+			break;
+
+		default:
+			dev_dbg(&ndev->dev,
+			    "%s -> Invalid parameter interrupt.\n", __func__);
+			retval = -EPERM;
+			break;
+		}
+	}
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_set_rx_enable(int handle, u32 buff_num, u32 set,
+				 struct net_device *ndev)
+{
+	u32 counter;
+	int retval = 0;
+	u32 if1_creq;
+
+	if (handle == 0) {
+		dev_err(&ndev->dev, "%s -> Invalid Handle.\n", __func__);
+		retval = -EPERM;
+	} else if ((pch_msg_obj_conf[buff_num - 1] != MSG_OBJ_RX) ||
+		 (buff_num > (pch_can_tx_buf_size + pch_can_rx_buf_size))) {
+		/* if invalid buffer number. */
+		dev_err(&ndev->dev,
+		    "%s -> Message object %u not configured for receive.\n",
+		    __func__, buff_num);
+		retval = -EPERM;
+	} else {
+		/* Obtaining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		/*Reading the receive buffer data from RAM to Interface1
+								 registers */
+		iowrite32(CAN_CMASK_RX_TX_GET,
+			       (can->io_base + CAN_IF1_CMASK_OFFSET));
+		iowrite32(buff_num,
+			       (can->io_base + CAN_IF1_CREQ_OFFSET));
+
+		counter = COUNTER_LIMIT;
+		while (counter) {
+			if1_creq = (ioread32(can->io_base +
+							CAN_IF1_CREQ_OFFSET)) &
+							CAN_IF_CREQ_BUSY;
+			if (if1_creq == 0)
+				break;
+
+			counter--;
+		}
+
+		if ((counter == 0)) {
+			dev_err(&ndev->dev,
+			    "%s -> Cannot read the message buffer object %u.\n",
+			    __func__, buff_num);
+			retval = -EPERM;
+		} else {		/* Reading successful */
+
+			/* Setting the IF1MASK1 register to access MsgVal and
+								 RxIE bits */
+			iowrite32((CAN_CMASK_RDWR | CAN_CMASK_ARB |
+						CAN_CMASK_CTRL),
+						(can->io_base +
+						CAN_IF1_CMASK_OFFSET));
+
+			if (set == ENABLE) {
+				/* Setting the MsgVal and RxIE bits */
+				PCH_CAN_BIT_SET((can->io_base +
+						 CAN_IF1_MCONT_OFFSET),
+						CAN_IF_MCONT_RXIE);
+				PCH_CAN_BIT_SET((can->io_base +
+						 CAN_IF1_ID2_OFFSET),
+						CAN_ID_MSGVAL);
+
+				dev_dbg(&ndev->dev,
+				   "%s -> Enabled receive message buffer %u.\n",
+				   __func__, buff_num);
+			} else if (set == DISABLE) {
+				/* Resetting the MsgVal and RxIE bits */
+				PCH_CAN_BIT_CLEAR((can->io_base +
+						   CAN_IF1_MCONT_OFFSET),
+						  CAN_IF_MCONT_RXIE);
+				PCH_CAN_BIT_CLEAR((can->io_base +
+						   CAN_IF1_ID2_OFFSET),
+						  CAN_ID_MSGVAL);
+
+				dev_dbg(&ndev->dev,
+				    "%s -> Disabled receive message buffer %u",
+				    __func__, buff_num);
+			}
+
+			/* Updating the changes to the message object. */
+			iowrite32(buff_num,
+				       (can->io_base + CAN_IF1_CREQ_OFFSET));
+
+			/* Confirming the write by checking the busy bit. */
+			counter = COUNTER_LIMIT;
+			while (counter) {
+				if1_creq = (ioread32(can->io_base +
+							CAN_IF1_CREQ_OFFSET)) &
+							CAN_IF_CREQ_BUSY;
+				if (if1_creq == 0)
+					break;
+
+				counter--;
+			}
+
+			if ((counter == 0)) {
+				dev_err(&ndev->dev,
+					"%s -> Write failed.\n", __func__);
+				retval = -EPERM;
+			}
+		}
+	}
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_rx_enable_all(int handle, struct net_device *ndev)
+{
+	u32 counter = 0;
+	int retval = 0;
+	u32 i;
+
+	if (handle == 0) {
+		dev_err(&ndev->dev, "%s -> Invalid Handle.\n", __func__);
+		retval = -EPERM;
+	} else {
+		/* Traversing to obtain the object configured as receivers. */
+		for (i = 0; i < (pch_can_tx_buf_size + pch_can_rx_buf_size);
+									i++) {
+			if (pch_msg_obj_conf[i] == MSG_OBJ_RX) {
+				/* Here i is the index, however (i+1) is object
+								 number. */
+				retval =
+				    pch_can_set_rx_enable(handle, (i + 1),
+							  ENABLE, ndev);
+
+				if (retval == -EPERM) {
+					dev_dbg(&ndev->dev,
+					    "%s -> Cannot Enable receive "
+					    "object%u\n", __func__, i + 1);
+					counter++;
+				} else {
+					dev_dbg(&ndev->dev,
+					   "%s -> Enabled receive object %u\n",
+					   __func__, i + 1);
+				}
+			}
+		}
+
+		/* If enabling of all the receive object failed. */
+		if (counter == pch_can_rx_buf_size) {
+			retval = -EPERM;
+			dev_err(&ndev->dev, "%s failed.\n", __func__);
+		}
+	}
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_rx_disable_all(int handle, struct net_device *ndev)
+{
+	u32 counter = 0;
+	int retval = 0;
+	u32 i;
+
+	if (handle == 0) {
+		dev_err(&ndev->dev, "%s -> Invalid Handle.\n", __func__);
+		retval = -EPERM;
+	} else {
+		/* Traversing to obtain the object configured as receivers. */
+		for (i = 0; i < (pch_can_rx_buf_size + pch_can_tx_buf_size);
+									i++) {
+			if (pch_msg_obj_conf[i] == MSG_OBJ_RX) {
+				/* Here i is the index, however (i+1) is the
+							 object number. */
+				retval =
+				    pch_can_set_rx_enable(handle, (i + 1),
+							  DISABLE, ndev);
+
+				if (retval == -EPERM) {
+					dev_dbg(&ndev->dev,
+					    "%s -> Disabling of Rx buffer %u "
+					    "failed.\n", __func__, (i + 1));
+					counter++;
+				} else {
+					dev_dbg(&ndev->dev,
+					  "%s -> Disabled receive object %u\n",
+					  __func__, i + 1);
+				}
+			}
+		}
+
+		/* If disabling of all the receive object failed. */
+		if (counter == pch_can_rx_buf_size) {
+			retval = -EPERM;
+			dev_err(&ndev->dev, "%s failed.\n", __func__);
+		}
+	}
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_set_tx_enable(int handle, u32 buff_num, u32 set,
+				 struct net_device *ndev)
+{
+	int retval = 0;
+	u32 counter;
+	u32 if1_creq;
+
+	if (handle == 0) {
+		dev_err(&ndev->dev, "%s -> Invalid Handle", __func__);
+		retval = -EPERM;
+	} else if ((pch_msg_obj_conf[buff_num - 1] != MSG_OBJ_TX) ||
+		 (buff_num > (pch_can_rx_buf_size + pch_can_tx_buf_size))) {
+		/* invalid buffer number. */
+		dev_err(&ndev->dev,
+		    "%s -> Message object %u not configured for transmit.\n",
+		    __func__, buff_num);
+		retval = -EPERM;
+	} else {
+		/* Obtaining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		/*Reading the Message buffer from Message RAM to Interface2
+								 registers. */
+		iowrite32(CAN_CMASK_RX_TX_GET,
+			       (can->io_base + CAN_IF1_CMASK_OFFSET));
+		iowrite32(buff_num,
+			       (can->io_base + CAN_IF1_CREQ_OFFSET));
+
+		counter = COUNTER_LIMIT;
+		while (counter) {
+			if1_creq = (ioread32(can->io_base +
+						CAN_IF1_CREQ_OFFSET)) &
+						CAN_IF_CREQ_BUSY;
+			if (if1_creq == 0)
+				break;
+
+			counter--;
+		}
+
+		if ((counter == 0)) {
+			dev_err(&ndev->dev,
+			   "%s -> Reading transmit buffer failed.\n", __func__);
+			retval = -EPERM;
+		} else {	/* Reading successful. */
+
+			/* Setting the IF2CMASK register for accessing the
+				MsgVal and TxIE bits */
+			iowrite32((CAN_CMASK_RDWR | CAN_CMASK_ARB |
+					CAN_CMASK_CTRL),
+				       (can->io_base +
+					CAN_IF1_CMASK_OFFSET));
+
+			if (set == ENABLE) {
+				/* Setting the MsgVal and TxIE bits */
+				PCH_CAN_BIT_SET((can->io_base +
+						 CAN_IF1_MCONT_OFFSET),
+						CAN_IF_MCONT_TXIE);
+				PCH_CAN_BIT_SET((can->io_base +
+						 CAN_IF1_ID2_OFFSET),
+						CAN_ID_MSGVAL);
+
+				dev_dbg(&ndev->dev,
+				   "%s -> Enabled transmit message buffer %u\n",
+				   __func__, buff_num);
+			} else if (set == DISABLE) {
+				/* Resetting the MsgVal and TxIE bits. */
+				PCH_CAN_BIT_CLEAR((can->io_base +
+						   CAN_IF1_MCONT_OFFSET),
+						  CAN_IF_MCONT_TXIE);
+				PCH_CAN_BIT_CLEAR((can->io_base +
+						   CAN_IF1_ID2_OFFSET),
+						  CAN_ID_MSGVAL);
+
+				dev_dbg(&ndev->dev,
+				  "%s -> Disabled transmit message buffer %u\n",
+				  __func__, buff_num);
+			}
+
+			/* Updating the changes to the message buffer. */
+			iowrite32(buff_num,
+				       (can->io_base + CAN_IF1_CREQ_OFFSET));
+
+			/* Confirming the updation. */
+			counter = COUNTER_LIMIT;
+			while (counter) {
+				if1_creq = (ioread32(can->io_base +
+						CAN_IF1_CREQ_OFFSET)) &
+						CAN_IF_CREQ_BUSY;
+				if (if1_creq == 0)
+					break;
+
+				counter--;
+			}
+
+			if ((counter == 0)) {	/* Updation failed. */
+				dev_err(&ndev->dev,
+					"%s -> Write failed.\n", __func__);
+				retval = -EPERM;
+			}
+		}
+	}
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_tx_enable_all(int handle, struct net_device *ndev)
+{
+	u32 counter = 0;
+	int retval = 0;
+	u32 i;
+
+	if (handle == 0) {
+		dev_err(&ndev->dev, "%s -> Invalid Handle.\n", __func__);
+		retval = -EPERM;
+	} else {
+		/* Traversing to obtain the object configured as transmit
+								 object. */
+		for (i = 0; i < (pch_can_tx_buf_size + pch_can_rx_buf_size);
+									i++) {
+			if (pch_msg_obj_conf[i] == MSG_OBJ_TX) {
+				/* Here i denotes the index, however (i+1) is
+							 the object number. */
+				retval =
+				    pch_can_set_tx_enable(handle, (i + 1),
+							  ENABLE, ndev);
+
+				if (retval == -EPERM) {
+					counter++;
+					dev_dbg(&ndev->dev, "%s -> "
+					  "Cannot Enable transmit object %u\n",
+					  __func__, (i + 1));
+				} else {
+					dev_dbg(&ndev->dev, "%s -> "
+					  "Enabled transmit object %u\n",
+					  __func__, (i + 1));
+				}
+			}
+		}
+
+		/* If enabling of all transmit object failed. */
+		if (counter == pch_can_tx_buf_size) {
+			dev_err(&ndev->dev, "%s failed.\n", __func__);
+			retval = -EPERM;
+		}
+
+	}
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_tx_disable_all(int handle, struct net_device *ndev)
+{
+	u32 counter = 0;
+	int retval = 0;
+	u32 i;
+
+	if (handle == 0) {
+		dev_err(&ndev->dev, "%s -> Invalid Handle.\n", __func__);
+		retval = -EPERM;
+	} else {
+		/* Traversing to obtain the object configured as transmit
+								 object. */
+		for (i = 0; i < (pch_can_tx_buf_size + pch_can_tx_buf_size);
+									i++) {
+			if (pch_msg_obj_conf[i] == MSG_OBJ_TX) {
+				/* Here i denotes the index, however (i+1) is
+							 the object number. */
+
+				/* Disabling. */
+				retval =
+				    pch_can_set_tx_enable(handle, (i + 1),
+							  DISABLE, ndev);
+
+				if (retval == -EPERM) {
+					dev_dbg(&ndev->dev,  "%s -> Disabling"
+						" Tx buffer %u failed.\n",
+						__func__, (i + 1));
+					counter++;
+				} else {
+					dev_dbg(&ndev->dev,
+					  "%s -> Disabled transmit object %u\n",
+					  __func__, (i + 1));
+				}
+			}
+		}
+
+		/* If disabling of all the transmit object failed. */
+		if (counter == pch_can_tx_buf_size) {
+			dev_err(&ndev->dev, "%s -> failed.\n", __func__);
+			retval = -EPERM;
+		}
+	}
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_set_rx_filter(int handle, struct pch_can_rx_filter *filter)
+{
+	u32 reg1;
+	u32 reg2;
+	u32 counter;
+	int retval = 0;
+	u32 if1_creq;
+
+	if ((handle == 0) || (filter == NULL)) {
+		retval = -EPERM;
+	} else {
+		/* Obtaining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		iowrite32(CAN_CMASK_RX_TX_GET,
+				can->io_base + CAN_IF1_CMASK_OFFSET);
+				/* Setting the CMASK for reading */
+		iowrite32(filter->num,
+				can->io_base + CAN_IF1_CREQ_OFFSET);
+				/* Setting CREQ to specified Msg Obj. */
+
+		/* Confirming the read completion. */
+		counter = COUNTER_LIMIT;
+		while (counter) {
+			if1_creq = (ioread32(can->io_base +
+						CAN_IF1_CREQ_OFFSET)) &
+						CAN_IF_CREQ_BUSY;
+			if (if1_creq == 0)
+				break;
+
+			counter--;
+		}
+
+		if ((counter == 0)) {	/* Read Unsuccessful. */
+			retval = -EPERM;
+		} else {	/* read successful. */
+
+			PCH_CAN_BIT_CLEAR((can->io_base +
+					CAN_IF1_ID2_OFFSET), MSK_ALL_THIRTEEN);
+					/* Clearing the bit 0- 12 of ID2 */
+			PCH_CAN_BIT_CLEAR((can->io_base +
+					CAN_IF1_ID2_OFFSET), CAN_ID2_XTD);
+					/* Clearing XTD bit */
+
+			if ((filter->aidr.id_ext == 1)) { /* Extended ID */
+				reg1 = filter->aidr.id & MSK_ALL_SIXTEEN;
+								/* ID1 value. */
+				/* ID2 value with XTD bit set. */
+				reg2 =
+				    (((filter->aidr.
+				       id & (MSK_ALL_THIRTEEN <<
+					     BIT_SHIFT_SIXTEEN))
+				      >> BIT_SHIFT_SIXTEEN) | CAN_ID2_XTD);
+			} else {	/* Standard ID */
+
+				reg1 = 0;
+				reg2 = ((filter->aidr.id & MSK_ALL_ELEVEN) <<
+								BIT_SHIFT_TWO);
+			}
+
+			iowrite32(reg1, (can->io_base + CAN_IF1_ID1_OFFSET));
+			PCH_CAN_BIT_SET((can->io_base +
+						CAN_IF1_ID2_OFFSET), reg2);
+
+			if (filter->umask == 1) {
+				/* If mask has to be set. */
+				PCH_CAN_BIT_CLEAR((can->io_base +
+							CAN_IF1_MASK2_OFFSET),
+							MSK_ALL_THIRTEEN);
+						/* Clearing bit 0-12 */
+				PCH_CAN_BIT_CLEAR((can->io_base +
+							CAN_IF1_MASK2_OFFSET),
+							CAN_MASK2_MDIR_MXTD);
+						/* Clearing Mdir & MXtd */
+
+				if (filter->amr.id_ext == 1) {
+							/* Extended Mask */
+					reg1 = filter->amr.id & MSK_ALL_SIXTEEN;
+							/* Mask1 value */
+					/* Mask2 value with MXtd set */
+					reg2 = (((filter->amr.
+						id & (MSK_ALL_THIRTEEN <<
+						BIT_SHIFT_SIXTEEN))
+						>> BIT_SHIFT_SIXTEEN) |
+						CAN_IF_MASK2_MXTD);
+				} else {
+					reg1 = 0;
+					reg2 = ((filter->amr.id &
+							MSK_ALL_ELEVEN) <<
+							BIT_SHIFT_TWO);
+							/* Mask2 Value */
+				}
+
+				iowrite32(reg1,
+				    (can->io_base + CAN_IF1_MASK1_OFFSET));
+							/* Writing MASK1 */
+				PCH_CAN_BIT_SET((can->io_base +
+						CAN_IF1_MASK2_OFFSET), reg2);
+							/* Writing MASK2 */
+				PCH_CAN_BIT_SET((can->io_base +
+				    CAN_IF1_MCONT_OFFSET), CAN_IF_MCONT_UMASK);
+							/* Setting Umask bit */
+			} else {
+				PCH_CAN_BIT_CLEAR((can->io_base +
+				    CAN_IF1_MCONT_OFFSET), CAN_IF_MCONT_UMASK);
+						/* Resetting Umask bit. */
+			}
+
+			/* Setting CMASK for writing */
+			iowrite32((CAN_CMASK_RDWR | CAN_CMASK_MASK |
+					CAN_CMASK_ARB | CAN_CMASK_CTRL),
+					(can->io_base +
+					CAN_IF1_CMASK_OFFSET));
+			iowrite32(filter->num, (can->io_base +
+					CAN_IF1_CREQ_OFFSET));
+					/* Setting CREQ for specified sg Obj. */
+
+			/* Confirming the write completion. */
+			counter = COUNTER_LIMIT;
+			while (counter) {
+				if1_creq = (ioread32(can->io_base +
+							CAN_IF1_CREQ_OFFSET)) &
+							CAN_IF_CREQ_BUSY;
+				if (if1_creq == 0)
+					break;
+
+				counter--;
+			}
+
+			if (counter == 0) /* Write failed */
+				retval = -EPERM;
+		}
+	}
+
+	return retval;
+}
+
+static int
+pch_can_rx_init_filter(int handle, u32 buff_num, struct net_device *ndev)
+{
+	int retval = 0;
+	struct pch_can_rx_filter filter;
+
+	if (handle == 0) {
+		retval = -EPERM;
+	} else if ((pch_msg_obj_conf[buff_num - 1] != MSG_OBJ_RX) ||
+		 (buff_num > (pch_can_tx_buf_size + pch_can_rx_buf_size))) {
+		/* if invalid buffer number. */
+		dev_err(&ndev->dev,
+			"%s -> Invalid buffer no:%d\n", __func__, buff_num);
+		retval = -EPERM;
+	} else {
+		/* Set all Rx filters to allow all msgs. */
+		filter.amr.id = (u32) 0;
+		filter.amr.id_ext = (u32) 0;
+
+		filter.aidr.id = (u32) 0;
+		filter.aidr.id_ext = (u32) 0;
+
+		filter.num = buff_num;
+		filter.umask = 1;
+
+		retval = pch_can_set_rx_filter(handle, &filter);
+	}
+
+	return retval;
+}
+
+static int pch_can_get_rx_enable(int handle, u32 buff_num, u32 *enable,
+				 struct net_device *ndev)
+{
+	int retval = 0;
+	u32 counter;
+	u32 if1_creq;
+
+	if ((handle == 0) || (enable == NULL)) {
+		dev_err(&ndev->dev,
+			"%s -> Invalid Parameter.\n", __func__);
+		retval = -EPERM;
+	}
+	/* Invalid buffer number. */
+	else if ((pch_msg_obj_conf[buff_num - 1] != MSG_OBJ_RX) ||
+		 (buff_num > (pch_can_tx_buf_size + pch_can_rx_buf_size))) {
+		dev_err(&ndev->dev,
+			"%s -> Message object %u not configured for receive.\n",
+			__func__, buff_num);
+		retval = -EPERM;
+	}
+
+	else {
+		/* Obtaining the remap address fro access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		iowrite32(CAN_CMASK_RX_TX_GET,
+				(can->io_base + CAN_IF1_CMASK_OFFSET));
+		iowrite32(buff_num,
+				(can->io_base + CAN_IF1_CREQ_OFFSET));
+
+		counter = COUNTER_LIMIT;
+		while (counter) {
+			if1_creq = (ioread32((can->io_base +
+						CAN_IF1_CREQ_OFFSET))) &
+						CAN_IF_CREQ_BUSY;
+			if (if1_creq == 0)
+				break;
+
+			counter--;
+		}
+
+		if (counter == 0) {
+			dev_err(&ndev->dev, "%s -> Read Failed.\n", __func__);
+			retval = -EPERM;
+		} else {
+			if (((ioread32(can->io_base +
+					CAN_IF1_ID2_OFFSET)) &
+					CAN_ID_MSGVAL) &&
+					((ioread32(can->io_base +
+					CAN_IF1_MCONT_OFFSET)) &
+					CAN_IF_MCONT_RXIE)) {
+				*enable = ENABLE;
+
+				dev_dbg(&ndev->dev, "%s -> Receive message "
+					"buffer %u is enabled.\n",
+					__func__, buff_num);
+			} else {
+				*enable = DISABLE;
+				dev_dbg(&ndev->dev, "%s -> Receive Message "
+					"buffer %u is disabled.\n",
+					__func__, buff_num);
+			}
+		}
+
+	}
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_get_tx_enable(int handle, u32 buff_num, u32 *enable,
+				 struct net_device *ndev)
+{
+	int retval = 0;
+	u32 counter;
+	u32 if1_creq;
+
+	if ((handle == 0) || (enable == NULL)) {
+		dev_err(&ndev->dev,
+			"%s -> Invalid Parameter.\n", __func__);
+		retval = -EPERM;
+	}
+	/* invalid buffer number. */
+	else if ((pch_msg_obj_conf[buff_num - 1] != MSG_OBJ_TX) ||
+		 (buff_num > (pch_can_rx_buf_size + pch_can_tx_buf_size))) {
+		dev_err(&ndev->dev, "%s ->"
+			" Invalid Message "
+			"object %u.\n", __func__, buff_num);
+		retval = -EPERM;
+	} else {
+		/* Obtaining the buffer number for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		iowrite32(CAN_CMASK_RX_TX_GET,
+			       (can->io_base + CAN_IF1_CMASK_OFFSET));
+		iowrite32(buff_num,
+			       (can->io_base + CAN_IF1_CREQ_OFFSET));
+
+		counter = COUNTER_LIMIT;
+		while (counter) {
+			if1_creq = (ioread32(can->io_base +
+						CAN_IF1_CREQ_OFFSET)) &
+						CAN_IF_CREQ_BUSY;
+			if (if1_creq == 0)
+				break;
+
+			counter--;
+		}
+
+		if (counter == 0) {
+			dev_err(&ndev->dev, "%s -> Read Failed.\n", __func__);
+			retval = -EPERM;
+		} else {
+			if (((ioread32(can->io_base +
+					CAN_IF1_ID2_OFFSET)) & CAN_ID_MSGVAL) &&
+					((ioread32(can->io_base +
+					CAN_IF1_MCONT_OFFSET)) &
+					CAN_IF_MCONT_TXIE)) {
+				*enable = ENABLE;
+
+				dev_dbg(&ndev->dev,
+					"%s -> Transmit message buffer %u is "
+					"enabled.\n", __func__, buff_num);
+			} else {
+				*enable = DISABLE;
+
+				dev_dbg(&ndev->dev,
+					"%s -> Transmit message buffer %u is "
+					"disabled.\n", __func__, buff_num);
+			}
+		}
+	}
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %d.\n", __func__, retval);
+	return retval;
+}
+
+/* This function returns whether or not interrupts are pending for the CAN
+ * device.
+*/
+static int pch_can_int_pending(int handle)
+{
+	int retval = 0;
+
+	if (handle ==  0) {
+		retval = -EPERM;
+	} else {
+		/* Obatining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+		retval = (ioread32(can->io_base + CAN_INT_OFFSET) &
+							MSK_ALL_SIXTEEN);
+	}
+
+	return retval;
+}
+
+static int pch_can_set_baud_simple(int handle, enum pch_can_baud baud)
+{
+	u32 reg_val;
+	int retval = 0;
+
+	if (handle == 0) {
+		retval = -EPERM;
+	} else {
+		/* Obtaining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+		u32 offset;
+
+		/* Setting the CCE bit of Can control register for accessing the
+							 Timing Register. */
+		PCH_CAN_BIT_SET((can->io_base + CAN_CONT_OFFSET),
+				CAN_CTRL_CCE);
+
+		/* Calculating the offset of the settings array for the current
+								 clock.  */
+		switch (pch_can_clock) {
+		case 62500:
+			offset = PCH_CAN_CLOCK_62_5_OFFSET;
+			break;
+
+		case 24000:
+			offset = PCH_CAN_CLOCK_24_OFFSET;
+			break;
+
+		case 50000:
+			offset = PCH_CAN_CLOCK_50_OFFSET;
+			break;
+
+			/* The default section will not be invoked since
+			the clock frequency has been validated at the module
+			init procedure. */
+		default:
+			offset = PCH_CAN_CLOCK_DEFAULT_OFFSET;
+			break;
+		}
+
+		/* Getting the appropriate register value. */
+		reg_val = (((can_rec_timing[baud + offset].
+				cfg_bitrate & MSK_BITT_BRP) << BIT_BITT_BRP) |
+				(can_rec_timing[baud + offset].
+				cfg_tseg1 << BIT_BITT_TSEG1) |
+				(can_rec_timing[baud + offset].cfg_tseg2 <<
+				BIT_BITT_TSEG2) |
+				(can_rec_timing[baud + offset].cfg_sjw <<
+				BIT_BITT_SJW));
+
+		/* Writing to Can Timing register. */
+		iowrite32(reg_val, (can->io_base + CAN_BITT_OFFSET));
+		/* Writing to the CAN BRP register. */
+		iowrite32(((can_rec_timing[baud + offset].
+				cfg_bitrate & MSK_BRPE_BRPE) >> BIT_BRPE_BRPE),
+				(can->io_base + CAN_BRPE_OFFSET));
+
+		/* Resetting the CCE bit of the Can control register. */
+		PCH_CAN_BIT_CLEAR((can->io_base + CAN_CONT_OFFSET),
+				  CAN_CTRL_CCE);
+	}
+
+	return retval;
+}
+
+static int pch_can_set_baud_custom(int handle, struct pch_can_timing *timing)
+{
+	u32 reg_val;
+	int retval = 0;
+
+	if ((handle == 0) || (timing == NULL))
+		retval = -EPERM;
+
+	/* max is MAX_BITRATE */
+	else if (timing->bitrate > MAX_BITRATE) {
+		retval = -EPERM;
+	}
+
+	else {
+		/* Obtaining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		/* Setting the CCE bit of Can control register for accessing the
+							 Can Timing register. */
+		PCH_CAN_BIT_SET((can->io_base + CAN_CONT_OFFSET),
+				CAN_CTRL_CCE);
+
+		/* Obtaining the appropriate register value. */
+		reg_val =
+		    (((timing->cfg_bitrate & MSK_BITT_BRP) << BIT_BITT_BRP) |
+		    (timing->cfg_tseg1 << BIT_BITT_TSEG1) |
+		    (timing->cfg_tseg2 << BIT_BITT_TSEG2) |
+		    (timing->cfg_sjw << BIT_BITT_SJW));
+
+		/* Writing to the timing register. */
+		iowrite32(reg_val, (can->io_base + CAN_BITT_OFFSET));
+		/* Writing to the BRP register. */
+		iowrite32(((timing->cfg_bitrate & MSK_BRPE_BRPE) >>
+					BIT_BRPE_BRPE),
+					(can->io_base + CAN_BRPE_OFFSET));
+
+		/* Resetting the CCE bit. */
+		PCH_CAN_BIT_CLEAR((can->io_base + CAN_CONT_OFFSET),
+								CAN_CTRL_CCE);
+
+	}
+
+	return retval;
+}
+
+static int pch_can_get_baud(int handle, struct pch_can_timing *timing)
+{
+	u32 timing_bitt_reg;
+	u32 timing_brpe_reg;
+	int retval = 0;
+
+	if ((handle == 0) || (timing == NULL)) {
+		retval = -EPERM;
+	} else {
+		/* Obtaining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		timing_bitt_reg = ioread32(can->io_base + CAN_BITT_OFFSET);
+		timing_brpe_reg = ioread32(can->io_base + CAN_BRPE_OFFSET);
+
+		/* Separating the individual part from the values read. */
+		timing->cfg_bitrate = ((timing_bitt_reg & MSK_BITT_BRP) |
+			((timing_brpe_reg & MSK_BRPE_GET) << BIT_BRPE_BRPE));
+		timing->cfg_tseg1 =
+			(timing_bitt_reg & MSK_BITT_TSEG1) >> BIT_BITT_TSEG1;
+		timing->cfg_tseg2 =
+			(timing_bitt_reg & MSK_BITT_TSEG2) >> BIT_BITT_TSEG2;
+		timing->cfg_sjw =
+			(timing_bitt_reg & MSK_BITT_SJW) >> BIT_BITT_SJW;
+	}
+
+	return retval;
+}
+
+static int pch_can_set_rx_buffer_link(int handle, u32 buffer_num, u32 set,
+				      struct net_device *ndev)
+{
+	u32 counter;
+	int retval = 0;
+	u32 if1_creq;
+
+	if (handle == 0) {
+		dev_err(&ndev->dev, "%s -> Invalid handle.\n", __func__);
+		retval = -EPERM;
+	} else if ((pch_msg_obj_conf[buffer_num - 1] != MSG_OBJ_RX) ||
+		(buffer_num > (pch_can_rx_buf_size + pch_can_tx_buf_size))) {
+		/* invalid buffer nummber. */
+		dev_err(&ndev->dev, "%s -> Invalid buffer number %u.\n"
+							, __func__, buffer_num);
+		retval = -EPERM;
+	} else {
+		/* Obtaining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		/* Reading the corresponding object. */
+		iowrite32(CAN_CMASK_RX_TX_GET,
+				(can->io_base + CAN_IF1_CMASK_OFFSET));
+		iowrite32(buffer_num,
+				(can->io_base + CAN_IF1_CREQ_OFFSET));
+
+		counter = COUNTER_LIMIT;
+		while (counter) {
+			if1_creq = ioread32((can->io_base +
+							CAN_IF1_CREQ_OFFSET)) &
+							CAN_IF_CREQ_BUSY;
+			if (if1_creq == 0)
+				break;
+
+			counter--;
+		}
+
+		/* Confirming read. */
+		if ((counter == 0)) {
+			dev_err(&ndev->dev, "%s -> Read failed\n", __func__);
+			retval = -EPERM;
+		} else {
+			iowrite32((CAN_CMASK_RDWR | CAN_CMASK_CTRL),
+				(can->io_base + CAN_IF1_CMASK_OFFSET));
+
+			/*
+			Setting/Resetting the EOD bit for Buffer link operation.
+			EOB bit = 1 -> Buffer link disabled.
+			EOB bit = 0 -> Biffer link enabled.
+			*/
+			if (set == ENABLE) {
+				PCH_CAN_BIT_CLEAR((can->io_base +
+				    CAN_IF1_MCONT_OFFSET), CAN_IF_MCONT_EOB);
+				dev_dbg(&ndev->dev,
+					"%s -> Buffer Link enabled.\n",
+					__func__);
+			} else {
+				PCH_CAN_BIT_SET((can->io_base +
+						 CAN_IF1_MCONT_OFFSET),
+						CAN_IF_MCONT_EOB);
+				dev_dbg(&ndev->dev,
+				    "%s -> Buffer Link disabled.\n", __func__);
+			}
+
+			iowrite32(buffer_num,
+				       (can->io_base + CAN_IF1_CREQ_OFFSET));
+
+			counter = COUNTER_LIMIT;
+			while (counter) {
+				if1_creq = ioread32(can->io_base +
+						CAN_IF1_CREQ_OFFSET) &
+						CAN_IF_CREQ_BUSY;
+				if (if1_creq == 0)
+					break;
+
+				counter--;
+			}
+
+			if (counter == 0) {
+				dev_err(&ndev->dev, "%s -> Write failed.\n",
+								__func__);
+				retval = -EPERM;
+			} else {
+				dev_dbg(&ndev->dev,
+					"%s -> Write successful.\n", __func__);
+				retval = 0;
+			}
+
+		}
+	}
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_get_rx_buffer_link(int handle, u32 buffer_num,
+				      u32 *link, struct net_device *ndev)
+{
+	u32 reg_val;
+	u32 counter;
+	int retval = 0;
+	u32 if1_creq;
+
+	if ((handle == 0) || (link == NULL)) {
+		dev_err(&ndev->dev, "%s -> Invalid Parameter.\n", __func__);
+		retval = -EPERM;
+	} else if ((pch_msg_obj_conf[buffer_num - 1] != MSG_OBJ_RX) ||
+		   (buffer_num > (pch_can_rx_buf_size + pch_can_tx_buf_size))) {
+		dev_err(&ndev->dev,
+		    "%s -> Invalid buffer number %u.\n", __func__, buffer_num);
+		retval = -EPERM;
+	} else {
+		/* Obatining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		/* Reading the corresponding message object. */
+		iowrite32(CAN_CMASK_RX_TX_GET,
+			       (can->io_base + CAN_IF1_CMASK_OFFSET));
+		iowrite32(buffer_num,
+			       (can->io_base + CAN_IF1_CREQ_OFFSET));
+
+		counter = COUNTER_LIMIT;
+		while (counter) {
+			if1_creq = (ioread32((can->io_base +
+				     CAN_IF1_CREQ_OFFSET)) & CAN_IF_CREQ_BUSY);
+			if (if1_creq == 0)
+				break;
+
+			counter--;
+		}
+
+		/* Confirming read. */
+		if ((counter == 0)) {
+			dev_err(&ndev->dev, "%s -> Read Failed.\n", __func__);
+			retval = -EPERM;
+		} else {
+			/* Checking for the EOB bit.
+			   EOB bit = 1 -> Buffer link disabled.
+			   EOB bit = 0 -> Biffer link enabled.
+			 */
+			reg_val = ioread32(can->io_base +
+							CAN_IF1_MCONT_OFFSET);
+			if (reg_val & CAN_IF_MCONT_EOB)
+				*link = DISABLE;
+			else
+				*link = ENABLE;
+			dev_dbg(&ndev->dev, "%s -> EOB bit =  %d\n", __func__,
+			    (reg_val & CAN_IF_MCONT_EOB) >> BIT_SHIFT_SEVEN);
+			dev_dbg(&ndev->dev,
+			    "%s -> Buffer Link =  %u (1 - Set ,0 -> not set)\n",
+			    __func__, *link);
+		}
+	}
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_get_rx_filter(int handle, struct pch_can_rx_filter *filter,
+				 struct net_device *ndev)
+{
+	u32 reg_val1;
+	u32 reg_val2;
+	u32 counter;
+	int retval = 0;
+	u32 if1_creq;
+
+	if ((handle == 0) || (filter == NULL)) {
+		dev_err(&ndev->dev, "%s -> Invalid Parameter.\n", __func__);
+		retval = -EPERM;
+	} else {
+		/* Obtaining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		/* Preparing to read the specified Msg Obj. */
+		iowrite32(CAN_CMASK_RX_TX_GET,
+				(can->io_base + CAN_IF1_CMASK_OFFSET));
+		iowrite32(filter->num,
+				(can->io_base + CAN_IF1_CREQ_OFFSET));
+
+		/* Confirming the read completion. */
+		counter = COUNTER_LIMIT;
+		while (counter) {
+			if1_creq = (ioread32(can->io_base +
+				CAN_IF1_CREQ_OFFSET)) & CAN_IF_CREQ_BUSY;
+			if (if1_creq == 0)
+				break;
+
+			counter--;
+		}
+
+		if ((counter == 0)) {	/* Read unsuccessful. */
+			dev_err(&ndev->dev,
+				"%s -> Reading of receive buffer %u failed.\n",
+				__func__, filter->num);
+			retval = -EPERM;
+		} else {	/* read successful. */
+
+			/* Checking for Umask */
+			reg_val1 = ioread32((can->io_base +
+							CAN_IF1_MCONT_OFFSET));
+			filter->umask = ((CAN_IF_MCONT_UMASK & reg_val1) >>
+							BIT_SHIFT_TWELVE);
+
+			if (filter->umask == 1) {	/* If Umask is set */
+				/* Getting the Mask data. */
+
+				/* Reading MASK2 register. */
+				reg_val1 = ioread32((can->io_base +
+							CAN_IF1_MASK2_OFFSET));
+
+				if ((CAN_IF_MASK2_MXTD & reg_val1) != 0) {
+					/* Extended Mask set.
+							 Mask ID is 29 bits */
+					reg_val2 = ioread32((can->io_base +
+							CAN_IF1_MASK1_OFFSET));
+
+					/* Extracting the 16 MSB bits of the
+					 29bit ID. */
+					reg_val2 = reg_val2 & MSK_ALL_SIXTEEN;
+					/* Extracting the remaing 13 bits */
+					reg_val1 = reg_val1 & MSK_ALL_THIRTEEN;
+
+					/* Combing them to a single 29bit ID. */
+					reg_val1 =
+						reg_val1 << BIT_SHIFT_SIXTEEN;
+					reg_val1 = reg_val1 | reg_val2;
+
+					filter->amr.id = reg_val1;
+					filter->amr.id_ext = 1;
+				} else { /* Standard Mask 11bit Mask ID */
+
+					/* Extracting the 13 bits of MASK2
+								 register. */
+					reg_val1 = reg_val1 & MSK_ALL_THIRTEEN;
+
+					/* Modifying it to represent 11bit Mask
+									 ID */
+					reg_val1 = reg_val1 >> BIT_SHIFT_TWO;
+
+					filter->amr.id = reg_val1;
+					filter->amr.id_ext = 0;
+				}
+			}
+
+			reg_val1 = ioread32((can->io_base +
+							CAN_IF1_ID2_OFFSET));
+
+			if ((CAN_ID2_XTD & reg_val1) != 0) {	/* Extended ID
+								 29bits */
+				reg_val2 = ioread32((can->io_base +
+							CAN_IF1_ID1_OFFSET));
+
+				/* Extracting the 16 MSB bits of the 29bit
+									 ID. */
+				reg_val2 = reg_val2 & MSK_ALL_SIXTEEN;
+				/* Extracting the remaining 13 bit. */
+				reg_val1 = reg_val1 & MSK_ALL_THIRTEEN;
+
+				/* Combining them to represent 29bit ID. */
+				reg_val1 = reg_val1 << BIT_SHIFT_SIXTEEN;
+				reg_val1 = reg_val1 | reg_val2;
+
+				filter->aidr.id = reg_val1;
+				filter->aidr.id_ext = 1;
+			} else {	/* Standard Id 11bits. */
+
+				/* Extracting the 13 bits of ID2 register */
+				reg_val1 = reg_val1 & MSK_ALL_THIRTEEN;
+				/* Modifying it to represent the 11 bit ID */
+				reg_val1 = reg_val1 >> BIT_SHIFT_TWO;
+
+				filter->aidr.id = reg_val1;
+				filter->aidr.id_ext = 0;
+			}
+
+			dev_dbg(&ndev->dev,
+			  "%s -> Successfully read the filter of Msg Obj %u.\n",
+			  __func__, filter->num);
+		}
+	}
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %d.\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_clear_buffers(int handle)
+{
+	u32 i;
+	u32 rx_buff_num;
+	u32 tx_buff_num;
+	int retval = 0;
+
+	if (handle == 0) {
+		retval = -EPERM;
+	} else {
+		/* Obatining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		iowrite32(CAN_CMASK_RX_TX_SET,
+			       (can->io_base + CAN_IF1_CMASK_OFFSET));
+		iowrite32(CAN_CMASK_RX_TX_SET,
+			       (can->io_base + CAN_IF2_CMASK_OFFSET));
+
+		iowrite32(MSK_ALL_SIXTEEN,
+			       (can->io_base + CAN_IF1_MASK1_OFFSET));
+		iowrite32(MSK_ALL_SIXTEEN,
+			       (can->io_base + CAN_IF1_MASK2_OFFSET));
+		iowrite32(MSK_ALL_SIXTEEN,
+			       (can->io_base + CAN_IF2_MASK1_OFFSET));
+		iowrite32(MSK_ALL_SIXTEEN,
+			       (can->io_base + CAN_IF2_MASK2_OFFSET));
+
+		iowrite32(0x0, (can->io_base + CAN_IF1_ID1_OFFSET));
+		iowrite32(0x0, (can->io_base + CAN_IF1_ID2_OFFSET));
+		iowrite32(0x0, (can->io_base + CAN_IF2_ID1_OFFSET));
+		iowrite32(0x0, (can->io_base + CAN_IF2_ID2_OFFSET));
+
+		iowrite32(0x0, (can->io_base + CAN_IF1_MCONT_OFFSET));
+		iowrite32(0x0, (can->io_base + CAN_IF2_MCONT_OFFSET));
+
+		iowrite32(0x0, (can->io_base + CAN_IF1_DATAA1_OFFSET));
+		iowrite32(0x0, (can->io_base + CAN_IF1_DATAA2_OFFSET));
+		iowrite32(0x0, (can->io_base + CAN_IF1_DATAB1_OFFSET));
+		iowrite32(0x0, (can->io_base + CAN_IF1_DATAB2_OFFSET));
+		iowrite32(0x0, (can->io_base + CAN_IF2_DATAA1_OFFSET));
+		iowrite32(0x0, (can->io_base + CAN_IF2_DATAA2_OFFSET));
+		iowrite32(0x0, (can->io_base + CAN_IF2_DATAB1_OFFSET));
+		iowrite32(0x0, (can->io_base + CAN_IF2_DATAB2_OFFSET));
+
+		for (i = 1; i <= (MAX_MSG_OBJ / 2); i++) {
+			rx_buff_num = 2 * i;
+			tx_buff_num = (2 * i) - 1;
+
+			iowrite32(rx_buff_num,
+				       (can->io_base + CAN_IF1_CREQ_OFFSET));
+			iowrite32(tx_buff_num,
+				       (can->io_base + CAN_IF2_CREQ_OFFSET));
+
+			mdelay(10);
+		}
+	}
+
+	return retval;
+}
+
+static void pch_can_config_rx_tx_buffers(int handle, struct net_device *ndev)
+{
+	u32 i;
+	u32 counter;
+	u32 if1_creq;
+	u32 if2_creq;
+
+	if (handle != 0) {	/* if handle valid. */
+		/* Obtaining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		/*For accssing MsgVal, ID and EOB bit */
+		iowrite32((CAN_CMASK_RDWR | CAN_CMASK_ARB |
+				CAN_CMASK_CTRL),
+			       (can->io_base + CAN_IF1_CMASK_OFFSET));
+		iowrite32((CAN_CMASK_RDWR | CAN_CMASK_ARB |
+				CAN_CMASK_CTRL),
+			       (can->io_base + CAN_IF2_CMASK_OFFSET));
+
+		iowrite32(0x0, (can->io_base + CAN_IF1_ID1_OFFSET));
+		iowrite32(0x0, (can->io_base + CAN_IF1_ID2_OFFSET));
+					/* Resetting DIR bit for reception */
+		iowrite32(0x0, (can->io_base + CAN_IF2_ID1_OFFSET));
+		iowrite32((CAN_ID2_DIR | (MSK_ALL_ELEVEN << 2)),
+					(can->io_base + CAN_IF2_ID2_OFFSET));
+					/* Setting DIR bit for transmission */
+
+		iowrite32(CAN_IF_MCONT_EOB,
+				(can->io_base + CAN_IF1_MCONT_OFFSET));
+					/* Setting EOB bit for receiver */
+		iowrite32(CAN_IF_MCONT_EOB,
+				(can->io_base + CAN_IF2_MCONT_OFFSET));
+					/* Setting EOB bit for transmitter */
+
+		for (i = 0; i < (pch_can_tx_buf_size + pch_can_rx_buf_size);
+									i++) {
+			counter = COUNTER_LIMIT;
+			/* Configure the receive message objects */
+			if (pch_msg_obj_conf[i] == MSG_OBJ_RX) {
+
+				iowrite32((i + 1), (can->io_base +
+							CAN_IF1_CREQ_OFFSET));
+
+				while (counter) {
+					if1_creq = (ioread32(can->io_base +
+							CAN_IF1_CREQ_OFFSET)) &
+							CAN_IF_CREQ_BUSY;
+					if (if1_creq == 0)
+						break;
+
+					counter--;
+				}
+
+				if ((counter == 0)) {
+					dev_dbg(&ndev->dev, "%s ->Config failed"
+					    " for receive message object %u\n",
+					    __func__, (i + 1));
+				}
+			}
+			/* Configure the transmit message objects */
+			else if (pch_msg_obj_conf[i] == MSG_OBJ_TX) {
+				iowrite32((i + 1), (can->io_base +
+							CAN_IF2_CREQ_OFFSET));
+
+				while (counter) {
+					if2_creq = (ioread32(can->io_base +
+							CAN_IF2_CREQ_OFFSET)) &
+							CAN_IF_CREQ_BUSY;
+					if (if2_creq == 0)
+						break;
+
+					counter--;
+				}
+
+				if ((counter == 0)) {
+					dev_dbg(&ndev->dev, "%s ->Config failed"
+					    " for transmit message object %u\n",
+					    __func__, (i + 1));
+				}
+			}
+
+		}
+	}
+}
+
+static int pch_can_open(int handle, enum pch_can_listen_mode listen,
+			enum pch_can_arbiter arbiter, struct net_device *ndev)
+{
+	int retval;
+	s32 i;
+	if (handle == 0) {
+		dev_err(&ndev->dev, "%s -> Invalid handle.\n", __func__);
+		retval = -EPERM;
+	} else {
+		do {
+			/* Stopping the Can device. */
+			retval = pch_can_set_run_mode(handle, PCH_CAN_STOP,
+									ndev);
+			if (retval == -EPERM) {
+				dev_err(&ndev->dev,
+				    "%s -> pch_can_set_run_mode "
+				    "failed(returned %d).\n", __func__, retval);
+
+				break;
+			}
+			dev_dbg(&ndev->dev,
+			   "%s -> pch_can_set_run_mode invoked successfully.\n",
+			   __func__);
+
+			/* Clearing all the message object buffers. */
+			retval = pch_can_clear_buffers(handle);
+			if (retval == -EPERM) {
+				dev_err(&ndev->dev, "%s ->pch_can_clear_buffers"
+				   " failed(returned %d).\n", __func__, retval);
+				break;
+			}
+			dev_dbg(&ndev->dev, "%s ->pch_can_clear_buffers invoked"
+			     " successfully(returned %d).\n", __func__, retval);
+
+			/* Configuring the respective message object as either
+						 receive/transmit object. */
+			pch_can_config_rx_tx_buffers(handle, ndev);
+			dev_dbg(&ndev->dev, "%s -> pch_can_config_rx_tx_buffers"
+					" invoked successfully.\n", __func__);
+
+			/* Initializing filters for receive object. */
+			for (i = 0;
+			     i < (pch_can_tx_buf_size + pch_can_rx_buf_size);
+									i++) {
+				if (pch_msg_obj_conf[i] == MSG_OBJ_RX) {
+					/* Here i denotes the index, however
+						 the object number is (i+1) */
+					retval =
+					    pch_can_rx_init_filter(handle,
+							   (i + 1), ndev);
+
+					if (retval != 0) {
+						dev_err(&ndev->dev,
+						    "pch_can_rx_init_filter "
+						    "failed for msg obj:%d\n",
+						    (i + 1));
+						break;
+					}
+				}
+			}
+			if (retval != 0)
+				break;
+			dev_dbg(&ndev->dev, "%s -> pch_can_rx_init_filter "
+					"invoked successfully.\n", __func__);
+
+			/* Enabling all receive objects. */
+			retval = pch_can_rx_enable_all(handle, ndev);
+
+			if (retval == -EPERM) {
+				dev_err(&ndev->dev,
+				    "%s -> pch_can_rx_enable_all "
+				    "failed(returned %d).\n", __func__, retval);
+				break;
+			}
+			dev_dbg(&ndev->dev, "%s -> pch_can_rx_enable_all "
+				"invoked successfully(returned %d).\n",
+				__func__, retval);
+
+			/* Enabling all transmit objects. */
+			retval = pch_can_tx_enable_all(handle, ndev);
+
+			if (retval == -EPERM) {
+				dev_err(&ndev->dev,
+					"%s -> pch_can_tx_enable_all failed"
+					"(returned %d).\n", __func__, retval);
+				break;
+			}
+			dev_dbg(&ndev->dev, "%s -> pch_can_tx_enable_all "
+				"invoked successfully(returned %d).\n",
+				__func__, retval);
+
+			/* Setting the arbiter mode. */
+			retval = pch_can_set_arbiter_mode(handle, arbiter,
+									ndev);
+			if (retval == -EPERM) {
+				dev_err(&ndev->dev,
+				    "%s -> pch_can_set_arbiter_mode "
+				    "failed(returned %d).\n", __func__, retval);
+				break;
+			}
+			dev_dbg(&ndev->dev, "%s -> pch_can_set_arbiter_mode "
+				"invoked successfully(returned %d).\n",
+				__func__, retval);
+
+			/* Setting the listen mode. */
+			retval = pch_can_set_listen_mode(handle, listen, ndev);
+			if (retval == -EPERM) {
+				dev_err(&ndev->dev,
+				    "%s -> pch_can_set_listen_mode "
+				    "failed(returned %d).\n", __func__, retval);
+				break;
+			}
+			dev_dbg(&ndev->dev, "%s -> pch_can_set_listen_mode "
+				"invoked successfully(returned %d).\n",
+				__func__, retval);
+
+			/* Enabling the interrupts. */
+			retval = pch_can_set_int_enables(handle, CAN_ALL, ndev);
+			if (retval == -EPERM) {
+				dev_err(&ndev->dev,
+				    "%s -> pch_can_set_int_enables "
+				    "failed(returned %d).\n", __func__, retval);
+				break;
+			}
+			dev_dbg(&ndev->dev, "%s -> pch_can_set_int_enables "
+				"invoked successfully(returned %d).\n",
+				__func__, retval);
+
+			/* Setting the restart mode. */
+			retval = pch_can_set_restart_mode(handle, CAN_AUTO,
+									ndev);
+			if (retval == -EPERM) {
+				dev_err(&ndev->dev,
+				    "%s -> pch_can_set_restart_mode failed"
+				    "(returned %d).\n", __func__, retval);
+				break;
+			}
+			dev_dbg(&ndev->dev, "%s -> pch_can_set_restart_mode "
+				"invoked successfully(returned %d).\n",
+				__func__, retval);
+
+			/* Setting the CAN to run mode. */
+			retval = pch_can_set_run_mode(handle, PCH_CAN_RUN,
+									ndev);
+			if (retval == -EPERM) {
+				dev_err(&ndev->dev,
+				    "%s -> pch_can_set_run_mode "
+				    "failed(returned %d).\n", __func__, retval);
+				break;
+			}
+			dev_dbg(&ndev->dev, "%s -> pch_can_set_set_run_mode "
+				"invoked successfully(returned %d).\n",
+				__func__, retval);
+
+		} while (false);
+	}
+
+	dev_dbg(&ndev->dev, "%s returns %d.\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_release(int handle, struct net_device *ndev)
+{
+	int retval = 0;
+
+	if (handle == 0) {
+		dev_err(&ndev->dev, "%s -> Invalid handle.\n", __func__);
+		retval = -EPERM;
+	} else {
+		do {
+			/* Stooping the CAN device. */
+			retval = pch_can_set_run_mode(handle, PCH_CAN_STOP,
+									ndev);
+
+			if (retval == -EPERM) {
+				dev_err(&ndev->dev,
+					"%s -> pch_can_set_run_mode failed"
+					"(returned %d).\n", __func__, retval);
+				break;
+			}
+			dev_dbg(&ndev->dev, "%s -> pch_can_set_run_mode invoked"
+			    " successfully(returned %d).\n", __func__, retval);
+
+			/* Disabling the interrupts. */
+			retval = pch_can_set_int_enables(handle, CAN_NONE,
+									ndev);
+
+			if (retval == -EPERM) {
+				dev_err(&ndev->dev,
+				    "%s -> pch_can_set_int_enables failed"
+				    "(returned %d).\n", __func__, retval);
+				break;
+			}
+			dev_dbg(&ndev->dev, "%s -> pch_can_set_int_enables "
+				"invoked successfully(returned %d).\n",
+				__func__, retval);
+
+			/* Disabling all the receive object. */
+			retval = pch_can_rx_disable_all(handle, ndev);
+			if (retval == -EPERM) {
+				dev_err(&ndev->dev,
+				"%s -> pch_can_rx_disable_all "
+				"failed(returned %d).\n", __func__, retval);
+				break;
+			}
+			dev_dbg(&ndev->dev,
+			    "%s -> pch_can_rx_disable_all invoked "
+			    "successfully(returned %d).\n", __func__, retval);
+
+			/* Disabling all the transmit object. */
+			retval = pch_can_tx_disable_all(handle, ndev);
+			if (retval == -EPERM) {
+				dev_err(&ndev->dev,
+				    "%s -> pch_can_tx_disable_all "
+				    "failed(returned %d).\n", __func__, retval);
+				break;
+			}
+			dev_dbg(&ndev->dev,
+			    "%s -> pch_can_tx_disable_all invoked "
+			    "successfully(returned %d).\n", __func__, retval);
+
+		} while (false);
+	}
+
+	dev_dbg(&ndev->dev, "%s returns %d.\n", __func__, retval);
+	return retval;
+}
+
+/* This function clears interrupt(s) from the CAN device. */
+static void pch_can_int_clr(int handle, u32 mask, struct net_device *ndev)
+{
+	u32 counter;
+	u32 rtr;
+	u32 if2_creq;
+
+	if ((handle != 0) && (mask != 0)) {	/* if valid
+								 parameters. */
+		/* Obtaining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		/* Clearing status interrupt. */
+		if (mask == CAN_STATUS_INT) {
+			ioread32((can->io_base + CAN_STAT_OFFSET));
+			dev_dbg(&ndev->dev,
+				"%s -> Status Interrupt cleared.\n", __func__);
+		} else if ((mask > 0) && (mask <= MAX_MSG_OBJ)) {
+			/* Clear interrupt for transmit object */
+			if (pch_msg_obj_conf[mask - 1] == MSG_OBJ_TX) {
+				/* Checking if the transmission is for remote
+								 frame. */
+				rtr = ((ioread32((can->io_base +
+							CAN_IF2_ID2_OFFSET)) &
+							CAN_ID2_DIR) == 0);
+
+				if (rtr == 1) {
+
+					dev_dbg(&ndev->dev,
+					    "%s -> Remote frame transmission "
+					    "interrupt cleared for message"
+					    "object %d.\n", __func__, mask);
+				} else {
+					dev_dbg(&ndev->dev,
+					  "%s -> Data frame transmission "
+					  "interrupt cleared for message "
+					  "object %d.\n", __func__, mask);
+				}
+
+				/* Setting CMASK for clearing interrupts for
+							 frame transmission. */
+				iowrite32((CAN_CMASK_RDWR | CAN_CMASK_CTRL |
+							CAN_CMASK_ARB),
+							(can->io_base +
+							CAN_IF2_CMASK_OFFSET));
+
+				/* Resetting the ID registers. */
+				PCH_CAN_BIT_SET((can->io_base +
+						 CAN_IF2_ID2_OFFSET),
+						(CAN_ID2_DIR |
+						 (MSK_ALL_ELEVEN << 2)));
+				iowrite32(0x0,
+					(can->io_base + CAN_IF2_ID1_OFFSET));
+
+				/* Claring NewDat, TxRqst & IntPnd */
+				PCH_CAN_BIT_CLEAR((can->io_base +
+						   CAN_IF2_MCONT_OFFSET),
+						  (CAN_IF_MCONT_NEWDAT |
+						   CAN_IF_MCONT_INTPND |
+						   CAN_IF_MCONT_TXRQXT));
+
+				iowrite32(mask,
+				       (can->io_base + CAN_IF2_CREQ_OFFSET));
+
+				counter = COUNTER_LIMIT;
+				while (counter) {
+					if2_creq = (ioread32(can->io_base +
+							CAN_IF2_CREQ_OFFSET) &
+							CAN_IF_CREQ_BUSY);
+					if (if2_creq == 0)
+						break;
+
+					counter--;
+				}
+			}
+			/* Clear interrupt for receive object */
+			else if (pch_msg_obj_conf[mask - 1] == MSG_OBJ_RX) {
+				/* Checking if the reception is for remote
+								 frame. */
+				rtr = ((ioread32((can->io_base +
+							CAN_IF2_ID2_OFFSET)) &
+							CAN_ID2_DIR) != 0);
+
+				if (rtr == 1) {	/* if remote frame. */
+					dev_dbg(&ndev->dev,
+						"%s -> Remote frame reception "
+						"interrupt cleared for message "
+						"object %d.\n", __func__, mask);
+				} else {
+					dev_dbg(&ndev->dev,
+					  "%s -> Data frame reception "
+					  "interrupt cleared for message object"
+					  "%d.\n", __func__, mask);
+				}
+
+				/* Setting CMASK for clearing the reception
+								 interrupts. */
+				iowrite32((CAN_CMASK_RDWR | CAN_CMASK_CTRL |
+							CAN_CMASK_ARB),
+							(can->io_base +
+							CAN_IF2_CMASK_OFFSET));
+
+				/* Clearing the Dir bit. */
+				PCH_CAN_BIT_CLEAR((can->io_base +
+							CAN_IF2_ID2_OFFSET),
+							CAN_ID2_DIR);
+
+				/* Clearing NewDat & IntPnd */
+				PCH_CAN_BIT_CLEAR((can->io_base +
+						   CAN_IF2_MCONT_OFFSET),
+						  (CAN_IF_MCONT_NEWDAT |
+						   CAN_IF_MCONT_INTPND));
+
+				iowrite32(mask,
+				       (can->io_base + CAN_IF2_CREQ_OFFSET));
+
+				counter = COUNTER_LIMIT;
+				while (counter) {
+					if2_creq = ioread32(can->io_base +
+							CAN_IF2_CREQ_OFFSET) &
+							CAN_IF_CREQ_BUSY;
+					if (if2_creq == 0)
+						break;
+
+					counter--;
+				}
+
+			}
+		}
+	}
+}
+
+static int pch_can_get_buffer_status(int handle)
+{
+	u32 reg_treq1;
+	u32 reg_treq2;
+	int retval = 0;
+
+	if (handle == 0) {
+		retval = -EPERM;
+	} else {
+		/* Obtaining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		/* Reading the transmission request registers. */
+		reg_treq1 = (ioread32(can->io_base + CAN_TREQ1_OFFSET) &
+							MSK_ALL_SIXTEEN);
+		reg_treq2 = ((ioread32(can->io_base + CAN_TREQ2_OFFSET) &
+					MSK_ALL_SIXTEEN) << BIT_SHIFT_SIXTEEN);
+
+		retval = (reg_treq1 | reg_treq2);
+	}
+
+	return retval;
+}
+
+static int pch_can_msg_tx(int handle, struct pch_can_msg *msg,
+			  struct net_device *ndev)
+{
+	u32 id1 = 0;
+	u32 id2 = 0;
+	u32 data_a1 = 0;
+	u32 data_a2 = 0;
+	u32 data_b1 = 0;
+	u32 data_b2 = 0;
+	u32 tx_disable_counter = 0;
+	u32 buffer_status = 0;
+	u32 tx_buffer_avail = 0;
+	u32 status;
+	u32 i;
+	u32 counter;
+	enum pch_can_run_mode run_mode;
+	int retval = 0;
+	u32 if1_creq;
+
+	if ((handle == 0) || (msg == NULL)) {
+		dev_err(&ndev->dev, "%s -> Invalid Parameter.\n", __func__);
+		retval = -EPERM;
+	}
+
+	else {
+		/* Obatining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		/* Getting the current CAN mode. */
+		pch_can_get_run_mode(handle, &run_mode, ndev);
+
+		/* If CAN is in STOP mode. */
+		if (run_mode != PCH_CAN_RUN) {
+			dev_err(&ndev->dev,
+			  "%s -> CAN stopped on transmit attempt.\n", __func__);
+			retval = -EPERM;
+		} else {
+			unsigned long flags;
+			/* Attaining the lock. */
+			spin_lock_irqsave(&can_os->tx_spinlock, flags);
+
+			/* Getting the message object status. */
+			buffer_status = (u32) pch_can_get_buffer_status(handle);
+
+			/* Getting the free transmit message object. */
+			for (i = 0;
+			     i < (pch_can_rx_buf_size + pch_can_tx_buf_size);
+									i++) {
+				if ((pch_msg_obj_conf[i] == MSG_OBJ_TX)) {
+					/* Checking whether the object is
+								enabled. */
+					pch_can_get_tx_enable(handle,
+								(i + 1),
+								&status, ndev);
+
+					if ((ENABLE == status)) {
+						if ((((buffer_status >> i) & 1)
+									== 0)) {
+							tx_buffer_avail =
+							    (i + 1);
+							break;
+						}
+					} else {
+						tx_disable_counter++;
+					}
+				}
+			}
+
+			/* If no transmit object available. */
+			if (tx_buffer_avail == 0) {
+				dev_dbg(&ndev->dev, "%s -> tx_disable_counter "
+				    "= %d.\n", __func__, tx_disable_counter);
+				/* If no object is enabled. */
+				if ((tx_disable_counter ==
+							pch_can_tx_buf_size)){
+					retval = -EPERM;
+					dev_err(&ndev->dev,
+						"%s -> All transmit buffers "
+						"are disabled.\n", __func__);
+				} else {
+					dev_err(&ndev->dev,
+					    "%s -> No transmit buffer free.\n",
+					    __func__);
+					retval = PCH_CAN_NO_TX_BUFF;
+				}
+			} else {
+				dev_dbg(&ndev->dev,
+				  "%s ->Transmit buffer obtained.\n", __func__);
+
+				/* Reading the message object from the Message
+					 RAM to the Interface register. */
+				iowrite32(CAN_CMASK_RX_TX_GET,
+					       (can->io_base +
+						CAN_IF1_CMASK_OFFSET));
+				iowrite32(tx_buffer_avail,
+					       (can->io_base +
+						CAN_IF1_CREQ_OFFSET));
+
+				/* Confirming the read. */
+				counter = COUNTER_LIMIT;
+				while (counter) {
+					if1_creq = (ioread32(can->io_base +
+							CAN_IF1_CREQ_OFFSET)) &
+							CAN_IF_CREQ_BUSY;
+					if (if1_creq == 0)
+						break;
+
+					counter--;
+				}
+				/* If Read not successful. */
+				if (counter == 0) {
+					pch_can_set_tx_enable(handle,
+								tx_buffer_avail,
+								ENABLE, ndev);
+					retval = -EPERM;
+				} else {
+					/* Setting the CMASK register. */
+					PCH_CAN_BIT_SET((can->io_base +
+							 CAN_IF1_CMASK_OFFSET),
+							CAN_CMASK_ALL);
+
+					/* If ID extended is set. */
+					if (msg->ide == 1) {
+						/* Setting 29 bit ID with XTD
+								 bit set. */
+						id1 =
+						    (msg->id & MSK_ALL_SIXTEEN);
+						id2 =
+						    ((msg->
+						      id & (MSK_ALL_THIRTEEN <<
+							    BIT_SHIFT_SIXTEEN))
+						     >> BIT_SHIFT_SIXTEEN);
+
+						id2 |= CAN_ID2_XTD;
+					} else {
+						/* Setting 11bit ID with XTD bit
+								 reset. */
+						id1 = 0;
+						id2 =
+						    ((msg->
+						      id & MSK_ALL_ELEVEN) <<
+						     BIT_SHIFT_TWO);
+					}
+					PCH_CAN_BIT_CLEAR((can->io_base +
+							   CAN_IF1_ID1_OFFSET),
+							  MSK_ALL_SIXTEEN);
+					PCH_CAN_BIT_CLEAR((can->io_base +
+							   CAN_IF1_ID2_OFFSET),
+							  (MSK_ALL_THIRTEEN |
+							   CAN_ID2_XTD));
+
+					PCH_CAN_BIT_SET((can->io_base +
+							 CAN_IF1_ID1_OFFSET),
+							id1);
+					PCH_CAN_BIT_SET((can->io_base +
+							 CAN_IF1_ID2_OFFSET),
+							id2);
+
+					/* If remote frame has to be
+							 transmitted.. */
+					if (msg->rtr == 1) {
+						PCH_CAN_BIT_CLEAR((
+							can->io_base +
+							CAN_IF1_ID2_OFFSET),
+							CAN_ID2_DIR);
+						msg->dlc = 0;
+
+						dev_dbg(&ndev->dev,
+						  "%s -> Transmitting a remote"
+						  " frame.\n", __func__);
+					} else {	/* Data frame
+							 transmission. */
+
+						msg->dlc &= MSK_ALL_FOUR;
+
+						dev_dbg(&ndev->dev,
+						  "%s -> Transmitting a data "
+						  "frame.\n", __func__);
+					}
+
+					/* Writing the data and the DLC */
+					switch (msg->dlc) {
+					case 0:
+						break;
+
+					case 1:
+						data_a1 = msg->data[0];
+						break;
+					case 2:
+						data_a1 = msg->data[0];
+						data_a1 |=
+						    (((u32) msg->
+						      data[1]) <<
+						     BIT_SHIFT_EIGHT);
+						break;
+					case 3:
+						data_a1 = msg->data[0];
+						data_a1 |=
+						    (((u32) msg->
+						      data[1]) <<
+						     BIT_SHIFT_EIGHT);
+						data_a2 = msg->data[2];
+						break;
+					case 4:
+						data_a1 = msg->data[0];
+						data_a1 |=
+						    (((u32) msg->
+						      data[1]) <<
+						     BIT_SHIFT_EIGHT);
+						data_a2 = msg->data[2];
+						data_a2 |=
+						    (((u32) msg->
+						      data[3]) <<
+						     BIT_SHIFT_EIGHT);
+						break;
+					case 5:
+						data_a1 = msg->data[0];
+						data_a1 |=
+						    (((u32) msg->
+						      data[1]) <<
+						     BIT_SHIFT_EIGHT);
+						data_a2 = msg->data[2];
+						data_a2 |=
+						    (((u32) msg->
+						      data[3]) <<
+						     BIT_SHIFT_EIGHT);
+						data_b1 = msg->data[4];
+						break;
+					case 6:
+						data_a1 = msg->data[0];
+						data_a1 |=
+						    (((u32) msg->
+						      data[1]) <<
+						     BIT_SHIFT_EIGHT);
+						data_a2 = msg->data[2];
+						data_a2 |=
+						    (((u32) msg->
+						      data[3]) <<
+						     BIT_SHIFT_EIGHT);
+						data_b1 = msg->data[4];
+						data_b1 |=
+						    (((u32) msg->
+						      data[5]) <<
+						     BIT_SHIFT_EIGHT);
+						break;
+					case 7:
+						data_a1 = msg->data[0];
+						data_a1 |=
+						    (((u32) msg->
+						      data[1]) <<
+						     BIT_SHIFT_EIGHT);
+						data_a2 = msg->data[2];
+						data_a2 |=
+						    (((u32) msg->
+						      data[3]) <<
+						     BIT_SHIFT_EIGHT);
+						data_b1 = msg->data[4];
+						data_b1 |=
+						    (((u32) msg->
+						      data[5]) <<
+						     BIT_SHIFT_EIGHT);
+						data_b2 = msg->data[6];
+						break;
+					case 8:
+					default:
+						data_a1 = msg->data[0];
+						data_a1 |=
+						    (((u32) msg->
+						      data[1]) <<
+						     BIT_SHIFT_EIGHT);
+						data_a2 = msg->data[2];
+						data_a2 |=
+						    (((u32) msg->
+						      data[3]) <<
+						     BIT_SHIFT_EIGHT);
+						data_b1 = msg->data[4];
+						data_b1 |=
+						    (((u32) msg->
+						      data[5]) <<
+						     BIT_SHIFT_EIGHT);
+						data_b2 = msg->data[6];
+						data_b2 |=
+						    (((u32) msg->
+						      data[7]) <<
+						     BIT_SHIFT_EIGHT);
+						break;
+
+					}
+
+					/* Writing the DATA registers. */
+					iowrite32(data_a1,
+						       (can->io_base +
+							CAN_IF1_DATAA1_OFFSET));
+					iowrite32(data_a2,
+						       (can->io_base +
+							CAN_IF1_DATAA2_OFFSET));
+					iowrite32(data_b1,
+						       (can->io_base +
+							CAN_IF1_DATAB1_OFFSET));
+					iowrite32(data_b2,
+						       (can->io_base +
+							CAN_IF1_DATAB2_OFFSET));
+
+					/* Updating the size of the data. */
+					PCH_CAN_BIT_CLEAR((can->io_base +
+							  CAN_IF1_MCONT_OFFSET),
+							  MSK_ALL_FOUR);
+					PCH_CAN_BIT_SET((can->io_base +
+							 CAN_IF1_MCONT_OFFSET),
+							msg->dlc);
+
+					/* Clearing IntPend, NewDat & TxRqst */
+					PCH_CAN_BIT_CLEAR((can->io_base +
+							CAN_IF1_MCONT_OFFSET),
+							(CAN_IF_MCONT_NEWDAT |
+							CAN_IF_MCONT_INTPND |
+							CAN_IF_MCONT_TXRQXT));
+
+					/* Setting NewDat, TxRqst bits */
+					PCH_CAN_BIT_SET((can->io_base +
+							 CAN_IF1_MCONT_OFFSET),
+							(CAN_IF_MCONT_NEWDAT |
+							 CAN_IF_MCONT_TXRQXT));
+
+					/* Writing the updation to the Message
+								 object. */
+					iowrite32(tx_buffer_avail,
+						       (can->io_base +
+							CAN_IF1_CREQ_OFFSET));
+
+					/* Confirming the updation. */
+					counter = COUNTER_LIMIT;
+					while (counter) {
+						if1_creq = (ioread32(
+							can->io_base +
+							CAN_IF1_CREQ_OFFSET)) &
+							CAN_IF_CREQ_BUSY;
+						if (if1_creq == 0)
+							break;
+
+						counter--;
+					}
+
+					if ((counter == 0)) {
+						retval = -EPERM;
+					} else {
+						dev_dbg(&ndev->dev,
+						  "%s -> Updation of transmit "
+						  "buffer successful.\n"
+						  "Message object enabled "
+						  "for transmission.\n",
+						  __func__);
+					}
+
+				}	/* if message read object successful */
+			}	/* if transmit buffer available */
+
+			/* Releasing the lock. */
+			spin_unlock_irqrestore(&can_os->tx_spinlock, flags);
+		}		/* if device in run mode */
+	}			/* if parameters valid */
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %d.\n", __func__, retval);
+	return retval;
+}
+
+/* This function gets a pending message from the CAN device. */
+static int pch_can_rx_dequeue(int handle, struct pch_can_msg *msg,
+			      u32 buff_num, struct net_device *ndev)
+{
+	s32 i;
+	u32 reg;
+	int retval = -EPERM;
+
+	if ((handle == 0) || (msg == NULL)) {
+		dev_err(&ndev->dev, "%s -> Invalid Parameter.\n", __func__);
+	} else if ((pch_msg_obj_conf[buff_num - 1] != MSG_OBJ_RX) ||
+		 (buff_num > (pch_can_rx_buf_size + pch_can_tx_buf_size))) {
+		/* invalid buffer number. */
+		dev_err(&ndev->dev, "%s -> Invalid Buffer number.\n", __func__);
+	} else {
+		/* Obtaining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) handle;
+
+		msg->ide = 0;
+		msg->id = 0;
+		msg->dlc = 0;
+		for (i = 0; i < PCH_CAN_MSG_DATA_LEN;)
+			msg->data[i++] = 0;
+
+		/* Read the ID type. */
+		msg->ide = ((ioread32(can->io_base + CAN_IF2_ID2_OFFSET)) &
+					CAN_ID2_XTD) >> BIT_SHIFT_FOURTEEN;
+
+		/* Extracting the ID. */
+		if (msg->ide == 1) {	/* Extended 29bit ID. */
+			msg->id = (ioread32(can->io_base +
+					CAN_IF2_ID1_OFFSET) & MSK_ALL_SIXTEEN);
+			msg->id |= (((ioread32(can->io_base +
+					CAN_IF2_ID2_OFFSET)) &
+					MSK_ALL_THIRTEEN) << BIT_SHIFT_SIXTEEN);
+		} else {	/* Standard 11bit ID. */
+
+			msg->id = (((ioread32(can->io_base +
+						CAN_IF2_ID2_OFFSET)) &
+						(MSK_ALL_ELEVEN <<
+						BIT_SHIFT_TWO)) >>
+						BIT_SHIFT_TWO);
+		}
+
+		/* Getting the size of the data and the Remote frame bit. */
+		if (msg->rtr == 1) {
+			msg->dlc = 0;
+
+			dev_dbg(&ndev->dev,
+			    "%s -> Remote frame read with message id: %x.\n",
+			    __func__, msg->id);
+		} else {
+			msg->dlc = ((ioread32(can->io_base +
+						CAN_IF2_MCONT_OFFSET)) &
+						MSK_ALL_FOUR);
+
+			dev_dbg(&ndev->dev,
+			    "%s -> Data frame read with message id: %x.\n",
+			    __func__, msg->id);
+		}
+
+		/* Reading back the data. */
+		switch (msg->dlc) {
+		case 0:
+			break;
+
+		case 1:
+			reg = ioread32(can->io_base + CAN_IF2_DATAA1_OFFSET);
+			msg->data[0] = reg & MSK_ALL_EIGHT;
+			break;
+
+		case 2:
+			reg = ioread32(can->io_base + CAN_IF2_DATAA1_OFFSET);
+			msg->data[0] = reg & MSK_ALL_EIGHT;
+			msg->data[1] =
+			    ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+			     >> BIT_SHIFT_EIGHT);
+			break;
+
+		case 3:
+			reg = ioread32(can->io_base + CAN_IF2_DATAA1_OFFSET);
+			msg->data[0] = reg & MSK_ALL_EIGHT;
+			msg->data[1] =
+			    ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+			     >> BIT_SHIFT_EIGHT);
+
+			reg = ioread32(can->io_base + CAN_IF2_DATAA2_OFFSET);
+			msg->data[2] = reg & MSK_ALL_EIGHT;
+			break;
+
+		case 4:
+			reg = ioread32(can->io_base + CAN_IF2_DATAA1_OFFSET);
+			msg->data[0] = reg & MSK_ALL_EIGHT;
+			msg->data[1] =
+			    ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+			     >> BIT_SHIFT_EIGHT);
+
+			reg = ioread32(can->io_base + CAN_IF2_DATAA2_OFFSET);
+			msg->data[2] = reg & MSK_ALL_EIGHT;
+			msg->data[3] =
+			    ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+			     >> BIT_SHIFT_EIGHT);
+			break;
+
+		case 5:
+			reg = ioread32(can->io_base + CAN_IF2_DATAA1_OFFSET);
+			msg->data[0] = reg & MSK_ALL_EIGHT;
+			msg->data[1] =
+			    ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+			     >> BIT_SHIFT_EIGHT);
+
+			reg = ioread32(can->io_base + CAN_IF2_DATAA2_OFFSET);
+			msg->data[2] = reg & MSK_ALL_EIGHT;
+			msg->data[3] =
+			    ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+			     >> BIT_SHIFT_EIGHT);
+
+			reg = ioread32(can->io_base + CAN_IF2_DATAB1_OFFSET);
+			msg->data[4] = reg & MSK_ALL_EIGHT;
+			break;
+
+		case 6:
+			reg = ioread32(can->io_base + CAN_IF2_DATAA1_OFFSET);
+			msg->data[0] = reg & MSK_ALL_EIGHT;
+			msg->data[1] =
+			    ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+			     >> BIT_SHIFT_EIGHT);
+
+			reg = ioread32(can->io_base + CAN_IF2_DATAA2_OFFSET);
+			msg->data[2] = reg & MSK_ALL_EIGHT;
+			msg->data[3] =
+			    ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+			     >> BIT_SHIFT_EIGHT);
+
+			reg = ioread32(can->io_base + CAN_IF2_DATAB1_OFFSET);
+			msg->data[4] = reg & MSK_ALL_EIGHT;
+			msg->data[5] =
+			    ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+			     >> BIT_SHIFT_EIGHT);
+			break;
+
+		case 7:
+			reg = ioread32(can->io_base + CAN_IF2_DATAA1_OFFSET);
+			msg->data[0] = reg & MSK_ALL_EIGHT;
+			msg->data[1] =
+			    ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+			     >> BIT_SHIFT_EIGHT);
+
+			reg = ioread32(can->io_base + CAN_IF2_DATAA2_OFFSET);
+			msg->data[2] = reg & MSK_ALL_EIGHT;
+			msg->data[3] =
+			    ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+			     >> BIT_SHIFT_EIGHT);
+
+			reg = ioread32(can->io_base + CAN_IF2_DATAB1_OFFSET);
+			msg->data[4] = reg & MSK_ALL_EIGHT;
+			msg->data[5] =
+			    ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+			     >> BIT_SHIFT_EIGHT);
+
+			reg = ioread32(can->io_base + CAN_IF2_DATAB2_OFFSET);
+			msg->data[6] = reg & MSK_ALL_EIGHT;
+			break;
+
+		case 8:
+		default:
+			reg = ioread32(can->io_base + CAN_IF2_DATAA1_OFFSET);
+			msg->data[0] = reg & MSK_ALL_EIGHT;
+			msg->data[1] =
+			    ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+			     >> BIT_SHIFT_EIGHT);
+
+			reg = ioread32(can->io_base + CAN_IF2_DATAA2_OFFSET);
+			msg->data[2] = reg & MSK_ALL_EIGHT;
+			msg->data[3] =
+			    ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+			     >> BIT_SHIFT_EIGHT);
+
+			reg = ioread32(can->io_base + CAN_IF2_DATAB1_OFFSET);
+			msg->data[4] = reg & MSK_ALL_EIGHT;
+			msg->data[5] =
+			    ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+			     >> BIT_SHIFT_EIGHT);
+
+			reg = ioread32(can->io_base + CAN_IF2_DATAB2_OFFSET);
+			msg->data[6] = reg & MSK_ALL_EIGHT;
+			msg->data[7] =
+			    ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+			     >> BIT_SHIFT_EIGHT);
+
+			break;
+		}
+		retval = 0;
+	}
+
+	dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_reset(struct pch_can_os *can_os)
+{
+	int retval = 0;
+
+	if ((can_os == NULL)) {
+		retval = -EPERM;
+	} else {
+		/* Obtaining the remap address for access. */
+		struct can_hw *can = (struct can_hw *) can_os->can;
+
+		/* write to sw reset register */
+		iowrite32(1, (can->io_base + CAN_SRST_OFFSET));
+		iowrite32(0, (can->io_base + CAN_SRST_OFFSET));
+
+	}
+	return retval;
+}
+
+static irqreturn_t pch_can_handler(int irq, void *dev_id)
+{
+	irqreturn_t retval = IRQ_NONE;
+	u32 int_stat;
+	struct pch_can_os *can_os = (struct pch_can_os *) dev_id;
+	dev_dbg(&can_os->ndev->dev, "%s -> Invoked.\n", __func__);
+
+	int_stat = pch_can_int_pending(can_os->can);
+
+	dev_dbg(&can_os->ndev->dev,
+	  "%s -> pch_can_int_pending returned value: %x\n", __func__, int_stat);
+
+	if ((can_os != NULL) && (int_stat > 0)) {
+		can_os->int_stat = int_stat;
+		(*can_os->can_callback) (can_os);
+
+		dev_dbg(&can_os->ndev->dev,
+		   "%s -> Callback function invoked successfully.\n", __func__);
+
+		retval = IRQ_HANDLED;
+	}
+	return retval;
+}
+
+static void pch_can_log_message(u32 status, struct net_device *ndev)
+{
+	static int cnt;
+
+	switch ((status & MSK_ALL_THREE)) {
+
+	case 0:
+		dev_dbg(&ndev->dev, "%s ->  No Error\n", __func__);
+		break;
+	case 1:
+		dev_err(&ndev->dev, "%s -> Stuff Error\n", __func__);
+		break;
+	case 2:
+		dev_err(&ndev->dev, "%s -> Form Error.\n", __func__);
+		break;
+	case 3:
+		if (cnt % 200 == 0)
+			dev_err(&ndev->dev, "%s -> Ack Error\n", __func__);
+		cnt++;
+		break;
+	case 4:
+		dev_err(&ndev->dev, "%s -> Bit 1 Error\n", __func__);
+		break;
+	case 5:
+		dev_err(&ndev->dev, "%s -> Bit 0 Error.\n", __func__);
+		break;
+	case 6:
+		dev_err(&ndev->dev, "%s -> Crc Error\n", __func__);
+		break;
+	case 7:
+		dev_err(&ndev->dev, "%s -> Undefined Error\n", __func__);
+		break;
+	default:
+		break;
+	}
+}
+
+static void pch_can_entcb(void (*pch_can_cb) (struct pch_can_os *),
+			  struct pch_can_os *p_can_os, struct net_device *ndev)
+{
+	if ((pch_can_cb != NULL) && (p_can_os != NULL)) {
+		p_can_os->can_callback = pch_can_cb;
+		dev_dbg(&ndev->dev,
+		    "%s -> Callback function set successful.\n", __func__);
+	} else {
+		dev_err(&ndev->dev,
+		    "%s -> Callback function set unsuccessful.\n", __func__);
+	}
+}
+
+static void pch_can_callback(struct pch_can_os *can_os)
+{
+	u32 int_stat;
+	u32 reg;
+	u32 reg_stat;
+	u32 counter;
+	struct pch_can_msg receive_msg;
+	struct can_hw *can = (struct can_hw *) (can_os->can);
+	int retval = 0;
+	u32 if2_creq;
+	enum pch_can_auto_restart restart_mode = 0;
+
+
+	/* Get the interrupt status */
+	int_stat = can_os->int_stat;
+	can_os->int_stat = 0;
+
+	/* Checking for status interrupt */
+	if (int_stat == CAN_STATUS_INT) {
+		/* Reading of the CANSTAT register. */
+		reg_stat = ioread32((can->io_base + CAN_STAT_OFFSET));
+		reg_stat = reg_stat & MSK_ALL_EIGHT;
+		dev_dbg(&can_os->ndev->dev,
+			"%s -> Status Register: %x.\n", __func__, reg_stat);
+
+		/* If recovered from Bus-Off interrupt. */
+		if ((reg_stat == 0) && (can_os->bus_off_interrupt == 1)) {
+			can_os->bus_off_interrupt = 0;
+			pch_can_tx_enable_all(can_os->can, can_os->ndev);
+			pch_can_rx_enable_all(can_os->can, can_os->ndev);
+
+			dev_err(&can_os->ndev->dev,
+				"%s -> Bus off stage recovered.\n", __func__);
+		} else {
+			/* Bus off interrupt. */
+			if (reg_stat & ((u32) 1 << BIT_SHIFT_SEVEN)) {
+				if (can_os->bus_off_interrupt == 0) {
+
+					dev_err(&can_os->ndev->dev,
+						"%s -> Bus off "
+						"interrupt.\n", __func__);
+
+					pch_can_tx_disable_all(can_os->can,
+								can_os->ndev);
+					pch_can_rx_disable_all(can_os->can,
+								can_os->ndev);
+
+					pch_can_get_restart_mode(can_os->can,
+						&restart_mode, can_os->ndev);
+
+					if (restart_mode == CAN_AUTO) {
+						can_os->bus_off_interrupt = 1;
+						pch_can_set_run_mode(
+							can_os->can,
+							PCH_CAN_RUN,
+							can_os->ndev);
+						dev_dbg(&can_os->ndev->dev,
+						    "%s -> Device restarted.\n",
+						    __func__);
+					}
+				}
+			}
+			/* EWarn interrupt. */
+			if ((reg_stat & ((u32) 1 << BIT_SHIFT_SIX)) != 0) {
+				dev_info(&can_os->ndev->dev,
+					"%s -> EWarn interrupt.\n", __func__);
+			}
+			/* EPass interrupt. */
+			if ((reg_stat & ((u32) 1 << BIT_SHIFT_FIVE)) != 0) {
+				dev_dbg(&can_os->ndev->dev,
+					"%s -> EPass interrupt.\n", __func__);
+			}
+			/* RxOK interrupt. */
+			if ((reg_stat & ((u32) 1 << BIT_SHIFT_FOUR)) != 0) {
+				dev_dbg(&can_os->ndev->dev,
+					"%s -> RxOK interrupt.\n", __func__);
+				reg_stat =
+				    reg_stat & ~((u32) 1 << BIT_SHIFT_FOUR);
+			}
+			/* TxOK interrupt */
+			if ((reg_stat & ((u32) 1 << BIT_SHIFT_THREE)) != 0) {
+				dev_dbg(&can_os->ndev->dev,
+					"%s -> TxOK interrupt.\n", __func__);
+				reg_stat =
+				    reg_stat & ~((u32) 1 << BIT_SHIFT_THREE);
+			}
+			/* Error status */
+			pch_can_log_message((reg_stat & MSK_ALL_THREE),
+								can_os->ndev);
+			reg_stat = reg_stat & ~(MSK_ALL_THREE);
+
+			/* Clearing status register interrupt bits. */
+			iowrite32(reg_stat,
+					(can->io_base + CAN_STAT_OFFSET));
+
+			int_stat = pch_can_int_pending(can_os->can);
+		}
+	}
+
+	/* Message object interrupt. */
+	if ((int_stat > 0) && (int_stat <= MAX_MSG_OBJ)) {
+		/* Reading the messsage object from the Message RAM to the
+							 interface registers. */
+		iowrite32(CAN_CMASK_RX_TX_GET,
+			       (can->io_base + CAN_IF2_CMASK_OFFSET));
+		iowrite32((int_stat),
+			       (can->io_base + CAN_IF2_CREQ_OFFSET));
+
+		/* Confirming the read. */
+		counter = COUNTER_LIMIT;
+		while (counter) {
+			if2_creq = (ioread32(can->io_base +
+						CAN_IF2_CREQ_OFFSET)) &
+						CAN_IF_CREQ_BUSY;
+
+			if (if2_creq == 0)
+				break;
+
+			counter--;
+		}
+
+		if (counter > 0) {	/* If read successful. */
+			/* Reading the MCONT register. */
+			reg = ioread32((can->io_base +
+							CAN_IF2_MCONT_OFFSET));
+			reg &= MSK_ALL_SIXTEEN;
+
+			/* If MsgLost bit set. */
+			if ((reg & CAN_IF_MCONT_MSGLOST) != 0) {
+				PCH_CAN_BIT_CLEAR((can->io_base +
+						   CAN_IF2_MCONT_OFFSET),
+						  CAN_IF_MCONT_MSGLOST);
+
+				dev_err(&can_os->ndev->dev,
+				    "%s -> Message object %d has "
+				    "been overwritten.\n", __func__, int_stat);
+			}
+
+			/* Read the direction bit for determination of remote
+						 frame during reception. */
+			receive_msg.rtr = ((ioread32((can->io_base +
+							CAN_IF2_ID2_OFFSET)) &
+							CAN_ID2_DIR) != 0);
+
+			/* Clearing interrupts. */
+			pch_can_int_clr(can_os->can, int_stat, can_os->ndev);
+			dev_dbg(&can_os->ndev->dev,
+			    "%s -> pch_can_int_clr invoked successfully.\n",
+			    __func__);
+
+			/* Hanlde reception interrupt */
+			if (pch_msg_obj_conf[int_stat - 1] == MSG_OBJ_RX) {
+				/* If new data arrived */
+				if ((reg & CAN_IF_MCONT_NEWDAT) != 0) {
+					/* Reading the message object content.*/
+					retval =
+					    pch_can_rx_dequeue(can_os->can,
+							&receive_msg,
+							int_stat, can_os->ndev);
+
+					if (retval == 0) {
+						struct sk_buff *skb;
+						struct can_frame *cf;
+						struct net_device_stats *stats;
+						stats = &(can_os->ndev->stats);
+						/* create zero'ed CAN frame
+								 buffer */
+						skb = alloc_can_skb
+							(can_os->ndev, &cf);
+						if (skb == NULL)
+							return;
+
+						if (receive_msg.ide) {
+							cf->can_id =
+							    ((receive_msg.id) &
+							    0x1fffffff) |
+							    0x80000000;
+						} else { /* Standard*/
+							cf->can_id =
+							    ((receive_msg.id) &
+							    0x00000fff);
+						}
+						if (receive_msg.rtr)
+							cf->can_id |=
+								0x40000000;
+						cf->can_dlc = receive_msg.dlc;
+						memcpy(cf->data,
+							receive_msg.data, 8);
+						netif_rx(skb);
+						stats->rx_packets++;
+						stats->rx_bytes += cf->can_dlc;
+
+					}
+					dev_dbg(&can_os->ndev->dev,
+					  "%s -> Reception interrupt handled "
+					  "for receive message object %u.\n",
+					  __func__, int_stat);
+				}
+
+			}
+			/* Hanlde transmission interrupt */
+			else if (pch_msg_obj_conf[int_stat - 1] == MSG_OBJ_TX) {
+				can_get_echo_skb(can_os->ndev, 0);
+				netif_wake_queue(can_os->ndev);
+
+				dev_dbg(&can_os->ndev->dev,
+				  "%s -> Transmission interrupt handled for "
+				  "transmit message object %u.\n",
+				  __func__, int_stat);
+			}
+		}
+	}
+}
+
+static void pch_can_start(struct net_device *ndev)
+{
+	struct pch_can_priv *priv = netdev_priv(ndev);
+
+	pch_can_reset(priv->pch_can_os_p);
+
+	return;
+}
+
+static int pch_can_do_set_mode(struct net_device *ndev, enum can_mode mode)
+{
+	int ret = 0;
+
+	switch (mode) {
+	case CAN_MODE_START:
+		pch_can_start(ndev);
+		netif_wake_queue(ndev);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+static int pch_can_get_state(const struct net_device *ndev,
+			     enum can_state *state)
+{
+	struct pch_can_priv *priv = netdev_priv(ndev);
+
+	*state = priv->can.state;
+	return 0;
+}
+
+static int get_baud_id(int baud_bps)
+{
+	int id;
+	switch (baud_bps) {
+	case 10000:/* 10kbps*/
+		id = PCH_CAN_BAUD_10;
+		break;
+	case 20000:
+		id = PCH_CAN_BAUD_20;
+		break;
+	case 50000:
+		id = PCH_CAN_BAUD_50;
+		break;
+	case 125000:
+		id = PCH_CAN_BAUD_125;
+		break;
+	case 250000:
+		id = PCH_CAN_BAUD_250;
+		break;
+	case 500000:
+		id = PCH_CAN_BAUD_500;
+		break;
+	case 800000:
+		id = PCH_CAN_BAUD_800;
+		break;
+	case 1000000:
+		id = PCH_CAN_BAUD_1000;
+		break;
+	default:
+		id = -1;
+	}
+	return id;
+}
+
+static int pch_set_bittiming(struct net_device *ndev)
+{
+	struct pch_can_priv *priv = netdev_priv(ndev);
+	struct pch_can_os *dev_can_os = priv->pch_can_os_p;
+	const struct can_bittiming *bt = &priv->can.bittiming;
+	struct pch_can_timing pch_can_timing_data;
+	int baurate_id;
+	enum pch_can_run_mode curr_mode;
+	int retval;
+
+	memset(&pch_can_timing_data, 0, sizeof(pch_can_timing_data));
+	pch_can_timing_data.bitrate = bt->bitrate/1000; /* bps to Kbps */
+	pch_can_timing_data.cfg_bitrate = (bt->tq) / (1000000/pch_can_clock);
+							/* Tq to BRP */
+	pch_can_timing_data.cfg_tseg1 = bt->phase_seg1;
+	pch_can_timing_data.cfg_tseg2 = bt->phase_seg2;
+	pch_can_timing_data.cfg_sjw = bt->sjw;
+	pch_can_timing_data.smpl_mode = bt->sample_point;
+	pch_can_timing_data.edge_mode = 0;
+
+	pch_can_get_run_mode(dev_can_os->can,
+				   &curr_mode, ndev);
+	if (curr_mode == PCH_CAN_RUN)
+		pch_can_set_run_mode(dev_can_os->can,
+					   PCH_CAN_STOP, ndev);
+
+	baurate_id = get_baud_id(bt->bitrate);
+	if (baurate_id == -1)
+		retval = pch_can_set_baud_custom(dev_can_os->can,
+							 &pch_can_timing_data);
+	else
+		retval = pch_can_set_baud_simple(dev_can_os->can, baurate_id);
+	if (curr_mode == PCH_CAN_RUN)
+		pch_can_set_run_mode(dev_can_os->can,
+					   PCH_CAN_RUN, ndev);
+
+	return 0;
+}
+
+static int pch_open(struct net_device *ndev)
+{
+	int err;
+	int retval;
+	int ret;
+	struct pch_can_priv *priv = netdev_priv(ndev);
+	struct pch_can_os *dev_can_os = priv->pch_can_os_p;
+
+	ret = mutex_lock_interruptible(&pch_can_mutex);
+	if (ret)
+		return -ERESTARTSYS;
+
+	retval = pch_can_open(dev_can_os->can,
+			      PCH_CAN_ACTIVE, PCH_CAN_FIXED_PRIORITY, ndev);
+	if (retval != 0) {
+		dev_err(&ndev->dev,
+			"%s -> pch_can_open failed (returned %d).\n",
+			__func__, retval);
+	} else {
+		dev_dbg(&ndev->dev,
+		    "%s -> pch_can_open invoked successfully (returned %d).\n",
+		    __func__, retval);
+
+		dev_can_os->rx_fifo = create_can_fifo(NUM_NODES, ndev);
+
+		if (!(dev_can_os->rx_fifo)) {
+			dev_err(&ndev->dev, "%s -> create_can_fifo failed.\n",
+								__func__);
+
+			pch_can_release(dev_can_os->can, ndev);
+			dev_dbg(&ndev->dev,
+				"%s -> pch_can_release invoked successfully.\n",
+				__func__);
+
+			retval = -EPERM;
+		} else {
+			dev_dbg(&ndev->dev,
+				"%s -> create_can_fifo invoked successfully.\n",
+				__func__);
+
+			/* Registering the callback function for
+						 interrupt handling. */
+			pch_can_entcb(pch_can_callback, dev_can_os, ndev);
+			dev_dbg(&ndev->dev,
+				"%s -> pch_can_entcb invoked successfully.\n",
+				__func__);
+
+			err = pci_enable_msi(dev_can_os->dev);
+			if (err != 0) {
+				priv->have_msi = 0;
+				dev_err(&ndev->dev, "Unable to allocate MSI "
+						"interrupt Error: %d\n", err);
+
+			} else {
+				priv->have_msi = 1;
+			}
+
+			/* Update IRQ value */
+			dev_can_os->irq = dev_can_os->dev->irq;
+			ndev->irq = dev_can_os->dev->irq;
+
+			/* Regsitering the interrupt. */
+			retval =
+			    request_irq(dev_can_os->dev->irq,
+					pch_can_handler, IRQF_SHARED,
+					ndev->name, dev_can_os
+			    );
+
+			if (retval != 0) {
+				pch_can_release(dev_can_os->can, ndev);
+				delete_can_fifo(dev_can_os->rx_fifo, ndev);
+				dev_can_os->rx_fifo = 0;
+				dev_can_os->can_callback = NULL;
+
+				dev_err(&ndev->dev,
+					"%s -> request_irq failed on irq %d"
+					"(returned %d).\n",
+					__func__, dev_can_os->irq, retval);
+			} else {
+				dev_dbg(&ndev->dev, "%s -> request_irq invoked "
+					"successfully(returned %d).\n",
+					__func__, retval);
+
+				/* Assuming that no bus off
+							 interrupt. */
+				dev_can_os->bus_off_interrupt = 0;
+				dev_can_os->write_wait_flag = 0;
+
+				/* Setting the block mode. */
+				dev_can_os->block_mode = 1;
+
+				dev_can_os->opened = 1;
+
+				/* Storing the can structure for further
+								 use. */
+				retval = 0;
+			}
+		}
+	}
+
+	/* Open common can device */
+	err = open_candev(ndev);
+	if (err) {
+		mutex_unlock(&pch_can_mutex);
+		dev_err(ndev->dev.parent, "open_candev() failed %d\n", err);
+		free_irq(ndev->irq, dev_can_os);
+		return err;
+	}
+
+	netif_start_queue(ndev);
+
+	mutex_unlock(&pch_can_mutex);
+	return 0;
+}
+
+static int pch_close(struct net_device *ndev)
+{
+	struct pch_can_priv *priv = netdev_priv(ndev);
+	struct pch_can_os *can_os = priv->pch_can_os_p;
+
+	netif_stop_queue(ndev);
+	close_candev(ndev);
+	free_irq(ndev->irq, can_os);
+	if (priv->have_msi != 0)
+		pci_disable_msi(can_os->dev);
+
+	delete_can_fifo(can_os->rx_fifo, ndev);
+	pch_can_release(can_os->can, ndev);
+	can_os->opened = 0;
+	can_os->rx_fifo = 0;
+	can_os->can_callback = NULL;
+
+	return 0;
+}
+
+static netdev_tx_t pch_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+	int err;		/* error variable. */
+	int ret;
+	struct pch_can_msg msg;	/* The message object for writing. */
+	struct pch_can_priv *priv = netdev_priv(ndev);
+	struct pch_can_os *can_os = priv->pch_can_os_p;
+	struct can_frame *canframe_dat = (struct can_frame *)skb->data;
+	struct net_device_stats *stats = &ndev->stats;
+
+	ret = mutex_lock_interruptible(&pch_can_mutex);
+	if (ret)
+		return -ERESTARTSYS;
+
+	/* Translate CAN core format to CAN PCH's HW format */
+	memset(&msg, 0, sizeof(msg));
+	msg.ide = canframe_dat->can_id & 0x80000000;
+	if (canframe_dat->can_id & 0x80000000) {
+		msg.ide = 1;
+		msg.id =  canframe_dat->can_id & 0x1fffffff;/* Extended
+								Message */
+	} else {
+		msg.ide = 0;
+		msg.id =  canframe_dat->can_id & 0x00000fff;/* Standard
+								Message */
+
+	}
+
+	msg.dlc = canframe_dat->can_dlc;
+	memcpy(&msg.data, canframe_dat->data, 8);
+
+	if (canframe_dat->can_id & 0x40000000)
+		msg.rtr = 1;
+	else
+		msg.rtr = 0;
+
+	/* If device suspended. */
+	if ((can_os->is_suspending) == 1) {
+		dev_err(&ndev->dev,
+				"%s -> Device is in suspend mode.\n", __func__);
+		dev_dbg(&ndev->dev, "%s returns %d\n", __func__, -EAGAIN);
+		err = -EAGAIN;
+		goto err_out;
+	}
+
+	can_put_echo_skb(skb, ndev, 0);
+	err = pch_can_msg_tx(can_os->can, &msg, ndev);
+
+	if ((err != 0)) {
+		/* Transmission failed due to unavailability of transmit object
+						 and it is block mode. */
+		if ((err == PCH_CAN_NO_TX_BUFF) && (can_os->block_mode == 1)) {
+			dev_dbg(&ndev->dev, "%s -> Waiting for "
+					"transmit message object.\n", __func__);
+
+			/* Transmitting again. */
+			err = pch_can_msg_tx(can_os->can, &msg, ndev);
+
+			/* If again error. */
+			if (err != 0) {
+				dev_err(&ndev->dev,
+				    "%s -> Transmit failed after 2 attempts.\n",
+				    __func__);
+				dev_dbg(&ndev->dev, "%s returns %d\n",
+							__func__, -EPERM);
+				err = -EPERM;
+				goto err_out;
+			}
+		} else {	/* If failed due to some other reasons. */
+			dev_err(&ndev->dev,
+			    "%s -> Write from CAN device failed %d.\n",
+			    __func__, -EIO);
+			dev_dbg(&ndev->dev, "%s returns %d\n", __func__, -EIO);
+			err = -EIO;
+			goto err_out;
+		}
+	}
+	dev_dbg(&ndev->dev,
+		"%s -> Message send for transmission successfully.\n"
+		"The transmitted Message is :\n"
+		"Msg ID   : 0x%x\n"
+		"EXT ID   : %hu\n"
+		"Msg Size : %hu\n"
+		"Rment    : %hu\n"
+		"Dat Byt1 : 0x%x\n"
+		"Dat Byt2 : 0x%x\n"
+		"Dat Byt3 : 0x%x\n"
+		"Dat Byt4 : 0x%x\n"
+		"Dat Byt5 : 0x%x\n"
+		"Dat Byt6 : 0x%x\n"
+		"Dat Byt7 : 0x%x\n"
+		"Dat Byt8 : 0x%x\n"
+		"Write from CAN device successful ( returns %d).",
+		__func__, msg.id, msg.ide, msg.dlc, msg.rtr, msg.data[0],
+		msg.data[1], msg.data[2], msg.data[3], msg.data[4], msg.data[5],
+		msg.data[6], msg.data[7], sizeof(struct pch_can_msg));
+
+	stats->tx_bytes += canframe_dat->can_dlc;
+	stats->tx_packets++;
+
+	mutex_unlock(&pch_can_mutex);
+	return NETDEV_TX_OK;
+
+err_out:
+	mutex_unlock(&pch_can_mutex);
+	return err;
+}
+
+static const struct net_device_ops pch_can_netdev_ops = {
+	.ndo_open		= pch_open,
+	.ndo_stop		= pch_close,
+	.ndo_start_xmit		= pch_xmit,
+};
+
+static void __devexit pch_can_remove(struct pci_dev *pdev)
+{
+	struct net_device *ndev = platform_get_drvdata(pdev);
+	struct pch_can_priv *priv = netdev_priv(ndev);
+	struct pch_can_os *can_os = priv->pch_can_os_p;
+
+	unregister_candev(ndev);
+	pch_can_destroy(can_os->can, ndev);
+	pci_iounmap(pdev, (void *)priv->base);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	free_candev(priv->ndev);
+	can_free_echo_skb(ndev, 0);
+	platform_set_drvdata(pdev, NULL);
+}
+
+#ifdef CONFIG_PM
+static int pch_can_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	int i;			/* Counter variable. */
+	int retval;		/* Return value. */
+/*      struct pch_can_os *can_os = pdev->dev.driver_data; */
+	struct pch_can_os *can_os =
+			(struct pch_can_os *) dev_get_drvdata(&pdev->dev);
+
+	/* If the device is opened get the current run mode. */
+	if (can_os->opened == 1) {
+		/* Save the Run Mode. */
+		pch_can_get_run_mode(can_os->can, &(can_os->run_mode),
+								can_os->ndev);
+	}
+
+	/* Stop the CAN controller */
+	pch_can_set_run_mode(can_os->can, PCH_CAN_STOP, can_os->ndev);
+
+	/* Indicate that we are aboutto/in suspend */
+	can_os->is_suspending = 1;
+
+	if (can_os->opened == 1) {
+		u32 buf_stat;	/* Variable for reading the transmit buffer
+								 status. */
+		u32 counter = 0xFFFFFF;
+
+		/*
+		   Waiting for all transmission to complete.
+		   This is done by checking the TXQST pending
+		    register. The loop teriminates when no
+		    transmission is pending.
+		 */
+		while (counter) {
+			buf_stat = pch_can_get_buffer_status(can_os->can);
+			if (buf_stat == 0)
+				break;
+
+			counter--;
+		}
+
+		if (counter > 0) {
+			dev_dbg(&pdev->dev,
+			    "%s -> No transmission is pending.\n", __func__);
+		} else {
+			dev_err(&pdev->dev,
+				"%s -> Transmission time out.\n", __func__);
+		}
+
+		/* Save interrupt configuration and then disable them */
+		pch_can_get_int_enables(can_os->can,
+					      &(can_os->int_enables));
+		pch_can_set_int_enables(can_os->can, CAN_DISABLE, can_os->ndev);
+
+		/* Save Tx buffer enable state */
+		for (i = 0; i < (pch_can_tx_buf_size + pch_can_rx_buf_size);
+									i++) {
+			if (pch_msg_obj_conf[i] == MSG_OBJ_TX) {
+				/* Here i is the index, however (i+1) is object
+								 number. */
+				pch_can_get_tx_enable(can_os->can,
+							(i + 1),
+							&(can_os->tx_enable[i]),
+							can_os->ndev);
+			}
+		}
+
+		/* Disable all Transmit buffers */
+		pch_can_tx_disable_all(can_os->can, can_os->ndev);
+
+		/* Save Rx buffer enable state */
+		for (i = 0; i < (pch_can_tx_buf_size + pch_can_rx_buf_size);
+									i++) {
+			if (pch_msg_obj_conf[i] == MSG_OBJ_RX) {
+				/* Here i is the index, however (i+1) is object
+								 number. */
+
+				pch_can_get_rx_enable(can_os->can,
+							(i + 1),
+							&(can_os->rx_enable[i]),
+							can_os->ndev);
+				pch_can_get_rx_buffer_link(can_os->can,
+							(i + 1),
+							&(can_os->rx_link[i]),
+							can_os->ndev);
+
+				/* Save Rx Filters */
+				can_os->rx_filter[i].num = (i + 1);
+				pch_can_get_rx_filter(can_os->can,
+							&(can_os->rx_filter[i]),
+							can_os->ndev);
+			}
+		}
+
+		/* Disable all Receive buffers */
+		pch_can_rx_disable_all(can_os->can, can_os->ndev);
+
+		/* Save Context */
+		pch_can_get_baud(can_os->can, &(can_os->timing));
+								/* Timing. */
+		pch_can_get_listen_mode(can_os->can,
+					&(can_os->listen_mode), can_os->ndev);
+							/* Listen mode  */
+		pch_can_get_arbiter_mode(can_os->can,
+					&(can_os->arbiter_mode), can_os->ndev);
+							/* Arbiter mode */
+
+	}
+
+	retval = pci_save_state(pdev);
+
+	if (retval != 0) {
+		/* Indicate that we have not suspended */
+		can_os->is_suspending = 0;
+
+		dev_err(&pdev->dev,
+			"%s -> pci_save_state failed(returned %d).\n",
+			__func__, retval);
+	} else {
+		dev_dbg(&pdev->dev,
+			"%s -> pci_save_state successful(returned %d).\n",
+			__func__, retval);
+
+		pci_enable_wake(pdev, PCI_D3hot, 0);
+		dev_dbg(&pdev->dev,
+		    "%s -> pci_enable_wake invoked successfully.\n", __func__);
+
+		pci_disable_device(pdev);
+		dev_dbg(&pdev->dev,
+		  "%s -> pci_disable_device invoked successfully.\n", __func__);
+
+		pci_set_power_state(pdev, pci_choose_state(pdev, state));
+		dev_dbg(&pdev->dev,
+		 "%s -> pci_set_power_state invoked successfully.\n", __func__);
+	}
+
+	dev_dbg(&pdev->dev, "%s returns %d.\n", __func__, retval);
+	return retval;
+}
+
+static int pch_can_resume(struct pci_dev *pdev)
+{
+	int i;			/* Counter variable. */
+	int retval;		/* Return variable. */
+	struct pch_can_os *can_os =
+			(struct pch_can_os *) dev_get_drvdata(&pdev->dev);
+
+	pci_set_power_state(pdev, PCI_D0);
+	dev_dbg(&pdev->dev,
+	    "pch_can_resume -> pci_set_power_state invoked successfully.\n");
+
+	pci_restore_state(pdev);
+	dev_dbg(&pdev->dev,
+		"pch_can_resume -> pci_restore_state invoked successfully.\n");
+
+	retval = pci_enable_device(pdev);
+	if (retval != 0) {
+		dev_err(&pdev->dev,
+		"pch_can_resume -> pci_enable_device failed(returned %d).\n",
+		retval);
+	}
+
+	else {
+		dev_dbg(&pdev->dev, "pch_can_resume -> pci_enable_device"
+				" invoked successfully(returned %d)\n", retval);
+		pci_enable_wake(pdev, PCI_D3hot, 0);
+
+		/* Disabling all interrupts. */
+		pch_can_set_int_enables(can_os->can, CAN_DISABLE, can_os->ndev);
+
+		/* Setting the CAN device in Stop Mode. */
+		pch_can_set_run_mode(can_os->can, PCH_CAN_STOP, can_os->ndev);
+
+		/* Configuring the transmit and receive buffers. */
+		pch_can_config_rx_tx_buffers(can_os->can, can_os->ndev);
+		dev_dbg(&pdev->dev, "pch_can_resume -> "
+			"pch_can_config_rx_tx_buffers invoked successfully.\n");
+
+		if (can_os->opened == 1) {
+			/* Restore the CAN state */
+			pch_can_set_baud_custom(can_os->can, &(can_os->timing));
+								/* Timing */
+			pch_can_set_listen_mode(
+				can_os->can, can_os->listen_mode, can_os->ndev);
+							/* Listen/Active */
+			pch_can_set_arbiter_mode(can_os->can,
+					can_os->arbiter_mode, can_os->ndev);
+							/* Arbiter mode */
+
+			/* Enabling the transmit buffer. */
+			for (i = 0;
+			     i < (pch_can_tx_buf_size + pch_can_rx_buf_size);
+									i++) {
+				if (pch_msg_obj_conf[i] == MSG_OBJ_TX) {
+					/* Here i is the index, however (i+1) is
+							 object number. */
+					pch_can_set_tx_enable(can_os->can,
+							(i + 1),
+							can_os->tx_enable[i],
+							can_os->ndev);
+				}
+			}
+
+			/* Configuring the receive buffer and enabling them. */
+			for (i = 0;
+			     i < (pch_can_tx_buf_size + pch_can_rx_buf_size);
+									i++) {
+				if (pch_msg_obj_conf[i] == MSG_OBJ_RX) {
+					/* Here i is the index, however (i+1) is
+							 object number. */
+
+					/* Restore buffer link */
+					pch_can_set_rx_buffer_link(can_os->can,
+							(i + 1),
+							can_os->rx_link[i],
+							can_os->ndev);
+
+					/* Restore Rx Filters */
+					can_os->rx_filter[i].num = (i + 1);
+					pch_can_set_rx_filter(can_os->can,
+						       &(can_os->rx_filter[i]));
+
+					/* Restore buffer enables */
+					pch_can_set_rx_enable(can_os->can,
+							(i + 1),
+							can_os->rx_enable[i],
+							can_os->ndev);
+				}
+			}
+
+			/* Enable CAN Interrupts */
+			pch_can_set_int_custom(can_os->can,
+						     can_os->int_enables);
+
+			/* Restore Run Mode */
+			pch_can_set_run_mode(can_os->can,
+						can_os->run_mode, can_os->ndev);
+		}
+		/* if opened */
+		can_os->is_suspending = 0;
+	}			/* else */
+
+	dev_dbg(&pdev->dev, "pch_can_resume returns %d\n", retval);
+	return retval;
+}
+#else
+#define pch_can_suspend NULL
+#define pch_can_resume NULL
+#endif
+
+static int __devinit pch_can_probe(struct pci_dev *pdev,
+				   const struct pci_device_id *id)
+{
+	struct net_device *ndev;
+	struct pch_can_priv *priv;
+	unsigned int can_num = 0;	/* Variable to denote the CAN */
+	int rc;
+	int index;
+
+	ndev = alloc_candev(sizeof(struct pch_can_priv), 1);
+	if (!ndev)
+		return -ENOMEM;
+	SET_NETDEV_DEV(ndev, &pdev->dev);
+
+	priv = netdev_priv(ndev);
+
+	priv->ndev = ndev;
+
+	priv->can.bittiming_const = &pch_can_bittiming_const;
+	priv->can.do_set_bittiming = &pch_set_bittiming;
+	priv->can.do_set_mode = pch_can_do_set_mode;
+	priv->can.do_get_state = pch_can_get_state;
+	priv->can.clock.freq = pch_can_clock * 1000;
+					/* Unit is Hz(pch_can_clock is KHz) */
+	priv->pch_can_os_p = &can_os[can_num];
+	ndev->flags |= (IFF_NOARP | IFF_ECHO);
+	platform_set_drvdata(pdev, ndev);
+	ndev->netdev_ops = &pch_can_netdev_ops;
+	rc = pci_enable_device(pdev);
+	if (rc)
+		goto err_out_free;
+
+	rc = pci_request_regions(pdev, DRIVER_NAME);
+	if (rc)
+		goto err_out_disable;
+
+	can_os[can_num].pci_remap = pci_iomap(pdev, 1, 0);
+	if (can_os[can_num].pci_remap == 0) {
+		rc = -EIO;
+		goto err_out_res;
+	}
+
+	/* Creating the device handle denoting the remap base address. */
+	can_os[can_num].can = pch_can_create((void *)can_os[can_num].pci_remap,
+									ndev);
+
+	/* If handle creation fails. */
+	if (can_os[can_num].can == 0) {
+		dev_err(&pdev->dev,
+			"%s -> pch_can_create failed.\n", __func__);
+		rc = -EPERM;
+		goto err_out_iomap;
+	}
+
+	/* Can number (index to the structure) */
+	can_os[can_num].can_num = can_num;
+	can_os[can_num].irq = pdev->irq;/* IRQ allocated to this device. */
+	ndev->irq = pdev->irq;
+	can_os[can_num].dev = pdev;/* Reference to pci_device structure. */
+	can_os[can_num].opened = 0;/* Open flag denoting the device usage. */
+	can_os[can_num].is_suspending = 0;/* Flag denoting the suspend stage. */
+	can_os[can_num].ndev = ndev;
+
+	priv->base = (void *)can_os[can_num].pci_remap;
+
+	for (index = 0; index < pch_can_rx_buf_size;)
+		pch_msg_obj_conf[index++] = MSG_OBJ_RX;
+
+	for (index = index;
+	     index < (pch_can_rx_buf_size + pch_can_tx_buf_size);)
+		pch_msg_obj_conf[index++] = MSG_OBJ_TX;
+
+	rc = register_candev(ndev);
+	if (rc)
+		goto err_out_reg_candev;
+
+	return 0;
+
+err_out_reg_candev:
+	pch_can_destroy(can_os->can, ndev);
+err_out_iomap:
+	pci_iounmap(pdev, (void *)can_os[can_num].pci_remap);
+err_out_res:
+	pci_release_regions(pdev);
+err_out_disable:
+	pci_disable_device(pdev);
+err_out_free:
+	free_candev(ndev);
+
+	return rc;
+}
+
+static struct pci_driver pch_can_pcidev = {
+	.name = MODULE_NAME,
+	.id_table = pch_can_pcidev_id,
+	.probe = pch_can_probe,
+	.remove = __devexit_p(pch_can_remove),
+	.suspend = pch_can_suspend,
+	.resume = pch_can_resume,
+};
+
+static int __init pch_can_pci_init(void)
+{
+	return pci_register_driver(&pch_can_pcidev);
+}
+
+static void __exit pch_can_pci_exit(void)
+{
+	/* Unregistering the registered PCI Driver. */
+	pci_unregister_driver(&pch_can_pcidev);
+}
+
+MODULE_DESCRIPTION("Controller Area Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.94");
+
+module_param_named(pch_can_rx_buf_size, pch_can_rx_buf_size, int, 444);
+module_param_named(pch_can_tx_buf_size, pch_can_tx_buf_size, int, 444);
+module_param_named(pch_can_clock, pch_can_clock, int, 444);
+MODULE_DEVICE_TABLE(pci, pch_can_pcidev_id);
+
+module_init(pch_can_pci_init);
+module_exit(pch_can_pci_exit);
diff --git a/drivers/net/can/pch_can.h b/drivers/net/can/pch_can.h
new file mode 100644
index 0000000..88a9559
--- /dev/null
+++ b/drivers/net/can/pch_can.h
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef __PCH_CAN_H__
+#define __PCH_CAN_H__
+
+#define MAX_CAN_DEVICES		1
+#define MAX_BITRATE		0x3e8
+#define NUM_NODES		2000	/* Maximum number of
+						 Software FIFO nodes. */
+#define MAX_MSG_OBJ		32
+#define MSG_OBJ_RX		0 /* The receive message object flag. */
+#define MSG_OBJ_TX		1 /* The transmit message object flag. */
+
+#define ENABLE			1 /* The enable flag */
+#define DISABLE			0 /* The disable flag */
+#define CAN_CTRL_INIT		0x0001 /* The INIT bit of CANCONT register. */
+#define CAN_CTRL_IE		0x0002 /* The IE bit of CAN control register */
+#define CAN_CTRL_SIE		0x0004
+#define CAN_CTRL_EIE		0x0008
+#define CAN_CTRL_DAR		0x0020
+#define CAN_CTRL_IE_SIE_EIE	0x000e
+#define CAN_CTRL_CCE		0x0040
+#define CAN_CTRL_OPT		0x0080 /* The OPT bit of CANCONT register. */
+#define CAN_OPT_SILENT		0x0008 /* The Silent bit of CANOPT register. */
+#define CAN_CMASK_RX_TX_SET	0x00f3
+#define CAN_CMASK_RX_TX_GET	0x0073
+#define CAN_CMASK_ALL		0xff
+#define CAN_CMASK_RDWR		0x80
+#define CAN_CMASK_ARB		0x20
+#define CAN_CMASK_CTRL		0x10
+#define CAN_CMASK_MASK		0x40
+#define CAN_CMASK_CLPNT		0x08
+
+#define CAN_CMASK_NEWINT	0x04 /* The TxRqst/NewDat bit for the CMASK
+					register. */
+
+#define CAN_IF_MCONT_NEWDAT	0x8000 /* The NewDat bit of the MCONT
+					  register. */
+
+#define CAN_IF_MCONT_INTPND	0x2000 /* The IntPnd bit of the MCONT
+					  register. */
+
+#define CAN_IF_MCONT_UMASK		0x1000
+#define CAN_IF_MCONT_TXIE		0x0800
+#define CAN_IF_MCONT_RXIE		0x0400
+#define CAN_IF_MCONT_RMTEN		0x0200
+#define CAN_IF_MCONT_TXRQXT		0x0100
+#define CAN_IF_MCONT_EOB		0x0080
+#define CAN_IF_MCONT_MSGLOST		0x4000
+#define CAN_MASK2_MDIR_MXTD		0xc000
+#define CAN_ID2_MSGVAL_XTD_DIR		0xe000
+#define CAN_ID2_MSGVAL_DIR		0xa000
+#define CAN_ID2_DIR			0x2000
+#define CAN_ID_MSGVAL			0x8000
+#define CAN_IF_MASK2_MDIR		((u32)1 << 14)
+#define CAN_IF_MASK2_MXTD		((u32)1 << 15)
+
+#define CAN_STATUS_INT			0x8000 /* The status interrupt value of
+						  the CAN device. */
+
+#define CAN_IF_CREQ_BUSY		0x8000 /* The Busy flag bit of the CREQ
+						  register. */
+
+#define CAN_ID2_XTD			0x4000 /* The Xtd bit of ID2
+						  register. */
+
+#define CAN_SRST_BIT			0x0001
+#define CAN_CONT_OFFSET			0x00	/*Can Control register */
+#define CAN_STAT_OFFSET			0x04
+#define CAN_ERRC_OFFSET			0x08
+#define CAN_BITT_OFFSET			0x0c
+#define CAN_INT_OFFSET			0x010
+#define CAN_OPT_OFFSET			0x14	/*Extended function register */
+#define CAN_BRPE_OFFSET			0x18
+
+/* Message interface one (IF1) registers */
+#define CAN_IF1_CREQ_OFFSET		0x020
+#define CAN_IF1_CMASK_OFFSET		0x024
+#define CAN_IF1_ID1_OFFSET		0x030
+#define CAN_IF1_ID2_OFFSET		0x034
+#define CAN_IF1_MCONT_OFFSET		0x038
+#define CAN_IF1_DATAA1_OFFSET		0x03C
+#define CAN_IF1_DATAA2_OFFSET		0x040
+#define CAN_IF1_DATAB1_OFFSET		0x044
+#define CAN_IF1_DATAB2_OFFSET		0x048
+#define CAN_IF1_MASK1_OFFSET		0x028
+#define CAN_IF1_MASK2_OFFSET		0x02c
+#define CAN_IF2_CREQ_OFFSET		0x080
+#define CAN_IF2_CMASK_OFFSET		0x084
+#define CAN_IF2_ID1_OFFSET		0x090
+#define CAN_IF2_ID2_OFFSET		0x094
+#define CAN_IF2_MCONT_OFFSET		0x098
+#define CAN_IF2_DATAA1_OFFSET		0x09c
+#define CAN_IF2_DATAA2_OFFSET		0x0a0
+#define CAN_IF2_DATAB1_OFFSET		0x0a4
+#define CAN_IF2_DATAB2_OFFSET		0x0a8
+#define CAN_IF2_MASK1_OFFSET		0x088
+#define CAN_IF2_MASK2_OFFSET		0x08c
+#define CAN_TREQ1_OFFSET		0x100
+#define CAN_TREQ2_OFFSET		0x104
+#define CAN_SRST_OFFSET			0x1FC
+#define BIT_SHIFT_ONE			1
+#define BIT_SHIFT_TWO			2
+#define BIT_SHIFT_THREE			3
+#define BIT_SHIFT_FOUR			4
+#define BIT_SHIFT_FIVE			5
+#define BIT_SHIFT_SIX			6
+#define BIT_SHIFT_SEVEN			7
+#define BIT_SHIFT_EIGHT			8
+#define BIT_SHIFT_TWELVE		12
+#define BIT_SHIFT_THIRTEEN		13
+#define BIT_SHIFT_FOURTEEN		14
+#define BIT_SHIFT_FIFTEEN		15
+#define BIT_SHIFT_SIXTEEN		16
+
+/* bit position of certain controller bits. */
+#define BIT_BITT_BRP			0
+#define BIT_BITT_SJW			6
+#define BIT_BITT_TSEG1			8
+#define BIT_BITT_TSEG2			12
+#define BIT_IF1_MCONT_RXIE		10
+#define BIT_IF2_MCONT_TXIE		11
+#define BIT_BRPE_BRPE			6
+#define BIT_ES_TXERRCNT			0
+#define BIT_ES_RXERRCNT			8
+#define MSK_BITT_BRP			0x3f
+#define MSK_BITT_SJW			0xc0
+#define MSK_BITT_TSEG1			0xf00
+#define MSK_BITT_TSEG2			0x7000
+#define MSK_BRPE_BRPE			0x3c0
+#define MSK_BRPE_GET			0x0f
+#define MSK_CTRL_IE_SIE_EIE		0x07
+#define MSK_MCONT_TXIE			0x08
+#define MSK_MCONT_RXIE			0x10
+#define MSK_ALL_THREE			0x07
+#define MSK_ALL_FOUR			0x0f
+#define MSK_ALL_EIGHT			0xff
+#define MSK_ALL_ELEVEN			0x7ff
+#define MSK_ALL_THIRTEEN		0x1fff
+#define MSK_ALL_SIXTEEN			0xffff
+
+/* Error */
+#define MSK_ES_TXERRCNT	((u32)0xff << BIT_ES_TXERRCNT)	/* Tx err count */
+#define MSK_ES_RXERRCNT	((u32)0x7f << BIT_ES_RXERRCNT)	/* Rx err count */
+
+#define PCH_CAN_BIT_SET(reg, bitmask)	\
+		(iowrite32((ioread32((reg)) | ((u32)(bitmask))), (reg)))
+#define PCH_CAN_BIT_CLEAR(reg, bitmask)	\
+		(iowrite32((ioread32((reg)) & ~((u32)(bitmask))), (reg)))
+
+#define PCH_CAN_NO_TX_BUFF		1 /* The flag value for denoting the
+					     unavailability of the transmit
+					     message object. */
+
+#define ERROR_COUNT			96
+#define PCH_CAN_MSG_DATA_LEN		8	/* CAN Msg data length */
+
+#define PCH_CAN_FIFO_NOT_EMPTY		0
+#define PCH_CAN_FIFO_EMPTY		1
+#define PCH_CAN_FIFO_FULL		2
+#define PCH_CAN_NULL			NULL
+
+#define PCI_DEVICE_ID_INTEL_PCH1_CAN	0x8818
+#define DRIVER_NAME			"can"
+
+#define PCH_CAN_CLOCK_DEFAULT_OFFSET	0
+#define PCH_CAN_CLOCK_62_5_OFFSET	0
+#define PCH_CAN_CLOCK_24_OFFSET		8
+#define PCH_CAN_CLOCK_50_OFFSET		16
+
+#define COUNTER_LIMIT 0xFFFF
+
+#define MODULE_NAME "pch_can"
+
+enum pch_can_listen_mode {
+	PCH_CAN_ACTIVE = 0,
+	PCH_CAN_LISTEN
+};
+
+enum pch_can_run_mode {
+	PCH_CAN_STOP = 0,
+	PCH_CAN_RUN
+};
+
+enum pch_can_arbiter {
+	PCH_CAN_ROUND_ROBIN = 0,
+	PCH_CAN_FIXED_PRIORITY
+};
+
+enum pch_can_auto_restart {
+	CAN_MANUAL = 0,
+	CAN_AUTO
+};
+
+enum pch_can_baud {
+	PCH_CAN_BAUD_10 = 0,
+	PCH_CAN_BAUD_20,
+	PCH_CAN_BAUD_50,
+	PCH_CAN_BAUD_125,
+	PCH_CAN_BAUD_250,
+	PCH_CAN_BAUD_500,
+	PCH_CAN_BAUD_800,
+	PCH_CAN_BAUD_1000
+};
+
+enum pch_can_interrupt {
+	CAN_ENABLE,
+	CAN_DISABLE,
+	CAN_ALL,
+	CAN_NONE
+};
+
+/**
+ * struct pch_can_msg - CAN message structure
+ * @ide:	Standard/extended msg
+ * @id:		11 or 29 bit msg id
+ * @dlc:	Size of data
+ * @data:	Message pay load
+ * @rtr:	RTR message
+ */
+struct pch_can_msg {
+	unsigned short ide;
+	unsigned int id;
+	unsigned short dlc;
+	unsigned char data[PCH_CAN_MSG_DATA_LEN];
+	unsigned short rtr;
+};
+
+/**
+ * pch_can_timing - CAN bittiming structure
+ * @bitrate:	Bitrate (kbps)
+ * @cfg_bitrate:	Bitrate
+ * @cfg_tseg1:	Tseg1
+ * @cfg_tseg2:	Tseg2
+ * @cfg_sjw:	Sync jump width
+ * @smpl_mode:	Sampling mode
+ * @edge_mode:	Edge R / D
+ */
+struct pch_can_timing {
+	unsigned int bitrate;
+	unsigned int cfg_bitrate;
+	unsigned int cfg_tseg1;
+	unsigned int cfg_tseg2;
+	unsigned int cfg_sjw;
+	unsigned int smpl_mode;
+	unsigned int edge_mode;
+};
+
+/**
+ * struct pch_can_error - CAN error structure
+ * @rxgte96:	Rx err cnt >=96
+ * @txgte96:	Tx err cnt >=96
+ * @error_stat:	Error state of CAN node,
+ *		00=error active (normal)
+ *		01=error passive
+ *		1x=bus off
+ * @rx_err_cnt:	Rx error count
+ * @tx_err_cnt:	Tx error count
+ */
+struct pch_can_error {
+	unsigned int rxgte96;
+	unsigned int txgte96;
+	unsigned int error_stat;
+	unsigned int rx_err_cnt;
+	unsigned int tx_err_cnt;
+};
+
+/**
+ * struct pch_can_acc_filter - CAN Filter structure
+ * @id:		The id/mask data
+ * @id_ext:	Standard/extended ID
+ * @rtr:	RTR message
+ */
+struct pch_can_acc_filter {
+	unsigned int id;
+	unsigned int id_ext;
+	unsigned int rtr;
+};
+
+/**
+ * struct pch_can_rx_filter - CAN RX filter
+ * @num:	Filter number
+ * @umask:	UMask value
+ * @amr:	Acceptance Mask Reg
+ * @aidr:	Acceptance Control Reg
+ */
+struct pch_can_rx_filter {
+	unsigned int num;
+	unsigned int umask;
+	struct pch_can_acc_filter amr;
+	struct pch_can_acc_filter aidr;
+};
+
+/**
+ * struct pch_can_os - structure to store the CAN device information.
+ * @can:		CAN: device handle
+ * @opened:		Linux opened device
+ * @can_num:		Linux: CAN Number
+ * @pci_remap:		Linux: MMap regs
+ * @dev:		Linux: PCI Device
+ * @irq:		Linux: IRQ
+ * @block_mode:		Blocking / non-blocking
+ * @rx_fifo:		Rx FIFO
+ * @read_wait_queue:	Linux: Read wait queue
+ * @write_wait_queue:	Linux: Write wait queue
+ * @write_wait_flag:	Linux: Write wait flag
+ * @read_wait_flag:	Linux: Read wait flag
+ * @open_spinlock:	Linux: Open lock variable
+ * @is_suspending:	Linux: Is suspending state
+ * @inode:		Linux: inode
+ * @timing:		CAN: timing
+ * @run_mode:		CAN: run mode
+ * @listen_mode:	CAN: listen mode
+ * @arbiter_mode:	CAN: arbiter mode
+ * @tx_enable:		CAN: Tx buffer state
+ * @rx_enable:		CAN: Rx buffer state
+ * @rx_link:		CAN: Rx link set
+ * @int_enables:	CAN: ints enabled
+ * @int_stat:		CAN: int status
+ * @bus_off_interrupt:	CAN: Buss off int flag
+ * @rx_filter:		CAN: Rx filters
+ * @can_callback:	CAN: callback function pointer
+ * @ndev:		net_device pointer
+ * @tx_spinlock:	CAN: transmission lock variable
+ */
+struct pch_can_os {
+	int can;
+	unsigned int opened;
+	unsigned int can_num;
+	void __iomem *pci_remap;
+	struct pci_dev *dev;
+	unsigned int irq;
+	int block_mode;
+	int rx_fifo;
+	wait_queue_head_t read_wait_queue;
+	wait_queue_head_t write_wait_queue;
+	unsigned int write_wait_flag;
+	unsigned int read_wait_flag;
+	spinlock_t open_spinlock;
+	unsigned int is_suspending;
+	struct inode *inode;
+	struct pch_can_timing timing;
+	enum pch_can_run_mode run_mode;
+	enum pch_can_listen_mode listen_mode;
+	enum pch_can_arbiter arbiter_mode;
+	unsigned int tx_enable[MAX_MSG_OBJ];
+	unsigned int rx_enable[MAX_MSG_OBJ];
+	unsigned int rx_link[MAX_MSG_OBJ];
+	unsigned int int_enables;
+	unsigned int int_stat;
+	unsigned int bus_off_interrupt;
+	struct pch_can_rx_filter rx_filter[MAX_MSG_OBJ];
+	void (*can_callback) (struct pch_can_os *);
+	struct net_device *ndev;
+	spinlock_t tx_spinlock;
+};
+
+/**
+ * struct pch_can_priv - CAN driver private data structure
+ * @can:		MUST be first member/field
+ * @ndev:		Pointer to net_device structure
+ * @clk:		unused
+ * @base:		Base address
+ * @scc_ram_offset:	unused
+ * @hecc_ram_offset:	unused
+ * @mbx_offset:		unused
+ * @int_line:		unused
+ * @mbx_lock:		unused
+ * @tx_head:		unused
+ * @tx_tail:		unused
+ * @rx_next:		unused
+ * @pch_can_os_p:	Pointer to CAN device information
+ * @have_msi:		PCI MSI mode flag
+ *
+ * Longer description of this structure.
+ */
+struct pch_can_priv {
+	struct can_priv can;
+	struct net_device *ndev;
+	struct clk *clk;
+	void __iomem *base;
+	u32 scc_ram_offset;
+	u32 hecc_ram_offset;
+	u32 mbx_offset;
+	u32 int_line;
+	spinlock_t mbx_lock;
+	u32 tx_head;
+	u32 tx_tail;
+	u32 rx_next;
+	struct pch_can_os *pch_can_os_p;
+	unsigned int have_msi;
+};
+
+/**
+ * struct can_fifo_item - FIFO Item structure
+ * @msg:	The msg object
+ * @next:	The next pointer
+ */
+struct can_fifo_item {
+	struct pch_can_msg msg;
+	struct can_fifo_item *next;
+};
+
+/**
+ * struct can_fifo - CAN FIFO structure
+ * @head:	The node where insertion can be done
+ * @tail:	The node where reading can be done
+ * @size:	The number of FIFO nodes
+ */
+struct can_fifo {
+	struct can_fifo_item *head;
+	struct can_fifo_item *tail;
+	unsigned int size;
+};
+
+/* This structure defines format for the storage of base address */
+struct can_hw {
+	void __iomem *io_base;
+};
+#endif /* __PCH_CAN_H__ */
-- 1.6.0.6


[-- Attachment #1.2: Type: text/html, Size: 130674 bytes --]

[-- Attachment #2: Type: text/plain, Size: 163 bytes --]

_______________________________________________
MeeGo-dev mailing list
MeeGo-dev-WXzIur8shnEAvxtiuMwx3w@public.gmane.org
http://lists.meego.com/listinfo/meego-dev

^ permalink raw reply related

* Re: [RFC PATCH] platform: Faciliatate the creation of pseduo-platform busses
From: Greg KH @ 2010-08-10 23:53 UTC (permalink / raw)
  To: Grant Likely
  Cc: Patrick Pannuto, Patrick Pannuto, linux-kernel@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, linux-omap@vger.kernel.org,
	damm@opensource.se, lethal@linux-sh.org, rjw@sisk.pl,
	dtor@mail.ru, eric.y.miao@gmail.com, netdev@vger.kernel.org,
	Kevin Hilman
In-Reply-To: <AANLkTimjXd=SL61KvjDfvJ-JtXsSVW9pwOYBFUHX0mVp@mail.gmail.com>

On Sat, Aug 07, 2010 at 11:28:13AM -0600, Grant Likely wrote:
> On Sat, Aug 7, 2010 at 12:35 AM, Grant Likely <grant.likely@secretlab.ca> wrote:
> > On Fri, Aug 6, 2010 at 5:46 PM, Greg KH <gregkh@suse.de> wrote:
> >> That would be nice, but take your "standard" PC today:
> >>        > ls /sys/devices/platform/
> >>        Fixed MDIO bus.0  i8042  pcspkr  power  serial8250  uevent vesafb.0
> >>
> >> There are tty devices below the serial port, which is nice to see, but
> >> the others?  I don't know what type of bus they would be on, do you?
> [...]
> > I wouldn't have any problem modifying those specific drivers to
> > register under something like /sys/devices/legacy, but I don't really
> > think it is in any way necessary.
> 
> Or for that matter, make those drivers explicitly use
> /sys/devices/platform so that I don't cause churn on PCs.  :-)  I'd
> like to be rid of it as default behaviour for embedded though.

Yes, that would be the easier (and better) solution.

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH 2/2] platform: Facilitate the creation of pseudo-platform buses
From: Patrick Pannuto @ 2010-08-10 23:49 UTC (permalink / raw)
  To: linux-kernel
  Cc: ppannuto, linux-arm-msm, magnus.damm, grant.likely, gregkh,
	Kevin Hilman, Paul Mundt, Magnus Damm, Rafael J. Wysocki,
	Eric Miao, Dmitry Torokhov, netdev
In-Reply-To: <1281484174-32174-1-git-send-email-ppannuto@codeaurora.org>

(lkml.org seems to have lost August 3rd...)
RFC: http://lkml.indiana.edu/hypermail//linux/kernel/1008.0/01342.html
 v1: http://lkml.indiana.edu/hypermail//linux/kernel/1008.0/01942.html

Based on the idea and code originally proposed by Kevin Hilman:
http://www.mail-archive.com/linux-omap@vger.kernel.org/msg31161.html

Changes from v1:

   * "Pseduo" buses are no longer init'd, they are [un]registered by:
       - pseudo_platform_bus_register(struct bus_type *)
       - pseudo_platform_bus_unregister(struct bus_type *)
   * These registrations [de]allocate a dev_pm_ops structure for the
     pseudo bus_type
   * Do not overwrite the parent if .bus is already set (that is, allow
     pseudo bus devices to be root devices)

   * Split into 2 patches:
       - 1/2: Already sent separately, but included here for clarity
       - 2/2: The real meat of the patch (this patch)

INTRO

As SOCs become more popular, the desire to quickly define a simple,
but functional, bus type with only a few unique properties becomes
desirable. As they become more complicated, the ability to nest these
simple busses and otherwise orchestrate them to match the actual
topology also becomes desirable.

EXAMPLE USAGE

/arch/ARCH/MY_ARCH/my_bus.c:

	#include <linux/device.h>
	#include <linux/platform_device.h>

	struct bus_type SOC_bus_type = {
		.name = "SOC-bus-type",
	};
	EXPORT_SYMBOL_GPL(SOC_bus_type);

	struct platform_device SOC_bus1 = {
		.name	 = "SOC-bus1",
		.id		= -1,
		.dev.bus = &SOC_bus_type;
	};
	EXPORT_SYMBOL_GPL(SOC_bus1);

	struct platform_device SOC_bus2 = {
		.name	 = "SOC-bus2",
		.id		= -2,
		.dev.bus = &SOC_bus_type;
	};
	EXPORT_SYMBOL_GPL(SOC_bus2);

	static int __init SOC_bus_init(void)
	{
		int error;

		error = pseudo_platform_bus_register(&SOC_bus_type);
		if (error)
			return error;

		error = platform_device_register(&SOC_bus1);
		if (error)
			goto fail_bus1;

		error = platform_device_register(&SOC_bus2);
		if (error)
			goto fail_bus2;

		return error;

		/* platform_device_unregister(&SOC_bus2); */
fail_bus2:
		platform_device_unregister(&SOC_bus1);
fail_bus1:
		pseudo_platform_bus_unregister(&SOC_bus_type);

		return error;
	}

/drivers/my_driver.c:
	static struct platform_driver my_driver = {
		.driver = {
			.name	= "my-driver",
			.owner	= THIS_MODULE,
			.bus	= &SOC_bus_type,
		},
	};

/somewhere/my_device.c:
	static struct platform_device my_device = {
		.name		= "my-device",
		.id		= -1,
		.dev.bus	= &my_bus_type,
		.dev.parent	= &SOC_bus1.dev,
	};

This will build a device tree that mirrors the actual system:

/sys/bus
|-- SOC-bus-type
|   |-- devices
|   |   |-- SOC_bus1 -> ../../../devices/SOC_bus1
|   |   |-- SOC_bus2 -> ../../../devices/SOC_bus2
|   |   |-- my-device -> ../../../devices/SOC_bus1/my-device
|   |-- drivers
|   |   |-- my-driver

/sys/devices
|-- SOC_bus1
|   |-- my-device
|-- SOC_bus2

Driver can drive any device on the SOC, which is logical, without
actually being registered on multiple /bus_types/, even though the
devices may be on different /physical buses/ (which are actually
just devices).

THOUGHTS:

1.
Notice that for a device / driver, only 3 lines were added to
switch from the platform bus to the new SOC_bus. This is
especially valuable if we consider supporting a legacy SOCs
and new SOCs where the same driver is used, but may need to
be on either the platform bus or the new SOC_bus. The above
code then becomes:

	(possibly in a header)
	#ifdef CONFIG_MY_BUS
	#define MY_BUS_TYPE     &SOC_bus_type
	#else
	#define MY_BUS_TYPE     NULL
	#endif

/drivers/my_driver.c
	static struct platform_driver my_driver = {
		.driver = {
			.name   = "my-driver",
			.owner  = THIS_MODULE,
			.bus    = MY_BUS_TYPE,
		},
	};

Which will allow the same driver to easily to used on either
the platform bus or the newly defined bus type.

2.
Implementations wishing to make dynamic / run-time decisions on where
devices are placed could easily create wrapper functions, that is

	int SOC_device_register(struct platform_device *pdev)
	{
		if (pdev->archdata->flag)
			pdev->dev.parent = &SOC_bus1.dev;
		else
			pdev->dev.parent = &SOC_bus2.dev;

		return platform_device_register(pdev);
	}

A similar solution also would allow for run-time determination of dev.bus,
if that were necessary for your platform.

3.
I'm not convinced that dynamically allocating a new copy of dev_pm_ops is
the best solution. I *AM*, however, convinced that removing const from
	struct bus_type {
		...
		const struct dev_pm_ops *pm;
		...
	};
would be a mistake; it is far too easy to overwrite one of the function
pointers on accident, and the const serves a very useful purpose here.

Cc: Kevin Hilman <khilman@deeprootsystems.com>
Signed-off-by: Patrick Pannuto <ppannuto@codeaurora.org>
---
 drivers/base/platform.c         |   92 +++++++++++++++++++++++++++++++++++++-
 include/linux/platform_device.h |    3 +
 2 files changed, 92 insertions(+), 3 deletions(-)

diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index b69ccb4..933e0c1 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -238,8 +238,12 @@ int platform_device_add(struct platform_device *pdev)
 	if (!pdev)
 		return -EINVAL;
 
-	if (!pdev->dev.parent)
-		pdev->dev.parent = &platform_bus;
+	if (!pdev->dev.bus) {
+		pdev->dev.bus = &platform_bus_type;
+
+		if (!pdev->dev.parent)
+			pdev->dev.parent = &platform_bus;
+	}
 
 	pdev->dev.bus = &platform_bus_type;
 
@@ -482,7 +486,8 @@ static void platform_drv_shutdown(struct device *_dev)
  */
 int platform_driver_register(struct platform_driver *drv)
 {
-	drv->driver.bus = &platform_bus_type;
+	if (!drv->driver.bus)
+		drv->driver.bus = &platform_bus_type;
 	if (drv->probe)
 		drv->driver.probe = platform_drv_probe;
 	if (drv->remove)
@@ -1017,6 +1022,87 @@ struct bus_type platform_bus_type = {
 };
 EXPORT_SYMBOL_GPL(platform_bus_type);
 
+/** pseudo_platform_bus_register - register an "almost platform bus"
+ * @bus: partially complete bus type to register
+ *
+ * This init will fill in any ommitted fields in @bus, however, it
+ * also allocates memory and replaces the pm field in @bus, since
+ * pm is const, but some of its pointers may need this one-time
+ * initialziation overwrite.
+ *
+ * @bus's registered this way should be released with
+ * pseudo_platform_bus_unregister
+ */
+int pseudo_platform_bus_register(struct bus_type *bus)
+{
+	int error;
+	struct dev_pm_ops* heap_pm;
+	heap_pm = kmalloc(sizeof (*heap_pm), GFP_KERNEL);
+
+	if (!heap_pm)
+		return -ENOMEM;
+
+	if (!bus->dev_attrs)
+		bus->dev_attrs = platform_bus_type.dev_attrs;
+	if (!bus->match)
+		bus->match = platform_bus_type.match;
+	if (!bus->uevent)
+		bus->uevent = platform_bus_type.uevent;
+	if (!bus->pm)
+		memcpy(heap_pm, &platform_bus_type.pm, sizeof(*heap_pm));
+	else {
+		heap_pm->prepare = (bus->pm->prepare) ?
+			bus->pm->prepare : platform_pm_prepare;
+		heap_pm->complete = (bus->pm->complete) ?
+			bus->pm->complete : platform_pm_complete;
+		heap_pm->suspend = (bus->pm->suspend) ?
+			bus->pm->suspend : platform_pm_suspend;
+		heap_pm->resume = (bus->pm->resume) ?
+			bus->pm->resume : platform_pm_resume;
+		heap_pm->freeze = (bus->pm->freeze) ?
+			bus->pm->freeze : platform_pm_freeze;
+		heap_pm->thaw = (bus->pm->thaw) ?
+			bus->pm->thaw : platform_pm_thaw;
+		heap_pm->poweroff = (bus->pm->poweroff) ?
+			bus->pm->poweroff : platform_pm_poweroff;
+		heap_pm->restore = (bus->pm->restore) ?
+			bus->pm->restore : platform_pm_restore;
+		heap_pm->suspend_noirq = (bus->pm->suspend_noirq) ?
+			bus->pm->suspend_noirq : platform_pm_suspend_noirq;
+		heap_pm->resume_noirq = (bus->pm->resume_noirq) ?
+			bus->pm->resume_noirq : platform_pm_resume_noirq;
+		heap_pm->freeze_noirq = (bus->pm->freeze_noirq) ?
+			bus->pm->freeze_noirq : platform_pm_freeze_noirq;
+		heap_pm->thaw_noirq = (bus->pm->thaw_noirq) ?
+			bus->pm->thaw_noirq : platform_pm_thaw_noirq;
+		heap_pm->poweroff_noirq = (bus->pm->poweroff_noirq) ?
+			bus->pm->poweroff_noirq : platform_pm_poweroff_noirq;
+		heap_pm->restore_noirq = (bus->pm->restore_noirq) ?
+			bus->pm->restore_noirq : platform_pm_restore_noirq;
+		heap_pm->runtime_suspend = (bus->pm->runtime_suspend) ?
+			bus->pm->runtime_suspend : platform_pm_runtime_suspend;
+		heap_pm->runtime_resume = (bus->pm->runtime_resume) ?
+			bus->pm->runtime_resume : platform_pm_runtime_resume;
+		heap_pm->runtime_idle = (bus->pm->runtime_idle) ?
+			bus->pm->runtime_idle : platform_pm_runtime_idle;
+	}
+	bus->pm = heap_pm;
+
+	error = bus_register(bus);
+	if (error)
+		kfree(bus->pm);
+
+	return error;
+}
+EXPORT_SYMBOL_GPL(pseudo_platform_bus_register);
+
+void pseudo_platform_bus_unregister(struct bus_type *bus)
+{
+	bus_unregister(bus);
+	kfree(bus->pm);
+}
+EXPORT_SYMBOL_GPL(pseudo_platform_bus_unregister);
+
 int __init platform_bus_init(void)
 {
 	int error;
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 5417944..5ec827c 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -79,6 +79,9 @@ extern int platform_driver_probe(struct platform_driver *driver,
 #define platform_get_drvdata(_dev)	dev_get_drvdata(&(_dev)->dev)
 #define platform_set_drvdata(_dev,data)	dev_set_drvdata(&(_dev)->dev, (data))
 
+extern int pseudo_platform_bus_register(struct bus_type *);
+extern void pseudo_platform_bus_unregister(struct bus_type *);
+
 extern struct platform_device *platform_create_bundle(struct platform_driver *driver,
 					int (*probe)(struct platform_device *),
 					struct resource *res, unsigned int n_res,
-- 
1.7.2

^ permalink raw reply related

* Re: [PATCH] 3c59x: fix deadlock when using netconsole with 3c59x
From: David Miller @ 2010-08-10 23:48 UTC (permalink / raw)
  To: nhorman; +Cc: netdev, klassert
In-Reply-To: <20100809163210.GA1781@hmsreliant.think-freely.org>

From: Neil Horman <nhorman@tuxdriver.com>
Date: Mon, 9 Aug 2010 12:32:10 -0400

> When using netpoll, its possible to deadlock the 3c59x driver.  Since it takes
> an internal spinlock (vp->lock) that serializes boomerang_interrupt and parts
> of boomerang_start_xmit, if we call pr_debug in the former, we can go through
> the tx path on the same cpu, and recurse into the same driver again, deadlocking
> in the transmit routine.
> 
> This patch fixes that problem by stopping the queues during interrupt
> processing, so that subsequent transmits will get queued until a later point.
> Its not a great solution, but we need to find some way to serialize access to
> the register file on the card without enforcing a deadlock.  I think the queue
> stop is the best way to do that.  And since we only print things in
> boomerang_interrupt when we have debug enabled, we can mitigate the impact of
> this change to only stop the queues when debug is on.
> 
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>

Nothing serialized changes to "vortex_debug" with the tests you're
making here.  Simply turning it off when a packet arrives can deadlock
the send queue of the device.

Even if proper serializatio did exist, I still see this as an awful
solution.

And the default value of this thing is "1" so it's always going to be
doing this send queue state flipping for effectively everyone.

Please find another way to solve this problem.

^ permalink raw reply

* Re: [PATCH v2] net: add Fast Ethernet driver for PXA168.
From: David Miller @ 2010-08-10 23:42 UTC (permalink / raw)
  To: prakity; +Cc: buytenh, ssanap, netdev, akarkare, sarnaik, eric.y.miao, markb
In-Reply-To: <847F8195-87A2-4318-9E07-FF8A7E9FA1E6@marvell.com>

From: Philip Rakity <prakity@marvell.com>
Date: Tue, 10 Aug 2010 11:12:45 -0700

> Maybe the solution is to add a new option in Kconfig to define the
> extra headers size the driver will need.  That option will increase
> the headers.  I do not like that very much since it requires someone
> know how big the value should be.  Could default it to 48 or 64
> bytes and allow it to be edited.  It is not great solution since it
> fixes the pxa168 driver but does not handle other drivers.

Take a look at how we define LL_MAX_HEADER in include/linux/netdevice.h

^ permalink raw reply

* Re: [PATCH 2/2] caif-spi: Bugfix SPI_DATA_POS settings were inverted.
From: David Miller @ 2010-08-10 23:39 UTC (permalink / raw)
  To: sjur.brandeland; +Cc: sjurbren, netdev
In-Reply-To: <1281461807-17408-2-git-send-email-sjur.brandeland@stericsson.com>

From: sjur.brandeland@stericsson.com
Date: Tue, 10 Aug 2010 19:36:47 +0200

> From: Sjur Braendeland <sjur.brandeland@stericsson.com>
> 
> The setting of SPI_DATA_POS depending on CONFIG_CAIF_SPI_SYNC
> where inverted.
> 
> Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>

Applied.

^ permalink raw reply

* Re: [PATCH 1/2] caif: Bugfix - Increase default headroom size for control channel.
From: David Miller @ 2010-08-10 23:39 UTC (permalink / raw)
  To: sjur.brandeland; +Cc: sjurbren, netdev
In-Reply-To: <1281461807-17408-1-git-send-email-sjur.brandeland@stericsson.com>

From: sjur.brandeland@stericsson.com
Date: Tue, 10 Aug 2010 19:36:46 +0200

> From: Sjur Braendeland <sjur.brandeland@stericsson.com>
> 
> Headroom size for control channel must be at least 48 bytes in some scenarios.
> 
> Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>

Applied.

^ permalink raw reply

* Re: [PATCH] netpoll: use non-BH variant of RCU
From: David Miller @ 2010-08-10 23:31 UTC (permalink / raw)
  To: paulmck; +Cc: herbert, linville, netdev
In-Reply-To: <20100810211932.GG2379@linux.vnet.ibm.com>

From: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
Date: Tue, 10 Aug 2010 14:19:32 -0700

> Your suggestion of providing another API rcu_read_lock_irqsoff()
> and rcu_read_unlock_irqsoff() is the best I can think of right offhand.
> 
> What tree/commit do you need the patch against?

Linus's tree is fine for this.

But we need this fix for 2.6.35-stable too.  Herbert would
you object to putting John's more simple fix there?

John, when referencing other commits in commit messages,
please provide the SHA1 ID as well as the commit message
header line.

Thanks.

^ permalink raw reply

* Re: [PATCH] net: make netpoll_rx return bool for !CONFIG_NETPOLL
From: David Miller @ 2010-08-10 23:24 UTC (permalink / raw)
  To: linville; +Cc: netdev
In-Reply-To: <1281469487-8946-1-git-send-email-linville@tuxdriver.com>

From: "John W. Linville" <linville@tuxdriver.com>
Date: Tue, 10 Aug 2010 15:44:47 -0400

> "netpoll: Use 'bool' for netpoll_rx() return type." missed the case when
> CONFIG_NETPOLL is disabled.
> 
> Signed-off-by: John W. Linville <linville@tuxdriver.com>

Applied, thanks John.

^ permalink raw reply

* Re: [RFC PATCH 1/2] pci: add function reset call that can be used inside of probe
From: Alexander Duyck @ 2010-08-10 23:14 UTC (permalink / raw)
  To: Kenji Kaneshige
  Cc: Kirsher, Jeffrey T, davem@davemloft.net, jbarnes@virtuousgeek.org,
	netdev@vger.kernel.org, linux-pci@vger.kernel.org
In-Reply-To: <4C612C5E.8020909@jp.fujitsu.com>

Kenji Kaneshige wrote:
> (2010/07/31 9:58), Jeff Kirsher wrote:
>> From: Alexander Duyck<alexander.h.duyck@intel.com>
>> +	/*
>> +	 * both INTx and MSI are disabled after the Interrupt Disable bit
>> +	 * is set and the Bus Master bit is cleared.
>> +	 */
>> +	pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
>> +
>> +	rc = __pci_dev_reset(dev, 0);
> 
> Could you tell me why you need to program command register before reset?
> 
> "MSI enable" and "Bus Master" bits are cleared by the reset. Furthermore,
> resetting the device clears the "Interrupt Disable bit", even though it
> was set just before the rest. So I'm a little confused.
> 
> Thanks,
> Kenji Kaneshige
> 

The point is to prevent any pending transactions from being on the bus 
while we are doing the reset.  By writing only the INTX disable bit we 
are disabling all interrupts from being generated, and also disabling 
all DMA and MSI interrupts since the bus master enable bit is not set.

Without this change the device might be in the middle of a transaction 
or sending an interrupt while we are doing the reset which may lead to 
other issues after the reset.

Thanks,

Alex

^ permalink raw reply

* Re: pull request: wireless-2.6 2010-08-10
From: David Miller @ 2010-08-10 23:00 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, netdev
In-Reply-To: <20100810204251.GB2728@tuxdriver.com>

From: "John W. Linville" <linville@tuxdriver.com>
Date: Tue, 10 Aug 2010 16:42:51 -0400

> Here are a few more fixes intended for 2.6.36.  Included are a locking
> fix for cfg80211, a fix for iwlagn to prevent it from using RTS/CTS
> or CTS-to-self protection on every frame (even inappropriately),
> a reversion of a mistakenly added PCI ID from p54, and a simple fix
> for some build breakage some have been experiencing in libertas.
> Also included are a handful of Bluetooth fixes by way of Marcel.

Pulled, thanks a lot John.

^ permalink raw reply

* Re: [PATCH] netpoll: use non-BH variant of RCU
From: Paul E. McKenney @ 2010-08-10 21:19 UTC (permalink / raw)
  To: Herbert Xu; +Cc: John W. Linville, netdev, David S. Miller
In-Reply-To: <20100810204358.GA1076@gondor.apana.org.au>

On Tue, Aug 10, 2010 at 04:43:58PM -0400, Herbert Xu wrote:
> On Tue, Aug 10, 2010 at 04:25:24PM -0400, John W. Linville wrote:
> > "netpoll: Fix RCU usage" switched netpoll_rx to use the BH variant
> > of RCU.  Unfortunately, calling netpoll_rx from netif_rx resulted in
> > the following backtrace:
> 
> Thanks for catching this John!
> 
> > diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
> > index 413742c..0bdd527 100644
> > --- a/include/linux/netpoll.h
> > +++ b/include/linux/netpoll.h
> > @@ -63,8 +63,8 @@ static inline bool netpoll_rx(struct sk_buff *skb)
> >  	unsigned long flags;
> >  	bool ret = false;
> >  
> > -	rcu_read_lock_bh();
> > -	npinfo = rcu_dereference_bh(skb->dev->npinfo);
> > +	rcu_read_lock();
> > +	npinfo = rcu_dereference(skb->dev->npinfo);
> 
> I really wanted to avoid mixing the two different RCU primitives
> because they require different synchronisations.
> 
> In this case, the problem is that we're being called in IRQ
> context, where BH is diabled anyway, so we don't actually need
> to do anything (assuming IRQ is off).
> 
> Paul, what could we do to resolve this (other than by switching
> to the non-BH variant of RCU)? Perhaps an additional variant
> of rcu_read_lock_bh that checks whether IRQ is off?

Hello, Herbert,

Your suggestion of providing another API rcu_read_lock_irqsoff()
and rcu_read_unlock_irqsoff() is the best I can think of right offhand.

What tree/commit do you need the patch against?

							Thanx, Paul

^ permalink raw reply

* Re: [PATCH] netpoll: use non-BH variant of RCU
From: Herbert Xu @ 2010-08-10 20:43 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev, David S. Miller, Paul E. McKenney
In-Reply-To: <1281471924-2237-1-git-send-email-linville@tuxdriver.com>

On Tue, Aug 10, 2010 at 04:25:24PM -0400, John W. Linville wrote:
> "netpoll: Fix RCU usage" switched netpoll_rx to use the BH variant
> of RCU.  Unfortunately, calling netpoll_rx from netif_rx resulted in
> the following backtrace:

Thanks for catching this John!

> diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
> index 413742c..0bdd527 100644
> --- a/include/linux/netpoll.h
> +++ b/include/linux/netpoll.h
> @@ -63,8 +63,8 @@ static inline bool netpoll_rx(struct sk_buff *skb)
>  	unsigned long flags;
>  	bool ret = false;
>  
> -	rcu_read_lock_bh();
> -	npinfo = rcu_dereference_bh(skb->dev->npinfo);
> +	rcu_read_lock();
> +	npinfo = rcu_dereference(skb->dev->npinfo);

I really wanted to avoid mixing the two different RCU primitives
because they require different synchronisations.

In this case, the problem is that we're being called in IRQ
context, where BH is diabled anyway, so we don't actually need
to do anything (assuming IRQ is off).

Paul, what could we do to resolve this (other than by switching
to the non-BH variant of RCU)? Perhaps an additional variant
of rcu_read_lock_bh that checks whether IRQ is off?

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* pull request: wireless-2.6 2010-08-10
From: John W. Linville @ 2010-08-10 20:42 UTC (permalink / raw)
  To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA

Dave,

Here are a few more fixes intended for 2.6.36.  Included are a locking
fix for cfg80211, a fix for iwlagn to prevent it from using RTS/CTS
or CTS-to-self protection on every frame (even inappropriately),
a reversion of a mistakenly added PCI ID from p54, and a simple fix
for some build breakage some have been experiencing in libertas.
Also included are a handful of Bluetooth fixes by way of Marcel.

Please let me know if there are problems!

Thanks,

John

---

The following changes since commit 9871e50edd25e2adf69b369817100821cb1e6de8:

  net: Use NET_XMIT_SUCCESS where possible. (2010-08-10 02:51:11 -0700)

are available in the git repository at:
  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git master

Johannes Berg (2):
      cfg80211: fix locking in action frame TX
      iwlagn: fix rts cts protection

John W. Linville (3):
      Revert "p54pci: Add PCI ID for SMC2802W"
      libertas: fix build break by including linux/sched.h
      Merge branch 'master' of git://git.kernel.org/.../holtmann/bluetooth-2.6

Mat Martineau (4):
      Bluetooth: Fix endianness issue with L2CAP MPS configuration
      Bluetooth: Change default L2CAP ERTM retransmit timeout
      Bluetooth: Fix incorrect setting of remote_tx_win for L2CAP ERTM
      Bluetooth: Use 3-DH5 payload size for default ERTM max PDU size

 drivers/net/wireless/iwlwifi/iwl-1000.c     |    2 +-
 drivers/net/wireless/iwlwifi/iwl-3945.c     |   18 +-----
 drivers/net/wireless/iwlwifi/iwl-4965.c     |    2 +-
 drivers/net/wireless/iwlwifi/iwl-5000.c     |   10 ++--
 drivers/net/wireless/iwlwifi/iwl-6000.c     |   16 +++---
 drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c |   19 +++++-
 drivers/net/wireless/iwlwifi/iwl-agn-tx.c   |   20 +------
 drivers/net/wireless/iwlwifi/iwl-agn.c      |   85 +++++++--------------------
 drivers/net/wireless/iwlwifi/iwl-core.c     |   29 ++++++++-
 drivers/net/wireless/iwlwifi/iwl-core.h     |   14 +++--
 drivers/net/wireless/iwlwifi/iwl3945-base.c |    5 +-
 drivers/net/wireless/libertas/cfg.c         |    1 +
 drivers/net/wireless/p54/p54pci.c           |    2 -
 include/net/bluetooth/l2cap.h               |    4 +-
 net/bluetooth/l2cap.c                       |   11 ++--
 net/wireless/mlme.c                         |    8 ++-
 16 files changed, 102 insertions(+), 144 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 8848333..fec0262 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -260,7 +260,7 @@ struct iwl_cfg iwl1000_bgn_cfg = {
 	.shadow_ram_support = false,
 	.ht_greenfield_support = true,
 	.led_compensation = 51,
-	.use_rts_for_ht = true, /* use rts/cts protection */
+	.use_rts_for_aggregation = true, /* use rts/cts protection */
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.support_ct_kill_exit = true,
 	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index a07310f..6950a78 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -769,22 +769,6 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
 		rts_retry_limit = data_retry_limit;
 	tx_cmd->rts_retry_limit = rts_retry_limit;
 
-	if (ieee80211_is_mgmt(fc)) {
-		switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
-		case cpu_to_le16(IEEE80211_STYPE_AUTH):
-		case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
-		case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
-		case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
-			if (tx_flags & TX_CMD_FLG_RTS_MSK) {
-				tx_flags &= ~TX_CMD_FLG_RTS_MSK;
-				tx_flags |= TX_CMD_FLG_CTS_MSK;
-			}
-			break;
-		default:
-			break;
-		}
-	}
-
 	tx_cmd->rate = rate;
 	tx_cmd->tx_flags = tx_flags;
 
@@ -2717,7 +2701,7 @@ static struct iwl_lib_ops iwl3945_lib = {
 static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
 	.get_hcmd_size = iwl3945_get_hcmd_size,
 	.build_addsta_hcmd = iwl3945_build_addsta_hcmd,
-	.rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
+	.tx_cmd_protection = iwlcore_tx_cmd_protection,
 	.request_scan = iwl3945_request_scan,
 };
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index d6531ad..d6da356 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -2223,7 +2223,7 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
 	.build_addsta_hcmd = iwl4965_build_addsta_hcmd,
 	.chain_noise_reset = iwl4965_chain_noise_reset,
 	.gain_computation = iwl4965_gain_computation,
-	.rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
+	.tx_cmd_protection = iwlcore_tx_cmd_protection,
 	.calc_rssi = iwl4965_calc_rssi,
 	.request_scan = iwlagn_request_scan,
 };
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 8093ce2..aacf377 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -506,7 +506,7 @@ struct iwl_cfg iwl5300_agn_cfg = {
 	.use_bsm = false,
 	.ht_greenfield_support = true,
 	.led_compensation = 51,
-	.use_rts_for_ht = true, /* use rts/cts protection */
+	.use_rts_for_aggregation = true, /* use rts/cts protection */
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 	.chain_noise_scale = 1000,
@@ -537,7 +537,7 @@ struct iwl_cfg iwl5100_bgn_cfg = {
 	.use_bsm = false,
 	.ht_greenfield_support = true,
 	.led_compensation = 51,
-	.use_rts_for_ht = true, /* use rts/cts protection */
+	.use_rts_for_aggregation = true, /* use rts/cts protection */
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 	.chain_noise_scale = 1000,
@@ -597,7 +597,7 @@ struct iwl_cfg iwl5100_agn_cfg = {
 	.use_bsm = false,
 	.ht_greenfield_support = true,
 	.led_compensation = 51,
-	.use_rts_for_ht = true, /* use rts/cts protection */
+	.use_rts_for_aggregation = true, /* use rts/cts protection */
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 	.chain_noise_scale = 1000,
@@ -628,7 +628,7 @@ struct iwl_cfg iwl5350_agn_cfg = {
 	.use_bsm = false,
 	.ht_greenfield_support = true,
 	.led_compensation = 51,
-	.use_rts_for_ht = true, /* use rts/cts protection */
+	.use_rts_for_aggregation = true, /* use rts/cts protection */
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 	.chain_noise_scale = 1000,
@@ -659,7 +659,7 @@ struct iwl_cfg iwl5150_agn_cfg = {
 	.use_bsm = false,
 	.ht_greenfield_support = true,
 	.led_compensation = 51,
-	.use_rts_for_ht = true, /* use rts/cts protection */
+	.use_rts_for_aggregation = true, /* use rts/cts protection */
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 	.chain_noise_scale = 1000,
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 5827052..af4fd50 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -381,7 +381,7 @@ struct iwl_cfg iwl6000g2a_2agn_cfg = {
 	.shadow_ram_support = true,
 	.ht_greenfield_support = true,
 	.led_compensation = 51,
-	.use_rts_for_ht = true, /* use rts/cts protection */
+	.use_rts_for_aggregation = true, /* use rts/cts protection */
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.supports_idle = true,
 	.adv_thermal_throttle = true,
@@ -489,7 +489,7 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = {
 	.shadow_ram_support = true,
 	.ht_greenfield_support = true,
 	.led_compensation = 51,
-	.use_rts_for_ht = true, /* use rts/cts protection */
+	.use_rts_for_aggregation = true, /* use rts/cts protection */
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.supports_idle = true,
 	.adv_thermal_throttle = true,
@@ -563,7 +563,7 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = {
 	.shadow_ram_support = true,
 	.ht_greenfield_support = true,
 	.led_compensation = 51,
-	.use_rts_for_ht = true, /* use rts/cts protection */
+	.use_rts_for_aggregation = true, /* use rts/cts protection */
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.supports_idle = true,
 	.adv_thermal_throttle = true,
@@ -637,7 +637,7 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = {
 	.shadow_ram_support = true,
 	.ht_greenfield_support = true,
 	.led_compensation = 51,
-	.use_rts_for_ht = true, /* use rts/cts protection */
+	.use_rts_for_aggregation = true, /* use rts/cts protection */
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.supports_idle = true,
 	.adv_thermal_throttle = true,
@@ -714,7 +714,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
 	.shadow_ram_support = true,
 	.ht_greenfield_support = true,
 	.led_compensation = 51,
-	.use_rts_for_ht = true, /* use rts/cts protection */
+	.use_rts_for_aggregation = true, /* use rts/cts protection */
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.supports_idle = true,
 	.adv_thermal_throttle = true,
@@ -821,7 +821,7 @@ struct iwl_cfg iwl6050_2agn_cfg = {
 	.shadow_ram_support = true,
 	.ht_greenfield_support = true,
 	.led_compensation = 51,
-	.use_rts_for_ht = true, /* use rts/cts protection */
+	.use_rts_for_aggregation = true, /* use rts/cts protection */
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.supports_idle = true,
 	.adv_thermal_throttle = true,
@@ -859,7 +859,7 @@ struct iwl_cfg iwl6050g2_bgn_cfg = {
 	.shadow_ram_support = true,
 	.ht_greenfield_support = true,
 	.led_compensation = 51,
-	.use_rts_for_ht = true, /* use rts/cts protection */
+	.use_rts_for_aggregation = true, /* use rts/cts protection */
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.supports_idle = true,
 	.adv_thermal_throttle = true,
@@ -933,7 +933,7 @@ struct iwl_cfg iwl6000_3agn_cfg = {
 	.shadow_ram_support = true,
 	.ht_greenfield_support = true,
 	.led_compensation = 51,
-	.use_rts_for_ht = true, /* use rts/cts protection */
+	.use_rts_for_aggregation = true, /* use rts/cts protection */
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.supports_idle = true,
 	.adv_thermal_throttle = true,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
index a7216dd..75b901b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
@@ -211,10 +211,21 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
 	}
 }
 
-static void iwlagn_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
-			__le32 *tx_flags)
+static void iwlagn_tx_cmd_protection(struct iwl_priv *priv,
+				     struct ieee80211_tx_info *info,
+				     __le16 fc, __le32 *tx_flags)
 {
-	*tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
+	if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS ||
+	    info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+		*tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
+		return;
+	}
+
+	if (priv->cfg->use_rts_for_aggregation &&
+	    info->flags & IEEE80211_TX_CTL_AMPDU) {
+		*tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
+		return;
+	}
 }
 
 /* Calc max signal level (dBm) among 3 possible receivers */
@@ -268,7 +279,7 @@ struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = {
 	.build_addsta_hcmd = iwlagn_build_addsta_hcmd,
 	.gain_computation = iwlagn_gain_computation,
 	.chain_noise_reset = iwlagn_chain_noise_reset,
-	.rts_tx_cmd_flag = iwlagn_rts_tx_cmd_flag,
+	.tx_cmd_protection = iwlagn_tx_cmd_protection,
 	.calc_rssi = iwlagn_calc_rssi,
 	.request_scan = iwlagn_request_scan,
 };
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index d04502d..69155aa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -379,10 +379,7 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
 		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
 	}
 
-	priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags);
-
-	if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
-		tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+	priv->cfg->ops->utils->tx_cmd_protection(priv, info, fc, &tx_flags);
 
 	tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
 	if (ieee80211_is_mgmt(fc)) {
@@ -456,21 +453,6 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
 	if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
 		rate_flags |= RATE_MCS_CCK_MSK;
 
-	/* Set up RTS and CTS flags for certain packets */
-	switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
-	case cpu_to_le16(IEEE80211_STYPE_AUTH):
-	case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
-	case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
-	case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
-		if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) {
-			tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK;
-			tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK;
-		}
-		break;
-	default:
-		break;
-	}
-
 	/* Set up antennas */
 	priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
 					      priv->hw_params.valid_tx_ant);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 35337b1..c1882fd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -202,13 +202,6 @@ int iwl_commit_rxon(struct iwl_priv *priv)
 
 	priv->start_calib = 0;
 	if (new_assoc) {
-		/*
-		 * allow CTS-to-self if possible for new association.
-		 * this is relevant only for 5000 series and up,
-		 * but will not damage 4965
-		 */
-		priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
-
 		/* Apply the new configuration
 		 * RXON assoc doesn't clear the station table in uCode,
 		 */
@@ -1618,45 +1611,9 @@ static ssize_t store_tx_power(struct device *d,
 
 static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
 
-static ssize_t show_rts_ht_protection(struct device *d,
-			     struct device_attribute *attr, char *buf)
-{
-	struct iwl_priv *priv = dev_get_drvdata(d);
-
-	return sprintf(buf, "%s\n",
-		priv->cfg->use_rts_for_ht ? "RTS/CTS" : "CTS-to-self");
-}
-
-static ssize_t store_rts_ht_protection(struct device *d,
-			      struct device_attribute *attr,
-			      const char *buf, size_t count)
-{
-	struct iwl_priv *priv = dev_get_drvdata(d);
-	unsigned long val;
-	int ret;
-
-	ret = strict_strtoul(buf, 10, &val);
-	if (ret)
-		IWL_INFO(priv, "Input is not in decimal form.\n");
-	else {
-		if (!iwl_is_associated(priv))
-			priv->cfg->use_rts_for_ht = val ? true : false;
-		else
-			IWL_ERR(priv, "Sta associated with AP - "
-				"Change protection mechanism is not allowed\n");
-		ret = count;
-	}
-	return ret;
-}
-
-static DEVICE_ATTR(rts_ht_protection, S_IWUSR | S_IRUGO,
-			show_rts_ht_protection, store_rts_ht_protection);
-
-
 static struct attribute *iwl_sysfs_entries[] = {
 	&dev_attr_temperature.attr,
 	&dev_attr_tx_power.attr,
-	&dev_attr_rts_ht_protection.attr,
 #ifdef CONFIG_IWLWIFI_DEBUG
 	&dev_attr_debug_level.attr,
 #endif
@@ -3464,25 +3421,6 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 	return ret;
 }
 
-/*
- * switch to RTS/CTS for TX
- */
-static void iwl_enable_rts_cts(struct iwl_priv *priv)
-{
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
-
-	priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
-	if (!test_bit(STATUS_SCANNING, &priv->status)) {
-		IWL_DEBUG_INFO(priv, "use RTS/CTS protection\n");
-		iwlcore_commit_rxon(priv);
-	} else {
-		/* scanning, defer the request until scan completed */
-		IWL_DEBUG_INFO(priv, "defer setting RTS/CTS protection\n");
-	}
-}
-
 static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
 				struct ieee80211_vif *vif,
 				enum ieee80211_ampdu_mlme_action action,
@@ -3529,14 +3467,33 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
 		}
 		if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 			ret = 0;
+		if (priv->cfg->use_rts_for_aggregation) {
+			struct iwl_station_priv *sta_priv =
+				(void *) sta->drv_priv;
+			/*
+			 * switch off RTS/CTS if it was previously enabled
+			 */
+
+			sta_priv->lq_sta.lq.general_params.flags &=
+				~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
+			iwl_send_lq_cmd(priv, &sta_priv->lq_sta.lq,
+				CMD_ASYNC, false);
+		}
 		break;
 	case IEEE80211_AMPDU_TX_OPERATIONAL:
-		if (priv->cfg->use_rts_for_ht) {
+		if (priv->cfg->use_rts_for_aggregation) {
+			struct iwl_station_priv *sta_priv =
+				(void *) sta->drv_priv;
+
 			/*
 			 * switch to RTS/CTS if it is the prefer protection
 			 * method for HT traffic
 			 */
-			iwl_enable_rts_cts(priv);
+
+			sta_priv->lq_sta.lq.general_params.flags |=
+				LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
+			iwl_send_lq_cmd(priv, &sta_priv->lq_sta.lq,
+				CMD_ASYNC, false);
 		}
 		ret = 0;
 		break;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 8ccb6d2..2c03c6e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -401,21 +401,38 @@ void iwlcore_free_geos(struct iwl_priv *priv)
 EXPORT_SYMBOL(iwlcore_free_geos);
 
 /*
- *  iwlcore_rts_tx_cmd_flag: Set rts/cts. 3945 and 4965 only share this
+ *  iwlcore_tx_cmd_protection: Set rts/cts. 3945 and 4965 only share this
  *  function.
  */
-void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
-				__le32 *tx_flags)
+void iwlcore_tx_cmd_protection(struct iwl_priv *priv,
+			       struct ieee80211_tx_info *info,
+			       __le16 fc, __le32 *tx_flags)
 {
 	if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
 		*tx_flags |= TX_CMD_FLG_RTS_MSK;
 		*tx_flags &= ~TX_CMD_FLG_CTS_MSK;
+		*tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+
+		if (!ieee80211_is_mgmt(fc))
+			return;
+
+		switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
+		case cpu_to_le16(IEEE80211_STYPE_AUTH):
+		case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
+		case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
+		case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
+			*tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+			*tx_flags |= TX_CMD_FLG_CTS_MSK;
+			break;
+		}
 	} else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
 		*tx_flags &= ~TX_CMD_FLG_RTS_MSK;
 		*tx_flags |= TX_CMD_FLG_CTS_MSK;
+		*tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
 	}
 }
-EXPORT_SYMBOL(iwlcore_rts_tx_cmd_flag);
+EXPORT_SYMBOL(iwlcore_tx_cmd_protection);
+
 
 static bool is_single_rx_stream(struct iwl_priv *priv)
 {
@@ -1869,6 +1886,10 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
 			priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
 		else
 			priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
+		if (bss_conf->use_cts_prot)
+			priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
+		else
+			priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
 	}
 
 	if (changes & BSS_CHANGED_BASIC_RATES) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index e9d23f2..4a71dfb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -104,8 +104,9 @@ struct iwl_hcmd_utils_ops {
 			u32 min_average_noise,
 			u8 default_chain);
 	void (*chain_noise_reset)(struct iwl_priv *priv);
-	void (*rts_tx_cmd_flag)(struct ieee80211_tx_info *info,
-			__le32 *tx_flags);
+	void (*tx_cmd_protection)(struct iwl_priv *priv,
+				  struct ieee80211_tx_info *info,
+				  __le16 fc, __le32 *tx_flags);
 	int  (*calc_rssi)(struct iwl_priv *priv,
 			  struct iwl_rx_phy_res *rx_resp);
 	void (*request_scan)(struct iwl_priv *priv, struct ieee80211_vif *vif);
@@ -249,7 +250,7 @@ struct iwl_mod_params {
  * @led_compensation: compensate on the led on/off time per HW according
  *	to the deviation to achieve the desired led frequency.
  *	The detail algorithm is described in iwl-led.c
- * @use_rts_for_ht: use rts/cts protection for HT traffic
+ * @use_rts_for_aggregation: use rts/cts protection for HT traffic
  * @chain_noise_num_beacons: number of beacons used to compute chain noise
  * @adv_thermal_throttle: support advance thermal throttle
  * @support_ct_kill_exit: support ct kill exit condition
@@ -318,7 +319,7 @@ struct iwl_cfg {
 	const bool ht_greenfield_support;
 	u16 led_compensation;
 	const bool broken_powersave;
-	bool use_rts_for_ht;
+	bool use_rts_for_aggregation;
 	int chain_noise_num_beacons;
 	const bool supports_idle;
 	bool adv_thermal_throttle;
@@ -390,8 +391,9 @@ void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif);
 void iwl_mac_reset_tsf(struct ieee80211_hw *hw);
 int iwl_alloc_txq_mem(struct iwl_priv *priv);
 void iwl_free_txq_mem(struct iwl_priv *priv);
-void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
-				__le32 *tx_flags);
+void iwlcore_tx_cmd_protection(struct iwl_priv *priv,
+			       struct ieee80211_tx_info *info,
+			       __le16 fc, __le32 *tx_flags);
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 int iwl_alloc_traffic_mem(struct iwl_priv *priv);
 void iwl_free_traffic_mem(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index d24eb47..70c4b8f 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -435,10 +435,7 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
 		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
 	}
 
-	priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags);
-
-	if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
-		tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+	priv->cfg->ops->utils->tx_cmd_protection(priv, info, fc, &tx_flags);
 
 	tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
 	if (ieee80211_is_mgmt(fc)) {
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 8e9fbfd..51a96f5 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -7,6 +7,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/sched.h>
 #include <linux/ieee80211.h>
 #include <net/cfg80211.h>
 #include <asm/unaligned.h>
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index 71a101f..822f8dc 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -43,8 +43,6 @@ static DEFINE_PCI_DEVICE_TABLE(p54p_table) = {
 	{ PCI_DEVICE(0x1260, 0x3886) },
 	/* Intersil PRISM Xbow Wireless LAN adapter (Symbol AP-300) */
 	{ PCI_DEVICE(0x1260, 0xffff) },
-	/* Standard Microsystems Corp SMC2802W Wireless PCI */
-	{ PCI_DEVICE(0x10b8, 0x2802) },
 	{ },
 };
 
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 636724b..6c24144 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -33,9 +33,9 @@
 #define L2CAP_DEFAULT_FLUSH_TO		0xffff
 #define L2CAP_DEFAULT_TX_WINDOW		63
 #define L2CAP_DEFAULT_MAX_TX		3
-#define L2CAP_DEFAULT_RETRANS_TO	1000    /* 1 second */
+#define L2CAP_DEFAULT_RETRANS_TO	2000    /* 2 seconds */
 #define L2CAP_DEFAULT_MONITOR_TO	12000   /* 12 seconds */
-#define L2CAP_DEFAULT_MAX_PDU_SIZE	672
+#define L2CAP_DEFAULT_MAX_PDU_SIZE	1009    /* Sized for 3-DH5 packet */
 #define L2CAP_DEFAULT_ACK_TO		200
 #define L2CAP_LOCAL_BUSY_TRIES		12
 
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 3e3cd9d..fadf26b 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -2705,8 +2705,9 @@ done:
 		case L2CAP_MODE_ERTM:
 			pi->remote_tx_win = rfc.txwin_size;
 			pi->remote_max_tx = rfc.max_transmit;
-			if (rfc.max_pdu_size > pi->conn->mtu - 10)
-				rfc.max_pdu_size = le16_to_cpu(pi->conn->mtu - 10);
+
+			if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10)
+				rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
 
 			pi->remote_mps = le16_to_cpu(rfc.max_pdu_size);
 
@@ -2723,8 +2724,8 @@ done:
 			break;
 
 		case L2CAP_MODE_STREAMING:
-			if (rfc.max_pdu_size > pi->conn->mtu - 10)
-				rfc.max_pdu_size = le16_to_cpu(pi->conn->mtu - 10);
+			if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10)
+				rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
 
 			pi->remote_mps = le16_to_cpu(rfc.max_pdu_size);
 
@@ -2806,7 +2807,6 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data,
 	if (*result == L2CAP_CONF_SUCCESS) {
 		switch (rfc.mode) {
 		case L2CAP_MODE_ERTM:
-			pi->remote_tx_win   = rfc.txwin_size;
 			pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
 			pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
 			pi->mps    = le16_to_cpu(rfc.max_pdu_size);
@@ -2862,7 +2862,6 @@ static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len)
 done:
 	switch (rfc.mode) {
 	case L2CAP_MODE_ERTM:
-		pi->remote_tx_win   = rfc.txwin_size;
 		pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
 		pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
 		pi->mps    = le16_to_cpu(rfc.max_pdu_size);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index e74a1a2..d1a3fb9 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -843,13 +843,19 @@ int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
 		return -EINVAL;
 	if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) {
 		/* Verify that we are associated with the destination AP */
+		wdev_lock(wdev);
+
 		if (!wdev->current_bss ||
 		    memcmp(wdev->current_bss->pub.bssid, mgmt->bssid,
 			   ETH_ALEN) != 0 ||
 		    (wdev->iftype == NL80211_IFTYPE_STATION &&
 		     memcmp(wdev->current_bss->pub.bssid, mgmt->da,
-			    ETH_ALEN) != 0))
+			    ETH_ALEN) != 0)) {
+			wdev_unlock(wdev);
 			return -ENOTCONN;
+		}
+
+		wdev_unlock(wdev);
 	}
 
 	if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0)
-- 
John W. Linville		Someday the world will need a hero, and you
linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org			might be all we have.  Be ready.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH] netpoll: use non-BH variant of RCU
From: John W. Linville @ 2010-08-10 20:25 UTC (permalink / raw)
  To: netdev; +Cc: David S. Miller, Herbert Xu, Paul E. McKenney, John W. Linville

"netpoll: Fix RCU usage" switched netpoll_rx to use the BH variant
of RCU.  Unfortunately, calling netpoll_rx from netif_rx resulted in
the following backtrace:

WARNING: at kernel/softirq.c:143 _local_bh_enable_ip+0x3e/0xab()
Hardware name: 2373HU6
Modules linked in: arc4 ecb lib80211_crypt_wep fuse nfsd lockd nfs_acl auth_rpcgss exportfs sunrpc cpufreq_ondemand acpi_cpufreq mperf ip6t_REJECT nf_conntrack_ipv6 ip6table_filter ip6_tables ipv6 dm_multipath uinput snd_intel8x0m snd_intel8x0 snd_ac97_codec ac97_bus ppdev snd_seq ipw2200 nsc_ircc snd_seq_device video irda e1000 parport_pc snd_pcm libipw parport output crc_ccitt thinkpad_acpi cfg80211 i2c_i801 joydev pcspkr iTCO_wdt rfkill iTCO_vendor_support lib80211 snd_timer snd soundcore snd_page_alloc yenta_socket radeon ttm drm_kms_helper drm i2c_algo_bit i2c_core [last unloaded: microcode]
Pid: 0, comm: swapper Not tainted 2.6.35-wl+ #5
Call Trace:
 [<c043aa42>] warn_slowpath_common+0x6a/0x7f
 [<c0440541>] ? _local_bh_enable_ip+0x3e/0xab
 [<c072e8dc>] ? rcu_read_unlock_bh+0x21/0x23
 [<c043aa6b>] warn_slowpath_null+0x14/0x18
 [<c0440541>] _local_bh_enable_ip+0x3e/0xab
 [<c04405cd>] local_bh_enable+0x10/0x12
 [<c072e8dc>] rcu_read_unlock_bh+0x21/0x23
 [<c072e978>] netpoll_rx+0x9a/0xa2
 [<c0730ab9>] netif_rx+0x13/0x85
 [<f7cc02db>] libipw_rx+0x78c/0x7b6 [libipw]
 [<c07c6902>] ? _raw_spin_lock_irqsave+0x60/0x6a
 [<f81aedc9>] ipw_irq_tasklet+0xec3/0x1285 [ipw2200]
 [<c07c6f01>] ? _raw_spin_unlock_irq+0x26/0x30
 [<c046189a>] ? print_lock_contention_bug+0x11/0xb2
 [<c046189a>] ? print_lock_contention_bug+0x11/0xb2
 [<c043fd87>] tasklet_action+0x78/0xcb
 [<c0440293>] __do_softirq+0xc4/0x183
 [<c044038d>] do_softirq+0x3b/0x5f
 [<c04404d0>] irq_exit+0x3a/0x6d
 [<c0404423>] do_IRQ+0x8b/0x9f
 [<c04038b5>] common_interrupt+0x35/0x3c
 [<c062ecfa>] ? acpi_idle_enter_simple+0xfe/0x13c
 [<c045007b>] ? exit_itimers+0x2d/0x73
 [<c062ecfc>] ? acpi_idle_enter_simple+0x100/0x13c
 [<c070bf10>] cpuidle_idle_call+0x78/0xdc
 [<c040251c>] cpu_idle+0x9b/0xb7
 [<c07b1dd2>] rest_init+0xa6/0xab
 [<c0a4b96d>] start_kernel+0x389/0x38e
 [<c0a4b0c9>] i386_start_kernel+0xc9/0xd0

Switching back to the non-BH variant of RCU resolves the issue.

Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
 include/linux/netpoll.h |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 413742c..0bdd527 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -63,8 +63,8 @@ static inline bool netpoll_rx(struct sk_buff *skb)
 	unsigned long flags;
 	bool ret = false;
 
-	rcu_read_lock_bh();
-	npinfo = rcu_dereference_bh(skb->dev->npinfo);
+	rcu_read_lock();
+	npinfo = rcu_dereference(skb->dev->npinfo);
 
 	if (!npinfo || (list_empty(&npinfo->rx_np) && !npinfo->rx_flags))
 		goto out;
@@ -76,13 +76,13 @@ static inline bool netpoll_rx(struct sk_buff *skb)
 	spin_unlock_irqrestore(&npinfo->rx_lock, flags);
 
 out:
-	rcu_read_unlock_bh();
+	rcu_read_unlock();
 	return ret;
 }
 
 static inline int netpoll_rx_on(struct sk_buff *skb)
 {
-	struct netpoll_info *npinfo = rcu_dereference_bh(skb->dev->npinfo);
+	struct netpoll_info *npinfo = rcu_dereference(skb->dev->npinfo);
 
 	return npinfo && (!list_empty(&npinfo->rx_np) || npinfo->rx_flags);
 }
-- 
1.7.2.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox