Netdev List
 help / color / mirror / Atom feed
* Subject: [PATCH 5/6] bna: Brocade 10Gb Ethernet device driver
From: Rasesh Mody @ 2010-02-12 14:00 UTC (permalink / raw)
  To: netdev; +Cc: adapter_linux_open_src_team

From: Rasesh Mody <rmody@brocade.com>

This is patch 5/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_fwimg_priv.h                  |   32 +
 include/bfi/bfi.h                 |  174 ++++++++++
 include/bfi/bfi_boot.h            |   35 ++
 include/bfi/bfi_cee.h             |  107 ++++++
 include/bfi/bfi_ctreg.h           |  631 ++++++++++++++++++++++++++++++++++++++
 include/bfi/bfi_ioc.h             |  202 ++++++++++++
 include/bfi/bfi_ll.h              |  422 +++++++++++++++++++++++++
 include/cee/bfa_cee.h             |   76 ++++
 include/cna/pstats/ethport_defs.h |   35 ++
 include/cna/pstats/phyport_defs.h |  196 +++++++++++
 include/cs/bfa_debug.h            |   45 ++
 include/cs/bfa_q.h                |   82 ++++
 include/cs/bfa_sm.h               |   79 ++++
 include/cs/bfa_trc.h              |  167 ++++++++++
 include/defs/bfa_defs_adapter.h   |   82 ++++
 include/defs/bfa_defs_cee.h       |  146 ++++++++
 include/defs/bfa_defs_ioc.h       |  150 +++++++++
 include/defs/bfa_defs_mfg.h       |  141 ++++++++
 include/defs/bfa_defs_pci.h       |   42 ++
 include/defs/bfa_defs_status.h    |  265 +++++++++++++++
 include/protocol/types.h          |   39 ++
 21 files changed, 3148 insertions(+)

diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/bfa_fwimg_priv.h net-next-2.6.33-rc5-mod/drivers/net/bna/bfa_fwimg_priv.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/bfa_fwimg_priv.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/bfa_fwimg_priv.h	2010-02-12 01:39:46.029571000 -0800
@@ -0,0 +1,32 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef __BFA_FWIMG_PRIV_H__
+#define __BFA_FWIMG_PRIV_H__
+
+#define	BFI_FLASH_CHUNK_SZ		256	/*  Flash chunk size */
+#define	BFI_FLASH_CHUNK_SZ_WORDS	(BFI_FLASH_CHUNK_SZ/sizeof(u32))
+
+extern u32 *bfi_image_ct_get_chunk(u32 off);
+extern u32 bfi_image_ct_size;
+extern u32 *bfi_image_cb_get_chunk(u32 off);
+extern u32 bfi_image_cb_size;
+extern u32 *bfi_image_cb;
+extern u32 *bfi_image_ct;
+
+#endif /* __BFA_FWIMG_PRIV_H__ */
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/bfi/bfi.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/bfi/bfi.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/bfi/bfi.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/bfi/bfi.h	2010-02-12 01:39:46.647568000 -0800
@@ -0,0 +1,174 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef __BFI_H__
+#define __BFI_H__
+
+#include "cna.h"
+#include "defs/bfa_defs_status.h"
+
+#pragma pack(1)
+
+/**
+ * Msg header common to all msgs
+ */
+struct bfi_mhdr {
+	u8		msg_class;	/*  @ref bfi_mclass_t		    */
+	u8		msg_id;		/*  msg opcode with in the class   */
+	union {
+		struct {
+			u8	rsvd;
+			u8	lpu_id;	/*  msg destination		    */
+		} h2i;
+		u16	i2htok;	/*  token in msgs to host	    */
+	} mtag;
+};
+
+#define bfi_h2i_set(_mh, _mc, _op, _lpuid) do {		\
+	(_mh).msg_class 		= (_mc);      \
+	(_mh).msg_id			= (_op);      \
+	(_mh).mtag.h2i.lpu_id	= (_lpuid);      \
+} while (0)
+
+#define bfi_i2h_set(_mh, _mc, _op, _i2htok) do {		\
+	(_mh).msg_class 		= (_mc);      \
+	(_mh).msg_id			= (_op);      \
+	(_mh).mtag.i2htok		= (_i2htok);      \
+} while (0)
+
+/*
+ * Message opcodes: 0-127 to firmware, 128-255 to host
+ */
+#define BFI_I2H_OPCODE_BASE	128
+#define BFA_I2HM(_x) 			((_x) + BFI_I2H_OPCODE_BASE)
+
+/**
+ ****************************************************************************
+ *
+ * Scatter Gather Element and Page definition
+ *
+ ****************************************************************************
+ */
+
+#define BFI_SGE_INLINE	1
+#define BFI_SGE_INLINE_MAX	(BFI_SGE_INLINE + 1)
+
+/**
+ * SG Flags
+ */
+enum {
+	BFI_SGE_DATA		= 0,	/*  data address, not last	     */
+	BFI_SGE_DATA_CPL	= 1,	/*  data addr, last in current page */
+	BFI_SGE_DATA_LAST	= 3,	/*  data address, last		     */
+	BFI_SGE_LINK		= 2,	/*  link address		     */
+	BFI_SGE_PGDLEN		= 2,	/*  cumulative data length for page */
+};
+
+/**
+ * DMA addresses
+ */
+union bfi_addr_u {
+	struct {
+		u32	addr_lo;
+		u32	addr_hi;
+	} a32;
+};
+
+/**
+ * Scatter Gather Element
+ */
+struct bfi_sge {
+#ifdef __BIGENDIAN
+	u32	flags:2,
+			rsvd:2,
+			sg_len:28;
+#else
+	u32	sg_len:28,
+			rsvd:2,
+			flags:2;
+#endif
+	union bfi_addr_u sga;
+};
+
+/**
+ * Scatter Gather Page
+ */
+#define BFI_SGPG_DATA_SGES		7
+#define BFI_SGPG_SGES_MAX		(BFI_SGPG_DATA_SGES + 1)
+#define BFI_SGPG_RSVD_WD_LEN	8
+struct bfi_sgpg {
+	struct bfi_sge sges[BFI_SGPG_SGES_MAX];
+	u32	rsvd[BFI_SGPG_RSVD_WD_LEN];
+};
+
+/*
+ * Large Message structure - 128 Bytes size Msgs
+ */
+#define BFI_LMSG_SZ		128
+#define BFI_LMSG_PL_WSZ	\
+			((BFI_LMSG_SZ - sizeof(struct bfi_mhdr)) / 4)
+
+struct bfi_msg {
+	struct bfi_mhdr mhdr;
+	u32	pl[BFI_LMSG_PL_WSZ];
+};
+
+/**
+ * Mailbox message structure
+ */
+#define BFI_MBMSG_SZ		7
+struct bfi_mbmsg {
+	struct bfi_mhdr mh;
+	u32		pl[BFI_MBMSG_SZ];
+};
+
+/**
+ * Message Classes
+ */
+enum bfi_mclass {
+	BFI_MC_IOC		= 1,	/*  IO Controller (IOC)	    */
+	BFI_MC_DIAG		= 2,	/*  Diagnostic Msgs		    */
+	BFI_MC_FLASH		= 3,	/*  Flash message class	    */
+	BFI_MC_CEE		= 4,	/*  CEE			    */
+	BFI_MC_FCPORT		= 5,	/*  FC port			    */
+	BFI_MC_IOCFC		= 6,	/*  FC - IO Controller (IOC)	    */
+	BFI_MC_LL		= 7,	/*  Link Layer			    */
+	BFI_MC_UF		= 8,	/*  Unsolicited frame receive	    */
+	BFI_MC_FCXP		= 9,	/*  FC Transport		    */
+	BFI_MC_LPS		= 10,	/*  lport fc login services	    */
+	BFI_MC_RPORT		= 11,	/*  Remote port		    */
+	BFI_MC_ITNIM		= 12,	/*  I-T nexus (Initiator mode)	    */
+	BFI_MC_IOIM_READ	= 13,	/*  read IO (Initiator mode)	    */
+	BFI_MC_IOIM_WRITE	= 14,	/*  write IO (Initiator mode)	    */
+	BFI_MC_IOIM_IO		= 15,	/*  IO (Initiator mode)	    */
+	BFI_MC_IOIM		= 16,	/*  IO (Initiator mode)	    */
+	BFI_MC_IOIM_IOCOM	= 17,	/*  good IO completion		    */
+	BFI_MC_TSKIM		= 18,	/*  Initiator Task management	    */
+	BFI_MC_SBOOT		= 19,	/*  SAN boot services		    */
+	BFI_MC_IPFC		= 20,	/*  IP over FC Msgs		    */
+	BFI_MC_PORT		= 21,	/*  Physical port		    */
+	BFI_MC_MAX		= 32
+};
+
+#define BFI_IOC_MAX_CQS		4
+#define BFI_IOC_MAX_CQS_ASIC	8
+#define BFI_IOC_MSGLEN_MAX	32	/* 32 bytes */
+
+#pragma pack()
+
+#endif /* __BFI_H__ */
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/bfi/bfi_boot.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/bfi/bfi_boot.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/bfi/bfi_boot.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/bfi/bfi_boot.h	2010-02-12 01:39:46.951514000 -0800
@@ -0,0 +1,35 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+/*
+ * bfi_boot.h
+ */
+
+#ifndef __BFI_BOOT_H__
+#define __BFI_BOOT_H__
+
+#define BFI_BOOT_TYPE_OFF		8
+#define BFI_BOOT_PARAM_OFF		12
+
+#define BFI_BOOT_TYPE_NORMAL 		0	/* param is device id */
+#define	BFI_BOOT_TYPE_FLASH		1
+#define	BFI_BOOT_TYPE_MEMTEST		2
+
+#define BFI_BOOT_MEMTEST_RES_ADDR   0x900
+#define BFI_BOOT_MEMTEST_RES_SIG    0xA0A1A2A3
+
+#endif
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/bfi/bfi_cee.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/bfi/bfi_cee.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/bfi/bfi_cee.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/bfi/bfi_cee.h	2010-02-12 01:39:46.988503000 -0800
@@ -0,0 +1,107 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/**
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ *  bfi_dcbx.h BFI Interface (Mailbox commands and related structures)
+ * between host driver and DCBX/LLDP firmware module.
+ *
+**/
+
+#ifndef __BFI_CEE_H__
+#define __BFI_CEE_H__
+
+#include "bfi/bfi.h"
+
+#pragma pack(1)
+
+enum bfi_cee_h2i_msgs {
+	BFI_CEE_H2I_GET_CFG_REQ = 1,
+	BFI_CEE_H2I_RESET_STATS = 2,
+	BFI_CEE_H2I_GET_STATS_REQ = 3,
+};
+
+enum bfi_cee_i2h_msgs {
+	BFI_CEE_I2H_GET_CFG_RSP = BFA_I2HM(1),
+	BFI_CEE_I2H_RESET_STATS_RSP = BFA_I2HM(2),
+	BFI_CEE_I2H_GET_STATS_RSP = BFA_I2HM(3),
+};
+
+/* Data structures */
+
+/*
+ * BFI_CEE_H2I_RESET_STATS
+ */
+struct bfi_lldp_reset_stats {
+	struct bfi_mhdr mh;
+};
+
+/*
+ * BFI_CEE_H2I_RESET_STATS
+ */
+struct bfi_cee_reset_stats {
+	struct bfi_mhdr mh;
+};
+
+/*
+ * BFI_CEE_H2I_GET_CFG_REQ
+ */
+struct bfi_cee_get_req {
+	struct bfi_mhdr mh;
+	union bfi_addr_u   dma_addr;
+};
+
+/*
+ * BFI_CEE_I2H_GET_CFG_RSP
+ */
+struct bfi_cee_get_rsp {
+	struct bfi_mhdr mh;
+	u8            cmd_status;
+	u8            rsvd[3];
+};
+
+/*
+ * BFI_CEE_H2I_GET_STATS_REQ
+ */
+struct bfi_cee_stats_req {
+	struct bfi_mhdr mh;
+	union bfi_addr_u   dma_addr;
+};
+
+/*
+ * BFI_CEE_I2H_GET_STATS_RSP
+ */
+struct bfi_cee_stats_rsp {
+	struct bfi_mhdr mh;
+	u8 		   cmd_status;
+	u8 		   rsvd[3];
+};
+
+union bfi_cee_h2i_msg_u {
+	struct bfi_mhdr mh;
+	struct bfi_cee_get_req get_req;
+	struct bfi_cee_stats_req stats_req;
+};
+
+union bfi_cee_i2h_msg_u {
+	struct bfi_mhdr mh;
+	struct bfi_cee_get_rsp get_rsp;
+	struct bfi_cee_stats_rsp stats_rsp;
+};
+
+#pragma pack()
+
+#endif /* __BFI_CEE_H__ */
+
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/bfi/bfi_ctreg.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/bfi/bfi_ctreg.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/bfi/bfi_ctreg.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/bfi/bfi_ctreg.h	2010-02-12 01:39:47.287506000 -0800
@@ -0,0 +1,631 @@
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+/*
+ * 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.
+ */
+
+/*
+ * bfi_ctreg.h catapult host block register definitions
+ *
+ * !!! Do not edit. Auto generated. !!!
+ */
+
+#ifndef __BFI_CTREG_H__
+#define __BFI_CTREG_H__
+
+#define HOSTFN0_LPU_MBOX0_0              0x00019200
+#define HOSTFN1_LPU_MBOX0_8              0x00019260
+#define LPU_HOSTFN0_MBOX0_0              0x00019280
+#define LPU_HOSTFN1_MBOX0_8              0x000192e0
+#define HOSTFN2_LPU_MBOX0_0              0x00019400
+#define HOSTFN3_LPU_MBOX0_8              0x00019460
+#define LPU_HOSTFN2_MBOX0_0              0x00019480
+#define LPU_HOSTFN3_MBOX0_8              0x000194e0
+#define HOSTFN0_INT_STATUS               0x00014000
+#define __HOSTFN0_HALT_OCCURRED          0x01000000
+#define __HOSTFN0_INT_STATUS_LVL_MK      0x00f00000
+#define __HOSTFN0_INT_STATUS_LVL_SH      20
+#define __HOSTFN0_INT_STATUS_LVL(_v)     ((_v) << __HOSTFN0_INT_STATUS_LVL_SH)
+#define __HOSTFN0_INT_STATUS_P_MK        0x000f0000
+#define __HOSTFN0_INT_STATUS_P_SH        16
+#define __HOSTFN0_INT_STATUS_P(_v)       ((_v) << __HOSTFN0_INT_STATUS_P_SH)
+#define __HOSTFN0_INT_STATUS_F           0x0000ffff
+#define HOSTFN0_INT_MSK                  0x00014004
+#define HOST_PAGE_NUM_FN0                0x00014008
+#define __HOST_PAGE_NUM_FN               0x000001ff
+#define HOST_MSIX_ERR_INDEX_FN0          0x0001400c
+#define __MSIX_ERR_INDEX_FN              0x000001ff
+#define HOSTFN1_INT_STATUS               0x00014100
+#define __HOSTFN1_HALT_OCCURRED          0x01000000
+#define __HOSTFN1_INT_STATUS_LVL_MK      0x00f00000
+#define __HOSTFN1_INT_STATUS_LVL_SH      20
+#define __HOSTFN1_INT_STATUS_LVL(_v)     ((_v) << __HOSTFN1_INT_STATUS_LVL_SH)
+#define __HOSTFN1_INT_STATUS_P_MK        0x000f0000
+#define __HOSTFN1_INT_STATUS_P_SH        16
+#define __HOSTFN1_INT_STATUS_P(_v)       ((_v) << __HOSTFN1_INT_STATUS_P_SH)
+#define __HOSTFN1_INT_STATUS_F           0x0000ffff
+#define HOSTFN1_INT_MSK                  0x00014104
+#define HOST_PAGE_NUM_FN1                0x00014108
+#define HOST_MSIX_ERR_INDEX_FN1          0x0001410c
+#define APP_PLL_425_CTL_REG              0x00014204
+#define __P_425_PLL_LOCK                 0x80000000
+#define __APP_PLL_425_SRAM_USE_100MHZ    0x00100000
+#define __APP_PLL_425_RESET_TIMER_MK     0x000e0000
+#define __APP_PLL_425_RESET_TIMER_SH     17
+#define __APP_PLL_425_RESET_TIMER(_v)    ((_v) << __APP_PLL_425_RESET_TIMER_SH)
+#define __APP_PLL_425_LOGIC_SOFT_RESET   0x00010000
+#define __APP_PLL_425_CNTLMT0_1_MK       0x0000c000
+#define __APP_PLL_425_CNTLMT0_1_SH       14
+#define __APP_PLL_425_CNTLMT0_1(_v)      ((_v) << __APP_PLL_425_CNTLMT0_1_SH)
+#define __APP_PLL_425_JITLMT0_1_MK       0x00003000
+#define __APP_PLL_425_JITLMT0_1_SH       12
+#define __APP_PLL_425_JITLMT0_1(_v)      ((_v) << __APP_PLL_425_JITLMT0_1_SH)
+#define __APP_PLL_425_HREF               0x00000800
+#define __APP_PLL_425_HDIV               0x00000400
+#define __APP_PLL_425_P0_1_MK            0x00000300
+#define __APP_PLL_425_P0_1_SH            8
+#define __APP_PLL_425_P0_1(_v)           ((_v) << __APP_PLL_425_P0_1_SH)
+#define __APP_PLL_425_Z0_2_MK            0x000000e0
+#define __APP_PLL_425_Z0_2_SH            5
+#define __APP_PLL_425_Z0_2(_v)           ((_v) << __APP_PLL_425_Z0_2_SH)
+#define __APP_PLL_425_RSEL200500         0x00000010
+#define __APP_PLL_425_ENARST             0x00000008
+#define __APP_PLL_425_BYPASS             0x00000004
+#define __APP_PLL_425_LRESETN            0x00000002
+#define __APP_PLL_425_ENABLE             0x00000001
+#define APP_PLL_312_CTL_REG              0x00014208
+#define __P_312_PLL_LOCK                 0x80000000
+#define __ENABLE_MAC_AHB_1               0x00800000
+#define __ENABLE_MAC_AHB_0               0x00400000
+#define __ENABLE_MAC_1                   0x00200000
+#define __ENABLE_MAC_0                   0x00100000
+#define __APP_PLL_312_RESET_TIMER_MK     0x000e0000
+#define __APP_PLL_312_RESET_TIMER_SH     17
+#define __APP_PLL_312_RESET_TIMER(_v)    ((_v) << __APP_PLL_312_RESET_TIMER_SH)
+#define __APP_PLL_312_LOGIC_SOFT_RESET   0x00010000
+#define __APP_PLL_312_CNTLMT0_1_MK       0x0000c000
+#define __APP_PLL_312_CNTLMT0_1_SH       14
+#define __APP_PLL_312_CNTLMT0_1(_v)      ((_v) << __APP_PLL_312_CNTLMT0_1_SH)
+#define __APP_PLL_312_JITLMT0_1_MK       0x00003000
+#define __APP_PLL_312_JITLMT0_1_SH       12
+#define __APP_PLL_312_JITLMT0_1(_v)      ((_v) << __APP_PLL_312_JITLMT0_1_SH)
+#define __APP_PLL_312_HREF               0x00000800
+#define __APP_PLL_312_HDIV               0x00000400
+#define __APP_PLL_312_P0_1_MK            0x00000300
+#define __APP_PLL_312_P0_1_SH            8
+#define __APP_PLL_312_P0_1(_v)           ((_v) << __APP_PLL_312_P0_1_SH)
+#define __APP_PLL_312_Z0_2_MK            0x000000e0
+#define __APP_PLL_312_Z0_2_SH            5
+#define __APP_PLL_312_Z0_2(_v)           ((_v) << __APP_PLL_312_Z0_2_SH)
+#define __APP_PLL_312_RSEL200500         0x00000010
+#define __APP_PLL_312_ENARST             0x00000008
+#define __APP_PLL_312_BYPASS             0x00000004
+#define __APP_PLL_312_LRESETN            0x00000002
+#define __APP_PLL_312_ENABLE             0x00000001
+#define MBIST_CTL_REG                    0x00014220
+#define __EDRAM_BISTR_START              0x00000004
+#define __MBIST_RESET                    0x00000002
+#define __MBIST_START                    0x00000001
+#define MBIST_STAT_REG                   0x00014224
+#define __EDRAM_BISTR_STATUS             0x00000008
+#define __EDRAM_BISTR_DONE               0x00000004
+#define __MEM_BIT_STATUS                 0x00000002
+#define __MBIST_DONE                     0x00000001
+#define HOST_SEM0_REG                    0x00014230
+#define __HOST_SEMAPHORE                 0x00000001
+#define HOST_SEM1_REG                    0x00014234
+#define HOST_SEM2_REG                    0x00014238
+#define HOST_SEM3_REG                    0x0001423c
+#define HOST_SEM0_INFO_REG               0x00014240
+#define HOST_SEM1_INFO_REG               0x00014244
+#define HOST_SEM2_INFO_REG               0x00014248
+#define HOST_SEM3_INFO_REG               0x0001424c
+#define ETH_MAC_SER_REG                  0x00014288
+#define __APP_EMS_CKBUFAMPIN             0x00000020
+#define __APP_EMS_REFCLKSEL              0x00000010
+#define __APP_EMS_CMLCKSEL               0x00000008
+#define __APP_EMS_REFCKBUFEN2            0x00000004
+#define __APP_EMS_REFCKBUFEN1            0x00000002
+#define __APP_EMS_CHANNEL_SEL            0x00000001
+#define HOSTFN2_INT_STATUS               0x00014300
+#define __HOSTFN2_HALT_OCCURRED          0x01000000
+#define __HOSTFN2_INT_STATUS_LVL_MK      0x00f00000
+#define __HOSTFN2_INT_STATUS_LVL_SH      20
+#define __HOSTFN2_INT_STATUS_LVL(_v)     ((_v) << __HOSTFN2_INT_STATUS_LVL_SH)
+#define __HOSTFN2_INT_STATUS_P_MK        0x000f0000
+#define __HOSTFN2_INT_STATUS_P_SH        16
+#define __HOSTFN2_INT_STATUS_P(_v)       ((_v) << __HOSTFN2_INT_STATUS_P_SH)
+#define __HOSTFN2_INT_STATUS_F           0x0000ffff
+#define HOSTFN2_INT_MSK                  0x00014304
+#define HOST_PAGE_NUM_FN2                0x00014308
+#define HOST_MSIX_ERR_INDEX_FN2          0x0001430c
+#define HOSTFN3_INT_STATUS               0x00014400
+#define __HALT_OCCURRED                  0x01000000
+#define __HOSTFN3_INT_STATUS_LVL_MK      0x00f00000
+#define __HOSTFN3_INT_STATUS_LVL_SH      20
+#define __HOSTFN3_INT_STATUS_LVL(_v)     ((_v) << __HOSTFN3_INT_STATUS_LVL_SH)
+#define __HOSTFN3_INT_STATUS_P_MK        0x000f0000
+#define __HOSTFN3_INT_STATUS_P_SH        16
+#define __HOSTFN3_INT_STATUS_P(_v)       ((_v) << __HOSTFN3_INT_STATUS_P_SH)
+#define __HOSTFN3_INT_STATUS_F           0x0000ffff
+#define HOSTFN3_INT_MSK                  0x00014404
+#define HOST_PAGE_NUM_FN3                0x00014408
+#define HOST_MSIX_ERR_INDEX_FN3          0x0001440c
+#define FNC_ID_REG                       0x00014600
+#define __FUNCTION_NUMBER                0x00000007
+#define FNC_PERS_REG                     0x00014604
+#define __F3_FUNCTION_ACTIVE             0x80000000
+#define __F3_FUNCTION_MODE               0x40000000
+#define __F3_PORT_MAP_MK                 0x30000000
+#define __F3_PORT_MAP_SH                 28
+#define __F3_PORT_MAP(_v)                ((_v) << __F3_PORT_MAP_SH)
+#define __F3_VM_MODE                     0x08000000
+#define __F3_INTX_STATUS_MK              0x07000000
+#define __F3_INTX_STATUS_SH              24
+#define __F3_INTX_STATUS(_v)             ((_v) << __F3_INTX_STATUS_SH)
+#define __F2_FUNCTION_ACTIVE             0x00800000
+#define __F2_FUNCTION_MODE               0x00400000
+#define __F2_PORT_MAP_MK                 0x00300000
+#define __F2_PORT_MAP_SH                 20
+#define __F2_PORT_MAP(_v)                ((_v) << __F2_PORT_MAP_SH)
+#define __F2_VM_MODE                     0x00080000
+#define __F2_INTX_STATUS_MK              0x00070000
+#define __F2_INTX_STATUS_SH              16
+#define __F2_INTX_STATUS(_v)             ((_v) << __F2_INTX_STATUS_SH)
+#define __F1_FUNCTION_ACTIVE             0x00008000
+#define __F1_FUNCTION_MODE               0x00004000
+#define __F1_PORT_MAP_MK                 0x00003000
+#define __F1_PORT_MAP_SH                 12
+#define __F1_PORT_MAP(_v)                ((_v) << __F1_PORT_MAP_SH)
+#define __F1_VM_MODE                     0x00000800
+#define __F1_INTX_STATUS_MK              0x00000700
+#define __F1_INTX_STATUS_SH              8
+#define __F1_INTX_STATUS(_v)             ((_v) << __F1_INTX_STATUS_SH)
+#define __F0_FUNCTION_ACTIVE             0x00000080
+#define __F0_FUNCTION_MODE               0x00000040
+#define __F0_PORT_MAP_MK                 0x00000030
+#define __F0_PORT_MAP_SH                 4
+#define __F0_PORT_MAP(_v)                ((_v) << __F0_PORT_MAP_SH)
+#define __F0_VM_MODE                     0x00000008
+#define __F0_INTX_STATUS                 0x00000007
+enum {
+    __F0_INTX_STATUS_MSIX            = 0x0,
+    __F0_INTX_STATUS_INTA            = 0x1,
+    __F0_INTX_STATUS_INTB            = 0x2,
+    __F0_INTX_STATUS_INTC            = 0x3,
+    __F0_INTX_STATUS_INTD            = 0x4,
+};
+#define OP_MODE                          0x0001460c
+#define __APP_ETH_CLK_LOWSPEED           0x00000004
+#define __GLOBAL_CORECLK_HALFSPEED       0x00000002
+#define __GLOBAL_FCOE_MODE               0x00000001
+#define HOST_SEM4_REG                    0x00014610
+#define HOST_SEM5_REG                    0x00014614
+#define HOST_SEM6_REG                    0x00014618
+#define HOST_SEM7_REG                    0x0001461c
+#define HOST_SEM4_INFO_REG               0x00014620
+#define HOST_SEM5_INFO_REG               0x00014624
+#define HOST_SEM6_INFO_REG               0x00014628
+#define HOST_SEM7_INFO_REG               0x0001462c
+#define HOSTFN0_LPU0_MBOX0_CMD_STAT      0x00019000
+#define __HOSTFN0_LPU0_MBOX0_INFO_MK     0xfffffffe
+#define __HOSTFN0_LPU0_MBOX0_INFO_SH     1
+#define __HOSTFN0_LPU0_MBOX0_INFO(_v)    ((_v) << __HOSTFN0_LPU0_MBOX0_INFO_SH)
+#define __HOSTFN0_LPU0_MBOX0_CMD_STATUS  0x00000001
+#define HOSTFN0_LPU1_MBOX0_CMD_STAT      0x00019004
+#define __HOSTFN0_LPU1_MBOX0_INFO_MK     0xfffffffe
+#define __HOSTFN0_LPU1_MBOX0_INFO_SH     1
+#define __HOSTFN0_LPU1_MBOX0_INFO(_v)    ((_v) << __HOSTFN0_LPU1_MBOX0_INFO_SH)
+#define __HOSTFN0_LPU1_MBOX0_CMD_STATUS  0x00000001
+#define LPU0_HOSTFN0_MBOX0_CMD_STAT      0x00019008
+#define __LPU0_HOSTFN0_MBOX0_INFO_MK     0xfffffffe
+#define __LPU0_HOSTFN0_MBOX0_INFO_SH     1
+#define __LPU0_HOSTFN0_MBOX0_INFO(_v)    ((_v) << __LPU0_HOSTFN0_MBOX0_INFO_SH)
+#define __LPU0_HOSTFN0_MBOX0_CMD_STATUS  0x00000001
+#define LPU1_HOSTFN0_MBOX0_CMD_STAT      0x0001900c
+#define __LPU1_HOSTFN0_MBOX0_INFO_MK     0xfffffffe
+#define __LPU1_HOSTFN0_MBOX0_INFO_SH     1
+#define __LPU1_HOSTFN0_MBOX0_INFO(_v)    ((_v) << __LPU1_HOSTFN0_MBOX0_INFO_SH)
+#define __LPU1_HOSTFN0_MBOX0_CMD_STATUS  0x00000001
+#define HOSTFN1_LPU0_MBOX0_CMD_STAT      0x00019010
+#define __HOSTFN1_LPU0_MBOX0_INFO_MK     0xfffffffe
+#define __HOSTFN1_LPU0_MBOX0_INFO_SH     1
+#define __HOSTFN1_LPU0_MBOX0_INFO(_v)    ((_v) << __HOSTFN1_LPU0_MBOX0_INFO_SH)
+#define __HOSTFN1_LPU0_MBOX0_CMD_STATUS  0x00000001
+#define HOSTFN1_LPU1_MBOX0_CMD_STAT      0x00019014
+#define __HOSTFN1_LPU1_MBOX0_INFO_MK     0xfffffffe
+#define __HOSTFN1_LPU1_MBOX0_INFO_SH     1
+#define __HOSTFN1_LPU1_MBOX0_INFO(_v)    ((_v) << __HOSTFN1_LPU1_MBOX0_INFO_SH)
+#define __HOSTFN1_LPU1_MBOX0_CMD_STATUS  0x00000001
+#define LPU0_HOSTFN1_MBOX0_CMD_STAT      0x00019018
+#define __LPU0_HOSTFN1_MBOX0_INFO_MK     0xfffffffe
+#define __LPU0_HOSTFN1_MBOX0_INFO_SH     1
+#define __LPU0_HOSTFN1_MBOX0_INFO(_v)    ((_v) << __LPU0_HOSTFN1_MBOX0_INFO_SH)
+#define __LPU0_HOSTFN1_MBOX0_CMD_STATUS  0x00000001
+#define LPU1_HOSTFN1_MBOX0_CMD_STAT      0x0001901c
+#define __LPU1_HOSTFN1_MBOX0_INFO_MK     0xfffffffe
+#define __LPU1_HOSTFN1_MBOX0_INFO_SH     1
+#define __LPU1_HOSTFN1_MBOX0_INFO(_v)    ((_v) << __LPU1_HOSTFN1_MBOX0_INFO_SH)
+#define __LPU1_HOSTFN1_MBOX0_CMD_STATUS  0x00000001
+#define HOSTFN2_LPU0_MBOX0_CMD_STAT      0x00019150
+#define __HOSTFN2_LPU0_MBOX0_INFO_MK     0xfffffffe
+#define __HOSTFN2_LPU0_MBOX0_INFO_SH     1
+#define __HOSTFN2_LPU0_MBOX0_INFO(_v)    ((_v) << __HOSTFN2_LPU0_MBOX0_INFO_SH)
+#define __HOSTFN2_LPU0_MBOX0_CMD_STATUS  0x00000001
+#define HOSTFN2_LPU1_MBOX0_CMD_STAT      0x00019154
+#define __HOSTFN2_LPU1_MBOX0_INFO_MK     0xfffffffe
+#define __HOSTFN2_LPU1_MBOX0_INFO_SH     1
+#define __HOSTFN2_LPU1_MBOX0_INFO(_v)    ((_v) << __HOSTFN2_LPU1_MBOX0_INFO_SH)
+#define __HOSTFN2_LPU1_MBOX0BOX0_CMD_STATUS 0x00000001
+#define LPU0_HOSTFN2_MBOX0_CMD_STAT      0x00019158
+#define __LPU0_HOSTFN2_MBOX0_INFO_MK     0xfffffffe
+#define __LPU0_HOSTFN2_MBOX0_INFO_SH     1
+#define __LPU0_HOSTFN2_MBOX0_INFO(_v)    ((_v) << __LPU0_HOSTFN2_MBOX0_INFO_SH)
+#define __LPU0_HOSTFN2_MBOX0_CMD_STATUS  0x00000001
+#define LPU1_HOSTFN2_MBOX0_CMD_STAT      0x0001915c
+#define __LPU1_HOSTFN2_MBOX0_INFO_MK     0xfffffffe
+#define __LPU1_HOSTFN2_MBOX0_INFO_SH     1
+#define __LPU1_HOSTFN2_MBOX0_INFO(_v)    ((_v) << __LPU1_HOSTFN2_MBOX0_INFO_SH)
+#define __LPU1_HOSTFN2_MBOX0_CMD_STATUS  0x00000001
+#define HOSTFN3_LPU0_MBOX0_CMD_STAT      0x00019160
+#define __HOSTFN3_LPU0_MBOX0_INFO_MK     0xfffffffe
+#define __HOSTFN3_LPU0_MBOX0_INFO_SH     1
+#define __HOSTFN3_LPU0_MBOX0_INFO(_v)    ((_v) << __HOSTFN3_LPU0_MBOX0_INFO_SH)
+#define __HOSTFN3_LPU0_MBOX0_CMD_STATUS  0x00000001
+#define HOSTFN3_LPU1_MBOX0_CMD_STAT      0x00019164
+#define __HOSTFN3_LPU1_MBOX0_INFO_MK     0xfffffffe
+#define __HOSTFN3_LPU1_MBOX0_INFO_SH     1
+#define __HOSTFN3_LPU1_MBOX0_INFO(_v)    ((_v) << __HOSTFN3_LPU1_MBOX0_INFO_SH)
+#define __HOSTFN3_LPU1_MBOX0_CMD_STATUS  0x00000001
+#define LPU0_HOSTFN3_MBOX0_CMD_STAT      0x00019168
+#define __LPU0_HOSTFN3_MBOX0_INFO_MK     0xfffffffe
+#define __LPU0_HOSTFN3_MBOX0_INFO_SH     1
+#define __LPU0_HOSTFN3_MBOX0_INFO(_v)    ((_v) << __LPU0_HOSTFN3_MBOX0_INFO_SH)
+#define __LPU0_HOSTFN3_MBOX0_CMD_STATUS  0x00000001
+#define LPU1_HOSTFN3_MBOX0_CMD_STAT      0x0001916c
+#define __LPU1_HOSTFN3_MBOX0_INFO_MK     0xfffffffe
+#define __LPU1_HOSTFN3_MBOX0_INFO_SH     1
+#define __LPU1_HOSTFN3_MBOX0_INFO(_v)    ((_v) << __LPU1_HOSTFN3_MBOX0_INFO_SH)
+#define __LPU1_HOSTFN3_MBOX0_CMD_STATUS  0x00000001
+#define FW_INIT_HALT_P0                  0x000191ac
+#define __FW_INIT_HALT_P                 0x00000001
+#define FW_INIT_HALT_P1                  0x000191bc
+#define CPE_PI_PTR_Q0                    0x00038000
+#define __CPE_PI_UNUSED_MK               0xffff0000
+#define __CPE_PI_UNUSED_SH               16
+#define __CPE_PI_UNUSED(_v)              ((_v) << __CPE_PI_UNUSED_SH)
+#define __CPE_PI_PTR                     0x0000ffff
+#define CPE_PI_PTR_Q1                    0x00038040
+#define CPE_CI_PTR_Q0                    0x00038004
+#define __CPE_CI_UNUSED_MK               0xffff0000
+#define __CPE_CI_UNUSED_SH               16
+#define __CPE_CI_UNUSED(_v)              ((_v) << __CPE_CI_UNUSED_SH)
+#define __CPE_CI_PTR                     0x0000ffff
+#define CPE_CI_PTR_Q1                    0x00038044
+#define CPE_DEPTH_Q0                     0x00038008
+#define __CPE_DEPTH_UNUSED_MK            0xf8000000
+#define __CPE_DEPTH_UNUSED_SH            27
+#define __CPE_DEPTH_UNUSED(_v)           ((_v) << __CPE_DEPTH_UNUSED_SH)
+#define __CPE_MSIX_VEC_INDEX_MK          0x07ff0000
+#define __CPE_MSIX_VEC_INDEX_SH          16
+#define __CPE_MSIX_VEC_INDEX(_v)         ((_v) << __CPE_MSIX_VEC_INDEX_SH)
+#define __CPE_DEPTH                      0x0000ffff
+#define CPE_DEPTH_Q1                     0x00038048
+#define CPE_QCTRL_Q0                     0x0003800c
+#define __CPE_CTRL_UNUSED30_MK           0xfc000000
+#define __CPE_CTRL_UNUSED30_SH           26
+#define __CPE_CTRL_UNUSED30(_v)          ((_v) << __CPE_CTRL_UNUSED30_SH)
+#define __CPE_FUNC_INT_CTRL_MK           0x03000000
+#define __CPE_FUNC_INT_CTRL_SH           24
+#define __CPE_FUNC_INT_CTRL(_v)          ((_v) << __CPE_FUNC_INT_CTRL_SH)
+enum {
+    __CPE_FUNC_INT_CTRL_DISABLE      = 0x0,
+    __CPE_FUNC_INT_CTRL_F2NF         = 0x1,
+    __CPE_FUNC_INT_CTRL_3QUART       = 0x2,
+    __CPE_FUNC_INT_CTRL_HALF         = 0x3,
+};
+#define __CPE_CTRL_UNUSED20_MK           0x00f00000
+#define __CPE_CTRL_UNUSED20_SH           20
+#define __CPE_CTRL_UNUSED20(_v)          ((_v) << __CPE_CTRL_UNUSED20_SH)
+#define __CPE_SCI_TH_MK                  0x000f0000
+#define __CPE_SCI_TH_SH                  16
+#define __CPE_SCI_TH(_v)                 ((_v) << __CPE_SCI_TH_SH)
+#define __CPE_CTRL_UNUSED10_MK           0x0000c000
+#define __CPE_CTRL_UNUSED10_SH           14
+#define __CPE_CTRL_UNUSED10(_v)          ((_v) << __CPE_CTRL_UNUSED10_SH)
+#define __CPE_ACK_PENDING                0x00002000
+#define __CPE_CTRL_UNUSED40_MK           0x00001c00
+#define __CPE_CTRL_UNUSED40_SH           10
+#define __CPE_CTRL_UNUSED40(_v)          ((_v) << __CPE_CTRL_UNUSED40_SH)
+#define __CPE_PCIEID_MK                  0x00000300
+#define __CPE_PCIEID_SH                  8
+#define __CPE_PCIEID(_v)                 ((_v) << __CPE_PCIEID_SH)
+#define __CPE_CTRL_UNUSED00_MK           0x000000fe
+#define __CPE_CTRL_UNUSED00_SH           1
+#define __CPE_CTRL_UNUSED00(_v)          ((_v) << __CPE_CTRL_UNUSED00_SH)
+#define __CPE_ESIZE                      0x00000001
+#define CPE_QCTRL_Q1                     0x0003804c
+#define __CPE_CTRL_UNUSED31_MK           0xfc000000
+#define __CPE_CTRL_UNUSED31_SH           26
+#define __CPE_CTRL_UNUSED31(_v)          ((_v) << __CPE_CTRL_UNUSED31_SH)
+#define __CPE_CTRL_UNUSED21_MK           0x00f00000
+#define __CPE_CTRL_UNUSED21_SH           20
+#define __CPE_CTRL_UNUSED21(_v)          ((_v) << __CPE_CTRL_UNUSED21_SH)
+#define __CPE_CTRL_UNUSED11_MK           0x0000c000
+#define __CPE_CTRL_UNUSED11_SH           14
+#define __CPE_CTRL_UNUSED11(_v)          ((_v) << __CPE_CTRL_UNUSED11_SH)
+#define __CPE_CTRL_UNUSED41_MK           0x00001c00
+#define __CPE_CTRL_UNUSED41_SH           10
+#define __CPE_CTRL_UNUSED41(_v)          ((_v) << __CPE_CTRL_UNUSED41_SH)
+#define __CPE_CTRL_UNUSED01_MK           0x000000fe
+#define __CPE_CTRL_UNUSED01_SH           1
+#define __CPE_CTRL_UNUSED01(_v)          ((_v) << __CPE_CTRL_UNUSED01_SH)
+#define RME_PI_PTR_Q0                    0x00038020
+#define __LATENCY_TIME_STAMP_MK          0xffff0000
+#define __LATENCY_TIME_STAMP_SH          16
+#define __LATENCY_TIME_STAMP(_v)         ((_v) << __LATENCY_TIME_STAMP_SH)
+#define __RME_PI_PTR                     0x0000ffff
+#define RME_PI_PTR_Q1                    0x00038060
+#define RME_CI_PTR_Q0                    0x00038024
+#define __DELAY_TIME_STAMP_MK            0xffff0000
+#define __DELAY_TIME_STAMP_SH            16
+#define __DELAY_TIME_STAMP(_v)           ((_v) << __DELAY_TIME_STAMP_SH)
+#define __RME_CI_PTR                     0x0000ffff
+#define RME_CI_PTR_Q1                    0x00038064
+#define RME_DEPTH_Q0                     0x00038028
+#define __RME_DEPTH_UNUSED_MK            0xf8000000
+#define __RME_DEPTH_UNUSED_SH            27
+#define __RME_DEPTH_UNUSED(_v)           ((_v) << __RME_DEPTH_UNUSED_SH)
+#define __RME_MSIX_VEC_INDEX_MK          0x07ff0000
+#define __RME_MSIX_VEC_INDEX_SH          16
+#define __RME_MSIX_VEC_INDEX(_v)         ((_v) << __RME_MSIX_VEC_INDEX_SH)
+#define __RME_DEPTH                      0x0000ffff
+#define RME_DEPTH_Q1                     0x00038068
+#define RME_QCTRL_Q0                     0x0003802c
+#define __RME_INT_LATENCY_TIMER_MK       0xff000000
+#define __RME_INT_LATENCY_TIMER_SH       24
+#define __RME_INT_LATENCY_TIMER(_v)      ((_v) << __RME_INT_LATENCY_TIMER_SH)
+#define __RME_INT_DELAY_TIMER_MK         0x00ff0000
+#define __RME_INT_DELAY_TIMER_SH         16
+#define __RME_INT_DELAY_TIMER(_v)        ((_v) << __RME_INT_DELAY_TIMER_SH)
+#define __RME_INT_DELAY_DISABLE          0x00008000
+#define __RME_DLY_DELAY_DISABLE          0x00004000
+#define __RME_ACK_PENDING                0x00002000
+#define __RME_FULL_INTERRUPT_DISABLE     0x00001000
+#define __RME_CTRL_UNUSED10_MK           0x00000c00
+#define __RME_CTRL_UNUSED10_SH           10
+#define __RME_CTRL_UNUSED10(_v)          ((_v) << __RME_CTRL_UNUSED10_SH)
+#define __RME_PCIEID_MK                  0x00000300
+#define __RME_PCIEID_SH                  8
+#define __RME_PCIEID(_v)                 ((_v) << __RME_PCIEID_SH)
+#define __RME_CTRL_UNUSED00_MK           0x000000fe
+#define __RME_CTRL_UNUSED00_SH           1
+#define __RME_CTRL_UNUSED00(_v)          ((_v) << __RME_CTRL_UNUSED00_SH)
+#define __RME_ESIZE                      0x00000001
+#define RME_QCTRL_Q1                     0x0003806c
+#define __RME_CTRL_UNUSED11_MK           0x00000c00
+#define __RME_CTRL_UNUSED11_SH           10
+#define __RME_CTRL_UNUSED11(_v)          ((_v) << __RME_CTRL_UNUSED11_SH)
+#define __RME_CTRL_UNUSED01_MK           0x000000fe
+#define __RME_CTRL_UNUSED01_SH           1
+#define __RME_CTRL_UNUSED01(_v)          ((_v) << __RME_CTRL_UNUSED01_SH)
+#define PSS_CTL_REG                      0x00018800
+#define __PSS_I2C_CLK_DIV_MK             0x007f0000
+#define __PSS_I2C_CLK_DIV_SH             16
+#define __PSS_I2C_CLK_DIV(_v)            ((_v) << __PSS_I2C_CLK_DIV_SH)
+#define __PSS_LMEM_INIT_DONE             0x00001000
+#define __PSS_LMEM_RESET                 0x00000200
+#define __PSS_LMEM_INIT_EN               0x00000100
+#define __PSS_LPU1_RESET                 0x00000002
+#define __PSS_LPU0_RESET                 0x00000001
+#define PSS_ERR_STATUS_REG               0x00018810
+#define __PSS_LPU1_TCM_READ_ERR          0x00200000
+#define __PSS_LPU0_TCM_READ_ERR          0x00100000
+#define __PSS_LMEM5_CORR_ERR             0x00080000
+#define __PSS_LMEM4_CORR_ERR             0x00040000
+#define __PSS_LMEM3_CORR_ERR             0x00020000
+#define __PSS_LMEM2_CORR_ERR             0x00010000
+#define __PSS_LMEM1_CORR_ERR             0x00008000
+#define __PSS_LMEM0_CORR_ERR             0x00004000
+#define __PSS_LMEM5_UNCORR_ERR           0x00002000
+#define __PSS_LMEM4_UNCORR_ERR           0x00001000
+#define __PSS_LMEM3_UNCORR_ERR           0x00000800
+#define __PSS_LMEM2_UNCORR_ERR           0x00000400
+#define __PSS_LMEM1_UNCORR_ERR           0x00000200
+#define __PSS_LMEM0_UNCORR_ERR           0x00000100
+#define __PSS_BAL_PERR                   0x00000080
+#define __PSS_DIP_IF_ERR                 0x00000040
+#define __PSS_IOH_IF_ERR                 0x00000020
+#define __PSS_TDS_IF_ERR                 0x00000010
+#define __PSS_RDS_IF_ERR                 0x00000008
+#define __PSS_SGM_IF_ERR                 0x00000004
+#define __PSS_LPU1_RAM_ERR               0x00000002
+#define __PSS_LPU0_RAM_ERR               0x00000001
+#define ERR_SET_REG                      0x00018818
+#define __PSS_ERR_STATUS_SET             0x003fffff
+#define HQM_QSET0_RXQ_DRBL_P0            0x00038000
+#define __RXQ0_ADD_VECTORS_P             0x80000000
+#define __RXQ0_STOP_P                    0x40000000
+#define __RXQ0_PRD_PTR_P                 0x0000ffff
+#define HQM_QSET1_RXQ_DRBL_P0            0x00038080
+#define __RXQ1_ADD_VECTORS_P             0x80000000
+#define __RXQ1_STOP_P                    0x40000000
+#define __RXQ1_PRD_PTR_P                 0x0000ffff
+#define HQM_QSET0_RXQ_DRBL_P1            0x0003c000
+#define HQM_QSET1_RXQ_DRBL_P1            0x0003c080
+#define HQM_QSET0_TXQ_DRBL_P0            0x00038020
+#define __TXQ0_ADD_VECTORS_P             0x80000000
+#define __TXQ0_STOP_P                    0x40000000
+#define __TXQ0_PRD_PTR_P                 0x0000ffff
+#define HQM_QSET1_TXQ_DRBL_P0            0x000380a0
+#define __TXQ1_ADD_VECTORS_P             0x80000000
+#define __TXQ1_STOP_P                    0x40000000
+#define __TXQ1_PRD_PTR_P                 0x0000ffff
+#define HQM_QSET0_TXQ_DRBL_P1            0x0003c020
+#define HQM_QSET1_TXQ_DRBL_P1            0x0003c0a0
+#define HQM_QSET0_IB_DRBL_1_P0           0x00038040
+#define __IB1_0_ACK_P                    0x80000000
+#define __IB1_0_DISABLE_P                0x40000000
+#define __IB1_0_NUM_OF_ACKED_EVENTS_P    0x0000ffff
+#define HQM_QSET1_IB_DRBL_1_P0           0x000380c0
+#define __IB1_1_ACK_P                    0x80000000
+#define __IB1_1_DISABLE_P                0x40000000
+#define __IB1_1_NUM_OF_ACKED_EVENTS_P    0x0000ffff
+#define HQM_QSET0_IB_DRBL_1_P1           0x0003c040
+#define HQM_QSET1_IB_DRBL_1_P1           0x0003c0c0
+#define HQM_QSET0_IB_DRBL_2_P0           0x00038060
+#define __IB2_0_ACK_P                    0x80000000
+#define __IB2_0_DISABLE_P                0x40000000
+#define __IB2_0_NUM_OF_ACKED_EVENTS_P    0x0000ffff
+#define HQM_QSET1_IB_DRBL_2_P0           0x000380e0
+#define __IB2_1_ACK_P                    0x80000000
+#define __IB2_1_DISABLE_P                0x40000000
+#define __IB2_1_NUM_OF_ACKED_EVENTS_P    0x0000ffff
+#define HQM_QSET0_IB_DRBL_2_P1           0x0003c060
+#define HQM_QSET1_IB_DRBL_2_P1           0x0003c0e0
+
+/*
+ * These definitions are either in error/missing in spec. Its auto-generated
+ * from hard coded values in regparse.pl.
+ */
+#define __EMPHPOST_AT_4G_MK_FIX          0x0000001c
+#define __EMPHPOST_AT_4G_SH_FIX          0x00000002
+#define __EMPHPRE_AT_4G_FIX              0x00000003
+#define __SFP_TXRATE_EN_FIX              0x00000100
+#define __SFP_RXRATE_EN_FIX              0x00000080
+
+/*
+ * These register definitions are auto-generated from hard coded values
+ * in regparse.pl.
+ */
+
+/*
+ * These register mapping definitions are auto-generated from mapping tables
+ * in regparse.pl.
+ */
+#define BFA_IOC0_HBEAT_REG               HOST_SEM0_INFO_REG
+#define BFA_IOC0_STATE_REG               HOST_SEM1_INFO_REG
+#define BFA_IOC1_HBEAT_REG               HOST_SEM2_INFO_REG
+#define BFA_IOC1_STATE_REG               HOST_SEM3_INFO_REG
+#define BFA_FW_USE_COUNT                 HOST_SEM4_INFO_REG
+
+#define CPE_DEPTH_Q(__n) \
+	(CPE_DEPTH_Q0 + (__n) * (CPE_DEPTH_Q1 - CPE_DEPTH_Q0))
+#define CPE_QCTRL_Q(__n) \
+	(CPE_QCTRL_Q0 + (__n) * (CPE_QCTRL_Q1 - CPE_QCTRL_Q0))
+#define CPE_PI_PTR_Q(__n) \
+	(CPE_PI_PTR_Q0 + (__n) * (CPE_PI_PTR_Q1 - CPE_PI_PTR_Q0))
+#define CPE_CI_PTR_Q(__n) \
+	(CPE_CI_PTR_Q0 + (__n) * (CPE_CI_PTR_Q1 - CPE_CI_PTR_Q0))
+#define RME_DEPTH_Q(__n) \
+	(RME_DEPTH_Q0 + (__n) * (RME_DEPTH_Q1 - RME_DEPTH_Q0))
+#define RME_QCTRL_Q(__n) \
+	(RME_QCTRL_Q0 + (__n) * (RME_QCTRL_Q1 - RME_QCTRL_Q0))
+#define RME_PI_PTR_Q(__n) \
+	(RME_PI_PTR_Q0 + (__n) * (RME_PI_PTR_Q1 - RME_PI_PTR_Q0))
+#define RME_CI_PTR_Q(__n) \
+	(RME_CI_PTR_Q0 + (__n) * (RME_CI_PTR_Q1 - RME_CI_PTR_Q0))
+#define HQM_QSET_RXQ_DRBL_P0(__n) \
+	(HQM_QSET0_RXQ_DRBL_P0 +  \
+		(__n) * (HQM_QSET1_RXQ_DRBL_P0 - HQM_QSET0_RXQ_DRBL_P0))
+#define HQM_QSET_TXQ_DRBL_P0(__n) \
+	(HQM_QSET0_TXQ_DRBL_P0 +  \
+		(__n) * (HQM_QSET1_TXQ_DRBL_P0 - HQM_QSET0_TXQ_DRBL_P0))
+#define HQM_QSET_IB_DRBL_1_P0(__n) \
+	(HQM_QSET0_IB_DRBL_1_P0 +  \
+		(__n) * (HQM_QSET1_IB_DRBL_1_P0 - HQM_QSET0_IB_DRBL_1_P0))
+#define HQM_QSET_IB_DRBL_2_P0(__n) \
+	(HQM_QSET0_IB_DRBL_2_P0 +  \
+		(__n) * (HQM_QSET1_IB_DRBL_2_P0 - HQM_QSET0_IB_DRBL_2_P0))
+#define HQM_QSET_RXQ_DRBL_P1(__n) \
+	(HQM_QSET0_RXQ_DRBL_P1 +  \
+		(__n) * (HQM_QSET1_RXQ_DRBL_P1 - HQM_QSET0_RXQ_DRBL_P1))
+#define HQM_QSET_TXQ_DRBL_P1(__n) \
+	(HQM_QSET0_TXQ_DRBL_P1 +  \
+		(__n) * (HQM_QSET1_TXQ_DRBL_P1 - HQM_QSET0_TXQ_DRBL_P1))
+#define HQM_QSET_IB_DRBL_1_P1(__n) \
+	(HQM_QSET0_IB_DRBL_1_P1 +  \
+		(__n) * (HQM_QSET1_IB_DRBL_1_P1 - HQM_QSET0_IB_DRBL_1_P1))
+#define HQM_QSET_IB_DRBL_2_P1(__n) \
+	(HQM_QSET0_IB_DRBL_2_P1 +  \
+		(__n) * (HQM_QSET1_IB_DRBL_2_P1 - HQM_QSET0_IB_DRBL_2_P1))
+
+#define CPE_Q_NUM(__fn, __q)  (((__fn) << 2) + (__q))
+#define RME_Q_NUM(__fn, __q)  (((__fn) << 2) + (__q))
+#define CPE_Q_MASK(__q)  ((__q) & 0x3)
+#define RME_Q_MASK(__q)  ((__q) & 0x3)
+
+/*
+ * PCI MSI-X vector defines
+ */
+enum {
+    BFA_MSIX_CPE_Q0 = 0,
+    BFA_MSIX_CPE_Q1 = 1,
+    BFA_MSIX_CPE_Q2 = 2,
+    BFA_MSIX_CPE_Q3 = 3,
+    BFA_MSIX_RME_Q0 = 4,
+    BFA_MSIX_RME_Q1 = 5,
+    BFA_MSIX_RME_Q2 = 6,
+    BFA_MSIX_RME_Q3 = 7,
+    BFA_MSIX_LPU_ERR = 8,
+    BFA_MSIX_CT_MAX = 9,
+};
+
+/*
+ * And corresponding host interrupt status bit field defines
+ */
+#define __HFN_INT_CPE_Q0                   0x00000001U
+#define __HFN_INT_CPE_Q1                   0x00000002U
+#define __HFN_INT_CPE_Q2                   0x00000004U
+#define __HFN_INT_CPE_Q3                   0x00000008U
+#define __HFN_INT_CPE_Q4                   0x00000010U
+#define __HFN_INT_CPE_Q5                   0x00000020U
+#define __HFN_INT_CPE_Q6                   0x00000040U
+#define __HFN_INT_CPE_Q7                   0x00000080U
+#define __HFN_INT_RME_Q0                   0x00000100U
+#define __HFN_INT_RME_Q1                   0x00000200U
+#define __HFN_INT_RME_Q2                   0x00000400U
+#define __HFN_INT_RME_Q3                   0x00000800U
+#define __HFN_INT_RME_Q4                   0x00001000U
+#define __HFN_INT_RME_Q5                   0x00002000U
+#define __HFN_INT_RME_Q6                   0x00004000U
+#define __HFN_INT_RME_Q7                   0x00008000U
+#define __HFN_INT_ERR_EMC                  0x00010000U
+#define __HFN_INT_ERR_LPU0                 0x00020000U
+#define __HFN_INT_ERR_LPU1                 0x00040000U
+#define __HFN_INT_ERR_PSS                  0x00080000U
+#define __HFN_INT_MBOX_LPU0                0x00100000U
+#define __HFN_INT_MBOX_LPU1                0x00200000U
+#define __HFN_INT_MBOX1_LPU0               0x00400000U
+#define __HFN_INT_MBOX1_LPU1               0x00800000U
+#define __HFN_INT_LL_HALT                  0x01000000U
+#define __HFN_INT_CPE_MASK                 0x000000ffU
+#define __HFN_INT_RME_MASK                 0x0000ff00U
+
+/*
+ * catapult memory map.
+ */
+#define LL_PGN_HQM0                      0x0096
+#define LL_PGN_HQM1                      0x0097
+#define PSS_SMEM_PAGE_START	0x8000
+#define PSS_SMEM_PGNUM(_pg0, _ma)	((_pg0) + ((_ma) >> 15))
+#define PSS_SMEM_PGOFF(_ma)	((_ma) & 0x7fff)
+
+/*
+ * End of catapult memory map
+ */
+
+#endif /* __BFI_CTREG_H__ */
+
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/bfi/bfi_ioc.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/bfi/bfi_ioc.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/bfi/bfi_ioc.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/bfi/bfi_ioc.h	2010-02-12 01:39:46.970503000 -0800
@@ -0,0 +1,202 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef __BFI_IOC_H__
+#define __BFI_IOC_H__
+
+#include "bfi.h"
+#include "defs/bfa_defs_ioc.h"
+
+#pragma pack(1)
+
+enum bfi_ioc_h2i_msgs {
+	BFI_IOC_H2I_ENABLE_REQ		= 1,
+	BFI_IOC_H2I_DISABLE_REQ		= 2,
+	BFI_IOC_H2I_GETATTR_REQ		= 3,
+	BFI_IOC_H2I_DBG_SYNC		= 4,
+	BFI_IOC_H2I_DBG_DUMP		= 5,
+};
+
+enum bfi_ioc_i2h_msgs {
+	BFI_IOC_I2H_ENABLE_REPLY	= BFA_I2HM(1),
+	BFI_IOC_I2H_DISABLE_REPLY 	= BFA_I2HM(2),
+	BFI_IOC_I2H_GETATTR_REPLY 	= BFA_I2HM(3),
+	BFI_IOC_I2H_READY_EVENT 	= BFA_I2HM(4),
+	BFI_IOC_I2H_HBEAT		= BFA_I2HM(5),
+};
+
+/**
+ * BFI_IOC_H2I_GETATTR_REQ message
+ */
+struct bfi_ioc_getattr_req {
+	struct bfi_mhdr mh;
+	union bfi_addr_u	attr_addr;
+};
+
+struct bfi_ioc_attr {
+	wwn_t		mfg_wwn;
+	struct mac mfg_mac;
+	u16	rsvd_a;
+	char		brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)];
+	u8		pcie_gen;
+	u8		pcie_lanes_orig;
+	u8		pcie_lanes;
+	u8		rx_bbcredit;	/*  receive buffer credits */
+	u32	adapter_prop;	/*  adapter properties     */
+	u16	maxfrsize;	/*  max receive frame size */
+	char		asic_rev;
+	u8		rsvd_b;
+	char		fw_version[BFA_VERSION_LEN];
+	char		optrom_version[BFA_VERSION_LEN];
+	struct bfa_mfg_vpd vpd;
+};
+
+/**
+ * BFI_IOC_I2H_GETATTR_REPLY message
+ */
+struct bfi_ioc_getattr_reply {
+	struct bfi_mhdr mh;	/*  Common msg header		*/
+	u8			status;	/*  cfg reply status		*/
+	u8			rsvd[3];
+};
+
+/**
+ * Firmware memory page offsets
+ */
+#define BFI_IOC_SMEM_PG0_CB	(0x40)
+#define BFI_IOC_SMEM_PG0_CT	(0x180)
+
+/**
+ * Firmware trace offset
+ */
+#define BFI_IOC_TRC_OFF		(0x4b00)
+#define BFI_IOC_TRC_ENTS	256
+
+#define BFI_IOC_FW_SIGNATURE	(0xbfadbfad)
+#define BFI_IOC_MD5SUM_SZ	4
+struct bfi_ioc_image_hdr {
+	u32	signature;	/*  constant signature */
+	u32	rsvd_a;
+	u32	exec;		/*  exec vector	*/
+	u32	param;		/*  parameters		*/
+	u32	rsvd_b[4];
+	u32	md5sum[BFI_IOC_MD5SUM_SZ];
+};
+
+/**
+ *  BFI_IOC_I2H_READY_EVENT message
+ */
+struct bfi_ioc_rdy_event {
+	struct bfi_mhdr mh;		/*  common msg header */
+	u8			init_status;	/*  init event status */
+	u8			rsvd[3];
+};
+
+struct bfi_ioc_hbeat {
+	struct bfi_mhdr mh;		/*  common msg header		*/
+	u32	   hb_count;	/*  current heart beat count	*/
+};
+
+/**
+ * IOC hardware/firmware state
+ */
+enum bfi_ioc_state {
+	BFI_IOC_UNINIT		= 0,	/*  not initialized		     */
+	BFI_IOC_INITING		= 1,	/*  h/w is being initialized	     */
+	BFI_IOC_HWINIT		= 2,	/*  h/w is initialized		     */
+	BFI_IOC_CFG		= 3,	/*  IOC configuration in progress   */
+	BFI_IOC_OP		= 4,	/*  IOC is operational		     */
+	BFI_IOC_DISABLING	= 5,	/*  IOC is being disabled	     */
+	BFI_IOC_DISABLED	= 6,	/*  IOC is disabled		     */
+	BFI_IOC_CFG_DISABLED	= 7,	/*  IOC is being disabled;transient */
+	BFI_IOC_FAIL		= 8,	/*  IOC heart-beat failure	     */
+	BFI_IOC_MEMTEST		= 9,	/*  IOC is doing memtest	     */
+};
+
+#define BFI_IOC_ENDIAN_SIG  0x12345678
+
+enum {
+	BFI_ADAPTER_TYPE_FC	= 0x01,		/*  FC adapters	   */
+	BFI_ADAPTER_TYPE_MK	= 0x0f0000,	/*  adapter type mask     */
+	BFI_ADAPTER_TYPE_SH	= 16,	        /*  adapter type shift    */
+	BFI_ADAPTER_NPORTS_MK	= 0xff00,	/*  number of ports mask  */
+	BFI_ADAPTER_NPORTS_SH	= 8,	        /*  number of ports shift */
+	BFI_ADAPTER_SPEED_MK	= 0xff,		/*  adapter speed mask    */
+	BFI_ADAPTER_SPEED_SH	= 0,	        /*  adapter speed shift   */
+	BFI_ADAPTER_PROTO	= 0x100000,	/*  prototype adapaters   */
+	BFI_ADAPTER_TTV		= 0x200000,	/*  TTV debug capable     */
+	BFI_ADAPTER_UNSUPP	= 0x400000,	/*  unknown adapter type  */
+};
+
+#define BFI_ADAPTER_GETP(__prop, __adap_prop)			\
+	(((__adap_prop) & BFI_ADAPTER_ ## __prop ## _MK) >>	\
+		BFI_ADAPTER_ ## __prop ## _SH)
+#define BFI_ADAPTER_SETP(__prop, __val)				\
+	((__val) << BFI_ADAPTER_ ## __prop ## _SH)
+#define BFI_ADAPTER_IS_PROTO(__adap_type)			\
+	((__adap_type) & BFI_ADAPTER_PROTO)
+#define BFI_ADAPTER_IS_TTV(__adap_type)				\
+	((__adap_type) & BFI_ADAPTER_TTV)
+#define BFI_ADAPTER_IS_UNSUPP(__adap_type)			\
+	((__adap_type) & BFI_ADAPTER_UNSUPP)
+#define BFI_ADAPTER_IS_SPECIAL(__adap_type)			\
+	((__adap_type) & (BFI_ADAPTER_TTV | BFI_ADAPTER_PROTO |	\
+			BFI_ADAPTER_UNSUPP))
+
+/**
+ * BFI_IOC_H2I_ENABLE_REQ & BFI_IOC_H2I_DISABLE_REQ messages
+ */
+struct bfi_ioc_ctrl_req {
+	struct bfi_mhdr mh;
+	u8			ioc_class;
+	u8			rsvd[3];
+};
+
+/**
+ * BFI_IOC_I2H_ENABLE_REPLY & BFI_IOC_I2H_DISABLE_REPLY messages
+ */
+struct bfi_ioc_ctrl_reply {
+	struct bfi_mhdr mh;		/*  Common msg header     */
+	u8			status;		/*  enable/disable status */
+	u8			rsvd[3];
+};
+
+#define BFI_IOC_MSGSZ   8
+/**
+ * H2I Messages
+ */
+union bfi_ioc_h2i_msg_u {
+	struct bfi_mhdr mh;
+	struct bfi_ioc_ctrl_req enable_req;
+	struct bfi_ioc_ctrl_req disable_req;
+	struct bfi_ioc_getattr_req getattr_req;
+	u32			mboxmsg[BFI_IOC_MSGSZ];
+};
+
+/**
+ * I2H Messages
+ */
+union bfi_ioc_i2h_msg_u {
+	struct bfi_mhdr mh;
+	struct bfi_ioc_rdy_event rdy_event;
+	u32			mboxmsg[BFI_IOC_MSGSZ];
+};
+
+#pragma pack()
+
+#endif /* __BFI_IOC_H__ */
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/bfi/bfi_ll.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/bfi/bfi_ll.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/bfi/bfi_ll.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/bfi/bfi_ll.h	2010-02-12 01:39:47.381503000 -0800
@@ -0,0 +1,422 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ *	file bfi_if.h BNA Hardware and Firmware Interface
+ */
+#ifndef __BFI_LL_H__
+#define __BFI_LL_H__
+
+#include "bfi/bfi.h"
+#include "defs/bfa_defs_ioc.h"
+
+#pragma pack(1)
+
+/**
+ *	"enums" for all LL mailbox messages other than IOC
+ */
+enum {
+	BFI_LL_H2I_MAC_UCAST_SET_REQ = 1,
+	BFI_LL_H2I_MAC_UCAST_ADD_REQ = 2,
+	BFI_LL_H2I_MAC_UCAST_DEL_REQ = 3,
+
+	BFI_LL_H2I_MAC_MCAST_ADD_REQ = 4,
+	BFI_LL_H2I_MAC_MCAST_DEL_REQ = 5,
+	BFI_LL_H2I_MAC_MCAST_FILTER_REQ = 6,
+	BFI_LL_H2I_MAC_MCAST_DEL_ALL_REQ = 7,
+
+	BFI_LL_H2I_PORT_ADMIN_REQ = 8,
+	BFI_LL_H2I_STATS_GET_REQ = 9,
+	BFI_LL_H2I_STATS_CLEAR_REQ = 10,
+
+	BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ = 11,
+	BFI_LL_H2I_RXF_DEFAULT_SET_REQ = 12,
+
+	BFI_LL_H2I_TXQ_STOP_REQ = 13,
+	BFI_LL_H2I_RXQ_STOP_REQ = 14,
+
+	BFI_LL_H2I_DIAG_LOOPBACK_REQ = 15,
+
+	BFI_LL_H2I_SET_PAUSE_REQ = 16,
+	BFI_LL_H2I_MTU_INFO_REQ = 17,
+
+	BFI_LL_H2I_RX_REQ = 18,
+};
+
+enum {
+	BFI_LL_I2H_MAC_UCAST_SET_RSP = BFA_I2HM(1),
+	BFI_LL_I2H_MAC_UCAST_ADD_RSP = BFA_I2HM(2),
+	BFI_LL_I2H_MAC_UCAST_DEL_RSP = BFA_I2HM(3),
+
+	BFI_LL_I2H_MAC_MCAST_ADD_RSP = BFA_I2HM(4),
+	BFI_LL_I2H_MAC_MCAST_DEL_RSP = BFA_I2HM(5),
+	BFI_LL_I2H_MAC_MCAST_FILTER_RSP = BFA_I2HM(6),
+	BFI_LL_I2H_MAC_MCAST_DEL_ALL_RSP = BFA_I2HM(7),
+
+	BFI_LL_I2H_PORT_ADMIN_RSP = BFA_I2HM(8),
+	BFI_LL_I2H_STATS_GET_RSP = BFA_I2HM(9),
+	BFI_LL_I2H_STATS_CLEAR_RSP = BFA_I2HM(10),
+
+	BFI_LL_I2H_RXF_PROMISCUOUS_SET_RSP = BFA_I2HM(11),
+	BFI_LL_I2H_RXF_DEFAULT_SET_RSP = BFA_I2HM(12),
+
+	BFI_LL_I2H_TXQ_STOP_RSP = BFA_I2HM(13),
+	BFI_LL_I2H_RXQ_STOP_RSP = BFA_I2HM(14),
+
+	BFI_LL_I2H_DIAG_LOOPBACK_RSP = BFA_I2HM(15),
+
+	BFI_LL_I2H_SET_PAUSE_RSP = BFA_I2HM(16),
+
+	BFI_LL_I2H_MTU_INFO_RSP = BFA_I2HM(17),
+	BFI_LL_I2H_RX_RSP = BFA_I2HM(18),
+
+	BFI_LL_I2H_LINK_DOWN_AEN = BFA_I2HM(19),
+	BFI_LL_I2H_LINK_UP_AEN = BFA_I2HM(20),
+};
+
+/**
+ *        BFI_LL_H2I_MAC_UCAST_SET_REQ
+ *        BFI_LL_H2I_MAC_UCAST_ADD_REQ
+ *        BFI_LL_H2I_MAC_UCAST_DEL_REQ
+ *        BFI_LL_H2I_MAC_MCAST_ADD_REQ
+ *        BFI_LL_H2I_MAC_MCAST_DEL_REQ
+ */
+struct bfi_ll_mac_addr_req {
+	struct bfi_mhdr mh;         /*  common msg header */
+	u8		rxf_id;
+	u8		rsvd1[3];
+	struct mac mac_addr;
+	u8		rsvd2[2];
+};
+
+/**
+ *	  BFI_LL_H2I_MAC_MCAST_FILTER_REQ
+ */
+struct bfi_ll_mcast_filter_req {
+	struct bfi_mhdr mh;         /*  common msg header */
+	u8		rxf_id;
+	u8		enable;
+	u8		rsvd[2];
+};
+
+/**
+ *	  BFI_LL_H2I_MAC_MCAST_DEL_ALL_REQ
+ */
+struct bfi_ll_mcast_del_all_req {
+	struct bfi_mhdr mh;         /*  common msg header */
+	u8		   rxf_id;
+	u8		   rsvd[3];
+};
+
+/**
+ *	BFI_LL_H2I_TXQ_STOP_REQ
+ *	BFI_LL_H2I_RXQ_STOP_REQ
+ */
+struct bfi_ll_q_stop_req {
+	struct bfi_mhdr mh;		/*  common msg header */
+	u32	q_id_mask[2];	/*  bit-mask for queue ids */
+};
+
+/**
+ *    BFI_LL_I2H_STATS_GET_REQ
+ *    BFI_LL_I2H_STATS_CLEAR_REQ
+ */
+struct bfi_ll_stats_req {
+	struct bfi_mhdr mh;		/*  common msg header */
+/*  bit-mask for non-function statistics */
+	u16	stats_mask;
+	u8		rsvd[2];
+	u32	rxf_id_mask[2];	/*  bit-mask for RxF Statistics */
+	u32	txf_id_mask[2];	/*  bit-mask for TxF Statistics */
+	union bfi_addr_u  host_buffer;	/*  where statistics are returned */
+};
+
+#define BFI_LL_STATS_MAC	(1 << 0)	/*  MAC Statistics */
+#define BFI_LL_STATS_BPC	(1 << 1)	/*  Pause Stats from BPC */
+#define BFI_LL_STATS_RAD	(1 << 2)	/*  Rx Admission Statistics */
+#define BFI_LL_STATS_RX_FC	(1 << 3)	/*  Rx FC Stats from RxA */
+#define BFI_LL_STATS_TX_FC	(1 << 4)	/*  Tx FC Stats from TxA */
+#define BFI_LL_STATS_ALL	0x1f
+
+struct bfi_ll_port_admin_req {
+	struct bfi_mhdr mh;         		/*  common msg header */
+	u8		 up;
+	u8		 rsvd[3];
+};
+
+/**
+ *      BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ
+ *      BFI_LL_H2I_RXF_DEFAULT_SET_REQ
+ */
+struct bfi_ll_rxf_req {
+	struct bfi_mhdr mh;         /*  common msg header */
+	u8		rxf_id;
+	u8		enable;
+	u8		rsvd[2];
+};
+
+/**
+ *      BFI_LL_H2I_RX_REQ
+ */
+struct bfi_ll_rxf_multi_req {
+	struct bfi_mhdr mh;		/*  common msg header */
+	u32	rxf_id_mask[2];
+	u8		enable;
+	u8		rsvd[3];
+};
+
+/**
+ *      BFI_LL_H2I_DIAG_LOOPBACK
+ */
+struct bfi_ll_diag_lb_req{
+struct bfi_mhdr mh;     /* 4 bytes */
+u8	enable;			/* =1 : enable, =0 : disable */
+u8	mode;			/* cable or Serdes */
+u8	rsvd[2];
+};
+
+enum {
+	BFI_LL_DIAG_LB_OPMODE_EXT = 0,
+	BFI_LL_DIAG_LB_OPMODE_CBL = 1,
+};
+
+/**
+ *	BFI_LL_H2I_SET_PAUSE_REQ
+ */
+struct bfi_ll_set_pause_req {
+	struct bfi_mhdr mh;
+	u8		tx_pause; /* 1 = enable, 0 =  disable */
+	u8		rx_pause; /* 1 = enable, 0 =  disable */
+	u8		rsvd[2];
+};
+
+/**
+ *	BFI_LL_H2I_MTU_INFO_REQ
+ */
+struct bfi_ll_mtu_info_req {
+	struct bfi_mhdr mh;
+	u16	mtu;
+	u8		rsvd[2];
+};
+
+/**
+ *	  Response header format used by all responses
+ *	  For both responses and asynchronous notifications
+ */
+struct bfi_ll_rsp {
+	struct bfi_mhdr mh;         		/*  common msg header */
+	u8 	 error;
+	u8		 rsvd[3];
+};
+
+/**
+ *	BFI_LL_I2H_LINK_DOWN_AEN
+ *	BFI_LL_I2H_LINK_UP_AEN
+ */
+struct bfi_ll_aen {
+	struct bfi_mhdr mh;          /*  common msg header */
+	u32           reason;
+	u8            cee_linkup;
+	u8            prio_map;    /*  LL priority bit-map */
+	u8            rsvd[2];
+};
+
+/**
+ * 	The following error codes can be returned
+ *	by the mbox commands
+ */
+enum {
+	BFI_LL_CMD_OK 		= 0,
+	BFI_LL_CMD_FAIL 	= 1,
+	BFI_LL_CMD_DUP_ENTRY	= 2,	/*  Duplicate entry in CAM */
+	BFI_LL_CMD_CAM_FULL	= 3,	/*  CAM is full */
+	BFI_LL_CMD_NOT_OWNER	= 4,   	/*  Not permitted, b'cos not owner */
+	BFI_LL_CMD_NOT_EXEC	= 5,   	/*  Was not sent to f/w at all */
+};
+
+/* Statistics */
+#define BFI_LL_TXF_ID_MAX  	64
+#define BFI_LL_RXF_ID_MAX  	64
+
+/* TxF Frame Statistics */
+struct bfi_ll_stats_txf {
+	u64 ucast_octets;
+	u64 ucast;
+	u64 ucast_vlan;
+
+	u64 mcast_octets;
+	u64 mcast;
+	u64 mcast_vlan;
+
+	u64 bcast_octets;
+	u64 bcast;
+	u64 bcast_vlan;
+
+	u64 errors;
+	u64 filter_vlan;      /* frames filtered due to VLAN */
+	u64 filter_mac_sa;    /* frames filtered due to SA check */
+};
+
+/* RxF Frame Statistics */
+struct bfi_ll_stats_rxf {
+	u64 ucast_octets;
+	u64 ucast;
+	u64 ucast_vlan;
+
+	u64 mcast_octets;
+	u64 mcast;
+	u64 mcast_vlan;
+
+	u64 bcast_octets;
+	u64 bcast;
+	u64 bcast_vlan;
+	u64 frame_drops;
+};
+
+/* FC Tx Frame Statistics */
+struct bfi_ll_stats_fc_tx {
+	u64 txf_ucast_octets;
+	u64 txf_ucast;
+	u64 txf_ucast_vlan;
+
+	u64 txf_mcast_octets;
+	u64 txf_mcast;
+	u64 txf_mcast_vlan;
+
+	u64 txf_bcast_octets;
+	u64 txf_bcast;
+	u64 txf_bcast_vlan;
+
+	u64 txf_parity_errors;
+	u64 txf_timeout;
+	u64 txf_fid_parity_errors;
+};
+
+/* FC Rx Frame Statistics */
+struct bfi_ll_stats_fc_rx {
+	u64 rxf_ucast_octets;
+	u64 rxf_ucast;
+	u64 rxf_ucast_vlan;
+
+	u64 rxf_mcast_octets;
+	u64 rxf_mcast;
+	u64 rxf_mcast_vlan;
+
+	u64 rxf_bcast_octets;
+	u64 rxf_bcast;
+	u64 rxf_bcast_vlan;
+};
+
+/* RAD Frame Statistics */
+struct bfi_ll_stats_rad {
+	u64 rx_frames;
+	u64 rx_octets;
+	u64 rx_vlan_frames;
+
+	u64 rx_ucast;
+	u64 rx_ucast_octets;
+	u64 rx_ucast_vlan;
+
+	u64 rx_mcast;
+	u64 rx_mcast_octets;
+	u64 rx_mcast_vlan;
+
+	u64 rx_bcast;
+	u64 rx_bcast_octets;
+	u64 rx_bcast_vlan;
+
+	u64 rx_drops;
+};
+
+/* BPC Tx Registers */
+struct bfi_ll_stats_bpc {
+    /* transmit stats */
+	u64 tx_pause[8];
+	u64 tx_zero_pause[8]; /*  Pause cancellation */
+	u64 tx_first_pause[8];/*  Pause initiation rather than retention*/
+
+	/* receive stats */
+	u64 rx_pause[8];
+	u64 rx_zero_pause[8]; /*  Pause cancellation */
+	u64 rx_first_pause[8];/*  Pause initiation rather than retention*/
+};
+
+/* MAC Rx Statistics */
+struct bfi_ll_stats_mac {
+	u64 frame_64;          /* both rx and tx counter */
+	u64 frame_65_127;      /* both rx and tx counter */
+	u64 frame_128_255;     /* both rx and tx counter */
+	u64 frame_256_511;     /* both rx and tx counter */
+	u64 frame_512_1023;    /* both rx and tx counter */
+	u64 frame_1024_1518;   /* both rx and tx counter */
+	u64 frame_1519_1522;   /* both rx and tx counter */
+
+	/* receive stats */
+	u64 rx_bytes;
+	u64 rx_packets;
+	u64 rx_fcs_error;
+	u64 rx_multicast;
+	u64 rx_broadcast;
+	u64 rx_control_frames;
+	u64 rx_pause;
+	u64 rx_unknown_opcode;
+	u64 rx_alignment_error;
+	u64 rx_frame_length_error;
+	u64 rx_code_error;
+	u64 rx_carrier_sense_error;
+	u64 rx_undersize;
+	u64 rx_oversize;
+	u64 rx_fragments;
+	u64 rx_jabber;
+	u64 rx_drop;
+
+	/* transmit stats */
+	u64 tx_bytes;
+	u64 tx_packets;
+	u64 tx_multicast;
+	u64 tx_broadcast;
+	u64 tx_pause;
+	u64 tx_deferral;
+	u64 tx_excessive_deferral;
+	u64 tx_single_collision;
+	u64 tx_muliple_collision;
+	u64 tx_late_collision;
+	u64 tx_excessive_collision;
+	u64 tx_total_collision;
+	u64 tx_pause_honored;
+	u64 tx_drop;
+	u64 tx_jabber;
+	u64 tx_fcs_error;
+	u64 tx_control_frame;
+	u64 tx_oversize;
+	u64 tx_undersize;
+	u64 tx_fragments;
+};
+
+/* Complete statistics */
+struct bfi_ll_stats {
+	struct bfi_ll_stats_mac		mac_stats;
+	struct bfi_ll_stats_bpc		bpc_stats;
+	struct bfi_ll_stats_rad		rad_stats;
+	struct bfi_ll_stats_fc_rx	fc_rx_stats;
+	struct bfi_ll_stats_fc_tx	fc_tx_stats;
+	struct bfi_ll_stats_rxf	rxf_stats[BFI_LL_RXF_ID_MAX];
+	struct bfi_ll_stats_txf	txf_stats[BFI_LL_TXF_ID_MAX];
+};
+
+#pragma pack()
+
+#endif  /* __BFI_LL_H__ */
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/cee/bfa_cee.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/cee/bfa_cee.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/cee/bfa_cee.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/cee/bfa_cee.h	2010-02-12 01:39:47.663502000 -0800
@@ -0,0 +1,76 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ *      @file bfa_cee.h CEE common module header file.
+ */
+
+#ifndef __BFA_CEE_H__
+#define __BFA_CEE_H__
+
+#include "defs/bfa_defs_cee.h"
+#include "bfa_ioc.h"
+#include "cs/bfa_trc.h"
+
+typedef void (*bfa_cee_get_attr_cbfn_t) (void *dev, bfa_status_t status);
+typedef void (*bfa_cee_get_stats_cbfn_t) (void *dev, bfa_status_t status);
+typedef void (*bfa_cee_reset_stats_cbfn_t) (void *dev, bfa_status_t status);
+typedef void (*bfa_cee_hbfail_cbfn_t) (void *dev, bfa_status_t status);
+
+struct bfa_cee_cbfn {
+	bfa_cee_get_attr_cbfn_t    get_attr_cbfn;
+	void *get_attr_cbarg;
+	bfa_cee_get_stats_cbfn_t   get_stats_cbfn;
+	void *get_stats_cbarg;
+	bfa_cee_reset_stats_cbfn_t reset_stats_cbfn;
+	void *reset_stats_cbarg;
+};
+
+struct bfa_cee {
+	void *dev;
+	bool get_attr_pending;
+	bool get_stats_pending;
+	bool reset_stats_pending;
+	bfa_status_t get_attr_status;
+	bfa_status_t get_stats_status;
+	bfa_status_t reset_stats_status;
+	struct bfa_cee_cbfn cbfn;
+	struct bfa_ioc_hbfail_notify hbfail;
+	struct bfa_trc_mod *trcmod;
+	struct bfa_log_mod *logmod;
+	struct bfa_cee_attr *attr;
+	struct bfa_cee_stats *stats;
+	struct bfa_dma attr_dma;
+	struct bfa_dma stats_dma;
+	struct bfa_ioc *ioc;
+	struct bfa_mbox_cmd get_cfg_mb;
+	struct bfa_mbox_cmd get_stats_mb;
+	struct bfa_mbox_cmd reset_stats_mb;
+};
+
+u32 bfa_cee_meminfo(void);
+void bfa_cee_mem_claim(struct bfa_cee *cee, u8 *dma_kva,
+    u64 dma_pa);
+void bfa_cee_attach(struct bfa_cee *cee, struct bfa_ioc *ioc, void *dev,
+    struct bfa_trc_mod *trcmod, struct bfa_log_mod *logmod);
+bfa_status_t bfa_cee_get_attr(struct bfa_cee *cee,
+    struct bfa_cee_attr *attr, bfa_cee_get_attr_cbfn_t cbfn, void *cbarg);
+bfa_status_t bfa_cee_get_stats(struct bfa_cee *cee,
+    struct bfa_cee_stats *stats, bfa_cee_get_stats_cbfn_t cbfn, void *cbarg);
+bfa_status_t bfa_cee_reset_stats(struct bfa_cee *cee,
+    bfa_cee_reset_stats_cbfn_t cbfn, void *cbarg);
+
+#endif /* __BFA_CEE_H__ */
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/cna/pstats/ethport_defs.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/cna/pstats/ethport_defs.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/cna/pstats/ethport_defs.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/cna/pstats/ethport_defs.h	2010-02-12 01:39:48.340434000 -0800
@@ -0,0 +1,35 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef __ETHPORT_DEFS_H__
+#define __ETHPORT_DEFS_H__
+
+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 napi_complete;
+};
+#endif
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/cna/pstats/phyport_defs.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/cna/pstats/phyport_defs.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/cna/pstats/phyport_defs.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/cna/pstats/phyport_defs.h	2010-02-12 01:39:48.677431000 -0800
@@ -0,0 +1,196 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef __PHYPORT_DEFS_H__
+#define __PHYPORT_DEFS_H__
+
+#define BNA_TXF_ID_MAX  	64
+#define BNA_RXF_ID_MAX  	64
+
+/* Statistics */
+
+/* TxF Frame Statistics */
+struct bna_stats_txf {
+	u64 ucast_octets;
+	u64 ucast;
+	u64 ucast_vlan;
+
+	u64 mcast_octets;
+	u64 mcast;
+	u64 mcast_vlan;
+
+	u64 bcast_octets;
+	u64 bcast;
+	u64 bcast_vlan;
+
+	u64 errors;
+	u64 filter_vlan;      /* frames filtered due to VLAN */
+	u64 filter_mac_sa;    /* frames filtered due to SA check */
+};
+
+/* RxF Frame Statistics */
+struct bna_stats_rxf {
+	u64 ucast_octets;
+	u64 ucast;
+	u64 ucast_vlan;
+
+	u64 mcast_octets;
+	u64 mcast;
+	u64 mcast_vlan;
+
+	u64 bcast_octets;
+	u64 bcast;
+	u64 bcast_vlan;
+	u64 frame_drops;
+};
+
+/* FC Tx Frame Statistics */
+struct bna_stats_fc_tx {
+	u64 txf_ucast_octets;
+	u64 txf_ucast;
+	u64 txf_ucast_vlan;
+
+	u64 txf_mcast_octets;
+	u64 txf_mcast;
+	u64 txf_mcast_vlan;
+
+	u64 txf_bcast_octets;
+	u64 txf_bcast;
+	u64 txf_bcast_vlan;
+
+	u64 txf_parity_errors;
+	u64 txf_timeout;
+	u64 txf_fid_parity_errors;
+};
+
+/* FC Rx Frame Statistics */
+struct bna_stats_fc_rx {
+	u64 rxf_ucast_octets;
+	u64 rxf_ucast;
+	u64 rxf_ucast_vlan;
+
+	u64 rxf_mcast_octets;
+	u64 rxf_mcast;
+	u64 rxf_mcast_vlan;
+
+	u64 rxf_bcast_octets;
+	u64 rxf_bcast;
+	u64 rxf_bcast_vlan;
+};
+
+/* RAD Frame Statistics */
+struct cna_stats_rad {
+	u64 rx_frames;
+	u64 rx_octets;
+	u64 rx_vlan_frames;
+
+	u64 rx_ucast;
+	u64 rx_ucast_octets;
+	u64 rx_ucast_vlan;
+
+	u64 rx_mcast;
+	u64 rx_mcast_octets;
+	u64 rx_mcast_vlan;
+
+	u64 rx_bcast;
+	u64 rx_bcast_octets;
+	u64 rx_bcast_vlan;
+
+	u64 rx_drops;
+};
+
+/* BPC Tx Registers */
+struct cna_stats_bpc_tx {
+	u64 tx_pause[8];
+	u64 tx_zero_pause[8]; /*  Pause cancellation */
+	u64 tx_first_pause[8];/*  Pause initiation rather than retention*/
+};
+
+/* BPC Rx Registers */
+struct cna_stats_bpc_rx {
+	u64 rx_pause[8];
+	u64 rx_zero_pause[8]; /*  Pause cancellation */
+	u64 rx_first_pause[8];/*  Pause initiation rather than retention*/
+};
+
+/* MAC Rx Statistics */
+struct cna_stats_mac_rx {
+	u64 frame_64;		/* both rx and tx counter */
+	u64 frame_65_127;		/* both rx and tx counter */
+	u64 frame_128_255;		/* both rx and tx counter */
+	u64 frame_256_511;		/* both rx and tx counter */
+	u64 frame_512_1023;	/* both rx and tx counter */
+	u64 frame_1024_1518;	/* both rx and tx counter */
+	u64 frame_1518_1522;	/* both rx and tx counter */
+	u64 rx_bytes;
+	u64 rx_packets;
+	u64 rx_fcs_error;
+	u64 rx_multicast;
+	u64 rx_broadcast;
+	u64 rx_control_frames;
+	u64 rx_pause;
+	u64 rx_unknown_opcode;
+	u64 rx_alignment_error;
+	u64 rx_frame_length_error;
+	u64 rx_code_error;
+	u64 rx_carrier_sense_error;
+	u64 rx_undersize;
+	u64 rx_oversize;
+	u64 rx_fragments;
+	u64 rx_jabber;
+	u64 rx_drop;
+};
+
+/* MAC Tx Statistics */
+struct cna_stats_mac_tx {
+	u64 tx_bytes;
+	u64 tx_packets;
+	u64 tx_multicast;
+	u64 tx_broadcast;
+	u64 tx_pause;
+	u64 tx_deferral;
+	u64 tx_excessive_deferral;
+	u64 tx_single_collision;
+	u64 tx_muliple_collision;
+	u64 tx_late_collision;
+	u64 tx_excessive_collision;
+	u64 tx_total_collision;
+	u64 tx_pause_honored;
+	u64 tx_drop;
+	u64 tx_jabber;
+	u64 tx_fcs_error;
+	u64 tx_control_frame;
+	u64 tx_oversize;
+	u64 tx_undersize;
+	u64 tx_fragments;
+};
+
+/* Complete statistics */
+struct bna_stats {
+	struct cna_stats_mac_rx	mac_rx_stats;
+	struct cna_stats_bpc_rx	bpc_rx_stats;
+	struct cna_stats_rad	rad_stats;
+	struct bna_stats_fc_rx	fc_rx_stats;
+	struct cna_stats_mac_tx	mac_tx_stats;
+	struct cna_stats_bpc_tx	bpc_tx_stats;
+	struct bna_stats_fc_tx	fc_tx_stats;
+	struct bna_stats_rxf	rxf_stats[BNA_TXF_ID_MAX];
+	struct bna_stats_txf	txf_stats[BNA_RXF_ID_MAX];
+};
+
+#endif
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/cs/bfa_debug.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/cs/bfa_debug.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/cs/bfa_debug.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/cs/bfa_debug.h	2010-02-12 01:39:49.528363000 -0800
@@ -0,0 +1,45 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+/**
+ *  bfa_debug.h BFA debug interfaces
+ */
+
+#ifndef __BFA_DEBUG_H__
+#define __BFA_DEBUG_H__
+
+#define bfa_assert(__cond)	do {					\
+	if (!(__cond)) 							\
+		bfa_panic(__LINE__, __FILE__, #__cond);      \
+} while (0)
+
+#define bfa_sm_fault(__mod, __event)	do {				\
+	bfa_sm_panic((__mod)->logm, __LINE__, __FILE__, __event);      \
+} while (0)
+
+#ifndef BFA_PERF_BUILD
+#define bfa_assert_fp(__cond)	bfa_assert(__cond)
+#else
+#define bfa_assert_fp(__cond)
+#endif
+
+struct bfa_log_mod;
+void bfa_panic(int line, char *file, char *panicstr);
+void bfa_sm_panic(struct bfa_log_mod *logm, int line, char *file, int event);
+
+#endif /* __BFA_DEBUG_H__ */
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/cs/bfa_q.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/cs/bfa_q.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/cs/bfa_q.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/cs/bfa_q.h	2010-02-12 01:39:49.066367000 -0800
@@ -0,0 +1,82 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+/**
+ *  bfa_q.h Circular queue definitions.
+ */
+
+#ifndef __BFA_Q_H__
+#define __BFA_Q_H__
+
+#define bfa_q_first(_q) ((void *)(((struct list_head *) (_q))->next))
+#define bfa_q_next(_qe)	(((struct list_head *) (_qe))->next)
+#define bfa_q_prev(_qe) (((struct list_head *) (_qe))->prev)
+
+/*
+ * bfa_q_qe_init - to initialize a queue element
+ */
+#define bfa_q_qe_init(_qe) {						\
+	bfa_q_next(_qe) = (struct list_head *) NULL;			\
+	bfa_q_prev(_qe) = (struct list_head *) NULL;			\
+}
+
+/*
+ * bfa_q_deq - dequeue an element from head of the queue
+ */
+#define bfa_q_deq(_q, _qe) {						\
+	if (!list_empty(_q)) {					\
+		(*((struct list_head **) (_qe))) = bfa_q_next(_q);	\
+		bfa_q_prev(bfa_q_next(*((struct list_head **) _qe))) =	\
+						(struct list_head *) (_q); \
+		bfa_q_next(_q) = bfa_q_next(*((struct list_head **) _qe)); \
+		BFA_Q_DBG_INIT(*((struct list_head **) _qe));		\
+	} else {							\
+		*((struct list_head **) (_qe)) = (struct list_head *) NULL; \
+	}								\
+}
+
+/*
+ * bfa_q_deq_tail - dequeue an element from tail of the queue
+ */
+#define bfa_q_deq_tail(_q, _qe) {					    \
+	if (!list_empty(_q)) {					            \
+		*((struct list_head **) (_qe)) = bfa_q_prev(_q);	    \
+		bfa_q_next(bfa_q_prev(*((struct list_head **) _qe))) = 	    \
+						(struct list_head *) (_q);  \
+		bfa_q_prev(_q) = bfa_q_prev(*(struct list_head **) _qe);    \
+		BFA_Q_DBG_INIT(*((struct list_head **) _qe));		    \
+	} else {							    \
+		*((struct list_head **) (_qe)) = (struct list_head *) NULL; \
+	}								    \
+}
+
+/*
+ * #ifdef BFA_DEBUG (Using bfa_assert to check for debug_build is not
+ * consistent across modules)
+ */
+#ifndef BFA_PERF_BUILD
+#define BFA_Q_DBG_INIT(_qe)	bfa_q_qe_init(_qe)
+#else
+#define BFA_Q_DBG_INIT(_qe)
+#endif
+
+#define bfa_q_is_on_q(_q, _qe)		\
+	bfa_q_is_on_q_func(_q, (struct list_head *)(_qe))
+extern int bfa_q_is_on_q_func(struct list_head *q, struct list_head *qe);
+
+#endif
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/cs/bfa_sm.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/cs/bfa_sm.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/cs/bfa_sm.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/cs/bfa_sm.h	2010-02-12 01:39:49.281363000 -0800
@@ -0,0 +1,79 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+/**
+ *  bfasm.h State machine defines
+ */
+
+#ifndef __BFA_SM_H__
+#define __BFA_SM_H__
+
+typedef void (*bfa_sm_t)(void *sm, int event);
+
+/**
+ * oc - object class eg. bfa_ioc
+ * st - state, eg. reset
+ * otype - object type, eg. struct bfa_ioc
+ * etype - object type, eg. enum ioc_event
+ */
+#define bfa_sm_state_decl(oc, st, otype, etype)		\
+	static void oc ## _sm_ ## st(otype * fsm, etype event)
+
+#define bfa_sm_set_state(_sm, _state)	((_sm)->sm = (bfa_sm_t)(_state))
+#define bfa_sm_send_event(_sm, _event)	((_sm)->sm((_sm), (_event)))
+#define bfa_sm_get_state(_sm)		((_sm)->sm)
+#define bfa_sm_cmp_state(_sm, _state)	((_sm)->sm == (bfa_sm_t)(_state))
+
+/**
+ * For converting from state machine function to state encoding.
+ */
+struct bfa_sm_table {
+	bfa_sm_t	sm;	/*  state machine function	*/
+	int		state;	/*  state machine encoding	*/
+	char		*name;	/*  state name for display	*/
+};
+#define BFA_SM(_sm)	((bfa_sm_t)(_sm))
+
+int bfa_sm_to_state(struct bfa_sm_table *smt, bfa_sm_t sm);
+
+/**
+ * State machine with entry actions.
+ */
+typedef void (*bfa_fsm_t)(void *fsm, int event);
+
+/**
+ * oc - object class eg. bfa_ioc
+ * st - state, eg. reset
+ * otype - object type, eg. struct bfa_ioc
+ * etype - object type, eg. enum ioc_event
+ */
+#define bfa_fsm_state_decl(oc, st, otype, etype)		\
+	static void oc ## _sm_ ## st(otype * fsm, etype event);      \
+	static void oc ## _sm_ ## st ## _entry(otype * fsm)
+
+#define bfa_fsm_set_state(_fsm, _state) do {	\
+	(_fsm)->fsm = (bfa_fsm_t)(_state);      \
+	_state ## _entry(_fsm);      \
+} while (0)
+
+#define bfa_fsm_send_event(_fsm, _event)	\
+	((_fsm)->fsm((_fsm), (_event)))
+#define bfa_fsm_cmp_state(_fsm, _state)		\
+	((_fsm)->fsm == (bfa_fsm_t)(_state))
+
+#endif
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/cs/bfa_trc.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/cs/bfa_trc.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/cs/bfa_trc.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/cs/bfa_trc.h	2010-02-12 01:39:49.340366000 -0800
@@ -0,0 +1,167 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#ifndef __BFA_TRC_H__
+#define __BFA_TRC_H__
+
+#include "cna.h"
+
+#ifndef BFA_TRC_MAX
+#define BFA_TRC_MAX	(4 * 1024)
+#endif
+
+#ifndef BFA_TRC_TS
+#define BFA_TRC_TS(_trcm)	((_trcm)->ticks++)
+#endif
+
+struct bfa_trc {
+#ifdef __BIGENDIAN
+	u16	fileno;
+	u16	line;
+#else
+	u16	line;
+	u16	fileno;
+#endif
+	u32	timestamp;
+	union {
+		struct {
+			u32	rsvd;
+			u32	u32;
+		} u32;
+		u64	u64;
+	} data;
+};
+
+struct bfa_trc_mod {
+	u32	head;
+	u32	tail;
+	u32	ntrc;
+	u32	stopped;
+	u32	ticks;
+	u32	rsvd[3];
+	struct bfa_trc trc[BFA_TRC_MAX];
+};
+
+enum {
+	BFA_TRC_FW   = 1,	/*  firmware modules */
+	BFA_TRC_HAL  = 2,	/*  BFA modules */
+	BFA_TRC_FCS  = 3,	/*  BFA FCS modules */
+	BFA_TRC_LDRV = 4,	/*  Linux driver modules */
+	BFA_TRC_SDRV = 5,	/*  Solaris driver modules */
+	BFA_TRC_VDRV = 6,	/*  vmware driver modules */
+	BFA_TRC_WDRV = 7,	/*  windows driver modules */
+	BFA_TRC_AEN  = 8,	/*  AEN module */
+	BFA_TRC_BIOS = 9,	/*  bios driver modules */
+	BFA_TRC_EFI  = 10,	/*  EFI driver modules */
+	BNA_TRC_WDRV = 11,	/*  BNA windows driver modules */
+	BNA_TRC_VDRV = 12,	/*  BNA vmware driver modules */
+	BNA_TRC_SDRV = 13,	/*  BNA Solaris driver modules */
+	BNA_TRC_LDRV = 14,	/*  BNA Linux driver modules */
+	BNA_TRC_HAL  = 15,	/*  BNA modules */
+	BFA_TRC_CNA  = 16,	/*  Common modules */
+	BNA_TRC_IMDRV = 17	/*  BNA windows intermediate driver modules */
+};
+#define BFA_TRC_MOD_SH	10
+#define BFA_TRC_MOD(__mod)	((BFA_TRC_ ## __mod) << BFA_TRC_MOD_SH)
+
+/**
+ * Define a new tracing file (module). Module should match one defined above.
+ */
+#define BFA_TRC_FILE(__mod, __submod)					\
+	static int __trc_fileno = ((BFA_TRC_ ## __mod ## _ ## __submod) | \
+						 BFA_TRC_MOD(__mod))
+
+#define bfa_trc32(_trcp, _data)	\
+	__bfa_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u32)_data)
+
+#ifndef BFA_BOOT_BUILD
+#define bfa_trc(_trcp, _data)	\
+	__bfa_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u64)_data)
+#else
+void bfa_boot_trc(struct bfa_trc_mod *trcmod, u16 fileno,
+			u16 line, u32 data);
+#define bfa_trc(_trcp, _data)	\
+	bfa_boot_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u32)_data)
+#endif
+
+static inline void bfa_trc_init(struct bfa_trc_mod *trcm)
+{
+	trcm->head = trcm->tail = trcm->stopped = 0;
+	trcm->ntrc = BFA_TRC_MAX;
+}
+
+static inline void bfa_trc_stop(struct bfa_trc_mod *trcm)
+{
+	trcm->stopped = 1;
+}
+
+#ifdef FWTRC
+extern void dc_flush(void *data);
+#else
+#define dc_flush(data)
+#endif
+
+static inline void __bfa_trc(struct bfa_trc_mod *trcm, int fileno, int line,
+	u64 data)
+{
+	int		tail = trcm->tail;
+	struct bfa_trc *trc = &trcm->trc[tail];
+
+	if (trcm->stopped)
+		return;
+
+	trc->fileno = (u16) fileno;
+	trc->line = (u16) line;
+	trc->data.u64 = data;
+	trc->timestamp = BFA_TRC_TS(trcm);
+	dc_flush(trc);
+
+	trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1);
+	if (trcm->tail == trcm->head)
+		trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1);
+	dc_flush(trcm);
+}
+
+static inline void __bfa_trc32(struct bfa_trc_mod *trcm, int fileno,
+	int line, u32 data)
+{
+	int		tail = trcm->tail;
+	struct bfa_trc *trc = &trcm->trc[tail];
+
+	if (trcm->stopped)
+		return;
+
+	trc->fileno = (u16) fileno;
+	trc->line = (u16) line;
+	trc->data.u32.u32 = data;
+	trc->timestamp = BFA_TRC_TS(trcm);
+	dc_flush(trc);
+
+	trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1);
+	if (trcm->tail == trcm->head)
+		trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1);
+	dc_flush(trcm);
+}
+
+#ifndef BFA_PERF_BUILD
+#define bfa_trc_fp(_trcp, _data)	bfa_trc(_trcp, _data)
+#else
+#define bfa_trc_fp(_trcp, _data)
+#endif
+
+#endif /* __BFA_TRC_H__ */
+
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/defs/bfa_defs_adapter.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/defs/bfa_defs_adapter.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/defs/bfa_defs_adapter.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/defs/bfa_defs_adapter.h	2010-02-12 01:39:49.821301000 -0800
@@ -0,0 +1,82 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#ifndef __BFA_DEFS_ADAPTER_H__
+#define __BFA_DEFS_ADAPTER_H__
+
+#include "protocol/types.h"
+#include "defs/bfa_defs_mfg.h"
+
+/**
+ * BFA adapter level attributes.
+ */
+enum {
+	BFA_ADAPTER_SERIAL_NUM_LEN = STRSZ(BFA_MFG_SERIALNUM_SIZE),
+					/*
+					 *!< adapter serial num length
+					 */
+	BFA_ADAPTER_MODEL_NAME_LEN  = 16,  /*  model name length */
+	BFA_ADAPTER_MODEL_DESCR_LEN = 128, /*  model description length */
+	BFA_ADAPTER_MFG_NAME_LEN    = 8,   /*  manufacturer name length */
+	BFA_ADAPTER_SYM_NAME_LEN    = 64,  /*  adapter symbolic name length */
+	BFA_ADAPTER_OS_TYPE_LEN	    = 64,  /*  adapter os type length */
+};
+
+struct bfa_adapter_attr {
+	char            manufacturer[BFA_ADAPTER_MFG_NAME_LEN];
+	char            serial_num[BFA_ADAPTER_SERIAL_NUM_LEN];
+	u32	rsvd1;
+	char            model[BFA_ADAPTER_MODEL_NAME_LEN];
+	char            model_descr[BFA_ADAPTER_MODEL_DESCR_LEN];
+	wwn_t           pwwn;
+	char            node_symname[FC_SYMNAME_MAX];
+	char            hw_ver[BFA_VERSION_LEN];
+	char            fw_ver[BFA_VERSION_LEN];
+	char            optrom_ver[BFA_VERSION_LEN];
+	char            os_type[BFA_ADAPTER_OS_TYPE_LEN];
+	struct bfa_mfg_vpd vpd;
+	struct mac mac;
+
+	u8		nports;
+	u8		max_speed;
+	u8		prototype;
+	char	        asic_rev;
+
+	u8         pcie_gen;
+	u8         pcie_lanes_orig;
+	u8         pcie_lanes;
+	u8	        cna_capable;
+};
+
+/**
+ * BFA adapter level events
+ * Arguments below are in BFAL context from Mgmt
+ * BFA_PORT_AEN_ADD:        [in]: None     [out]: serial_num, pwwn, nports
+ * BFA_PORT_AEN_REMOVE:     [in]: pwwn     [out]: serial_num, pwwn, nports
+ */
+enum bfa_adapter_aen_event {
+	BFA_ADAPTER_AEN_ADD 	= 1,	/*  New Adapter found event */
+	BFA_ADAPTER_AEN_REMOVE 	= 2,	/*  Adapter removed event */
+};
+
+struct bfa_adapter_aen_data {
+	char            serial_num[BFA_ADAPTER_SERIAL_NUM_LEN];
+	u32        nports;	/*  Number of NPorts */
+	wwn_t           pwwn;	/*  WWN of one of its physical port */
+};
+
+#endif /* __BFA_DEFS_ADAPTER_H__ */
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/defs/bfa_defs_cee.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/defs/bfa_defs_cee.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/defs/bfa_defs_cee.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/defs/bfa_defs_cee.h	2010-02-12 01:39:50.474300000 -0800
@@ -0,0 +1,146 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ *  bfa_defs_cee.h Interface declarations between host based
+ *	BFAL and DCBX/LLDP module in Firmware
+ */
+#ifndef __BFA_DEFS_CEE_H__
+#define __BFA_DEFS_CEE_H__
+
+#include "protocol/types.h"
+
+#pragma pack(1)
+
+#define BFA_CEE_LLDP_MAX_STRING_LEN (128)
+
+#define BFA_CEE_LLDP_SYS_CAP_OTHER       0x0001
+#define BFA_CEE_LLDP_SYS_CAP_REPEATER    0x0002
+#define BFA_CEE_LLDP_SYS_CAP_MAC_BRIDGE  0x0004
+#define BFA_CEE_LLDP_SYS_CAP_WLAN_AP     0x0008
+#define BFA_CEE_LLDP_SYS_CAP_ROUTER      0x0010
+#define BFA_CEE_LLDP_SYS_CAP_TELEPHONE 	 0x0020
+#define BFA_CEE_LLDP_SYS_CAP_DOCSIS_CD   0x0040
+#define BFA_CEE_LLDP_SYS_CAP_STATION     0x0080
+#define BFA_CEE_LLDP_SYS_CAP_CVLAN	 0x0100
+#define BFA_CEE_LLDP_SYS_CAP_SVLAN	 0x0200
+#define BFA_CEE_LLDP_SYS_CAP_TPMR	 0x0400
+
+/* LLDP string type */
+struct bfa_cee_lldp_str {
+	u8 sub_type;
+	u8 len;
+	u8 rsvd[2];
+	u8 value[BFA_CEE_LLDP_MAX_STRING_LEN];
+};
+
+/* LLDP paramters */
+struct bfa_cee_lldp_cfg {
+	struct bfa_cee_lldp_str chassis_id;
+	struct bfa_cee_lldp_str port_id;
+	struct bfa_cee_lldp_str port_desc;
+	struct bfa_cee_lldp_str sys_name;
+	struct bfa_cee_lldp_str sys_desc;
+	struct bfa_cee_lldp_str mgmt_addr;
+	u16    time_to_interval;
+	u16    enabled_system_cap;
+};
+
+enum bfa_cee_dcbx_version {
+	DCBX_PROTOCOL_PRECEE = 1,
+	DCBX_PROTOCOL_CEE    = 2,
+};
+
+enum bfa_cee_lls {
+	CEE_LLS_DOWN_NO_TLV = 0, /* LLS is down bcoz TLV not sent by the peer */
+	CEE_LLS_DOWN        = 1, /* LLS is down as advertised by the peer */
+	CEE_LLS_UP          = 2,
+};
+
+/* CEE/DCBX parameters */
+struct bfa_cee_dcbx_cfg {
+	u8 pgid[8];
+	u8 pg_percentage[8];
+	u8 pfc_enabled;          /* bitmap of priorties with PFC enabled */
+	u8 fcoe_user_priority;  /* bitmap of priorities for FcoE traffic */
+	u8 dcbx_version;		  /* operating version:CEE or preCEE */
+	u8 lls_fcoe;			  /* FCoE Logical Link Status */
+	u8 lls_lan;			  /* LAN Logical Link Status */
+	u8 rsvd[3];
+};
+
+/* CEE status */
+/* Making this to tri-state for the benefit of port list command */
+enum bfa_cee_status {
+    CEE_UP = 0,
+    CEE_PHY_UP = 1,
+	CEE_LOOPBACK = 2,
+    CEE_PHY_DOWN = 3,
+};
+
+/* CEE Query */
+struct bfa_cee_attr {
+	u8                   cee_status;
+	u8                   error_reason;
+	struct bfa_cee_lldp_cfg lldp_remote;
+	struct bfa_cee_dcbx_cfg dcbx_remote;
+	struct mac src_mac;
+	u8 link_speed;
+	u8 nw_priority;
+	u8 filler[2];
+};
+
+/* LLDP/DCBX/CEE Statistics */
+
+struct bfa_cee_lldp_stats {
+	u32 frames_transmitted;
+	u32 frames_aged_out;
+	u32 frames_discarded;
+	u32 frames_in_error;
+	u32 frames_rcvd;
+	u32 tlvs_discarded;
+	u32 tlvs_unrecognized;
+};
+
+struct bfa_cee_dcbx_stats {
+	u32 subtlvs_unrecognized;
+	u32 negotiation_failed;
+	u32 remote_cfg_changed;
+	u32 tlvs_received;
+	u32 tlvs_invalid;
+	u32 seqno;
+	u32 ackno;
+	u32 recvd_seqno;
+	u32 recvd_ackno;
+};
+
+struct bfa_cee_cfg_stats {
+	u32 cee_status_down;
+	u32 cee_status_up;
+	u32 cee_hw_cfg_changed;
+	u32 recvd_invalid_cfg;
+};
+
+struct bfa_cee_stats {
+	struct bfa_cee_lldp_stats lldp_stats;
+	struct bfa_cee_dcbx_stats dcbx_stats;
+	struct bfa_cee_cfg_stats cfg_stats;
+};
+
+#pragma pack()
+
+#endif	/* __BFA_DEFS_CEE_H__ */
+
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/defs/bfa_defs_ioc.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/defs/bfa_defs_ioc.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/defs/bfa_defs_ioc.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/defs/bfa_defs_ioc.h	2010-02-12 01:39:50.767235000 -0800
@@ -0,0 +1,150 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef __BFA_DEFS_IOC_H__
+#define __BFA_DEFS_IOC_H__
+
+#include "protocol/types.h"
+#include "defs/bfa_defs_adapter.h"
+
+enum {
+	BFA_IOC_DRIVER_LEN	= 16,
+	BFA_IOC_CHIP_REV_LEN 	= 8,
+};
+
+/**
+ * Driver and firmware versions.
+ */
+struct bfa_ioc_driver_attr {
+	char            driver[BFA_IOC_DRIVER_LEN];	/*  driver name */
+	char            driver_ver[BFA_VERSION_LEN];	/*  driver version */
+	char            fw_ver[BFA_VERSION_LEN];	/*  firmware version*/
+	char            bios_ver[BFA_VERSION_LEN];	/*  bios version */
+	char            efi_ver[BFA_VERSION_LEN];	/*  EFI version */
+	char            ob_ver[BFA_VERSION_LEN];	/*  openboot version*/
+};
+
+/**
+ * IOC PCI device attributes
+ */
+struct bfa_ioc_pci_attr {
+	u16        vendor_id;	/*  PCI vendor ID */
+	u16        device_id;	/*  PCI device ID */
+	u16        ssid;		/*  subsystem ID */
+	u16        ssvid;		/*  subsystem vendor ID */
+	u32        pcifn;		/*  PCI device function */
+	u32        rsvd;		/* padding */
+	u8         chip_rev[BFA_IOC_CHIP_REV_LEN];	 /*  chip revision */
+};
+
+/**
+ * IOC states
+ */
+enum bfa_ioc_state {
+	BFA_IOC_RESET       = 1,  /*  IOC is in reset state */
+	BFA_IOC_SEMWAIT     = 2,  /*  Waiting for IOC hardware semaphore */
+	BFA_IOC_HWINIT 	    = 3,  /*  IOC hardware is being initialized */
+	BFA_IOC_GETATTR     = 4,  /*  IOC is being configured */
+	BFA_IOC_OPERATIONAL = 5,  /*  IOC is operational */
+	BFA_IOC_INITFAIL    = 6,  /*  IOC hardware failure */
+	BFA_IOC_HBFAIL      = 7,  /*  IOC heart-beat failure */
+	BFA_IOC_DISABLING   = 8,  /*  IOC is being disabled */
+	BFA_IOC_DISABLED    = 9,  /*  IOC is disabled */
+	BFA_IOC_FWMISMATCH  = 10, /*  IOC firmware different from drivers */
+};
+
+/**
+ * IOC firmware stats
+ */
+struct bfa_fw_ioc_stats {
+	u32        hb_count;
+	u32        cfg_reqs;
+	u32        enable_reqs;
+	u32        disable_reqs;
+	u32        stats_reqs;
+	u32        clrstats_reqs;
+	u32        unknown_reqs;
+	u32        ic_reqs;		/*  interrupt coalesce reqs */
+};
+
+/**
+ * IOC driver stats
+ */
+struct bfa_ioc_drv_stats {
+	u32	ioc_isrs;
+	u32	ioc_enables;
+	u32	ioc_disables;
+	u32	ioc_hbfails;
+	u32	ioc_boots;
+	u32	stats_tmos;
+	u32        hb_count;
+	u32        disable_reqs;
+	u32        enable_reqs;
+	u32        disable_replies;
+	u32        enable_replies;
+};
+
+/**
+ * IOC statistics
+ */
+struct bfa_ioc_stats {
+	struct bfa_ioc_drv_stats drv_stats; /*  driver IOC stats */
+	struct bfa_fw_ioc_stats fw_stats;  /*  firmware IOC stats */
+};
+
+enum bfa_ioc_type {
+	BFA_IOC_TYPE_FC	  = 1,
+	BFA_IOC_TYPE_FCoE = 2,
+	BFA_IOC_TYPE_LL	  = 3,
+};
+
+/**
+ * IOC attributes returned in queries
+ */
+struct bfa_ioc_attr {
+	enum bfa_ioc_type ioc_type;
+	enum bfa_ioc_state 		state;		/*  IOC state      */
+	struct bfa_adapter_attr adapter_attr;	/*  HBA attributes */
+	struct bfa_ioc_driver_attr driver_attr;	/*  driver attr    */
+	struct bfa_ioc_pci_attr pci_attr;
+	u8				port_id;	/*  port number    */
+	u8				rsvd[7];	/*  64bit align    */
+};
+
+/**
+ * BFA IOC level events
+ */
+enum bfa_ioc_aen_event {
+	BFA_IOC_AEN_HBGOOD	= 1,	/*  Heart Beat restore event	*/
+	BFA_IOC_AEN_HBFAIL	= 2,	/*  Heart Beat failure event	*/
+	BFA_IOC_AEN_ENABLE	= 3,	/*  IOC enabled event		*/
+	BFA_IOC_AEN_DISABLE	= 4,	/*  IOC disabled event		*/
+	BFA_IOC_AEN_FWMISMATCH	= 5,	/*  IOC firmware mismatch	*/
+};
+
+/**
+ * BFA IOC level event data, now just a place holder
+ */
+struct bfa_ioc_aen_data {
+	wwn_t	pwwn;
+	s16 ioc_type;
+	struct mac mac;
+};
+
+#endif /* __BFA_DEFS_IOC_H__ */
+
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/defs/bfa_defs_mfg.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/defs/bfa_defs_mfg.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/defs/bfa_defs_mfg.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/defs/bfa_defs_mfg.h	2010-02-12 01:39:50.261297000 -0800
@@ -0,0 +1,141 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#ifndef __BFA_DEFS_MFG_H__
+#define __BFA_DEFS_MFG_H__
+
+#include "cna.h"
+
+/**
+ * Manufacturing block version
+ */
+#define BFA_MFG_VERSION				2
+
+/**
+ * Manufacturing block encrypted version
+ */
+#define BFA_MFG_ENC_VER				2
+
+/**
+ * Manufacturing block version 1 length
+ */
+#define BFA_MFG_VER1_LEN			128
+
+/**
+ * Manufacturing block header length
+ */
+#define BFA_MFG_HDR_LEN				4
+
+/**
+ * Checksum size
+ */
+#define BFA_MFG_CHKSUM_SIZE			16
+
+/**
+ * Manufacturing block encrypted version
+ */
+#define BFA_MFG_ENC_VER				2
+
+/**
+ * Manufacturing block version 1 length
+ */
+#define BFA_MFG_VER1_LEN			128
+
+/**
+ * Manufacturing block header length
+ */
+#define BFA_MFG_HDR_LEN				4
+
+/**
+ * Checksum size
+ */
+#define BFA_MFG_CHKSUM_SIZE			16
+
+/**
+ * Manufacturing block format
+ */
+#define BFA_MFG_SERIALNUM_SIZE			11
+#define BFA_MFG_PARTNUM_SIZE			14
+#define BFA_MFG_SUPPLIER_ID_SIZE		10
+#define BFA_MFG_SUPPLIER_PARTNUM_SIZE		20
+#define BFA_MFG_SUPPLIER_SERIALNUM_SIZE		20
+#define BFA_MFG_SUPPLIER_REVISION_SIZE		4
+#define STRSZ(_n)	(((_n) + 4) & ~3)
+
+/**
+ * Manufacturing card type
+ */
+enum {
+	BFA_MFG_TYPE_CB_MAX  = 825,      /*  Crossbow card type max	*/
+	BFA_MFG_TYPE_FC8P2   = 825,      /*  8G 2port FC card		*/
+	BFA_MFG_TYPE_FC8P1   = 815,      /*  8G 1port FC card		*/
+	BFA_MFG_TYPE_FC4P2   = 425,      /*  4G 2port FC card		*/
+	BFA_MFG_TYPE_FC4P1   = 415,      /*  4G 1port FC card		*/
+	BFA_MFG_TYPE_CNA10P2 = 1020,     /*  10G 2port CNA card	*/
+	BFA_MFG_TYPE_CNA10P1 = 1010,     /*  10G 1port CNA card	*/
+};
+
+#pragma pack(1)
+
+/**
+ * Card type to port number conversion
+ */
+#define bfa_mfg_type2port_num(card_type) (((card_type) / 10) % 10)
+
+/**
+ * All numerical fields are in big-endian format.
+ */
+struct bfa_mfg_block {
+};
+
+/**
+ * VPD data length
+ */
+#define BFA_MFG_VPD_LEN		512
+
+#define BFA_MFG_VPD_PCI_HDR_OFF		137
+#define BFA_MFG_VPD_PCI_VER_MASK	0x07	/*  version mask 3 bits */
+#define BFA_MFG_VPD_PCI_VDR_MASK	0xf8	/*  vendor mask 5 bits */
+
+/**
+ * VPD vendor tag
+ */
+enum {
+	BFA_MFG_VPD_UNKNOWN	= 0,     /*  vendor unknown 		*/
+	BFA_MFG_VPD_IBM 	= 1,     /*  vendor IBM 		*/
+	BFA_MFG_VPD_HP  	= 2,     /*  vendor HP  		*/
+	BFA_MFG_VPD_PCI_IBM 	= 0x08,  /*  PCI VPD IBM     		*/
+	BFA_MFG_VPD_PCI_HP  	= 0x10,  /*  PCI VPD HP		*/
+	BFA_MFG_VPD_PCI_BRCD 	= 0xf8,  /*  PCI VPD Brocade 		*/
+};
+
+/**
+ * All numerical fields are in big-endian format.
+ */
+struct bfa_mfg_vpd {
+	u8		version;	/*  vpd data version */
+	u8		vpd_sig[3];	/*  characters 'V', 'P', 'D' */
+	u8		chksum;		/*  u8 checksum */
+	u8		vendor;		/*  vendor */
+	u8 	len;		/*  vpd data length excluding header */
+	u8 	rsv;
+	u8		data[BFA_MFG_VPD_LEN];	/*  vpd data */
+};
+
+#pragma pack()
+
+#endif /* __BFA_DEFS_MFG_H__ */
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/defs/bfa_defs_pci.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/defs/bfa_defs_pci.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/defs/bfa_defs_pci.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/defs/bfa_defs_pci.h	2010-02-12 01:39:50.000298000 -0800
@@ -0,0 +1,42 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef __BFA_DEFS_PCI_H__
+#define __BFA_DEFS_PCI_H__
+
+/**
+ * PCI device and vendor ID information
+ */
+enum {
+	BFA_PCI_VENDOR_ID_BROCADE	= 0x1657,
+	BFA_PCI_DEVICE_ID_FC_8G2P	= 0x13,
+	BFA_PCI_DEVICE_ID_FC_8G1P	= 0x17,
+	BFA_PCI_DEVICE_ID_CT		= 0x14,
+};
+
+/**
+ * PCI sub-system device and vendor ID information
+ */
+enum {
+	BFA_PCI_FCOE_SSDEVICE_ID	= 0x14,
+};
+
+#define BFA_PCI_ACCESS_RANGES 1	/* Maximum number of device address ranges
+				 * mapped through different BAR(s). */
+
+#endif /* __BFA_DEFS_PCI_H__ */
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/defs/bfa_defs_status.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/defs/bfa_defs_status.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/defs/bfa_defs_status.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/defs/bfa_defs_status.h	2010-02-12 01:39:50.806234000 -0800
@@ -0,0 +1,265 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#ifndef __BFA_DEFS_STATUS_H__
+#define __BFA_DEFS_STATUS_H__
+
+/**
+ * API status return values
+ *
+ * NOTE: The error msgs are auto generated from the comments. Only singe line
+ * comments are supported
+ */
+enum bfa_status {
+	BFA_STATUS_OK 		= 0,	/*  Success */
+	BFA_STATUS_FAILED 	= 1,	/*  Operation failed */
+	BFA_STATUS_EINVAL 	= 2,	/*  Invalid params Check input
+					 * parameters */
+	BFA_STATUS_ENOMEM 	= 3,	/*  Out of resources */
+	BFA_STATUS_ENOSYS 	= 4,	/*  Function not implemented */
+	BFA_STATUS_ETIMER 	= 5,	/*  Timer expired - Retry, if
+					 * persists, contact support */
+	BFA_STATUS_EPROTOCOL 	= 6,	/*  Protocol error */
+	BFA_STATUS_ENOFCPORTS 	= 7,	/*  No FC ports resources */
+	BFA_STATUS_NOFLASH 	= 8,	/*  Flash not present */
+	BFA_STATUS_BADFLASH 	= 9,	/*  Flash is corrupted or bad */
+	BFA_STATUS_SFP_UNSUPP 	= 10,	/*  Unsupported SFP - Replace SFP */
+	BFA_STATUS_UNKNOWN_VFID = 11,	/*  VF_ID not found */
+	BFA_STATUS_DATACORRUPTED = 12,	/*  Diag returned data corrupted
+					 * contact support */
+	BFA_STATUS_DEVBUSY 	= 13,	/*  Device busy - Retry operation */
+	BFA_STATUS_ABORTED 	= 14,	/*  Operation aborted */
+	BFA_STATUS_NODEV 	= 15,	/*  Dev is not present */
+	BFA_STATUS_HDMA_FAILED 	= 16,	/*  Host dma failed contact support */
+	BFA_STATUS_FLASH_BAD_LEN = 17,	/*  Flash bad length */
+	BFA_STATUS_UNKNOWN_LWWN = 18,	/*  LPORT PWWN not found */
+	BFA_STATUS_UNKNOWN_RWWN = 19,	/*  RPORT PWWN not found */
+	BFA_STATUS_FCPT_LS_RJT 	= 20,	/*  Got LS_RJT for FC Pass
+					 * through Req */
+	BFA_STATUS_VPORT_EXISTS = 21,	/*  VPORT already exists */
+	BFA_STATUS_VPORT_MAX 	= 22,	/*  Reached max VPORT supported
+					 * limit */
+	BFA_STATUS_UNSUPP_SPEED = 23,	/*  Invalid Speed Check speed
+					 * setting */
+	BFA_STATUS_INVLD_DFSZ 	= 24,	/*  Invalid Max data field size */
+	BFA_STATUS_CNFG_FAILED 	= 25,	/*  Setting can not be persisted */
+	BFA_STATUS_CMD_NOTSUPP 	= 26,	/*  Command/API not supported */
+	BFA_STATUS_NO_ADAPTER 	= 27,	/*  No Brocade Adapter Found */
+	BFA_STATUS_LINKDOWN 	= 28,	/*  Link is down - Check or replace
+					 * SFP/cable */
+	BFA_STATUS_FABRIC_RJT 	= 29,	/*  Reject from attached fabric */
+	BFA_STATUS_UNKNOWN_VWWN = 30,	/*  VPORT PWWN not found */
+	BFA_STATUS_NSLOGIN_FAILED = 31,	/*  Nameserver login failed */
+	BFA_STATUS_NO_RPORTS 	= 32,	/*  No remote ports found */
+	BFA_STATUS_NSQUERY_FAILED = 33,	/*  Nameserver query failed */
+	BFA_STATUS_PORT_OFFLINE = 34,	/*  Port is not online */
+	BFA_STATUS_RPORT_OFFLINE = 35,	/*  RPORT is not online */
+	BFA_STATUS_TGTOPEN_FAILED = 36,	/*  Remote SCSI target open failed */
+	BFA_STATUS_BAD_LUNS 	= 37,	/*  No valid LUNs found */
+	BFA_STATUS_IO_FAILURE 	= 38,	/*  SCSI target IO failure */
+	BFA_STATUS_NO_FABRIC 	= 39,	/*  No switched fabric present */
+	BFA_STATUS_EBADF 	= 40,	/*  Bad file descriptor */
+	BFA_STATUS_EINTR 	= 41,	/*  A signal was caught during ioctl */
+	BFA_STATUS_EIO 		= 42,	/*  I/O error */
+	BFA_STATUS_ENOTTY 	= 43,	/*  Inappropriate I/O control
+					 * operation */
+	BFA_STATUS_ENXIO 	= 44,	/*  No such device or address */
+	BFA_STATUS_EFOPEN 	= 45,	/*  Failed to open file */
+	BFA_STATUS_VPORT_WWN_BP = 46,	/*  WWN is same as base port's WWN */
+	BFA_STATUS_PORT_NOT_DISABLED = 47, /*  Port not disabled disable port
+					    * first */
+	BFA_STATUS_BADFRMHDR 	= 48,	/*  Bad frame header */
+	BFA_STATUS_BADFRMSZ 	= 49,	/*  Bad frame size check and replace
+					 * SFP/cable */
+	BFA_STATUS_MISSINGFRM 	= 50,	/*  Missing frame check and replace
+					 * SFP/cable */
+	BFA_STATUS_LINKTIMEOUT 	= 51,	/*  Link timeout check and replace
+					 * SFP/cable */
+	BFA_STATUS_NO_FCPIM_NEXUS = 52,	/*  No FCP Nexus exists with the
+					 * rport */
+	BFA_STATUS_CHECKSUM_FAIL = 53,	/*  checksum failure */
+	BFA_STATUS_GZME_FAILED 	= 54,	/*  Get zone member query failed */
+	BFA_STATUS_SCSISTART_REQD = 55,	/*  SCSI disk require START command */
+	BFA_STATUS_IOC_FAILURE 	= 56,	/*  IOC failure - Retry, if persists
+					 * contact support */
+	BFA_STATUS_INVALID_WWN 	= 57,	/*  Invalid WWN */
+	BFA_STATUS_MISMATCH 	= 58,	/*  Version mismatch */
+	BFA_STATUS_IOC_ENABLED 	= 59,	/*  IOC is already enabled */
+	BFA_STATUS_ADAPTER_ENABLED = 60, /*  Adapter is not disabled disable
+					  * adapter first */
+	BFA_STATUS_IOC_NON_OP 	= 61,	/*  IOC is not operational. Enable IOC
+					 * and if it still fails,
+					 * contact support */
+	BFA_STATUS_ADDR_MAP_FAILURE = 62, /*  PCI base address not mapped
+					   * in OS */
+	BFA_STATUS_SAME_NAME 	= 63,	/*  Name exists! use a different
+					 * name */
+	BFA_STATUS_PENDING      = 64,   /*  API completes asynchronously */
+	BFA_STATUS_8G_SPD	= 65,	/*  Speed setting not valid for
+					 * 8G HBA */
+	BFA_STATUS_4G_SPD	= 66,	/*  Speed setting not valid for
+					 * 4G HBA */
+	BFA_STATUS_AD_IS_ENABLE = 67,	/*  Adapter is already enabled */
+	BFA_STATUS_EINVAL_TOV 	= 68,	/*  Invalid path failover TOV */
+	BFA_STATUS_EINVAL_QDEPTH = 69,	/*  Invalid queue depth value */
+	BFA_STATUS_VERSION_FAIL = 70,	/*  Application/Driver version
+					 * mismatch */
+	BFA_STATUS_DIAG_BUSY    = 71,	/*  diag busy */
+	BFA_STATUS_BEACON_ON	= 72,	/*  Port Beacon already on */
+	BFA_STATUS_BEACON_OFF	= 73,	/*  Port Beacon already off */
+	BFA_STATUS_LBEACON_ON   = 74,	/*  Link End-to-End Beacon already
+					 * on */
+	BFA_STATUS_LBEACON_OFF	= 75,	/*  Link End-to-End Beacon already
+					 * off */
+	BFA_STATUS_PORT_NOT_INITED = 76, /*  Port not initialized */
+	BFA_STATUS_RPSC_ENABLED = 77, /*  Target has a valid speed */
+	BFA_STATUS_ENOFSAVE = 78,	/*  No saved firmware trace */
+	BFA_STATUS_BAD_FILE = 79,	/*  Not a valid Brocade Boot Code
+					 * file */
+	BFA_STATUS_RLIM_EN = 80,	/*  Target rate limiting is already
+					 * enabled */
+	BFA_STATUS_RLIM_DIS = 81,  /*  Target rate limiting is already
+				    * disabled */
+	BFA_STATUS_IOC_DISABLED = 82,   /*  IOC is already disabled */
+	BFA_STATUS_ADAPTER_DISABLED = 83,   /*  Adapter is already disabled */
+	BFA_STATUS_BIOS_DISABLED = 84,   /*  Bios is already disabled */
+	BFA_STATUS_AUTH_ENABLED = 85,   /*  Authentication is already
+					 * enabled */
+	BFA_STATUS_AUTH_DISABLED = 86,   /*  Authentication is already
+					 * disabled */
+	BFA_STATUS_ERROR_TRL_ENABLED = 87,   /*  Target rate limiting is
+					      * enabled */
+	BFA_STATUS_ERROR_QOS_ENABLED = 88,   /*  QoS is enabled */
+	BFA_STATUS_NO_SFP_DEV = 89, /*  No SFP device check or replace SFP */
+	BFA_STATUS_MEMTEST_FAILED = 90,	/*  Memory test failed contact
+					 * support */
+	BFA_STATUS_INVALID_DEVID = 91,	/*  Invalid device id provided */
+	BFA_STATUS_QOS_ENABLED = 92, /*  QOS is already enabled */
+	BFA_STATUS_QOS_DISABLED = 93, /*  QOS is already disabled */
+	BFA_STATUS_INCORRECT_DRV_CONFIG = 94, /*  Check configuration
+					       * key/value pair */
+	BFA_STATUS_REG_FAIL = 95, /*  Can't read windows registry */
+	BFA_STATUS_IM_INV_CODE = 96, /*  Invalid IOCTL code */
+	BFA_STATUS_IM_INV_VLAN = 97, /*  Invalid VLAN ID */
+	BFA_STATUS_IM_INV_ADAPT_NAME = 98, /*  Invalid adapter name */
+	BFA_STATUS_IM_LOW_RESOURCES = 99, /*  Memory allocation failure in
+					   * driver */
+	BFA_STATUS_IM_VLANID_IS_PVID = 100, /*  Given VLAN id same as PVID */
+	BFA_STATUS_IM_VLANID_EXISTS = 101, /*  Given VLAN id already exists */
+	BFA_STATUS_IM_FW_UPDATE_FAIL = 102, /*  Updating firmware with new
+					     * VLAN ID failed */
+	BFA_STATUS_PORTLOG_ENABLED = 103, /*  Port Log is already enabled */
+	BFA_STATUS_PORTLOG_DISABLED = 104, /*  Port Log is already disabled */
+	BFA_STATUS_FILE_NOT_FOUND = 105, /*  Specified file could not be
+					  * found */
+	BFA_STATUS_QOS_FC_ONLY = 106, /*  QOS can be enabled for FC mode
+				       * only */
+	BFA_STATUS_RLIM_FC_ONLY = 107, /*  RATELIM can be enabled for FC mode
+					* only */
+	BFA_STATUS_CT_SPD = 108, /*  Invalid speed selection for Catapult. */
+	BFA_STATUS_LEDTEST_OP = 109, /*  LED test is operating */
+	BFA_STATUS_CEE_NOT_DN = 110, /*  eth port is not at down state, please
+				      * bring down first */
+	BFA_STATUS_10G_SPD = 111, /*  Speed setting not valid for 10G HBA */
+	BFA_STATUS_IM_INV_TEAM_NAME = 112, /*  Invalid team name */
+	BFA_STATUS_IM_DUP_TEAM_NAME = 113, /*  Given team name already
+					    * exists */
+	BFA_STATUS_IM_ADAPT_ALREADY_IN_TEAM = 114, /*  Given adapter is part
+						    * of another team or VLANS
+						    * exist */
+	BFA_STATUS_IM_ADAPT_HAS_VLANS = 115, /*  Adapter has VLANs configured.
+					      * Delete all VLANs to become part
+					      * of team */
+	BFA_STATUS_IM_PVID_MISMATCH = 116, /*  Mismatching PVIDs configured
+					    * for adapters */
+	BFA_STATUS_IM_LINK_SPEED_MISMATCH = 117, /*  Mismatching link speeds
+						  * configured for adapters */
+	BFA_STATUS_IM_MTU_MISMATCH = 118, /*  Mismatching MTUs configured for
+					   * adapters */
+	BFA_STATUS_IM_RSS_MISMATCH = 119, /*  Mismatching RSS parameters
+					   * configured for adapters */
+	BFA_STATUS_IM_HDS_MISMATCH = 120, /*  Mismatching HDS parameters
+					   * configured for adapters */
+	BFA_STATUS_IM_OFFLOAD_MISMATCH = 121, /*  Mismatching offload
+					       * parameters configured for
+					       * adapters */
+	BFA_STATUS_IM_PORT_PARAMS = 122, /*  Error setting port parameters */
+	BFA_STATUS_IM_PORT_NOT_IN_TEAM = 123, /*  Port is not part of team */
+	BFA_STATUS_IM_CANNOT_REM_PRI = 124, /*  Primary adapter cannot be
+					     * removed. Change primary before
+					     * removing */
+	BFA_STATUS_IM_MAX_PORTS_REACHED = 125, /*  Exceeding maximum ports
+						* per team */
+	BFA_STATUS_IM_LAST_PORT_DELETE = 126, /*  Last port in team being
+					       * deleted */
+	BFA_STATUS_IM_NO_DRIVER = 127, /*  IM driver is not installed */
+	BFA_STATUS_IM_MAX_VLANS_REACHED = 128, /*  Exceeding maximum VLANs
+						* per port */
+	BFA_STATUS_TOMCAT_SPD_NOT_ALLOWED = 129, /* Bios speed config not
+						  * allowed for CNA */
+	BFA_STATUS_NO_MINPORT_DRIVER = 130, /*  Miniport driver is not
+					     * loaded */
+	BFA_STATUS_CARD_TYPE_MISMATCH = 131, /*  Card type mismatch */
+	BFA_STATUS_BAD_ASICBLK = 132, /*  Bad ASIC block */
+	BFA_STATUS_NO_DRIVER = 133, /*  Brocade adapter/driver not installed
+				     * or loaded */
+	BFA_STATUS_INVALID_MAC = 134, /*  Invalid mac address */
+	BFA_STATUS_IM_NO_VLAN = 135, /*  No VLANs configured on the adapter */
+	BFA_STATUS_IM_ETH_LB_FAILED = 136, /*  Ethernet loopback test failed */
+	BFA_STATUS_IM_PVID_REMOVE = 137, /*  Cannot remove port vlan (PVID) */
+	BFA_STATUS_IM_PVID_EDIT = 138, /*  Cannot edit port vlan (PVID) */
+	BFA_STATUS_CNA_NO_BOOT = 139, /*  Boot upload not allowed for CNA */
+	BFA_STATUS_IM_PVID_NON_ZERO = 140, /*  Port VLAN ID (PVID) is Set to
+					    * Non-Zero Value */
+	BFA_STATUS_IM_INETCFG_LOCK_FAILED = 141, /*  Acquiring Network
+						  * Subsytem Lock Failed.Please
+						  * try after some time */
+	BFA_STATUS_IM_GET_INETCFG_FAILED = 142, /*  Acquiring Network Subsytem
+						 * handle Failed. Please try
+						 * after some time */
+	BFA_STATUS_IM_NOT_BOUND = 143, /*  IM driver is not active */
+	BFA_STATUS_INSUFFICIENT_PERMS = 144, /*  User doesn't have sufficient
+					      * permissions to execute the BCU
+					      * application */
+	BFA_STATUS_IM_INV_VLAN_NAME = 145, /*  Invalid/Reserved Vlan name
+					    * string. The name is not allowed
+					    * for the normal Vlans */
+	BFA_STATUS_CMD_NOTSUPP_CNA = 146, /*  Command not supported for CNA */
+	BFA_STATUS_IM_PASSTHRU_EDIT = 147, /*  Can not edit passthru vlan id */
+	BFA_STATUS_IM_BIND_FAILED = 148, /*! < IM Driver bind operation
+					  * failed */
+	BFA_STATUS_IM_UNBIND_FAILED = 149, /* ! < IM Driver unbind operation
+					    * failed */
+	BFA_STATUS_IM_PORT_IN_TEAM = 150, /*  Port is already part of the
+					   * team */
+	BFA_STATUS_IM_VLAN_NOT_FOUND = 151, /*  VLAN ID doesn't exists */
+	BFA_STATUS_IM_TEAM_NOT_FOUND = 152, /*  Teaming configuration doesn't
+					     * exists */
+	BFA_STATUS_IM_TEAM_CFG_NOT_ALLOWED = 153, /*  Given settings are not
+						   * allowed for the current
+						   * Teaming mode */
+	BFA_STATUS_MAX_VAL		/*  Unknown error code */
+};
+#define bfa_status_t enum bfa_status
+
+enum bfa_eproto_status {
+	BFA_EPROTO_BAD_ACCEPT = 0,
+	BFA_EPROTO_UNKNOWN_RSP = 1
+};
+#define bfa_eproto_status_t enum bfa_eproto_status
+
+#endif /* __BFA_DEFS_STATUS_H__ */
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/include/protocol/types.h net-next-2.6.33-rc5-mod/drivers/net/bna/include/protocol/types.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/include/protocol/types.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/include/protocol/types.h	2010-02-12 01:39:50.974230000 -0800
@@ -0,0 +1,39 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+/**
+ *  types.h Protocol defined base types
+ */
+
+#ifndef __TYPES_H__
+#define __TYPES_H__
+
+#include "cna.h"
+
+#define wwn_t u64
+
+#define FC_SYMNAME_MAX	256	/*  max name server symbolic name size */
+#define FC_ALPA_MAX	128
+
+#pragma pack(1)
+
+struct mac { u8 mac[ETH_ALEN]; };
+
+#pragma pack()
+
+#endif

^ permalink raw reply

* Subject: [PATCH 1/6] bna: Brocade 10Gb Ethernet device driver
From: Rasesh Mody @ 2010-02-12 14:00 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 | 3503 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 bnad.h |  343 ++++++
 2 files changed, 3846 insertions(+)

diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/bnad.c net-next-2.6.33-rc5-mod/drivers/net/bna/bnad.c
--- net-next-2.6.33-rc5-orig/drivers/net/bna/bnad.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/bnad.c	2010-02-12 01:39:39.940983000 -0800
@@ -0,0 +1,3503 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+/**
+ *  bnad.c  Brocade 10G PCIe Ethernet driver.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/pci.h>
+#include <linux/bitops.h>
+#include <linux/etherdevice.h>
+#include <linux/in.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/delay.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_ether.h>
+#include <linux/workqueue.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/pm.h>
+#include <linux/random.h>
+
+#include <net/checksum.h>
+
+#include "bnad.h"
+#include "cna.h"
+#include "bna_iocll.h"
+#include "bna_intr.h"
+#include "bnad_defs.h"
+
+#define BNAD_TXQ_WI_NEEDED(_vectors)	(((_vectors) + 3) >> 2)
+const static bool bnad_msix = 1;
+const static bool bnad_small_large_rxbufs = 1;
+static uint bnad_rxqsets_used;
+const static bool bnad_ipid_mode;
+const static bool bnad_vlan_strip = 1;
+const static uint bnad_txq_depth = BNAD_ENTRIES_PER_TXQ;
+const static uint bnad_rxq_depth = BNAD_ENTRIES_PER_RXQ;
+static uint bnad_log_level ;
+
+static uint bnad_ioc_auto_recover = 1;
+module_param(bnad_ioc_auto_recover, uint, 0444);
+MODULE_PARM_DESC(bnad_ioc_auto_recover, "Enable auto recovery");
+
+uint bnad_rxqs_per_cq = 2;
+
+const char *bnad_states[] = {
+	"START",
+	"INIT",
+	"INIT_DOWN",
+	"INIT_DISABLING",
+	"INIT_DISABLED",
+	"OPENING",
+	"OPEN",
+	"OPEN_DOWN",
+	"OPEN_DISABING",
+	"OPEN_DISABLED",
+	"CLOSING",
+	"UNLOADING"
+};
+
+DEFINE_MUTEX(bnad_fwimg_mutex);
+
+static void bnad_disable_msix(struct bnad *bnad);
+static void bnad_free_ibs(struct bnad *bnad);
+static void bnad_set_rx_mode(struct net_device *netdev);
+static void bnad_set_rx_mode_locked(struct net_device *netdev);
+static void bnad_reconfig_vlans(struct bnad *bnad);
+static void bnad_q_num_init(struct bnad *bnad, uint rxqsets);
+static int bnad_set_mac_address(struct net_device *netdev, void *addr);
+static int bnad_set_mac_address_locked(struct net_device *netdev, void *addr);
+static int bnad_disable_locked(struct bnad *bnad);
+static int bnad_change_mtu(struct net_device *netdev, int new_mtu);
+static void
+bnad_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp);
+static void bnad_vlan_rx_add_vid(struct net_device *netdev, unsigned short vid);
+static void
+bnad_vlan_rx_kill_vid(struct net_device *netdev, unsigned short vid);
+static void bnad_netpoll(struct net_device *netdev);
+
+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_stats,
+	.ndo_set_rx_mode		= &bnad_set_rx_mode,
+	.ndo_set_multicast_list		= bnad_set_rx_mode,
+	.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
+};
+
+void bnad_ioc_timeout(unsigned long ioc_arg)
+{
+	struct bnad *bnad = (struct bnad *)(((struct bfa_ioc*)ioc_arg)->bfa);
+	spin_lock_irq(&bnad->priv_lock);
+	spin_unlock_irq(&bnad->priv_lock);
+}
+
+void bnad_ioc_sem_timeout(unsigned long ioc_arg)
+{
+	struct bnad *bnad = (struct bnad *)(((struct bfa_ioc*)ioc_arg)->bfa);
+	spin_lock_irq(&bnad->priv_lock);
+	bfa_ioc_sem_timeout(ioc_arg);
+	spin_unlock_irq(&bnad->priv_lock);
+}
+
+void bnad_ioc_hb_check(unsigned long ioc_arg)
+{
+	struct bnad *bnad = (struct bnad *)(((struct bfa_ioc*)ioc_arg)->bfa);
+	spin_lock_irq(&bnad->priv_lock);
+	bfa_ioc_hb_check(ioc_arg);
+	spin_unlock_irq(&bnad->priv_lock);
+}
+
+u32
+bnad_get_msglevel(struct net_device *netdev)
+{
+	return bnad_log_level;
+}
+
+void
+bnad_set_msglevel(struct net_device *netdev, u32 msglevel)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	mutex_lock(&bnad->conf_mutex);
+	bnad_log_level = msglevel;
+	mutex_unlock(&bnad->conf_mutex);
+}
+
+static unsigned int bnad_free_txbufs(struct bnad_txq_info *txqinfo,
+	u16 updated_txq_cons)
+{
+	struct bnad *bnad = txqinfo->bnad;
+	unsigned int sent_packets = 0, sent_bytes = 0;
+	u16 wis, unmap_cons;
+	struct bnad_skb_unmap *unmap_array;
+	struct sk_buff *skb;
+	int i;
+
+	wis = BNAD_Q_INDEX_CHANGE(txqinfo->txq.q.consumer_index,
+				  updated_txq_cons, txqinfo->txq.q.q_depth);
+	BUG_ON(!(wis <=
+		   BNA_QE_IN_USE_CNT(&txqinfo->txq.q, txqinfo->txq.q.q_depth)));
+	unmap_array = txqinfo->skb_unmap_q.unmap_array;
+	unmap_cons = txqinfo->skb_unmap_q.consumer_index;
+	prefetch(&unmap_array[unmap_cons + 1]);
+	while (wis) {
+		skb = unmap_array[unmap_cons].skb;
+		unmap_array[unmap_cons].skb = NULL;
+		BUG_ON(!(wis >=
+			   BNAD_TXQ_WI_NEEDED(1 + skb_shinfo(skb)->nr_frags)));
+		BUG_ON(!(((txqinfo->skb_unmap_q.producer_index -
+			     unmap_cons)) & (txqinfo->skb_unmap_q.q_depth -
+					    1)) >=
+			   1 + skb_shinfo(skb)->nr_frags);
+
+		sent_packets++;
+		sent_bytes += skb->len;
+		wis -= BNAD_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, txqinfo->skb_unmap_q.q_depth);
+		prefetch(&unmap_array[unmap_cons + 1]);
+		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);
+			BNA_QE_INDX_ADD(unmap_cons, 1,
+					txqinfo->skb_unmap_q.q_depth);
+			prefetch(&unmap_array[unmap_cons + 1]);
+		}
+		dev_kfree_skb_any(skb);
+	}
+
+	/* Update consumer pointers. */
+	txqinfo->txq.q.consumer_index = updated_txq_cons;
+	txqinfo->skb_unmap_q.consumer_index = unmap_cons;
+	txqinfo->tx_packets += sent_packets;
+	txqinfo->tx_bytes += sent_bytes;
+	return sent_packets;
+}
+
+static inline void bnad_disable_txrx_irqs(struct bnad *bnad)
+{
+	int i;
+
+	for (i = 0; i < bnad->txq_num; i++) {
+		bna_ib_coalescing_timer_set(bnad->priv, &bnad->txq_table[i].ib,
+					    0);
+		bna_ib_ack(bnad->priv, &bnad->txq_table[i].ib, 0);
+	}
+
+	for (i = 0; i < bnad->cq_num; i++) {
+		bna_ib_coalescing_timer_set(bnad->priv, &bnad->cq_table[i].ib,
+					    0);
+		bna_ib_ack(bnad->priv, &bnad->cq_table[i].ib, 0);
+	}
+}
+
+static inline void bnad_enable_txrx_irqs(struct bnad *bnad)
+{
+	int i;
+
+	spin_lock_irq(&bnad->priv_lock);
+	for (i = 0; i < bnad->txq_num; i++) {
+		bna_ib_coalescing_timer_set(bnad->priv, &bnad->txq_table[i].ib,
+					    bnad->tx_coalescing_timeo);
+		bna_ib_ack(bnad->priv, &bnad->txq_table[i].ib, 0);
+	}
+
+	for (i = 0; i < bnad->cq_num; i++) {
+		bna_ib_coalescing_timer_set(bnad->priv, &bnad->cq_table[i].ib,
+					    bnad->cq_table[i].
+					    rx_coalescing_timeo);
+		bna_ib_ack(bnad->priv, &bnad->cq_table[i].ib, 0);
+	}
+	spin_unlock_irq(&bnad->priv_lock);
+}
+
+static inline void bnad_disable_rx_irq(struct bnad *bnad,
+	struct bnad_cq_info *cqinfo)
+{
+	bna_ib_coalescing_timer_set(bnad->priv, &cqinfo->ib, 0);
+	bna_ib_ack(bnad->priv, &cqinfo->ib, 0);
+}
+static inline void bnad_enable_rx_irq(struct bnad *bnad,
+	struct bnad_cq_info *cqinfo)
+{
+	spin_lock_irq(&bnad->priv_lock);
+
+	bna_ib_coalescing_timer_set(bnad->priv, &cqinfo->ib,
+				    cqinfo->rx_coalescing_timeo);
+
+	bna_ib_ack(bnad->priv, &cqinfo->ib, 0);
+
+	spin_unlock_irq(&bnad->priv_lock);
+}
+
+static unsigned int bnad_tx(struct bnad *bnad, struct bnad_txq_info *txqinfo)
+{
+	struct net_device *netdev = bnad->netdev;
+	unsigned int sent;
+
+	if (test_and_set_bit(BNAD_TXQ_FREE_SENT, &txqinfo->flags))
+		return 0;
+
+	sent = bnad_free_txbufs(txqinfo,
+				(u16) (*txqinfo->hw_consumer_index));
+	if (sent) {
+		if (netif_queue_stopped(netdev) &&
+		    BNA_Q_FREE_COUNT(&txqinfo->txq) >=
+		    BNAD_NETIF_WAKE_THRESHOLD) {
+			netif_wake_queue(netdev);
+			bnad->stats.netif_queue_wakeup++;
+		}
+		bna_ib_ack(bnad->priv, &txqinfo->ib, sent);
+	} else {
+		bna_ib_ack(bnad->priv, &txqinfo->ib, 0);
+	}
+
+	smp_mb__before_clear_bit();
+	clear_bit(BNAD_TXQ_FREE_SENT, &txqinfo->flags);
+
+	return sent;
+}
+
+static irqreturn_t bnad_msix_tx(int irq, void *data)
+{
+	struct bnad_txq_info *txqinfo = (struct bnad_txq_info *)data;
+	struct bnad *bnad = txqinfo->bnad;
+
+	bnad_tx(bnad, txqinfo);
+
+	return IRQ_HANDLED;
+}
+
+static void bnad_alloc_rxbufs(struct bnad_rxq_info *rxqinfo)
+{
+	u16 to_alloc, alloced, unmap_prod, wi_range;
+	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(&rxqinfo->skb_unmap_q,
+				rxqinfo->skb_unmap_q.q_depth);
+
+	unmap_array = rxqinfo->skb_unmap_q.unmap_array;
+	unmap_prod = rxqinfo->skb_unmap_q.producer_index;
+	BNA_RXQ_QPGE_PTR_GET(unmap_prod, &rxqinfo->rxq.q, rxent, wi_range);
+	BUG_ON(!(wi_range && wi_range <= rxqinfo->rxq.q.q_depth));
+
+	while (to_alloc--) {
+		if (!wi_range) {
+			BNA_RXQ_QPGE_PTR_GET(unmap_prod, &rxqinfo->rxq.q, rxent,
+					     wi_range);
+			BUG_ON(!(wi_range &&
+				   wi_range <= rxqinfo->rxq.q.q_depth));
+		}
+		skb = alloc_skb(rxqinfo->rxq_config.buffer_size + NET_IP_ALIGN,
+				GFP_ATOMIC);
+		if (unlikely(!skb)) {
+			rxqinfo->rxbuf_alloc_failed++;
+			goto finishing;
+		}
+		skb->dev = rxqinfo->bnad->netdev;
+		skb_reserve(skb, NET_IP_ALIGN);
+		unmap_array[unmap_prod].skb = skb;
+		dma_addr =
+			pci_map_single(rxqinfo->bnad->pcidev, skb->data,
+				       rxqinfo->rxq_config.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, rxqinfo->skb_unmap_q.q_depth);
+
+		rxent++;
+		wi_range--;
+		alloced++;
+	}
+
+finishing:
+	if (likely(alloced)) {
+		rxqinfo->skb_unmap_q.producer_index = unmap_prod;
+		rxqinfo->rxq.q.producer_index = unmap_prod;
+		smp_mb();
+		bna_rxq_prod_indx_doorbell(&rxqinfo->rxq);
+	}
+}
+
+static inline void bnad_refill_rxq(struct bnad_rxq_info *rxqinfo)
+{
+	if (!test_and_set_bit(BNAD_RXQ_REFILL, &rxqinfo->flags)) {
+		if (BNA_QE_FREE_CNT
+		    (&rxqinfo->skb_unmap_q,
+		     rxqinfo->skb_unmap_q.
+		     q_depth) >> BNAD_RXQ_REFILL_THRESHOLD_SHIFT)
+			bnad_alloc_rxbufs(rxqinfo);
+		smp_mb__before_clear_bit();
+		clear_bit(BNAD_RXQ_REFILL, &rxqinfo->flags);
+	}
+}
+
+static unsigned int bnad_poll_cq(struct bnad *bnad,
+	struct bnad_cq_info *cqinfo, int budget)
+{
+	struct bna_cq_entry *cmpl, *next_cmpl;
+	unsigned int wi_range, packets = 0, wis = 0;
+	struct bnad_rxq_info *rxqinfo = NULL;
+	struct bnad_unmap_q *unmap_q;
+	struct sk_buff *skb;
+	u32 flags;
+	struct bna_pkt_rate *pkt_rt = &cqinfo->pkt_rate;
+
+	prefetch(bnad->netdev);
+	cmpl = bna_cq_pg_prod_ptr(&cqinfo->cq, &wi_range);
+	BUG_ON(!(wi_range && wi_range <= cqinfo->cq.q.q_depth));
+	while (cmpl->valid && packets < budget) {
+		packets++;
+		BNA_UPDATE_PKT_CNT(pkt_rt, ntohs(cmpl->length));
+
+		rxqinfo = &bnad->rxq_table[cmpl->rxq_id];
+		unmap_q = &rxqinfo->skb_unmap_q;
+
+		skb = unmap_q->unmap_array[unmap_q->consumer_index].skb;
+		prefetch(skb->data - NET_IP_ALIGN);
+		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),
+				 rxqinfo->rxq_config.buffer_size,
+				 PCI_DMA_FROMDEVICE);
+		BNA_QE_INDX_ADD(unmap_q->consumer_index, 1, unmap_q->q_depth);
+		/* XXX May be bad for performance. */
+		/* CATAPULT_BRINGUP : Should we add all the packets ? */
+		BNA_Q_CI_ADD(&rxqinfo->rxq, 1);
+
+		wis++;
+		if (likely(--wi_range))
+			next_cmpl = cmpl + 1;
+		else {
+			BNA_Q_PI_ADD(&cqinfo->cq, wis);
+			wis = 0;
+			next_cmpl = bna_cq_pg_prod_ptr(&cqinfo->cq, &wi_range);
+			BUG_ON(!(wi_range &&
+				   wi_range <= cqinfo->cq.q.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(skb);
+			rxqinfo->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;
+
+		rxqinfo->rx_packets++;
+		rxqinfo->rx_bytes += skb->len;
+		skb->protocol = eth_type_trans(skb, bnad->netdev);
+
+		if (bnad->vlangrp && (flags & BNA_CQ_EF_VLAN) &&
+		    bnad_vlan_strip) {
+			vlan_hwaccel_receive_skb(skb, bnad->vlangrp,
+						 ntohs(cmpl->vlan_tag));
+		} else
+			netif_receive_skb(skb);
+next:
+		cmpl->valid = 0;
+		cmpl = next_cmpl;
+	}
+
+	BNA_Q_PI_ADD(&cqinfo->cq, wis);
+
+	if (likely(rxqinfo)) {
+		bna_ib_ack(bnad->priv, &cqinfo->ib, packets);
+		/* Check the current queue first. */
+		bnad_refill_rxq(rxqinfo);
+
+		/* XXX counters per queue for refill? */
+		if (likely(bnad_small_large_rxbufs)) {
+			/* There are 2 RxQs - small and large buffer queues */
+			unsigned int rxq_id = (rxqinfo->rxq_id ^ 1);
+			bnad_refill_rxq(&bnad->rxq_table[rxq_id]);
+		}
+	} else {
+		bna_ib_ack(bnad->priv, &cqinfo->ib, 0);
+	}
+
+	return packets;
+}
+
+static irqreturn_t bnad_msix_rx(int irq, void *data)
+{
+	struct bnad_cq_info *cqinfo = (struct bnad_cq_info *)data;
+	struct bnad *bnad = cqinfo->bnad;
+
+	if (likely(napi_schedule_prep(&cqinfo->napi))) {
+		bnad_disable_rx_irq(bnad, cqinfo);
+		__napi_schedule(&cqinfo->napi);
+	}
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t bnad_msix_err_mbox(int irq, void *data)
+{
+	struct net_device *netdev = data;
+	struct bnad *bnad = netdev_priv(netdev);
+	u32 intr_status;
+
+	spin_lock(&bnad->priv_lock);
+
+	bna_intr_status_get(bnad->priv, &intr_status);
+	if (BNA_IS_MBOX_ERR_INTR(intr_status))
+		bna_mbox_err_handler(bnad->priv, intr_status);
+
+	spin_unlock(&bnad->priv_lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t bnad_isr(int irq, void *data)
+{
+	struct net_device *netdev = data;
+	struct bnad *bnad = netdev_priv(netdev);
+	u32 intr_status;
+
+	spin_lock(&bnad->priv_lock);
+	bna_intr_status_get(bnad->priv, &intr_status);
+
+	if (!intr_status) {
+		spin_unlock(&bnad->priv_lock);
+		return IRQ_NONE;
+	}
+
+	if (BNA_IS_MBOX_ERR_INTR(intr_status)) {
+		bna_mbox_err_handler(bnad->priv, intr_status);
+		spin_unlock(&bnad->priv_lock);
+		if (BNA_IS_ERR_INTR(intr_status) ||
+		    !BNA_IS_INTX_DATA_INTR(intr_status))
+			goto exit_isr;
+	} else
+		spin_unlock(&bnad->priv_lock);
+
+	if (likely(napi_schedule_prep(&bnad->cq_table[0].napi))) {
+		bnad_disable_txrx_irqs(bnad);
+		__napi_schedule(&bnad->cq_table[0].napi);
+	}
+
+exit_isr:
+	return IRQ_HANDLED;
+}
+
+static int bnad_request_mbox_irq(struct bnad *bnad)
+{
+	int err;
+
+	if (bnad->config & BNAD_CF_MSIX) {
+		err = request_irq(bnad->msix_table[bnad->msix_num - 1].vector,
+				  &bnad_msix_err_mbox, 0,
+				  bnad->netdev->name, bnad->netdev);
+	} else {
+		err = request_irq(bnad->pcidev->irq, &bnad_isr,
+				  IRQF_SHARED, bnad->netdev->name,
+				  bnad->netdev);
+	}
+
+	if (err) {
+		dev_err(&bnad->pcidev->dev,
+			"Request irq for mailbox failed: %d\n", err);
+		return err;
+	}
+
+	if (bnad->config & BNAD_CF_MSIX)
+		bna_mbox_msix_idx_set(bnad->priv, bnad->msix_num - 1);
+
+	bna_mbox_intr_enable(bnad->priv);
+	return 0;
+}
+
+static void bnad_sync_mbox_irq(struct bnad *bnad)
+{
+	uint irq;
+
+	if (bnad->config & BNAD_CF_MSIX)
+		irq = bnad->msix_table[bnad->msix_num - 1].vector;
+	else
+		irq = bnad->pcidev->irq;
+	synchronize_irq(irq);
+}
+
+static void bnad_free_mbox_irq(struct bnad *bnad)
+{
+	uint irq;
+
+	if (bnad->config & BNAD_CF_MSIX)
+		irq = bnad->msix_table[bnad->msix_num - 1].vector;
+	else
+		irq = bnad->pcidev->irq;
+
+	spin_lock_irq(&bnad->priv_lock);
+	bna_mbox_intr_disable(bnad->priv);
+	spin_unlock_irq(&bnad->priv_lock);
+
+	free_irq(irq, bnad->netdev);
+}
+
+static int bnad_request_txq_irq(struct bnad *bnad, uint txq_id)
+{
+	if (!(bnad->config & BNAD_CF_MSIX))
+		return 0;
+	return request_irq(bnad->msix_table[txq_id].vector,
+			   &bnad_msix_tx, 0,
+			   bnad->txq_table[txq_id].name,
+			   &bnad->txq_table[txq_id]);
+}
+
+int
+bnad_request_cq_irq(struct bnad *bnad, uint cq_id)
+{
+	if (!(bnad->config & BNAD_CF_MSIX))
+		return 0;
+	return request_irq(bnad->msix_table[bnad->txq_num + cq_id].vector,
+			   &bnad_msix_rx, 0,
+			   bnad->cq_table[cq_id].name, &bnad->cq_table[cq_id]);
+}
+
+static int bnad_request_txrx_irqs(struct bnad *bnad)
+{
+	struct msix_entry *entries;
+	int i;
+	int err;
+
+	if (!(bnad->config & BNAD_CF_MSIX)) {
+		u32 mask;
+		bna_intx_disable(bnad->priv, &mask);
+		mask &= ~0xffff;
+		bna_intx_enable(bnad->priv, mask);
+		for (i = 0; i < bnad->ib_num; i++)
+			bna_ib_ack(bnad->priv, bnad->ib_table[i].ib, 0);
+		return 0;
+	}
+
+	entries = bnad->msix_table;
+	for (i = 0; i < bnad->txq_num; i++) {
+		err = bnad_request_txq_irq(bnad, i);
+		if (err) {
+			pr_info("%s request irq for TxQ %d failed %d",
+				bnad->netdev->name, i, err);
+			while (--i >= 0) {
+				free_irq(entries[i].vector,
+					 &bnad->txq_table[i]);
+			}
+			return err;
+		}
+	}
+
+	for (i = 0; i < bnad->cq_num; i++) {
+		err = bnad_request_cq_irq(bnad, i);
+		if (err) {
+			pr_info("%s request irq for CQ %u failed %d",
+				bnad->netdev->name, i, err);
+			while (--i >= 0) {
+				free_irq(entries[bnad->txq_num + i].vector,
+					 &bnad->cq_table[i]);
+			}
+			goto free_txq_irqs;
+		}
+	}
+
+	return 0;
+
+free_txq_irqs:
+	for (i = 0; i < bnad->txq_num; i++)
+		free_irq(entries[i].vector, &bnad->txq_table[i]);
+
+	bnad_disable_msix(bnad);
+
+	return err;
+}
+
+static void bnad_free_txrx_irqs(struct bnad *bnad)
+{
+	struct msix_entry *entries;
+	uint i;
+
+	if (bnad->config & BNAD_CF_MSIX) {
+		entries = bnad->msix_table;
+		for (i = 0; i < bnad->txq_num; i++)
+			free_irq(entries[i].vector, &bnad->txq_table[i]);
+
+		for (i = 0; i < bnad->cq_num; i++) {
+			free_irq(entries[bnad->txq_num + i].vector,
+				 &bnad->cq_table[i]);
+		}
+	} else
+		synchronize_irq(bnad->pcidev->irq);
+}
+
+void
+bnad_setup_ib(struct bnad *bnad, uint ib_id)
+{
+	struct bnad_ib_entry *ib_entry;
+
+	ib_entry = &bnad->ib_table[ib_id];
+	spin_lock_irq(&bnad->priv_lock);
+	bna_ib_config_set(bnad->priv, ib_entry->ib, ib_id,
+			  &ib_entry->ib_config);
+	/* Start the IB */
+	bna_ib_ack(bnad->priv, ib_entry->ib, 0);
+	spin_unlock_irq(&bnad->priv_lock);
+}
+
+static void bnad_setup_ibs(struct bnad *bnad)
+{
+	int i;
+
+	for (i = 0; i < bnad->txq_num; i++)
+		bnad_setup_ib(bnad, bnad->txq_table[i].txq_config.ib_id);
+
+	for (i = 0; i < bnad->cq_num; i++)
+		bnad_setup_ib(bnad, bnad->cq_table[i].cq_config.ib_id);
+}
+
+/* These functions are called back with priv_lock held. */
+
+static void bnad_lldp_get_cfg_cb(void *arg, u8 status)
+{
+	struct bnad *bnad = arg;
+	bnad->lldp_comp_status = status;
+	complete(&bnad->lldp_comp);
+}
+
+static void bnad_cee_get_attr_cb(void *arg, bfa_status_t status)
+{
+	struct bnad *bnad = arg;
+	bnad->lldp_comp_status = status;
+	complete(&bnad->lldp_comp);
+}
+
+static void bnad_cee_get_stats_cb(void *arg, bfa_status_t status)
+{
+	struct bnad *bnad = arg;
+	bnad->cee_stats_comp_status = status;
+	complete(&bnad->cee_stats_comp);
+}
+
+static void bnad_cee_reset_stats_cb(void *arg, bfa_status_t status)
+{
+	struct bnad *bnad = arg;
+	bnad->cee_reset_stats_status = status;
+	complete(&bnad->cee_reset_stats_comp);
+}
+
+static void bnad_ucast_set_cb(void *arg, u8 status)
+{
+	struct bnad *bnad = (struct bnad *)arg;
+
+	bnad->ucast_comp_status = status;
+	complete(&bnad->ucast_comp);
+}
+
+static void bnad_q_stop_cb(void *arg, u8 status)
+{
+	struct bnad *bnad = arg;
+
+	bnad->qstop_comp_status = status;
+	complete(&bnad->qstop_comp);
+}
+
+static unsigned int bnad_get_priority(struct bnad *bnad, u8 prio_map)
+{
+	unsigned int i;
+
+	if (prio_map) {
+		for (i = 0; i < 8; i++) {
+			if ((prio_map >> i) & 0x1)
+				break;
+		}
+		return i;
+	}
+	return 0;
+}
+
+static void bnad_link_up_cb(void *arg, u8 status)
+{
+	struct bnad *bnad = (struct bnad *)arg;
+	struct bfi_ll_aen *up_aen = (struct bfi_ll_aen *)
+		(&bnad->priv->mb_msg);
+
+	bnad->cee_linkup = up_aen->cee_linkup;
+	bnad->priority = bnad_get_priority(bnad, up_aen->prio_map);
+
+	bnad->link_state = BNAD_LS_UP;
+	bnad->work_flags |= BNAD_WF_LS_NOTIFY;
+
+	schedule_work(&bnad->work);
+}
+
+static void bnad_link_down_cb(void *arg, u8 status)
+{
+	struct bnad *bnad = (struct bnad *)arg;
+
+	bnad->link_state = BNAD_LS_DOWN;
+	bnad->work_flags |= BNAD_WF_LS_NOTIFY;
+
+	schedule_work(&bnad->work);
+}
+
+static void bnad_stats_get_cb(void *arg, u8 status)
+{
+	struct bnad *bnad = (struct bnad *)arg;
+
+	bnad->stats.hw_stats_updates++;
+	if (bnad->state == BNAD_S_OPEN)
+		mod_timer(&bnad->stats_timer, jiffies + HZ);
+}
+
+/* Called with bnad priv_lock held. */
+static void bnad_hw_error(struct bnad *bnad, u8 status)
+{
+	unsigned int irq;
+
+	set_bit(BNAD_F_HWERROR, &bnad->flags);
+
+	bna_mbox_intr_disable(bnad->priv);
+	if (bnad->config & BNAD_CF_MSIX) {
+		if (!test_and_set_bit(BNAD_F_MBOX_IRQ_DISABLED, &bnad->flags)) {
+			irq = bnad->msix_table[bnad->msix_num - 1].vector;
+			pr_info("Disabling Mbox IRQ %d for port %d",
+				irq, bnad->bna_id);
+			disable_irq_nosync(irq);
+		}
+	}
+
+	bna_cleanup(bnad->priv);
+
+	bnad->work_flags = BNAD_WF_ERROR;
+	if (bnad->state != BNAD_S_UNLOADING)
+		schedule_work(&bnad->work);
+}
+
+static void bnad_hw_error_cb(void *arg, u8 status)
+{
+	struct bnad *bnad = (struct bnad *)arg;
+
+	bnad_hw_error(bnad, status);
+}
+
+int
+bnad_alloc_unmap_q(struct bnad_unmap_q *unmap_q, u32 q_depth)
+{
+	/* Q_depth must be power of 2 for macros to work. */
+	unmap_q->q_depth = q_depth;
+	unmap_q->unmap_array = vmalloc(q_depth * sizeof(struct bnad_skb_unmap));
+	if (!unmap_q->unmap_array)
+		return -ENOMEM;
+	memset(unmap_q->unmap_array, 0,
+	       q_depth * sizeof(struct bnad_skb_unmap));
+	return 0;
+}
+
+static int bnad_alloc_unmap_queues(struct bnad *bnad)
+{
+	int i, err = 0;
+	struct bnad_txq_info *txqinfo;
+	struct bnad_rxq_info *rxqinfo;
+
+	for (i = 0; i < bnad->txq_num; i++) {
+		txqinfo = &bnad->txq_table[i];
+		err = bnad_alloc_unmap_q(&txqinfo->skb_unmap_q,
+					 txqinfo->txq.q.q_depth * 4);
+		if (err) {
+			pr_info(
+				"%s allocating Tx unmap Q %d failed: %d",
+				bnad->netdev->name, i, err);
+			return err;
+		}
+	}
+	for (i = 0; i < bnad->rxq_num; i++) {
+		rxqinfo = &bnad->rxq_table[i];
+		err = bnad_alloc_unmap_q(&rxqinfo->skb_unmap_q,
+					 rxqinfo->rxq.q.q_depth);
+		if (err) {
+			pr_info(
+				"%s allocating Rx unmap Q %d failed: %d",
+				bnad->netdev->name, i, err);
+			return err;
+		}
+	}
+	return 0;
+}
+
+static void bnad_reset_q(struct bnad *bnad, struct bna_q *q,
+	struct bnad_unmap_q *unmap_q)
+{
+	q->producer_index = 0;
+	q->consumer_index = 0;
+	unmap_q->producer_index = 0;
+	unmap_q->consumer_index = 0;
+}
+
+static void bnad_flush_rxbufs(struct bnad_rxq_info *rxqinfo)
+{
+	struct bnad *bnad = rxqinfo->bnad;
+	struct bnad_unmap_q *unmap_q;
+	struct sk_buff *skb;
+	u32 cq_id;
+
+	unmap_q = &rxqinfo->skb_unmap_q;
+	while (BNA_QE_IN_USE_CNT(unmap_q, unmap_q->q_depth)) {
+		skb = unmap_q->unmap_array[unmap_q->consumer_index].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),
+				 rxqinfo->rxq_config.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_Q_CI_ADD(&rxqinfo->rxq, 1);
+	}
+
+	bnad_reset_q(bnad, &rxqinfo->rxq.q, &rxqinfo->skb_unmap_q);
+	cq_id = rxqinfo->rxq_id / bnad_rxqs_per_cq;
+	*bnad->cq_table[cq_id].hw_producer_index = 0;
+}
+
+/* Should be called with conf_lock held. */
+static int bnad_disable_txq(struct bnad *bnad, u32 txq_id)
+{
+	int err;
+
+	WARN_ON(in_interrupt());
+
+	init_completion(&bnad->qstop_comp);
+	spin_lock_irq(&bnad->priv_lock);
+	err = bna_txq_stop(bnad->priv, txq_id);
+	spin_unlock_irq(&bnad->priv_lock);
+
+	if (err) {
+		if (err == BNA_AGAIN)
+			err = 0;
+		goto txq_stop_exit;
+	}
+
+	if (BNAD_NOT_READY(bnad)) {
+		err = BNA_FAIL;
+		goto txq_stop_exit;
+	}
+	wait_for_completion(&bnad->qstop_comp);
+	err = bnad->qstop_comp_status;
+
+	if (err == BFI_LL_CMD_NOT_EXEC) {
+		if (bnad->state == BNAD_S_CLOSING)
+			err = 0;
+		else
+			err = BNA_FAIL;
+	}
+
+txq_stop_exit:
+	if (err) {
+		pr_info("%s stop TxQ %u failed %d", bnad->netdev->name,
+			txq_id, err);
+	}
+
+	return err;
+}
+
+/* Should be called with conf_lock held. */
+int
+bnad_disable_rxqs(struct bnad *bnad, u64 rxq_id_mask)
+{
+	int err;
+
+	WARN_ON(in_interrupt());
+
+	init_completion(&bnad->qstop_comp);
+
+	spin_lock_irq(&bnad->priv_lock);
+	err = bna_multi_rxq_stop(bnad->priv, rxq_id_mask);
+	spin_unlock_irq(&bnad->priv_lock);
+	if (err) {
+		if (err == BNA_AGAIN)
+			err = 0;
+		goto rxq_stop_exit;
+	}
+
+	if (BNAD_NOT_READY(bnad)) {
+		err = BNA_FAIL;
+		goto rxq_stop_exit;
+	}
+	wait_for_completion(&bnad->qstop_comp);
+
+	err = bnad->qstop_comp_status;
+
+	if (err == BFI_LL_CMD_NOT_EXEC) {
+		if (bnad->state == BNAD_S_CLOSING)
+			err = 0;
+		else
+			err = BNA_FAIL;
+	}
+
+rxq_stop_exit:
+	if (err) {
+		pr_info("%s stop RxQs(0x%llu) failed %d",
+			bnad->netdev->name, rxq_id_mask, err);
+	}
+
+	return err;
+}
+
+static int bnad_poll_rx(struct napi_struct *napi, int budget)
+{
+	struct bnad_cq_info *cqinfo =
+		container_of(napi, struct bnad_cq_info, napi);
+	struct bnad *bnad = cqinfo->bnad;
+	unsigned int rcvd;
+
+	rcvd = bnad_poll_cq(bnad, cqinfo, budget);
+	if (rcvd == budget)
+		return rcvd;
+	napi_complete(napi);
+	bnad->stats.napi_complete++;
+	bnad_enable_rx_irq(bnad, cqinfo);
+	return rcvd;
+}
+
+static int bnad_poll_txrx(struct napi_struct *napi, int budget)
+{
+	struct bnad_cq_info *cqinfo =
+		container_of(napi, struct bnad_cq_info, napi);
+	struct bnad *bnad = cqinfo->bnad;
+	unsigned int rcvd;
+
+	bnad_tx(bnad, &bnad->txq_table[0]);
+	rcvd = bnad_poll_cq(bnad, cqinfo, budget);
+	if (rcvd == budget)
+		return rcvd;
+	napi_complete(napi);
+	bnad->stats.napi_complete++;
+	bnad_enable_txrx_irqs(bnad);
+	return rcvd;
+}
+
+static void bnad_napi_init(struct bnad *bnad)
+{
+	int (*napi_poll) (struct napi_struct *, int);
+	int i;
+
+	if (bnad->config & BNAD_CF_MSIX)
+		napi_poll = bnad_poll_rx;
+	else
+		napi_poll = bnad_poll_txrx;
+
+	for (i = 0; i < bnad->cq_num; i++)
+		netif_napi_add(bnad->netdev, &bnad->cq_table[i].napi, napi_poll,
+			       64);
+}
+
+static void bnad_napi_enable(struct bnad *bnad)
+{
+	int i;
+
+	for (i = 0; i < bnad->cq_num; i++)
+		napi_enable(&bnad->cq_table[i].napi);
+}
+
+static void bnad_napi_disable(struct bnad *bnad)
+{
+	int i;
+
+	for (i = 0; i < bnad->cq_num; i++)
+		napi_disable(&bnad->cq_table[i].napi);
+}
+
+static void bnad_napi_uninit(struct bnad *bnad)
+{
+	int i;
+
+	for (i = 0; i < bnad->cq_num; i++)
+		netif_napi_del(&bnad->cq_table[i].napi);
+}
+
+static void bnad_stop_data_path(struct bnad *bnad, int on_error)
+{
+	int i;
+
+	spin_lock_irq(&bnad->priv_lock);
+	if (!on_error && !BNAD_NOT_READY(bnad)) {
+		bna_txf_disable(bnad->priv, BNAD_TX_FUNC_ID);
+		bna_multi_rxf_disable(bnad->priv, (1 << bnad->rxf_num) - 1);
+		for (i = 0; i < bnad->txq_num; i++)
+			bna_ib_disable(bnad->priv, &bnad->txq_table[i].ib);
+		for (i = 0; i < bnad->cq_num; i++)
+			bna_ib_disable(bnad->priv, &bnad->cq_table[i].ib);
+	}
+	spin_unlock_irq(&bnad->priv_lock);
+
+	/* Wait to make sure Tx and Rx are stopped. */
+	msleep(1000);
+	bnad_free_txrx_irqs(bnad);
+	bnad_sync_mbox_irq(bnad);
+
+	bnad_napi_disable(bnad);
+	bnad_napi_uninit(bnad);
+	/* Delete the stats timer after synchronize with mbox irq. */
+	del_timer_sync(&bnad->stats_timer);
+
+	netif_tx_disable(bnad->netdev);
+	netif_carrier_off(bnad->netdev);
+
+	/*
+	 * Remove tasklets if scheduled
+	 */
+	tasklet_kill(&bnad->tx_free_tasklet);
+}
+
+static void bnad_port_admin_locked(struct bnad *bnad, u8 up)
+{
+
+	spin_lock_irq(&bnad->priv_lock);
+	if (!BNAD_NOT_READY(bnad)) {
+		bna_port_admin(bnad->priv, up);
+		if (up)
+			mod_timer(&bnad->stats_timer, jiffies + HZ);
+		else
+			bnad->link_state = BNAD_LS_DOWN;
+	}
+	spin_unlock_irq(&bnad->priv_lock);
+}
+
+/* Should be called with conf_lock held */
+static int bnad_stop_locked_internal(struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+
+	switch (bnad->state) {
+	case BNAD_S_OPEN:
+		bnad->state = BNAD_S_CLOSING;
+		bnad_disable_locked(bnad);
+		bnad->state = BNAD_S_INIT;
+		pr_info("%s is stopped", bnad->netdev->name);
+		break;
+	case BNAD_S_OPEN_DOWN:
+		bnad->state = BNAD_S_INIT_DOWN;
+		break;
+	case BNAD_S_OPEN_DISABLED:
+		bnad->state = BNAD_S_INIT_DISABLED;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/* Should be called with conf_lock held */
+int
+bnad_ioc_disabling_locked(struct bnad *bnad)
+{
+	switch (bnad->state) {
+	case BNAD_S_INIT:
+	case BNAD_S_INIT_DOWN:
+		bnad->state = BNAD_S_INIT_DISABLING;
+		break;
+	case BNAD_S_OPEN:
+		bnad->state = BNAD_S_OPEN_DISABLING;
+		bnad_port_admin_locked(bnad, BNA_DISABLE);
+		bnad_disable_locked(bnad);
+		break;
+	case BNAD_S_OPEN_DOWN:
+		bnad->state = BNAD_S_OPEN_DISABLING;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int bnad_alloc_ib(struct bnad *bnad, uint ib_id)
+{
+	struct bnad_ib_entry *ib_entry;
+	dma_addr_t dma_addr;
+
+	ib_entry = &bnad->ib_table[ib_id];
+	ib_entry->ib_seg_addr =
+		pci_alloc_consistent(bnad->pcidev, L1_CACHE_BYTES, &dma_addr);
+	if (!ib_entry->ib_seg_addr)
+		return -ENOMEM;
+
+	BNA_SET_DMA_ADDR(dma_addr, &ib_entry->ib_config.ib_seg_addr);
+	return 0;
+}
+static int bnad_alloc_ibs(struct bnad *bnad)
+{
+	uint i;
+	int err;
+
+	bnad->ib_num = bnad->txq_num + bnad->cq_num;
+	bnad->ib_table =
+		kcalloc(bnad->ib_num, sizeof(struct bnad_ib_entry),
+			GFP_KERNEL);
+	if (!bnad->ib_table)
+		return -ENOMEM;
+
+	for (i = 0; i < bnad->ib_num; i++) {
+		err = bnad_alloc_ib(bnad, i);
+		if (err)
+			goto free_ibs;
+	}
+	return 0;
+
+free_ibs:
+	bnad_free_ibs(bnad);
+	return err;
+}
+
+void
+bnad_free_ib(struct bnad *bnad, uint ib_id)
+{
+	struct bnad_ib_entry *ib_entry;
+	dma_addr_t dma_addr;
+
+	ib_entry = &bnad->ib_table[ib_id];
+	if (ib_entry->ib_seg_addr) {
+		BNA_GET_DMA_ADDR(&ib_entry->ib_config.ib_seg_addr, dma_addr);
+		pci_free_consistent(bnad->pcidev, L1_CACHE_BYTES,
+				    ib_entry->ib_seg_addr, dma_addr);
+		ib_entry->ib_seg_addr = NULL;
+	}
+}
+
+static void bnad_free_ibs(struct bnad *bnad)
+{
+	uint i;
+
+	if (!bnad->ib_table)
+		return;
+	for (i = 0; i < bnad->ib_num; i++)
+		bnad_free_ib(bnad, i);
+	kfree(bnad->ib_table);
+	bnad->ib_table = NULL;
+}
+
+/* Let the caller deal with error - free memory. */
+static int bnad_alloc_q(struct bnad *bnad, struct bna_qpt *qpt,
+	struct bna_q *q, size_t qsize)
+{
+	size_t i;
+	dma_addr_t dma_addr;
+
+	qsize = ALIGN(qsize, PAGE_SIZE);
+	qpt->page_count = qsize >> PAGE_SHIFT;
+	qpt->page_size = PAGE_SIZE;
+
+	qpt->kv_qpt_ptr =
+		pci_alloc_consistent(bnad->pcidev,
+				     qpt->page_count *
+				     sizeof(struct bna_dma_addr), &dma_addr);
+	if (!qpt->kv_qpt_ptr)
+		return -ENOMEM;
+	BNA_SET_DMA_ADDR(dma_addr, &qpt->hw_qpt_ptr);
+
+	q->qpt_ptr = kcalloc(qpt->page_count, sizeof(void *), GFP_KERNEL);
+	if (!q->qpt_ptr)
+		return -ENOMEM;
+	qpt->qpt_ptr = q->qpt_ptr;
+	for (i = 0; i < qpt->page_count; i++) {
+		q->qpt_ptr[i] =
+			pci_alloc_consistent(bnad->pcidev, PAGE_SIZE,
+					     &dma_addr);
+		if (!q->qpt_ptr[i])
+			return -ENOMEM;
+		BNA_SET_DMA_ADDR(dma_addr,
+				 &((struct bna_dma_addr *)qpt->kv_qpt_ptr)[i]);
+
+	}
+
+	return 0;
+}
+
+static void bnad_free_q(struct bnad *bnad, struct bna_qpt *qpt,
+	struct bna_q *q)
+{
+	int i;
+	dma_addr_t dma_addr;
+
+	if (qpt->kv_qpt_ptr && q->qpt_ptr) {
+		for (i = 0; i < qpt->page_count; i++) {
+			if (q->qpt_ptr[i]) {
+				BNA_GET_DMA_ADDR(&
+						 ((struct bna_dma_addr *)qpt->
+						  kv_qpt_ptr)[i], dma_addr);
+				pci_free_consistent(bnad->pcidev, PAGE_SIZE,
+						    q->qpt_ptr[i], dma_addr);
+			}
+		}
+	}
+
+	kfree(q->qpt_ptr);
+	qpt->qpt_ptr = q->qpt_ptr = NULL;
+
+	if (qpt->kv_qpt_ptr) {
+		BNA_GET_DMA_ADDR(&qpt->hw_qpt_ptr, dma_addr);
+		pci_free_consistent(bnad->pcidev,
+				    qpt->page_count *
+				    sizeof(struct bna_dma_addr),
+				    qpt->kv_qpt_ptr, dma_addr);
+		qpt->kv_qpt_ptr = NULL;
+	}
+}
+
+static void bnad_free_txq(struct bnad *bnad, uint txq_id)
+{
+	struct bnad_txq_info *txqinfo;
+
+	txqinfo = &bnad->txq_table[txq_id];
+	bnad_free_q(bnad, &txqinfo->txq_config.qpt, &txqinfo->txq.q);
+	if (txqinfo->skb_unmap_q.unmap_array) {
+		bnad_free_txbufs(txqinfo, txqinfo->txq.q.producer_index);
+		vfree(txqinfo->skb_unmap_q.unmap_array);
+		txqinfo->skb_unmap_q.unmap_array = NULL;
+	}
+}
+
+void
+bnad_free_rxq(struct bnad *bnad, uint rxq_id)
+{
+	struct bnad_rxq_info *rxqinfo;
+
+	rxqinfo = &bnad->rxq_table[rxq_id];
+	bnad_free_q(bnad, &rxqinfo->rxq_config.qpt, &rxqinfo->rxq.q);
+	if (rxqinfo->skb_unmap_q.unmap_array) {
+		bnad_flush_rxbufs(rxqinfo);
+		vfree(rxqinfo->skb_unmap_q.unmap_array);
+		rxqinfo->skb_unmap_q.unmap_array = NULL;
+	}
+}
+
+void
+bnad_free_cq(struct bnad *bnad, uint cq_id)
+{
+	struct bnad_cq_info *cqinfo = &bnad->cq_table[cq_id];
+
+	bnad_free_q(bnad, &cqinfo->cq_config.qpt, &cqinfo->cq.q);
+}
+
+static void bnad_free_queues(struct bnad *bnad)
+{
+	uint i;
+
+	if (bnad->txq_table) {
+		for (i = 0; i < bnad->txq_num; i++)
+			bnad_free_txq(bnad, i);
+		kfree(bnad->txq_table);
+		bnad->txq_table = NULL;
+	}
+
+	if (bnad->rxq_table) {
+		for (i = 0; i < bnad->rxq_num; i++)
+			bnad_free_rxq(bnad, i);
+		kfree(bnad->rxq_table);
+		bnad->rxq_table = NULL;
+	}
+
+	if (bnad->cq_table) {
+		for (i = 0; i < bnad->cq_num; i++)
+			bnad_free_cq(bnad, i);
+		kfree(bnad->cq_table);
+		bnad->cq_table = NULL;
+	}
+}
+
+static int bnad_txq_init(struct bnad *bnad, uint txq_id)
+{
+	struct bnad_txq_info *txqinfo;
+	int err;
+
+	txqinfo = &bnad->txq_table[txq_id];
+	err = bnad_alloc_q(bnad, &txqinfo->txq_config.qpt, &txqinfo->txq.q,
+			   bnad->txq_depth * sizeof(struct bna_txq_entry));
+	if (err) {
+		bnad_free_q(bnad, &txqinfo->txq_config.qpt, &txqinfo->txq.q);
+		return err;
+	}
+	txqinfo->txq.q.q_depth = bnad->txq_depth;
+	txqinfo->bnad = bnad;
+	txqinfo->txq_config.txf_id = BNAD_TX_FUNC_ID;
+	snprintf(txqinfo->name, sizeof(txqinfo->name), "%s TxQ %d",
+		 bnad->netdev->name, txq_id);
+	return 0;
+}
+
+static int bnad_txqs_init(struct bnad *bnad)
+{
+	int i, err = 0;
+
+	bnad->txq_table =
+		kcalloc(bnad->txq_num, sizeof(struct bnad_txq_info),
+			GFP_KERNEL);
+	if (!bnad->txq_table)
+		return -ENOMEM;
+
+	for (i = 0; i < bnad->txq_num; i++) {
+		err = bnad_txq_init(bnad, i);
+		if (err)
+			break;
+	}
+	return err;
+}
+
+int
+bnad_rxq_init(struct bnad *bnad, uint rxq_id)
+{
+	struct bnad_rxq_info *rxqinfo;
+	int err;
+
+	rxqinfo = &bnad->rxq_table[rxq_id];
+	err = bnad_alloc_q(bnad, &rxqinfo->rxq_config.qpt, &rxqinfo->rxq.q,
+			   bnad->rxq_depth * sizeof(struct bna_rxq_entry));
+	if (err) {
+		bnad_free_q(bnad, &rxqinfo->rxq_config.qpt, &rxqinfo->rxq.q);
+		return err;
+	}
+	rxqinfo->rxq.q.q_depth = bnad->rxq_depth;
+	rxqinfo->bnad = bnad;
+	rxqinfo->rxq_id = rxq_id;
+	rxqinfo->rxq_config.cq_id = rxq_id / bnad_rxqs_per_cq;
+
+	return 0;
+}
+
+static int
+bnad_rxqs_init(struct bnad *bnad)
+{
+	int i, err = 0;
+
+	bnad->rxq_table =
+		kcalloc(bnad->rxq_num, sizeof(struct bnad_rxq_info),
+			GFP_KERNEL);
+	if (!bnad->rxq_table)
+		return -EINVAL;
+
+	for (i = 0; i < bnad->rxq_num; i++) {
+		err = bnad_rxq_init(bnad, i);
+		if (err)
+			break;
+	}
+	return err;
+}
+
+int
+bnad_cq_init(struct bnad *bnad, uint cq_id)
+{
+	struct bnad_cq_info *cqinfo;
+	int err;
+
+	cqinfo = &bnad->cq_table[cq_id];
+	err = bnad_alloc_q(bnad, &cqinfo->cq_config.qpt, &cqinfo->cq.q,
+			   bnad->rxq_depth * bnad_rxqs_per_cq *
+			   sizeof(struct bna_cq_entry));
+	if (err) {
+		bnad_free_q(bnad, &cqinfo->cq_config.qpt, &cqinfo->cq.q);
+		return err;
+	}
+
+	cqinfo->cq.q.q_depth = bnad->rxq_depth * bnad_rxqs_per_cq;
+	cqinfo->bnad = bnad;
+
+	cqinfo->rx_coalescing_timeo = bnad->rx_coalescing_timeo;
+
+	cqinfo->cq_id = cq_id;
+	snprintf(cqinfo->name, sizeof(cqinfo->name), "%s CQ %d",
+		 bnad->netdev->name, cq_id);
+
+	return 0;
+}
+
+static int bnad_cqs_init(struct bnad *bnad)
+{
+	int i, err = 0;
+
+	bnad->cq_table =
+		kcalloc(bnad->cq_num, sizeof(struct bnad_cq_info), GFP_KERNEL);
+	if (!bnad->cq_table)
+		return -ENOMEM;
+
+	for (i = 0; i < bnad->cq_num; i++) {
+		err = bnad_cq_init(bnad, i);
+		if (err)
+			break;
+	}
+	return err;
+}
+
+static uint bnad_get_qsize(uint qsize_conf, uint mtu)
+{
+	uint qsize;
+
+	if (mtu >= ETH_DATA_LEN) {
+		qsize = qsize_conf / (mtu / ETH_DATA_LEN);
+		if (!BNA_POWER_OF_2(qsize))
+			BNA_TO_POWER_OF_2_HIGH(qsize);
+		if (qsize < BNAD_MIN_Q_DEPTH)
+			qsize = BNAD_MIN_Q_DEPTH;
+	} else
+		qsize = bnad_txq_depth;
+
+	return qsize;
+}
+
+static int bnad_init_queues(struct bnad *bnad)
+{
+	int err;
+
+	if (!(bnad->config & BNAD_CF_TXQ_DEPTH))
+		bnad->txq_depth =
+			bnad_get_qsize(bnad_txq_depth, bnad->netdev->mtu);
+	if (!(bnad->config & BNAD_CF_RXQ_DEPTH))
+		bnad->rxq_depth =
+			bnad_get_qsize(bnad_rxq_depth, bnad->netdev->mtu);
+
+	err = bnad_txqs_init(bnad);
+	if (err)
+		return err;
+
+	err = bnad_rxqs_init(bnad);
+	if (err)
+		return err;
+
+	err = bnad_cqs_init(bnad);
+
+	return err;
+}
+
+void
+bnad_rxib_init(struct bnad *bnad, uint cq_id, uint ib_id)
+{
+	struct bnad_cq_info *cqinfo;
+	struct bnad_ib_entry *ib_entry;
+	struct bna_ib_config *ib_config;
+
+	cqinfo = &bnad->cq_table[cq_id];
+	ib_entry = &bnad->ib_table[ib_id];
+
+	cqinfo->hw_producer_index = (u32 *) (ib_entry->ib_seg_addr);
+	cqinfo->cq_config.ib_id = ib_id;
+	cqinfo->cq_config.ib_seg_index = 0;
+
+	ib_entry->ib = &cqinfo->ib;
+	ib_config = &ib_entry->ib_config;
+	ib_config->coalescing_timer = bnad->rx_coalescing_timeo;
+	ib_config->control_flags =
+		BNA_IB_CF_INT_ENABLE | BNA_IB_CF_MASTER_ENABLE;
+	if (bnad->config & BNAD_CF_MSIX) {
+		ib_config->control_flags |= BNA_IB_CF_MSIX_MODE;
+		ib_config->msix_vector = ib_id;
+	} else
+		ib_config->msix_vector = 1 << ib_id;
+
+	/* Every CQ has its own IB. */
+	ib_config->seg_size = 1;
+	ib_config->index_table_offset = ib_id;
+}
+
+static void bnad_ibs_init(struct bnad *bnad)
+{
+	struct bnad_ib_entry *ib_entry;
+	struct bna_ib_config *ib_config;
+	struct bnad_txq_info *txqinfo;
+
+	int ib_id, i;
+
+	ib_id = 0;
+	for (i = 0; i < bnad->txq_num; i++) {
+		txqinfo = &bnad->txq_table[i];
+		ib_entry = &bnad->ib_table[ib_id];
+
+		txqinfo->hw_consumer_index = ib_entry->ib_seg_addr;
+		txqinfo->txq_config.ib_id = ib_id;
+		txqinfo->txq_config.ib_seg_index = 0;
+
+		ib_entry->ib = &txqinfo->ib;
+		ib_config = &ib_entry->ib_config;
+		ib_config->coalescing_timer = bnad->tx_coalescing_timeo;
+		ib_config->control_flags =
+			BNA_IB_CF_INTER_PKT_DMA | BNA_IB_CF_INT_ENABLE |
+			BNA_IB_CF_COALESCING_MODE | BNA_IB_CF_MASTER_ENABLE;
+		if (bnad->config & BNAD_CF_MSIX) {
+			ib_config->control_flags |= BNA_IB_CF_MSIX_MODE;
+			ib_config->msix_vector = ib_id;
+		} else
+			ib_config->msix_vector = 1 << ib_id;
+		ib_config->interpkt_count = bnad->tx_interpkt_count;
+
+		/* Every TxQ has its own IB. */
+		ib_config->seg_size = 1;
+		ib_config->index_table_offset = ib_id;
+		ib_id++;
+	}
+
+	for (i = 0; i < bnad->cq_num; i++, ib_id++)
+		bnad_rxib_init(bnad, i, ib_id);
+}
+
+static void
+bnad_txf_init(struct bnad *bnad, uint txf_id)
+{
+	struct bnad_txf_info *txf_info;
+
+	txf_info = &bnad->txf_table[txf_id];
+	txf_info->txf_id = txf_id;
+	txf_info->txf_config.flags =
+		BNA_TXF_CF_VLAN_WI_BASED | BNA_TXF_CF_ENABLE;
+}
+
+void
+bnad_rxf_init(struct bnad *bnad, uint rxf_id, u8 rit_offset, int rss)
+{
+	struct bnad_rxf_info *rxf_info;
+
+	rxf_info = &bnad->rxf_table[rxf_id];
+	rxf_info->rxf_id = rxf_id;
+	rxf_info->rxf_config.rit_offset = rit_offset;
+	rxf_info->rxf_config.mcast_rxq_id = BNAD_MULTICAST_RXQ_ID;
+	if (bnad_small_large_rxbufs)
+		rxf_info->rxf_config.flags |= BNA_RXF_CF_SM_LG_RXQ;
+	if (bnad_vlan_strip)
+		rxf_info->rxf_config.flags |= BNA_RXF_CF_VLAN_STRIP;
+	if (rss) {
+		struct bna_rxf_rss *rxf_rss;
+
+		rxf_info->rxf_config.flags |= BNA_RXF_CF_RSS_ENABLE;
+		rxf_rss = &rxf_info->rxf_config.rss;
+		rxf_rss->type =
+			BNA_RSS_V4_TCP | BNA_RSS_V4_IP | BNA_RSS_V6_TCP |
+			BNA_RSS_V6_IP;
+		rxf_rss->hash_mask = bnad->cq_num - 1;
+		get_random_bytes(rxf_rss->toeplitz_hash_key,
+				 sizeof(rxf_rss->toeplitz_hash_key));
+	}
+}
+
+static int bnad_init_funcs(struct bnad *bnad)
+{
+	bnad->txf_table =
+		kcalloc(bnad->txf_num, sizeof(struct bnad_txf_info),
+			GFP_KERNEL);
+	if (!bnad->txf_table)
+		return -ENOMEM;
+	bnad_txf_init(bnad, BNAD_TX_FUNC_ID);
+
+	bnad->rxf_table =
+		kcalloc(bnad->rxf_num, sizeof(struct bnad_rxf_info),
+			GFP_KERNEL);
+	if (!bnad->rxf_table)
+		return -ENOMEM;
+	bnad_rxf_init(bnad, BNAD_RX_FUNC_ID, BNAD_RIT_OFFSET,
+		      (bnad->cq_num > 1) ? 1 : 0);
+	return 0;
+}
+
+static void bnad_setup_txq(struct bnad *bnad, uint txq_id)
+{
+	struct bnad_txq_info *txqinfo;
+
+	txqinfo = &bnad->txq_table[txq_id];
+
+	/* CEE state should not change while we do this */
+	spin_lock_irq(&bnad->priv_lock);
+	if (!bnad->cee_linkup) {
+		txqinfo->txq_config.priority = bnad->curr_priority = txq_id;
+		clear_bit(BNAD_F_CEE_RUNNING, &bnad->flags);
+	} else {
+		txqinfo->txq_config.priority = bnad->curr_priority =
+			bnad->priority;
+		set_bit(BNAD_F_CEE_RUNNING, &bnad->flags);
+	}
+	/*  Set wrr_quota properly if multiple priorities/TxQs are enabled. */
+	txqinfo->txq_config.wrr_quota = BNAD_TX_MAX_WRR_QUOTA;
+	bna_txq_config(bnad->priv, &txqinfo->txq, txq_id, &txqinfo->txq_config);
+	spin_unlock_irq(&bnad->priv_lock);
+}
+
+void
+bnad_setup_rxq(struct bnad *bnad, uint rxq_id)
+{
+	struct bnad_rxq_info *rxqinfo;
+
+	rxqinfo = &bnad->rxq_table[rxq_id];
+
+	/*
+	 * Every RxQ set has 2 RxQs: the first is large buffer RxQ,
+	 * the second is small buffer RxQ.
+	 */
+	if ((rxq_id % bnad_rxqs_per_cq) == 0)
+		rxqinfo->rxq_config.buffer_size =
+			(bnad_vlan_strip ? VLAN_ETH_HLEN : ETH_HLEN) +
+			bnad->netdev->mtu + ETH_FCS_LEN;
+	else
+		rxqinfo->rxq_config.buffer_size = BNAD_SMALL_RXBUF_SIZE;
+
+	spin_lock_irq(&bnad->priv_lock);
+	bna_rxq_config(bnad->priv, &rxqinfo->rxq, rxq_id, &rxqinfo->rxq_config);
+	spin_unlock_irq(&bnad->priv_lock);
+}
+
+void
+bnad_setup_cq(struct bnad *bnad, uint cq_id)
+{
+	struct bnad_cq_info *cqinfo;
+
+	cqinfo = &bnad->cq_table[cq_id];
+	spin_lock_irq(&bnad->priv_lock);
+	bna_cq_config(bnad->priv, &cqinfo->cq, cq_id, &cqinfo->cq_config);
+	spin_unlock_irq(&bnad->priv_lock);
+}
+
+static void bnad_setup_queues(struct bnad *bnad)
+{
+	uint i;
+
+	for (i = 0; i < bnad->txq_num; i++)
+		bnad_setup_txq(bnad, i);
+
+	for (i = 0; i < bnad->rxq_num; i++)
+		bnad_setup_rxq(bnad, i);
+
+	for (i = 0; i < bnad->cq_num; i++)
+		bnad_setup_cq(bnad, i);
+}
+
+static void bnad_setup_rit(struct bnad *bnad)
+{
+	int i, size;
+
+	size = bnad->cq_num;
+	for (i = 0; i < size; i++) {
+		if (bnad_small_large_rxbufs) {
+			bnad->rit[i].large_rxq_id = (i << 1);
+			bnad->rit[i].small_rxq_id = (i << 1) + 1;
+		} else {
+			bnad->rit[i].large_rxq_id = i;
+		}
+	}
+	spin_lock_irq(&bnad->priv_lock);
+	bna_rit_config_set(bnad->priv, BNAD_RIT_OFFSET, bnad->rit, size);
+	spin_unlock_irq(&bnad->priv_lock);
+}
+
+void
+bnad_alloc_for_rxq(struct bnad *bnad, uint rxq_id)
+{
+	struct bnad_rxq_info *rxqinfo = &bnad->rxq_table[rxq_id];
+	u16 rxbufs;
+
+	bnad_alloc_rxbufs(rxqinfo);
+	rxbufs = BNA_QE_IN_USE_CNT(&rxqinfo->skb_unmap_q,
+				   rxqinfo->skb_unmap_q.q_depth);
+}
+
+static int bnad_config_hw(struct bnad *bnad)
+{
+	int i, err = 0;
+	u64 rxq_id_mask = 0;
+	struct sockaddr sa;
+	struct net_device *netdev = bnad->netdev;
+
+	spin_lock_irq(&bnad->priv_lock);
+	if (BNAD_NOT_READY(bnad))
+		goto unlock_and_return;
+
+	/* Disable the RxF until later bringing port up. */
+	bna_multi_rxf_disable(bnad->priv, (1 << bnad->rxf_num) - 1);
+	for (i = 0; i < bnad->txq_num; i++) {
+		spin_unlock_irq(&bnad->priv_lock);
+		err = bnad_disable_txq(bnad, i);
+		spin_lock_irq(&bnad->priv_lock);
+		if (err || BNAD_NOT_READY(bnad))
+			goto unlock_and_return;
+	}
+	for (i = 0; i < bnad->rxq_num; i++)
+		rxq_id_mask |= (1 << i);
+	if (rxq_id_mask) {
+		spin_unlock_irq(&bnad->priv_lock);
+		err = bnad_disable_rxqs(bnad, rxq_id_mask);
+		spin_lock_irq(&bnad->priv_lock);
+		if (err || BNAD_NOT_READY(bnad))
+			goto unlock_and_return;
+	}
+	spin_unlock_irq(&bnad->priv_lock);
+
+	bnad_setup_queues(bnad);
+
+	bnad_setup_rit(bnad);
+
+	spin_lock_irq(&bnad->priv_lock);
+	bna_txf_config_set(bnad->priv, BNAD_TX_FUNC_ID,
+			   &bnad->txf_table->txf_config);
+	for (i = 0; i < bnad->rxf_num; i++) {
+		bna_rxf_config_set(bnad->priv, i,
+				   &bnad->rxf_table[i].rxf_config);
+		bna_rxf_vlan_filter(bnad->priv, i, BNA_ENABLE);
+	}
+
+	spin_unlock_irq(&bnad->priv_lock);
+	/* Mailbox should be enabled before this! */
+	memcpy(sa.sa_data, netdev->dev_addr, netdev->addr_len);
+	err = bnad_set_mac_address_locked(netdev, &sa);
+	spin_lock_irq(&bnad->priv_lock);
+	if (err || BNAD_NOT_READY(bnad))
+		goto unlock_and_return;
+
+	/* Receive broadcasts */
+	bna_rxf_broadcast(bnad->priv, BNAD_RX_FUNC_ID, BNA_ENABLE);
+
+	bna_mtu_info(bnad->priv, netdev->mtu, bnad);
+	bna_set_pause_config(bnad->priv, &bnad->pause_config, bnad);
+
+	bna_rxf_mcast_del_all(bnad->priv, BNAD_RX_FUNC_ID);
+	bna_mcast_mac_reset_list(bnad->priv);
+
+	bnad_set_rx_mode_locked(bnad->netdev);
+
+	bnad_reconfig_vlans(bnad);
+	spin_unlock_irq(&bnad->priv_lock);
+
+	bnad_setup_ibs(bnad);
+	return 0;
+
+unlock_and_return:
+	if (BNAD_NOT_READY(bnad))
+		err = BNA_FAIL;
+	spin_unlock_irq(&bnad->priv_lock);
+	return err;
+}
+
+/* Note: bnad_cleanup doesn't free irqs */
+static void bnad_cleanup(struct bnad *bnad)
+{
+
+	kfree(bnad->rit);
+	bnad->rit = NULL;
+
+	kfree(bnad->txf_table);
+	bnad->txf_table = NULL;
+
+	kfree(bnad->rxf_table);
+	bnad->rxf_table = NULL;
+
+	bnad_free_ibs(bnad);
+	bnad_free_queues(bnad);
+}
+
+/* Should be called with rtnl_lock held. */
+static int bnad_init(struct bnad *bnad)
+{
+	int err;
+
+	err = bnad_alloc_ibs(bnad);
+	if (err)
+		goto finished;
+
+	err = bnad_init_queues(bnad);
+	if (err)
+		goto finished;
+
+	bnad_ibs_init(bnad);
+
+	err = bnad_init_funcs(bnad);
+	if (err)
+		goto finished;
+
+	err = bnad_alloc_unmap_queues(bnad);
+	if (err)
+		goto finished;
+
+	bnad->rit =
+		kcalloc(bnad->cq_num, sizeof(struct bna_rit_entry),
+			GFP_KERNEL);
+	if (!bnad->rit)
+		goto finished;
+
+	return 0;
+
+finished:
+	bnad_cleanup(bnad);
+	return err;
+}
+
+static int bnad_enable_locked(struct bnad *bnad)
+{
+	struct net_device *netdev = bnad->netdev;
+	int err = 0;
+	uint i;
+
+	bnad->state = BNAD_S_OPENING;
+
+	err = bnad_init(bnad);
+	if (err) {
+		pr_info("%s init failed %d", netdev->name, err);
+		bnad->state = BNAD_S_INIT;
+		return err;
+	}
+
+	err = bnad_config_hw(bnad);
+	if (err) {
+		pr_info("%s config HW failed %d", netdev->name, err);
+		goto init_failed;
+	}
+
+	err = bnad_request_txrx_irqs(bnad);
+	if (err) {
+		pr_info("%s requests Tx/Rx irqs failed: %d",
+			bnad->netdev->name, err);
+		goto init_failed;
+	}
+	bnad_napi_init(bnad);
+	bnad_napi_enable(bnad);
+	for (i = 0; i < bnad->rxq_num; i++)
+		bnad_alloc_for_rxq(bnad, i);
+
+	bnad->state = BNAD_S_OPEN;
+	pr_info("%s is opened", bnad->netdev->name);
+
+	spin_lock_irq(&bnad->priv_lock);
+	if (BNAD_NOT_READY(bnad)) {
+		/* Let bnad_error take care of the error. */
+		spin_unlock_irq(&bnad->priv_lock);
+		return 0;
+	}
+
+	/* RxF was disabled earlier. */
+	bna_rxf_enable(bnad->priv, BNAD_RX_FUNC_ID);
+	spin_unlock_irq(&bnad->priv_lock);
+
+	return 0;
+
+init_failed:
+	bnad_cleanup(bnad);
+	bnad->state = BNAD_S_INIT;
+	return err;
+}
+
+/* Should be called with conf_lock held */
+static int
+bnad_open_locked_internal(struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	int err = 0;
+
+	switch (bnad->state) {
+	case BNAD_S_INIT:
+		err = bnad_enable_locked(bnad);
+		break;
+	case BNAD_S_INIT_DOWN:
+		bnad->state = BNAD_S_OPEN_DOWN;
+		pr_info("%s is not ready yet: IOC down", netdev->name);
+		break;
+	case BNAD_S_INIT_DISABLED:
+		bnad->state = BNAD_S_OPEN_DISABLED;
+		pr_info("%s is not ready yet: IOC disabled",
+			netdev->name);
+		break;
+	default:
+		BUG_ON(1);
+		break;
+	}
+	return err;
+}
+
+int
+bnad_open_locked(struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	int err;
+
+	err = bnad_open_locked_internal(netdev);
+
+	if (!err && (bnad->state == BNAD_S_OPEN))
+		bnad_port_admin_locked(bnad, BNA_ENABLE);
+
+	return err;
+}
+
+int
+bnad_open(struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	int err = 0;
+
+	pr_info("%s open", netdev->name);
+
+	mutex_lock(&bnad->conf_mutex);
+
+	if (test_bit(BNAD_F_BCU_DISABLED, &bnad->flags))
+		pr_info("%s is disabled", netdev->name);
+	 else
+		err = bnad_open_locked(netdev);
+
+	mutex_unlock(&bnad->conf_mutex);
+
+	return err;
+}
+
+static int bnad_disable_locked(struct bnad *bnad)
+{
+	int err = 0, i;
+	u64 rxq_id_mask = 0;
+
+	bnad_stop_data_path(bnad, 0);
+
+	for (i = 0; i < bnad->txq_num; i++) {
+		err = bnad_disable_txq(bnad, i);
+		if (err)
+			goto cleanup;
+	}
+
+	for (i = 0; i < bnad->rxq_num; i++)
+		rxq_id_mask |= (1 << i);
+	if (rxq_id_mask) {
+		err = bnad_disable_rxqs(bnad, rxq_id_mask);
+		if (err)
+			goto cleanup;
+	}
+
+cleanup:
+	bnad_cleanup(bnad);
+	return err;
+}
+
+int
+bnad_stop_locked(struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+
+	if (bnad->state == BNAD_S_OPEN)
+		bnad_port_admin_locked(bnad, BNA_DISABLE);
+
+	return bnad_stop_locked_internal(netdev);
+}
+
+int
+bnad_stop(struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	int err = 0;
+
+	pr_info("%s stop", netdev->name);
+
+	mutex_lock(&bnad->conf_mutex);
+
+	if (test_bit(BNAD_F_BCU_DISABLED, &bnad->flags))
+		pr_info("%s port is disabled", netdev->name);
+	 else
+		err = bnad_stop_locked(netdev);
+
+	mutex_unlock(&bnad->conf_mutex);
+
+	return err;
+}
+
+/* Should be called with conf_lock held. */
+int
+bnad_sw_reset_locked_internal(struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	int err;
+
+	err = bnad_stop_locked_internal(netdev);
+	if (err) {
+		pr_info("%s sw reset internal: stop failed %d",
+			bnad->netdev->name, err);
+		goto done;
+	}
+
+	err = bnad_open_locked_internal(netdev);
+
+	if (err) {
+		pr_info("%s sw reset internal: open failed %d",
+			bnad->netdev->name, err);
+		goto done;
+	}
+	return 0;
+done:
+	return err;
+}
+
+/* Should be called with conf_lock held. */
+int
+bnad_sw_reset_locked(struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	int err;
+
+	if (bnad->state != BNAD_S_OPEN)
+		return 0;
+
+	bnad_port_admin_locked(bnad, BNA_DISABLE);
+
+	err = bnad_sw_reset_locked_internal(netdev);
+
+	if (err) {
+		pr_info("%s sw reset: failed %d", bnad->netdev->name,
+			err);
+		return err;
+	}
+
+	/* After the reset, make sure we are in the OPEN state) */
+	if (bnad->state == BNAD_S_OPEN)
+		bnad_port_admin_locked(bnad, BNA_ENABLE);
+
+	return 0;
+}
+
+static int bnad_tso_prepare(struct bnad *bnad, struct sk_buff *skb)
+{
+	int err;
+
+	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->stats.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->stats.tso4++;
+	} else {
+		struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+
+		ipv6h->payload_len = 0;
+		tcp_hdr(skb)->check =
+			~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, 0,
+					 IPPROTO_TCP, 0);
+		bnad->stats.tso6++;
+	}
+
+	return 0;
+}
+
+netdev_tx_t
+bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	struct bnad_txq_info *txqinfo;
+	struct bna_txq *txq;
+	struct bnad_unmap_q *unmap_q;
+	u16 txq_prod, vlan_tag = 0;
+	unsigned int unmap_prod, wis, wis_used, wi_range;
+	unsigned int vectors, vect_id, i, acked;
+	int err;
+	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 > BNAD_TX_MAX_DATA_PER_WI)) {
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	txqinfo = &bnad->txq_table[0];
+	txq = &txqinfo->txq;
+	unmap_q = &txqinfo->skb_unmap_q;
+
+	vectors = 1 + skb_shinfo(skb)->nr_frags;
+	if (vectors > BNAD_TX_MAX_VECTORS) {
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+	wis = BNAD_TXQ_WI_NEEDED(vectors);	/* 4 vectors per work item */
+	acked = 0;
+	if (unlikely
+	    (wis > BNA_Q_FREE_COUNT(txq) ||
+	     vectors > BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth))) {
+		if ((u16) (*txqinfo->hw_consumer_index) !=
+		    txq->q.consumer_index &&
+		    !test_and_set_bit(BNAD_TXQ_FREE_SENT, &txqinfo->flags)) {
+			acked = bnad_free_txbufs(txqinfo,
+						 (u16)(*txqinfo->
+							    hw_consumer_index));
+			bna_ib_ack(bnad->priv, &txqinfo->ib, acked);
+
+			smp_mb__before_clear_bit();
+			clear_bit(BNAD_TXQ_FREE_SENT, &txqinfo->flags);
+		} else
+			netif_stop_queue(netdev);
+
+		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_Q_FREE_COUNT(txq) ||
+		     vectors > BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth))) {
+			bnad->stats.netif_queue_stop++;
+			return NETDEV_TX_BUSY;
+		} else
+			netif_wake_queue(netdev);
+	}
+
+	unmap_prod = unmap_q->producer_index;
+	wis_used = 1;
+	vect_id = 0;
+	flags = 0;
+
+	txq_prod = txq->q.producer_index;
+	BNA_TXQ_QPGE_PTR_GET(txq_prod, &txq->q, txqent, wi_range);
+	BUG_ON(!(wi_range && wi_range <= txq->q.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_ipid_mode)
+		flags |= BNA_TXQ_WI_CF_IPID_MODE;
+
+	if (bnad->vlangrp && 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_F_CEE_RUNNING, &bnad->flags)) {
+		vlan_tag =
+			(bnad->curr_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)) {
+			/* XXX the 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->stats.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->stats.udpcsum_offload++;
+			BUG_ON(!(skb_headlen(skb)) >=
+				   skb_transport_offset(skb) +
+				   sizeof(struct udphdr));
+		} else {
+			err = skb_checksum_help(skb);
+			bnad->stats.csum_help++;
+			if (err) {
+				dev_kfree_skb(skb);
+				bnad->stats.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) <= BNAD_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];
+
+		if (++vect_id == BNAD_TX_MAX_VECTORS_PER_WI) {
+			vect_id = 0;
+			if (--wi_range)
+				txqent++;
+			else {
+				BNA_QE_INDX_ADD(txq_prod, wis_used,
+						txq->q.q_depth);
+				wis_used = 0;
+				BNA_TXQ_QPGE_PTR_GET(txq_prod, &txq->q, txqent,
+						     wi_range);
+				BUG_ON(!(wi_range &&
+					   wi_range <= txq->q.q_depth));
+			}
+			wis_used++;
+			txqent->hdr.wi_ext.opcode = htons(BNA_TXQ_WI_EXTENSION);
+		}
+
+		txqent->vector[vect_id].length = htons(frag->size);
+		dma_addr =
+			pci_map_page(bnad->pcidev, frag->page,
+				     frag->page_offset, frag->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, txq->q.q_depth);
+	txq->q.producer_index = txq_prod;
+
+	smp_mb();
+	bna_txq_prod_indx_doorbell(txq);
+
+	if ((u16) (*txqinfo->hw_consumer_index) != txq->q.consumer_index)
+		tasklet_schedule(&bnad->tx_free_tasklet);
+
+	return NETDEV_TX_OK;
+}
+
+struct net_device_stats
+*bnad_get_stats(struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	struct net_device_stats *net_stats = &bnad->net_stats;
+	struct cna_stats_mac_rx *rxstats = &bnad->hw_stats->mac_rx_stats;
+	struct cna_stats_mac_tx *txstats = &bnad->hw_stats->mac_tx_stats;
+	int i;
+
+	memset(net_stats, 0, sizeof(*net_stats));
+	if (bnad->rxq_table) {
+		for (i = 0; i < bnad->rxq_num; i++) {
+			net_stats->rx_packets += bnad->rxq_table[i].rx_packets;
+			net_stats->rx_bytes += bnad->rxq_table[i].rx_bytes;
+		}
+	}
+	if (bnad->txq_table) {
+		for (i = 0; i < bnad->txq_num; i++) {
+			net_stats->tx_packets += bnad->txq_table[i].tx_packets;
+			net_stats->tx_bytes += bnad->txq_table[i].tx_bytes;
+		}
+	}
+	net_stats->rx_errors =
+		rxstats->rx_fcs_error + rxstats->rx_alignment_error +
+		rxstats->rx_frame_length_error + rxstats->rx_code_error +
+		rxstats->rx_undersize;
+	net_stats->tx_errors = txstats->tx_fcs_error + txstats->tx_undersize;
+	net_stats->rx_dropped = rxstats->rx_drop;
+	net_stats->tx_dropped = txstats->tx_drop;
+	net_stats->multicast = rxstats->rx_multicast;
+	net_stats->collisions = txstats->tx_total_collision;
+
+	net_stats->rx_length_errors = rxstats->rx_frame_length_error;
+	net_stats->rx_crc_errors = rxstats->rx_fcs_error;
+	net_stats->rx_frame_errors = rxstats->rx_alignment_error;
+	/* recv'r fifo overrun */
+	net_stats->rx_fifo_errors = bnad->hw_stats->rxf_stats[0].frame_drops;
+
+	return net_stats;
+}
+
+/* Should be called with priv_lock held. */
+static void bnad_set_rx_mode_locked(struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	int err;
+
+	if (netdev->flags & IFF_PROMISC) {
+		bna_rxf_promiscuous(bnad->priv, BNAD_RX_FUNC_ID, BNA_ENABLE);
+		bnad->config |= BNAD_CF_PROMISC;
+	} else {
+		bna_rxf_promiscuous(bnad->priv, BNAD_RX_FUNC_ID, BNA_DISABLE);
+		bnad->config &= ~BNAD_CF_PROMISC;
+	}
+
+	if (netdev->flags & IFF_ALLMULTI) {
+		if (!(bnad->config & BNAD_CF_ALLMULTI)) {
+			bna_rxf_mcast_filter(bnad->priv, BNAD_RX_FUNC_ID,
+					     BNA_DISABLE);
+			bnad->config |= BNAD_CF_ALLMULTI;
+		}
+	} else {
+		if (bnad->config & BNAD_CF_ALLMULTI) {
+			bna_rxf_mcast_filter(bnad->priv, BNAD_RX_FUNC_ID,
+					     BNA_ENABLE);
+			bnad->config &= ~BNAD_CF_ALLMULTI;
+		}
+	}
+
+	if (netdev->mc_count) {
+		struct mac *mcaddr_list;
+		struct dev_mc_list *mc;
+		int i;
+
+		mcaddr_list =
+			kcalloc((netdev->mc_count + 1), sizeof(struct mac),
+				GFP_ATOMIC);
+		if (!mcaddr_list)
+			return;
+
+		mcaddr_list[0] = bna_bcast_addr;
+
+		mc = netdev->mc_list;
+		for (i = 1; mc && i < netdev->mc_count + 1; i++, mc = mc->next)
+			memcpy(&mcaddr_list[i], mc->dmi_addr,
+				sizeof(struct mac));
+
+		err = bna_rxf_mcast_mac_set_list(bnad->priv, BNAD_RX_FUNC_ID,
+			(const struct mac *)mcaddr_list,
+				 netdev->mc_count + 1);
+
+		/* XXX Should we enable BNAD_CF_ALLMULTI for err != 0 ? */
+
+		kfree(mcaddr_list);
+	}
+}
+
+static void bnad_set_rx_mode(struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+
+	spin_lock_irq(&bnad->priv_lock);
+	bnad_set_rx_mode_locked(netdev);
+	spin_unlock_irq(&bnad->priv_lock);
+}
+
+/* Should be called with conf_lock held. */
+int bnad_ucast_mac(struct bnad *bnad, unsigned int rxf_id, u8 * mac_ptr,
+	unsigned int cmd)
+{
+	int err = 0;
+	enum bna_status(*ucast_mac_func) (struct bna_dev *bna_dev,
+		unsigned int rxf_id, const struct mac *mac_addr_ptr) = NULL;
+
+	WARN_ON(in_interrupt());
+	if (!is_valid_ether_addr(mac_ptr))
+		return -EINVAL;
+
+	switch (cmd) {
+	case BNAD_UCAST_MAC_SET:
+		ucast_mac_func = bna_rxf_ucast_mac_set;
+		break;
+	case BNAD_UCAST_MAC_ADD:
+		ucast_mac_func = bna_rxf_ucast_mac_add;
+		break;
+	case BNAD_UCAST_MAC_DEL:
+		ucast_mac_func = bna_rxf_ucast_mac_del;
+		break;
+	}
+
+	init_completion(&bnad->ucast_comp);
+	spin_lock_irq(&bnad->priv_lock);
+	err = ucast_mac_func(bnad->priv, rxf_id, (const struct mac *)mac_ptr);
+	spin_unlock_irq(&bnad->priv_lock);
+	if (err) {
+		if (err == BNA_AGAIN)
+			err = 0;
+		goto ucast_mac_exit;
+	}
+	wait_for_completion(&bnad->ucast_comp);
+	err = bnad->ucast_comp_status;
+	if (err == BFI_LL_CMD_NOT_EXEC)
+		err = 0;
+
+ucast_mac_exit:
+	if (err) {
+		pr_info("%s unicast MAC address command %d failed: %d",
+			bnad->netdev->name, cmd, err);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Should be called with conf_lock held. */
+static int bnad_set_mac_address_locked(struct net_device *netdev, void *addr)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	struct sockaddr *sa = (struct sockaddr *)addr;
+	int err;
+
+	if (!is_valid_ether_addr(sa->sa_data))
+		return -EADDRNOTAVAIL;
+
+	err = bnad_ucast_mac(bnad, BNAD_RX_FUNC_ID, (u8 *) sa->sa_data,
+			     BNAD_UCAST_MAC_SET);
+	if (err)
+		return err;
+
+	memcpy(netdev->dev_addr, sa->sa_data, netdev->addr_len);
+	return 0;
+}
+
+static int bnad_set_mac_address(struct net_device *netdev, void *addr)
+{
+	int err = 0;
+	struct bnad *bnad = netdev_priv(netdev);
+
+	mutex_lock(&bnad->conf_mutex);
+	err = bnad_set_mac_address_locked(netdev, addr);
+	mutex_unlock(&bnad->conf_mutex);
+	return err;
+
+}
+
+static int bnad_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	int err = 0;
+	struct bnad *bnad = netdev_priv(netdev);
+
+	WARN_ON(in_interrupt());
+
+	if (new_mtu + ETH_HLEN < ETH_ZLEN || new_mtu > BNAD_JUMBO_MTU)
+		return -EINVAL;
+
+	mutex_lock(&bnad->conf_mutex);
+	netdev->mtu = new_mtu;
+	err = bnad_sw_reset_locked(netdev);
+	mutex_unlock(&bnad->conf_mutex);
+
+	return err;
+}
+
+static void bnad_vlan_rx_register(struct net_device *netdev,
+	struct vlan_group *grp)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+
+	mutex_lock(&bnad->conf_mutex);
+	bnad->vlangrp = 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);
+
+	mutex_lock(&bnad->conf_mutex);
+	spin_lock_irq(&bnad->priv_lock);
+	if (bnad->state == BNAD_S_OPEN && !BNAD_NOT_READY(bnad))
+		bna_rxf_vlan_add(bnad->priv, BNAD_RX_FUNC_ID,
+				 (unsigned int)vid);
+	spin_unlock_irq(&bnad->priv_lock);
+	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);
+
+	mutex_lock(&bnad->conf_mutex);
+	spin_lock_irq(&bnad->priv_lock);
+	if (bnad->state == BNAD_S_OPEN && !BNAD_NOT_READY(bnad))
+		bna_rxf_vlan_del(bnad->priv, BNAD_RX_FUNC_ID,
+				 (unsigned int)vid);
+	spin_unlock_irq(&bnad->priv_lock);
+	mutex_unlock(&bnad->conf_mutex);
+}
+
+/* Should be called with priv_lock held. */
+static void bnad_reconfig_vlans(struct bnad *bnad)
+{
+	u16 vlan_id;
+
+	bna_rxf_vlan_del_all(bnad->priv, BNAD_RX_FUNC_ID);
+	if (bnad->vlangrp) {
+		for (vlan_id = 0; vlan_id < VLAN_GROUP_ARRAY_LEN; vlan_id++) {
+			if (vlan_group_get_device(bnad->vlangrp, vlan_id))
+				bna_rxf_vlan_add(bnad->priv, BNAD_RX_FUNC_ID,
+						 (unsigned int)vlan_id);
+		}
+	}
+}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void bnad_netpoll(struct net_device *netdev)
+{
+	struct bnad *bnad = netdev_priv(netdev);
+	struct bnad_cq_info *cqinfo;
+	int i;
+
+	if (!(bnad->config & BNAD_CF_MSIX)) {
+		disable_irq(bnad->pcidev->irq);
+		bnad_isr(bnad->pcidev->irq, netdev);
+		enable_irq(bnad->pcidev->irq);
+	} else {
+		for (i = 0; i < bnad->cq_num; i++) {
+			cqinfo = &bnad->cq_table[i];
+			if (likely(napi_schedule_prep(&cqinfo->napi))) {
+				bnad_disable_rx_irq(bnad, cqinfo);
+				__napi_schedule(&cqinfo->napi);
+			}
+		}
+	}
+}
+#endif
+
+static void bnad_q_num_init(struct bnad *bnad, uint rxqsets)
+{
+	bnad->txq_num = BNAD_TXQ_NUM;
+	bnad->txf_num = 1;
+
+	if (bnad->config & BNAD_CF_MSIX) {
+		if (rxqsets) {
+			bnad->cq_num = rxqsets;
+			if (bnad->cq_num > BNAD_MAX_CQS)
+				bnad->cq_num = BNAD_MAX_CQS;
+		} else
+			bnad->cq_num =
+				min((uint) num_online_cpus(),
+				    (uint) BNAD_MAX_RXQSETS_USED);
+		/* VMware does not use RSS like Linux driver */
+		if (!BNA_POWER_OF_2(bnad->cq_num))
+			BNA_TO_POWER_OF_2(bnad->cq_num);
+		bnad->rxq_num = bnad->cq_num * bnad_rxqs_per_cq;
+
+		bnad->rxf_num = 1;
+		bnad->msix_num =
+			bnad->txq_num + bnad->cq_num +
+			BNAD_MSIX_ERR_MAILBOX_NUM;
+	} else {
+		bnad->cq_num = 1;
+		bnad->rxq_num = bnad->cq_num * bnad_rxqs_per_cq;
+		bnad->rxf_num = 1;
+		bnad->msix_num = 0;
+	}
+}
+
+static void bnad_enable_msix(struct bnad *bnad)
+{
+	int i, ret;
+
+	if (!(bnad->config & BNAD_CF_MSIX) || bnad->msix_table)
+		return;
+
+	bnad->msix_table =
+		kcalloc(bnad->msix_num, sizeof(struct msix_entry), GFP_KERNEL);
+	if (!bnad->msix_table)
+		goto intx_mode;
+
+	for (i = 0; i < bnad->msix_num; i++)
+		bnad->msix_table[i].entry = i;
+
+	ret = pci_enable_msix(bnad->pcidev, bnad->msix_table, bnad->msix_num);
+	if (ret > 0) {
+		/* Not enough MSI-X vectors. */
+		int rxqsets = ret;
+
+		dev_err(&bnad->pcidev->dev,
+			"Tried to get %d MSI-X vectors, only got %d\n",
+			bnad->msix_num, ret);
+		BNA_TO_POWER_OF_2(rxqsets);
+		while (bnad->msix_num > ret && rxqsets) {
+			bnad_q_num_init(bnad, rxqsets);
+			rxqsets >>= 1;
+		}
+		if (bnad->msix_num <= ret) {
+			ret = pci_enable_msix(bnad->pcidev, bnad->msix_table,
+					      bnad->msix_num);
+			if (ret) {
+				dev_err(&bnad->pcidev->dev,
+					"Enabling MSI-X failed: %d\n", ret);
+				goto intx_mode;
+			}
+		} else {
+			dev_err(&bnad->pcidev->dev,
+				"Enabling MSI-X failed: limited (%d) vectors\n",
+				ret);
+			goto intx_mode;
+		}
+	} else if (ret < 0) {
+		dev_err(&bnad->pcidev->dev, "Enabling MSI-X failed: %d\n", ret);
+		goto intx_mode;
+	}
+
+	dev_info(&bnad->pcidev->dev,
+		 "Enabling MSI-X succeeded with %d vectors, %s\n",
+		 bnad->msix_num,
+		 (bnad->cq_num > 1) ? "RSS is enabled" : "RSS is not enabled");
+	return;
+
+intx_mode:
+	dev_warn(&bnad->pcidev->dev, "Switching to INTx mode with no RSS\n");
+
+	kfree(bnad->msix_table);
+	bnad->msix_table = NULL;
+
+	bnad->config &= ~BNAD_CF_MSIX;
+	bnad_q_num_init(bnad, 0);
+}
+
+static void bnad_disable_msix(struct bnad *bnad)
+{
+	if (bnad->config & BNAD_CF_MSIX) {
+		pci_disable_msix(bnad->pcidev);
+		kfree(bnad->msix_table);
+		bnad->msix_table = NULL;
+		bnad->config &= ~BNAD_CF_MSIX;
+	}
+}
+
+static void bnad_error(struct bnad *bnad)
+{
+
+	spin_lock_irq(&bnad->priv_lock);
+
+	if (!test_and_clear_bit(BNAD_F_HWERROR, &bnad->flags)) {
+		spin_unlock_irq(&bnad->priv_lock);
+		return;
+	}
+	spin_unlock_irq(&bnad->priv_lock);
+
+	switch (bnad->state) {
+	case BNAD_S_INIT:
+		bnad->state = BNAD_S_INIT_DOWN;
+		break;
+	case BNAD_S_OPEN:
+		bnad->state = BNAD_S_OPEN_DOWN;
+		bnad_stop_data_path(bnad, 1);
+		bnad_cleanup(bnad);
+		break;
+	case BNAD_S_START:
+	case BNAD_S_INIT_DISABLING:
+	case BNAD_S_OPENING:
+	case BNAD_S_OPEN_DISABLING:
+	case BNAD_S_CLOSING:
+		BUG_ON(1);
+		/* fall through */
+	default:
+		break;
+	}
+}
+
+static void bnad_resume_after_reset(struct bnad *bnad)
+{
+	int err;
+	struct net_device *netdev = bnad->netdev;
+
+	switch (bnad->state) {
+	case BNAD_S_INIT_DOWN:
+		bnad->state = BNAD_S_INIT;
+
+		bna_port_mac_get(bnad->priv, (struct mac *)netdev->perm_addr);
+		if (is_zero_ether_addr(netdev->dev_addr))
+			memcpy(netdev->dev_addr, netdev->perm_addr,
+			       netdev->addr_len);
+		break;
+	case BNAD_S_OPEN_DOWN:
+		err = bnad_enable_locked(bnad);
+		if (err) {
+			pr_info(
+				"%s bnad_enable failed after reset: %d",
+				bnad->netdev->name, err);
+		} else {
+			bnad_port_admin_locked(bnad, BNA_ENABLE);
+		}
+		break;
+	case BNAD_S_START:
+	case BNAD_S_INIT_DISABLING:
+	case BNAD_S_OPENING:
+	case BNAD_S_OPEN:
+	case BNAD_S_OPEN_DISABLING:
+	case BNAD_S_CLOSING:
+		BUG_ON(1);
+		/* fall through */
+	default:
+		break;
+	}
+
+}
+
+static void bnad_tx_free_tasklet(unsigned long bnad_ptr)
+{
+	struct bnad *bnad = (struct bnad *)bnad_ptr;
+	struct bnad_txq_info *txqinfo;
+	struct bna_txq *txq;
+	unsigned int acked;
+
+	txqinfo = &bnad->txq_table[0];
+	txq = &txqinfo->txq;
+
+	if ((u16) (*txqinfo->hw_consumer_index) != txq->q.consumer_index &&
+	    !test_and_set_bit(BNAD_TXQ_FREE_SENT, &txqinfo->flags)) {
+		acked = bnad_free_txbufs(txqinfo,
+					 (u16) (*txqinfo->
+						     hw_consumer_index));
+		bna_ib_ack(bnad->priv, &txqinfo->ib, acked);
+		smp_mb__before_clear_bit();
+		clear_bit(BNAD_TXQ_FREE_SENT, &txqinfo->flags);
+	}
+}
+
+static void bnad_cee_reconfig_prio(struct bnad *bnad, u8 cee_linkup,
+	unsigned int prio)
+{
+
+	if (prio != bnad->curr_priority)
+		bnad_sw_reset_locked_internal(bnad->netdev);
+	 else {
+		spin_lock_irq(&bnad->priv_lock);
+		if (!cee_linkup)
+			clear_bit(BNAD_F_CEE_RUNNING, &bnad->flags);
+		else
+			set_bit(BNAD_F_CEE_RUNNING, &bnad->flags);
+		spin_unlock_irq(&bnad->priv_lock);
+	}
+}
+
+static void bnad_link_state_notify(struct bnad *bnad)
+{
+	struct net_device *netdev = bnad->netdev;
+	enum bnad_link_state link_state;
+	u8 cee_linkup;
+	unsigned int prio = 0;
+
+	if (bnad->state != BNAD_S_OPEN) {
+		pr_info("%s link up in state %d", netdev->name,
+			bnad->state);
+		return;
+	}
+
+	spin_lock_irq(&bnad->priv_lock);
+	link_state = bnad->link_state;
+	cee_linkup = bnad->cee_linkup;
+	if (cee_linkup)
+		prio = bnad->priority;
+	spin_unlock_irq(&bnad->priv_lock);
+
+	if (link_state == BNAD_LS_UP) {
+		bnad_cee_reconfig_prio(bnad, cee_linkup, prio);
+		if (!netif_carrier_ok(netdev)) {
+			netif_carrier_on(netdev);
+			netif_wake_queue(netdev);
+			bnad->stats.netif_queue_wakeup++;
+		}
+	} else {
+		if (netif_carrier_ok(netdev)) {
+			netif_carrier_off(netdev);
+			bnad->stats.netif_queue_stop++;
+		}
+	}
+}
+
+static void bnad_work(struct work_struct *work)
+{
+	struct bnad *bnad = container_of(work, struct bnad, work);
+	unsigned long work_flags;
+
+	mutex_lock(&bnad->conf_mutex);
+
+	spin_lock_irq(&bnad->priv_lock);
+	work_flags = bnad->work_flags;
+	bnad->work_flags = 0;
+	spin_unlock_irq(&bnad->priv_lock);
+
+	if (work_flags & BNAD_WF_ERROR)
+		bnad_error(bnad);
+	if (work_flags & BNAD_WF_RESETDONE)
+		bnad_resume_after_reset(bnad);
+
+	if (work_flags & BNAD_WF_LS_NOTIFY)
+		bnad_link_state_notify(bnad);
+
+	mutex_unlock(&bnad->conf_mutex);
+}
+
+static void bnad_stats_timeo(unsigned long data)
+{
+	struct bnad *bnad = (struct bnad *)data;
+	int i;
+	struct bnad_rxq_info *rxqinfo;
+
+	spin_lock_irq(&bnad->priv_lock);
+	bna_stats_get(bnad->priv);
+	spin_unlock_irq(&bnad->priv_lock);
+
+	if (bnad->rx_dyn_coalesce_on) {
+		u8 cls_timer;
+		struct bnad_cq_info *cq;
+		for (i = 0; i < bnad->cq_num; i++) {
+			cq = &bnad->cq_table[i];
+
+			if ((cq->pkt_rate.small_pkt_cnt == 0) &&
+			    (cq->pkt_rate.large_pkt_cnt == 0))
+				continue;
+
+			cls_timer =
+				bna_calc_coalescing_timer(bnad->priv,
+							  &cq->pkt_rate);
+
+			/* For NAPI version, coalescing timer need to stored */
+			cq->rx_coalescing_timeo = cls_timer;
+
+			bna_ib_coalescing_timer_set(bnad->priv, &cq->ib,
+						    cls_timer);
+		}
+	}
+
+	for (i = 0; i < bnad->rxq_num; i++) {
+		rxqinfo = &bnad->rxq_table[i];
+		if (!
+		    (BNA_QE_IN_USE_CNT
+		     (&rxqinfo->skb_unmap_q,
+		      rxqinfo->skb_unmap_q.
+		      q_depth) >> BNAD_RXQ_REFILL_THRESHOLD_SHIFT)) {
+			if (test_and_set_bit(BNAD_RXQ_REFILL, &rxqinfo->flags))
+				continue;
+			bnad_alloc_rxbufs(rxqinfo);
+			smp_mb__before_clear_bit();
+			clear_bit(BNAD_RXQ_REFILL, &rxqinfo->flags);
+		}
+	}
+}
+
+static void
+bnad_free_ioc_mem(struct bnad *bnad)
+{
+	enum bna_dma_mem_type i;
+
+	for (i = 0; i < BNA_MEM_T_MAX; i++) {
+		if (!bnad->ioc_meminfo[i].len)
+			continue;
+		if (bnad->ioc_meminfo[i].kva && bnad->ioc_meminfo[i].dma)
+			pci_free_consistent(bnad->pcidev,
+					    bnad->ioc_meminfo[i].len,
+					    bnad->ioc_meminfo[i].kva,
+					    *(dma_addr_t *) &bnad->
+					    ioc_meminfo[i].dma);
+		else if (bnad->ioc_meminfo[i].kva)
+			vfree(bnad->ioc_meminfo[i].kva);
+		bnad->ioc_meminfo[i].kva = NULL;
+	}
+}
+
+/* The following IOC callback functions are called with priv_lock held. */
+
+void
+bna_iocll_enable_cbfn(void *arg, enum bfa_status error)
+{
+	struct bnad *bnad = arg;
+
+	if (!error) {
+		bnad->work_flags &= ~BNAD_WF_LS_NOTIFY;
+		bnad->work_flags |= BNAD_WF_RESETDONE;
+
+		if (bnad->state != BNAD_S_UNLOADING)
+			schedule_work(&bnad->work);
+	}
+
+	bnad->ioc_comp_status = error;
+	complete(&bnad->ioc_comp);
+}
+
+void
+bna_iocll_disable_cbfn(void *arg)
+{
+	struct bnad *bnad = arg;
+
+	complete(&bnad->ioc_comp);
+}
+
+void
+bna_iocll_hbfail_cbfn(void *arg)
+{
+	struct bnad *bnad = arg;
+
+	bnad_hw_error(bnad, BFA_STATUS_IOC_FAILURE);
+}
+
+void
+bna_iocll_reset_cbfn(void *arg)
+{
+	struct bnad *bnad = arg;
+	u32 int_status, int_mask;
+	unsigned int irq;
+
+	/* Clear the status */
+	bna_intr_status_get(bnad->priv, &int_status);
+
+	if (bnad->config & BNAD_CF_MSIX) {
+		if (test_and_clear_bit(BNAD_F_MBOX_IRQ_DISABLED,
+		    &bnad->flags)) {
+			irq = bnad->msix_table[bnad->msix_num - 1].vector;
+			enable_irq(irq);
+		}
+	}
+
+	int_mask = ~(__LPU2HOST_MBOX_MASK_BITS | __ERROR_MASK_BITS);
+	bna_intx_enable(bnad->priv, int_mask);
+}
+
+s32
+bnad_cee_attach(struct bnad *bnad)
+{
+	u8 *dma_kva;
+	dma_addr_t dma_pa;
+	struct bfa_cee *cee = &bnad->cee;
+
+	memset(cee, 0, sizeof(struct bfa_cee));
+
+	/* Allocate memory for dma */
+	dma_kva =
+		pci_alloc_consistent(bnad->pcidev, bfa_cee_meminfo(), &dma_pa);
+	if (dma_kva == NULL)
+		return -ENOMEM;
+
+	/* Ugly... need to remove once CAL is fixed. */
+	((struct bna_dev *) bnad->priv)->cee = cee;
+
+	bnad->cee_cbfn.get_attr_cbfn = bnad_cee_get_attr_cb;
+	bnad->cee_cbfn.get_stats_cbfn = bnad_cee_get_stats_cb;
+	bnad->cee_cbfn.reset_stats_cbfn = bnad_cee_reset_stats_cb;
+	bnad->cee_cbfn.reset_stats_cbfn = NULL;
+
+	/* Invoke cee attach function */
+	bfa_cee_attach(cee, &bnad->priv->ioc, bnad, bnad->trcmod, bnad->logmod);
+	bfa_cee_mem_claim(cee, dma_kva, dma_pa);
+	return 0;
+}
+
+static void bnad_cee_detach(struct bnad *bnad)
+{
+	struct bfa_cee *cee = &bnad->cee;
+
+	if (cee->attr_dma.kva) {
+		pci_free_consistent(bnad->pcidev, bfa_cee_meminfo(),
+				    cee->attr_dma.kva, cee->attr_dma.pa);
+	}
+}
+
+static int bnad_priv_init(struct bnad *bnad)
+{
+	dma_addr_t dma_addr;
+	struct bna_dma_addr bna_dma_addr;
+	int err = 0, i;
+	struct bfa_pcidev pcidev_info;
+	u32 intr_mask;
+
+	if (bnad_msix)
+		bnad->config |= BNAD_CF_MSIX;
+	bnad_q_num_init(bnad, bnad_rxqsets_used);
+
+	bnad->work_flags = 0;
+	INIT_WORK(&bnad->work, bnad_work);
+
+	tasklet_init(&bnad->tx_free_tasklet, bnad_tx_free_tasklet,
+		     (unsigned long)bnad);
+
+	setup_timer(&bnad->stats_timer, bnad_stats_timeo,
+		    (unsigned long)bnad);
+
+	bnad->tx_coalescing_timeo = BNAD_TX_COALESCING_TIMEO;
+	bnad->tx_interpkt_count = BNAD_TX_INTERPKT_COUNT;
+
+	bnad->rx_coalescing_timeo = BNAD_RX_COALESCING_TIMEO;
+	bnad->rx_interpkt_count = BNAD_RX_INTERPKT_COUNT;
+	bnad->rx_interpkt_timeo = BNAD_RX_INTERPKT_TIMEO;
+
+	bnad->rx_dyn_coalesce_on = true;
+
+	bnad->rx_csum = 1;
+	bnad->pause_config.tx_pause = 0;
+	bnad->pause_config.rx_pause = 0;
+
+	/* XXX could be vmalloc? */
+	bnad->trcmod = kzalloc(sizeof(struct bfa_trc_mod), GFP_KERNEL);
+	if (!bnad->trcmod) {
+		printk(KERN_ERR "port %u failed allocating trace buffer!\n",
+		       bnad->bna_id);
+		return -ENOMEM;
+	}
+
+	bfa_trc_init(bnad->trcmod);
+
+	bnad->logmod = NULL;
+
+	bnad->priv = kzalloc(bna_get_handle_size(), GFP_KERNEL);
+	if (!bnad->priv) {
+		printk(KERN_ERR "port %u failed allocating memory for bna\n",
+		       bnad->bna_id);
+		err = -ENOMEM;
+		goto free_trcmod;
+	}
+	bnad->priv_stats =
+		pci_alloc_consistent(bnad->pcidev, BNA_HW_STATS_SIZE,
+				     &dma_addr);
+	if (!bnad->priv_stats) {
+		printk(KERN_ERR
+		       "port %u failed allocating memory for bna stats\n",
+		       bnad->bna_id);
+		err = -ENOMEM;
+		goto free_priv_mem;
+	}
+	pci_unmap_addr_set(bnad, priv_stats_dma, dma_addr);
+
+	BNA_SET_DMA_ADDR(dma_addr, &bna_dma_addr);
+	bna_init(bnad->priv, (void *)bnad->bar0, bnad->priv_stats, bna_dma_addr,
+		 bnad->trcmod, bnad->logmod);
+	bna_all_stats_get(bnad->priv, &bnad->hw_stats);
+
+	spin_lock_init(&bnad->priv_lock);
+	mutex_init(&bnad->conf_mutex);
+	bnad->priv_cbfn.ucast_set_cb = bnad_ucast_set_cb;
+	bnad->priv_cbfn.txq_stop_cb = bnad_q_stop_cb;
+	bnad->priv_cbfn.rxq_stop_cb = bnad_q_stop_cb;
+	bnad->priv_cbfn.link_up_cb = bnad_link_up_cb;
+	bnad->priv_cbfn.link_down_cb = bnad_link_down_cb;
+	bnad->priv_cbfn.stats_get_cb = bnad_stats_get_cb;
+	bnad->priv_cbfn.hw_error_cb = bnad_hw_error_cb;
+	bnad->priv_cbfn.lldp_get_cfg_cb = bnad_lldp_get_cfg_cb;
+
+	bna_register_callback(bnad->priv, &bnad->priv_cbfn, bnad);
+
+	bna_iocll_meminfo(bnad->priv, bnad->ioc_meminfo);
+	for (i = 0; i < BNA_MEM_T_MAX; i++) {
+		if (!bnad->ioc_meminfo[i].len)
+			continue;
+		switch (i) {
+		case BNA_KVA_MEM_T_FWTRC:
+			bnad->ioc_meminfo[i].kva =
+				vmalloc(bnad->ioc_meminfo[i].len);
+			break;
+		default:
+			bnad->ioc_meminfo[i].kva =
+				pci_alloc_consistent(bnad->pcidev,
+						     bnad->ioc_meminfo[i].len,
+						     (dma_addr_t *) &bnad->
+						     ioc_meminfo[i].dma);
+
+			break;
+		}
+		if (!bnad->ioc_meminfo[i].kva) {
+			printk(KERN_ERR
+			       "port %u failed allocating %u "
+			       "bytes memory for IOC\n",
+			       bnad->bna_id, bnad->ioc_meminfo[i].len);
+			err = -ENOMEM;
+			goto free_ioc_mem;
+		} else
+			memset(bnad->ioc_meminfo[i].kva, 0,
+			       bnad->ioc_meminfo[i].len);
+	}
+
+	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;
+	bna_iocll_attach(bnad->priv, bnad, bnad->ioc_meminfo, &pcidev_info,
+			 bnad->trcmod, NULL, bnad->logmod);
+
+	err = bnad_cee_attach(bnad);
+	if (err) {
+		printk(KERN_ERR "port %u cee_attach failed: %d\n", bnad->bna_id,
+		       err);
+		goto iocll_detach;
+	}
+
+	if (bnad->config & BNAD_CF_MSIX)
+		bnad_enable_msix(bnad);
+	else
+		dev_info(&bnad->pcidev->dev, "Working in INTx mode, no RSS\n");
+	bna_intx_disable(bnad->priv, &intr_mask);
+	err = bnad_request_mbox_irq(bnad);
+	if (err)
+		goto disable_msix;
+
+
+	mutex_lock(&bnad->conf_mutex);
+	bnad->state = BNAD_S_START;
+
+	init_completion(&bnad->ioc_comp);
+	spin_lock_irq(&bnad->priv_lock);
+	bna_iocll_enable(bnad->priv);
+	spin_unlock_irq(&bnad->priv_lock);
+
+	wait_for_completion(&bnad->ioc_comp);
+
+	if (!bnad->ioc_comp_status) {
+		bnad->state = BNAD_S_INIT;
+		bna_port_mac_get(bnad->priv,
+		(struct mac *)bnad->netdev->perm_addr);
+	} else {
+		bnad->state = BNAD_S_INIT_DOWN;
+	}
+	mutex_unlock(&bnad->conf_mutex);
+
+	return 0;
+
+disable_msix:
+	bnad_disable_msix(bnad);
+	bnad_cee_detach(bnad);
+iocll_detach:
+	bna_iocll_detach(bnad->priv);
+free_ioc_mem:
+	bnad_free_ioc_mem(bnad);
+	pci_free_consistent(bnad->pcidev, BNA_HW_STATS_SIZE, bnad->priv_stats,
+			    pci_unmap_addr(bnad, priv_stats_dma));
+	bnad->priv_stats = NULL;
+free_priv_mem:
+	kfree(bnad->priv);
+	bnad->priv = NULL;
+free_trcmod:
+	kfree(bnad->trcmod);
+	bnad->trcmod = NULL;
+
+	return err;
+}
+
+static void bnad_priv_uninit(struct bnad *bnad)
+{
+	int i;
+	enum bna_status err;
+
+	if (bnad->priv) {
+
+		init_completion(&bnad->ioc_comp);
+
+		for (i = 0; i < 10; i++) {
+			spin_lock_irq(&bnad->priv_lock);
+			err = bna_iocll_disable(bnad->priv);
+			spin_unlock_irq(&bnad->priv_lock);
+			if (!err)
+				break;
+			msleep(1000);
+		}
+		if (err) {
+			/* Probably firmware crashed. */
+			pr_info(
+				"bna_iocll_disable failed, "
+				"clean up and try again");
+			spin_lock_irq(&bnad->priv_lock);
+			bna_cleanup(bnad->priv);
+			err = bna_iocll_disable(bnad->priv);
+			spin_unlock_irq(&bnad->priv_lock);
+		}
+		wait_for_completion(&bnad->ioc_comp);
+
+		pr_info("port %u IOC is disabled", bnad->bna_id);
+
+		bnad->state = BNAD_S_UNLOADING;
+
+		del_timer_sync(&bnad->priv->ioc.ioc_timer);
+		del_timer_sync(&bnad->priv->ioc.hb_timer);
+		del_timer_sync(&bnad->priv->ioc.sem_timer);
+
+		bnad_free_ioc_mem(bnad);
+		bna_iocll_detach(bnad->priv);
+
+		mutex_destroy(&bnad->conf_mutex);
+
+		flush_scheduled_work();
+		bnad_free_mbox_irq(bnad);
+
+		bnad_disable_msix(bnad);
+
+		if (bnad->priv_stats) {
+			pci_free_consistent(bnad->pcidev, BNA_HW_STATS_SIZE,
+					    bnad->priv_stats,
+					    pci_unmap_addr(bnad,
+							   priv_stats_dma));
+			bnad->priv_stats = NULL;
+		}
+		kfree(bnad->priv);
+		bnad->priv = NULL;
+	}
+	kfree(bnad->trcmod);
+	bnad->trcmod = NULL;
+}
+
+DEFINE_PCI_DEVICE_TABLE(bnad_pci_id_table) = { 
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_BROCADE, 
+			PCI_DEVICE_ID_BROCADE_CATAPULT),
+		.class = PCI_CLASS_NETWORK_ETHERNET << 8,
+		.class_mask =  0xffff00
+	}, {0,  }
+};
+
+MODULE_DEVICE_TABLE(pci, bnad_pci_id_table);
+
+static int __devinit bnad_pci_probe(struct pci_dev *pdev,
+	const struct pci_device_id *pcidev_id)
+{
+	int err, using_dac;
+	struct net_device *netdev;
+	struct bnad *bnad;
+	unsigned long mmio_start, mmio_len;
+	static u32 bna_id;
+
+	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 (!bfad_get_firmware_buf(pdev)) { /* Returns image */
+		mutex_unlock(&bnad_fwimg_mutex);
+		printk(KERN_WARNING "Failed to load Firmware Image!\n");
+		return -ENODEV;
+	}
+	mutex_unlock(&bnad_fwimg_mutex);
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		dev_err(&pdev->dev, "pci_enable_device failed: %d\n", err);
+		return err;
+	}
+
+	err = pci_request_regions(pdev, BNAD_NAME);
+	if (err) {
+		dev_err(&pdev->dev, "pci_request_regions failed: %d\n", 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) {
+				dev_err(&pdev->dev,
+					"set 32bit consistent DMA mask failed: "
+					"%d\n", err);
+				goto release_regions;
+			}
+		}
+		using_dac = 0;
+	}
+
+	pci_set_master(pdev);
+
+	netdev = alloc_etherdev(sizeof(struct bnad));
+	if (!netdev) {
+		dev_err(&pdev->dev, "alloc_etherdev failed\n");
+		err = -ENOMEM;
+		goto release_regions;
+	}
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+	pci_set_drvdata(pdev, netdev);
+
+	bnad = netdev_priv(netdev);
+
+	bnad->netdev = netdev;
+	bnad->pcidev = pdev;
+	mmio_start = pci_resource_start(pdev, 0);
+	mmio_len = pci_resource_len(pdev, 0);
+	bnad->bar0 = ioremap_nocache(mmio_start, mmio_len);
+	if (!bnad->bar0) {
+		dev_err(&pdev->dev, "ioremap for bar0 failed\n");
+		err = -ENOMEM;
+		goto free_devices;
+	}
+	printk(KERN_INFO "bar0 mapped to %p, len %lu\n", bnad->bar0, mmio_len);
+
+	netdev->netdev_ops = &bnad_netdev_ops;
+
+	netdev->features = NETIF_F_SG | NETIF_F_IP_CSUM;
+	netdev->features |= NETIF_F_IPV6_CSUM;
+	netdev->features |= NETIF_F_TSO;
+	netdev->features |= NETIF_F_TSO6;
+
+	netdev->vlan_features = netdev->features;
+	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->mem_start = mmio_start;
+	netdev->mem_end = mmio_start + mmio_len - 1;
+
+	bnad_set_ethtool_ops(netdev);
+
+	bnad->bna_id = bna_id;
+	err = bnad_priv_init(bnad);
+	if (err) {
+		printk(KERN_ERR "port %u init failed: %d\n", bnad->bna_id, err);
+		goto unmap_bar0;
+	}
+
+	memcpy(netdev->dev_addr, netdev->perm_addr, netdev->addr_len);
+
+	netif_carrier_off(netdev);
+	err = register_netdev(netdev);
+	if (err) {
+		printk(KERN_ERR "port %u register_netdev failed: %d\n",
+		       bnad->bna_id, err);
+		goto bnad_device_uninit;
+	}
+	bna_id++;
+	return 0;
+
+bnad_device_uninit:
+	bnad_priv_uninit(bnad);
+unmap_bar0:
+	iounmap(bnad->bar0);
+free_devices:
+	pci_set_drvdata(pdev, NULL);
+	free_netdev(netdev);
+release_regions:
+	pci_release_regions(pdev);
+disable_device:
+	pci_disable_device(pdev);
+
+	return err;
+}
+
+static void __devexit bnad_pci_remove(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct bnad *bnad;
+
+	if (!netdev)
+		return;
+
+	printk(KERN_INFO "%s bnad_pci_remove\n", netdev->name);
+	bnad = netdev_priv(netdev);
+
+	unregister_netdev(netdev);
+
+	bnad_priv_uninit(bnad);
+	iounmap(bnad->bar0);
+	pci_set_drvdata(pdev, NULL);
+	free_netdev(netdev);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+}
+
+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)
+{
+
+	printk(KERN_INFO "Brocade 10G Ethernet driver\n");
+
+	bfa_ioc_auto_recover(bnad_ioc_auto_recover);
+
+	return pci_register_driver(&bnad_pci_driver);
+}
+
+static void __exit bnad_module_exit(void)
+{
+	pci_unregister_driver(&bnad_pci_driver);
+
+	if (bfi_image_ct_size && bfi_image_ct)
+		vfree(bfi_image_ct);
+}
+
+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);
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/bnad.h net-next-2.6.33-rc5-mod/drivers/net/bna/bnad.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/bnad.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/bnad.h	2010-02-12 01:39:40.261979000 -0800
@@ -0,0 +1,343 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef _BNAD_H_
+#define _BNAD_H_
+
+#include "cee/bfa_cee.h"
+#include "bna.h"
+
+#define BNAD_MAX_Q_DEPTH	0x10000
+#define BNAD_MIN_Q_DEPTH	0x200
+
+#define BNAD_TXQ_NUM		1
+#define BNAD_TX_FUNC_ID		0
+#define BNAD_ENTRIES_PER_TXQ	2048
+
+#define BNAD_MAX_RXQS		64
+#define BNAD_MAX_RXQSETS_USED	16
+#define BNAD_RX_FUNC_ID		0
+#define BNAD_ENTRIES_PER_RXQ	2048
+
+#define BNAD_MAX_CQS		64
+#define BNAD_MAX_RXQS_PER_CQ	2
+
+#define BNAD_MSIX_ERR_MAILBOX_NUM	1
+
+#define BNAD_INTX_MAX_IB_NUM	16
+#define BNAD_INTX_IB_NUM	2	/* 1 for Tx, 1 for Rx */
+#define BNAD_INTX_TX_IB_ID	0
+#define BNAD_INTX_RX_IB_ID	1
+
+#define BNAD_QUEUE_NAME_SIZE	16
+
+#define BNAD_JUMBO_MTU		9000
+
+#define BNAD_COALESCING_TIMER_UNIT	5	/* 5us */
+#define BNAD_MAX_COALESCING_TIMEO	0xFF	/* in 5us units */
+#define BNAD_MAX_INTERPKT_COUNT		0xFF
+#define BNAD_MAX_INTERPKT_TIMEO		0xF	/* in 0.5us units */
+
+#define BNAD_TX_COALESCING_TIMEO	20	/* 20 * 5 = 100us */
+#define BNAD_TX_INTERPKT_COUNT		32
+
+#define BNAD_RX_COALESCING_TIMEO	12	/* 12 * 5 = 60us */
+#define BNAD_RX_INTERPKT_COUNT		6
+#define BNAD_RX_INTERPKT_TIMEO		3	/* 3 * 0.5 = 1.5us */
+
+#define BNAD_SMALL_RXBUF_SIZE	128
+
+#define BNAD_RIT_OFFSET		0
+#define BNAD_MULTICAST_RXQ_ID	0
+
+#define BNAD_NETIF_WAKE_THRESHOLD	8
+
+#define BNAD_TX_MAX_VECTORS		255
+#define BNAD_TX_MAX_VECTORS_PER_WI	4
+#define BNAD_TX_MAX_DATA_PER_WI		0xFFFFFF	/* 24 bits */
+#define BNAD_TX_MAX_DATA_PER_VECTOR	0x3FFF	/* 14 bits */
+#define BNAD_TX_MAX_WRR_QUOTA		0xFFF	/* 12 bits */
+
+#define BNAD_RXQ_REFILL_THRESHOLD_SHIFT	3
+
+#define BNAD_NOT_READY(_bnad)	test_bit(BNAD_F_HWERROR, &(_bnad)->flags)
+#define BNAD_ADMIN_DOWN(_bnad)	(!netif_running((_bnad)->netdev) ||	\
+	test_bit(BNAD_F_BCU_DISABLED, &(_bnad)->flags))
+
+#define BNAD_Q_INDEX_CHANGE(_old_idx, _updated_idx, _q_depth)	\
+	(((_updated_idx) - (_old_idx)) & ((_q_depth) - 1))
+
+extern u32 bfi_image_ct_size;
+extern u32 *bfi_image_ct;
+extern u32 *bfad_get_firmware_buf(struct pci_dev *pdev);
+
+struct bnad_skb_unmap {
+	struct sk_buff *skb;
+	DECLARE_PCI_UNMAP_ADDR(dma_addr)
+};
+
+struct bnad_unmap_q {
+	u32 producer_index;
+	u32 consumer_index;
+	struct bnad_skb_unmap *unmap_array;
+	u32 q_depth;
+};
+
+struct bnad_ib_entry {
+	struct bna_ib *ib;
+	void *ib_seg_addr;
+	struct bna_ib_config ib_config;
+};
+
+struct bnad_txq_info {
+	unsigned long flags;
+#define BNAD_TXQ_FREE_SENT	0
+	struct bna_txq txq;
+	struct bna_ib ib;
+	struct bnad_unmap_q skb_unmap_q;
+	u64 tx_packets;
+	u64 tx_bytes;
+	struct bnad *bnad;
+	volatile u32 *hw_consumer_index;
+	struct bna_txq_config txq_config;
+	char name[BNAD_QUEUE_NAME_SIZE];
+} ____cacheline_aligned;
+
+struct bnad_rxq_info {
+	unsigned long flags;
+#define BNAD_RXQ_REFILL		0
+	struct bna_rxq rxq;
+	struct bnad_unmap_q skb_unmap_q;
+	u64 rx_packets;
+	u64 rx_bytes;
+	u64 rx_packets_with_error;
+	u64 rxbuf_alloc_failed;
+	struct bnad *bnad;
+	u32 rxq_id;
+	struct bna_rxq_config rxq_config;
+} ____cacheline_aligned;
+
+struct bnad_cq_info {
+	struct bna_cq cq;
+	struct bna_ib ib;
+	struct bnad *bnad;
+	struct bna_pkt_rate pkt_rate;
+	u8 rx_coalescing_timeo;	/* Unit is 5usec. */
+	volatile u32 *hw_producer_index;
+	struct napi_struct napi;
+	u32 cq_id;
+	struct bna_cq_config cq_config;
+	char name[BNAD_QUEUE_NAME_SIZE];
+} ____cacheline_aligned;
+
+struct bnad_txf_info {
+	u32 txf_id;
+	struct bna_txf_config txf_config;
+};
+
+struct bnad_rxf_info {
+	u32 rxf_id;
+	struct bna_rxf_config rxf_config;
+};
+
+enum bnad_ucast_cmd {
+	BNAD_UCAST_MAC_SET,
+	BNAD_UCAST_MAC_ADD,
+	BNAD_UCAST_MAC_DEL
+};
+
+enum bnad_state {
+	BNAD_S_START = 0,
+	BNAD_S_INIT = 1,
+	BNAD_S_INIT_DOWN = 2,
+	BNAD_S_INIT_DISABLING = 3,
+	BNAD_S_INIT_DISABLED = 4,
+	BNAD_S_OPENING = 5,
+	BNAD_S_OPEN = 6,
+	BNAD_S_OPEN_DOWN = 7,
+	BNAD_S_OPEN_DISABLING = 8,
+	BNAD_S_OPEN_DISABLED = 9,
+	BNAD_S_CLOSING = 10,
+	BNAD_S_UNLOADING = 11
+};
+
+enum bnad_link_state {
+	BNAD_LS_DOWN = 0,
+	BNAD_LS_UP = 1
+};
+struct bnad {
+	struct net_device *netdev;
+	struct pci_dev *pcidev;
+	struct bna_dev *priv;
+
+	enum bnad_state state;
+	unsigned long flags;
+#define BNAD_F_BCU_DISABLED		0
+#define BNAD_F_HWERROR			1
+#define BNAD_F_MBOX_IRQ_DISABLED	2
+#define BNAD_F_CEE_RUNNING		3
+
+	unsigned int config;
+#define BNAD_CF_MSIX		0x01
+#define BNAD_CF_PROMISC		0x02
+#define BNAD_CF_ALLMULTI		0x04
+#define BNAD_CF_TXQ_DEPTH	0x10
+#define BNAD_CF_RXQ_DEPTH	0x20
+
+	unsigned int priority;
+	unsigned int curr_priority;	/* currently applied priority */
+
+	enum bnad_link_state link_state;
+	u8 cee_linkup;
+
+	uint txq_num;
+	uint txq_depth;
+	struct bnad_txq_info *txq_table;
+
+	struct tasklet_struct tx_free_tasklet;	/* For Tx cleanup */
+
+	uint rxq_num;
+	uint rxq_depth;
+	struct bnad_rxq_info *rxq_table;
+	uint cq_num;
+	struct bnad_cq_info *cq_table;
+
+	struct vlan_group *vlangrp;
+
+	u32 rx_csum;
+
+	uint msix_num;
+	struct msix_entry *msix_table;
+
+	uint ib_num;
+	struct bnad_ib_entry *ib_table;
+
+	struct bna_rit_entry *rit;	/* RxQ Indirection Table */
+
+	spinlock_t priv_lock ____cacheline_aligned;
+
+	uint txf_num;
+	struct bnad_txf_info *txf_table;
+	uint rxf_num;
+	struct bnad_rxf_info *rxf_table;
+
+	struct timer_list stats_timer;
+	struct net_device_stats net_stats;
+
+	u8 tx_coalescing_timeo;	/* Unit is 5usec. */
+	u8 tx_interpkt_count;
+
+	u8 rx_coalescing_timeo;	/* Unit is 5usec. */
+	u8 rx_interpkt_count;
+	u8 rx_interpkt_timeo;	/* 4 bits, unit is 0.5usec. */
+
+	u8 rx_dyn_coalesce_on;	/* Rx Dynamic Intr Moderation Flag */
+
+	u8 ref_count;
+
+	u8 lldp_comp_status;
+	u8 cee_stats_comp_status;
+	u8 cee_reset_stats_status;
+	u8 ucast_comp_status;
+	u8 qstop_comp_status;
+
+	int ioc_comp_status;
+
+	struct bna_pause_config pause_config;
+
+	struct bna_stats *hw_stats;
+	struct bnad_drv_stats stats;
+
+	struct work_struct work;
+	unsigned int work_flags;
+#define BNAD_WF_ERROR		0x1
+#define BNAD_WF_RESETDONE	0x2
+#define BNAD_WF_CEE_PRIO	0x4
+#define BNAD_WF_LS_NOTIFY	0x8
+
+	struct completion lldp_comp;
+	struct completion cee_stats_comp;
+	struct completion cee_reset_stats_comp;
+	struct completion ucast_comp;
+	struct completion qstop_comp;
+	struct completion ioc_comp;
+
+	u32 bna_id;
+	u8 __iomem *bar0;	/* registers */
+
+	void *priv_stats;
+	  DECLARE_PCI_UNMAP_ADDR(priv_stats_dma)
+
+	struct bfa_trc_mod *trcmod;
+	struct bfa_log_mod *logmod;
+	struct bna_meminfo ioc_meminfo[BNA_MEM_T_MAX];
+	struct timer_list ioc_timer;
+	struct mutex conf_mutex; 
+
+	struct bna_mbox_cbfn priv_cbfn;
+
+	char adapter_name[64];
+	char port_name[64];
+
+	/* CEE Stuff */
+	struct bfa_cee_cbfn cee_cbfn;
+	struct bfa_cee cee;
+
+	struct list_head list_entry;
+};
+
+extern uint bnad_rxqs_per_cq;
+
+extern struct semaphore bnad_list_sem;
+extern struct list_head bnad_list;
+
+int bnad_open(struct net_device *netdev);
+int bnad_stop(struct net_device *netdev);
+int bnad_stop_locked(struct net_device *netdev);
+int bnad_open_locked(struct net_device *netdev);
+int bnad_sw_reset_locked(struct net_device *netdev);
+int bnad_ioc_disabling_locked(struct bnad *bnad);
+void bnad_set_ethtool_ops(struct net_device *netdev);
+void bnad_ioctl_init(void);
+void bnad_ioctl_exit(void);
+struct net_device_stats *bnad_get_stats(struct net_device *netdev);
+
+int bnad_ucast_mac(struct bnad *bnad, unsigned int rxf_id, u8 * mac_ptr,
+		   unsigned int cmd);
+void bnad_rxf_init(struct bnad *bnad, uint rxf_id, u8 rit_offset, int rss);
+int bnad_rxq_init(struct bnad *bnad, uint rxq_id);
+void bnad_setup_rxq(struct bnad *bnad, uint rxq_id);
+void bnad_alloc_for_rxq(struct bnad *bnad, uint rxq_id);
+int bnad_disable_rxqs(struct bnad *bnad, u64 rxq_id_mask);
+void bnad_free_rxq(struct bnad *bnad, uint rxq_id);
+int bnad_cq_init(struct bnad *bnad, uint cq_id);
+void bnad_setup_cq(struct bnad *bnad, uint cq_id);
+void bnad_setup_ib(struct bnad *bnad, uint ib_id);
+void bnad_rxib_init(struct bnad *bnad, uint cq_id, uint ib_id);
+void bnad_free_ib(struct bnad *bnad, uint ib_id);
+int bnad_request_cq_irq(struct bnad *bnad, uint cq_id);
+u32 bnad_get_msglevel(struct net_device *netdev);
+void bnad_set_msglevel(struct net_device *netdev, u32 msglevel);
+int bnad_alloc_unmap_q(struct bnad_unmap_q *unmap_q, u32 q_depth);
+void bnad_free_cq(struct bnad *bnad, uint cq_id);
+void bnad_add_to_list(struct bnad *bnad);
+void bnad_remove_from_list(struct bnad *bnad);
+struct bnad *get_bnadev(int bna_id);
+int bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev);
+
+#endif /* _BNAD_H_ */

^ permalink raw reply

* Subject: [PATCH 3/6] bna: Brocade 10Gb Ethernet device driver
From: Rasesh Mody @ 2010-02-12 14:00 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     |  464 +++++++++++++
 bfa_csdebug.c |   57 +
 bfa_ioc.c     | 1963 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 bfa_ioc_ct.c  |  412 ++++++++++++
 bfa_sm.c      |   38 +
 bna_if.c      |  538 +++++++++++++++
 bna_iocll.h   |   60 +
 bna_priv.h    |  472 +++++++++++++
 bnad_defs.h   |   37 +
 cna.h         |   41 +
 10 files changed, 4082 insertions(+)

diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/bfa_cee.c net-next-2.6.33-rc5-mod/drivers/net/bna/bfa_cee.c
--- net-next-2.6.33-rc5-orig/drivers/net/bna/bfa_cee.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/bfa_cee.c	2010-02-12 01:39:41.984841000 -0800
@@ -0,0 +1,464 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ *      @file bfa_cee.c CEE module source file.
+ */
+
+#include "defs/bfa_defs_cee.h"
+#include "cs/bfa_trc.h"
+#include "cs/bfa_debug.h"
+#include "cee/bfa_cee.h"
+#include "bfi/bfi_cee.h"
+#include "bfi/bfi.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_dcbcx_stats(struct bfa_cee_dcbx_stats *dcbcx_stats);
+static void bfa_cee_format_lldp_stats(struct bfa_cee_lldp_stats *lldp_stats);
+static void bfa_cee_format_cfg_stats(struct bfa_cee_cfg_stats *cfg_stats);
+static void bfa_cee_format_cee_cfg(void *buffer);
+static void bfa_cee_format_cee_stats(void *buffer);
+
+static void
+bfa_cee_format_cee_stats(void *buffer)
+{
+	struct bfa_cee_stats *cee_stats = buffer;
+	bfa_cee_format_dcbcx_stats(&cee_stats->dcbx_stats);
+	bfa_cee_format_lldp_stats(&cee_stats->lldp_stats);
+	bfa_cee_format_cfg_stats(&cee_stats->cfg_stats);
+}
+
+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_format_dcbcx_stats(struct bfa_cee_dcbx_stats *dcbcx_stats)
+{
+	dcbcx_stats->subtlvs_unrecognized  =
+			ntohl(dcbcx_stats->subtlvs_unrecognized);
+	dcbcx_stats->negotiation_failed =
+			ntohl(dcbcx_stats->negotiation_failed);
+	dcbcx_stats->remote_cfg_changed =
+			ntohl(dcbcx_stats->remote_cfg_changed);
+	dcbcx_stats->tlvs_received =
+			ntohl(dcbcx_stats->tlvs_received);
+	dcbcx_stats->tlvs_invalid =
+			ntohl(dcbcx_stats->tlvs_invalid);
+	dcbcx_stats->seqno =
+			ntohl(dcbcx_stats->seqno);
+	dcbcx_stats->ackno =
+			ntohl(dcbcx_stats->ackno);
+	dcbcx_stats->recvd_seqno =
+			ntohl(dcbcx_stats->recvd_seqno);
+	dcbcx_stats->recvd_ackno =
+			ntohl(dcbcx_stats->recvd_ackno);
+}
+
+static void
+bfa_cee_format_lldp_stats(struct bfa_cee_lldp_stats *lldp_stats)
+{
+	lldp_stats->frames_transmitted	=
+			ntohl(lldp_stats->frames_transmitted);
+	lldp_stats->frames_aged_out	=
+			ntohl(lldp_stats->frames_aged_out);
+	lldp_stats->frames_discarded	=
+			ntohl(lldp_stats->frames_discarded);
+	lldp_stats->frames_in_error	=
+			ntohl(lldp_stats->frames_in_error);
+	lldp_stats->frames_rcvd	=
+			ntohl(lldp_stats->frames_rcvd);
+	lldp_stats->tlvs_discarded	=
+			ntohl(lldp_stats->tlvs_discarded);
+	lldp_stats->tlvs_unrecognized	=
+			ntohl(lldp_stats->tlvs_unrecognized);
+}
+
+static void
+bfa_cee_format_cfg_stats(struct bfa_cee_cfg_stats *cfg_stats)
+{
+	cfg_stats->cee_status_down	=
+			ntohl(cfg_stats->cee_status_down);
+	cfg_stats->cee_status_up	=
+			ntohl(cfg_stats->cee_status_up);
+	cfg_stats->cee_hw_cfg_changed      =
+			ntohl(cfg_stats->cee_hw_cfg_changed);
+	cfg_stats->recvd_invalid_cfg      =
+			ntohl(cfg_stats->recvd_invalid_cfg);
+}
+
+static void
+bfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg *lldp_cfg)
+{
+	lldp_cfg->time_to_interval =
+			ntohs(lldp_cfg->time_to_interval);
+	lldp_cfg->enabled_system_cap =
+			ntohs(lldp_cfg->enabled_system_cap);
+}
+
+/**
+ * bfa_cee_attr_meminfo()
+ *
+ *
+ * @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()
+ *
+ *
+ * @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()
+ *
+ *
+ * @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, bfa_status_t status)
+{
+	cee->get_attr_status = status;
+	if (status == BFA_STATUS_OK) {
+		/*
+		 * The requested data has been copied to the DMA area,
+		 * process it.
+		 */
+		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()
+ *
+ *
+ * @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, bfa_status_t status)
+{
+	cee->get_stats_status = status;
+	if (status == BFA_STATUS_OK) {
+		/*
+		 * The requested data has been copied to the DMA area,
+		 * process it.
+		 */
+		memcpy(cee->stats, cee->stats_dma.kva,
+					sizeof(struct bfa_cee_stats));
+		bfa_cee_format_cee_stats(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()
+ *
+ *
+ * @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, bfa_status_t 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()
+ *
+ *
+ * @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()
+ *
+ *
+ * @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()
+ *
+ *   Send the request to the f/w to fetch CEE attributes.
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return Status
+ */
+
+bfa_status_t
+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;
+
+	bfa_assert((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()
+ *
+ *   Send the request to the f/w to fetch CEE statistics.
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return Status
+ */
+
+bfa_status_t
+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;
+
+	bfa_assert((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()
+ *
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return Status
+ */
+
+bfa_status_t
+bfa_cee_reset_stats(struct bfa_cee *cee, bfa_cee_reset_stats_cbfn_t cbfn,
+			void *cbarg)
+{
+	struct bfi_cee_reset_stats *cmd;
+
+	bfa_assert((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()
+ *
+ *
+ * @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:
+		bfa_assert(0);
+	}
+}
+
+/**
+ * bfa_cee_hbfail()
+ *
+ *
+ * @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()
+ *
+ *
+ * @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.
+ *            trcmod -
+ *            logmod -
+ *
+ * @return void
+ */
+void
+bfa_cee_attach(struct bfa_cee *cee, struct bfa_ioc *ioc,
+		void *dev,
+		struct bfa_trc_mod *trcmod,
+		struct bfa_log_mod *logmod)
+{
+	bfa_assert(cee != NULL);
+	cee->dev = dev;
+	cee->trcmod = trcmod;
+	cee->logmod = logmod;
+	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);
+}
+
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/bfa_csdebug.c net-next-2.6.33-rc5-mod/drivers/net/bna/bfa_csdebug.c
--- net-next-2.6.33-rc5-orig/drivers/net/bna/bfa_csdebug.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/bfa_csdebug.c	2010-02-12 01:39:42.172839000 -0800
@@ -0,0 +1,57 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#include "cs/bfa_debug.h"
+#include "cna.h"
+#include "cs/bfa_q.h"
+
+/**
+ *  cs_debug_api
+ */
+
+void
+bfa_panic(int line, char *file, char *panicstr)
+{
+
+		pr_err("Assertion failure: %s:%d: %s", file, line, panicstr);
+}
+
+void
+bfa_sm_panic(struct bfa_log_mod *logm, int line, char *file, int event)
+{
+
+		pr_err("SM Assertion failure: %s:%d: event = %d",
+			file, line, event);
+}
+
+int
+bfa_q_is_on_q_func(struct list_head *q, struct list_head *qe)
+{
+	struct list_head        *tqe;
+
+	tqe = bfa_q_next(q);
+	while (tqe != q) {
+		if (tqe == qe)
+			return 1;
+		tqe = bfa_q_next(tqe);
+		if (tqe == NULL)
+			break;
+	}
+	return 0;
+}
+
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/bfa_ioc.c net-next-2.6.33-rc5-mod/drivers/net/bna/bfa_ioc.c
--- net-next-2.6.33-rc5-orig/drivers/net/bna/bfa_ioc.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/bfa_ioc.c	2010-02-12 01:39:42.265843000 -0800
@@ -0,0 +1,1963 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#include "bfa_ioc.h"
+#include "bfa_fwimg_priv.h"
+#include "cs/bfa_debug.h"
+#include "bfi/bfi_ioc.h"
+#include "bfi/bfi_ctreg.h"
+#include "defs/bfa_defs_pci.h"
+#include "cna.h"
+
+/**
+ * IOC local definitions
+ */
+
+#define BFA_DBG_FWTRC_ENTS	(BFI_IOC_TRC_ENTS)
+#define BFA_DBG_FWTRC_LEN					\
+	(BFA_DBG_FWTRC_ENTS * sizeof(struct bfa_trc) +	\
+	 (sizeof(struct bfa_trc_mod) -			\
+	  BFA_TRC_MAX * sizeof(struct bfa_trc)))
+#define BFA_DBG_FWTRC_OFF(_fn)	(BFI_IOC_TRC_OFF + BFA_DBG_FWTRC_LEN * (_fn))
+
+/**
+ * Asic specific macros : see bfa_hw_cb.c and bfa_hw_ct.c for details.
+ */
+
+#define bfa_ioc_firmware_lock(__ioc)			\
+			((__ioc)->ioc_hwif->ioc_firmware_lock(__ioc))
+#define bfa_ioc_firmware_unlock(__ioc)			\
+			((__ioc)->ioc_hwif->ioc_firmware_unlock(__ioc))
+#define bfa_ioc_fwimg_get_chunk(__ioc, __off)		\
+			((__ioc)->ioc_hwif->ioc_fwimg_get_chunk(__ioc, __off))
+#define bfa_ioc_fwimg_get_size(__ioc)			\
+			((__ioc)->ioc_hwif->ioc_fwimg_get_size(__ioc))
+#define bfa_ioc_reg_init(__ioc) ((__ioc)->ioc_hwif->ioc_reg_init(__ioc))
+#define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc))
+#define bfa_ioc_notify_hbfail(__ioc)			\
+			((__ioc)->ioc_hwif->ioc_notify_hbfail(__ioc))
+
+bool bfa_auto_recover = true;
+
+/*
+ * forward declarations
+ */
+static void bfa_ioc_hw_sem_get(struct bfa_ioc *ioc);
+static void bfa_ioc_hw_sem_get_cancel(struct bfa_ioc *ioc);
+static void bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force);
+static void bfa_ioc_send_enable(struct bfa_ioc *ioc);
+static void bfa_ioc_send_disable(struct bfa_ioc *ioc);
+static void bfa_ioc_send_getattr(struct bfa_ioc *ioc);
+static void bfa_ioc_hb_monitor(struct bfa_ioc *ioc);
+static void bfa_ioc_hb_stop(struct bfa_ioc *ioc);
+static void bfa_ioc_reset(struct bfa_ioc *ioc, bool force);
+static void bfa_ioc_mbox_poll(struct bfa_ioc *ioc);
+static void bfa_ioc_mbox_hbfail(struct bfa_ioc *ioc);
+static void bfa_ioc_recover(struct bfa_ioc *ioc);
+static void bfa_ioc_disable_comp(struct bfa_ioc *ioc);
+static void bfa_ioc_lpu_stop(struct bfa_ioc *ioc);
+
+/**
+ *  hal_ioc_sm
+ */
+
+/**
+ * IOC state machine events
+ */
+enum ioc_event {
+	IOC_E_ENABLE		= 1,	/*  IOC enable request		*/
+	IOC_E_DISABLE		= 2,	/*  IOC disable request	*/
+	IOC_E_TIMEOUT		= 3,	/*  f/w response timeout	*/
+	IOC_E_FWREADY		= 4,	/*  f/w initialization done	*/
+	IOC_E_FWRSP_GETATTR	= 5,	/*  IOC get attribute response	*/
+	IOC_E_FWRSP_ENABLE	= 6,	/*  enable f/w response	*/
+	IOC_E_FWRSP_DISABLE	= 7,	/*  disable f/w response	*/
+	IOC_E_HBFAIL		= 8,	/*  heartbeat failure		*/
+	IOC_E_HWERROR		= 9,	/*  hardware error interrupt	*/
+	IOC_E_SEMLOCKED		= 10,	/*  h/w semaphore is locked	*/
+	IOC_E_DETACH		= 11,	/*  driver detach cleanup	*/
+};
+
+bfa_fsm_state_decl(bfa_ioc, reset, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, fwcheck, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, mismatch, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, semwait, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, hwinit, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, enabling, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, getattr, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, op, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, initfail, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, hbfail, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc, enum ioc_event);
+
+static struct bfa_sm_table ioc_sm_table[] = {
+	{BFA_SM(bfa_ioc_sm_reset), BFA_IOC_RESET},
+	{BFA_SM(bfa_ioc_sm_fwcheck), BFA_IOC_FWMISMATCH},
+	{BFA_SM(bfa_ioc_sm_mismatch), BFA_IOC_FWMISMATCH},
+	{BFA_SM(bfa_ioc_sm_semwait), BFA_IOC_SEMWAIT},
+	{BFA_SM(bfa_ioc_sm_hwinit), BFA_IOC_HWINIT},
+	{BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_HWINIT},
+	{BFA_SM(bfa_ioc_sm_getattr), BFA_IOC_GETATTR},
+	{BFA_SM(bfa_ioc_sm_op), BFA_IOC_OPERATIONAL},
+	{BFA_SM(bfa_ioc_sm_initfail), BFA_IOC_INITFAIL},
+	{BFA_SM(bfa_ioc_sm_hbfail), BFA_IOC_HBFAIL},
+	{BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING},
+	{BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED},
+};
+
+/**
+ * Reset entry actions -- initialize state machine
+ */
+static void
+bfa_ioc_sm_reset_entry(struct bfa_ioc *ioc)
+{
+	ioc->retry_count = 0;
+	ioc->auto_recover = bfa_auto_recover;
+}
+
+/**
+ * Beginning state. IOC is in reset state.
+ */
+static void
+bfa_ioc_sm_reset(struct bfa_ioc *ioc, enum ioc_event event)
+{
+
+	switch (event) {
+	case IOC_E_ENABLE:
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_fwcheck);
+		break;
+
+	case IOC_E_DISABLE:
+		bfa_ioc_disable_comp(ioc);
+		break;
+
+	case IOC_E_DETACH:
+		break;
+
+	default:
+		bfa_sm_fault(ioc, event);
+	}
+}
+
+/**
+ * Semaphore should be acquired for version check.
+ */
+static void
+bfa_ioc_sm_fwcheck_entry(struct bfa_ioc *ioc)
+{
+	bfa_ioc_hw_sem_get(ioc);
+}
+
+/**
+ * Awaiting h/w semaphore to continue with version check.
+ */
+static void
+bfa_ioc_sm_fwcheck(struct bfa_ioc *ioc, enum ioc_event event)
+{
+
+	switch (event) {
+	case IOC_E_SEMLOCKED:
+		if (bfa_ioc_firmware_lock(ioc)) {
+			ioc->retry_count = 0;
+			bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
+		} else {
+			bfa_ioc_hw_sem_release(ioc);
+			bfa_fsm_set_state(ioc, bfa_ioc_sm_mismatch);
+		}
+		break;
+
+	case IOC_E_DISABLE:
+		bfa_ioc_disable_comp(ioc);
+		/* fall through */
+
+	case IOC_E_DETACH:
+		bfa_ioc_hw_sem_get_cancel(ioc);
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+		break;
+
+	case IOC_E_FWREADY:
+		break;
+
+	default:
+		bfa_sm_fault(ioc, event);
+	}
+}
+
+/**
+ * Notify enable completion callback and generate mismatch AEN.
+ */
+static void
+bfa_ioc_sm_mismatch_entry(struct bfa_ioc *ioc)
+{
+	/**
+	 * Provide enable completion callback and AEN notification only once.
+	 */
+	if (ioc->retry_count == 0)
+		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+
+	ioc->retry_count++;
+	mod_timer(&ioc->ioc_timer, jiffies +
+	msecs_to_jiffies(BFA_IOC_TOV));
+}
+
+/**
+ * Awaiting firmware version match.
+ */
+static void
+bfa_ioc_sm_mismatch(struct bfa_ioc *ioc, enum ioc_event event)
+{
+
+	switch (event) {
+	case IOC_E_TIMEOUT:
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_fwcheck);
+		break;
+
+	case IOC_E_DISABLE:
+		bfa_ioc_disable_comp(ioc);
+		/* fall through */
+
+	case IOC_E_DETACH:
+		del_timer(&ioc->ioc_timer);
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+		break;
+
+	case IOC_E_FWREADY:
+		break;
+
+	default:
+		bfa_sm_fault(ioc, event);
+	}
+}
+
+/**
+ * Request for semaphore.
+ */
+static void
+bfa_ioc_sm_semwait_entry(struct bfa_ioc *ioc)
+{
+	bfa_ioc_hw_sem_get(ioc);
+}
+
+/**
+ * Awaiting semaphore for h/w initialzation.
+ */
+static void
+bfa_ioc_sm_semwait(struct bfa_ioc *ioc, enum ioc_event event)
+{
+
+	switch (event) {
+	case IOC_E_SEMLOCKED:
+		ioc->retry_count = 0;
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
+		break;
+
+	case IOC_E_DISABLE:
+		bfa_ioc_hw_sem_get_cancel(ioc);
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+		break;
+
+	default:
+		bfa_sm_fault(ioc, event);
+	}
+}
+
+static void
+bfa_ioc_sm_hwinit_entry(struct bfa_ioc *ioc)
+{
+	mod_timer(&ioc->ioc_timer, jiffies +
+	msecs_to_jiffies(BFA_IOC_TOV));
+	bfa_ioc_reset(ioc, false);
+}
+
+/**
+ * Hardware is being initialized. Interrupts are enabled.
+ * Holding hardware semaphore lock.
+ */
+static void
+bfa_ioc_sm_hwinit(struct bfa_ioc *ioc, enum ioc_event event)
+{
+
+	switch (event) {
+	case IOC_E_FWREADY:
+		del_timer(&ioc->ioc_timer);
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling);
+		break;
+
+	case IOC_E_HWERROR:
+		del_timer(&ioc->ioc_timer);
+		/* fall through */
+
+	case IOC_E_TIMEOUT:
+		ioc->retry_count++;
+		if (ioc->retry_count < BFA_IOC_HWINIT_MAX) {
+			mod_timer(&ioc->ioc_timer, jiffies +
+	msecs_to_jiffies(BFA_IOC_TOV));
+			bfa_ioc_reset(ioc, true);
+			break;
+		}
+
+		bfa_ioc_hw_sem_release(ioc);
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
+		break;
+
+	case IOC_E_DISABLE:
+		bfa_ioc_hw_sem_release(ioc);
+		del_timer(&ioc->ioc_timer);
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+		break;
+
+	default:
+		bfa_sm_fault(ioc, event);
+	}
+}
+
+static void
+bfa_ioc_sm_enabling_entry(struct bfa_ioc *ioc)
+{
+	mod_timer(&ioc->ioc_timer, jiffies +
+	msecs_to_jiffies(BFA_IOC_TOV));
+	bfa_ioc_send_enable(ioc);
+}
+
+/**
+ * Host IOC function is being enabled, awaiting response from firmware.
+ * Semaphore is acquired.
+ */
+static void
+bfa_ioc_sm_enabling(struct bfa_ioc *ioc, enum ioc_event event)
+{
+
+	switch (event) {
+	case IOC_E_FWRSP_ENABLE:
+		del_timer(&ioc->ioc_timer);
+		bfa_ioc_hw_sem_release(ioc);
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
+		break;
+
+	case IOC_E_HWERROR:
+		del_timer(&ioc->ioc_timer);
+		/* fall through */
+
+	case IOC_E_TIMEOUT:
+		ioc->retry_count++;
+		if (ioc->retry_count < BFA_IOC_HWINIT_MAX) {
+			writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate);
+			bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
+			break;
+		}
+
+		bfa_ioc_hw_sem_release(ioc);
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
+		break;
+
+	case IOC_E_DISABLE:
+		del_timer(&ioc->ioc_timer);
+		bfa_ioc_hw_sem_release(ioc);
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+		break;
+
+	case IOC_E_FWREADY:
+		bfa_ioc_send_enable(ioc);
+		break;
+
+	default:
+		bfa_sm_fault(ioc, event);
+	}
+}
+
+static void
+bfa_ioc_sm_getattr_entry(struct bfa_ioc *ioc)
+{
+	mod_timer(&ioc->ioc_timer, jiffies +
+	msecs_to_jiffies(BFA_IOC_TOV));
+	bfa_ioc_send_getattr(ioc);
+}
+
+/**
+ * IOC configuration in progress. Timer is active.
+ */
+static void
+bfa_ioc_sm_getattr(struct bfa_ioc *ioc, enum ioc_event event)
+{
+
+	switch (event) {
+	case IOC_E_FWRSP_GETATTR:
+		del_timer(&ioc->ioc_timer);
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_op);
+		break;
+
+	case IOC_E_HWERROR:
+		del_timer(&ioc->ioc_timer);
+		/* fall through */
+
+	case IOC_E_TIMEOUT:
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
+		break;
+
+	case IOC_E_DISABLE:
+		del_timer(&ioc->ioc_timer);
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+		break;
+
+	default:
+		bfa_sm_fault(ioc, event);
+	}
+}
+
+static void
+bfa_ioc_sm_op_entry(struct bfa_ioc *ioc)
+{
+	ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK);
+	bfa_ioc_hb_monitor(ioc);
+}
+
+static void
+bfa_ioc_sm_op(struct bfa_ioc *ioc, enum ioc_event event)
+{
+
+	switch (event) {
+	case IOC_E_ENABLE:
+		break;
+
+	case IOC_E_DISABLE:
+		bfa_ioc_hb_stop(ioc);
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
+		break;
+
+	case IOC_E_HWERROR:
+	case IOC_E_FWREADY:
+		/**
+		 * Hard error or IOC recovery by other function.
+		 * Treat it same as heartbeat failure.
+		 */
+		bfa_ioc_hb_stop(ioc);
+		/* !!! fall through !!! */
+
+	case IOC_E_HBFAIL:
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_hbfail);
+		break;
+
+	default:
+		bfa_sm_fault(ioc, event);
+	}
+}
+
+static void
+bfa_ioc_sm_disabling_entry(struct bfa_ioc *ioc)
+{
+	mod_timer(&ioc->ioc_timer, jiffies +
+	msecs_to_jiffies(BFA_IOC_TOV));
+	bfa_ioc_send_disable(ioc);
+}
+
+/**
+ * IOC is being disabled
+ */
+static void
+bfa_ioc_sm_disabling(struct bfa_ioc *ioc, enum ioc_event event)
+{
+
+	switch (event) {
+	case IOC_E_FWRSP_DISABLE:
+		del_timer(&ioc->ioc_timer);
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+		break;
+
+	case IOC_E_HWERROR:
+		del_timer(&ioc->ioc_timer);
+		/*
+		 * !!! fall through !!!
+		 */
+
+	case IOC_E_TIMEOUT:
+		writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+		break;
+
+	default:
+		bfa_sm_fault(ioc, event);
+	}
+}
+
+/**
+ * IOC disable completion entry.
+ */
+static void
+bfa_ioc_sm_disabled_entry(struct bfa_ioc *ioc)
+{
+	bfa_ioc_disable_comp(ioc);
+}
+
+static void
+bfa_ioc_sm_disabled(struct bfa_ioc *ioc, enum ioc_event event)
+{
+
+	switch (event) {
+	case IOC_E_ENABLE:
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
+		break;
+
+	case IOC_E_DISABLE:
+		ioc->cbfn->disable_cbfn(ioc->bfa);
+		break;
+
+	case IOC_E_FWREADY:
+		break;
+
+	case IOC_E_DETACH:
+		bfa_ioc_firmware_unlock(ioc);
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+		break;
+
+	default:
+		bfa_sm_fault(ioc, event);
+	}
+}
+
+static void
+bfa_ioc_sm_initfail_entry(struct bfa_ioc *ioc)
+{
+	ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+	mod_timer(&ioc->ioc_timer, jiffies +
+	msecs_to_jiffies(BFA_IOC_TOV));
+}
+
+/**
+ * Hardware initialization failed.
+ */
+static void
+bfa_ioc_sm_initfail(struct bfa_ioc *ioc, enum ioc_event event)
+{
+
+	switch (event) {
+	case IOC_E_DISABLE:
+		del_timer(&ioc->ioc_timer);
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+		break;
+
+	case IOC_E_DETACH:
+		del_timer(&ioc->ioc_timer);
+		bfa_ioc_firmware_unlock(ioc);
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+		break;
+
+	case IOC_E_TIMEOUT:
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
+		break;
+
+	default:
+		bfa_sm_fault(ioc, event);
+	}
+}
+
+static void
+bfa_ioc_sm_hbfail_entry(struct bfa_ioc *ioc)
+{
+	struct list_head			*qe;
+	struct bfa_ioc_hbfail_notify *notify;
+
+	/**
+	 * Mark IOC as failed in hardware and stop firmware.
+	 */
+	bfa_ioc_lpu_stop(ioc);
+	writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
+
+	/**
+	 * Notify other functions on HB failure.
+	 */
+	bfa_ioc_notify_hbfail(ioc);
+
+	/**
+	 * Notify driver and common modules registered for notification.
+	 */
+	ioc->cbfn->hbfail_cbfn(ioc->bfa);
+	list_for_each(qe, &ioc->hb_notify_q) {
+		notify = (struct bfa_ioc_hbfail_notify *) qe;
+		notify->cbfn(notify->cbarg);
+	}
+
+	/**
+	 * Flush any queued up mailbox requests.
+	 */
+	bfa_ioc_mbox_hbfail(ioc);
+
+	/**
+	 * Trigger auto-recovery after a delay.
+	 */
+	if (ioc->auto_recover) {
+		mod_timer(&ioc->ioc_timer, jiffies +
+		msecs_to_jiffies(BFA_IOC_TOV_RECOVER));
+	}
+}
+
+/**
+ * IOC heartbeat failure.
+ */
+static void
+bfa_ioc_sm_hbfail(struct bfa_ioc *ioc, enum ioc_event event)
+{
+
+	switch (event) {
+
+	case IOC_E_ENABLE:
+		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+		break;
+
+	case IOC_E_DISABLE:
+		if (ioc->auto_recover)
+			del_timer(&ioc->ioc_timer);
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+		break;
+
+	case IOC_E_TIMEOUT:
+		bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
+		break;
+
+	case IOC_E_FWREADY:
+		/**
+		 * Recovery is already initiated by other function.
+		 */
+		break;
+
+	case IOC_E_HWERROR:
+		/*
+		 * HB failure notification, ignore.
+		 */
+		break;
+	default:
+		bfa_sm_fault(ioc, event);
+	}
+}
+
+/**
+ *  hal_ioc_pvt BFA IOC private functions
+ */
+
+static void
+bfa_ioc_disable_comp(struct bfa_ioc *ioc)
+{
+	struct list_head			*qe;
+	struct bfa_ioc_hbfail_notify *notify;
+
+	ioc->cbfn->disable_cbfn(ioc->bfa);
+
+	/**
+	 * Notify common modules registered for notification.
+	 */
+	list_for_each(qe, &ioc->hb_notify_q) {
+		notify = (struct bfa_ioc_hbfail_notify *) qe;
+		notify->cbfn(notify->cbarg);
+	}
+}
+
+void
+bfa_ioc_sem_timeout(unsigned long ioc_arg)
+{
+	struct bfa_ioc *ioc = (struct bfa_ioc *) ioc_arg;
+
+	bfa_ioc_hw_sem_get(ioc);
+}
+
+bool
+bfa_ioc_sem_get(char __iomem *sem_reg)
+{
+	u32 r32;
+	int cnt = 0;
+#define BFA_SEM_SPINCNT	3000
+
+	r32 = readl(sem_reg);
+
+	while (r32 && (cnt < BFA_SEM_SPINCNT)) {
+		cnt++;
+		udelay(2);
+		r32 = readl(sem_reg);
+	}
+
+	if (r32 == 0)
+		return true;
+
+	bfa_assert(cnt < BFA_SEM_SPINCNT);
+	return false;
+}
+
+void
+bfa_ioc_sem_release(char __iomem *sem_reg)
+{
+	writel(1, sem_reg);
+}
+
+static void
+bfa_ioc_hw_sem_get(struct bfa_ioc *ioc)
+{
+	u32	r32;
+
+	/**
+	 * First read to the semaphore register will return 0, subsequent reads
+	 * will return 1. Semaphore is released by writing 1 to the register
+	 */
+	r32 = readl(ioc->ioc_regs.ioc_sem_reg);
+	if (r32 == 0) {
+		bfa_fsm_send_event(ioc, IOC_E_SEMLOCKED);
+		return;
+	}
+
+	mod_timer(&ioc->sem_timer, jiffies +
+		msecs_to_jiffies(BFA_IOC_HWSEM_TOV));
+}
+
+void
+bfa_ioc_hw_sem_release(struct bfa_ioc *ioc)
+{
+	writel(1, ioc->ioc_regs.ioc_sem_reg);
+}
+
+static void
+bfa_ioc_hw_sem_get_cancel(struct bfa_ioc *ioc)
+{
+	del_timer(&ioc->sem_timer);
+}
+
+/**
+ * Initialize LPU local memory (aka secondary memory / SRAM)
+ */
+static void
+bfa_ioc_lmem_init(struct bfa_ioc *ioc)
+{
+	u32	pss_ctl;
+	int		i;
+#define PSS_LMEM_INIT_TIME  10000
+
+	pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
+	pss_ctl &= ~__PSS_LMEM_RESET;
+	pss_ctl |= __PSS_LMEM_INIT_EN;
+
+	/*
+	 * i2c workaround 12.5khz clock
+	 */
+	pss_ctl |= __PSS_I2C_CLK_DIV(3UL);
+	writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
+
+	/**
+	 * wait for memory initialization to be complete
+	 */
+	i = 0;
+	do {
+		pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
+		i++;
+	} while (!(pss_ctl & __PSS_LMEM_INIT_DONE) && (i < PSS_LMEM_INIT_TIME));
+
+	/**
+	 * If memory initialization is not successful, IOC timeout will catch
+	 * such failures.
+	 */
+	bfa_assert(pss_ctl & __PSS_LMEM_INIT_DONE);
+
+	pss_ctl &= ~(__PSS_LMEM_INIT_DONE | __PSS_LMEM_INIT_EN);
+	writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
+}
+
+static void
+bfa_ioc_lpu_start(struct bfa_ioc *ioc)
+{
+	u32	pss_ctl;
+
+	/**
+	 * Take processor out of reset.
+	 */
+	pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
+	pss_ctl &= ~__PSS_LPU0_RESET;
+
+	writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
+}
+
+static void
+bfa_ioc_lpu_stop(struct bfa_ioc *ioc)
+{
+	u32	pss_ctl;
+
+	/**
+	 * Put processors in reset.
+	 */
+	pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
+	pss_ctl |= (__PSS_LPU0_RESET | __PSS_LPU1_RESET);
+
+	writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
+}
+
+/**
+ * Get driver and firmware versions.
+ */
+void
+bfa_ioc_fwver_get(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr)
+{
+	u32	pgnum, pgoff;
+	u32	loff = 0;
+	int		i;
+	u32	*fwsig = (u32 *) fwhdr;
+
+	pgnum = bfa_ioc_smem_pgnum(ioc, loff);
+	pgoff = bfa_ioc_smem_pgoff(ioc, loff);
+	writel(pgnum, ioc->ioc_regs.host_page_num_fn);
+
+	for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr) / sizeof(u32));
+	     i++) {
+		fwsig[i] =
+			ntohl(readl((ioc->ioc_regs.smem_page_start) + (loff)));
+		loff += sizeof(u32);
+	}
+}
+
+/**
+ * Returns TRUE if same.
+ */
+bool
+bfa_ioc_fwver_cmp(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr)
+{
+	struct bfi_ioc_image_hdr *drv_fwhdr;
+	int i;
+
+	drv_fwhdr =
+		(struct bfi_ioc_image_hdr *) bfa_ioc_fwimg_get_chunk(ioc, 0);
+
+	for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) {
+		if (fwhdr->md5sum[i] != drv_fwhdr->md5sum[i])
+			return false;
+
+	}
+
+	return true;
+}
+
+/**
+ * Return true if current running version is valid. Firmware signature and
+ * execution context (driver/bios) must match.
+ */
+static bool
+bfa_ioc_fwver_valid(struct bfa_ioc *ioc)
+{
+	struct bfi_ioc_image_hdr fwhdr, *drv_fwhdr;
+
+	/**
+	 * If bios/efi boot (flash based) -- return true
+	 */
+	if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
+		return true;
+
+	bfa_ioc_fwver_get(ioc, &fwhdr);
+	drv_fwhdr =
+		(struct bfi_ioc_image_hdr *) bfa_ioc_fwimg_get_chunk(ioc, 0);
+
+	if (fwhdr.signature != drv_fwhdr->signature)
+		return false;
+
+
+	if (fwhdr.exec != drv_fwhdr->exec)
+		return false;
+
+
+	return bfa_ioc_fwver_cmp(ioc, &fwhdr);
+}
+
+/**
+ * Conditionally flush any pending message from firmware at start.
+ */
+static void
+bfa_ioc_msgflush(struct bfa_ioc *ioc)
+{
+	u32	r32;
+
+	r32 = readl(ioc->ioc_regs.lpu_mbox_cmd);
+	if (r32)
+		writel(1, ioc->ioc_regs.lpu_mbox_cmd);
+}
+
+static void
+bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force)
+{
+	enum bfi_ioc_state ioc_fwstate;
+	bool fwvalid;
+
+	ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate);
+
+	if (force)
+		ioc_fwstate = BFI_IOC_UNINIT;
+
+	/**
+	 * check if firmware is valid
+	 */
+	fwvalid = (ioc_fwstate == BFI_IOC_UNINIT) ?
+		false : bfa_ioc_fwver_valid(ioc);
+
+	if (!fwvalid) {
+		bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id);
+		return;
+	}
+
+	/**
+	 * If hardware initialization is in progress (initialized by other IOC),
+	 * just wait for an initialization completion interrupt.
+	 */
+	if (ioc_fwstate == BFI_IOC_INITING) {
+		ioc->cbfn->reset_cbfn(ioc->bfa);
+		return;
+	}
+
+	/**
+	 * If IOC function is disabled and firmware version is same,
+	 * just re-enable IOC.
+	 */
+	if (ioc_fwstate == BFI_IOC_DISABLED || ioc_fwstate == BFI_IOC_OP) {
+
+		/**
+		 * When using MSI-X any pending firmware ready event should
+		 * be flushed. Otherwise MSI-X interrupts are not delivered.
+		 */
+		bfa_ioc_msgflush(ioc);
+		ioc->cbfn->reset_cbfn(ioc->bfa);
+		bfa_fsm_send_event(ioc, IOC_E_FWREADY);
+		return;
+	}
+
+	/**
+	 * Initialize the h/w for any other states.
+	 */
+	bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id);
+}
+
+void bfa_ioc_timeout(unsigned long ioc_arg)
+{
+	struct bfa_ioc *ioc = (struct bfa_ioc *) ioc_arg;
+
+	bfa_fsm_send_event(ioc, IOC_E_TIMEOUT);
+}
+
+void
+bfa_ioc_mbox_send(struct bfa_ioc *ioc, void *ioc_msg, int len)
+{
+	u32 *msgp = (u32 *) ioc_msg;
+	u32 i;
+
+	bfa_assert(len <= BFI_IOC_MSGLEN_MAX);
+
+	/*
+	 * first write msg to mailbox registers
+	 */
+	for (i = 0; i < len / sizeof(u32); i++)
+		writel(cpu_to_le32(msgp[i]),
+			ioc->ioc_regs.hfn_mbox + i * sizeof(u32));
+
+	for (; i < BFI_IOC_MSGLEN_MAX / sizeof(u32); i++)
+		writel(0, ioc->ioc_regs.hfn_mbox + i * sizeof(u32));
+
+	/*
+	 * write 1 to mailbox CMD to trigger LPU event
+	 */
+	writel(1, ioc->ioc_regs.hfn_mbox_cmd);
+	(void) readl(ioc->ioc_regs.hfn_mbox_cmd);
+}
+
+static void
+bfa_ioc_send_enable(struct bfa_ioc *ioc)
+{
+	struct bfi_ioc_ctrl_req enable_req;
+
+	bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ,
+		    bfa_ioc_portid(ioc));
+	enable_req.ioc_class = ioc->ioc_mc;
+	bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req));
+}
+
+static void
+bfa_ioc_send_disable(struct bfa_ioc *ioc)
+{
+	struct bfi_ioc_ctrl_req disable_req;
+
+	bfi_h2i_set(disable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_DISABLE_REQ,
+		    bfa_ioc_portid(ioc));
+	bfa_ioc_mbox_send(ioc, &disable_req, sizeof(struct bfi_ioc_ctrl_req));
+}
+
+static void
+bfa_ioc_send_getattr(struct bfa_ioc *ioc)
+{
+	struct bfi_ioc_getattr_req attr_req;
+
+	bfi_h2i_set(attr_req.mh, BFI_MC_IOC, BFI_IOC_H2I_GETATTR_REQ,
+		    bfa_ioc_portid(ioc));
+	bfa_dma_be_addr_set(attr_req.attr_addr, ioc->attr_dma.pa);
+	bfa_ioc_mbox_send(ioc, &attr_req, sizeof(attr_req));
+}
+
+void bfa_ioc_hb_check(unsigned long cbarg)
+{
+	struct bfa_ioc *ioc = (struct bfa_ioc *) cbarg;
+	u32	hb_count;
+
+	hb_count = readl(ioc->ioc_regs.heartbeat);
+	if (ioc->hb_count == hb_count) {
+
+		pr_crit("Firmware heartbeat failure at %d", hb_count);
+		bfa_ioc_recover(ioc);
+		return;
+	} else {
+		ioc->hb_count = hb_count;
+	}
+
+	bfa_ioc_mbox_poll(ioc);
+	mod_timer(&ioc->hb_timer, jiffies + msecs_to_jiffies(BFA_IOC_HB_TOV));
+}
+
+static void
+bfa_ioc_hb_monitor(struct bfa_ioc *ioc)
+{
+	ioc->hb_count = readl(ioc->ioc_regs.heartbeat);
+	mod_timer(&ioc->hb_timer, jiffies + msecs_to_jiffies(BFA_IOC_HB_TOV));
+}
+
+static void
+bfa_ioc_hb_stop(struct bfa_ioc *ioc)
+{
+	del_timer(&ioc->ioc_timer);
+}
+
+/**
+ *	Initiate a full firmware download.
+ */
+static void
+bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type,
+		    u32 boot_param)
+{
+	u32 *fwimg;
+	u32 pgnum, pgoff;
+	u32 loff = 0;
+	u32 chunkno = 0;
+	u32 i;
+
+	/**
+	 * Initialize LMEM first before code download
+	 */
+	bfa_ioc_lmem_init(ioc);
+
+	/**
+	 * Flash based firmware boot
+	 */
+	if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
+		boot_type = BFI_BOOT_TYPE_FLASH;
+	fwimg = bfa_ioc_fwimg_get_chunk(ioc, chunkno);
+
+	pgnum = bfa_ioc_smem_pgnum(ioc, loff);
+	pgoff = bfa_ioc_smem_pgoff(ioc, loff);
+
+	writel(pgnum, ioc->ioc_regs.host_page_num_fn);
+
+	for (i = 0; i < bfa_ioc_fwimg_get_size(ioc); i++) {
+
+		if (BFA_IOC_FLASH_CHUNK_NO(i) != chunkno) {
+			chunkno = BFA_IOC_FLASH_CHUNK_NO(i);
+			fwimg = bfa_ioc_fwimg_get_chunk(ioc,
+					BFA_IOC_FLASH_CHUNK_ADDR(chunkno));
+		}
+
+		/**
+		 * write smem
+		 */
+		writel(htonl((fwimg[BFA_IOC_FLASH_OFFSET_IN_CHUNK(i)])),
+			((ioc->ioc_regs.smem_page_start) + (loff)));
+
+		loff += sizeof(u32);
+
+		/**
+		 * handle page offset wrap around
+		 */
+		loff = PSS_SMEM_PGOFF(loff);
+		if (loff == 0) {
+			pgnum++;
+			writel(pgnum, ioc->ioc_regs.host_page_num_fn);
+		}
+	}
+
+	writel(bfa_ioc_smem_pgnum(ioc, 0), ioc->ioc_regs.host_page_num_fn);
+
+	/*
+	 * Set boot type and boot param at the end.
+	*/
+	writel(htonl((swab32(boot_type))),
+		((ioc->ioc_regs.smem_page_start) + (BFI_BOOT_TYPE_OFF)));
+	writel(htonl((swab32(boot_param))),
+		((ioc->ioc_regs.smem_page_start) + (BFI_BOOT_PARAM_OFF)));
+}
+
+static void
+bfa_ioc_reset(struct bfa_ioc *ioc, bool force)
+{
+	bfa_ioc_hwinit(ioc, force);
+}
+
+/**
+ * Update BFA configuration from firmware configuration.
+ */
+static void
+bfa_ioc_getattr_reply(struct bfa_ioc *ioc)
+{
+	struct bfi_ioc_attr *attr = ioc->attr;
+
+	attr->adapter_prop  = ntohl(attr->adapter_prop);
+	attr->maxfrsize	    = ntohs(attr->maxfrsize);
+
+	bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR);
+}
+
+/**
+ * Attach time initialization of mbox logic.
+ */
+static void
+bfa_ioc_mbox_attach(struct bfa_ioc *ioc)
+{
+	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+	int	mc;
+
+	INIT_LIST_HEAD(&mod->cmd_q);
+	for (mc = 0; mc < BFI_MC_MAX; mc++) {
+		mod->mbhdlr[mc].cbfn = NULL;
+		mod->mbhdlr[mc].cbarg = ioc->bfa;
+	}
+}
+
+/**
+ * Mbox poll timer -- restarts any pending mailbox requests.
+ */
+static void
+bfa_ioc_mbox_poll(struct bfa_ioc *ioc)
+{
+	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+	struct bfa_mbox_cmd *cmd;
+	u32			stat;
+
+	/**
+	 * If no command pending, do nothing
+	 */
+	if (list_empty(&mod->cmd_q))
+		return;
+
+	/**
+	 * If previous command is not yet fetched by firmware, do nothing
+	 */
+	stat = readl(ioc->ioc_regs.hfn_mbox_cmd);
+	if (stat)
+		return;
+
+	/**
+	 * Enqueue command to firmware.
+	 */
+	bfa_q_deq(&mod->cmd_q, &cmd);
+	bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
+}
+
+/**
+ * Cleanup any pending requests.
+ */
+static void
+bfa_ioc_mbox_hbfail(struct bfa_ioc *ioc)
+{
+	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+	struct bfa_mbox_cmd *cmd;
+
+	while (!list_empty(&mod->cmd_q))
+		bfa_q_deq(&mod->cmd_q, &cmd);
+}
+
+/**
+ *  hal_ioc_public
+ */
+
+/**
+ * Interface used by diag module to do firmware boot with memory test
+ * as the entry vector.
+ */
+void
+bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_param)
+{
+	char __iomem *rb;
+
+	bfa_ioc_stats(ioc, ioc_boots);
+
+	if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK)
+		return;
+
+	/**
+	 * Initialize IOC state of all functions on a chip reset.
+	 */
+	rb = ioc->pcidev.pci_bar_kva;
+	if (boot_param == BFI_BOOT_TYPE_MEMTEST) {
+		writel(BFI_IOC_MEMTEST, (rb + BFA_IOC0_STATE_REG));
+		writel(BFI_IOC_MEMTEST, (rb + BFA_IOC1_STATE_REG));
+	} else {
+		writel(BFI_IOC_INITING, (rb + BFA_IOC0_STATE_REG));
+		writel(BFI_IOC_INITING, (rb + BFA_IOC1_STATE_REG));
+	}
+
+	bfa_ioc_download_fw(ioc, boot_type, boot_param);
+
+	/**
+	 * Enable interrupts just before starting LPU
+	 */
+	ioc->cbfn->reset_cbfn(ioc->bfa);
+	bfa_ioc_lpu_start(ioc);
+}
+
+/**
+ * Enable/disable IOC failure auto recovery.
+ */
+void
+bfa_ioc_auto_recover(bool auto_recover)
+{
+	bfa_auto_recover = auto_recover;
+}
+
+bool
+bfa_ioc_is_operational(struct bfa_ioc *ioc)
+{
+	return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_op);
+}
+
+void
+bfa_ioc_msgget(struct bfa_ioc *ioc, void *mbmsg)
+{
+	u32	*msgp = mbmsg;
+	u32	r32;
+	int		i;
+
+	/**
+	 * read the MBOX msg
+	 */
+	for (i = 0; i < (sizeof(union bfi_ioc_i2h_msg_u) / sizeof(u32));
+	     i++) {
+		r32 = readl(ioc->ioc_regs.lpu_mbox +
+				   i * sizeof(u32));
+		msgp[i] = htonl(r32);
+	}
+
+	/**
+	 * turn off mailbox interrupt by clearing mailbox status
+	 */
+	writel(1, ioc->ioc_regs.lpu_mbox_cmd);
+	readl(ioc->ioc_regs.lpu_mbox_cmd);
+}
+
+void
+bfa_ioc_isr(struct bfa_ioc *ioc, struct bfi_mbmsg *m)
+{
+	union bfi_ioc_i2h_msg_u	*msg;
+
+	msg = (union bfi_ioc_i2h_msg_u *) m;
+
+	bfa_ioc_stats(ioc, ioc_isrs);
+
+	switch (msg->mh.msg_id) {
+	case BFI_IOC_I2H_HBEAT:
+		break;
+
+	case BFI_IOC_I2H_READY_EVENT:
+		bfa_fsm_send_event(ioc, IOC_E_FWREADY);
+		break;
+
+	case BFI_IOC_I2H_ENABLE_REPLY:
+		bfa_fsm_send_event(ioc, IOC_E_FWRSP_ENABLE);
+		break;
+
+	case BFI_IOC_I2H_DISABLE_REPLY:
+		bfa_fsm_send_event(ioc, IOC_E_FWRSP_DISABLE);
+		break;
+
+	case BFI_IOC_I2H_GETATTR_REPLY:
+		bfa_ioc_getattr_reply(ioc);
+		break;
+
+	default:
+		bfa_assert(0);
+	}
+}
+
+/**
+ * IOC attach time initialization and setup.
+ *
+ * @param[in]	ioc	memory for IOC
+ * @param[in]	bfa	driver instance structure
+ * @param[in]	trcmod	kernel trace module
+ * @param[in]	aen	kernel aen event module
+ * @param[in]	logm	kernel logging module
+ */
+void
+bfa_ioc_attach(struct bfa_ioc *ioc, void *bfa, struct bfa_ioc_cbfn *cbfn,
+	       struct bfa_trc_mod *trcmod,
+	       struct bfa_aen *aen, struct bfa_log_mod *logm)
+{
+	ioc->bfa	= bfa;
+	ioc->cbfn	= cbfn;
+	ioc->trcmod	= trcmod;
+	ioc->aen	= aen;
+	ioc->logm	= logm;
+	ioc->fcmode	= false;
+	ioc->pllinit	= false;
+	ioc->dbg_fwsave_once = true;
+
+	bfa_ioc_mbox_attach(ioc);
+	INIT_LIST_HEAD(&ioc->hb_notify_q);
+
+	bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+}
+
+/**
+ * Driver detach time IOC cleanup.
+ */
+void
+bfa_ioc_detach(struct bfa_ioc *ioc)
+{
+	bfa_fsm_send_event(ioc, IOC_E_DETACH);
+}
+
+/**
+ * Setup IOC PCI properties.
+ *
+ * @param[in]	pcidev	PCI device information for this IOC
+ */
+void
+bfa_ioc_pci_init(struct bfa_ioc *ioc, struct bfa_pcidev *pcidev,
+		 enum bfi_mclass mc)
+{
+	ioc->ioc_mc	= mc;
+	ioc->pcidev	= *pcidev;
+	ioc->ctdev	= (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT);
+	ioc->cna	= ioc->ctdev && !ioc->fcmode;
+
+	/**
+	 * Set asic specific interfaces. See bfa_ioc_cb.c and bfa_ioc_ct.c
+	 */
+	bfa_ioc_set_ct_hwif(ioc);
+
+	bfa_ioc_map_port(ioc);
+	bfa_ioc_reg_init(ioc);
+}
+
+/**
+ * Initialize IOC dma memory
+ *
+ * @param[in]	dm_kva	kernel virtual address of IOC dma memory
+ * @param[in]	dm_pa	physical address of IOC dma memory
+ */
+void
+bfa_ioc_mem_claim(struct bfa_ioc *ioc,  u8 *dm_kva, u64 dm_pa)
+{
+	/**
+	 * dma memory for firmware attribute
+	 */
+	ioc->attr_dma.kva = dm_kva;
+	ioc->attr_dma.pa = dm_pa;
+	ioc->attr = (struct bfi_ioc_attr *) dm_kva;
+}
+
+/**
+ * Return size of dma memory required.
+ */
+u32
+bfa_ioc_meminfo(void)
+{
+	return roundup(sizeof(struct bfi_ioc_attr), BFA_DMA_ALIGN_SZ);
+}
+
+void
+bfa_ioc_enable(struct bfa_ioc *ioc)
+{
+	bfa_ioc_stats(ioc, ioc_enables);
+	ioc->dbg_fwsave_once = true;
+
+	bfa_fsm_send_event(ioc, IOC_E_ENABLE);
+}
+
+void
+bfa_ioc_disable(struct bfa_ioc *ioc)
+{
+	bfa_ioc_stats(ioc, ioc_disables);
+	bfa_fsm_send_event(ioc, IOC_E_DISABLE);
+}
+
+/**
+ * Returns memory required for saving firmware trace in case of crash.
+ * Driver must call this interface to allocate memory required for
+ * automatic saving of firmware trace. Driver should call
+ * bfa_ioc_debug_memclaim() right after bfa_ioc_attach() to setup this
+ * trace memory.
+ */
+int
+bfa_ioc_debug_trcsz(bool auto_recover)
+{
+	return (auto_recover) ? BFA_DBG_FWTRC_LEN : 0;
+}
+
+/**
+ * Initialize memory for saving firmware trace. Driver must initialize
+ * trace memory before call bfa_ioc_enable().
+ */
+void
+bfa_ioc_debug_memclaim(struct bfa_ioc *ioc, void *dbg_fwsave)
+{
+	ioc->dbg_fwsave	    = dbg_fwsave;
+	ioc->dbg_fwsave_len = bfa_ioc_debug_trcsz(ioc->auto_recover);
+}
+
+u32
+bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr)
+{
+	return PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, fmaddr);
+}
+
+u32
+bfa_ioc_smem_pgoff(struct bfa_ioc *ioc, u32 fmaddr)
+{
+	return PSS_SMEM_PGOFF(fmaddr);
+}
+
+/**
+ * Register mailbox message handler functions
+ *
+ * @param[in]	ioc		IOC instance
+ * @param[in]	mcfuncs		message class handler functions
+ */
+void
+bfa_ioc_mbox_register(struct bfa_ioc *ioc, bfa_ioc_mbox_mcfunc_t *mcfuncs)
+{
+	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+	int				mc;
+
+	for (mc = 0; mc < BFI_MC_MAX; mc++)
+		mod->mbhdlr[mc].cbfn = mcfuncs[mc];
+}
+
+/**
+ * Register mailbox message handler function, to be called by common modules
+ */
+void
+bfa_ioc_mbox_regisr(struct bfa_ioc *ioc, enum bfi_mclass mc,
+		    bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg)
+{
+	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+
+	mod->mbhdlr[mc].cbfn	= cbfn;
+	mod->mbhdlr[mc].cbarg = cbarg;
+}
+
+/**
+ * Queue a mailbox command request to firmware. Waits if mailbox is busy.
+ * Responsibility of caller to serialize
+ *
+ * @param[in]	ioc	IOC instance
+ * @param[i]	cmd	Mailbox command
+ */
+void
+bfa_ioc_mbox_queue(struct bfa_ioc *ioc, struct bfa_mbox_cmd *cmd)
+{
+	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+	u32			stat;
+
+	/**
+	 * If a previous command is pending, queue new command
+	 */
+	if (!list_empty(&mod->cmd_q)) {
+		list_add_tail(&cmd->qe, &mod->cmd_q);
+		return;
+	}
+
+	/**
+	 * If mailbox is busy, queue command for poll timer
+	 */
+	stat = readl(ioc->ioc_regs.hfn_mbox_cmd);
+	if (stat) {
+		list_add_tail(&cmd->qe, &mod->cmd_q);
+		return;
+	}
+
+	/**
+	 * mailbox is free -- queue command to firmware
+	 */
+	bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
+}
+
+/**
+ * Handle mailbox interrupts
+ */
+void
+bfa_ioc_mbox_isr(struct bfa_ioc *ioc)
+{
+	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+	struct bfi_mbmsg m;
+	int				mc;
+
+	bfa_ioc_msgget(ioc, &m);
+
+	/**
+	 * Treat IOC message class as special.
+	 */
+	mc = m.mh.msg_class;
+	if (mc == BFI_MC_IOC) {
+		bfa_ioc_isr(ioc, &m);
+		return;
+	}
+
+	if ((mc > BFI_MC_MAX) || (mod->mbhdlr[mc].cbfn == NULL)) {
+		bfa_assert(0);
+		bfa_trc_stop(ioc->trcmod);
+		return;
+	}
+
+	mod->mbhdlr[mc].cbfn(mod->mbhdlr[mc].cbarg, &m);
+}
+
+void
+bfa_ioc_error_isr(struct bfa_ioc *ioc)
+{
+	bfa_fsm_send_event(ioc, IOC_E_HWERROR);
+}
+
+#ifndef BFA_BIOS_BUILD
+
+/**
+ * return true if IOC is disabled
+ */
+bool
+bfa_ioc_is_disabled(struct bfa_ioc *ioc)
+{
+	return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabling) ||
+		bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled);
+}
+
+/**
+ * return true if IOC firmware is different.
+ */
+bool
+bfa_ioc_fw_mismatch(struct bfa_ioc *ioc)
+{
+	return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_reset) ||
+		bfa_fsm_cmp_state(ioc, bfa_ioc_sm_fwcheck) ||
+		bfa_fsm_cmp_state(ioc, bfa_ioc_sm_mismatch);
+}
+
+#define bfa_ioc_state_disabled(__sm)		\
+	(((__sm) == BFI_IOC_UNINIT) ||		\
+	 ((__sm) == BFI_IOC_INITING) ||		\
+	 ((__sm) == BFI_IOC_HWINIT) ||		\
+	 ((__sm) == BFI_IOC_DISABLED) ||	\
+	 ((__sm) == BFI_IOC_FAIL) ||		\
+	 ((__sm) == BFI_IOC_CFG_DISABLED))
+
+/**
+ * Check if adapter is disabled -- both IOCs should be in a disabled
+ * state.
+ */
+bool
+bfa_ioc_adapter_is_disabled(struct bfa_ioc *ioc)
+{
+	u32	ioc_state;
+	char __iomem *rb = ioc->pcidev.pci_bar_kva;
+
+	if (!bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled))
+		return false;
+
+	ioc_state = readl(rb + BFA_IOC0_STATE_REG);
+	if (!bfa_ioc_state_disabled(ioc_state))
+		return false;
+
+	ioc_state = readl(rb + BFA_IOC1_STATE_REG);
+	if (!bfa_ioc_state_disabled(ioc_state))
+		return false;
+
+	return true;
+}
+
+/**
+ * Add to IOC heartbeat failure notification queue. To be used by common
+ * modules such as cee, port, diag.
+ */
+void
+bfa_ioc_hbfail_register(struct bfa_ioc *ioc,
+			struct bfa_ioc_hbfail_notify *notify)
+{
+	list_add_tail(&notify->qe, &ioc->hb_notify_q);
+}
+
+#define BFA_MFG_NAME "Brocade"
+void
+bfa_ioc_get_adapter_attr(struct bfa_ioc *ioc,
+			 struct bfa_adapter_attr *ad_attr)
+{
+	struct bfi_ioc_attr *ioc_attr;
+
+	ioc_attr = ioc->attr;
+
+	bfa_ioc_get_adapter_serial_num(ioc, ad_attr->serial_num);
+	bfa_ioc_get_adapter_fw_ver(ioc, ad_attr->fw_ver);
+	bfa_ioc_get_adapter_optrom_ver(ioc, ad_attr->optrom_ver);
+	bfa_ioc_get_adapter_manufacturer(ioc, ad_attr->manufacturer);
+	memcpy(&ad_attr->vpd, &ioc_attr->vpd,
+		      sizeof(struct bfa_mfg_vpd));
+
+	ad_attr->nports = bfa_ioc_get_nports(ioc);
+	ad_attr->max_speed = bfa_ioc_speed_sup(ioc);
+
+	bfa_ioc_get_adapter_model(ioc, ad_attr->model);
+	/* For now, model descr uses same model string */
+	bfa_ioc_get_adapter_model(ioc, ad_attr->model_descr);
+
+	if (BFI_ADAPTER_IS_SPECIAL(ioc_attr->adapter_prop))
+		ad_attr->prototype = 1;
+	else
+		ad_attr->prototype = 0;
+
+	ad_attr->pwwn = bfa_ioc_get_pwwn(ioc);
+	ad_attr->mac  = bfa_ioc_get_mac(ioc);
+
+	ad_attr->pcie_gen = ioc_attr->pcie_gen;
+	ad_attr->pcie_lanes = ioc_attr->pcie_lanes;
+	ad_attr->pcie_lanes_orig = ioc_attr->pcie_lanes_orig;
+	ad_attr->asic_rev = ioc_attr->asic_rev;
+
+	bfa_ioc_get_pci_chip_rev(ioc, ad_attr->hw_ver);
+
+	ad_attr->cna_capable = ioc->cna;
+}
+
+enum bfa_ioc_type
+bfa_ioc_get_type(struct bfa_ioc *ioc)
+{
+	if (!ioc->ctdev || ioc->fcmode)
+		return BFA_IOC_TYPE_FC;
+	else if (ioc->ioc_mc == BFI_MC_IOCFC)
+		return BFA_IOC_TYPE_FCoE;
+	else if (ioc->ioc_mc == BFI_MC_LL)
+		return BFA_IOC_TYPE_LL;
+	else {
+		bfa_assert(ioc->ioc_mc == BFI_MC_LL);
+		return BFA_IOC_TYPE_LL;
+	}
+}
+
+void
+bfa_ioc_get_adapter_serial_num(struct bfa_ioc *ioc, char *serial_num)
+{
+	memset((void *)serial_num, 0, BFA_ADAPTER_SERIAL_NUM_LEN);
+	memcpy((void *)serial_num,
+			(void *)ioc->attr->brcd_serialnum,
+			BFA_ADAPTER_SERIAL_NUM_LEN);
+}
+
+void
+bfa_ioc_get_adapter_fw_ver(struct bfa_ioc *ioc, char *fw_ver)
+{
+	memset((void *)fw_ver, 0, BFA_VERSION_LEN);
+	memcpy(fw_ver, ioc->attr->fw_version, BFA_VERSION_LEN);
+}
+
+void
+bfa_ioc_get_pci_chip_rev(struct bfa_ioc *ioc, char *chip_rev)
+{
+	bfa_assert(chip_rev);
+
+	memset((void *)chip_rev, 0, BFA_IOC_CHIP_REV_LEN);
+
+	chip_rev[0] = 'R';
+	chip_rev[1] = 'e';
+	chip_rev[2] = 'v';
+	chip_rev[3] = '-';
+	chip_rev[4] = ioc->attr->asic_rev;
+	chip_rev[5] = '\0';
+}
+
+void
+bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc *ioc, char *optrom_ver)
+{
+	memset((void *)optrom_ver, 0, BFA_VERSION_LEN);
+	memcpy(optrom_ver, ioc->attr->optrom_version,
+		      BFA_VERSION_LEN);
+}
+
+void
+bfa_ioc_get_adapter_manufacturer(struct bfa_ioc *ioc, char *manufacturer)
+{
+	memset((void *)manufacturer, 0, BFA_ADAPTER_MFG_NAME_LEN);
+	memcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
+}
+
+void
+bfa_ioc_get_adapter_model(struct bfa_ioc *ioc, char *model)
+{
+	struct bfi_ioc_attr *ioc_attr;
+	u8		nports;
+	u8		max_speed;
+
+	bfa_assert(model);
+	memset((void *)model, 0, BFA_ADAPTER_MODEL_NAME_LEN);
+
+	ioc_attr = ioc->attr;
+
+	nports = bfa_ioc_get_nports(ioc);
+	max_speed = bfa_ioc_speed_sup(ioc);
+
+	/**
+	 * model name
+	 */
+	if (max_speed == 10) {
+		strcpy(model, "BR-10?0");
+		model[5] = '0' + nports;
+	} else {
+		strcpy(model, "Brocade-??5");
+		model[8] = '0' + max_speed;
+		model[9] = '0' + nports;
+	}
+}
+
+enum bfa_ioc_state
+bfa_ioc_get_state(struct bfa_ioc *ioc)
+{
+	return bfa_sm_to_state(ioc_sm_table, ioc->fsm);
+}
+
+void
+bfa_ioc_get_attr(struct bfa_ioc *ioc, struct bfa_ioc_attr *ioc_attr)
+{
+	memset((void *)ioc_attr, 0, sizeof(struct bfa_ioc_attr));
+
+	ioc_attr->state = bfa_ioc_get_state(ioc);
+	ioc_attr->port_id = ioc->port_id;
+
+	ioc_attr->ioc_type = bfa_ioc_get_type(ioc);
+
+	bfa_ioc_get_adapter_attr(ioc, &ioc_attr->adapter_attr);
+
+	ioc_attr->pci_attr.device_id = ioc->pcidev.device_id;
+	ioc_attr->pci_attr.pcifn = ioc->pcidev.pci_func;
+	bfa_ioc_get_pci_chip_rev(ioc, ioc_attr->pci_attr.chip_rev);
+}
+
+/**
+ *  hal_wwn_public
+ */
+wwn_t
+bfa_ioc_get_pwwn(struct bfa_ioc *ioc)
+{
+	union {
+		wwn_t	wwn;
+		u8	byte[sizeof(wwn_t)];
+	} w;
+
+	w.wwn = ioc->attr->mfg_wwn;
+
+	if (bfa_ioc_portid(ioc) == 1)
+		w.byte[7]++;
+
+	return w.wwn;
+}
+
+wwn_t
+bfa_ioc_get_nwwn(struct bfa_ioc *ioc)
+{
+	union {
+		wwn_t	wwn;
+		u8	byte[sizeof(wwn_t)];
+	} w;
+
+	w.wwn = ioc->attr->mfg_wwn;
+
+	if (bfa_ioc_portid(ioc) == 1)
+		w.byte[7]++;
+
+	w.byte[0] = 0x20;
+
+	return w.wwn;
+}
+
+wwn_t
+bfa_ioc_get_wwn_naa5(struct bfa_ioc *ioc, u16 inst)
+{
+	union {
+		wwn_t		wwn;
+		u8		byte[sizeof(wwn_t)];
+	} w, w5;
+
+	w.wwn = ioc->attr->mfg_wwn;
+	w5.byte[0] = 0x50 | w.byte[2] >> 4;
+	w5.byte[1] = w.byte[2] << 4 | w.byte[3] >> 4;
+	w5.byte[2] = w.byte[3] << 4 | w.byte[4] >> 4;
+	w5.byte[3] = w.byte[4] << 4 | w.byte[5] >> 4;
+	w5.byte[4] = w.byte[5] << 4 | w.byte[6] >> 4;
+	w5.byte[5] = w.byte[6] << 4 | w.byte[7] >> 4;
+	w5.byte[6] = w.byte[7] << 4 | (inst & 0x0f00) >> 8;
+	w5.byte[7] = (inst & 0xff);
+
+	return w5.wwn;
+}
+
+u64
+bfa_ioc_get_adid(struct bfa_ioc *ioc)
+{
+	return ioc->attr->mfg_wwn;
+}
+
+struct mac
+bfa_ioc_get_mac(struct bfa_ioc *ioc)
+{
+	struct mac mac;
+
+	mac = ioc->attr->mfg_mac;
+	mac.mac[ETH_ALEN - 1] += bfa_ioc_pcifn(ioc);
+
+	return mac;
+}
+
+void
+bfa_ioc_set_fcmode(struct bfa_ioc *ioc)
+{
+	ioc->fcmode  = true;
+	ioc->port_id = bfa_ioc_pcifn(ioc);
+}
+
+bool
+bfa_ioc_get_fcmode(struct bfa_ioc *ioc)
+{
+	return ioc->fcmode || (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_CT);
+}
+
+/**
+ * Retrieve saved firmware trace from a prior IOC failure.
+ */
+bfa_status_t
+bfa_ioc_debug_fwsave(struct bfa_ioc *ioc, void *trcdata, int *trclen)
+{
+	int	tlen;
+
+	if (ioc->dbg_fwsave_len == 0)
+		return BFA_STATUS_ENOFSAVE;
+
+	tlen = *trclen;
+	if (tlen > ioc->dbg_fwsave_len)
+		tlen = ioc->dbg_fwsave_len;
+
+	memcpy(trcdata, ioc->dbg_fwsave, tlen);
+	*trclen = tlen;
+	return BFA_STATUS_OK;
+}
+
+/**
+ * Clear saved firmware trace
+ */
+void
+bfa_ioc_debug_fwsave_clear(struct bfa_ioc *ioc)
+{
+	ioc->dbg_fwsave_once = true;
+}
+
+/**
+ * Retrieve saved firmware trace from a prior IOC failure.
+ */
+bfa_status_t
+bfa_ioc_debug_fwtrc(struct bfa_ioc *ioc, void *trcdata, int *trclen)
+{
+	u32 pgnum;
+	u32 loff = BFA_DBG_FWTRC_OFF(bfa_ioc_portid(ioc));
+	int i, tlen;
+	u32 *tbuf = trcdata, r32;
+
+	pgnum = bfa_ioc_smem_pgnum(ioc, loff);
+	loff = bfa_ioc_smem_pgoff(ioc, loff);
+
+	/*
+	 *  Hold semaphore to serialize pll init and fwtrc.
+	 */
+	if (false == bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg))
+		return BFA_STATUS_FAILED;
+
+	writel(pgnum, ioc->ioc_regs.host_page_num_fn);
+
+	tlen = *trclen;
+	if (tlen > BFA_DBG_FWTRC_LEN)
+		tlen = BFA_DBG_FWTRC_LEN;
+	tlen /= sizeof(u32);
+
+	for (i = 0; i < tlen; i++) {
+		r32 = ntohl(readl((ioc->ioc_regs.smem_page_start) + (loff)));
+		tbuf[i] = ntohl(r32);
+		loff += sizeof(u32);
+
+		/**
+		 * handle page offset wrap around
+		 */
+		loff = PSS_SMEM_PGOFF(loff);
+		if (loff == 0) {
+			pgnum++;
+			writel(pgnum, ioc->ioc_regs.host_page_num_fn);
+		}
+	}
+	writel(bfa_ioc_smem_pgnum(ioc, 0), ioc->ioc_regs.host_page_num_fn);
+
+	/*
+	 *  release semaphore.
+	 */
+	bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg);
+
+	*trclen = tlen * sizeof(u32);
+	return BFA_STATUS_OK;
+}
+
+/**
+ * Save firmware trace if configured.
+ */
+static void
+bfa_ioc_debug_save(struct bfa_ioc *ioc)
+{
+	int		tlen;
+
+	if (ioc->dbg_fwsave_len) {
+		tlen = ioc->dbg_fwsave_len;
+		bfa_ioc_debug_fwtrc(ioc, ioc->dbg_fwsave, &tlen);
+	}
+}
+
+/**
+ * Firmware failure detected. Start recovery actions.
+ */
+static void
+bfa_ioc_recover(struct bfa_ioc *ioc)
+{
+	if (ioc->dbg_fwsave_once) {
+		ioc->dbg_fwsave_once = false;
+		bfa_ioc_debug_save(ioc);
+	}
+
+	bfa_ioc_stats(ioc, ioc_hbfails);
+	bfa_fsm_send_event(ioc, IOC_E_HBFAIL);
+}
+
+#else
+
+static void
+bfa_ioc_recover(struct bfa_ioc *ioc)
+{
+	bfa_assert(0);
+}
+
+#endif
+
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/bfa_ioc_ct.c net-next-2.6.33-rc5-mod/drivers/net/bna/bfa_ioc_ct.c
--- net-next-2.6.33-rc5-orig/drivers/net/bna/bfa_ioc_ct.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/bfa_ioc_ct.c	2010-02-12 01:39:42.292839000 -0800
@@ -0,0 +1,412 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#include "bfa_ioc.h"
+#include "bfa_fwimg_priv.h"
+#include "cs/bfa_debug.h"
+#include "bfi/bfi_ioc.h"
+#include "bfi/bfi_ctreg.h"
+#include "defs/bfa_defs_pci.h"
+
+/*
+ * forward declarations
+ */
+static bfa_status_t bfa_ioc_ct_pll_init(struct bfa_ioc *ioc);
+static bool bfa_ioc_ct_firmware_lock(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_firmware_unlock(struct bfa_ioc *ioc);
+static u32 *bfa_ioc_ct_fwimg_get_chunk(struct bfa_ioc *ioc,
+						u32 off);
+static u32 bfa_ioc_ct_fwimg_get_size(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 = {
+	bfa_ioc_ct_pll_init,
+	bfa_ioc_ct_firmware_lock,
+	bfa_ioc_ct_firmware_unlock,
+	bfa_ioc_ct_fwimg_get_chunk,
+	bfa_ioc_ct_fwimg_get_size,
+	bfa_ioc_ct_reg_init,
+	bfa_ioc_ct_map_port,
+	bfa_ioc_ct_isr_mode_set,
+	bfa_ioc_ct_notify_hbfail,
+	bfa_ioc_ct_ownership_reset,
+};
+
+/**
+ * Called from bfa_ioc_attach() to map asic specific calls.
+ */
+void
+bfa_ioc_set_ct_hwif(struct bfa_ioc *ioc)
+{
+	ioc->ioc_hwif = &hwif_ct;
+}
+
+static u32 *
+bfa_ioc_ct_fwimg_get_chunk(struct bfa_ioc *ioc, u32 off)
+{
+	return bfi_image_ct_get_chunk(off);
+}
+
+static u32
+bfa_ioc_ct_fwimg_get_size(struct bfa_ioc *ioc)
+{
+	return bfi_image_ct_size;
+}
+
+/**
+ * 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_ioc_ct_fwimg_get_size(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.
+	 */
+	bfa_assert(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 bios boot (flash based) -- do not decrement usage count
+	 */
+	if (!ioc->cna || bfa_ioc_ct_fwimg_get_size(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);
+	bfa_assert(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)
+{
+	char __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)
+{
+	char __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)
+{
+	char __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);
+}
+
+static bfa_status_t
+bfa_ioc_ct_pll_init(struct bfa_ioc *ioc)
+{
+	char __iomem *rb = ioc->pcidev.pci_bar_kva;
+	u32	pll_sclk, pll_fclk, r32;
+
+	/*
+	 *  Hold semaphore so that nobody can access the chip during init.
+	 */
+	bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg);
+
+	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);
+
+	/**
+	 *	For catapult, choose operational mode FC/FCoE
+	 */
+	if (ioc->fcmode) {
+		writel(0, (rb + OP_MODE));
+		writel(__APP_EMS_CMLCKSEL |
+			      __APP_EMS_REFCKBUFEN2 |
+			      __APP_EMS_CHANNEL_SEL, (rb + ETH_MAC_SER_REG));
+	} else {
+		ioc->pllinit = true;
+		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,
+			ioc->ioc_regs.app_pll_slow_ctl_reg);
+	writel(pll_fclk |
+		__APP_PLL_425_LOGIC_SOFT_RESET,
+			ioc->ioc_regs.app_pll_fast_ctl_reg);
+	writel(pll_sclk |
+		__APP_PLL_312_LOGIC_SOFT_RESET | __APP_PLL_312_ENABLE,
+			ioc->ioc_regs.app_pll_slow_ctl_reg);
+	writel(pll_fclk |
+		__APP_PLL_425_LOGIC_SOFT_RESET | __APP_PLL_425_ENABLE,
+			ioc->ioc_regs.app_pll_fast_ctl_reg);
+
+	/**
+	 * Wait for PLLs to lock.
+	 */
+	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, ioc->ioc_regs.app_pll_slow_ctl_reg);
+	writel(pll_fclk |
+		__APP_PLL_425_ENABLE, ioc->ioc_regs.app_pll_fast_ctl_reg);
+
+	writel(__EDRAM_BISTR_START, (rb + MBIST_CTL_REG));
+	udelay(1000);
+	r32 = readl((rb + MBIST_STAT_REG));
+	/*
+	 *  release semaphore.
+	 */
+	bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg);
+
+	return BFA_STATUS_OK;
+}
+
+/**
+ * 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);
+}
+
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/bfa_sm.c net-next-2.6.33-rc5-mod/drivers/net/bna/bfa_sm.c
--- net-next-2.6.33-rc5-orig/drivers/net/bna/bfa_sm.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/bfa_sm.c	2010-02-12 01:39:42.398847000 -0800
@@ -0,0 +1,38 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+/**
+ *  bfasm.c BFA State machine utility functions
+ */
+
+#include "cs/bfa_sm.h"
+
+/**
+ *  cs_sm_api
+ */
+
+int
+bfa_sm_to_state(struct bfa_sm_table *smt, bfa_sm_t sm)
+{
+	int             i = 0;
+
+	while (smt[i].sm && smt[i].sm != sm)
+		i++;
+	return smt[i].state;
+}
+
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/bna_if.c net-next-2.6.33-rc5-mod/drivers/net/bna/bna_if.c
--- net-next-2.6.33-rc5-orig/drivers/net/bna/bna_if.c	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/bna_if.c	2010-02-12 01:39:42.707832000 -0800
@@ -0,0 +1,538 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ *	file bna_if.c BNA Hardware and Firmware Interface
+ */
+#include "cna.h"
+#include "bna.h"
+#include "bna_hwreg.h"
+#include "bna_priv.h"
+#include "bna_iocll.h"
+#include "bna_intr.h"
+#include "bfi/bfi_cee.h"
+#include "protocol/types.h"
+#include "cee/bfa_cee.h"
+#include "bfa_ioc.h"
+
+#define BNA_FLASH_DMA_BUF_SZ	0x010000	/* 64K */
+
+#define DO_CALLBACK(cbfn)	\
+do {				\
+	if (mb_cbfns->cbfn) {      \
+		if (qe && qe->cbarg) {      \
+			(mb_cbfns->cbfn)(qe->cbarg, status);      \
+		} else {					\
+			(mb_cbfns->cbfn)(dev->cbarg, status);      \
+		}			\
+	}			\
+} while (0)
+
+#define DO_DIAG_CALLBACK(cbfn, data)	\
+do {								\
+	if (mb_cbfns->cbfn) {      \
+		if (qe && qe->cbarg) {      \
+			(mb_cbfns->cbfn)(qe->cbarg, data, status);      \
+		} else {					\
+			(mb_cbfns->cbfn)(dev->cbarg, data, status);      \
+		}						\
+	}							\
+} while (0)
+
+#define bna_mbox_q_is_empty(mb_q)		\
+	((mb_q)->producer_index == 		\
+	    (mb_q)->consumer_index)
+
+#define bna_mbox_q_first(mb_q)			\
+	 (&(mb_q)->mb_qe[(mb_q)->consumer_index])
+
+/**
+ * bna_register_callback()
+ *
+ *	  Function called by the driver to register a callback
+ *	  with the BNA
+ *
+ * @param[in] bna_dev   - Opaque handle to BNA private device
+ * @param[in] cbfns	- Structure for the callback functions.
+ * @param[in] cbarg	- Argument to use with the callback
+ *
+ * @return void
+ */
+void bna_register_callback(struct bna_dev *dev, struct bna_mbox_cbfn *cbfns,
+	void *cbarg)
+{
+	memcpy(&dev->mb_cbfns, cbfns, sizeof(dev->mb_cbfns));
+	dev->cbarg = cbarg;
+}
+
+void bna_mbox_q_init(struct bna_mbox_q *q)
+{
+	q->producer_index = q->consumer_index = 0;
+	q->posted = NULL;
+}
+
+static struct bna_mbox_cmd_qe *bna_mbox_enq(struct bna_mbox_q *mbox_q,
+	void *cmd, u32 cmd_len, void *cbarg)
+{
+	struct bna_mbox_cmd_qe *qe;
+
+	if (!BNA_QE_FREE_CNT(mbox_q, BNA_MAX_MBOX_CMD_QUEUE))
+		return NULL;
+
+	qe = &mbox_q->mb_qe[mbox_q->producer_index];
+	BNA_QE_INDX_ADD(mbox_q->producer_index, 1, BNA_MAX_MBOX_CMD_QUEUE);
+	memcpy(&qe->cmd.msg[0], cmd, cmd_len);
+	qe->cmd_len = cmd_len;
+	qe->cbarg = cbarg;
+
+	return qe;
+}
+
+static void bna_mbox_deq(struct bna_mbox_q *mbox_q)
+{
+
+	/* Free one from the head */
+	BNA_QE_INDX_ADD(mbox_q->consumer_index, 1, BNA_MAX_MBOX_CMD_QUEUE);
+}
+
+static void bna_do_stats_update(struct bna_dev *dev, u8 status)
+{
+	if (status != BFI_LL_CMD_OK)
+		return;
+
+	bna_stats_process(dev);
+}
+
+static void bna_do_drv_ll_cb(struct bna_dev *dev, u8 cmd_code,
+	u8 status, struct bna_mbox_cmd_qe *qe)
+{
+	struct bna_mbox_cbfn *mb_cbfns = &dev->mb_cbfns;
+
+	switch (cmd_code) {
+	case BFI_LL_I2H_MAC_UCAST_SET_RSP:
+		DO_CALLBACK(ucast_set_cb);
+		break;
+	case BFI_LL_I2H_MAC_UCAST_ADD_RSP:
+		DO_CALLBACK(ucast_add_cb);
+		break;
+	case BFI_LL_I2H_MAC_UCAST_DEL_RSP:
+		DO_CALLBACK(ucast_del_cb);
+		break;
+	case BFI_LL_I2H_MAC_MCAST_ADD_RSP:
+		DO_CALLBACK(mcast_add_cb);
+		break;
+	case BFI_LL_I2H_MAC_MCAST_DEL_RSP:
+		DO_CALLBACK(mcast_del_cb);
+		break;
+	case BFI_LL_I2H_MAC_MCAST_FILTER_RSP:
+		DO_CALLBACK(mcast_filter_cb);
+		break;
+	case BFI_LL_I2H_MAC_MCAST_DEL_ALL_RSP:
+		DO_CALLBACK(mcast_del_all_cb);
+		break;
+	case BFI_LL_I2H_RXF_PROMISCUOUS_SET_RSP:
+		DO_CALLBACK(set_promisc_cb);
+		break;
+	case BFI_LL_I2H_RXF_DEFAULT_SET_RSP:
+		DO_CALLBACK(set_default_cb);
+		break;
+	case BFI_LL_I2H_TXQ_STOP_RSP:
+		DO_CALLBACK(txq_stop_cb);
+		break;
+	case BFI_LL_I2H_RXQ_STOP_RSP:
+		DO_CALLBACK(rxq_stop_cb);
+		break;
+	case BFI_LL_I2H_PORT_ADMIN_RSP:
+		DO_CALLBACK(port_admin_cb);
+		break;
+	case BFI_LL_I2H_STATS_GET_RSP:
+		bna_do_stats_update(dev, status);
+		DO_CALLBACK(stats_get_cb);
+		break;
+	case BFI_LL_I2H_STATS_CLEAR_RSP:
+		DO_CALLBACK(stats_clr_cb);
+		break;
+	case BFI_LL_I2H_LINK_DOWN_AEN:
+		DO_CALLBACK(link_down_cb);
+		break;
+	case BFI_LL_I2H_LINK_UP_AEN:
+		DO_CALLBACK(link_up_cb);
+		break;
+	case BFI_LL_I2H_DIAG_LOOPBACK_RSP:
+		DO_CALLBACK(set_diag_lb_cb);
+		break;
+	case BFI_LL_I2H_SET_PAUSE_RSP:
+		DO_CALLBACK(set_pause_cb);
+		break;
+	case BFI_LL_I2H_MTU_INFO_RSP:
+		DO_CALLBACK(mtu_info_cb);
+		break;
+	case BFI_LL_I2H_RX_RSP:
+		DO_CALLBACK(rxf_cb);
+		break;
+	default:
+		break;
+	}
+}
+
+static enum bna_status bna_flush_mbox_q(struct bna_dev *dev,
+	u8 wait_for_rsp)
+{
+	struct bna_mbox_q *q;
+	struct bna_mbox_cmd_qe *qe = NULL;
+	u8 msg_id = 0, msg_class = 0;
+
+	q = &dev->mbox_q;
+
+	if (bna_mbox_q_is_empty(q))
+		return BNA_OK;
+
+	if (q->posted != NULL && wait_for_rsp) {
+		qe = (struct bna_mbox_cmd_qe *)(q->posted);
+		/* The driver has to retry */
+		return BNA_BUSY;
+	}
+
+	while (!bna_mbox_q_is_empty(q)) {
+		qe = bna_mbox_q_first(q);
+		msg_class = ((struct bfi_mhdr *)(&qe->cmd.msg[0]))->msg_class;
+		msg_id = ((struct bfi_mhdr *)(&qe->cmd.msg[0]))->msg_id;
+
+		BUG_ON(!(msg_class == BFI_MC_LL));
+		bna_do_drv_ll_cb(dev, BFA_I2HM(msg_id), BFI_LL_CMD_NOT_EXEC,
+				 qe);
+		bna_mbox_deq(q);
+	}
+	/* Reinit the queue, i.e prod = cons = 0; */
+	bna_mbox_q_init(q);
+	return BNA_OK;
+}
+
+enum bna_status bna_cleanup(void *bna_dev)
+{
+	struct bna_dev *dev = (struct bna_dev *) bna_dev;
+
+	dev->msg_ctr = 0;
+
+	memset(&dev->mb_msg, 0, sizeof(dev->mb_msg));
+
+	return bna_flush_mbox_q(dev, 0);
+}
+
+/**
+ * Check both command queues
+ * Write to mailbox if required
+ */
+static enum bna_status bna_chk_n_snd_q(struct bna_dev *dev)
+{
+	struct bna_mbox_cmd_qe *qe = NULL;
+	struct bna_mbox_q *q;
+	struct bfi_mhdr *mh = NULL;
+
+	q = &dev->mbox_q;
+
+	if (bna_mbox_q_is_empty(q))
+		return BNA_OK;
+
+	if (q->posted != NULL)
+		return BNA_OK;
+
+
+	qe = bna_mbox_q_first(q);
+	/* Do not post any more commands if disable pending */
+	if (dev->ioc_disable_pending == 1)
+		return BNA_OK;
+
+
+	mh = ((struct bfi_mhdr *)(&qe->cmd.msg[0]));
+	mh->mtag.i2htok = htons(dev->msg_ctr);
+	dev->msg_ctr++;
+	bfa_ioc_mbox_queue(&dev->ioc, &qe->cmd);
+	q->posted = qe;
+
+	return BNA_OK;
+}
+
+enum bna_status bna_mbox_send(struct bna_dev *dev, void *cmd,
+	u32 cmd_len, void *cbarg)
+{
+	struct bna_mbox_cmd_qe *qe;
+	struct bna_mbox_q *q;
+	struct bfi_mhdr *mh = (struct bfi_mhdr *)cmd;
+
+	if (dev->ioc_disable_pending) {
+		pr_info(
+			       "IOC Disable is pending : Cannot queue Cmd "
+			       "class %d id %d", mh->msg_class, mh->msg_id);
+		return BNA_AGAIN;
+	}
+
+	if (!bfa_ioc_is_operational(&dev->ioc)) {
+		pr_info(
+			       "IOC is not operational : Cannot queue Cmd "
+			       "class %d id %d", mh->msg_class, mh->msg_id);
+		return BNA_AGAIN;
+	}
+
+	q = &dev->mbox_q;
+	qe = bna_mbox_enq(q, cmd, cmd_len, cbarg);
+	if (qe == NULL) {
+		pr_info("No free Mbox Command Element");
+		return BNA_FAIL;
+	}
+	return bna_chk_n_snd_q(dev);
+}
+
+/**
+ * Returns 1, if this is an aen, 0 otherwise
+ */
+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_err_handler(struct bna_dev *dev, u32 intr_status)
+{
+	u32 curr_mask, init_halt;
+
+	pr_info("HW ERROR : INT statux 0x%x on port %d",
+		       intr_status, dev->port);
+
+	if (intr_status & __HALT_STATUS_BITS) {
+		init_halt = readl(dev->ioc.ioc_regs.ll_halt);
+		init_halt &= ~__FW_INIT_HALT_P;
+		writel(init_halt, dev->ioc.ioc_regs.ll_halt);
+	}
+
+	bfa_ioc_error_isr(&dev->ioc);
+
+	/*
+	 * Disable all the bits in interrupt mask, including
+	 * the mbox & error bits.
+	 * This is required so that once h/w error hits, we don't
+	 * get into a loop.
+	 */
+	bna_intx_disable(dev, &curr_mask);
+
+}
+
+void bna_ll_isr(void *llarg, struct bfi_mbmsg *msg)
+{
+	u32 aen = 0;
+	struct bna_dev *dev = (struct bna_dev *) llarg;
+	struct bna_mbox_cmd_qe *qe = NULL;
+	struct bna_mbox_q *mbox_q = NULL;
+	struct bfi_ll_rsp *mb_rsp = NULL;
+
+	mb_rsp = (struct bfi_ll_rsp *)(msg);
+
+	BUG_ON(!(mb_rsp->mh.msg_class == BFI_MC_LL));
+
+	aen = bna_is_aen(mb_rsp->mh.msg_id);
+	if (!aen) {
+		mbox_q = &dev->mbox_q;
+
+		qe = bna_mbox_q_first(mbox_q);
+		if (!qe || (mbox_q->posted != qe)) {
+			pr_info("BNA : Mbox error on %d\n", dev->port);
+			return;
+		}
+
+		if (BFA_I2HM(((struct bfi_mhdr *)(&qe->cmd.msg[0]))->msg_id)
+		    != mb_rsp->mh.msg_id) {
+			pr_info(
+				       "Invalid Rsp Msg %d:%d (Expected %d:%d) "
+				       "on %d", mb_rsp->mh.msg_class,
+				       mb_rsp->mh.msg_id,
+				       ((struct bfi_mhdr *)(&qe->cmd.
+							      msg[0]))->
+				       msg_class,
+				       BFA_I2HM(((struct bfi_mhdr *)
+						 (&qe->cmd.msg[0]))->msg_id),
+				       dev->port);
+			BUG_ON(1);
+			return;
+		}
+		bna_mbox_deq(mbox_q);
+		mbox_q->posted = NULL;
+	}
+
+	memcpy(&dev->mb_msg, msg, sizeof(dev->mb_msg));
+
+	bna_do_drv_ll_cb(dev, mb_rsp->mh.msg_id, mb_rsp->error, qe);
+
+	bna_chk_n_snd_q(dev);
+}
+
+void bna_mbox_err_handler(struct bna_dev *dev, u32 intr_status)
+{
+	if (BNA_IS_ERR_INTR(intr_status)) {
+		bna_err_handler(dev, intr_status);
+		return;
+	}
+
+	if (BNA_IS_MBOX_INTR(intr_status))
+		bfa_ioc_mbox_isr(&dev->ioc);
+}
+
+/**
+ * bna_port_admin()
+ *
+ *   Enable (up) or disable (down) the interface administratively.
+ *
+ * @param[in]  dev	- pointer to BNA device structure
+ * @param[in]  enable - enable/disable the interface.
+ *
+ * @return BNA_OK or BNA_FAIL
+ */
+enum bna_status bna_port_admin(struct bna_dev *bna_dev,
+	enum bna_enable enable)
+{
+	struct bna_dev *dev = (struct bna_dev *) bna_dev;
+	struct bfi_ll_port_admin_req 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.i2htok = 0;
+
+	ll_req.up = enable;
+
+	/* send to f/w */
+	return bna_mbox_send(dev, &ll_req, sizeof(ll_req), dev->cbarg);
+}
+
+/**
+ * bna_port_param_get()
+ *
+ *   Get the port parameters.
+ *
+ * @param[in]   dev	   - pointer to BNA device structure
+ * @param[out]  param_ptr - pointer to where the parameters will be returned.
+ *
+ * @return void
+ */
+void bna_port_param_get(struct bna_dev *dev,
+	struct bna_port_param *param_ptr)
+{
+	param_ptr->supported = true;
+	param_ptr->advertising = true;
+	param_ptr->speed = BNA_LINK_SPEED_10Gbps;
+	param_ptr->duplex = true;
+	param_ptr->autoneg = false;
+	param_ptr->port = dev->port;
+}
+
+/**
+ * bna_port_mac_get()
+ *
+ *   Get the Burnt-in or permanent MAC address.  This function does not return
+ *   the MAC set thru bna_rxf_ucast_mac_set() but the one that is assigned to
+ *   the port upon reset.
+ *
+ * @param[in]  dev	 - pointer to BNA device structure
+ * @param[out] mac_ptr - Burnt-in or permanent MAC address.
+ *
+ * @return void
+ */
+void bna_port_mac_get(struct bna_dev *bna_dev, struct mac *mac_ptr)
+{
+	struct bna_dev *dev = (struct bna_dev *) bna_dev;
+
+	*mac_ptr = bfa_ioc_get_mac(&dev->ioc);
+}
+
+/**
+ *	IOC Integration
+ */
+
+/**
+ *	bfa_iocll_cbfn
+ *	Structure for callbacks to be implemented by
+ *	the driver.
+ */
+static struct bfa_ioc_cbfn bfa_iocll_cbfn = {
+	bna_iocll_enable_cbfn,
+	bna_iocll_disable_cbfn,
+	bna_iocll_hbfail_cbfn,
+	bna_iocll_reset_cbfn
+};
+
+static void bna_iocll_memclaim(struct bna_dev *dev, struct bna_meminfo *mi)
+{
+
+	bfa_ioc_mem_claim(&dev->ioc, mi[BNA_DMA_MEM_T_ATTR].kva,
+			  mi[BNA_DMA_MEM_T_ATTR].dma);
+
+	bfa_ioc_debug_memclaim(&dev->ioc, mi[BNA_KVA_MEM_T_FWTRC].kva);
+}
+
+void bna_iocll_meminfo(struct bna_dev *dev, struct bna_meminfo *mi)
+{
+
+	mi[BNA_DMA_MEM_T_ATTR].len =
+		ALIGN(bfa_ioc_meminfo(), PAGE_SIZE);
+
+	mi[BNA_KVA_MEM_T_FWTRC].len = bfa_ioc_debug_trcsz(true);
+}
+
+void bna_iocll_attach(struct bna_dev *dev, void *bnad,
+	struct bna_meminfo *meminfo, struct bfa_pcidev *pcidev,
+	struct bfa_trc_mod *trcmod, struct bfa_aen *aen,
+	struct bfa_log_mod *logm)
+{
+	struct bfa_ioc *ioc = &dev->ioc;
+	bfa_ioc_attach(&dev->ioc, bnad, &bfa_iocll_cbfn,
+		       trcmod, aen, logm);
+	setup_timer(&ioc->ioc_timer, bnad_ioc_timeout,
+				(unsigned long)ioc);
+	setup_timer(&ioc->hb_timer, bnad_ioc_hb_check,
+				(unsigned long)ioc);
+	setup_timer(&ioc->sem_timer, bnad_ioc_sem_timeout,
+				(unsigned long)ioc);
+	bfa_ioc_pci_init(&dev->ioc, pcidev, BFI_MC_LL);
+
+	bfa_ioc_mbox_regisr(&dev->ioc, BFI_MC_LL, bna_ll_isr, dev);
+	bna_iocll_memclaim(dev, meminfo);
+
+
+}
+
+/**
+ * Either the driver or CAL should serialize
+ * this IOC disable
+ * Currently this is happening indirectly b'cos
+ * bfa_ioc_disable() is not called if there
+ * is an outstanding cmd in the queue, which
+ * could not be flushed.
+ */
+enum bna_status bna_iocll_disable(struct bna_dev *dev)
+{
+	enum bna_status ret;
+
+	dev->ioc_disable_pending = 1;
+	ret = bna_flush_mbox_q(dev, 1);
+	if (ret != BNA_OK) {
+		pr_info("Unable to flush Mbox Queues [%d]",
+			       ret);
+		return ret;
+	}
+
+	bfa_ioc_disable(&dev->ioc);
+	dev->ioc_disable_pending = 0;
+
+	return BNA_OK;
+}
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/bna_iocll.h net-next-2.6.33-rc5-mod/drivers/net/bna/bna_iocll.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/bna_iocll.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/bna_iocll.h	2010-02-12 01:39:43.003779000 -0800
@@ -0,0 +1,60 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef __BNA_IOCLL_H__
+#define __BNA_IOCLL_H__
+
+#include "bfa_ioc.h"
+#include "bfi/bfi_ll.h"
+
+#define BNA_IOC_TIMER_PERIOD BFA_TIMER_FREQ
+
+/*
+ * LL specific IOC functions.
+ */
+void bna_iocll_meminfo(struct bna_dev *bna_dev, struct bna_meminfo *meminfo);
+void bna_iocll_attach(struct bna_dev *bna_dev, void *bnad,
+		      struct bna_meminfo *meminfo, struct bfa_pcidev *pcidev,
+		      struct bfa_trc_mod *trcmod, struct bfa_aen *aen,
+		      struct bfa_log_mod *logmod);
+enum bna_status bna_iocll_disable(struct bna_dev *bna_dev);
+#define bna_iocll_detach(dev) bfa_ioc_detach(&((dev)->ioc))
+#define bna_iocll_enable(dev) bfa_ioc_enable(&((dev)->ioc))
+#define bna_iocll_debug_fwsave(dev, trc_data, trc_len)		\
+	bfa_ioc_debug_fwsave(&((dev)->ioc), (trc_data), (trc_len))
+#define bna_iocll_debug_fwtrc(dev, trc_data, trc_len)		\
+	bfa_ioc_debug_fwtrc(&((dev)->ioc), (trc_data), (trc_len))
+#define bna_iocll_getstats(dev, ioc_stats)	\
+	bfa_ioc_fetch_stats(&((dev)->ioc), (ioc_stats))
+#define bna_iocll_resetstats(dev) bfa_ioc_clr_stats(&((dev)->ioc))
+#define bna_iocll_getattr(dev, ioc_attr)	\
+	bfa_ioc_get_attr(&((dev)->ioc), (ioc_attr))
+#define bna_iocll_getstate(dev)	\
+	bfa_ioc_get_state(&((dev)->ioc))
+#define bna_iocll_get_serial_num(_dev, _serial_num) \
+	bfa_ioc_get_adapter_serial_num(&((_dev)->ioc), (_serial_num))
+
+/**
+ * Callback functions to be implemented by the driver
+ */
+void bna_iocll_enable_cbfn(void *bnad, enum bfa_status status);
+void bna_iocll_disable_cbfn(void *bnad);
+void bna_iocll_hbfail_cbfn(void *bnad);
+void bna_iocll_reset_cbfn(void *bnad);
+
+#endif /* __BNA_IOCLL_H__ */
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/bna_priv.h net-next-2.6.33-rc5-mod/drivers/net/bna/bna_priv.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/bna_priv.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/bna_priv.h	2010-02-12 01:39:43.199770000 -0800
@@ -0,0 +1,472 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * See <license_file> for copyright and licensing details.
+ */
+
+/**
+ *  BNA register access macros.p
+ */
+
+#ifndef __BNA_PRIV_H__
+#define __BNA_PRIV_H__
+
+/**
+	Macros to declare a bit table
+ *
+ * @param[in] _table - bit table to be declared
+ * @param[in] _size  - size in bits
+ */
+#define BNA_BIT_TABLE_DECLARE(_table, _size)	\
+	(u32 _table[(_size) / 32])
+/**
+	Macros to set bits in  a bit table
+ *
+ * @param[in] _table - bit table to be declared
+ * @param[in] _bit	- bit to be set
+ */
+#define BNA_BIT_TABLE_SET(_table, _bit)				\
+	(_table[(_bit) / 32] |= (1 << ((_bit) & (32 - 1))))
+/**
+	Macros to clear bits in  a bit table
+ *
+ * @param[in] _table - bit table to be declared
+ * @param[in] _bit	- bit to be set
+ */
+#define BNA_BIT_TABLE_CLEAR(_table, _bit)	 	 \
+	(_table[(_bit) / 32] &= ~(1 << ((_bit) & (32 - 1))))
+/**
+	Macros to set bits in a 32 bit word
+ *
+ * @param[in] _word  - word in which bit is to be set
+ * @param[in] _bit	- bit to be set (starting at 0)
+ */
+#define BNA_BIT_WORD_SET(_word, _bit)		\
+	((_word) |= (1 << (_bit)))
+/**
+	Macros to clear bits in a 32 bit word
+ *
+ * @param[in] _word  - word in which bit is to be cleared
+ * @param[in] _bit	- bit to be cleared (starting at 0)
+ */
+#define BNA_BIT_WORD_CLEAR(_word, _bit) 	\
+	((_word) &= ~(1 << (_bit)))
+
+/**
+ * BNA_GET_PAGE_NUM()
+ *
+ *  Macro to calculate the page number for the
+ *  memory spanning multiple pages.
+ *
+ * @param[in] _base_page - Base Page Number for memory
+ * @param[in] _offset	- Offset for which page number
+ *			  is calculated
+ */
+#define BNA_GET_PAGE_NUM(_base_page, _offset)	\
+	((_base_page) + ((_offset) >> 15))
+/**
+ * BNA_GET_PAGE_OFFSET()
+ *
+ *  Macro to calculate the page offset for the
+ *  from the base offset (from the top of the block)
+ *  Each page 0x8000 (32KB) in size
+ *
+ * @param[in] _offset - Offset from the top of the block
+ */
+#define BNA_GET_PAGE_OFFSET(_offset)	\
+	((_offset) & 0x7fff)
+
+/**
+ * BNA_GET_WORD_OFFSET()
+ *
+ *  Macro to calculate the address of a word from
+ *  the base address. Needed to access H/W memory
+ *  as 4 byte words. Starts from 0.
+ *
+ * @param[in] _base_offset - Starting offset of the data
+ * @param[in] _word		- Word no. for which address is calculated
+ */
+#define BNA_GET_WORD_OFFSET(_base_offset, _word)	\
+	((_base_offset) + ((_word) << 2))
+/**
+ * BNA_GET_BYTE_OFFSET()
+ *
+ *  Macro to calculate the address of a byte from
+ *  the base address. Most of H/W memory is accessed
+ *  as 4 byte words, so use this macro carefully.
+ *  Starts from 0.
+ *
+ * @param[in] _base_offset	- Starting offset of the data
+ * @param[in] _byte		- Byte no. for which address is calculated
+ */
+#define BNA_GET_BYTE_OFFSET(_base_offset, _byte)	\
+	((_base_offset) + (_byte))
+
+/**
+ * BNA_GET_MEM_BASE_ADDR()
+ *
+ *  Macro to calculate the base address of
+ *  any memory block given the bar0 address
+ *  and the memory base offset
+ *
+ * @param[in] _bar0	 - BARO address
+ * @param[in] _base_offset - Starting offset of the memory
+ */
+#define BNA_GET_MEM_BASE_ADDR(_bar0, _base_offset)	\
+	((_bar0) + HW_BLK_HOST_MEM_ADDR		\
+	  + BNA_GET_PAGE_OFFSET((_base_offset)))
+
+/**
+ *  Structure which maps to Rx FnDb config
+ *  Size : 4 words
+ *  See catapult_spec.pdf, RxA for details
+ */
+struct bna_rx_fndb_ram {
+	u32 rss_prop;
+	u32 size_routing_props;
+	u32 rit_hds_mcastq;
+	u32 control_flags;
+};
+
+/**
+ *  Structure which maps to Tx FnDb config
+ *  Size : 1 word
+ *  See catapult_spec.pdf, TxA for details
+ */
+struct bna_tx_fndb_ram {
+	u32 vlan_n_ctrl_flags;
+};
+
+/**
+ *  Structure which maps to Unicast/Multicast CAM entry
+ *  Size : 2 words
+ *  See catapult_spec.pdf, LUT for details
+ */
+struct bna_cam {
+	u32 cam_mac_addr_47_32;	/*  31:16->res;15:0->MAC */
+	u32 cam_mac_addr_31_0;
+};
+
+/**
+ *  Structure which maps to Unicast RAM entry
+ *  Size : 1 word
+ *  See catapult_spec.pdf, LUT for details
+ */
+struct bna_ucast_mem {
+	u32 ucast_ram_entry;
+};
+
+/**
+ *  Structure which maps to VLAN RAM entry
+ *  Size : 1 word
+ *  See catapult_spec.pdf, LUT for details
+ */
+struct bna_vlan_mem {
+	u32 vlan_ram_entry;
+};
+#define BNA_GET_VLAN_MEM_ENTRY_ADDR(_bar0, _fn_id, _vlan_id)\
+	(_bar0 + (HW_BLK_HOST_MEM_ADDR)  \
+	+ (BNA_GET_PAGE_OFFSET(VLAN_RAM_BASE_OFFSET))	\
+	+ (((_fn_id) & 0x3f) << 9)	  \
+	+ (((_vlan_id) & 0xfe0) >> 3))
+
+/**
+ *  Structure which maps to exact/approx MVT RAM entry
+ *  Size : 4 words
+ *  See catapult_spec.pdf, RxA for details
+ */
+struct bna_mvt_mem {
+	u32 reserved;
+	u32 fc_bit;	/*  31:1->res;0->fc_bit */
+	u32 ll_fn_63_32;	/*  LL fns 63 to 32 */
+	u32 ll_fn_31_0;	/*  LL fns 31 to 0 */
+};
+
+/**
+ *  Structure which maps to RxFn Indirection Table (RIT)
+ *  Size : 1 word
+ *  See catapult_spec.pdf, RxA for details
+ */
+struct bna_rit_mem {
+	u32 rxq_ids;	/*  31:12->res;11:0->two 6 bit RxQ Ids */
+};
+
+/**
+ *  Structure which maps to RSS Table entry
+ *  Size : 16 words
+ *  See catapult_spec.pdf, RAD for details
+ */
+struct bna_rss_mem {
+	u32 type_n_hash;	/* 31:12->res; */
+				/* 11:8 ->protocol type */
+				/* 7:0 ->hash index */
+	u32 hash_key[10];  /* 40 byte Toeplitz hash key */
+	u32 reserved[5];
+};
+
+/**
+ *  Structure which maps to RxQ Memory entry
+ *  Size : 16 words, entries are 32 words apart
+ *	Alternate arrangement of RxQ & TxQ
+ *  See catapult_spec.pdf, HQM for details
+ */
+struct bna_rxq_mem {
+	u32 pg_tbl_addr_lo;
+	u32 pg_tbl_addr_hi;
+	u32 cur_q_entry_lo;
+	u32 cur_q_entry_hi;
+	u32 reserved1;
+	u32 reserved2;
+	u32 pg_cnt_n_prd_ptr;	/* 31:16->total page count */
+					/* 15:0 ->producer pointer (index?) */
+	u32 entry_n_pg_size;	/* 31:16->entry size */
+					/* 15:0 ->page size */
+	u32 sg_n_cq_n_cns_ptr;	/* 31:28->reserved; 27:24->sg count */
+					/* 23:16->CQ; */
+					/* 15:0->consumer pointer(index?) */
+	u32 buf_sz_n_q_state; 	/* 31:16->buffer size; 15:0-> Q state */
+	u32 next_qid;		/* 17:10->next QId */
+	u32 reserved3;
+	u32 reserved4[4];
+};
+
+/**
+ *  Structure which maps to TxQ Memory entry
+ *  Size : 16 words, entries are 32 words apart
+ *		Alternate arrangement of RxQ & TxQ
+ *  See catapult_spec.pdf, HQM for details
+ */
+struct bna_txq_mem {
+	u32 pg_tbl_addr_lo;
+	u32 pg_tbl_addr_hi;
+	u32 cur_q_entry_lo;
+	u32 cur_q_entry_hi;
+	u32 reserved1;
+	u32 reserved2;
+	u32 pg_cnt_n_prd_ptr;	/* 31:16->total page count */
+					/* 15:0 ->producer pointer (index?) */
+	u32 entry_n_pg_size; 	/* 31:16->entry size */
+					/* 15:0 ->page size */
+	u32 int_blk_n_cns_ptr;	/* 31:24->Int Blk Id;  */
+					/* 23:16->Int Blk Offset */
+					/* 15:0 ->consumer pointer(index?) */
+	u32 cns_ptr2_n_q_state;	/* 31:16->cons. ptr 2; 15:0-> Q state */
+	u32 nxt_qid_n_fid_n_pri;	/* 17:10->next */
+					/* QId;9:3->FID;2:0->Priority */
+	u32 wvc_n_cquota_n_rquota; /* 31:24->WI Vector Count; */
+					/* 23:12->Cfg Quota; */
+					/* 11:0 ->Run Quota */
+	u32 reserved3[4];
+};
+
+/**
+ *  Structure which maps to RxQ and TxQ Memory entry
+ *  Size : 32 words, entries are 32 words apart
+ *	Alternate arrangement of RxQ & TxQ
+ *  See catapult_spec.pdf, HQM for details
+ */
+struct bna_rxtx_q_mem {
+	struct bna_rxq_mem rxq;
+	struct bna_txq_mem txq;
+};
+
+/**
+ *  Structure which maps to CQ Memory entry
+ *  Size : 16 words
+ *  See catapult_spec.pdf, HQM for details
+ */
+struct bna_cq_mem {
+	u32 pg_tbl_addr_lo;
+	u32 pg_tbl_addr_hi;
+	u32 cur_q_entry_lo;
+	u32 cur_q_entry_hi;
+	u32 reserved1;
+	u32 reserved2;
+	u32 pg_cnt_n_prd_ptr;	/* 31:16->total page count */
+					/* 15:0 ->producer pointer (index?) */
+	u32 entry_n_pg_size;	/* 31:16->entry size */
+					/* 15:0 ->page size */
+	u32 int_blk_n_cns_ptr;	/* 31:24->Int Blk Id; */
+					/* 23:16->Int Blk Offset */
+					/* 15:0 ->consumer pointer(index?) */
+	u32 q_state;		/* 31:16->reserved; 15:0-> Q state */
+	u32 reserved3[2];
+	u32 reserved4[4];
+};
+
+/**
+ *  Structure which maps to Interrupt Block Memory entry
+ *  Size : 8 words (used: 5 words)
+ *  See catapult_spec.pdf, HQM for details
+ */
+struct bna_ib_blk_mem {
+	u32 host_addr_lo;
+	u32 host_addr_hi;
+	u32 clsc_n_ctrl_n_msix;	/* 31:24->coalescing; */
+					/* 23:16->coalescing cfg; */
+					/* 15:8 ->control; */
+					/* 7:0 ->msix; */
+	u32 ipkt_n_ent_n_idxof;
+	u32 ipkt_cnt_cfg_n_unacked;
+
+	u32 reserved[3];
+};
+
+/**
+ *  Structure which maps to Index Table Block Memory entry
+ *  Size : 1 word
+ *  See catapult_spec.pdf, HQM for details
+ */
+struct bna_idx_tbl_mem {
+	u32 idx;	  /*  31:16->res;15:0->idx; */
+};
+
+/**
+ *  Structure which maps to Doorbell QSet Memory,
+ *  Organization of Doorbell address space for a
+ *  QSet (RxQ, TxQ, Rx IB, Tx IB)
+ *  For Non-VM qset entries are back to back.
+ *  Size : 128 bytes / 4K bytes for Non-VM / VM
+ *  See catapult_spec.pdf, HQM for details
+ */
+struct bna_doorbell_qset {
+	u32 rxq[0x20 >> 2];
+	u32 txq[0x20 >> 2];
+	u32 ib0[0x20 >> 2];
+	u32 ib1[0x20 >> 2];
+};
+
+#define BNA_GET_DOORBELL_BASE_ADDR(_bar0)	\
+	((_bar0) + HQM_DOORBELL_BLK_BASE_ADDR)
+
+/**
+ * BNA_GET_DOORBELL_ENTRY_OFFSET()
+ *
+ *  Macro to calculate the offset of the Doorbell QSet
+ *  in the Non VM case.
+ *  Entries are 128 bytes apart. Does not need a page
+ *  number register for access.
+ *
+ * @param[in] _entry - Entry Number
+ */
+#define BNA_GET_DOORBELL_ENTRY_OFFSET(_entry)		\
+	((HQM_DOORBELL_BLK_BASE_ADDR)		\
+	+ (_entry << 7))
+/**
+ * BNA_GET_DOORBELL_VM_ENTRY_OFFSET()
+ *
+ *  Macro to calculate the offset of the Doorbell QSet
+ *  in the VM case.
+ *  Entries are 4K (0x1000) bytes apart.
+ *  Does not need a page number register for access.
+ *
+ * @param[in] _entry - Entry Number
+ */
+#define BNA_GET_DOORBELL_VM_ENTRY_OFFSET(_entry)	\
+	((HQM_DOORBELL_VM_BLK_BASE_ADDR)	\
+	+ (_entry << 12))
+
+/**
+ * BNA_GET_PSS_SMEM_PAGE_NUM()
+ *
+ *  Macro to calculate the page number of PSS SMEM
+ *  block from a linear offset
+ *
+ * @param[in] _loff - Linear offset from the top of memory
+ */
+#define BNA_GET_PSS_SMEM_PAGE_NUM(_loff)		\
+	(BNA_GET_PAGE_NUM(PSS_SMEM_BLK_PG_NUM, (_loff)))
+/**
+ * BNA_GET_PSS_SMEM_PAGE_OFFSET()
+ *
+ *  Macro to calculate the page offset from the top
+ *  of a PSS SMEM page, for a given linear offset
+ *
+ * @param[in] _loff - Linear offset from the top of memory
+ */
+#define BNA_GET_PSS_SMEM_PAGE_OFFSET(_loff)	 	 \
+	(PSS_SMEM_BLK_MEM_ADDR  		\
+	+ BNA_GET_PAGE_OFFSET((_loff)))
+
+/**
+ * BNA_GET_MBOX_PAGE_NUM()
+ *
+ *  Macro to calculate the page number of HostFn<->LPU/
+ *  LPU<->HostFn Mailbox block from a linear offset
+ *
+ * @param[in] _loff - Linear offset from the top of memory
+ */
+#define BNA_GET_MBOX_PAGE_NUM(_loff)			\
+	(BNA_GET_PAGE_NUM(CPQ_BLK_PG_NUM, (_loff)))
+/**
+ * BNA_GET_HOSTFN_LPU_MBOX_PAGE_OFFSET()
+ *
+ *  Macro to calculate the HostFn<->LPU
+ *  Mailbox page offset from the linear offset
+ *
+ * @param[in] _loff - Linear offset in bytes from the top of memory
+ */
+#define BNA_GET_HOSTFN_LPU_MBOX_PAGE_OFFSET(_loff)		\
+	(HOSTFN_LPU_MBOX + BNA_GET_PAGE_OFFSET((_loff)))
+/**
+ * BNA_GET_LPU_HOSTFN_MBOX_PAGE_OFFSET()
+ *
+ *  Macro to calculate the LPU<->HostFn
+ *  Mailbox page offset from the linear offset
+ *
+ * @param[in] _loff - Linear offset from the top of memory
+ */
+#define BNA_GET_LPU_HOSTFN_MBOX_PAGE_OFFSET(_loff)		\
+	(LPU_HOSTFN_MBOX + BNA_GET_PAGE_OFFSET((_loff)))
+
+#define bna_hw_stats_to_stats cpu_to_be64
+
+void bna_mbox_q_init(struct bna_mbox_q *q);
+
+/**
+ * Interrupt Moderation
+ */
+
+#define BNA_80K_PKT_RATE		 80000
+#define BNA_70K_PKT_RATE		 70000
+#define BNA_60K_PKT_RATE		 60000
+#define BNA_50K_PKT_RATE		 50000
+#define BNA_40K_PKT_RATE		 40000
+#define BNA_30K_PKT_RATE		 30000
+#define BNA_20K_PKT_RATE		 20000
+#define BNA_10K_PKT_RATE		 10000
+
+/**
+ * Defines are in order of decreasing load
+ * i.e BNA_HIGH_LOAD_3 has the highest load
+ * and BNA_LOW_LOAD_3 has the lowest load.
+ */
+
+#define BNA_HIGH_LOAD_4		0 	/* r >= 80 */
+#define BNA_HIGH_LOAD_3		1	/* 60 <= r < 80 */
+#define BNA_HIGH_LOAD_2		2	/* 50 <= r < 60 */
+#define BNA_HIGH_LOAD_1		3	/* 40 <= r < 50 */
+#define BNA_LOW_LOAD_1		4	/* 30 <= r < 40 */
+#define BNA_LOW_LOAD_2		5	/* 20 <= r < 30 */
+#define BNA_LOW_LOAD_3		6	/* 10 <= r < 20 */
+#define BNA_LOW_LOAD_4		7	/* r  <  10 K */
+#define BNA_LOAD_TYPES		BNA_LOW_LOAD_4
+
+#define BNA_BIAS_TYPES		2 	/* small : small > large*2 */
+					/* large : if small is false */
+
+#endif /* __BNA_PRIV_H__ */
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/bnad_defs.h net-next-2.6.33-rc5-mod/drivers/net/bna/bnad_defs.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/bnad_defs.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/bnad_defs.h	2010-02-12 01:39:43.418772000 -0800
@@ -0,0 +1,37 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef _BNAD_DEFS_H_
+#define _BNAD_DEFS_H_
+
+#define BNAD_NAME	"bna"
+#ifdef BNA_DRIVER_VERSION
+#define BNAD_VERSION	BNA_DRIVER_VERSION
+#else
+#define BNAD_VERSION	"2.1.2.1"
+#endif
+
+#ifndef PCI_VENDOR_ID_BROCADE
+#define PCI_VENDOR_ID_BROCADE	0x1657
+#endif
+
+#ifndef PCI_DEVICE_ID_BROCADE_CATAPULT
+#define PCI_DEVICE_ID_BROCADE_CATAPULT	0x0014
+#endif
+
+#endif /* _BNAD_DEFS_H_ */
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/cna.h net-next-2.6.33-rc5-mod/drivers/net/bna/cna.h
--- net-next-2.6.33-rc5-orig/drivers/net/bna/cna.h	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/cna.h	2010-02-12 01:39:43.505770000 -0800
@@ -0,0 +1,41 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef __CNA_H__
+#define __CNA_H__
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/if_ether.h>
+#include <asm/page.h>
+
+#define BFA_VERSION_LEN       64
+
+#define bfa_u32(__pa64)	((__pa64) >> 32)
+
+#define PFX "BNA: "
+#define DPRINTK(klevel, fmt, args...) do {  \
+	printk(KERN_##klevel PFX fmt, ## args);      \
+} while (0)
+
+extern char bfa_version[];
+void bfa_ioc_auto_recover(bool auto_recover);
+
+#endif /* __CNA_H__ */

^ permalink raw reply

* Subject: [PATCH 6/6] bna: Brocade 10Gb Ethernet device driver
From: Rasesh Mody @ 2010-02-12 14:00 UTC (permalink / raw)
  To: netdev; +Cc: adapter_linux_open_src_team

From: Rasesh Mody <rmody@brocade.com>

This is patch 6/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>
---
 Kconfig      |   15 +++++++++++++++
 Makefile     |    1 +
 bna/Makefile |   14 ++++++++++++++
 3 files changed, 30 insertions(+)

diff -ruP net-next-2.6.33-rc5-orig/drivers/net/Kconfig net-next-2.6.33-rc5-mod/drivers/net/Kconfig
--- net-next-2.6.33-rc5-orig/drivers/net/Kconfig	2010-02-05 20:04:14.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/Kconfig	2010-02-12 02:02:46.390419000 -0800
@@ -2792,6 +2792,21 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called qlge.
 
+config BNA
+        tristate "Brocade 1010/1020 10Gb Ethernet Driver support"
+        depends on PCI
+        ---help---
+          This driver supports Brocade 1010/1020 10Gb CEE capable Ethernet
+          cards.
+
+          To compile this driver as a module, choose M here: the module
+          will be called bna.
+
+          For general information and support, go to the Brocade support
+          website at:
+
+          <http://support.brocade.com>
+
 source "drivers/net/sfc/Kconfig"
 
 source "drivers/net/benet/Kconfig"
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/Makefile net-next-2.6.33-rc5-mod/drivers/net/Makefile
--- net-next-2.6.33-rc5-orig/drivers/net/Makefile	2010-02-05 20:04:14.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/Makefile	2010-02-12 02:02:46.431414000 -0800
@@ -32,6 +32,7 @@
 obj-$(CONFIG_JME) += jme.o
 obj-$(CONFIG_BE2NET) += benet/
 obj-$(CONFIG_VMXNET3) += vmxnet3/
+obj-$(CONFIG_BNA) += bna/
 
 gianfar_driver-objs := gianfar.o \
 		gianfar_ethtool.o \
diff -ruP net-next-2.6.33-rc5-orig/drivers/net/bna/Makefile net-next-2.6.33-rc5-mod/drivers/net/bna/Makefile
--- net-next-2.6.33-rc5-orig/drivers/net/bna/Makefile	1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6.33-rc5-mod/drivers/net/bna/Makefile	2010-02-12 02:02:46.567416000 -0800
@@ -0,0 +1,14 @@
+#
+# Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+# All rights reserved.
+#
+
+obj-$(CONFIG_BNA) += bna.o
+
+bna-objs := bnad.o bnad_ethtool.o bna_fn.o bna_if.o bna_queue.o
+bna-objs += bfad_fwimg.o bfa_csdebug.o bfa_sm.o bfa_ioc.o bfa_ioc_ct.o
+bna-objs += bfa_cee.o
+
+EXTRA_CFLAGS := -Idrivers/net/bna -Idrivers/net/bna/include/cee
+EXTRA_CFLAGS +=	-Idrivers/net/bna/include -Idrivers/net/bna/include/cs
+EXTRA_CFLAGS +=	-Idrivers/net/bna/include/cna/pstats

^ permalink raw reply

* Re: [net-next PATCH v3 3/3] net: TCP thin dupack
From: Ilpo Järvinen @ 2010-02-12 11:43 UTC (permalink / raw)
  To: William Allen Simpson
  Cc: Andreas Petlund, netdev@vger.kernel.org, Eric Dumazet,
	Arnd Hannemann, LKML, shemminger, David Miller, damian
In-Reply-To: <4B753943.2080800@gmail.com>

On Fri, 12 Feb 2010, William Allen Simpson wrote:

> Andreas Petlund wrote:
> > diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
> > index 28e0296..c5a73ab 100644
> > --- a/net/ipv4/tcp_input.c
> > +++ b/net/ipv4/tcp_input.c
> > @@ -89,6 +89,8 @@ int sysctl_tcp_frto __read_mostly = 2;
> >  int sysctl_tcp_frto_response __read_mostly;
> >  int sysctl_tcp_nometrics_save __read_mostly;
> >  +int sysctl_tcp_force_thin_dupack __read_mostly;
> > +
> >  int sysctl_tcp_moderate_rcvbuf __read_mostly = 1;
> 
> Where is the sysctl initialized?

...That's offloaded to the compiler, like is done with some of the above 
ones too. There's nothing to worry in that.

-- 
 i.

^ permalink raw reply

* Re: [net-next PATCH v3 3/3] net: TCP thin dupack
From: William Allen Simpson @ 2010-02-12 11:19 UTC (permalink / raw)
  To: Andreas Petlund
  Cc: netdev@vger.kernel.org, Ilpo Järvinen, Eric Dumazet,
	Arnd Hannemann, LKML, shemminger, David Miller, damian
In-Reply-To: <4B73F31F.9000204@simula.no>

Last year, I'm pretty sure I was on record as thinking this is *not* a
good idea.  But at least it now requires a sysctl to turn on, and
should default to off.

Also that naming was a bit dicey.  Now the names are more descriptive,
but the "force" is a bit overkill.

How about:
   NET_TCP_FORCE_THIN_LINEAR_DUPACK -> NET_TCP_THIN_LINEAR_DUPACK
   tcp_force_thin_dupack            -> tcp_thin_linear_dupack
   sysctl_tcp_force_thin_dupack     -> sysctl_tcp_thin_linear_dupack


Andreas Petlund wrote:
> diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
> index 28e0296..c5a73ab 100644
> --- a/net/ipv4/tcp_input.c
> +++ b/net/ipv4/tcp_input.c
> @@ -89,6 +89,8 @@ int sysctl_tcp_frto __read_mostly = 2;
>  int sysctl_tcp_frto_response __read_mostly;
>  int sysctl_tcp_nometrics_save __read_mostly;
>  
> +int sysctl_tcp_force_thin_dupack __read_mostly;
> +
>  int sysctl_tcp_moderate_rcvbuf __read_mostly = 1;

Where is the sysctl initialized?

^ permalink raw reply

* Re: [net-next PATCH v3 2/3] net: TCP thin linear timeouts
From: William Allen Simpson @ 2010-02-12 11:19 UTC (permalink / raw)
  To: Andreas Petlund
  Cc: netdev@vger.kernel.org, Ilpo Järvinen, Eric Dumazet,
	Arnd Hannemann, LKML, shemminger, David Miller, damian
In-Reply-To: <4B73F30D.6040205@simula.no>

Last year, I'm pretty sure I was on record as thinking this is only a
marginally good idea, that would be better at the application layer.

Also that naming was a bit dicey.  Now the names are more descriptive,
but the "force" is a bit overkill.

How about?
   NET_TCP_FORCE_THIN_LINEAR_TIMEOUTS    -> NET_TCP_THIN_LINEAR_TIMEOUTS
   TCP_THIN_LT                           -> TCP_THIN_LINEAR_TIMEOUTS
   TCP_THIN_LT_RETRIES                   -> TCP_THIN_LINEAR_RETRIES
   tcp_force_thin_linear_timeouts        -> tcp_thin_linear_timeouts
   sysctl_tcp_force_thin_linear_timeouts -> sysctl_tcp_thin_linear_timeouts
   tp->thin_lt                           -> tp->thin_lto

The latter mostly traditional "to" for "timeout", as used most everywhere.


Andreas Petlund wrote:
> diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
> index de7d1bf..a682479 100644
> --- a/net/ipv4/tcp_timer.c
> +++ b/net/ipv4/tcp_timer.c
> @@ -29,6 +29,7 @@ int sysctl_tcp_keepalive_intvl __read_mostly = TCP_KEEPALIVE_INTVL;
>  int sysctl_tcp_retries1 __read_mostly = TCP_RETR1;
>  int sysctl_tcp_retries2 __read_mostly = TCP_RETR2;
>  int sysctl_tcp_orphan_retries __read_mostly;
> +int sysctl_tcp_force_thin_linear_timeouts __read_mostly;
>  
Where is the sysctl initialized?


> +	if ((tp->thin_lt || sysctl_tcp_force_thin_linear_timeouts) &&
> +	    tcp_stream_is_thin(sk) && sk->sk_state == TCP_ESTABLISHED &&
> +	    icsk->icsk_retransmits <= TCP_THIN_LT_RETRIES) {

Just for efficiency, I'd reorder this
   +	if (sk->sk_state == TCP_ESTABLISHED &&
   +	    (tp->thin_lt || sysctl_tcp_force_thin_linear_timeouts) &&
   +	    tcp_stream_is_thin(sk) &&
   +	    icsk->icsk_retransmits <= TCP_THIN_LT_RETRIES) {


^ permalink raw reply

* [PATCH net-2.6] net: bug fix for vlan + gro issue
From: Ajit Khaparde @ 2010-02-12  5:34 UTC (permalink / raw)
  To: davem, kaber, herbert; +Cc: Ajit Khaparde, netdev

Traffic doesn't start on a vlan interface when gro is enabled.
Even the tcp handshake was not taking place.
This is because, the eth_type_trans() call before the netif_receive_skb()
in napi_frags_finish() resets the skb->dev to napi->dev from the previously
set vlan netdev interface. This causes the ip_route_input() to drop the
incoming packet considering it as a packet coming from a martian source.

I could repro this on 2.6.32.7 (stable) and 2.6.33-rc7.
With this fix, the traffic starts and the test runs fine. Please review.

Alternatively:
Previously the skb->dev was updated by the driver and I don't know
why it has to be set in eth_type_trans. May be removing that from
eth_type_trans() and expecting the caller to set the skb->dev could be
an alternative fix.

Signed-off-by: Ajit Khaparde <ajitk@serverengines.com>
---
 net/core/dev.c |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/net/core/dev.c b/net/core/dev.c
index be9924f..16aac06 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2761,7 +2761,10 @@ gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb,
 	switch (ret) {
 	case GRO_NORMAL:
 	case GRO_HELD:
-		skb->protocol = eth_type_trans(skb, napi->dev);
+		if (skb->vlan_tci)
+			skb->protocol = eth_type_trans(skb, skb->dev);
+		else
+			skb->protocol = eth_type_trans(skb, napi->dev);
 
 		if (ret == GRO_HELD)
 			skb_gro_pull(skb, -ETH_HLEN);
-- 
1.6.3.3


^ permalink raw reply related

* Re: [PATCH tip/core/rcu 05/13] net: add checking to rcu_dereference() primitives
From: Eric Dumazet @ 2010-02-12  4:15 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: linux-kernel, mingo, laijs, dipankar, akpm, mathieu.desnoyers,
	josh, dvhltc, niv, tglx, peterz, rostedt, Valdis.Kletnieks,
	dhowells, David Miller, netdev
In-Reply-To: <1265932839-25899-5-git-send-email-paulmck@linux.vnet.ibm.com>

Le jeudi 11 février 2010 à 16:00 -0800, Paul E. McKenney a écrit :
> Update rcu_dereference() primitives to use new lockdep-based checking.
> The rcu_dereference() in __in6_dev_get() may be protected either by
> rcu_read_lock() or RTNL, per Eric Dumazet.  The rcu_dereference()
> in __sk_free() is protected by the fact that it is never reached if an
> update could change it.  Check for this by using rcu_dereference_check()
> to verify that the struct sock's ->sk_wmem_alloc counter is zero.
> 
> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>

CC to netdev and David Miller, network maintainer.

Acked-by: Eric Dumazet <eric.dumazet@gmail.com>

Thanks Paul, great work !

> ---
>  include/linux/rtnetlink.h |    3 +++
>  include/net/addrconf.h    |    4 +++-
>  net/core/dev.c            |    2 +-
>  net/core/filter.c         |    6 +++---
>  net/core/rtnetlink.c      |    8 ++++++++
>  net/core/sock.c           |    3 ++-
>  net/decnet/dn_route.c     |   14 +++++++-------
>  net/ipv4/route.c          |   14 +++++++-------
>  net/packet/af_packet.c    |    2 +-
>  9 files changed, 35 insertions(+), 21 deletions(-)
> 
> diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
> index 05330fc..5c52fa4 100644
> --- a/include/linux/rtnetlink.h
> +++ b/include/linux/rtnetlink.h
> @@ -735,6 +735,9 @@ extern void rtnl_lock(void);
>  extern void rtnl_unlock(void);
>  extern int rtnl_trylock(void);
>  extern int rtnl_is_locked(void);
> +#ifdef CONFIG_PROVE_LOCKING
> +extern int lockdep_rtnl_is_held(void);
> +#endif /* #ifdef CONFIG_PROVE_LOCKING */
>  
>  extern void rtnetlink_init(void);
>  extern void __rtnl_unlock(void);
> diff --git a/include/net/addrconf.h b/include/net/addrconf.h
> index 0f7c378..45375b4 100644
> --- a/include/net/addrconf.h
> +++ b/include/net/addrconf.h
> @@ -177,7 +177,9 @@ extern int unregister_inet6addr_notifier(struct notifier_block *nb);
>  static inline struct inet6_dev *
>  __in6_dev_get(struct net_device *dev)
>  {
> -	return rcu_dereference(dev->ip6_ptr);
> +	return rcu_dereference_check(dev->ip6_ptr,
> +				     rcu_read_lock_held() ||
> +				     lockdep_rtnl_is_held());
>  }
>  
>  static inline struct inet6_dev *
> diff --git a/net/core/dev.c b/net/core/dev.c
> index be9924f..0d0ff82 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -2041,7 +2041,7 @@ gso:
>  	rcu_read_lock_bh();
>  
>  	txq = dev_pick_tx(dev, skb);
> -	q = rcu_dereference(txq->qdisc);
> +	q = rcu_dereference_bh(txq->qdisc);
>  
>  #ifdef CONFIG_NET_CLS_ACT
>  	skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_EGRESS);
> diff --git a/net/core/filter.c b/net/core/filter.c
> index 08db7b9..3541aa4 100644
> --- a/net/core/filter.c
> +++ b/net/core/filter.c
> @@ -86,7 +86,7 @@ int sk_filter(struct sock *sk, struct sk_buff *skb)
>  		return err;
>  
>  	rcu_read_lock_bh();
> -	filter = rcu_dereference(sk->sk_filter);
> +	filter = rcu_dereference_bh(sk->sk_filter);
>  	if (filter) {
>  		unsigned int pkt_len = sk_run_filter(skb, filter->insns,
>  				filter->len);
> @@ -521,7 +521,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
>  	}
>  
>  	rcu_read_lock_bh();
> -	old_fp = rcu_dereference(sk->sk_filter);
> +	old_fp = rcu_dereference_bh(sk->sk_filter);
>  	rcu_assign_pointer(sk->sk_filter, fp);
>  	rcu_read_unlock_bh();
>  
> @@ -536,7 +536,7 @@ int sk_detach_filter(struct sock *sk)
>  	struct sk_filter *filter;
>  
>  	rcu_read_lock_bh();
> -	filter = rcu_dereference(sk->sk_filter);
> +	filter = rcu_dereference_bh(sk->sk_filter);
>  	if (filter) {
>  		rcu_assign_pointer(sk->sk_filter, NULL);
>  		sk_filter_delayed_uncharge(sk, filter);
> diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
> index 794bcb8..4c7d3f6 100644
> --- a/net/core/rtnetlink.c
> +++ b/net/core/rtnetlink.c
> @@ -89,6 +89,14 @@ int rtnl_is_locked(void)
>  }
>  EXPORT_SYMBOL(rtnl_is_locked);
>  
> +#ifdef CONFIG_PROVE_LOCKING
> +int lockdep_rtnl_is_held(void)
> +{
> +	return lockdep_is_held(&rtnl_mutex);
> +}
> +EXPORT_SYMBOL(lockdep_rtnl_is_held);
> +#endif /* #ifdef CONFIG_PROVE_LOCKING */
> +
>  static struct rtnl_link *rtnl_msg_handlers[NPROTO];
>  
>  static inline int rtm_msgindex(int msgtype)
> diff --git a/net/core/sock.c b/net/core/sock.c
> index e1f6f22..305cba4 100644
> --- a/net/core/sock.c
> +++ b/net/core/sock.c
> @@ -1073,7 +1073,8 @@ static void __sk_free(struct sock *sk)
>  	if (sk->sk_destruct)
>  		sk->sk_destruct(sk);
>  
> -	filter = rcu_dereference(sk->sk_filter);
> +	filter = rcu_dereference_check(sk->sk_filter,
> +				       atomic_read(&sk->sk_wmem_alloc) == 0);
>  	if (filter) {
>  		sk_filter_uncharge(sk, filter);
>  		rcu_assign_pointer(sk->sk_filter, NULL);
> diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
> index a032840..a7bf03c 100644
> --- a/net/decnet/dn_route.c
> +++ b/net/decnet/dn_route.c
> @@ -1155,8 +1155,8 @@ static int __dn_route_output_key(struct dst_entry **pprt, const struct flowi *fl
>  
>  	if (!(flags & MSG_TRYHARD)) {
>  		rcu_read_lock_bh();
> -		for(rt = rcu_dereference(dn_rt_hash_table[hash].chain); rt;
> -			rt = rcu_dereference(rt->u.dst.dn_next)) {
> +		for (rt = rcu_dereference_bh(dn_rt_hash_table[hash].chain); rt;
> +			rt = rcu_dereference_bh(rt->u.dst.dn_next)) {
>  			if ((flp->fld_dst == rt->fl.fld_dst) &&
>  			    (flp->fld_src == rt->fl.fld_src) &&
>  			    (flp->mark == rt->fl.mark) &&
> @@ -1618,9 +1618,9 @@ int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb)
>  		if (h > s_h)
>  			s_idx = 0;
>  		rcu_read_lock_bh();
> -		for(rt = rcu_dereference(dn_rt_hash_table[h].chain), idx = 0;
> +		for(rt = rcu_dereference_bh(dn_rt_hash_table[h].chain), idx = 0;
>  			rt;
> -			rt = rcu_dereference(rt->u.dst.dn_next), idx++) {
> +			rt = rcu_dereference_bh(rt->u.dst.dn_next), idx++) {
>  			if (idx < s_idx)
>  				continue;
>  			skb_dst_set(skb, dst_clone(&rt->u.dst));
> @@ -1654,12 +1654,12 @@ static struct dn_route *dn_rt_cache_get_first(struct seq_file *seq)
>  
>  	for(s->bucket = dn_rt_hash_mask; s->bucket >= 0; --s->bucket) {
>  		rcu_read_lock_bh();
> -		rt = dn_rt_hash_table[s->bucket].chain;
> +		rt = rcu_dereference_bh(dn_rt_hash_table[s->bucket].chain);
>  		if (rt)
>  			break;
>  		rcu_read_unlock_bh();
>  	}
> -	return rcu_dereference(rt);
> +	return rt;
>  }
>  
>  static struct dn_route *dn_rt_cache_get_next(struct seq_file *seq, struct dn_route *rt)
> @@ -1674,7 +1674,7 @@ static struct dn_route *dn_rt_cache_get_next(struct seq_file *seq, struct dn_rou
>  		rcu_read_lock_bh();
>  		rt = dn_rt_hash_table[s->bucket].chain;
>  	}
> -	return rcu_dereference(rt);
> +	return rcu_dereference_bh(rt);
>  }
>  
>  static void *dn_rt_cache_seq_start(struct seq_file *seq, loff_t *pos)
> diff --git a/net/ipv4/route.c b/net/ipv4/route.c
> index e446496..3476b3b 100644
> --- a/net/ipv4/route.c
> +++ b/net/ipv4/route.c
> @@ -287,12 +287,12 @@ static struct rtable *rt_cache_get_first(struct seq_file *seq)
>  		if (!rt_hash_table[st->bucket].chain)
>  			continue;
>  		rcu_read_lock_bh();
> -		r = rcu_dereference(rt_hash_table[st->bucket].chain);
> +		r = rcu_dereference_bh(rt_hash_table[st->bucket].chain);
>  		while (r) {
>  			if (dev_net(r->u.dst.dev) == seq_file_net(seq) &&
>  			    r->rt_genid == st->genid)
>  				return r;
> -			r = rcu_dereference(r->u.dst.rt_next);
> +			r = rcu_dereference_bh(r->u.dst.rt_next);
>  		}
>  		rcu_read_unlock_bh();
>  	}
> @@ -314,7 +314,7 @@ static struct rtable *__rt_cache_get_next(struct seq_file *seq,
>  		rcu_read_lock_bh();
>  		r = rt_hash_table[st->bucket].chain;
>  	}
> -	return rcu_dereference(r);
> +	return rcu_dereference_bh(r);
>  }
>  
>  static struct rtable *rt_cache_get_next(struct seq_file *seq,
> @@ -2687,8 +2687,8 @@ int __ip_route_output_key(struct net *net, struct rtable **rp,
>  	hash = rt_hash(flp->fl4_dst, flp->fl4_src, flp->oif, rt_genid(net));
>  
>  	rcu_read_lock_bh();
> -	for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
> -		rth = rcu_dereference(rth->u.dst.rt_next)) {
> +	for (rth = rcu_dereference_bh(rt_hash_table[hash].chain); rth;
> +		rth = rcu_dereference_bh(rth->u.dst.rt_next)) {
>  		if (rth->fl.fl4_dst == flp->fl4_dst &&
>  		    rth->fl.fl4_src == flp->fl4_src &&
>  		    rth->fl.iif == 0 &&
> @@ -3006,8 +3006,8 @@ int ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb)
>  		if (!rt_hash_table[h].chain)
>  			continue;
>  		rcu_read_lock_bh();
> -		for (rt = rcu_dereference(rt_hash_table[h].chain), idx = 0; rt;
> -		     rt = rcu_dereference(rt->u.dst.rt_next), idx++) {
> +		for (rt = rcu_dereference_bh(rt_hash_table[h].chain), idx = 0; rt;
> +		     rt = rcu_dereference_bh(rt->u.dst.rt_next), idx++) {
>  			if (!net_eq(dev_net(rt->u.dst.dev), net) || idx < s_idx)
>  				continue;
>  			if (rt_is_expired(rt))
> diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
> index f126d18..939471e 100644
> --- a/net/packet/af_packet.c
> +++ b/net/packet/af_packet.c
> @@ -508,7 +508,7 @@ static inline unsigned int run_filter(struct sk_buff *skb, struct sock *sk,
>  	struct sk_filter *filter;
>  
>  	rcu_read_lock_bh();
> -	filter = rcu_dereference(sk->sk_filter);
> +	filter = rcu_dereference_bh(sk->sk_filter);
>  	if (filter != NULL)
>  		res = sk_run_filter(skb, filter->insns, filter->len);
>  	rcu_read_unlock_bh();

^ permalink raw reply

* Re: [net-next PATCH v3 2/3] net: TCP thin linear timeouts
From: Eric Dumazet @ 2010-02-12  3:52 UTC (permalink / raw)
  To: Andreas Petlund
  Cc: netdev@vger.kernel.org, Ilpo Järvinen, Arnd Hannemann, LKML,
	shemminger, David Miller, william.allen.simpson, damian
In-Reply-To: <4B73F30D.6040205@simula.no>

Le jeudi 11 février 2010 à 13:07 +0100, Andreas Petlund a écrit :
> Major changes:
>       -Possible to disable mechanisms by socket option
>       -Socket option value boundary check
> 
> 
> Signed-off-by: Andreas Petlund <apetlund@simula.no>
> ---
>  include/linux/sysctl.h     |    1 +
>  include/linux/tcp.h        |    3 +++
>  include/net/tcp.h          |    4 ++++
>  net/ipv4/sysctl_net_ipv4.c |    7 +++++++
>  net/ipv4/tcp.c             |    7 +++++++
>  net/ipv4/tcp_timer.c       |   19 ++++++++++++++++++-
>  6 files changed, 40 insertions(+), 1 deletions(-)
> 
> diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
> index 9f236cd..d840d75 100644
> --- a/include/linux/sysctl.h
> +++ b/include/linux/sysctl.h
> @@ -425,6 +425,7 @@ enum
>  	NET_TCP_ALLOWED_CONG_CONTROL=123,
>  	NET_TCP_MAX_SSTHRESH=124,
>  	NET_TCP_FRTO_RESPONSE=125,
> +	NET_TCP_FORCE_THIN_LINEAR_TIMEOUTS=126,
>  };
>  
>  enum {
> diff --git a/include/linux/tcp.h b/include/linux/tcp.h
> index 7fee8a4..67da706 100644
> --- a/include/linux/tcp.h
> +++ b/include/linux/tcp.h
> @@ -103,6 +103,7 @@ enum {
>  #define TCP_CONGESTION		13	/* Congestion control algorithm */
>  #define TCP_MD5SIG		14	/* TCP MD5 Signature (RFC2385) */
>  #define TCP_COOKIE_TRANSACTIONS	15	/* TCP Cookie Transactions */
> +#define TCP_THIN_LT             16      /* Use linear timeouts for thin streams*/
>  
>  /* for TCP_INFO socket option */
>  #define TCPI_OPT_TIMESTAMPS	1
> @@ -341,6 +342,8 @@ struct tcp_sock {
>  	u16	advmss;		/* Advertised MSS			*/
>  	u8	frto_counter;	/* Number of new acks after RTO */
>  	u8	nonagle;	/* Disable Nagle algorithm?             */
> +	u8      thin_lt     : 1,/* Use linear timeouts for thin streams */
> +		thin_undef  : 7;
>  
>  /* RTT measurement */
>  	u32	srtt;		/* smoothed round trip time << 3	*/
> diff --git a/include/net/tcp.h b/include/net/tcp.h
> index e5e2056..bc5856a 100644
> --- a/include/net/tcp.h
> +++ b/include/net/tcp.h
> @@ -196,6 +196,9 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
>  #define TCP_NAGLE_CORK		2	/* Socket is corked	    */
>  #define TCP_NAGLE_PUSH		4	/* Cork is overridden for already queued data */
>  
> +/* TCP thin-stream limits */
> +#define TCP_THIN_LT_RETRIES     6       /* After 6 linear retries, do exp. backoff */
> +
>  extern struct inet_timewait_death_row tcp_death_row;
>  
>  /* sysctl variables for tcp */
> @@ -241,6 +244,7 @@ extern int sysctl_tcp_workaround_signed_windows;
>  extern int sysctl_tcp_slow_start_after_idle;
>  extern int sysctl_tcp_max_ssthresh;
>  extern int sysctl_tcp_cookie_size;
> +extern int sysctl_tcp_force_thin_linear_timeouts;
>  
>  extern atomic_t tcp_memory_allocated;
>  extern struct percpu_counter tcp_sockets_allocated;
> diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
> index 7e3712c..cb2ed35 100644
> --- a/net/ipv4/sysctl_net_ipv4.c
> +++ b/net/ipv4/sysctl_net_ipv4.c
> @@ -576,6 +576,13 @@ static struct ctl_table ipv4_table[] = {
>  		.proc_handler	= proc_dointvec
>  	},
>  	{
> +		.procname       = "tcp_force_thin_linear_timeouts",
> +		.data           = &sysctl_tcp_force_thin_linear_timeouts,
> +		.maxlen         = sizeof(int),
> +		.mode           = 0644,
> +		.proc_handler   = proc_dointvec
> +	},
> +	{
>  		.procname	= "udp_mem",
>  		.data		= &sysctl_udp_mem,
>  		.maxlen		= sizeof(sysctl_udp_mem),
> diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
> index d5d69ea..ce9aeb0 100644
> --- a/net/ipv4/tcp.c
> +++ b/net/ipv4/tcp.c
> @@ -2229,6 +2229,13 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
>  		}
>  		break;
>  
> +	case TCP_THIN_LT:
> +		if (val < 0 || val > 1)
> +			err = -EINVAL;
> +		else
> +			tp->thin_lt = val;
> +		break;
> +
>  	case TCP_CORK:
>  		/* When set indicates to always queue non-full frames.
>  		 * Later the user clears this option and we transmit
> diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
> index de7d1bf..a682479 100644
> --- a/net/ipv4/tcp_timer.c
> +++ b/net/ipv4/tcp_timer.c
> @@ -29,6 +29,7 @@ int sysctl_tcp_keepalive_intvl __read_mostly = TCP_KEEPALIVE_INTVL;
>  int sysctl_tcp_retries1 __read_mostly = TCP_RETR1;
>  int sysctl_tcp_retries2 __read_mostly = TCP_RETR2;
>  int sysctl_tcp_orphan_retries __read_mostly;
> +int sysctl_tcp_force_thin_linear_timeouts __read_mostly;
>  
>  static void tcp_write_timer(unsigned long);
>  static void tcp_delack_timer(unsigned long);
> @@ -415,7 +416,23 @@ void tcp_retransmit_timer(struct sock *sk)
>  	icsk->icsk_retransmits++;
>  
>  out_reset_timer:
> -	icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
> +	/* If stream is thin, use linear timeouts. Since 'icsk_backoff' is
> +	 * used to reset timer, set to 0. Recalculate 'icsk_rto' as this
> +	 * might be increased if the stream oscillates between thin and thick,
> +	 * thus the old value might already be too high compared to the value
> +	 * set by 'tcp_set_rto' in tcp_input.c which resets the rto without
> +	 * backoff. Limit to TCP_THIN_LT_RETRIES before initiating exponential
> +	 * backoff behaviour to avoid continue hammering linear-timeout
> +	 * retransmissions into a black hole*/
> +	if ((tp->thin_lt || sysctl_tcp_force_thin_linear_timeouts) &&
> +	    tcp_stream_is_thin(sk) && sk->sk_state == TCP_ESTABLISHED &&
> +	    icsk->icsk_retransmits <= TCP_THIN_LT_RETRIES) {
> +		icsk->icsk_backoff = 0;
> +		icsk->icsk_rto = min(__tcp_set_rto(tp), TCP_RTO_MAX);
> +	} else {
> +		/* Use normal (exponential) backoff */
> +		icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
> +	}
>  	inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX);
>  	if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1))
>  		__sk_dst_reset(sk);

Hi Anreas

Could you include a section in Documentation/networking/ip-sysctl.txt
about tcp_force_thin_linear_timeouts setting ?

Also, you should provide some documentation to be included in man pages
(man 7 tcp), to Michael Kerrisk ( <mtk.manpages@gmail.com> ), both for
tcp_force_thin_linear_timeouts and TCP_THIN_LT

(Same applies for patch 3/3 and tcp_force_thin_dupack /
TCP_THIN_DUPACK )

^ permalink raw reply

* Re: Note: Atheros ethernet part of compat-wireless too
From: Luis R. Rodriguez @ 2010-02-12  1:09 UTC (permalink / raw)
  To: Tony Espy; +Cc: netdev, Ubuntu Kernel Team
In-Reply-To: <43e72e891002101822h562fc25h996bafdfd87c50c5@mail.gmail.com>

On Wed, Feb 10, 2010 at 6:22 PM, Luis R. Rodriguez <mcgrof@gmail.com> wrote:
> On Wed, Feb 10, 2010 at 10:16 AM, Luis R. Rodriguez <mcgrof@gmail.com> wrote:
>> On Tue, Feb 2, 2010 at 9:26 AM, Tony Espy <espy@canonical.com> wrote:
>>> Luis R. Rodriguez wrote:
>>>>
>>>> I wanted to let you know I threw in the Atheros ethernet drivers as
>>>> part of compat-wireless.
>>>
>>> Luis --
>>>
>>> Does this include support for the Atheros AR8152 PCI-E fast ethernet
>>> adapter?  Also, what's the lead time for this to land in a "stable" release?
>>
>> Figured I'd give you the heads up that the AR8152 is not supported
>> upstream yet. I just got a tarball of the driver that supports this
>> and AR8151. Here's our current upstream support status table:
>>
>> Driver Model-name             vendor:device    Type
>> atl1c  AR8131                 1969:1063        Gigabit Ethernet
>> atl1c  AR8132                 1969:1062        Fast Ethernet
>> atl1   L1                     1969:1048        Gigabit Ethernet
>> atl2   L2                     1969:2048        Fast Ethernet
>> atl1e  AR8121/AR8113/AR8114   1969:1026        Gigabit/Fast Ethernet(driver
>>                                               check one internal register to
>>                                               see if support gigabit)
>> atl1c  AR8151(v1.0)           1969:1073        Gigabit Ethernet(not support
>>                                               in kernel yet)
>> atl1c  AR8152(v1.1)           1969:2060        Fast Ethernet(not support
>>                                               in kernel yet)
>> atl1c  AR8152(v2.0)           1969:2062        Fast Ethernet(not support
>>                                               in kernel yet)
>>
>> I just updated the PCI ID database accordingly. The driver patches for
>> atl1c might be easy, will take a quick look. FWIW the tarball I will
>> be looking at in a few moments is
>>
>> http://kernel.org/pub/linux/kernel/people/mcgrof/ethernet/AR81Family-linux-v1.0.1.6.tar.bz2
>
> OK I got some patch now, will send an RFT.

This worked for me, so compat-wireless-2.6.34 should get AR8152 PCI-E
fast ethernet support as well, assuming of course my patch gets into
2.6.34.

  Luis

-- 
kernel-team mailing list
kernel-team@lists.ubuntu.com
https://lists.ubuntu.com/mailman/listinfo/kernel-team

^ permalink raw reply

* [PATCH] atl1c: Add support for Atheros AR8152 and AR8152
From: Luis R. Rodriguez @ 2010-02-12  0:33 UTC (permalink / raw)
  To: davem, netdev
  Cc: linux-kernel, espy, ken.wu, graham.richards, scott.tan, mcgrof,
	chris.snook, Luis R. Rodriguez

AR8151 is a Gigabit Ethernet device. AR8152 devices are
Fast Ethernet devices, there are two revisions, a 1.0
and a 2.0 revision.

This has been tested against these devices:

Driver	Model-name	vendor:device	Type
atl1c 	AR8131		1969:1063	Gigabit Ethernet
atl1c	AR8132		1969:1062	Fast Ethernet
atl1c	AR8151(v1.0)	1969:1073	Gigabit Ethernet
atl1c	AR8152(v1.1)	1969:2060	Fast Ethernet

This device has no hardware available yet so it goes untested,
but it should work:

atl1c	AR8152(v2.0)	1969:2062	Fast Ethernet

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---

If you are a distribution looking to just suck this patch
into your tree you can wget this:

http://kernel.org/pub/linux/kernel/people/mcgrof/ethernet/AR8152-AR8152.patch

 drivers/net/atl1c/atl1c.h         |   11 +++-
 drivers/net/atl1c/atl1c_ethtool.c |    2 +-
 drivers/net/atl1c/atl1c_hw.c      |   83 +++++++++++++++++++++++----
 drivers/net/atl1c/atl1c_hw.h      |    5 ++
 drivers/net/atl1c/atl1c_main.c    |  115 +++++++++++++++++++++++++++++++++---
 5 files changed, 191 insertions(+), 25 deletions(-)

diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h
index efe5435..84ae905 100644
--- a/drivers/net/atl1c/atl1c.h
+++ b/drivers/net/atl1c/atl1c.h
@@ -313,6 +313,9 @@ enum atl1c_rss_type {
 enum atl1c_nic_type {
 	athr_l1c = 0,
 	athr_l2c = 1,
+	athr_l2c_b,
+	athr_l2c_b2,
+	athr_l1d,
 };
 
 enum atl1c_trans_queue {
@@ -426,8 +429,12 @@ struct atl1c_hw {
 #define ATL1C_ASPM_L1_SUPPORT		0x0100
 #define ATL1C_ASPM_CTRL_MON		0x0200
 #define ATL1C_HIB_DISABLE		0x0400
-#define ATL1C_LINK_CAP_1000M		0x0800
-#define ATL1C_FPGA_VERSION		0x8000
+#define ATL1C_APS_MODE_ENABLE           0x0800
+#define ATL1C_LINK_EXT_SYNC             0x1000
+#define ATL1C_CLK_GATING_EN             0x2000
+#define ATL1C_FPGA_VERSION              0x8000
+	u16 link_cap_flags;
+#define ATL1C_LINK_CAP_1000M		0x0001
 	u16 cmb_tpd;
 	u16 cmb_rrd;
 	u16 cmb_rx_timer; /* 2us resolution */
diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c
index 9b1e0ea..61a0f2f 100644
--- a/drivers/net/atl1c/atl1c_ethtool.c
+++ b/drivers/net/atl1c/atl1c_ethtool.c
@@ -37,7 +37,7 @@ static int atl1c_get_settings(struct net_device *netdev,
 			   SUPPORTED_100baseT_Full |
 			   SUPPORTED_Autoneg       |
 			   SUPPORTED_TP);
-	if (hw->ctrl_flags & ATL1C_LINK_CAP_1000M)
+	if (hw->link_cap_flags & ATL1C_LINK_CAP_1000M)
 		ecmd->supported |= SUPPORTED_1000baseT_Full;
 
 	ecmd->advertising = ADVERTISED_TP;
diff --git a/drivers/net/atl1c/atl1c_hw.c b/drivers/net/atl1c/atl1c_hw.c
index 3e69b94..f1389d6 100644
--- a/drivers/net/atl1c/atl1c_hw.c
+++ b/drivers/net/atl1c/atl1c_hw.c
@@ -70,17 +70,39 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
 	u32 otp_ctrl_data;
 	u32 twsi_ctrl_data;
 	u8  eth_addr[ETH_ALEN];
+	u16 phy_data;
+	bool raise_vol = false;
 
 	/* init */
 	addr[0] = addr[1] = 0;
 	AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
 	if (atl1c_check_eeprom_exist(hw)) {
-		/* Enable OTP CLK */
-		if (!(otp_ctrl_data & OTP_CTRL_CLK_EN)) {
-			otp_ctrl_data |= OTP_CTRL_CLK_EN;
-			AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
-			AT_WRITE_FLUSH(hw);
-			msleep(1);
+		if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b) {
+			/* Enable OTP CLK */
+			if (!(otp_ctrl_data & OTP_CTRL_CLK_EN)) {
+				otp_ctrl_data |= OTP_CTRL_CLK_EN;
+				AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
+				AT_WRITE_FLUSH(hw);
+				msleep(1);
+			}
+		}
+
+		if (hw->nic_type == athr_l2c_b ||
+		    hw->nic_type == athr_l2c_b2 ||
+		    hw->nic_type == athr_l1d) {
+			atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00);
+			if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
+				goto out;
+			phy_data &= 0xFF7F;
+			atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
+
+			atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B);
+			if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
+				goto out;
+			phy_data |= 0x8;
+			atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
+			udelay(20);
+			raise_vol = true;
 		}
 
 		AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
@@ -96,11 +118,31 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
 			return -1;
 	}
 	/* Disable OTP_CLK */
-	if (otp_ctrl_data & OTP_CTRL_CLK_EN) {
-		otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
-		AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
-		AT_WRITE_FLUSH(hw);
-		msleep(1);
+	if ((hw->nic_type == athr_l1c || hw->nic_type == athr_l2c)) {
+		if (otp_ctrl_data & OTP_CTRL_CLK_EN) {
+			otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
+			AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
+			AT_WRITE_FLUSH(hw);
+			msleep(1);
+		}
+	}
+	if (raise_vol) {
+		if (hw->nic_type == athr_l2c_b ||
+		    hw->nic_type == athr_l2c_b2 ||
+		    hw->nic_type == athr_l1d) {
+			atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00);
+			if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
+				goto out;
+			phy_data |= 0x80;
+			atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
+
+			atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B);
+			if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
+				goto out;
+			phy_data &= 0xFFF7;
+			atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
+			udelay(20);
+		}
 	}
 
 	/* maybe MAC-address is from BIOS */
@@ -114,6 +156,7 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
 		return 0;
 	}
 
+out:
 	return -1;
 }
 
@@ -307,7 +350,7 @@ static int atl1c_phy_setup_adv(struct atl1c_hw *hw)
 		mii_adv_data |= ADVERTISE_10HALF  | ADVERTISE_10FULL |
 				ADVERTISE_100HALF | ADVERTISE_100FULL;
 
-	if (hw->ctrl_flags & ATL1C_LINK_CAP_1000M) {
+	if (hw->link_cap_flags & ATL1C_LINK_CAP_1000M) {
 		if (hw->autoneg_advertised & ADVERTISED_1000baseT_Half)
 			mii_giga_ctrl_data |= ADVERTISE_1000HALF;
 		if (hw->autoneg_advertised & ADVERTISED_1000baseT_Full)
@@ -389,6 +432,7 @@ int atl1c_phy_reset(struct atl1c_hw *hw)
 {
 	struct atl1c_adapter *adapter = hw->adapter;
 	struct pci_dev *pdev = adapter->pdev;
+	u16 phy_data;
 	u32 phy_ctrl_data = GPHY_CTRL_DEFAULT;
 	u32 mii_ier_data = IER_LINK_UP | IER_LINK_DOWN;
 	int err;
@@ -404,6 +448,21 @@ int atl1c_phy_reset(struct atl1c_hw *hw)
 	AT_WRITE_FLUSH(hw);
 	msleep(10);
 
+	if (hw->nic_type == athr_l2c_b) {
+		atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x0A);
+		atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data);
+		atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data & 0xDFFF);
+	}
+
+	if (hw->nic_type == athr_l2c_b ||
+	    hw->nic_type == athr_l2c_b2 ||
+	    hw->nic_type == athr_l1d) {
+		atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B);
+		atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data);
+		atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data & 0xFFF7);
+		msleep(20);
+	}
+
 	/*Enable PHY LinkChange Interrupt */
 	err = atl1c_write_phy_reg(hw, MII_IER, mii_ier_data);
 	if (err) {
diff --git a/drivers/net/atl1c/atl1c_hw.h b/drivers/net/atl1c/atl1c_hw.h
index c2c738d..1eeb3ed 100644
--- a/drivers/net/atl1c/atl1c_hw.h
+++ b/drivers/net/atl1c/atl1c_hw.h
@@ -57,6 +57,7 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
 #define REG_LINK_CTRL			0x68
 #define LINK_CTRL_L0S_EN		0x01
 #define LINK_CTRL_L1_EN			0x02
+#define LINK_CTRL_EXT_SYNC		0x80
 
 #define REG_VPD_CAP			0x6C
 #define VPD_CAP_ID_MASK                 0xff
@@ -156,6 +157,8 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
 #define PM_CTRL_PM_REQ_TIMER_SHIFT	20
 #define PM_CTRL_LCKDET_TIMER_MASK	0x3F
 #define PM_CTRL_LCKDET_TIMER_SHIFT	24
+#define PM_CTRL_EN_BUFS_RX_L0S		0x10000000
+#define PM_CTRL_SA_DLY_EN		0x20000000
 #define PM_CTRL_MAC_ASPM_CHK		0x40000000
 #define PM_CTRL_HOTRST			0x80000000
 
@@ -314,6 +317,8 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
 #define MAC_CTRL_BC_EN              	0x4000000
 #define MAC_CTRL_DBG                	0x8000000
 #define MAC_CTRL_SINGLE_PAUSE_EN	0x10000000
+#define MAC_CTRL_HASH_ALG_CRC32		0x20000000
+#define MAC_CTRL_SPEED_MODE_SW		0x40000000
 
 /* MAC IPG/IFG Control Register  */
 #define REG_MAC_IPG_IFG             	0x1484
diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c
index 2f4be59..1fd2f3e 100644
--- a/drivers/net/atl1c/atl1c_main.c
+++ b/drivers/net/atl1c/atl1c_main.c
@@ -21,11 +21,18 @@
 
 #include "atl1c.h"
 
-#define ATL1C_DRV_VERSION "1.0.0.1-NAPI"
+#define ATL1C_DRV_VERSION "1.0.0.2-NAPI"
 char atl1c_driver_name[] = "atl1c";
 char atl1c_driver_version[] = ATL1C_DRV_VERSION;
 #define PCI_DEVICE_ID_ATTANSIC_L2C      0x1062
 #define PCI_DEVICE_ID_ATTANSIC_L1C      0x1063
+#define PCI_DEVICE_ID_ATHEROS_L2C_B	0x2060 /* AR8152 v1.1 Fast 10/100 */
+#define PCI_DEVICE_ID_ATHEROS_L2C_B2	0x2062 /* AR8152 v2.0 Fast 10/100 */
+#define PCI_DEVICE_ID_ATHEROS_L1D	0x1073 /* AR8151 v1.0 Gigabit 1000 */
+
+#define L2CB_V10			0xc0
+#define L2CB_V11			0xc1
+
 /*
  * atl1c_pci_tbl - PCI Device ID Table
  *
@@ -38,6 +45,9 @@ char atl1c_driver_version[] = ATL1C_DRV_VERSION;
 static struct pci_device_id atl1c_pci_tbl[] = {
 	{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1C)},
 	{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2C)},
+	{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L2C_B)},
+	{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L2C_B2)},
+	{PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L1D)},
 	/* required last entry */
 	{ 0 }
 };
@@ -593,11 +603,18 @@ static void atl1c_set_mac_type(struct atl1c_hw *hw)
 	case PCI_DEVICE_ID_ATTANSIC_L2C:
 		hw->nic_type = athr_l2c;
 		break;
-
 	case PCI_DEVICE_ID_ATTANSIC_L1C:
 		hw->nic_type = athr_l1c;
 		break;
-
+	case PCI_DEVICE_ID_ATHEROS_L2C_B:
+		hw->nic_type = athr_l2c_b;
+		break;
+	case PCI_DEVICE_ID_ATHEROS_L2C_B2:
+		hw->nic_type = athr_l2c_b2;
+		break;
+	case PCI_DEVICE_ID_ATHEROS_L1D:
+		hw->nic_type = athr_l1d;
+		break;
 	default:
 		break;
 	}
@@ -620,10 +637,13 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw)
 		hw->ctrl_flags |= ATL1C_ASPM_L0S_SUPPORT;
 	if (link_ctrl_data & LINK_CTRL_L1_EN)
 		hw->ctrl_flags |= ATL1C_ASPM_L1_SUPPORT;
+	if (link_ctrl_data & LINK_CTRL_EXT_SYNC)
+		hw->ctrl_flags |= ATL1C_LINK_EXT_SYNC;
 
-	if (hw->nic_type == athr_l1c) {
+	if (hw->nic_type == athr_l1c ||
+	    hw->nic_type == athr_l1d) {
 		hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON;
-		hw->ctrl_flags |= ATL1C_LINK_CAP_1000M;
+		hw->link_cap_flags |= ATL1C_LINK_CAP_1000M;
 	}
 	return 0;
 }
@@ -1234,21 +1254,92 @@ static void atl1c_disable_l0s_l1(struct atl1c_hw *hw)
 static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
 {
 	u32 pm_ctrl_data;
+	u32 link_ctrl_data;
 
 	AT_READ_REG(hw, REG_PM_CTRL, &pm_ctrl_data);
-
+	AT_READ_REG(hw, REG_LINK_CTRL, &link_ctrl_data);
 	pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1;
+
 	pm_ctrl_data &=  ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
 			PM_CTRL_L1_ENTRY_TIMER_SHIFT);
+	pm_ctrl_data &= ~(PM_CTRL_LCKDET_TIMER_MASK <<
+			  PM_CTRL_LCKDET_TIMER_SHIFT);
 
 	pm_ctrl_data |= PM_CTRL_MAC_ASPM_CHK;
+	pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+	pm_ctrl_data |= PM_CTRL_RBER_EN;
+	pm_ctrl_data |= PM_CTRL_SDES_EN;
+
+	if (hw->nic_type == athr_l2c_b ||
+	    hw->nic_type == athr_l1d ||
+	    hw->nic_type == athr_l2c_b2) {
+		link_ctrl_data &= ~LINK_CTRL_EXT_SYNC;
+		if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE)) {
+			if (hw->nic_type == athr_l2c_b &&
+			    hw->revision_id == L2CB_V10)
+				link_ctrl_data |= LINK_CTRL_EXT_SYNC;
+		}
+
+		AT_WRITE_REG(hw, REG_LINK_CTRL, link_ctrl_data);
+
+		pm_ctrl_data |= PM_CTRL_PCIE_RECV;
+		pm_ctrl_data |= AT_ASPM_L1_TIMER << PM_CTRL_PM_REQ_TIMER_SHIFT;
+		pm_ctrl_data &= ~PM_CTRL_EN_BUFS_RX_L0S;
+		pm_ctrl_data &= ~PM_CTRL_SA_DLY_EN;
+		pm_ctrl_data &= ~PM_CTRL_HOTRST;
+		pm_ctrl_data |= 1 << PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+		pm_ctrl_data |= PM_CTRL_SERDES_PD_EX_L1;
+	}
 
 	if (linkup) {
-		pm_ctrl_data |= PM_CTRL_SERDES_PLL_L1_EN;
-		pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1;
+		pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+		pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
+		if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT)
+			pm_ctrl_data |= PM_CTRL_ASPM_L1_EN;
+		if (hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT)
+			pm_ctrl_data |= PM_CTRL_ASPM_L0S_EN;
+
+		if (hw->nic_type == athr_l2c_b ||
+		    hw->nic_type == athr_l1d ||
+		    hw->nic_type == athr_l2c_b2) {
+			if (hw->nic_type == athr_l2c_b)
+				if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE))
+					pm_ctrl_data &= PM_CTRL_ASPM_L0S_EN;
+			pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN;
+			pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN;
+			pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
+			pm_ctrl_data |= PM_CTRL_CLK_SWH_L1;
+			if (hw->adapter->link_speed == SPEED_100 ||
+			    hw->adapter->link_speed == SPEED_1000) {
+				pm_ctrl_data &=
+					~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
+					  PM_CTRL_L1_ENTRY_TIMER_SHIFT);
+				if (hw->nic_type == athr_l1d)
+					pm_ctrl_data |= 0xF <<
+						PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+				else
+					pm_ctrl_data |= 7 <<
+						PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+			}
+		} else {
+			pm_ctrl_data |= PM_CTRL_SERDES_L1_EN;
+			pm_ctrl_data |= PM_CTRL_SERDES_PLL_L1_EN;
+			pm_ctrl_data |= PM_CTRL_SERDES_BUDS_RX_L1_EN;
+			pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1;
+			pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
+			pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+		}
+		atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
+		if (hw->adapter->link_speed == SPEED_10)
+			if (hw->nic_type == athr_l1d)
+				atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0xB69D);
+			else
+				atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD);
+		else if (hw->adapter->link_speed == SPEED_100)
+			atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB2DD);
+		else
+			atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x96DD);
 
-		pm_ctrl_data |= PM_CTRL_SERDES_BUDS_RX_L1_EN;
-		pm_ctrl_data |= PM_CTRL_SERDES_L1_EN;
 	} else {
 		pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
 		pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN;
@@ -1302,6 +1393,10 @@ static void atl1c_setup_mac_ctrl(struct atl1c_adapter *adapter)
 		mac_ctrl_data |= MAC_CTRL_MC_ALL_EN;
 
 	mac_ctrl_data |= MAC_CTRL_SINGLE_PAUSE_EN;
+	if (hw->nic_type == athr_l1d || hw->nic_type == athr_l2c_b2) {
+		mac_ctrl_data |= MAC_CTRL_SPEED_MODE_SW;
+		mac_ctrl_data |= MAC_CTRL_HASH_ALG_CRC32;
+	}
 	AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
 }
 
-- 
1.6.3.3

^ permalink raw reply related

* [PATCH] ethtool: allow non-admin user to read GRO settings.
From: Stephen Hemminger @ 2010-02-11 23:48 UTC (permalink / raw)
  To: David Miller, Herbert Xu; +Cc: netdev

Looks like an oversight in GRO design.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

--- a/net/core/ethtool.c	2010-02-11 15:45:32.480296094 -0800
+++ b/net/core/ethtool.c	2010-02-11 15:46:34.669670657 -0800
@@ -927,6 +927,7 @@ int dev_ethtool(struct net *net, struct 
 	case ETHTOOL_GPERMADDR:
 	case ETHTOOL_GUFO:
 	case ETHTOOL_GGSO:
+	case ETHTOOL_GGRO:
 	case ETHTOOL_GFLAGS:
 	case ETHTOOL_GPFLAGS:
 	case ETHTOOL_GRXFH:

^ permalink raw reply

* [PATCH] ixgbe: prevent speculative processing of descriptors before ready
From: Anton Blanchard @ 2010-02-11 23:23 UTC (permalink / raw)
  To: Jeff Kirsher, Jesse Brandeburg, Bruce Allan, Alex Duyck, PJ 
  Cc: netdev, e1000-devel, davem

From: Milton Miller <miltonm@bga.com>

The PowerPC architecture does not require loads to independent bytes to be
ordered without adding an explicit barrier.

In ixgbe_clean_rx_irq we load the status bit then load the packet data.
With packet split disabled if these loads go out of order we get a
stale packet, but we will notice the bad sequence numbers and drop it.

The problem occurs with packet split enabled where the TCP/IP header and data
are in different descriptors. If the reads go out of order we may have data
that doesn't match the TCP/IP header. Since we use hardware checksumming this
bad data is never verified and it makes it all the way to the application.

This bug was found during stress testing and adding this barrier has been shown
to fix it.

Signed-off-by: Milton Miller <miltonm@bga.com>
Signed-off-by: Anton Blanchard <anton@samba.org>
---

This was a nasty bug to hunt down, if people agree with the fix I think
it's a candidate for stable.

Index: work.git/drivers/net/ixgbe/ixgbe_main.c
===================================================================
--- work.git.orig/drivers/net/ixgbe/ixgbe_main.c	2010-02-11 16:24:27.000000000 -0600
+++ work.git/drivers/net/ixgbe/ixgbe_main.c	2010-02-11 16:49:27.000000000 -0600
@@ -806,6 +806,7 @@ static bool ixgbe_clean_rx_irq(struct ix
 			break;
 		(*work_done)++;
 
+		rmb(); /* read descriptor and rx_buffer_info after status DD */
 		if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED) {
 			hdr_info = le16_to_cpu(ixgbe_get_hdr_info(rx_desc));
 			len = (hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >>

^ permalink raw reply

* Re: [PATCH] [V5] net: emaclite: adding MDIO and phy lib support
From: Grant Likely @ 2010-02-11 22:40 UTC (permalink / raw)
  To: John Linn
  Cc: netdev, linuxppc-dev, jgarzik, jwboyer, john.williams,
	Sadanand Mutyala
In-Reply-To: <38677d6a-3f33-483c-8fbe-5f5c46d70140@VA3EHSMHS027.ehs.local>

On Thu, Feb 11, 2010 at 3:12 PM, John Linn <john.linn@xilinx.com> wrote:
> These changes add MDIO and phy lib support to the driver as the
> IP core now supports the MDIO bus.
>
> The MDIO bus and phy are added as a child to the emaclite in the device
> tree as illustrated below.
>
> mdio {
>        #address-cells = <1>;
>        #size-cells = <0>;
>        phy0: phy@7 {
>                compatible = "marvell,88e1111";
>                reg = <7>;
>        } ;
> }
>
> Signed-off-by: Sadanand Mutyala <Sadanand.Mutyala@xilinx.com>
> Signed-off-by: John Linn <john.linn@xilinx.com>

Acked-by: Grant Likely <grant.likely@secretlab.ca>

I've noticed one more problem below, but I'm okay with this being
merged as-is and fixed up with a follow-on patch later.

g.

> +/**
> + * xemaclite_mdio_setup - Register mii_bus for the Emaclite device
> + * @lp:                Pointer to the Emaclite device private data
> + * @ofdev:     Pointer to OF device structure
> + *
> + * This function enables MDIO bus in the Emaclite device and registers a
> + * mii_bus.
> + *
> + * Return:     0 upon success or a negative error upon failure
> + */
> +static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev)
> +{
> +       struct mii_bus *bus;
> +       int rc;
> +       struct resource res;
> +       struct device_node *np = of_get_parent(lp->phy_node);
> +
> +       /* Don't register the MDIO bus if the phy_node or its parent node
> +        * can't be found.
> +        */
> +       if (!np)
> +               return -ENODEV;

This doesn't make sense.  The MDIO bus registration should not be
conditional on whether or not this particular xemaclite instance has a
phy on this particular bus.  Instead of following the mac
--(phandle)--> phy-device --(parent)--> mdio node linkage, this
function should look at the mac nodes children to find the mdio node.

In fact, now that I think about it, the code is actually dangerous,
because it may try and register a different mdio bus node as its own.

> +
> +       /* Enable the MDIO bus by asserting the enable bit in MDIO Control
> +        * register.
> +        */
> +       out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET,
> +                XEL_MDIOCTRL_MDIOEN_MASK);
> +
> +       bus = mdiobus_alloc();
> +       if (!bus)
> +               return -ENOMEM;
> +
> +       of_address_to_resource(np, 0, &res);
> +       snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
> +                (unsigned long long)res.start);
> +       bus->priv = lp;
> +       bus->name = "Xilinx Emaclite MDIO";
> +       bus->read = xemaclite_mdio_read;
> +       bus->write = xemaclite_mdio_write;
> +       bus->reset = xemaclite_mdio_reset;
> +       bus->parent = dev;
> +       bus->irq = lp->mdio_irqs; /* preallocated IRQ table */
> +
> +       lp->mii_bus = bus;
> +
> +       rc = of_mdiobus_register(bus, np);
> +       if (rc)
> +               goto err_register;
> +
> +       return 0;
> +
> +err_register:
> +       mdiobus_free(bus);
> +       return rc;
> +}


-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [PATCH] mlx4: replace the dma_sync_single_range_for_cpu/device API
From: Roland Dreier @ 2010-02-11 22:31 UTC (permalink / raw)
  To: David Miller; +Cc: fujita.tomonori, netdev, rolandd, eli, linux-kernel
In-Reply-To: <20100204.210939.133998827.davem@davemloft.net>

 > > There are only two users of the dma_sync_single_range_for_cpu/device
 > > API in mainline (mlx4 and ssb). The
 > > dma_sync_single_range_for_cpu/device API has never been documented and
 > > the dma_sync_single_for_cpu/device API also support a partial sync.
 > > 
 > > This converts mlx4 to use the dma_sync_single_for_cpu/device API
 > > (preparations for the removal of the dma_sync_single_range_for_cpu/device API).
 > > 
 > > Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
 > 
 > Acked-by: David S. Miller <davem@davemloft.net>

Dave, please go ahead and merge this -- this affects the mlx4 ethernet
driver, so it's your area anyway.
-- 
Roland Dreier  <rolandd@cisco.com>
For corporate legal information go to:
http://www.cisco.com/web/about/doing_business/legal/cri/index.html

^ permalink raw reply

* [PATCH] [V5] net: emaclite: adding MDIO and phy lib support
From: John Linn @ 2010-02-11 22:12 UTC (permalink / raw)
  To: netdev, linuxppc-dev, jgarzik, grant.likely, jwboyer
  Cc: John Linn, john.williams, Sadanand Mutyala

These changes add MDIO and phy lib support to the driver as the
IP core now supports the MDIO bus.

The MDIO bus and phy are added as a child to the emaclite in the device
tree as illustrated below.

mdio {
	#address-cells = <1>;
	#size-cells = <0>;
	phy0: phy@7 {
		compatible = "marvell,88e1111";
		reg = <7>;
	} ;
}

Signed-off-by: Sadanand Mutyala <Sadanand.Mutyala@xilinx.com>
Signed-off-by: John Linn <john.linn@xilinx.com>

---

V2 - updated it for Grant's comments, except I couldn't find any tabs
converted to white space issue, let's see if V2 has it also

V3 - updated it for Grant's comments, aded mutex release when a timeout
happens, and added Grant's acked by.

V4 - removed the mutex as I realized the higher layer mdio calls already
use a mutex and there are no internal calls to the driver except in open.
Didn't integrate John W comments since releasing mutex wasn't needed.

V5 - changed calls to mdio functions in the driver to use the phy lib
functions so the correct mdio bus gets used, based on Grant's comments.
---
 drivers/net/Kconfig           |    1 +
 drivers/net/xilinx_emaclite.c |  378 ++++++++++++++++++++++++++++++++++++-----
 2 files changed, 336 insertions(+), 43 deletions(-)

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index dd9a09c..9509a36 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1939,6 +1939,7 @@ config ATL2
 config XILINX_EMACLITE
 	tristate "Xilinx 10/100 Ethernet Lite support"
 	depends on PPC32 || MICROBLAZE
+	select PHYLIB
 	help
 	  This driver supports the 10/100 Ethernet Lite from Xilinx.
 
diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c
index 8c777ba..844da1e 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/xilinx_emaclite.c
@@ -22,11 +22,17 @@
 
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
+#include <linux/of_mdio.h>
+#include <linux/phy.h>
 
 #define DRIVER_NAME "xilinx_emaclite"
 
 /* Register offsets for the EmacLite Core */
 #define XEL_TXBUFF_OFFSET 	0x0		/* Transmit Buffer */
+#define XEL_MDIOADDR_OFFSET	0x07E4		/* MDIO Address Register */
+#define XEL_MDIOWR_OFFSET	0x07E8		/* MDIO Write Data Register */
+#define XEL_MDIORD_OFFSET	0x07EC		/* MDIO Read Data Register */
+#define XEL_MDIOCTRL_OFFSET	0x07F0		/* MDIO Control Register */
 #define XEL_GIER_OFFSET		0x07F8		/* GIE Register */
 #define XEL_TSR_OFFSET		0x07FC		/* Tx status */
 #define XEL_TPLR_OFFSET		0x07F4		/* Tx packet length */
@@ -37,6 +43,22 @@
 
 #define XEL_BUFFER_OFFSET	0x0800		/* Next Tx/Rx buffer's offset */
 
+/* MDIO Address Register Bit Masks */
+#define XEL_MDIOADDR_REGADR_MASK  0x0000001F	/* Register Address */
+#define XEL_MDIOADDR_PHYADR_MASK  0x000003E0	/* PHY Address */
+#define XEL_MDIOADDR_PHYADR_SHIFT 5
+#define XEL_MDIOADDR_OP_MASK	  0x00000400	/* RD/WR Operation */
+
+/* MDIO Write Data Register Bit Masks */
+#define XEL_MDIOWR_WRDATA_MASK	  0x0000FFFF	/* Data to be Written */
+
+/* MDIO Read Data Register Bit Masks */
+#define XEL_MDIORD_RDDATA_MASK	  0x0000FFFF	/* Data to be Read */
+
+/* MDIO Control Register Bit Masks */
+#define XEL_MDIOCTRL_MDIOSTS_MASK 0x00000001	/* MDIO Status Mask */
+#define XEL_MDIOCTRL_MDIOEN_MASK  0x00000008	/* MDIO Enable */
+
 /* Global Interrupt Enable Register (GIER) Bit Masks */
 #define XEL_GIER_GIE_MASK	0x80000000 	/* Global Enable */
 
@@ -87,6 +109,12 @@
  * @reset_lock:		lock used for synchronization
  * @deferred_skb:	holds an skb (for transmission at a later time) when the
  *			Tx buffer is not free
+ * @phy_dev:		pointer to the PHY device
+ * @phy_node:		pointer to the PHY device node
+ * @mii_bus:		pointer to the MII bus
+ * @mdio_irqs:		IRQs table for MDIO bus
+ * @last_link:		last link status
+ * @has_mdio:		indicates whether MDIO is included in the HW
  */
 struct net_local {
 
@@ -100,6 +128,15 @@ struct net_local {
 
 	spinlock_t reset_lock;
 	struct sk_buff *deferred_skb;
+
+	struct phy_device *phy_dev;
+	struct device_node *phy_node;
+
+	struct mii_bus *mii_bus;
+	int mdio_irqs[PHY_MAX_ADDR];
+
+	int last_link;
+	bool has_mdio;
 };
 
 
@@ -431,7 +468,7 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
 }
 
 /**
- * xemaclite_set_mac_address - Set the MAC address for this device
+ * xemaclite_update_address - Update the MAC address in the device
  * @drvdata:	Pointer to the Emaclite device private data
  * @address_ptr:Pointer to the MAC address (MAC address is a 48-bit value)
  *
@@ -441,8 +478,8 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
  * The MAC address can be programmed using any of the two transmit
  * buffers (if configured).
  */
-static void xemaclite_set_mac_address(struct net_local *drvdata,
-				      u8 *address_ptr)
+static void xemaclite_update_address(struct net_local *drvdata,
+				     u8 *address_ptr)
 {
 	void __iomem *addr;
 	u32 reg_data;
@@ -465,6 +502,30 @@ static void xemaclite_set_mac_address(struct net_local *drvdata,
 }
 
 /**
+ * xemaclite_set_mac_address - Set the MAC address for this device
+ * @dev:	Pointer to the network device instance
+ * @addr:	Void pointer to the sockaddr structure
+ *
+ * This function copies the HW address from the sockaddr strucutre to the
+ * net_device structure and updates the address in HW.
+ *
+ * Return:	Error if the net device is busy or 0 if the addr is set
+ *		successfully
+ */
+static int xemaclite_set_mac_address(struct net_device *dev, void *address)
+{
+	struct net_local *lp = (struct net_local *) netdev_priv(dev);
+	struct sockaddr *addr = address;
+
+	if (netif_running(dev))
+		return -EBUSY;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+	xemaclite_update_address(lp, dev->dev_addr);
+	return 0;
+}
+
+/**
  * xemaclite_tx_timeout - Callback for Tx Timeout
  * @dev:	Pointer to the network device
  *
@@ -641,12 +702,219 @@ static irqreturn_t xemaclite_interrupt(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+/**********************/
+/* MDIO Bus functions */
+/**********************/
+
+/**
+ * xemaclite_mdio_wait - Wait for the MDIO to be ready to use
+ * @lp:		Pointer to the Emaclite device private data
+ *
+ * This function waits till the device is ready to accept a new MDIO
+ * request.
+ *
+ * Return:	0 for success or ETIMEDOUT for a timeout
+ */
+
+static int xemaclite_mdio_wait(struct net_local *lp)
+{
+	long end = jiffies + 2;
+
+	/* wait for the MDIO interface to not be busy or timeout
+	   after some time.
+	*/
+	while (in_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET) &
+			XEL_MDIOCTRL_MDIOSTS_MASK) {
+		if (end - jiffies <= 0) {
+			WARN_ON(1);
+			return -ETIMEDOUT;
+		}
+		msleep(1);
+	}
+	return 0;
+}
+
+/**
+ * xemaclite_mdio_read - Read from a given MII management register
+ * @bus:	the mii_bus struct
+ * @phy_id:	the phy address
+ * @reg:	register number to read from
+ *
+ * This function waits till the device is ready to accept a new MDIO
+ * request and then writes the phy address to the MDIO Address register
+ * and reads data from MDIO Read Data register, when its available.
+ *
+ * Return:	Value read from the MII management register
+ */
+static int xemaclite_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+	struct net_local *lp = bus->priv;
+	u32 ctrl_reg;
+	u32 rc;
+
+	if (xemaclite_mdio_wait(lp))
+		return -ETIMEDOUT;
+
+	/* Write the PHY address, register number and set the OP bit in the
+	 * MDIO Address register. Set the Status bit in the MDIO Control
+	 * register to start a MDIO read transaction.
+	 */
+	ctrl_reg = in_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET);
+	out_be32(lp->base_addr + XEL_MDIOADDR_OFFSET,
+		 XEL_MDIOADDR_OP_MASK |
+		 ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg));
+	out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET,
+		 ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK);
+
+	if (xemaclite_mdio_wait(lp))
+		return -ETIMEDOUT;
+
+	rc = in_be32(lp->base_addr + XEL_MDIORD_OFFSET);
+
+	dev_dbg(&lp->ndev->dev,
+		"xemaclite_mdio_read(phy_id=%i, reg=%x) == %x\n",
+		phy_id, reg, rc);
+
+	return rc;
+}
+
+/**
+ * xemaclite_mdio_write - Write to a given MII management register
+ * @bus:	the mii_bus struct
+ * @phy_id:	the phy address
+ * @reg:	register number to write to
+ * @val:	value to write to the register number specified by reg
+ *
+ * This fucntion waits till the device is ready to accept a new MDIO
+ * request and then writes the val to the MDIO Write Data register.
+ */
+static int xemaclite_mdio_write(struct mii_bus *bus, int phy_id, int reg,
+				u16 val)
+{
+	struct net_local *lp = bus->priv;
+	u32 ctrl_reg;
+
+	dev_dbg(&lp->ndev->dev,
+		"xemaclite_mdio_write(phy_id=%i, reg=%x, val=%x)\n",
+		phy_id, reg, val);
+
+	if (xemaclite_mdio_wait(lp))
+		return -ETIMEDOUT;
+
+	/* Write the PHY address, register number and clear the OP bit in the
+	 * MDIO Address register and then write the value into the MDIO Write
+	 * Data register. Finally, set the Status bit in the MDIO Control
+	 * register to start a MDIO write transaction.
+	 */
+	ctrl_reg = in_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET);
+	out_be32(lp->base_addr + XEL_MDIOADDR_OFFSET,
+		 ~XEL_MDIOADDR_OP_MASK &
+		 ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg));
+	out_be32(lp->base_addr + XEL_MDIOWR_OFFSET, val);
+	out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET,
+		 ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK);
+
+	return 0;
+}
+
+/**
+ * xemaclite_mdio_reset - Reset the mdio bus.
+ * @bus:	Pointer to the MII bus
+ *
+ * This function is required(?) as per Documentation/networking/phy.txt.
+ * There is no reset in this device; this function always returns 0.
+ */
+static int xemaclite_mdio_reset(struct mii_bus *bus)
+{
+	return 0;
+}
+
+/**
+ * xemaclite_mdio_setup - Register mii_bus for the Emaclite device
+ * @lp:		Pointer to the Emaclite device private data
+ * @ofdev:	Pointer to OF device structure
+ *
+ * This function enables MDIO bus in the Emaclite device and registers a
+ * mii_bus.
+ *
+ * Return:	0 upon success or a negative error upon failure
+ */
+static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev)
+{
+	struct mii_bus *bus;
+	int rc;
+	struct resource res;
+	struct device_node *np = of_get_parent(lp->phy_node);
+
+	/* Don't register the MDIO bus if the phy_node or its parent node
+	 * can't be found.
+	 */
+	if (!np)
+		return -ENODEV;
+
+	/* Enable the MDIO bus by asserting the enable bit in MDIO Control
+	 * register.
+	 */
+	out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET,
+		 XEL_MDIOCTRL_MDIOEN_MASK);
+
+	bus = mdiobus_alloc();
+	if (!bus)
+		return -ENOMEM;
+
+	of_address_to_resource(np, 0, &res);
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
+		 (unsigned long long)res.start);
+	bus->priv = lp;
+	bus->name = "Xilinx Emaclite MDIO";
+	bus->read = xemaclite_mdio_read;
+	bus->write = xemaclite_mdio_write;
+	bus->reset = xemaclite_mdio_reset;
+	bus->parent = dev;
+	bus->irq = lp->mdio_irqs; /* preallocated IRQ table */
+
+	lp->mii_bus = bus;
+
+	rc = of_mdiobus_register(bus, np);
+	if (rc)
+		goto err_register;
+
+	return 0;
+
+err_register:
+	mdiobus_free(bus);
+	return rc;
+}
+
+/**
+ * xemaclite_adjust_link - Link state callback for the Emaclite device
+ * @ndev: pointer to net_device struct
+ *
+ * There's nothing in the Emaclite device to be configured when the link
+ * state changes. We just print the status.
+ */
+void xemaclite_adjust_link(struct net_device *ndev)
+{
+	struct net_local *lp = netdev_priv(ndev);
+	struct phy_device *phy = lp->phy_dev;
+	int link_state;
+
+	/* hash together the state values to decide if something has changed */
+	link_state = phy->speed | (phy->duplex << 1) | phy->link;
+
+	if (lp->last_link != link_state) {
+		lp->last_link = link_state;
+		phy_print_status(phy);
+	}
+}
+
 /**
  * xemaclite_open - Open the network device
  * @dev:	Pointer to the network device
  *
  * This function sets the MAC address, requests an IRQ and enables interrupts
  * for the Emaclite device and starts the Tx queue.
+ * It also connects to the phy device, if MDIO is included in Emaclite device.
  */
 static int xemaclite_open(struct net_device *dev)
 {
@@ -656,14 +924,47 @@ static int xemaclite_open(struct net_device *dev)
 	/* Just to be safe, stop the device first */
 	xemaclite_disable_interrupts(lp);
 
+	if (lp->phy_node) {
+		u32 bmcr;
+
+		lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node,
+					     xemaclite_adjust_link, 0,
+					     PHY_INTERFACE_MODE_MII);
+		if (!lp->phy_dev) {
+			dev_err(&lp->ndev->dev, "of_phy_connect() failed\n");
+			return -ENODEV;
+		}
+
+		/* EmacLite doesn't support giga-bit speeds */
+		lp->phy_dev->supported &= (PHY_BASIC_FEATURES);
+		lp->phy_dev->advertising = lp->phy_dev->supported;
+
+		/* Don't advertise 1000BASE-T Full/Half duplex speeds */
+		phy_write(lp->phy_dev, MII_CTRL1000, 0);
+
+		/* Advertise only 10 and 100mbps full/half duplex speeds */
+		phy_write(lp->phy_dev, MII_ADVERTISE, ADVERTISE_ALL);
+
+		/* Restart auto negotiation */
+		bmcr = phy_read(lp->phy_dev, MII_BMCR);
+		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+		phy_write(lp->phy_dev, MII_BMCR, bmcr);
+
+		phy_start(lp->phy_dev);
+	}
+
 	/* Set the MAC address each time opened */
-	xemaclite_set_mac_address(lp, dev->dev_addr);
+	xemaclite_update_address(lp, dev->dev_addr);
 
 	/* Grab the IRQ */
 	retval = request_irq(dev->irq, xemaclite_interrupt, 0, dev->name, dev);
 	if (retval) {
 		dev_err(&lp->ndev->dev, "Could not allocate interrupt %d\n",
 			dev->irq);
+		if (lp->phy_dev)
+			phy_disconnect(lp->phy_dev);
+		lp->phy_dev = NULL;
+
 		return retval;
 	}
 
@@ -682,6 +983,7 @@ static int xemaclite_open(struct net_device *dev)
  *
  * This function stops the Tx queue, disables interrupts and frees the IRQ for
  * the Emaclite device.
+ * It also disconnects the phy device associated with the Emaclite device.
  */
 static int xemaclite_close(struct net_device *dev)
 {
@@ -691,6 +993,10 @@ static int xemaclite_close(struct net_device *dev)
 	xemaclite_disable_interrupts(lp);
 	free_irq(dev->irq, dev);
 
+	if (lp->phy_dev)
+		phy_disconnect(lp->phy_dev);
+	lp->phy_dev = NULL;
+
 	return 0;
 }
 
@@ -754,42 +1060,6 @@ static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev)
 }
 
 /**
- * xemaclite_ioctl - Perform IO Control operations on the network device
- * @dev:	Pointer to the network device
- * @rq:		Pointer to the interface request structure
- * @cmd:	IOCTL command
- *
- * The only IOCTL operation supported by this function is setting the MAC
- * address. An error is reported if any other operations are requested.
- *
- * Return:	0 to indicate success, or a negative error for failure.
- */
-static int xemaclite_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	struct net_local *lp = (struct net_local *) netdev_priv(dev);
-	struct hw_addr_data *hw_addr = (struct hw_addr_data *) &rq->ifr_hwaddr;
-
-	switch (cmd) {
-	case SIOCETHTOOL:
-		return -EIO;
-
-	case SIOCSIFHWADDR:
-		dev_err(&lp->ndev->dev, "SIOCSIFHWADDR\n");
-
-		/* Copy MAC address in from user space */
-		copy_from_user((void __force *) dev->dev_addr,
-			       (void __user __force *) hw_addr,
-			       IFHWADDRLEN);
-		xemaclite_set_mac_address(lp, dev->dev_addr);
-		break;
-	default:
-		return -EOPNOTSUPP;
-	}
-
-	return 0;
-}
-
-/**
  * xemaclite_remove_ndev - Free the network device
  * @ndev:	Pointer to the network device to be freed
  *
@@ -840,6 +1110,8 @@ static struct net_device_ops xemaclite_netdev_ops;
  * This function probes for the Emaclite device in the device tree.
  * It initializes the driver data structure and the hardware, sets the MAC
  * address and registers the network device.
+ * It also registers a mii_bus for the Emaclite device, if MDIO is included
+ * in the device.
  *
  * Return:	0, if the driver is bound to the Emaclite device, or
  *		a negative error if there is failure.
@@ -880,6 +1152,7 @@ static int __devinit xemaclite_of_probe(struct of_device *ofdev,
 	}
 
 	dev_set_drvdata(dev, ndev);
+	SET_NETDEV_DEV(ndev, &ofdev->dev);
 
 	ndev->irq = r_irq.start;
 	ndev->mem_start = r_mem.start;
@@ -923,7 +1196,12 @@ static int __devinit xemaclite_of_probe(struct of_device *ofdev,
 	out_be32(lp->base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET, 0);
 
 	/* Set the MAC address in the EmacLite device */
-	xemaclite_set_mac_address(lp, ndev->dev_addr);
+	xemaclite_update_address(lp, ndev->dev_addr);
+
+	lp->phy_node = of_parse_phandle(ofdev->node, "phy-handle", 0);
+	rc = xemaclite_mdio_setup(lp, &ofdev->dev);
+	if (rc)
+		dev_warn(&ofdev->dev, "error registering MDIO bus\n");
 
 	dev_info(dev,
 		 "MAC address is now %2x:%2x:%2x:%2x:%2x:%2x\n",
@@ -972,12 +1250,25 @@ static int __devexit xemaclite_of_remove(struct of_device *of_dev)
 	struct device *dev = &of_dev->dev;
 	struct net_device *ndev = dev_get_drvdata(dev);
 
+	struct net_local *lp = (struct net_local *) netdev_priv(ndev);
+
+	/* Un-register the mii_bus, if configured */
+	if (lp->has_mdio) {
+		mdiobus_unregister(lp->mii_bus);
+		kfree(lp->mii_bus->irq);
+		mdiobus_free(lp->mii_bus);
+		lp->mii_bus = NULL;
+	}
+
 	unregister_netdev(ndev);
 
+	if (lp->phy_node)
+		of_node_put(lp->phy_node);
+	lp->phy_node = NULL;
+
 	release_mem_region(ndev->mem_start, ndev->mem_end-ndev->mem_start + 1);
 
 	xemaclite_remove_ndev(ndev);
-
 	dev_set_drvdata(dev, NULL);
 
 	return 0;
@@ -987,7 +1278,7 @@ static struct net_device_ops xemaclite_netdev_ops = {
 	.ndo_open		= xemaclite_open,
 	.ndo_stop		= xemaclite_close,
 	.ndo_start_xmit		= xemaclite_send,
-	.ndo_do_ioctl		= xemaclite_ioctl,
+	.ndo_set_mac_address	= xemaclite_set_mac_address,
 	.ndo_tx_timeout		= xemaclite_tx_timeout,
 	.ndo_get_stats		= xemaclite_get_stats,
 };
@@ -999,6 +1290,7 @@ static struct of_device_id xemaclite_of_match[] __devinitdata = {
 	{ .compatible = "xlnx,xps-ethernetlite-1.00.a", },
 	{ .compatible = "xlnx,xps-ethernetlite-2.00.a", },
 	{ .compatible = "xlnx,xps-ethernetlite-2.01.a", },
+	{ .compatible = "xlnx,xps-ethernetlite-3.00.a", },
 	{ /* end of list */ },
 };
 MODULE_DEVICE_TABLE(of, xemaclite_of_match);
-- 
1.6.2.1



This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

^ permalink raw reply related

* RE: [PATCH] [V4] net: emaclite: adding MDIO and phy lib support
From: John Linn @ 2010-02-11 21:22 UTC (permalink / raw)
  To: Grant Likely
  Cc: netdev, linuxppc-dev, jgarzik, jwboyer, john.williams,
	Sadanand Mutyala
In-Reply-To: <fa686aa41002111316n13ce32bcyc8e5186c4776e1b4@mail.gmail.com>

> -----Original Message-----
> From: glikely@secretlab.ca [mailto:glikely@secretlab.ca] On Behalf Of Grant Likely
> Sent: Thursday, February 11, 2010 2:16 PM
> To: John Linn
> Cc: netdev@vger.kernel.org; linuxppc-dev@ozlabs.org; jgarzik@pobox.com; jwboyer@linux.vnet.ibm.com;
> john.williams@petalogix.com; Sadanand Mutyala
> Subject: Re: [PATCH] [V4] net: emaclite: adding MDIO and phy lib support
> 
> On Thu, Feb 11, 2010 at 1:52 PM, John Linn <john.linn@xilinx.com> wrote:
> > These changes add MDIO and phy lib support to the driver as the
> > IP core now supports the MDIO bus.
> >
> > The MDIO bus and phy are added as a child to the emaclite in the device
> > tree as illustrated below.
> >
> > mdio {
> >        #address-cells = <1>;
> >        #size-cells = <0>;
> >        phy0: phy@7 {
> >                compatible = "marvell,88e1111";
> >                reg = <7>;
> >        } ;
> > }
> >
> > Signed-off-by: Sadanand Mutyala <Sadanand.Mutyala@xilinx.com>
> > Signed-off-by: John Linn <john.linn@xilinx.com>
> >
> > ---
> >
> > V2 - updated it for Grant's comments, except I couldn't find any tabs
> > converted to white space issue, let's see if V2 has it also
> >
> > V3 - updated it for Grant's comments, aded mutex release when a timeout
> > happens, and added Grant's acked by.
> >
> > V4 - removed the mutex as I realized the higher layer mdio calls already
> > use a mutex and there are no internal calls to the driver except in open.
> > Didn't integrate John W comments since releasing mutex wasn't needed.
> > ---
> >  drivers/net/Kconfig           |    1 +
> >  drivers/net/xilinx_emaclite.c |  381 ++++++++++++++++++++++++++++++++++++-----
> >  2 files changed, 339 insertions(+), 43 deletions(-)
> [...]
> >  /**
> >  * xemaclite_open - Open the network device
> >  * @dev:       Pointer to the network device
> >  *
> >  * This function sets the MAC address, requests an IRQ and enables interrupts
> >  * for the Emaclite device and starts the Tx queue.
> > + * It also connects to the phy device, if MDIO is included in Emaclite device.
> >  */
> >  static int xemaclite_open(struct net_device *dev)
> >  {
> > @@ -656,14 +924,50 @@ static int xemaclite_open(struct net_device *dev)
> >        /* Just to be safe, stop the device first */
> >        xemaclite_disable_interrupts(lp);
> >
> > +       if (lp->phy_node) {
> > +               u32 bmcr;
> > +
> > +               lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node,
> > +                                            xemaclite_adjust_link, 0,
> > +                                            PHY_INTERFACE_MODE_MII);
> > +               if (!lp->phy_dev) {
> > +                       dev_err(&lp->ndev->dev, "of_phy_connect() failed\n");
> > +                       return -ENODEV;
> > +               }
> > +
> > +               /* EmacLite doesn't support giga-bit speeds */
> > +               lp->phy_dev->supported &= (PHY_BASIC_FEATURES);
> > +               lp->phy_dev->advertising = lp->phy_dev->supported;
> > +
> > +               /* Don't advertise 1000BASE-T Full/Half duplex speeds */
> > +               xemaclite_mdio_write(lp->mii_bus, lp->phy_dev->addr,
> > +                                    MII_CTRL1000, 0x00);
> 
> Wait!  No.  This is wrong.  Sorry, I was all ready to ack this patch,
> but I just realized what was bothering me (and I should have clued
> into it earlier).  The driver cannot assume that the PHY is on an
> xemaclite MDIO bus.  It might be on a GPIO driven MDIO bus.  Or
> something else.  Calling xemaclite_mdio_{write,read} is not the right
> thing to do here.
> 
> Instead, the driver should call the phy library function
> phy_write(lp->phy_dev, MII_CTRL1000, 0);  The phylib code will route
> it to the correct mdio bus.  It also takes care of grabbing the mutex
> lock.
> 
> Make this fix, and then I can ack the driver.
> 

Ok, no worries, one more spin, I'm getting pretty good at spinning it.

Will make those changes to the calls in open, retest and respin.

Thanks,
John

> Cheers,
> g.
> 
> 
> --
> Grant Likely, B.Sc., P.Eng.
> Secret Lab Technologies Ltd.


This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.



^ permalink raw reply

* Re: [PATCH] [V4] net: emaclite: adding MDIO and phy lib support
From: Grant Likely @ 2010-02-11 21:16 UTC (permalink / raw)
  To: John Linn
  Cc: netdev, linuxppc-dev, jgarzik, jwboyer, john.williams,
	Sadanand Mutyala
In-Reply-To: <e9ea9b59-9435-4712-a854-2c46046eb08e@SG2EHSMHS005.ehs.local>

On Thu, Feb 11, 2010 at 1:52 PM, John Linn <john.linn@xilinx.com> wrote:
> These changes add MDIO and phy lib support to the driver as the
> IP core now supports the MDIO bus.
>
> The MDIO bus and phy are added as a child to the emaclite in the device
> tree as illustrated below.
>
> mdio {
>        #address-cells = <1>;
>        #size-cells = <0>;
>        phy0: phy@7 {
>                compatible = "marvell,88e1111";
>                reg = <7>;
>        } ;
> }
>
> Signed-off-by: Sadanand Mutyala <Sadanand.Mutyala@xilinx.com>
> Signed-off-by: John Linn <john.linn@xilinx.com>
>
> ---
>
> V2 - updated it for Grant's comments, except I couldn't find any tabs
> converted to white space issue, let's see if V2 has it also
>
> V3 - updated it for Grant's comments, aded mutex release when a timeout
> happens, and added Grant's acked by.
>
> V4 - removed the mutex as I realized the higher layer mdio calls already
> use a mutex and there are no internal calls to the driver except in open.
> Didn't integrate John W comments since releasing mutex wasn't needed.
> ---
>  drivers/net/Kconfig           |    1 +
>  drivers/net/xilinx_emaclite.c |  381 ++++++++++++++++++++++++++++++++++++-----
>  2 files changed, 339 insertions(+), 43 deletions(-)
[...]
>  /**
>  * xemaclite_open - Open the network device
>  * @dev:       Pointer to the network device
>  *
>  * This function sets the MAC address, requests an IRQ and enables interrupts
>  * for the Emaclite device and starts the Tx queue.
> + * It also connects to the phy device, if MDIO is included in Emaclite device.
>  */
>  static int xemaclite_open(struct net_device *dev)
>  {
> @@ -656,14 +924,50 @@ static int xemaclite_open(struct net_device *dev)
>        /* Just to be safe, stop the device first */
>        xemaclite_disable_interrupts(lp);
>
> +       if (lp->phy_node) {
> +               u32 bmcr;
> +
> +               lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node,
> +                                            xemaclite_adjust_link, 0,
> +                                            PHY_INTERFACE_MODE_MII);
> +               if (!lp->phy_dev) {
> +                       dev_err(&lp->ndev->dev, "of_phy_connect() failed\n");
> +                       return -ENODEV;
> +               }
> +
> +               /* EmacLite doesn't support giga-bit speeds */
> +               lp->phy_dev->supported &= (PHY_BASIC_FEATURES);
> +               lp->phy_dev->advertising = lp->phy_dev->supported;
> +
> +               /* Don't advertise 1000BASE-T Full/Half duplex speeds */
> +               xemaclite_mdio_write(lp->mii_bus, lp->phy_dev->addr,
> +                                    MII_CTRL1000, 0x00);

Wait!  No.  This is wrong.  Sorry, I was all ready to ack this patch,
but I just realized what was bothering me (and I should have clued
into it earlier).  The driver cannot assume that the PHY is on an
xemaclite MDIO bus.  It might be on a GPIO driven MDIO bus.  Or
something else.  Calling xemaclite_mdio_{write,read} is not the right
thing to do here.

Instead, the driver should call the phy library function
phy_write(lp->phy_dev, MII_CTRL1000, 0);  The phylib code will route
it to the correct mdio bus.  It also takes care of grabbing the mutex
lock.

Make this fix, and then I can ack the driver.

Cheers,
g.


-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [PATCH v2] net/macvtap: fix reference counting
From: Sridhar Samudrala @ 2010-02-11 21:09 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: Patrick McHardy, Ed Swierk, netdev
In-Reply-To: <201002111655.40349.arnd@arndb.de>

On Thu, 2010-02-11 at 16:55 +0100, Arnd Bergmann wrote:
> The RCU usage in the original code was broken because
> there are cases where we possibly sleep with rcu_read_lock
> held. As a fix, change the macvtap_file_get_queue to
> get a reference on the socket and the netdev instead of
> taking the full rcu_read_lock.
> 
> Also, change macvtap_file_get_queue failure case to
> not require a subsequent macvtap_file_put_queue, as
> pointed out by Ed Swierk.

Looks good.

Acked-by: Sridhar Samudrala <sri@us.ibm.com>

> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> Cc: Ed Swierk <eswierk@aristanetworks.com>
> Cc: Sridhar Samudrala <sri@us.ibm.com>
> ---
>  drivers/net/macvtap.c |   35 ++++++++++++++++++++++-------------
>  1 files changed, 22 insertions(+), 13 deletions(-)
> 
> Please disregard v1 of this patch, I accidentally sent Sridhar's
> patch...
> 
> diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
> index ad1f6ef..fe7656b 100644
> --- a/drivers/net/macvtap.c
> +++ b/drivers/net/macvtap.c
> @@ -70,7 +70,8 @@ static struct cdev macvtap_cdev;
>   * exists.
>   *
>   * The callbacks from macvlan are always done with rcu_read_lock held
> - * already, while in the file_operations, we get it ourselves.
> + * already. For calls from file_operations, we use the rcu_read_lock_bh
> + * to get a reference count on the socket and the device.
>   *
>   * When destroying a queue, we remove the pointers from the file and
>   * from the dev and then synchronize_rcu to make sure no thread is
> @@ -159,13 +160,21 @@ static void macvtap_del_queues(struct net_device *dev)
> 
>  static inline struct macvtap_queue *macvtap_file_get_queue(struct file *file)
>  {
> +	struct macvtap_queue *q;
>  	rcu_read_lock_bh();
> -	return rcu_dereference(file->private_data);
> +	q = rcu_dereference(file->private_data);
> +	if (q) {
> +		sock_hold(&q->sk);
> +		dev_hold(q->vlan->dev);
> +	}
> +	rcu_read_unlock_bh();
> +	return q;
>  }
> 
> -static inline void macvtap_file_put_queue(void)
> +static inline void macvtap_file_put_queue(struct macvtap_queue *q)
>  {
> -	rcu_read_unlock_bh();
> +	sock_put(&q->sk);
> +	dev_put(q->vlan->dev);
>  }
> 
>  /*
> @@ -314,8 +323,8 @@ static unsigned int macvtap_poll(struct file *file, poll_table * wait)
>  	     sock_writeable(&q->sk)))
>  		mask |= POLLOUT | POLLWRNORM;
> 
> +	macvtap_file_put_queue(q);
>  out:
> -	macvtap_file_put_queue();
>  	return mask;
>  }
> 
> @@ -366,8 +375,8 @@ static ssize_t macvtap_aio_write(struct kiocb *iocb, const struct iovec *iv,
> 
>  	result = macvtap_get_user(q, iv, iov_length(iv, count),
>  			      file->f_flags & O_NONBLOCK);
> +	macvtap_file_put_queue(q);
>  out:
> -	macvtap_file_put_queue();
>  	return result;
>  }
> 
> @@ -398,10 +407,8 @@ static ssize_t macvtap_aio_read(struct kiocb *iocb, const struct iovec *iv,
>  	struct sk_buff *skb;
>  	ssize_t len, ret = 0;
> 
> -	if (!q) {
> -		ret = -ENOLINK;
> -		goto out;
> -	}
> +	if (!q)
> +		return -ENOLINK;
> 
>  	len = iov_length(iv, count);
>  	if (len < 0) {
> @@ -437,7 +444,7 @@ static ssize_t macvtap_aio_read(struct kiocb *iocb, const struct iovec *iv,
>  	remove_wait_queue(q->sk.sk_sleep, &wait);
> 
>  out:
> -	macvtap_file_put_queue();
> +	macvtap_file_put_queue(q);
>  	return ret;
>  }
> 
> @@ -468,7 +475,7 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
>  		if (!q)
>  			return -ENOLINK;
>  		memcpy(devname, q->vlan->dev->name, sizeof(devname));
> -		macvtap_file_put_queue();
> +		macvtap_file_put_queue(q);
> 
>  		if (copy_to_user(&ifr->ifr_name, q->vlan->dev->name, IFNAMSIZ) ||
>  		    put_user((TUN_TAP_DEV | TUN_NO_PI), &ifr->ifr_flags))
> @@ -485,8 +492,10 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
>  			return -EFAULT;
> 
>  		q = macvtap_file_get_queue(file);
> +		if (!q)
> +			return -ENOLINK;
>  		q->sk.sk_sndbuf = u;
> -		macvtap_file_put_queue();
> +		macvtap_file_put_queue(q);
>  		return 0;
> 
>  	case TUNSETOFFLOAD:


^ permalink raw reply

* Re: [PATCH] l2tp: Fix a UDP socket reference count bug in the pppol2tp driver
From: David Miller @ 2010-02-11 21:00 UTC (permalink / raw)
  To: jchapman; +Cc: netdev
In-Reply-To: <4B73EABC.5000707@katalix.com>

From: James Chapman <jchapman@katalix.com>
Date: Thu, 11 Feb 2010 11:32:12 +0000

> David Miller wrote:
>> From: James Chapman <jchapman@katalix.com>
>> Date: Wed, 27 Jan 2010 13:14:56 +0000
>> 
>>> Does the above help?
>> 
>> Thanks for the detailed explanation, I'll take another look
>> at this.
> 
> Did you get a chance to look at this?

Not yet, sorry.  Too many other things are preempting this
at the moment.

^ permalink raw reply

* [PATCH] [V4] net: emaclite: adding MDIO and phy lib support
From: John Linn @ 2010-02-11 20:52 UTC (permalink / raw)
  To: netdev, linuxppc-dev, jgarzik, grant.likely, jwboyer
  Cc: john.williams, John Linn, Sadanand Mutyala

These changes add MDIO and phy lib support to the driver as the
IP core now supports the MDIO bus.

The MDIO bus and phy are added as a child to the emaclite in the device
tree as illustrated below.

mdio {
	#address-cells = <1>;
	#size-cells = <0>;
	phy0: phy@7 {
		compatible = "marvell,88e1111";
		reg = <7>;
	} ;
}

Signed-off-by: Sadanand Mutyala <Sadanand.Mutyala@xilinx.com>
Signed-off-by: John Linn <john.linn@xilinx.com>

---

V2 - updated it for Grant's comments, except I couldn't find any tabs
converted to white space issue, let's see if V2 has it also

V3 - updated it for Grant's comments, aded mutex release when a timeout
happens, and added Grant's acked by.

V4 - removed the mutex as I realized the higher layer mdio calls already
use a mutex and there are no internal calls to the driver except in open.
Didn't integrate John W comments since releasing mutex wasn't needed.
---
 drivers/net/Kconfig           |    1 +
 drivers/net/xilinx_emaclite.c |  381 ++++++++++++++++++++++++++++++++++++-----
 2 files changed, 339 insertions(+), 43 deletions(-)

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index dd9a09c..9509a36 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1939,6 +1939,7 @@ config ATL2
 config XILINX_EMACLITE
 	tristate "Xilinx 10/100 Ethernet Lite support"
 	depends on PPC32 || MICROBLAZE
+	select PHYLIB
 	help
 	  This driver supports the 10/100 Ethernet Lite from Xilinx.
 
diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c
index 8c777ba..d294ec5 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/xilinx_emaclite.c
@@ -22,11 +22,17 @@
 
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
+#include <linux/of_mdio.h>
+#include <linux/phy.h>
 
 #define DRIVER_NAME "xilinx_emaclite"
 
 /* Register offsets for the EmacLite Core */
 #define XEL_TXBUFF_OFFSET 	0x0		/* Transmit Buffer */
+#define XEL_MDIOADDR_OFFSET	0x07E4		/* MDIO Address Register */
+#define XEL_MDIOWR_OFFSET	0x07E8		/* MDIO Write Data Register */
+#define XEL_MDIORD_OFFSET	0x07EC		/* MDIO Read Data Register */
+#define XEL_MDIOCTRL_OFFSET	0x07F0		/* MDIO Control Register */
 #define XEL_GIER_OFFSET		0x07F8		/* GIE Register */
 #define XEL_TSR_OFFSET		0x07FC		/* Tx status */
 #define XEL_TPLR_OFFSET		0x07F4		/* Tx packet length */
@@ -37,6 +43,22 @@
 
 #define XEL_BUFFER_OFFSET	0x0800		/* Next Tx/Rx buffer's offset */
 
+/* MDIO Address Register Bit Masks */
+#define XEL_MDIOADDR_REGADR_MASK  0x0000001F	/* Register Address */
+#define XEL_MDIOADDR_PHYADR_MASK  0x000003E0	/* PHY Address */
+#define XEL_MDIOADDR_PHYADR_SHIFT 5
+#define XEL_MDIOADDR_OP_MASK	  0x00000400	/* RD/WR Operation */
+
+/* MDIO Write Data Register Bit Masks */
+#define XEL_MDIOWR_WRDATA_MASK	  0x0000FFFF	/* Data to be Written */
+
+/* MDIO Read Data Register Bit Masks */
+#define XEL_MDIORD_RDDATA_MASK	  0x0000FFFF	/* Data to be Read */
+
+/* MDIO Control Register Bit Masks */
+#define XEL_MDIOCTRL_MDIOSTS_MASK 0x00000001	/* MDIO Status Mask */
+#define XEL_MDIOCTRL_MDIOEN_MASK  0x00000008	/* MDIO Enable */
+
 /* Global Interrupt Enable Register (GIER) Bit Masks */
 #define XEL_GIER_GIE_MASK	0x80000000 	/* Global Enable */
 
@@ -87,6 +109,12 @@
  * @reset_lock:		lock used for synchronization
  * @deferred_skb:	holds an skb (for transmission at a later time) when the
  *			Tx buffer is not free
+ * @phy_dev:		pointer to the PHY device
+ * @phy_node:		pointer to the PHY device node
+ * @mii_bus:		pointer to the MII bus
+ * @mdio_irqs:		IRQs table for MDIO bus
+ * @last_link:		last link status
+ * @has_mdio:		indicates whether MDIO is included in the HW
  */
 struct net_local {
 
@@ -100,6 +128,15 @@ struct net_local {
 
 	spinlock_t reset_lock;
 	struct sk_buff *deferred_skb;
+
+	struct phy_device *phy_dev;
+	struct device_node *phy_node;
+
+	struct mii_bus *mii_bus;
+	int mdio_irqs[PHY_MAX_ADDR];
+
+	int last_link;
+	bool has_mdio;
 };
 
 
@@ -431,7 +468,7 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
 }
 
 /**
- * xemaclite_set_mac_address - Set the MAC address for this device
+ * xemaclite_update_address - Update the MAC address in the device
  * @drvdata:	Pointer to the Emaclite device private data
  * @address_ptr:Pointer to the MAC address (MAC address is a 48-bit value)
  *
@@ -441,8 +478,8 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
  * The MAC address can be programmed using any of the two transmit
  * buffers (if configured).
  */
-static void xemaclite_set_mac_address(struct net_local *drvdata,
-				      u8 *address_ptr)
+static void xemaclite_update_address(struct net_local *drvdata,
+				     u8 *address_ptr)
 {
 	void __iomem *addr;
 	u32 reg_data;
@@ -465,6 +502,30 @@ static void xemaclite_set_mac_address(struct net_local *drvdata,
 }
 
 /**
+ * xemaclite_set_mac_address - Set the MAC address for this device
+ * @dev:	Pointer to the network device instance
+ * @addr:	Void pointer to the sockaddr structure
+ *
+ * This function copies the HW address from the sockaddr strucutre to the
+ * net_device structure and updates the address in HW.
+ *
+ * Return:	Error if the net device is busy or 0 if the addr is set
+ *		successfully
+ */
+static int xemaclite_set_mac_address(struct net_device *dev, void *address)
+{
+	struct net_local *lp = (struct net_local *) netdev_priv(dev);
+	struct sockaddr *addr = address;
+
+	if (netif_running(dev))
+		return -EBUSY;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+	xemaclite_update_address(lp, dev->dev_addr);
+	return 0;
+}
+
+/**
  * xemaclite_tx_timeout - Callback for Tx Timeout
  * @dev:	Pointer to the network device
  *
@@ -641,12 +702,219 @@ static irqreturn_t xemaclite_interrupt(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+/**********************/
+/* MDIO Bus functions */
+/**********************/
+
+/**
+ * xemaclite_mdio_wait - Wait for the MDIO to be ready to use
+ * @lp:		Pointer to the Emaclite device private data
+ *
+ * This function waits till the device is ready to accept a new MDIO
+ * request.
+ *
+ * Return:	0 for success or ETIMEDOUT for a timeout
+ */
+
+static int xemaclite_mdio_wait(struct net_local *lp)
+{
+	long end = jiffies + 2;
+
+	/* wait for the MDIO interface to not be busy or timeout
+	   after some time.
+	*/
+	while (in_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET) &
+			XEL_MDIOCTRL_MDIOSTS_MASK) {
+		if (end - jiffies <= 0) {
+			WARN_ON(1);
+			return -ETIMEDOUT;
+		}
+		msleep(1);
+	}
+	return 0;
+}
+
+/**
+ * xemaclite_mdio_read - Read from a given MII management register
+ * @bus:	the mii_bus struct
+ * @phy_id:	the phy address
+ * @reg:	register number to read from
+ *
+ * This function waits till the device is ready to accept a new MDIO
+ * request and then writes the phy address to the MDIO Address register
+ * and reads data from MDIO Read Data register, when its available.
+ *
+ * Return:	Value read from the MII management register
+ */
+static int xemaclite_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+	struct net_local *lp = bus->priv;
+	u32 ctrl_reg;
+	u32 rc;
+
+	if (xemaclite_mdio_wait(lp))
+		return -ETIMEDOUT;
+
+	/* Write the PHY address, register number and set the OP bit in the
+	 * MDIO Address register. Set the Status bit in the MDIO Control
+	 * register to start a MDIO read transaction.
+	 */
+	ctrl_reg = in_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET);
+	out_be32(lp->base_addr + XEL_MDIOADDR_OFFSET,
+		 XEL_MDIOADDR_OP_MASK |
+		 ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg));
+	out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET,
+		 ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK);
+
+	if (xemaclite_mdio_wait(lp))
+		return -ETIMEDOUT;
+
+	rc = in_be32(lp->base_addr + XEL_MDIORD_OFFSET);
+
+	dev_dbg(&lp->ndev->dev,
+		"xemaclite_mdio_read(phy_id=%i, reg=%x) == %x\n",
+		phy_id, reg, rc);
+
+	return rc;
+}
+
+/**
+ * xemaclite_mdio_write - Write to a given MII management register
+ * @bus:	the mii_bus struct
+ * @phy_id:	the phy address
+ * @reg:	register number to write to
+ * @val:	value to write to the register number specified by reg
+ *
+ * This fucntion waits till the device is ready to accept a new MDIO
+ * request and then writes the val to the MDIO Write Data register.
+ */
+static int xemaclite_mdio_write(struct mii_bus *bus, int phy_id, int reg,
+				u16 val)
+{
+	struct net_local *lp = bus->priv;
+	u32 ctrl_reg;
+
+	dev_dbg(&lp->ndev->dev,
+		"xemaclite_mdio_write(phy_id=%i, reg=%x, val=%x)\n",
+		phy_id, reg, val);
+
+	if (xemaclite_mdio_wait(lp))
+		return -ETIMEDOUT;
+
+	/* Write the PHY address, register number and clear the OP bit in the
+	 * MDIO Address register and then write the value into the MDIO Write
+	 * Data register. Finally, set the Status bit in the MDIO Control
+	 * register to start a MDIO write transaction.
+	 */
+	ctrl_reg = in_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET);
+	out_be32(lp->base_addr + XEL_MDIOADDR_OFFSET,
+		 ~XEL_MDIOADDR_OP_MASK &
+		 ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg));
+	out_be32(lp->base_addr + XEL_MDIOWR_OFFSET, val);
+	out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET,
+		 ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK);
+
+	return 0;
+}
+
+/**
+ * xemaclite_mdio_reset - Reset the mdio bus.
+ * @bus:	Pointer to the MII bus
+ *
+ * This function is required(?) as per Documentation/networking/phy.txt.
+ * There is no reset in this device; this function always returns 0.
+ */
+static int xemaclite_mdio_reset(struct mii_bus *bus)
+{
+	return 0;
+}
+
+/**
+ * xemaclite_mdio_setup - Register mii_bus for the Emaclite device
+ * @lp:		Pointer to the Emaclite device private data
+ * @ofdev:	Pointer to OF device structure
+ *
+ * This function enables MDIO bus in the Emaclite device and registers a
+ * mii_bus.
+ *
+ * Return:	0 upon success or a negative error upon failure
+ */
+static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev)
+{
+	struct mii_bus *bus;
+	int rc;
+	struct resource res;
+	struct device_node *np = of_get_parent(lp->phy_node);
+
+	/* Don't register the MDIO bus if the phy_node or its parent node
+	 * can't be found.
+	 */
+	if (!np)
+		return -ENODEV;
+
+	/* Enable the MDIO bus by asserting the enable bit in MDIO Control
+	 * register.
+	 */
+	out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET,
+		 XEL_MDIOCTRL_MDIOEN_MASK);
+
+	bus = mdiobus_alloc();
+	if (!bus)
+		return -ENOMEM;
+
+	of_address_to_resource(np, 0, &res);
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
+		 (unsigned long long)res.start);
+	bus->priv = lp;
+	bus->name = "Xilinx Emaclite MDIO";
+	bus->read = xemaclite_mdio_read;
+	bus->write = xemaclite_mdio_write;
+	bus->reset = xemaclite_mdio_reset;
+	bus->parent = dev;
+	bus->irq = lp->mdio_irqs; /* preallocated IRQ table */
+
+	lp->mii_bus = bus;
+
+	rc = of_mdiobus_register(bus, np);
+	if (rc)
+		goto err_register;
+
+	return 0;
+
+err_register:
+	mdiobus_free(bus);
+	return rc;
+}
+
+/**
+ * xemaclite_adjust_link - Link state callback for the Emaclite device
+ * @ndev: pointer to net_device struct
+ *
+ * There's nothing in the Emaclite device to be configured when the link
+ * state changes. We just print the status.
+ */
+void xemaclite_adjust_link(struct net_device *ndev)
+{
+	struct net_local *lp = netdev_priv(ndev);
+	struct phy_device *phy = lp->phy_dev;
+	int link_state;
+
+	/* hash together the state values to decide if something has changed */
+	link_state = phy->speed | (phy->duplex << 1) | phy->link;
+
+	if (lp->last_link != link_state) {
+		lp->last_link = link_state;
+		phy_print_status(phy);
+	}
+}
+
 /**
  * xemaclite_open - Open the network device
  * @dev:	Pointer to the network device
  *
  * This function sets the MAC address, requests an IRQ and enables interrupts
  * for the Emaclite device and starts the Tx queue.
+ * It also connects to the phy device, if MDIO is included in Emaclite device.
  */
 static int xemaclite_open(struct net_device *dev)
 {
@@ -656,14 +924,50 @@ static int xemaclite_open(struct net_device *dev)
 	/* Just to be safe, stop the device first */
 	xemaclite_disable_interrupts(lp);
 
+	if (lp->phy_node) {
+		u32 bmcr;
+
+		lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node,
+					     xemaclite_adjust_link, 0,
+					     PHY_INTERFACE_MODE_MII);
+		if (!lp->phy_dev) {
+			dev_err(&lp->ndev->dev, "of_phy_connect() failed\n");
+			return -ENODEV;
+		}
+
+		/* EmacLite doesn't support giga-bit speeds */
+		lp->phy_dev->supported &= (PHY_BASIC_FEATURES);
+		lp->phy_dev->advertising = lp->phy_dev->supported;
+
+		/* Don't advertise 1000BASE-T Full/Half duplex speeds */
+		xemaclite_mdio_write(lp->mii_bus, lp->phy_dev->addr,
+				     MII_CTRL1000, 0x00);
+		/* Advertise only 10 and 100mbps full/half duplex speeds */
+		xemaclite_mdio_write(lp->mii_bus, lp->phy_dev->addr,
+				     MII_ADVERTISE, ADVERTISE_ALL);
+
+		/* Restart auto negotiation */
+		bmcr = xemaclite_mdio_read(lp->mii_bus,
+					   lp->phy_dev->addr, MII_BMCR);
+		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+		xemaclite_mdio_write(lp->mii_bus, lp->phy_dev->addr,
+				     MII_BMCR, bmcr);
+
+		phy_start(lp->phy_dev);
+	}
+
 	/* Set the MAC address each time opened */
-	xemaclite_set_mac_address(lp, dev->dev_addr);
+	xemaclite_update_address(lp, dev->dev_addr);
 
 	/* Grab the IRQ */
 	retval = request_irq(dev->irq, xemaclite_interrupt, 0, dev->name, dev);
 	if (retval) {
 		dev_err(&lp->ndev->dev, "Could not allocate interrupt %d\n",
 			dev->irq);
+		if (lp->phy_dev)
+			phy_disconnect(lp->phy_dev);
+		lp->phy_dev = NULL;
+
 		return retval;
 	}
 
@@ -682,6 +986,7 @@ static int xemaclite_open(struct net_device *dev)
  *
  * This function stops the Tx queue, disables interrupts and frees the IRQ for
  * the Emaclite device.
+ * It also disconnects the phy device associated with the Emaclite device.
  */
 static int xemaclite_close(struct net_device *dev)
 {
@@ -691,6 +996,10 @@ static int xemaclite_close(struct net_device *dev)
 	xemaclite_disable_interrupts(lp);
 	free_irq(dev->irq, dev);
 
+	if (lp->phy_dev)
+		phy_disconnect(lp->phy_dev);
+	lp->phy_dev = NULL;
+
 	return 0;
 }
 
@@ -754,42 +1063,6 @@ static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev)
 }
 
 /**
- * xemaclite_ioctl - Perform IO Control operations on the network device
- * @dev:	Pointer to the network device
- * @rq:		Pointer to the interface request structure
- * @cmd:	IOCTL command
- *
- * The only IOCTL operation supported by this function is setting the MAC
- * address. An error is reported if any other operations are requested.
- *
- * Return:	0 to indicate success, or a negative error for failure.
- */
-static int xemaclite_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	struct net_local *lp = (struct net_local *) netdev_priv(dev);
-	struct hw_addr_data *hw_addr = (struct hw_addr_data *) &rq->ifr_hwaddr;
-
-	switch (cmd) {
-	case SIOCETHTOOL:
-		return -EIO;
-
-	case SIOCSIFHWADDR:
-		dev_err(&lp->ndev->dev, "SIOCSIFHWADDR\n");
-
-		/* Copy MAC address in from user space */
-		copy_from_user((void __force *) dev->dev_addr,
-			       (void __user __force *) hw_addr,
-			       IFHWADDRLEN);
-		xemaclite_set_mac_address(lp, dev->dev_addr);
-		break;
-	default:
-		return -EOPNOTSUPP;
-	}
-
-	return 0;
-}
-
-/**
  * xemaclite_remove_ndev - Free the network device
  * @ndev:	Pointer to the network device to be freed
  *
@@ -840,6 +1113,8 @@ static struct net_device_ops xemaclite_netdev_ops;
  * This function probes for the Emaclite device in the device tree.
  * It initializes the driver data structure and the hardware, sets the MAC
  * address and registers the network device.
+ * It also registers a mii_bus for the Emaclite device, if MDIO is included
+ * in the device.
  *
  * Return:	0, if the driver is bound to the Emaclite device, or
  *		a negative error if there is failure.
@@ -880,6 +1155,7 @@ static int __devinit xemaclite_of_probe(struct of_device *ofdev,
 	}
 
 	dev_set_drvdata(dev, ndev);
+	SET_NETDEV_DEV(ndev, &ofdev->dev);
 
 	ndev->irq = r_irq.start;
 	ndev->mem_start = r_mem.start;
@@ -923,7 +1199,12 @@ static int __devinit xemaclite_of_probe(struct of_device *ofdev,
 	out_be32(lp->base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET, 0);
 
 	/* Set the MAC address in the EmacLite device */
-	xemaclite_set_mac_address(lp, ndev->dev_addr);
+	xemaclite_update_address(lp, ndev->dev_addr);
+
+	lp->phy_node = of_parse_phandle(ofdev->node, "phy-handle", 0);
+	rc = xemaclite_mdio_setup(lp, &ofdev->dev);
+	if (rc)
+		dev_warn(&ofdev->dev, "error registering MDIO bus\n");
 
 	dev_info(dev,
 		 "MAC address is now %2x:%2x:%2x:%2x:%2x:%2x\n",
@@ -972,12 +1253,25 @@ static int __devexit xemaclite_of_remove(struct of_device *of_dev)
 	struct device *dev = &of_dev->dev;
 	struct net_device *ndev = dev_get_drvdata(dev);
 
+	struct net_local *lp = (struct net_local *) netdev_priv(ndev);
+
+	/* Un-register the mii_bus, if configured */
+	if (lp->has_mdio) {
+		mdiobus_unregister(lp->mii_bus);
+		kfree(lp->mii_bus->irq);
+		mdiobus_free(lp->mii_bus);
+		lp->mii_bus = NULL;
+	}
+
 	unregister_netdev(ndev);
 
+	if (lp->phy_node)
+		of_node_put(lp->phy_node);
+	lp->phy_node = NULL;
+
 	release_mem_region(ndev->mem_start, ndev->mem_end-ndev->mem_start + 1);
 
 	xemaclite_remove_ndev(ndev);
-
 	dev_set_drvdata(dev, NULL);
 
 	return 0;
@@ -987,7 +1281,7 @@ static struct net_device_ops xemaclite_netdev_ops = {
 	.ndo_open		= xemaclite_open,
 	.ndo_stop		= xemaclite_close,
 	.ndo_start_xmit		= xemaclite_send,
-	.ndo_do_ioctl		= xemaclite_ioctl,
+	.ndo_set_mac_address	= xemaclite_set_mac_address,
 	.ndo_tx_timeout		= xemaclite_tx_timeout,
 	.ndo_get_stats		= xemaclite_get_stats,
 };
@@ -999,6 +1293,7 @@ static struct of_device_id xemaclite_of_match[] __devinitdata = {
 	{ .compatible = "xlnx,xps-ethernetlite-1.00.a", },
 	{ .compatible = "xlnx,xps-ethernetlite-2.00.a", },
 	{ .compatible = "xlnx,xps-ethernetlite-2.01.a", },
+	{ .compatible = "xlnx,xps-ethernetlite-3.00.a", },
 	{ /* end of list */ },
 };
 MODULE_DEVICE_TABLE(of, xemaclite_of_match);
-- 
1.6.2.1



This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.



^ permalink raw reply related

* ipg and dl2k both claiming D-Link DGE-550T
From: Jeff Mahoney @ 2010-02-11 20:26 UTC (permalink / raw)
  To: Francois Romieu, Sorbica Shieh, Jesse Huang; +Cc: Network Development


Hi all -

I've seen this report a bunch of times but google didn't point to any
resolution. I'm not really involved with network driver development, so
I'm hoping that someone who knows the history here can speak up.

I have a report[1] where the D-Link DGE-550T is being associated with the
ipg driver. It works for a very short amount of time and then fails.
Unloading the driver and loading dl2k instead results in a working
system. The DGE-550T is a DL2000 based card, but the ipg (IP1000)
driver is claiming it and has been since the driver was added to the
kernel in 2.6.24. dl2k has been claiming this ID since the 2.4 days.

Which driver is correct? Can we remove the PCI IDs associated with the
wrong driver? Users keep working around this with module blacklisting
but they shouldn't have to.

Thanks.

-Jeff

[1] https://bugzilla.novell.com/show_bug.cgi?id=579219

---

ipg: Remove device claimed by dl2k from pci id table

 This patch removes D-Link DGE-550T PCI ID (1186:4000) from the ipg
 driver. The ipg driver is for IP2000-based cards and the DGE-550T is
 a DL2000-based card. The driver loads and works for a few moments, but
 once a real workload is applied it stops operating. The ipg driver
 claimed this ID since it was introduced in 2.6.24 and it's forced many
 users to blacklist it.

 The correct driver for this hardware is the dl2k driver, which has been
 claiming this PCI ID since the 2.4 days.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 drivers/net/ipg.c |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

--- a/drivers/net/ipg.c
+++ b/drivers/net/ipg.c
@@ -88,7 +88,6 @@ static const char *ipg_brand_name[] = {
 	"Sundance Technology ST2021 based NIC",
 	"Tamarack Microelectronics TC9020/9021 based NIC",
 	"Tamarack Microelectronics TC9020/9021 based NIC",
-	"D-Link NIC",
 	"D-Link NIC IP1000A"
 };
 
@@ -97,8 +96,7 @@ static struct pci_device_id ipg_pci_tbl[
 	{ PCI_VDEVICE(SUNDANCE,	0x2021), 1 },
 	{ PCI_VDEVICE(SUNDANCE,	0x1021), 2 },
 	{ PCI_VDEVICE(DLINK,	0x9021), 3 },
-	{ PCI_VDEVICE(DLINK,	0x4000), 4 },
-	{ PCI_VDEVICE(DLINK,	0x4020), 5 },
+	{ PCI_VDEVICE(DLINK,	0x4020), 4 },
 	{ 0, }
 };
 

-- 
Jeff Mahoney
SUSE Labs

^ permalink raw reply

* Re: [PATCH] ethtool: Use explicit designated initializers for .cmd
From: David Miller @ 2010-02-11 20:14 UTC (permalink / raw)
  To: rdreier; +Cc: netdev
In-Reply-To: <adatytn7crt.fsf@roland-alpha.cisco.com>

From: Roland Dreier <rdreier@cisco.com>
Date: Thu, 11 Feb 2010 12:12:06 -0800

> Initialize the .cmd member of various ethtool using a designated struct
> initializer rather.  This makes things a teeny bit more robust, although
> the chance of a struct layout changing is extremely remote, and also
> makes the code a little easier to read.
> 
> Signed-off-by: Roland Dreier <rolandd@cisco.com>

Applied to net-next-2.6, thanks Roland.

^ permalink raw reply

* [PATCH] ethtool: Use explicit designated initializers for .cmd
From: Roland Dreier @ 2010-02-11 20:12 UTC (permalink / raw)
  To: davem; +Cc: netdev

Initialize the .cmd member of various ethtool using a designated struct
initializer rather.  This makes things a teeny bit more robust, although
the chance of a struct layout changing is extremely remote, and also
makes the code a little easier to read.

Signed-off-by: Roland Dreier <rolandd@cisco.com>
---
Just something I noticed while browsing the code.  Doesn't change
generated code, and at least for me makes things slightly cleaner.

 net/core/ethtool.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index d8aee58..f1d5c6d 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -146,7 +146,7 @@ int ethtool_op_set_flags(struct net_device *dev, u32 data)
 
 static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
 {
-	struct ethtool_cmd cmd = { ETHTOOL_GSET };
+	struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET };
 	int err;
 
 	if (!dev->ethtool_ops->get_settings)
@@ -324,7 +324,7 @@ static int ethtool_reset(struct net_device *dev, char __user *useraddr)
 
 static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
 {
-	struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
+	struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
 
 	if (!dev->ethtool_ops->get_wol)
 		return -EOPNOTSUPP;
@@ -458,7 +458,7 @@ static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)
 
 static int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr)
 {
-	struct ethtool_coalesce coalesce = { ETHTOOL_GCOALESCE };
+	struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE };
 
 	if (!dev->ethtool_ops->get_coalesce)
 		return -EOPNOTSUPP;
@@ -485,7 +485,7 @@ static int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr)
 
 static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr)
 {
-	struct ethtool_ringparam ringparam = { ETHTOOL_GRINGPARAM };
+	struct ethtool_ringparam ringparam = { .cmd = ETHTOOL_GRINGPARAM };
 
 	if (!dev->ethtool_ops->get_ringparam)
 		return -EOPNOTSUPP;
@@ -839,7 +839,7 @@ static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr)
 static int ethtool_get_value(struct net_device *dev, char __user *useraddr,
 			     u32 cmd, u32 (*actor)(struct net_device *))
 {
-	struct ethtool_value edata = { cmd };
+	struct ethtool_value edata = { .cmd = cmd };
 
 	if (!actor)
 		return -EOPNOTSUPP;

-- 
Roland Dreier  <rolandd@cisco.com>
For corporate legal information go to:
http://www.cisco.com/web/about/doing_business/legal/cri/index.html

^ 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