]> git.openfabrics.org - ~emulex/for-vlad/old/compat-rdma.git/commitdiff
cxgb4: Add support for T4 configuration file
authorVipul Pandya <vipul@chelsio.com>
Fri, 5 Oct 2012 10:32:32 +0000 (03:32 -0700)
committerVipul Pandya <vipul@chelsio.com>
Fri, 5 Oct 2012 10:32:32 +0000 (03:32 -0700)
This patch adds patch series from linux-next tree to add support for T4
configuration file.

Starting with T4 firmware version 1.3.11.0 the firmware now supports device
configuration via a Firmware Configuration File. The Firmware Configuration
File was primarily developed in order to centralize all of the configuration,
resource allocation, etc. for Unified Wire operation where multiple
Physical / Virtual Function Drivers would be using a T4 adapter simultaneously.

The Firmware Configuration file can live in three locations as shown below
in order of precedence.
1) User defined configuration file: /lib/firmware/cxgb4/t4-config.txt
2) Factory Default configuration file written to FLASH within
   the manufacturing process.
3) Hardwired driver configuration.

Signed-off-by: Vipul Pandya <vipul@chelsio.com>
linux-next-cherry-picks/0002-cxgb4-Fix-incorrect-values-for-MEMWIN.patch [new file with mode: 0644]
linux-next-cherry-picks/0003-cxgb4-Add-functions-to-read-memory-via-PCIE-memory-w.patch [new file with mode: 0644]
linux-next-cherry-picks/0004-cxgb4-cxgb4vf-Code-cleanup-to-enable-T4-Configuratio.patch [new file with mode: 0644]
linux-next-cherry-picks/0005-cxgb4-Add-support-for-T4-configuration-file.patch [new file with mode: 0644]
linux-next-cherry-picks/0006-cxgb4-Add-support-for-T4-hardwired-driver-configurat.patch [new file with mode: 0644]
linux-next-cherry-picks/0007-cxgb4-Inform-caller-if-driver-didn-t-upgrade-firmwar.patch [new file with mode: 0644]
linux-next-cherry-picks/0008-cxgb4-Don-t-attempt-to-upgrade-T4-firmware-when-cxgb.patch [new file with mode: 0644]

diff --git a/linux-next-cherry-picks/0002-cxgb4-Fix-incorrect-values-for-MEMWIN.patch b/linux-next-cherry-picks/0002-cxgb4-Fix-incorrect-values-for-MEMWIN.patch
new file mode 100644 (file)
index 0000000..1490c39
--- /dev/null
@@ -0,0 +1,32 @@
+commit 3eb4afbfceb44750d9afb832e6c992adec9fc571
+Author: Vipul Pandya <vipul@chelsio.com>
+Date:   Wed Sep 26 02:39:36 2012 +0000
+
+cxgb4: Fix incorrect values for MEMWIN*_APERTURE and MEMWIN*_BASE
+
+Signed-off-by: Jay Hernandez <jay@chelsio.com>
+Signed-off-by: Vipul Pandya <vipul@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -67,12 +67,12 @@ enum {
+ };
+
+ enum {
+-      MEMWIN0_APERTURE = 65536,
+-      MEMWIN0_BASE     = 0x30000,
++      MEMWIN0_APERTURE = 2048,
++      MEMWIN0_BASE     = 0x1b800,
+       MEMWIN1_APERTURE = 32768,
+       MEMWIN1_BASE     = 0x28000,
+-      MEMWIN2_APERTURE = 2048,
+-      MEMWIN2_BASE     = 0x1b800,
++      MEMWIN2_APERTURE = 65536,
++      MEMWIN2_BASE     = 0x30000,
+ };
+
+ enum dev_master {
+--
+1.7.1
diff --git a/linux-next-cherry-picks/0003-cxgb4-Add-functions-to-read-memory-via-PCIE-memory-w.patch b/linux-next-cherry-picks/0003-cxgb4-Add-functions-to-read-memory-via-PCIE-memory-w.patch
new file mode 100644 (file)
index 0000000..323fd0c
--- /dev/null
@@ -0,0 +1,280 @@
+From 5afc8b84eb7b29e4646d6e8ca7e6d7196031d6f7 Mon Sep 17 00:00:00 2001
+From: Vipul Pandya <vipul@chelsio.com>
+Date: Wed, 26 Sep 2012 02:39:37 +0000
+Subject: [PATCH 1/6] cxgb4: Add functions to read memory via PCIE memory window
+
+This patch implements two new functions t4_mem_win_read and t4_memory_read.
+These new functions can be used to read memory via the PCIE memory window.
+Please note, for proper execution of these functions PCIE_MEM_ACCESS_BASE_WIN
+registers must be setup correctly like how setup_memwin in the cxgb4 driver
+does it.
+
+Signed-off-by: Jay Hernandez <jay@chelsio.com>
+Signed-off-by: Vipul Pandya <vipul@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h |    2 +
+ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c |  137 ++++++++++++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/t4_hw.h |   80 ++++++++++++++++
+ 3 files changed, 219 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+index f3fe236..7de740a 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -664,6 +664,8 @@ int t4_wait_dev_ready(struct adapter *adap);
+ int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port,
+                 struct link_config *lc);
+ int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port);
++int t4_memory_write(struct adapter *adap, int mtype, u32 addr, u32 len,
++                  __be32 *buf);
+ int t4_seeprom_wp(struct adapter *adapter, bool enable);
+ int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size);
+ int t4_check_fw_version(struct adapter *adapter);
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+index 8e988d6..259d0dc 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+@@ -330,6 +330,143 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
+       return 0;
+ }
++/*
++ *    t4_mem_win_rw - read/write memory through PCIE memory window
++ *    @adap: the adapter
++ *    @addr: address of first byte requested
++ *    @data: MEMWIN0_APERTURE bytes of data containing the requested address
++ *    @dir: direction of transfer 1 => read, 0 => write
++ *
++ *    Read/write MEMWIN0_APERTURE bytes of data from MC starting at a
++ *    MEMWIN0_APERTURE-byte-aligned address that covers the requested
++ *    address @addr.
++ */
++static int t4_mem_win_rw(struct adapter *adap, u32 addr, __be32 *data, int dir)
++{
++      int i;
++
++      /*
++       * Setup offset into PCIE memory window.  Address must be a
++       * MEMWIN0_APERTURE-byte-aligned address.  (Read back MA register to
++       * ensure that changes propagate before we attempt to use the new
++       * values.)
++       */
++      t4_write_reg(adap, PCIE_MEM_ACCESS_OFFSET,
++                   addr & ~(MEMWIN0_APERTURE - 1));
++      t4_read_reg(adap, PCIE_MEM_ACCESS_OFFSET);
++
++      /* Collecting data 4 bytes at a time upto MEMWIN0_APERTURE */
++      for (i = 0; i < MEMWIN0_APERTURE; i = i+0x4) {
++              if (dir)
++                      *data++ = t4_read_reg(adap, (MEMWIN0_BASE + i));
++              else
++                      t4_write_reg(adap, (MEMWIN0_BASE + i), *data++);
++      }
++
++      return 0;
++}
++
++/**
++ *    t4_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window
++ *    @adap: the adapter
++ *    @mtype: memory type: MEM_EDC0, MEM_EDC1 or MEM_MC
++ *    @addr: address within indicated memory type
++ *    @len: amount of memory to transfer
++ *    @buf: host memory buffer
++ *    @dir: direction of transfer 1 => read, 0 => write
++ *
++ *    Reads/writes an [almost] arbitrary memory region in the firmware: the
++ *    firmware memory address, length and host buffer must be aligned on
++ *    32-bit boudaries.  The memory is transferred as a raw byte sequence
++ *    from/to the firmware's memory.  If this memory contains data
++ *    structures which contain multi-byte integers, it's the callers
++ *    responsibility to perform appropriate byte order conversions.
++ */
++static int t4_memory_rw(struct adapter *adap, int mtype, u32 addr, u32 len,
++                      __be32 *buf, int dir)
++{
++      u32 pos, start, end, offset, memoffset;
++      int ret;
++
++      /*
++       * Argument sanity checks ...
++       */
++      if ((addr & 0x3) || (len & 0x3))
++              return -EINVAL;
++
++      /*
++       * Offset into the region of memory which is being accessed
++       * MEM_EDC0 = 0
++       * MEM_EDC1 = 1
++       * MEM_MC   = 2
++       */
++      memoffset = (mtype * (5 * 1024 * 1024));
++
++      /* Determine the PCIE_MEM_ACCESS_OFFSET */
++      addr = addr + memoffset;
++
++      /*
++       * The underlaying EDC/MC read routines read MEMWIN0_APERTURE bytes
++       * at a time so we need to round down the start and round up the end.
++       * We'll start copying out of the first line at (addr - start) a word
++       * at a time.
++       */
++      start = addr & ~(MEMWIN0_APERTURE-1);
++      end = (addr + len + MEMWIN0_APERTURE-1) & ~(MEMWIN0_APERTURE-1);
++      offset = (addr - start)/sizeof(__be32);
++
++      for (pos = start; pos < end; pos += MEMWIN0_APERTURE, offset = 0) {
++              __be32 data[MEMWIN0_APERTURE/sizeof(__be32)];
++
++              /*
++               * If we're writing, copy the data from the caller's memory
++               * buffer
++               */
++              if (!dir) {
++                      /*
++                       * If we're doing a partial write, then we need to do
++                       * a read-modify-write ...
++                       */
++                      if (offset || len < MEMWIN0_APERTURE) {
++                              ret = t4_mem_win_rw(adap, pos, data, 1);
++                              if (ret)
++                                      return ret;
++                      }
++                      while (offset < (MEMWIN0_APERTURE/sizeof(__be32)) &&
++                             len > 0) {
++                              data[offset++] = *buf++;
++                              len -= sizeof(__be32);
++                      }
++              }
++
++              /*
++               * Transfer a block of memory and bail if there's an error.
++               */
++              ret = t4_mem_win_rw(adap, pos, data, dir);
++              if (ret)
++                      return ret;
++
++              /*
++               * If we're reading, copy the data into the caller's memory
++               * buffer.
++               */
++              if (dir)
++                      while (offset < (MEMWIN0_APERTURE/sizeof(__be32)) &&
++                             len > 0) {
++                              *buf++ = data[offset++];
++                              len -= sizeof(__be32);
++                      }
++      }
++
++      return 0;
++}
++
++int t4_memory_write(struct adapter *adap, int mtype, u32 addr, u32 len,
++                  __be32 *buf)
++{
++      return t4_memory_rw(adap, mtype, addr, len, buf, 0);
++}
++
+ #define EEPROM_STAT_ADDR   0x7bfc
+ #define VPD_BASE           0
+ #define VPD_LEN            512
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
+index c26b455..f534ed7 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
+@@ -58,6 +58,7 @@ enum {
+ enum {
+       SF_PAGE_SIZE = 256,           /* serial flash page size */
++      SF_SEC_SIZE = 64 * 1024,      /* serial flash sector size */
+ };
+ enum { RSP_TYPE_FLBUF, RSP_TYPE_CPL, RSP_TYPE_INTR }; /* response entry types */
+@@ -137,4 +138,83 @@ struct rsp_ctrl {
+ #define QINTR_CNT_EN       0x1
+ #define QINTR_TIMER_IDX(x) ((x) << 1)
+ #define QINTR_TIMER_IDX_GET(x) (((x) >> 1) & 0x7)
++
++/*
++ * Flash layout.
++ */
++#define FLASH_START(start)    ((start) * SF_SEC_SIZE)
++#define FLASH_MAX_SIZE(nsecs) ((nsecs) * SF_SEC_SIZE)
++
++enum {
++      /*
++       * Various Expansion-ROM boot images, etc.
++       */
++      FLASH_EXP_ROM_START_SEC = 0,
++      FLASH_EXP_ROM_NSECS = 6,
++      FLASH_EXP_ROM_START = FLASH_START(FLASH_EXP_ROM_START_SEC),
++      FLASH_EXP_ROM_MAX_SIZE = FLASH_MAX_SIZE(FLASH_EXP_ROM_NSECS),
++
++      /*
++       * iSCSI Boot Firmware Table (iBFT) and other driver-related
++       * parameters ...
++       */
++      FLASH_IBFT_START_SEC = 6,
++      FLASH_IBFT_NSECS = 1,
++      FLASH_IBFT_START = FLASH_START(FLASH_IBFT_START_SEC),
++      FLASH_IBFT_MAX_SIZE = FLASH_MAX_SIZE(FLASH_IBFT_NSECS),
++
++      /*
++       * Boot configuration data.
++       */
++      FLASH_BOOTCFG_START_SEC = 7,
++      FLASH_BOOTCFG_NSECS = 1,
++      FLASH_BOOTCFG_START = FLASH_START(FLASH_BOOTCFG_START_SEC),
++      FLASH_BOOTCFG_MAX_SIZE = FLASH_MAX_SIZE(FLASH_BOOTCFG_NSECS),
++
++      /*
++       * Location of firmware image in FLASH.
++       */
++      FLASH_FW_START_SEC = 8,
++      FLASH_FW_NSECS = 8,
++      FLASH_FW_START = FLASH_START(FLASH_FW_START_SEC),
++      FLASH_FW_MAX_SIZE = FLASH_MAX_SIZE(FLASH_FW_NSECS),
++
++      /*
++       * iSCSI persistent/crash information.
++       */
++      FLASH_ISCSI_CRASH_START_SEC = 29,
++      FLASH_ISCSI_CRASH_NSECS = 1,
++      FLASH_ISCSI_CRASH_START = FLASH_START(FLASH_ISCSI_CRASH_START_SEC),
++      FLASH_ISCSI_CRASH_MAX_SIZE = FLASH_MAX_SIZE(FLASH_ISCSI_CRASH_NSECS),
++
++      /*
++       * FCoE persistent/crash information.
++       */
++      FLASH_FCOE_CRASH_START_SEC = 30,
++      FLASH_FCOE_CRASH_NSECS = 1,
++      FLASH_FCOE_CRASH_START = FLASH_START(FLASH_FCOE_CRASH_START_SEC),
++      FLASH_FCOE_CRASH_MAX_SIZE = FLASH_MAX_SIZE(FLASH_FCOE_CRASH_NSECS),
++
++      /*
++       * Location of Firmware Configuration File in FLASH.  Since the FPGA
++       * "FLASH" is smaller we need to store the Configuration File in a
++       * different location -- which will overlap the end of the firmware
++       * image if firmware ever gets that large ...
++       */
++      FLASH_CFG_START_SEC = 31,
++      FLASH_CFG_NSECS = 1,
++      FLASH_CFG_START = FLASH_START(FLASH_CFG_START_SEC),
++      FLASH_CFG_MAX_SIZE = FLASH_MAX_SIZE(FLASH_CFG_NSECS),
++
++      FLASH_FPGA_CFG_START_SEC = 15,
++      FLASH_FPGA_CFG_START = FLASH_START(FLASH_FPGA_CFG_START_SEC),
++
++      /*
++       * Sectors 32-63 are reserved for FLASH failover.
++       */
++};
++
++#undef FLASH_START
++#undef FLASH_MAX_SIZE
++
+ #endif /* __T4_HW_H */
+-- 
+1.7.1
+
diff --git a/linux-next-cherry-picks/0004-cxgb4-cxgb4vf-Code-cleanup-to-enable-T4-Configuratio.patch b/linux-next-cherry-picks/0004-cxgb4-cxgb4vf-Code-cleanup-to-enable-T4-Configuratio.patch
new file mode 100644 (file)
index 0000000..e9a42f3
--- /dev/null
@@ -0,0 +1,813 @@
+From 52367a763d8046190754ab43743e42638564a2d1 Mon Sep 17 00:00:00 2001
+From: Vipul Pandya <vipul@chelsio.com>
+Date: Wed, 26 Sep 2012 02:39:38 +0000
+Subject: [PATCH 2/6] cxgb4/cxgb4vf: Code cleanup to enable T4 Configuration File support
+
+This patch adds new enums and macros to enable T4 configuration file support. It
+also removes duplicate macro definitions.
+
+It fixes the build failure in cxgb4vf driver introduced because of old macro
+definition removal.
+
+It also performs SGE initialization based on T4 configuration file is provided
+or not. If it is provided then it uses the parameters provided in it otherwise
+it uses hard coded values.
+
+Signed-off-by: Jay Hernandez <jay@chelsio.com>
+Signed-off-by: Vipul Pandya <vipul@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h    |   18 ++-
+ drivers/net/ethernet/chelsio/cxgb4/sge.c      |  337 ++++++++++++++++++++-----
+ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h  |   35 +++-
+ drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h |   41 +++-
+ drivers/net/ethernet/chelsio/cxgb4vf/sge.c    |    5 +-
+ 5 files changed, 365 insertions(+), 71 deletions(-)
+
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+index 7de740a..ae040cf 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -315,6 +315,9 @@ enum {                                 /* adapter flags */
+       USING_MSI          = (1 << 1),
+       USING_MSIX         = (1 << 2),
+       FW_OK              = (1 << 4),
++      USING_SOFT_PARAMS  = (1 << 6),
++      MASTER_PF          = (1 << 7),
++      FW_OFLD_CONN       = (1 << 9),
+ };
+ struct rx_sw_desc;
+@@ -467,6 +470,11 @@ struct sge {
+       u16 rdma_rxq[NCHAN];
+       u16 timer_val[SGE_NTIMERS];
+       u8 counter_val[SGE_NCOUNTERS];
++      u32 fl_pg_order;            /* large page allocation size */
++      u32 stat_len;               /* length of status page at ring end */
++      u32 pktshift;               /* padding between CPL & packet data */
++      u32 fl_align;               /* response queue message alignment */
++      u32 fl_starve_thres;        /* Free List starvation threshold */
+       unsigned int starve_thres;
+       u8 idma_state[2];
+       unsigned int egr_start;
+@@ -619,7 +627,7 @@ int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq,
+ int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq,
+                         struct net_device *dev, unsigned int iqid);
+ irqreturn_t t4_sge_intr_msix(int irq, void *cookie);
+-void t4_sge_init(struct adapter *adap);
++int t4_sge_init(struct adapter *adap);
+ void t4_sge_start(struct adapter *adap);
+ void t4_sge_stop(struct adapter *adap);
+ extern int dbfifo_int_thresh;
+@@ -638,6 +646,14 @@ static inline unsigned int us_to_core_ticks(const struct adapter *adap,
+       return (us * adap->params.vpd.cclk) / 1000;
+ }
++static inline unsigned int core_ticks_to_us(const struct adapter *adapter,
++                                          unsigned int ticks)
++{
++      /* add Core Clock / 2 to round ticks to nearest uS */
++      return ((ticks * 1000 + adapter->params.vpd.cclk/2) /
++              adapter->params.vpd.cclk);
++}
++
+ void t4_set_reg_field(struct adapter *adap, unsigned int addr, u32 mask,
+                     u32 val);
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c
+index 1fde57d..3ecc087 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/sge.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c
+@@ -68,9 +68,6 @@
+  */
+ #define RX_PKT_SKB_LEN   512
+-/* Ethernet header padding prepended to RX_PKTs */
+-#define RX_PKT_PAD 2
+-
+ /*
+  * Max number of Tx descriptors we clean up at a time.  Should be modest as
+  * freeing skbs isn't cheap and it happens while holding locks.  We just need
+@@ -137,13 +134,6 @@
+  */
+ #define MAX_CTRL_WR_LEN SGE_MAX_WR_LEN
+-enum {
+-      /* packet alignment in FL buffers */
+-      FL_ALIGN = L1_CACHE_BYTES < 32 ? 32 : L1_CACHE_BYTES,
+-      /* egress status entry size */
+-      STAT_LEN = L1_CACHE_BYTES > 64 ? 128 : 64
+-};
+-
+ struct tx_sw_desc {                /* SW state per Tx descriptor */
+       struct sk_buff *skb;
+       struct ulptx_sgl *sgl;
+@@ -155,16 +145,57 @@ struct rx_sw_desc {                /* SW state per Rx descriptor */
+ };
+ /*
+- * The low bits of rx_sw_desc.dma_addr have special meaning.
++ * Rx buffer sizes for "useskbs" Free List buffers (one ingress packet pe skb
++ * buffer).  We currently only support two sizes for 1500- and 9000-byte MTUs.
++ * We could easily support more but there doesn't seem to be much need for
++ * that ...
++ */
++#define FL_MTU_SMALL 1500
++#define FL_MTU_LARGE 9000
++
++static inline unsigned int fl_mtu_bufsize(struct adapter *adapter,
++                                        unsigned int mtu)
++{
++      struct sge *s = &adapter->sge;
++
++      return ALIGN(s->pktshift + ETH_HLEN + VLAN_HLEN + mtu, s->fl_align);
++}
++
++#define FL_MTU_SMALL_BUFSIZE(adapter) fl_mtu_bufsize(adapter, FL_MTU_SMALL)
++#define FL_MTU_LARGE_BUFSIZE(adapter) fl_mtu_bufsize(adapter, FL_MTU_LARGE)
++
++/*
++ * Bits 0..3 of rx_sw_desc.dma_addr have special meaning.  The hardware uses
++ * these to specify the buffer size as an index into the SGE Free List Buffer
++ * Size register array.  We also use bit 4, when the buffer has been unmapped
++ * for DMA, but this is of course never sent to the hardware and is only used
++ * to prevent double unmappings.  All of the above requires that the Free List
++ * Buffers which we allocate have the bottom 5 bits free (0) -- i.e. are
++ * 32-byte or or a power of 2 greater in alignment.  Since the SGE's minimal
++ * Free List Buffer alignment is 32 bytes, this works out for us ...
+  */
+ enum {
+-      RX_LARGE_BUF    = 1 << 0, /* buffer is larger than PAGE_SIZE */
+-      RX_UNMAPPED_BUF = 1 << 1, /* buffer is not mapped */
++      RX_BUF_FLAGS     = 0x1f,   /* bottom five bits are special */
++      RX_BUF_SIZE      = 0x0f,   /* bottom three bits are for buf sizes */
++      RX_UNMAPPED_BUF  = 0x10,   /* buffer is not mapped */
++
++      /*
++       * XXX We shouldn't depend on being able to use these indices.
++       * XXX Especially when some other Master PF has initialized the
++       * XXX adapter or we use the Firmware Configuration File.  We
++       * XXX should really search through the Host Buffer Size register
++       * XXX array for the appropriately sized buffer indices.
++       */
++      RX_SMALL_PG_BUF  = 0x0,   /* small (PAGE_SIZE) page buffer */
++      RX_LARGE_PG_BUF  = 0x1,   /* buffer large (FL_PG_ORDER) page buffer */
++
++      RX_SMALL_MTU_BUF = 0x2,   /* small MTU buffer */
++      RX_LARGE_MTU_BUF = 0x3,   /* large MTU buffer */
+ };
+ static inline dma_addr_t get_buf_addr(const struct rx_sw_desc *d)
+ {
+-      return d->dma_addr & ~(dma_addr_t)(RX_LARGE_BUF | RX_UNMAPPED_BUF);
++      return d->dma_addr & ~(dma_addr_t)RX_BUF_FLAGS;
+ }
+ static inline bool is_buf_mapped(const struct rx_sw_desc *d)
+@@ -392,14 +423,35 @@ static inline void reclaim_completed_tx(struct adapter *adap, struct sge_txq *q,
+       }
+ }
+-static inline int get_buf_size(const struct rx_sw_desc *d)
++static inline int get_buf_size(struct adapter *adapter,
++                             const struct rx_sw_desc *d)
+ {
+-#if FL_PG_ORDER > 0
+-      return (d->dma_addr & RX_LARGE_BUF) ? (PAGE_SIZE << FL_PG_ORDER) :
+-                                            PAGE_SIZE;
+-#else
+-      return PAGE_SIZE;
+-#endif
++      struct sge *s = &adapter->sge;
++      unsigned int rx_buf_size_idx = d->dma_addr & RX_BUF_SIZE;
++      int buf_size;
++
++      switch (rx_buf_size_idx) {
++      case RX_SMALL_PG_BUF:
++              buf_size = PAGE_SIZE;
++              break;
++
++      case RX_LARGE_PG_BUF:
++              buf_size = PAGE_SIZE << s->fl_pg_order;
++              break;
++
++      case RX_SMALL_MTU_BUF:
++              buf_size = FL_MTU_SMALL_BUFSIZE(adapter);
++              break;
++
++      case RX_LARGE_MTU_BUF:
++              buf_size = FL_MTU_LARGE_BUFSIZE(adapter);
++              break;
++
++      default:
++              BUG_ON(1);
++      }
++
++      return buf_size;
+ }
+ /**
+@@ -418,7 +470,8 @@ static void free_rx_bufs(struct adapter *adap, struct sge_fl *q, int n)
+               if (is_buf_mapped(d))
+                       dma_unmap_page(adap->pdev_dev, get_buf_addr(d),
+-                                     get_buf_size(d), PCI_DMA_FROMDEVICE);
++                                     get_buf_size(adap, d),
++                                     PCI_DMA_FROMDEVICE);
+               put_page(d->page);
+               d->page = NULL;
+               if (++q->cidx == q->size)
+@@ -444,7 +497,7 @@ static void unmap_rx_buf(struct adapter *adap, struct sge_fl *q)
+       if (is_buf_mapped(d))
+               dma_unmap_page(adap->pdev_dev, get_buf_addr(d),
+-                             get_buf_size(d), PCI_DMA_FROMDEVICE);
++                             get_buf_size(adap, d), PCI_DMA_FROMDEVICE);
+       d->page = NULL;
+       if (++q->cidx == q->size)
+               q->cidx = 0;
+@@ -485,6 +538,7 @@ static inline void set_rx_sw_desc(struct rx_sw_desc *sd, struct page *pg,
+ static unsigned int refill_fl(struct adapter *adap, struct sge_fl *q, int n,
+                             gfp_t gfp)
+ {
++      struct sge *s = &adap->sge;
+       struct page *pg;
+       dma_addr_t mapping;
+       unsigned int cred = q->avail;
+@@ -493,25 +547,27 @@ static unsigned int refill_fl(struct adapter *adap, struct sge_fl *q, int n,
+       gfp |= __GFP_NOWARN | __GFP_COLD;
+-#if FL_PG_ORDER > 0
++      if (s->fl_pg_order == 0)
++              goto alloc_small_pages;
++
+       /*
+        * Prefer large buffers
+        */
+       while (n) {
+-              pg = alloc_pages(gfp | __GFP_COMP, FL_PG_ORDER);
++              pg = alloc_pages(gfp | __GFP_COMP, s->fl_pg_order);
+               if (unlikely(!pg)) {
+                       q->large_alloc_failed++;
+                       break;       /* fall back to single pages */
+               }
+               mapping = dma_map_page(adap->pdev_dev, pg, 0,
+-                                     PAGE_SIZE << FL_PG_ORDER,
++                                     PAGE_SIZE << s->fl_pg_order,
+                                      PCI_DMA_FROMDEVICE);
+               if (unlikely(dma_mapping_error(adap->pdev_dev, mapping))) {
+-                      __free_pages(pg, FL_PG_ORDER);
++                      __free_pages(pg, s->fl_pg_order);
+                       goto out;   /* do not try small pages for this error */
+               }
+-              mapping |= RX_LARGE_BUF;
++              mapping |= RX_LARGE_PG_BUF;
+               *d++ = cpu_to_be64(mapping);
+               set_rx_sw_desc(sd, pg, mapping);
+@@ -525,8 +581,8 @@ static unsigned int refill_fl(struct adapter *adap, struct sge_fl *q, int n,
+               }
+               n--;
+       }
+-#endif
++alloc_small_pages:
+       while (n--) {
+               pg = __skb_alloc_page(gfp, NULL);
+               if (unlikely(!pg)) {
+@@ -1519,6 +1575,8 @@ static noinline int handle_trace_pkt(struct adapter *adap,
+ static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl,
+                  const struct cpl_rx_pkt *pkt)
+ {
++      struct adapter *adapter = rxq->rspq.adap;
++      struct sge *s = &adapter->sge;
+       int ret;
+       struct sk_buff *skb;
+@@ -1529,11 +1587,11 @@ static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl,
+       }
+
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+-      copy_frags(skb, gl, RX_PKT_PAD);
++      copy_frags(skb, gl, s->pktshift);
+ #else
+       copy_frags(skb_shinfo(skb), gl, RX_PKT_PAD);
+ #endif
+-      skb->len = gl->tot_len - RX_PKT_PAD;
++      skb->len = gl->tot_len - s->pktshift;
+       skb->data_len = skb->len;
+       skb->truesize += skb->data_len;
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+@@ -1566,6 +1624,7 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
+       struct sk_buff *skb;
+       const struct cpl_rx_pkt *pkt;
+       struct sge_eth_rxq *rxq = container_of(q, struct sge_eth_rxq, rspq);
++      struct sge *s = &q->adap->sge;
+       if (unlikely(*(u8 *)rsp == CPL_TRACE_PKT))
+               return handle_trace_pkt(q->adap, si);
+@@ -1585,7 +1644,7 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
+               return 0;
+       }
+-      __skb_pull(skb, RX_PKT_PAD);      /* remove ethernet header padding */
++      __skb_pull(skb, s->pktshift);      /* remove ethernet header padding */
+       skb->protocol = eth_type_trans(skb, q->netdev);
+       skb_record_rx_queue(skb, q->idx);
+       if (skb->dev->features & NETIF_F_RXHASH)
+@@ -1696,6 +1755,8 @@ static int process_responses(struct sge_rspq *q, int budget)
+       int budget_left = budget;
+       const struct rsp_ctrl *rc;
+       struct sge_eth_rxq *rxq = container_of(q, struct sge_eth_rxq, rspq);
++      struct adapter *adapter = q->adap;
++      struct sge *s = &adapter->sge;
+       while (likely(budget_left)) {
+               rc = (void *)q->cur_desc + (q->iqe_len - sizeof(*rc));
+@@ -1722,7 +1783,7 @@ static int process_responses(struct sge_rspq *q, int budget)
+                       /* gather packet fragments */
+                       for (frags = 0, fp = si.frags; ; frags++, fp++) {
+                               rsd = &rxq->fl.sdesc[rxq->fl.cidx];
+-                              bufsz = get_buf_size(rsd);
++                              bufsz = get_buf_size(adapter, rsd);
+                               fp->page = rsd->page;
+                               fp->offset = q->offset;
+                               fp->size = min(bufsz, len);
+@@ -1747,7 +1808,7 @@ static int process_responses(struct sge_rspq *q, int budget)
+                       ret = q->handler(q, q->cur_desc, &si);
+                       if (likely(ret == 0))
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+-                              q->offset += ALIGN(fp->size, FL_ALIGN);
++                              q->offset += ALIGN(fp->size, s->fl_align);
+ #else
+                               q->offset += ALIGN(skb_frag_size(fp), FL_ALIGN);
+ #endif
+@@ -1983,6 +2044,7 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
+ {
+       int ret, flsz = 0;
+       struct fw_iq_cmd c;
++      struct sge *s = &adap->sge;
+       struct port_info *pi = netdev_priv(dev);
+       /* Size needs to be multiple of 16, including status entry. */
+@@ -2015,11 +2077,11 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
+               fl->size = roundup(fl->size, 8);
+               fl->desc = alloc_ring(adap->pdev_dev, fl->size, sizeof(__be64),
+                                     sizeof(struct rx_sw_desc), &fl->addr,
+-                                    &fl->sdesc, STAT_LEN, NUMA_NO_NODE);
++                                    &fl->sdesc, s->stat_len, NUMA_NO_NODE);
+               if (!fl->desc)
+                       goto fl_nomem;
+-              flsz = fl->size / 8 + STAT_LEN / sizeof(struct tx_desc);
++              flsz = fl->size / 8 + s->stat_len / sizeof(struct tx_desc);
+               c.iqns_to_fl0congen = htonl(FW_IQ_CMD_FL0PACKEN |
+                                           FW_IQ_CMD_FL0FETCHRO(1) |
+                                           FW_IQ_CMD_FL0DATARO(1) |
+@@ -2096,14 +2158,15 @@ int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
+ {
+       int ret, nentries;
+       struct fw_eq_eth_cmd c;
++      struct sge *s = &adap->sge;
+       struct port_info *pi = netdev_priv(dev);
+       /* Add status entries */
+-      nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc);
++      nentries = txq->q.size + s->stat_len / sizeof(struct tx_desc);
+       txq->q.desc = alloc_ring(adap->pdev_dev, txq->q.size,
+                       sizeof(struct tx_desc), sizeof(struct tx_sw_desc),
+-                      &txq->q.phys_addr, &txq->q.sdesc, STAT_LEN,
++                      &txq->q.phys_addr, &txq->q.sdesc, s->stat_len,
+                       netdev_queue_numa_node_read(netdevq));
+       if (!txq->q.desc)
+               return -ENOMEM;
+@@ -2149,10 +2212,11 @@ int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq,
+ {
+       int ret, nentries;
+       struct fw_eq_ctrl_cmd c;
++      struct sge *s = &adap->sge;
+       struct port_info *pi = netdev_priv(dev);
+       /* Add status entries */
+-      nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc);
++      nentries = txq->q.size + s->stat_len / sizeof(struct tx_desc);
+       txq->q.desc = alloc_ring(adap->pdev_dev, nentries,
+                                sizeof(struct tx_desc), 0, &txq->q.phys_addr,
+@@ -2200,14 +2264,15 @@ int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq,
+ {
+       int ret, nentries;
+       struct fw_eq_ofld_cmd c;
++      struct sge *s = &adap->sge;
+       struct port_info *pi = netdev_priv(dev);
+       /* Add status entries */
+-      nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc);
++      nentries = txq->q.size + s->stat_len / sizeof(struct tx_desc);
+       txq->q.desc = alloc_ring(adap->pdev_dev, txq->q.size,
+                       sizeof(struct tx_desc), sizeof(struct tx_sw_desc),
+-                      &txq->q.phys_addr, &txq->q.sdesc, STAT_LEN,
++                      &txq->q.phys_addr, &txq->q.sdesc, s->stat_len,
+                       NUMA_NO_NODE);
+       if (!txq->q.desc)
+               return -ENOMEM;
+@@ -2251,8 +2316,10 @@ int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq,
+ static void free_txq(struct adapter *adap, struct sge_txq *q)
+ {
++      struct sge *s = &adap->sge;
++
+       dma_free_coherent(adap->pdev_dev,
+-                        q->size * sizeof(struct tx_desc) + STAT_LEN,
++                        q->size * sizeof(struct tx_desc) + s->stat_len,
+                         q->desc, q->phys_addr);
+       q->cntxt_id = 0;
+       q->sdesc = NULL;
+@@ -2262,6 +2329,7 @@ static void free_txq(struct adapter *adap, struct sge_txq *q)
+ static void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq,
+                        struct sge_fl *fl)
+ {
++      struct sge *s = &adap->sge;
+       unsigned int fl_id = fl ? fl->cntxt_id : 0xffff;
+       adap->sge.ingr_map[rq->cntxt_id - adap->sge.ingr_start] = NULL;
+@@ -2276,7 +2344,7 @@ static void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq,
+       if (fl) {
+               free_rx_bufs(adap, fl, fl->avail);
+-              dma_free_coherent(adap->pdev_dev, fl->size * 8 + STAT_LEN,
++              dma_free_coherent(adap->pdev_dev, fl->size * 8 + s->stat_len,
+                                 fl->desc, fl->addr);
+               kfree(fl->sdesc);
+               fl->sdesc = NULL;
+@@ -2408,18 +2476,112 @@ void t4_sge_stop(struct adapter *adap)
+  *    Performs SGE initialization needed every time after a chip reset.
+  *    We do not initialize any of the queues here, instead the driver
+  *    top-level must request them individually.
++ *
++ *    Called in two different modes:
++ *
++ *     1. Perform actual hardware initialization and record hard-coded
++ *        parameters which were used.  This gets used when we're the
++ *        Master PF and the Firmware Configuration File support didn't
++ *        work for some reason.
++ *
++ *     2. We're not the Master PF or initialization was performed with
++ *        a Firmware Configuration File.  In this case we need to grab
++ *        any of the SGE operating parameters that we need to have in
++ *        order to do our job and make sure we can live with them ...
+  */
+-void t4_sge_init(struct adapter *adap)
++
++static int t4_sge_init_soft(struct adapter *adap)
+ {
+-      unsigned int i, v;
+       struct sge *s = &adap->sge;
+-      unsigned int fl_align_log = ilog2(FL_ALIGN);
++      u32 fl_small_pg, fl_large_pg, fl_small_mtu, fl_large_mtu;
++      u32 timer_value_0_and_1, timer_value_2_and_3, timer_value_4_and_5;
++      u32 ingress_rx_threshold;
+-      t4_set_reg_field(adap, SGE_CONTROL, PKTSHIFT_MASK |
+-                       INGPADBOUNDARY_MASK | EGRSTATUSPAGESIZE,
+-                       INGPADBOUNDARY(fl_align_log - 5) | PKTSHIFT(2) |
+-                       RXPKTCPLMODE |
+-                       (STAT_LEN == 128 ? EGRSTATUSPAGESIZE : 0));
++      /*
++       * Verify that CPL messages are going to the Ingress Queue for
++       * process_responses() and that only packet data is going to the
++       * Free Lists.
++       */
++      if ((t4_read_reg(adap, SGE_CONTROL) & RXPKTCPLMODE_MASK) !=
++          RXPKTCPLMODE(X_RXPKTCPLMODE_SPLIT)) {
++              dev_err(adap->pdev_dev, "bad SGE CPL MODE\n");
++              return -EINVAL;
++      }
++
++      /*
++       * Validate the Host Buffer Register Array indices that we want to
++       * use ...
++       *
++       * XXX Note that we should really read through the Host Buffer Size
++       * XXX register array and find the indices of the Buffer Sizes which
++       * XXX meet our needs!
++       */
++      #define READ_FL_BUF(x) \
++              t4_read_reg(adap, SGE_FL_BUFFER_SIZE0+(x)*sizeof(u32))
++
++      fl_small_pg = READ_FL_BUF(RX_SMALL_PG_BUF);
++      fl_large_pg = READ_FL_BUF(RX_LARGE_PG_BUF);
++      fl_small_mtu = READ_FL_BUF(RX_SMALL_MTU_BUF);
++      fl_large_mtu = READ_FL_BUF(RX_LARGE_MTU_BUF);
++
++      #undef READ_FL_BUF
++
++      if (fl_small_pg != PAGE_SIZE ||
++          (fl_large_pg != 0 && (fl_large_pg <= fl_small_pg ||
++                                (fl_large_pg & (fl_large_pg-1)) != 0))) {
++              dev_err(adap->pdev_dev, "bad SGE FL page buffer sizes [%d, %d]\n",
++                      fl_small_pg, fl_large_pg);
++              return -EINVAL;
++      }
++      if (fl_large_pg)
++              s->fl_pg_order = ilog2(fl_large_pg) - PAGE_SHIFT;
++
++      if (fl_small_mtu < FL_MTU_SMALL_BUFSIZE(adap) ||
++          fl_large_mtu < FL_MTU_LARGE_BUFSIZE(adap)) {
++              dev_err(adap->pdev_dev, "bad SGE FL MTU sizes [%d, %d]\n",
++                      fl_small_mtu, fl_large_mtu);
++              return -EINVAL;
++      }
++
++      /*
++       * Retrieve our RX interrupt holdoff timer values and counter
++       * threshold values from the SGE parameters.
++       */
++      timer_value_0_and_1 = t4_read_reg(adap, SGE_TIMER_VALUE_0_AND_1);
++      timer_value_2_and_3 = t4_read_reg(adap, SGE_TIMER_VALUE_2_AND_3);
++      timer_value_4_and_5 = t4_read_reg(adap, SGE_TIMER_VALUE_4_AND_5);
++      s->timer_val[0] = core_ticks_to_us(adap,
++              TIMERVALUE0_GET(timer_value_0_and_1));
++      s->timer_val[1] = core_ticks_to_us(adap,
++              TIMERVALUE1_GET(timer_value_0_and_1));
++      s->timer_val[2] = core_ticks_to_us(adap,
++              TIMERVALUE2_GET(timer_value_2_and_3));
++      s->timer_val[3] = core_ticks_to_us(adap,
++              TIMERVALUE3_GET(timer_value_2_and_3));
++      s->timer_val[4] = core_ticks_to_us(adap,
++              TIMERVALUE4_GET(timer_value_4_and_5));
++      s->timer_val[5] = core_ticks_to_us(adap,
++              TIMERVALUE5_GET(timer_value_4_and_5));
++
++      ingress_rx_threshold = t4_read_reg(adap, SGE_INGRESS_RX_THRESHOLD);
++      s->counter_val[0] = THRESHOLD_0_GET(ingress_rx_threshold);
++      s->counter_val[1] = THRESHOLD_1_GET(ingress_rx_threshold);
++      s->counter_val[2] = THRESHOLD_2_GET(ingress_rx_threshold);
++      s->counter_val[3] = THRESHOLD_3_GET(ingress_rx_threshold);
++
++      return 0;
++}
++
++static int t4_sge_init_hard(struct adapter *adap)
++{
++      struct sge *s = &adap->sge;
++
++      /*
++       * Set up our basic SGE mode to deliver CPL messages to our Ingress
++       * Queue and Packet Date to the Free List.
++       */
++      t4_set_reg_field(adap, SGE_CONTROL, RXPKTCPLMODE_MASK,
++                       RXPKTCPLMODE_MASK);
+       /*
+        * Set up to drop DOORBELL writes when the DOORBELL FIFO overflows
+@@ -2433,13 +2595,24 @@ void t4_sge_init(struct adapter *adap)
+       t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_ENABLE_DROP,
+                       F_ENABLE_DROP);
+-      for (i = v = 0; i < 32; i += 4)
+-              v |= (PAGE_SHIFT - 10) << i;
+-      t4_write_reg(adap, SGE_HOST_PAGE_SIZE, v);
+-      t4_write_reg(adap, SGE_FL_BUFFER_SIZE0, PAGE_SIZE);
+-#if FL_PG_ORDER > 0
+-      t4_write_reg(adap, SGE_FL_BUFFER_SIZE1, PAGE_SIZE << FL_PG_ORDER);
+-#endif
++      /*
++       * SGE_FL_BUFFER_SIZE0 (RX_SMALL_PG_BUF) is set up by
++       * t4_fixup_host_params().
++       */
++      s->fl_pg_order = FL_PG_ORDER;
++      if (s->fl_pg_order)
++              t4_write_reg(adap,
++                           SGE_FL_BUFFER_SIZE0+RX_LARGE_PG_BUF*sizeof(u32),
++                           PAGE_SIZE << FL_PG_ORDER);
++      t4_write_reg(adap, SGE_FL_BUFFER_SIZE0+RX_SMALL_MTU_BUF*sizeof(u32),
++                   FL_MTU_SMALL_BUFSIZE(adap));
++      t4_write_reg(adap, SGE_FL_BUFFER_SIZE0+RX_LARGE_MTU_BUF*sizeof(u32),
++                   FL_MTU_LARGE_BUFSIZE(adap));
++
++      /*
++       * Note that the SGE Ingress Packet Count Interrupt Threshold and
++       * Timer Holdoff values must be supplied by our caller.
++       */
+       t4_write_reg(adap, SGE_INGRESS_RX_THRESHOLD,
+                    THRESHOLD_0(s->counter_val[0]) |
+                    THRESHOLD_1(s->counter_val[1]) |
+@@ -2449,14 +2622,54 @@ void t4_sge_init(struct adapter *adap)
+                    TIMERVALUE0(us_to_core_ticks(adap, s->timer_val[0])) |
+                    TIMERVALUE1(us_to_core_ticks(adap, s->timer_val[1])));
+       t4_write_reg(adap, SGE_TIMER_VALUE_2_AND_3,
+-                   TIMERVALUE0(us_to_core_ticks(adap, s->timer_val[2])) |
+-                   TIMERVALUE1(us_to_core_ticks(adap, s->timer_val[3])));
++                   TIMERVALUE2(us_to_core_ticks(adap, s->timer_val[2])) |
++                   TIMERVALUE3(us_to_core_ticks(adap, s->timer_val[3])));
+       t4_write_reg(adap, SGE_TIMER_VALUE_4_AND_5,
+-                   TIMERVALUE0(us_to_core_ticks(adap, s->timer_val[4])) |
+-                   TIMERVALUE1(us_to_core_ticks(adap, s->timer_val[5])));
++                   TIMERVALUE4(us_to_core_ticks(adap, s->timer_val[4])) |
++                   TIMERVALUE5(us_to_core_ticks(adap, s->timer_val[5])));
++
++      return 0;
++}
++
++int t4_sge_init(struct adapter *adap)
++{
++      struct sge *s = &adap->sge;
++      u32 sge_control;
++      int ret;
++
++      /*
++       * Ingress Padding Boundary and Egress Status Page Size are set up by
++       * t4_fixup_host_params().
++       */
++      sge_control = t4_read_reg(adap, SGE_CONTROL);
++      s->pktshift = PKTSHIFT_GET(sge_control);
++      s->stat_len = (sge_control & EGRSTATUSPAGESIZE_MASK) ? 128 : 64;
++      s->fl_align = 1 << (INGPADBOUNDARY_GET(sge_control) +
++                          X_INGPADBOUNDARY_SHIFT);
++
++      if (adap->flags & USING_SOFT_PARAMS)
++              ret = t4_sge_init_soft(adap);
++      else
++              ret = t4_sge_init_hard(adap);
++      if (ret < 0)
++              return ret;
++
++      /*
++       * A FL with <= fl_starve_thres buffers is starving and a periodic
++       * timer will attempt to refill it.  This needs to be larger than the
++       * SGE's Egress Congestion Threshold.  If it isn't, then we can get
++       * stuck waiting for new packets while the SGE is waiting for us to
++       * give it more Free List entries.  (Note that the SGE's Egress
++       * Congestion Threshold is in units of 2 Free List pointers.)
++       */
++      s->fl_starve_thres
++              = EGRTHRESHOLD_GET(t4_read_reg(adap, SGE_CONM_CTRL))*2 + 1;
++
+       setup_timer(&s->rx_timer, sge_rx_timer_cb, (unsigned long)adap);
+       setup_timer(&s->tx_timer, sge_tx_timer_cb, (unsigned long)adap);
+       s->starve_thres = core_ticks_per_usec(adap) * 1000000;  /* 1 s */
+       s->idma_state[0] = s->idma_state[1] = 0;
+       spin_lock_init(&s->intrq_lock);
++
++      return 0;
+ }
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+index 8e814bc..2767ca6 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+@@ -86,10 +86,17 @@
+ #define  CIDXINC_SHIFT     0
+ #define  CIDXINC(x)        ((x) << CIDXINC_SHIFT)
++#define X_RXPKTCPLMODE_SPLIT     1
++#define X_INGPADBOUNDARY_SHIFT 5
++
+ #define SGE_CONTROL 0x1008
+ #define  DCASYSTYPE             0x00080000U
+-#define  RXPKTCPLMODE           0x00040000U
+-#define  EGRSTATUSPAGESIZE      0x00020000U
++#define  RXPKTCPLMODE_MASK      0x00040000U
++#define  RXPKTCPLMODE_SHIFT     18
++#define  RXPKTCPLMODE(x)        ((x) << RXPKTCPLMODE_SHIFT)
++#define  EGRSTATUSPAGESIZE_MASK  0x00020000U
++#define  EGRSTATUSPAGESIZE_SHIFT 17
++#define  EGRSTATUSPAGESIZE(x)    ((x) << EGRSTATUSPAGESIZE_SHIFT)
+ #define  PKTSHIFT_MASK          0x00001c00U
+ #define  PKTSHIFT_SHIFT         10
+ #define  PKTSHIFT(x)            ((x) << PKTSHIFT_SHIFT)
+@@ -173,6 +180,12 @@
+ #define  THRESHOLD_3(x)     ((x) << THRESHOLD_3_SHIFT)
+ #define  THRESHOLD_3_GET(x) (((x) & THRESHOLD_3_MASK) >> THRESHOLD_3_SHIFT)
++#define SGE_CONM_CTRL 0x1094
++#define  EGRTHRESHOLD_MASK   0x00003f00U
++#define  EGRTHRESHOLDshift   8
++#define  EGRTHRESHOLD(x)     ((x) << EGRTHRESHOLDshift)
++#define  EGRTHRESHOLD_GET(x) (((x) & EGRTHRESHOLD_MASK) >> EGRTHRESHOLDshift)
++
+ #define SGE_TIMER_VALUE_0_AND_1 0x10b8
+ #define  TIMERVALUE0_MASK   0xffff0000U
+ #define  TIMERVALUE0_SHIFT  16
+@@ -184,7 +197,25 @@
+ #define  TIMERVALUE1_GET(x) (((x) & TIMERVALUE1_MASK) >> TIMERVALUE1_SHIFT)
+ #define SGE_TIMER_VALUE_2_AND_3 0x10bc
++#define  TIMERVALUE2_MASK   0xffff0000U
++#define  TIMERVALUE2_SHIFT  16
++#define  TIMERVALUE2(x)     ((x) << TIMERVALUE2_SHIFT)
++#define  TIMERVALUE2_GET(x) (((x) & TIMERVALUE2_MASK) >> TIMERVALUE2_SHIFT)
++#define  TIMERVALUE3_MASK   0x0000ffffU
++#define  TIMERVALUE3_SHIFT  0
++#define  TIMERVALUE3(x)     ((x) << TIMERVALUE3_SHIFT)
++#define  TIMERVALUE3_GET(x) (((x) & TIMERVALUE3_MASK) >> TIMERVALUE3_SHIFT)
++
+ #define SGE_TIMER_VALUE_4_AND_5 0x10c0
++#define  TIMERVALUE4_MASK   0xffff0000U
++#define  TIMERVALUE4_SHIFT  16
++#define  TIMERVALUE4(x)     ((x) << TIMERVALUE4_SHIFT)
++#define  TIMERVALUE4_GET(x) (((x) & TIMERVALUE4_MASK) >> TIMERVALUE4_SHIFT)
++#define  TIMERVALUE5_MASK   0x0000ffffU
++#define  TIMERVALUE5_SHIFT  0
++#define  TIMERVALUE5(x)     ((x) << TIMERVALUE5_SHIFT)
++#define  TIMERVALUE5_GET(x) (((x) & TIMERVALUE5_MASK) >> TIMERVALUE5_SHIFT)
++
+ #define SGE_DEBUG_INDEX 0x10cc
+ #define SGE_DEBUG_DATA_HIGH 0x10d0
+ #define SGE_DEBUG_DATA_LOW 0x10d4
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+index ad53f79..94e3484 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+@@ -401,6 +401,14 @@ enum fw_caps_config_fcoe {
+       FW_CAPS_CONFIG_FCOE_TARGET      = 0x00000002,
+ };
++enum fw_memtype_cf {
++      FW_MEMTYPE_CF_EDC0              = 0x0,
++      FW_MEMTYPE_CF_EDC1              = 0x1,
++      FW_MEMTYPE_CF_EXTMEM            = 0x2,
++      FW_MEMTYPE_CF_FLASH             = 0x4,
++      FW_MEMTYPE_CF_INTERNAL          = 0x5,
++};
++
+ struct fw_caps_config_cmd {
+       __be32 op_to_write;
+       __be32 retval_len16;
+@@ -416,10 +424,15 @@ struct fw_caps_config_cmd {
+       __be16 r4;
+       __be16 iscsicaps;
+       __be16 fcoecaps;
+-      __be32 r5;
+-      __be64 r6;
++      __be32 cfcsum;
++      __be32 finiver;
++      __be32 finicsum;
+ };
++#define FW_CAPS_CONFIG_CMD_CFVALID          (1U << 27)
++#define FW_CAPS_CONFIG_CMD_MEMTYPE_CF(x)    ((x) << 24)
++#define FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(x) ((x) << 16)
++
+ /*
+  * params command mnemonics
+  */
+@@ -451,6 +464,7 @@ enum fw_params_param_dev {
+       FW_PARAMS_PARAM_DEV_INTVER_FCOE = 0x0A,
+       FW_PARAMS_PARAM_DEV_FWREV = 0x0B,
+       FW_PARAMS_PARAM_DEV_TPREV = 0x0C,
++      FW_PARAMS_PARAM_DEV_CF = 0x0D,
+ };
+ /*
+@@ -492,6 +506,8 @@ enum fw_params_param_pfvf {
+       FW_PARAMS_PARAM_PFVF_IQFLINT_END = 0x2A,
+       FW_PARAMS_PARAM_PFVF_EQ_START   = 0x2B,
+       FW_PARAMS_PARAM_PFVF_EQ_END     = 0x2C,
++      FW_PARAMS_PARAM_PFVF_ACTIVE_FILTER_START = 0x2D,
++      FW_PARAMS_PARAM_PFVF_ACTIVE_FILTER_END = 0x2E
+ };
+ /*
+@@ -507,8 +523,16 @@ enum fw_params_param_dmaq {
+ #define FW_PARAMS_MNEM(x)      ((x) << 24)
+ #define FW_PARAMS_PARAM_X(x)   ((x) << 16)
+-#define FW_PARAMS_PARAM_Y(x)   ((x) << 8)
+-#define FW_PARAMS_PARAM_Z(x)   ((x) << 0)
++#define FW_PARAMS_PARAM_Y_SHIFT  8
++#define FW_PARAMS_PARAM_Y_MASK   0xffU
++#define FW_PARAMS_PARAM_Y(x)     ((x) << FW_PARAMS_PARAM_Y_SHIFT)
++#define FW_PARAMS_PARAM_Y_GET(x) (((x) >> FW_PARAMS_PARAM_Y_SHIFT) &\
++              FW_PARAMS_PARAM_Y_MASK)
++#define FW_PARAMS_PARAM_Z_SHIFT  0
++#define FW_PARAMS_PARAM_Z_MASK   0xffu
++#define FW_PARAMS_PARAM_Z(x)     ((x) << FW_PARAMS_PARAM_Z_SHIFT)
++#define FW_PARAMS_PARAM_Z_GET(x) (((x) >> FW_PARAMS_PARAM_Z_SHIFT) &\
++              FW_PARAMS_PARAM_Z_MASK)
+ #define FW_PARAMS_PARAM_XYZ(x) ((x) << 0)
+ #define FW_PARAMS_PARAM_YZ(x)  ((x) << 0)
+@@ -1599,6 +1623,15 @@ struct fw_debug_cmd {
+       } u;
+ };
++#define FW_PCIE_FW_ERR           (1U << 31)
++#define FW_PCIE_FW_INIT          (1U << 30)
++#define FW_PCIE_FW_MASTER_VLD    (1U << 15)
++#define FW_PCIE_FW_MASTER_MASK   0x7
++#define FW_PCIE_FW_MASTER_SHIFT  12
++#define FW_PCIE_FW_MASTER(x)     ((x) << FW_PCIE_FW_MASTER_SHIFT)
++#define FW_PCIE_FW_MASTER_GET(x) (((x) >> FW_PCIE_FW_MASTER_SHIFT) & \
++                               FW_PCIE_FW_MASTER_MASK)
++
+ struct fw_hdr {
+       u8 ver;
+       u8 reserved1;
+-- 
+1.7.1
+
diff --git a/linux-next-cherry-picks/0005-cxgb4-Add-support-for-T4-configuration-file.patch b/linux-next-cherry-picks/0005-cxgb4-Add-support-for-T4-configuration-file.patch
new file mode 100644 (file)
index 0000000..9f94811
--- /dev/null
@@ -0,0 +1,1435 @@
+From 636f9d371f70f22961fd598fe18380057518ca31 Mon Sep 17 00:00:00 2001
+From: Vipul Pandya <vipul@chelsio.com>
+Date: Wed, 26 Sep 2012 02:39:39 +0000
+Subject: [PATCH 3/6] cxgb4: Add support for T4 configuration file
+
+Starting with T4 firmware version 1.3.11.0 the firmware now supports device
+configuration via a Firmware Configuration File. The Firmware Configuration
+File was primarily developed in order to centralize all of the configuration,
+resource allocation, etc. for Unified Wire operation where multiple
+Physical / Virtual Function Drivers would be using a T4 adapter simultaneously.
+
+The Firmware Configuration file can live in three locations as shown below
+in order of precedence.
+1) User defined configuration file: /lib/firmware/cxgb4/t4-config.txt
+2) Factory Default configuration file written to FLASH within
+   the manufacturing process.
+3) Hardwired driver configuration.
+
+Signed-off-by: Jay Hernandez <jay@chelsio.com>
+Signed-off-by: Vipul Pandya <vipul@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h      |   15 +
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c |  570 +++++++++++++++++++----
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h  |    2 +
+ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c      |  392 +++++++++++++++-
+ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h    |   37 ++-
+ drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h   |   37 +-
+ 6 files changed, 920 insertions(+), 133 deletions(-)
+
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+index ae040cf..777cbb4 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -211,6 +211,9 @@ struct tp_err_stats {
+ struct tp_params {
+       unsigned int ntxchan;        /* # of Tx channels */
+       unsigned int tre;            /* log2 of core clocks per TP tick */
++
++      uint32_t dack_re;            /* DACK timer resolution */
++      unsigned short tx_modq[NCHAN];  /* channel to modulation queue map */
+ };
+ struct vpd_params {
+@@ -519,6 +522,8 @@ struct adapter {
+       struct net_device *port[MAX_NPORTS];
+       u8 chan_map[NCHAN];                   /* channel -> port map */
++      unsigned int l2t_start;
++      unsigned int l2t_end;
+       struct l2t_data *l2t;
+       void *uld_handle[CXGB4_ULD_MAX];
+       struct list_head list_node;
+@@ -683,7 +688,9 @@ int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port);
+ int t4_memory_write(struct adapter *adap, int mtype, u32 addr, u32 len,
+                   __be32 *buf);
+ int t4_seeprom_wp(struct adapter *adapter, bool enable);
++int get_vpd_params(struct adapter *adapter, struct vpd_params *p);
+ int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size);
++unsigned int t4_flash_cfg_addr(struct adapter *adapter);
+ int t4_check_fw_version(struct adapter *adapter);
+ int t4_prep_adapter(struct adapter *adapter);
+ int t4_port_init(struct adapter *adap, int mbox, int pf, int vf);
+@@ -698,6 +705,8 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data,
+ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p);
+ void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log);
++void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr,
++                          unsigned int mask, unsigned int val);
+ void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
+                        struct tp_tcp_stats *v6);
+ void t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
+@@ -713,6 +722,12 @@ int t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox,
+ int t4_fw_bye(struct adapter *adap, unsigned int mbox);
+ int t4_early_init(struct adapter *adap, unsigned int mbox);
+ int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset);
++int t4_fw_config_file(struct adapter *adap, unsigned int mbox,
++                    unsigned int mtype, unsigned int maddr,
++                    u32 *finiver, u32 *finicsum, u32 *cfcsum);
++int t4_fixup_host_params(struct adapter *adap, unsigned int page_size,
++                        unsigned int cache_line_size);
++int t4_fw_initialize(struct adapter *adap, unsigned int mbox);
+ int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
+                   unsigned int vf, unsigned int nparams, const u32 *params,
+                   u32 *val);
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+index 34d510d..cb3e663 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -193,6 +193,7 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = {
+ };
+ #define FW_FNAME "cxgb4/t4fw.bin"
++#define FW_CFNAME "cxgb4/t4-config.txt"
+ MODULE_DESCRIPTION(DRV_DESC);
+ MODULE_AUTHOR("Chelsio Communications");
+@@ -201,6 +202,17 @@ MODULE_VERSION(DRV_VERSION);
+ MODULE_DEVICE_TABLE(pci, cxgb4_pci_tbl);
+ MODULE_FIRMWARE(FW_FNAME);
++/*
++ * Normally we're willing to become the firmware's Master PF but will be happy
++ * if another PF has already become the Master and initialized the adapter.
++ * Setting "force_init" will cause this driver to forcibly establish itself as
++ * the Master PF and initialize the adapter.
++ */
++static uint force_init;
++
++module_param(force_init, uint, 0644);
++MODULE_PARM_DESC(force_init, "Forcibly become Master PF and initialize adapter");
++
+ static int dflt_msg_enable = DFLT_MSG_ENABLE;
+ module_param(dflt_msg_enable, int, 0644);
+@@ -236,6 +248,20 @@ module_param_array(intr_cnt, uint, NULL, 0644);
+ MODULE_PARM_DESC(intr_cnt,
+                "thresholds 1..3 for queue interrupt packet counters");
++/*
++ * Normally we tell the chip to deliver Ingress Packets into our DMA buffers
++ * offset by 2 bytes in order to have the IP headers line up on 4-byte
++ * boundaries.  This is a requirement for many architectures which will throw
++ * a machine check fault if an attempt is made to access one of the 4-byte IP
++ * header fields on a non-4-byte boundary.  And it's a major performance issue
++ * even on some architectures which allow it like some implementations of the
++ * x86 ISA.  However, some architectures don't mind this and for some very
++ * edge-case performance sensitive applications (like forwarding large volumes
++ * of small packets), setting this DMA offset to 0 will decrease the number of
++ * PCI-E Bus transfers enough to measurably affect performance.
++ */
++static int rx_dma_offset = 2;
++
+ static bool vf_acls;
+ #ifdef CONFIG_PCI_IOV
+@@ -3076,6 +3102,10 @@ static void setup_memwin(struct adapter *adap)
+       t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2),
+                    (bar0 + MEMWIN2_BASE) | BIR(0) |
+                    WINDOW(ilog2(MEMWIN2_APERTURE) - 10));
++}
++
++static void setup_memwin_rdma(struct adapter *adap)
++{
+       if (adap->vres.ocq.size) {
+               unsigned int start, sz_kb;
+@@ -3155,6 +3185,232 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
+ /*
+  * Phase 0 of initialization: contact FW, obtain config, perform basic init.
++ *
++ * If the firmware we're dealing with has Configuration File support, then
++ * we use that to perform all configuration
++ */
++
++/*
++ * Tweak configuration based on module parameters, etc.  Most of these have
++ * defaults assigned to them by Firmware Configuration Files (if we're using
++ * them) but need to be explicitly set if we're using hard-coded
++ * initialization.  But even in the case of using Firmware Configuration
++ * Files, we'd like to expose the ability to change these via module
++ * parameters so these are essentially common tweaks/settings for
++ * Configuration Files and hard-coded initialization ...
++ */
++static int adap_init0_tweaks(struct adapter *adapter)
++{
++      /*
++       * Fix up various Host-Dependent Parameters like Page Size, Cache
++       * Line Size, etc.  The firmware default is for a 4KB Page Size and
++       * 64B Cache Line Size ...
++       */
++      t4_fixup_host_params(adapter, PAGE_SIZE, L1_CACHE_BYTES);
++
++      /*
++       * Process module parameters which affect early initialization.
++       */
++      if (rx_dma_offset != 2 && rx_dma_offset != 0) {
++              dev_err(&adapter->pdev->dev,
++                      "Ignoring illegal rx_dma_offset=%d, using 2\n",
++                      rx_dma_offset);
++              rx_dma_offset = 2;
++      }
++      t4_set_reg_field(adapter, SGE_CONTROL,
++                       PKTSHIFT_MASK,
++                       PKTSHIFT(rx_dma_offset));
++
++      /*
++       * Don't include the "IP Pseudo Header" in CPL_RX_PKT checksums: Linux
++       * adds the pseudo header itself.
++       */
++      t4_tp_wr_bits_indirect(adapter, TP_INGRESS_CONFIG,
++                             CSUM_HAS_PSEUDO_HDR, 0);
++
++      return 0;
++}
++
++/*
++ * Attempt to initialize the adapter via a Firmware Configuration File.
++ */
++static int adap_init0_config(struct adapter *adapter, int reset)
++{
++      struct fw_caps_config_cmd caps_cmd;
++      const struct firmware *cf;
++      unsigned long mtype = 0, maddr = 0;
++      u32 finiver, finicsum, cfcsum;
++      int ret, using_flash;
++
++      /*
++       * Reset device if necessary.
++       */
++      if (reset) {
++              ret = t4_fw_reset(adapter, adapter->mbox,
++                                PIORSTMODE | PIORST);
++              if (ret < 0)
++                      goto bye;
++      }
++
++      /*
++       * If we have a T4 configuration file under /lib/firmware/cxgb4/,
++       * then use that.  Otherwise, use the configuration file stored
++       * in the adapter flash ...
++       */
++      ret = request_firmware(&cf, FW_CFNAME, adapter->pdev_dev);
++      if (ret < 0) {
++              using_flash = 1;
++              mtype = FW_MEMTYPE_CF_FLASH;
++              maddr = t4_flash_cfg_addr(adapter);
++      } else {
++              u32 params[7], val[7];
++
++              using_flash = 0;
++              if (cf->size >= FLASH_CFG_MAX_SIZE)
++                      ret = -ENOMEM;
++              else {
++                      params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
++                           FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_CF));
++                      ret = t4_query_params(adapter, adapter->mbox,
++                                            adapter->fn, 0, 1, params, val);
++                      if (ret == 0) {
++                              /*
++                               * For t4_memory_write() below addresses and
++                               * sizes have to be in terms of multiples of 4
++                               * bytes.  So, if the Configuration File isn't
++                               * a multiple of 4 bytes in length we'll have
++                               * to write that out separately since we can't
++                               * guarantee that the bytes following the
++                               * residual byte in the buffer returned by
++                               * request_firmware() are zeroed out ...
++                               */
++                              size_t resid = cf->size & 0x3;
++                              size_t size = cf->size & ~0x3;
++                              __be32 *data = (__be32 *)cf->data;
++
++                              mtype = FW_PARAMS_PARAM_Y_GET(val[0]);
++                              maddr = FW_PARAMS_PARAM_Z_GET(val[0]) << 16;
++
++                              ret = t4_memory_write(adapter, mtype, maddr,
++                                                    size, data);
++                              if (ret == 0 && resid != 0) {
++                                      union {
++                                              __be32 word;
++                                              char buf[4];
++                                      } last;
++                                      int i;
++
++                                      last.word = data[size >> 2];
++                                      for (i = resid; i < 4; i++)
++                                              last.buf[i] = 0;
++                                      ret = t4_memory_write(adapter, mtype,
++                                                            maddr + size,
++                                                            4, &last.word);
++                              }
++                      }
++              }
++
++              release_firmware(cf);
++              if (ret)
++                      goto bye;
++      }
++
++      /*
++       * Issue a Capability Configuration command to the firmware to get it
++       * to parse the Configuration File.  We don't use t4_fw_config_file()
++       * because we want the ability to modify various features after we've
++       * processed the configuration file ...
++       */
++      memset(&caps_cmd, 0, sizeof(caps_cmd));
++      caps_cmd.op_to_write =
++              htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
++                    FW_CMD_REQUEST |
++                    FW_CMD_READ);
++      caps_cmd.retval_len16 =
++              htonl(FW_CAPS_CONFIG_CMD_CFVALID |
++                    FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) |
++                    FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(maddr >> 16) |
++                    FW_LEN16(caps_cmd));
++      ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
++                       &caps_cmd);
++      if (ret < 0)
++              goto bye;
++
++      finiver = ntohl(caps_cmd.finiver);
++      finicsum = ntohl(caps_cmd.finicsum);
++      cfcsum = ntohl(caps_cmd.cfcsum);
++      if (finicsum != cfcsum)
++              dev_warn(adapter->pdev_dev, "Configuration File checksum "\
++                       "mismatch: [fini] csum=%#x, computed csum=%#x\n",
++                       finicsum, cfcsum);
++
++      /*
++       * If we're a pure NIC driver then disable all offloading facilities.
++       * This will allow the firmware to optimize aspects of the hardware
++       * configuration which will result in improved performance.
++       */
++      caps_cmd.ofldcaps = 0;
++      caps_cmd.iscsicaps = 0;
++      caps_cmd.rdmacaps = 0;
++      caps_cmd.fcoecaps = 0;
++
++      /*
++       * And now tell the firmware to use the configuration we just loaded.
++       */
++      caps_cmd.op_to_write =
++              htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
++                    FW_CMD_REQUEST |
++                    FW_CMD_WRITE);
++      caps_cmd.retval_len16 = htonl(FW_LEN16(caps_cmd));
++      ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
++                       NULL);
++      if (ret < 0)
++              goto bye;
++
++      /*
++       * Tweak configuration based on system architecture, module
++       * parameters, etc.
++       */
++      ret = adap_init0_tweaks(adapter);
++      if (ret < 0)
++              goto bye;
++
++      /*
++       * And finally tell the firmware to initialize itself using the
++       * parameters from the Configuration File.
++       */
++      ret = t4_fw_initialize(adapter, adapter->mbox);
++      if (ret < 0)
++              goto bye;
++
++      /*
++       * Return successfully and note that we're operating with parameters
++       * not supplied by the driver, rather than from hard-wired
++       * initialization constants burried in the driver.
++       */
++      adapter->flags |= USING_SOFT_PARAMS;
++      dev_info(adapter->pdev_dev, "Successfully configured using Firmware "\
++               "Configuration File %s, version %#x, computed checksum %#x\n",
++               (using_flash
++                ? "in device FLASH"
++                : "/lib/firmware/" FW_CFNAME),
++               finiver, cfcsum);
++      return 0;
++
++      /*
++       * Something bad happened.  Return the error ...  (If the "error"
++       * is that there's no Configuration File on the adapter we don't
++       * want to issue a warning since this is fairly common.)
++       */
++bye:
++      if (ret != -ENOENT)
++              dev_warn(adapter->pdev_dev, "Configuration file error %d\n",
++                       -ret);
++      return ret;
++}
++
++/*
++ * Phase 0 of initialization: contact FW, obtain config, perform basic init.
+  */
+ static int adap_init0(struct adapter *adap)
+ {
+@@ -3162,72 +3418,197 @@ static int adap_init0(struct adapter *adap)
+       u32 v, port_vec;
+       enum dev_state state;
+       u32 params[7], val[7];
+-      struct fw_caps_config_cmd c;
++      int reset = 1, j;
+-      ret = t4_check_fw_version(adap);
+-      if (ret == -EINVAL || ret > 0) {
+-              if (upgrade_fw(adap) >= 0)             /* recache FW version */
+-                      ret = t4_check_fw_version(adap);
+-      }
+-      if (ret < 0)
+-              return ret;
+-
+-      /* contact FW, request master */
+-      ret = t4_fw_hello(adap, adap->fn, adap->fn, MASTER_MUST, &state);
++      /*
++       * Contact FW, advertising Master capability (and potentially forcing
++       * ourselves as the Master PF if our module parameter force_init is
++       * set).
++       */
++      ret = t4_fw_hello(adap, adap->mbox, adap->fn,
++                        force_init ? MASTER_MUST : MASTER_MAY,
++                        &state);
+       if (ret < 0) {
+               dev_err(adap->pdev_dev, "could not connect to FW, error %d\n",
+                       ret);
+               return ret;
+       }
++      if (ret == adap->mbox)
++              adap->flags |= MASTER_PF;
++      if (force_init && state == DEV_STATE_INIT)
++              state = DEV_STATE_UNINIT;
+-      /* reset device */
+-      ret = t4_fw_reset(adap, adap->fn, PIORSTMODE | PIORST);
+-      if (ret < 0)
+-              goto bye;
+-
+-      for (v = 0; v < SGE_NTIMERS - 1; v++)
+-              adap->sge.timer_val[v] = min(intr_holdoff[v], MAX_SGE_TIMERVAL);
+-      adap->sge.timer_val[SGE_NTIMERS - 1] = MAX_SGE_TIMERVAL;
+-      adap->sge.counter_val[0] = 1;
+-      for (v = 1; v < SGE_NCOUNTERS; v++)
+-              adap->sge.counter_val[v] = min(intr_cnt[v - 1],
+-                                             THRESHOLD_3_MASK);
+-#define FW_PARAM_DEV(param) \
+-      (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \
+-       FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param))
++      /*
++       * If we're the Master PF Driver and the device is uninitialized,
++       * then let's consider upgrading the firmware ...  (We always want
++       * to check the firmware version number in order to A. get it for
++       * later reporting and B. to warn if the currently loaded firmware
++       * is excessively mismatched relative to the driver.)
++       */
++      ret = t4_check_fw_version(adap);
++      if ((adap->flags & MASTER_PF) && state != DEV_STATE_INIT) {
++              if (ret == -EINVAL || ret > 0) {
++                      if (upgrade_fw(adap) >= 0) {
++                              /*
++                               * Note that the chip was reset as part of the
++                               * firmware upgrade so we don't reset it again
++                               * below and grab the new firmware version.
++                               */
++                              reset = 0;
++                              ret = t4_check_fw_version(adap);
++                      }
++              }
++              if (ret < 0)
++                      return ret;
++      }
+-      params[0] = FW_PARAM_DEV(CCLK);
+-      ret = t4_query_params(adap, adap->fn, adap->fn, 0, 1, params, val);
++      /*
++       * Grab VPD parameters.  This should be done after we establish a
++       * connection to the firmware since some of the VPD parameters
++       * (notably the Core Clock frequency) are retrieved via requests to
++       * the firmware.  On the other hand, we need these fairly early on
++       * so we do this right after getting ahold of the firmware.
++       */
++      ret = get_vpd_params(adap, &adap->params.vpd);
+       if (ret < 0)
+               goto bye;
+-      adap->params.vpd.cclk = val[0];
+-      ret = adap_init1(adap, &c);
++      /*
++       * Find out what ports are available to us.
++       */
++      v =
++          FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
++          FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_PORTVEC);
++      ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 1, &v, &port_vec);
+       if (ret < 0)
+               goto bye;
++      adap->params.nports = hweight32(port_vec);
++      adap->params.portvec = port_vec;
++
++      /*
++       * If the firmware is initialized already (and we're not forcing a
++       * master initialization), note that we're living with existing
++       * adapter parameters.  Otherwise, it's time to try initializing the
++       * adapter ...
++       */
++      if (state == DEV_STATE_INIT) {
++              dev_info(adap->pdev_dev, "Coming up as %s: "\
++                       "Adapter already initialized\n",
++                       adap->flags & MASTER_PF ? "MASTER" : "SLAVE");
++              adap->flags |= USING_SOFT_PARAMS;
++      } else {
++              dev_info(adap->pdev_dev, "Coming up as MASTER: "\
++                       "Initializing adapter\n");
++              /*
++               * Find out whether we're dealing with a version of
++               * the firmware which has configuration file support.
++               */
++              params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
++                           FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_CF));
++              ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 1,
++                                    params, val);
++
++              /*
++               * If the firmware doesn't support Configuration
++               * Files warn user and exit,
++               */
++              if (ret < 0)
++                      dev_warn(adap->pdev_dev, "Firmware doesn't support "\
++                               "configuration file.\n");
++              else {
++                      /*
++                       * The firmware provides us with a memory
++                       * buffer where we can load a Configuration
++                       * File from the host if we want to override
++                       * the Configuration File in flash.
++                       */
++
++                      ret = adap_init0_config(adap, reset);
++                      if (ret == -ENOENT) {
++                              dev_info(adap->pdev_dev,
++                                  "No Configuration File present "
++                                  "on adapter.\n");
++                      }
++              }
++              if (ret < 0) {
++                      dev_err(adap->pdev_dev,
++                              "could not initialize adapter, error %d\n",
++                              -ret);
++                      goto bye;
++              }
++      }
++
++      /*
++       * If we're living with non-hard-coded parameters (either from a
++       * Firmware Configuration File or values programmed by a different PF
++       * Driver), give the SGE code a chance to pull in anything that it
++       * needs ...  Note that this must be called after we retrieve our VPD
++       * parameters in order to know how to convert core ticks to seconds.
++       */
++      if (adap->flags & USING_SOFT_PARAMS) {
++              ret = t4_sge_init(adap);
++              if (ret < 0)
++                      goto bye;
++      }
++
++      /*
++       * Grab some of our basic fundamental operating parameters.
++       */
++#define FW_PARAM_DEV(param) \
++      (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \
++      FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param))
++
+ #define FW_PARAM_PFVF(param) \
+-      (FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \
+-       FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param) | \
+-       FW_PARAMS_PARAM_Y(adap->fn))
++      FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \
++      FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)|  \
++      FW_PARAMS_PARAM_Y(0) | \
++      FW_PARAMS_PARAM_Z(0)
+-      params[0] = FW_PARAM_DEV(PORTVEC);
++      params[0] = FW_PARAM_PFVF(EQ_START);
+       params[1] = FW_PARAM_PFVF(L2T_START);
+       params[2] = FW_PARAM_PFVF(L2T_END);
+       params[3] = FW_PARAM_PFVF(FILTER_START);
+       params[4] = FW_PARAM_PFVF(FILTER_END);
+       params[5] = FW_PARAM_PFVF(IQFLINT_START);
+-      params[6] = FW_PARAM_PFVF(EQ_START);
+-      ret = t4_query_params(adap, adap->fn, adap->fn, 0, 7, params, val);
++      ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 6, params, val);
+       if (ret < 0)
+               goto bye;
+-      port_vec = val[0];
++      adap->sge.egr_start = val[0];
++      adap->l2t_start = val[1];
++      adap->l2t_end = val[2];
+       adap->tids.ftid_base = val[3];
+       adap->tids.nftids = val[4] - val[3] + 1;
+       adap->sge.ingr_start = val[5];
+-      adap->sge.egr_start = val[6];
+-      if (c.ofldcaps) {
++      /* query params related to active filter region */
++      params[0] = FW_PARAM_PFVF(ACTIVE_FILTER_START);
++      params[1] = FW_PARAM_PFVF(ACTIVE_FILTER_END);
++      ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val);
++      /* If Active filter size is set we enable establishing
++       * offload connection through firmware work request
++       */
++      if ((val[0] != val[1]) && (ret >= 0)) {
++              adap->flags |= FW_OFLD_CONN;
++              adap->tids.aftid_base = val[0];
++              adap->tids.aftid_end = val[1];
++      }
++
++#ifdef CONFIG_CHELSIO_T4_OFFLOAD
++      /*
++       * Get device capabilities so we can determine what resources we need
++       * to manage.
++       */
++      memset(&caps_cmd, 0, sizeof(caps_cmd));
++      caps_cmd.op_to_write = htonl(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
++                                   F_FW_CMD_REQUEST | F_FW_CMD_READ);
++      caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
++      ret = t4_wr_mbox(adap, adap->mbox, &caps_cmd, sizeof(caps_cmd),
++                       &caps_cmd);
++      if (ret < 0)
++              goto bye;
++
++      if (caps_cmd.toecaps) {
+               /* query offload-related parameters */
+               params[0] = FW_PARAM_DEV(NTID);
+               params[1] = FW_PARAM_PFVF(SERVER_START);
+@@ -3235,28 +3616,55 @@ static int adap_init0(struct adapter *adap)
+               params[3] = FW_PARAM_PFVF(TDDP_START);
+               params[4] = FW_PARAM_PFVF(TDDP_END);
+               params[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ);
+-              ret = t4_query_params(adap, adap->fn, adap->fn, 0, 6, params,
+-                                    val);
++              ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 6,
++                                    params, val);
+               if (ret < 0)
+                       goto bye;
+               adap->tids.ntids = val[0];
+               adap->tids.natids = min(adap->tids.ntids / 2, MAX_ATIDS);
+               adap->tids.stid_base = val[1];
+               adap->tids.nstids = val[2] - val[1] + 1;
++              /*
++               * Setup server filter region. Divide the availble filter
++               * region into two parts. Regular filters get 1/3rd and server
++               * filters get 2/3rd part. This is only enabled if workarond
++               * path is enabled.
++               * 1. For regular filters.
++               * 2. Server filter: This are special filters which are used
++               * to redirect SYN packets to offload queue.
++               */
++              if (adap->flags & FW_OFLD_CONN && !is_bypass(adap)) {
++                      adap->tids.sftid_base = adap->tids.ftid_base +
++                                      DIV_ROUND_UP(adap->tids.nftids, 3);
++                      adap->tids.nsftids = adap->tids.nftids -
++                                       DIV_ROUND_UP(adap->tids.nftids, 3);
++                      adap->tids.nftids = adap->tids.sftid_base -
++                                              adap->tids.ftid_base;
++              }
+               adap->vres.ddp.start = val[3];
+               adap->vres.ddp.size = val[4] - val[3] + 1;
+               adap->params.ofldq_wr_cred = val[5];
++
++              params[0] = FW_PARAM_PFVF(ETHOFLD_START);
++              params[1] = FW_PARAM_PFVF(ETHOFLD_END);
++              ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2,
++                                    params, val);
++              if ((val[0] != val[1]) && (ret >= 0)) {
++                      adap->tids.uotid_base = val[0];
++                      adap->tids.nuotids = val[1] - val[0] + 1;
++              }
++
+               adap->params.offload = 1;
+       }
+-      if (c.rdmacaps) {
++      if (caps_cmd.rdmacaps) {
+               params[0] = FW_PARAM_PFVF(STAG_START);
+               params[1] = FW_PARAM_PFVF(STAG_END);
+               params[2] = FW_PARAM_PFVF(RQ_START);
+               params[3] = FW_PARAM_PFVF(RQ_END);
+               params[4] = FW_PARAM_PFVF(PBL_START);
+               params[5] = FW_PARAM_PFVF(PBL_END);
+-              ret = t4_query_params(adap, adap->fn, adap->fn, 0, 6, params,
+-                                    val);
++              ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 6,
++                                    params, val);
+               if (ret < 0)
+                       goto bye;
+               adap->vres.stag.start = val[0];
+@@ -3272,8 +3680,7 @@ static int adap_init0(struct adapter *adap)
+               params[3] = FW_PARAM_PFVF(CQ_END);
+               params[4] = FW_PARAM_PFVF(OCQ_START);
+               params[5] = FW_PARAM_PFVF(OCQ_END);
+-              ret = t4_query_params(adap, adap->fn, adap->fn, 0, 6, params,
+-                                    val);
++              ret = t4_query_params(adap, 0, 0, 0, 6, params, val);
+               if (ret < 0)
+                       goto bye;
+               adap->vres.qp.start = val[0];
+@@ -3283,11 +3690,11 @@ static int adap_init0(struct adapter *adap)
+               adap->vres.ocq.start = val[4];
+               adap->vres.ocq.size = val[5] - val[4] + 1;
+       }
+-      if (c.iscsicaps) {
++      if (caps_cmd.iscsicaps) {
+               params[0] = FW_PARAM_PFVF(ISCSI_START);
+               params[1] = FW_PARAM_PFVF(ISCSI_END);
+-              ret = t4_query_params(adap, adap->fn, adap->fn, 0, 2, params,
+-                                    val);
++              ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2,
++                                    params, val);
+               if (ret < 0)
+                       goto bye;
+               adap->vres.iscsi.start = val[0];
+@@ -3295,63 +3702,33 @@ static int adap_init0(struct adapter *adap)
+       }
+ #undef FW_PARAM_PFVF
+ #undef FW_PARAM_DEV
++#endif /* CONFIG_CHELSIO_T4_OFFLOAD */
+-      adap->params.nports = hweight32(port_vec);
+-      adap->params.portvec = port_vec;
+-      adap->flags |= FW_OK;
+-
+-      /* These are finalized by FW initialization, load their values now */
++      /*
++       * These are finalized by FW initialization, load their values now.
++       */
+       v = t4_read_reg(adap, TP_TIMER_RESOLUTION);
+       adap->params.tp.tre = TIMERRESOLUTION_GET(v);
++      adap->params.tp.dack_re = DELAYEDACKRESOLUTION_GET(v);
+       t4_read_mtu_tbl(adap, adap->params.mtus, NULL);
+       t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd,
+                    adap->params.b_wnd);
+-#ifdef CONFIG_PCI_IOV
+-      /*
+-       * Provision resource limits for Virtual Functions.  We currently
+-       * grant them all the same static resource limits except for the Port
+-       * Access Rights Mask which we're assigning based on the PF.  All of
+-       * the static provisioning stuff for both the PF and VF really needs
+-       * to be managed in a persistent manner for each device which the
+-       * firmware controls.
+-       */
+-      {
+-              int pf, vf;
+-
+-              for (pf = 0; pf < ARRAY_SIZE(num_vf); pf++) {
+-                      if (num_vf[pf] <= 0)
+-                              continue;
+-
+-                      /* VF numbering starts at 1! */
+-                      for (vf = 1; vf <= num_vf[pf]; vf++) {
+-                              ret = t4_cfg_pfvf(adap, adap->fn, pf, vf,
+-                                                VFRES_NEQ, VFRES_NETHCTRL,
+-                                                VFRES_NIQFLINT, VFRES_NIQ,
+-                                                VFRES_TC, VFRES_NVI,
+-                                                FW_PFVF_CMD_CMASK_MASK,
+-                                                pfvfres_pmask(adap, pf, vf),
+-                                                VFRES_NEXACTF,
+-                                                VFRES_R_CAPS, VFRES_WX_CAPS);
+-                              if (ret < 0)
+-                                      dev_warn(adap->pdev_dev, "failed to "
+-                                               "provision pf/vf=%d/%d; "
+-                                               "err=%d\n", pf, vf, ret);
+-                      }
+-              }
+-      }
+-#endif
++      /* MODQ_REQ_MAP defaults to setting queues 0-3 to chan 0-3 */
++      for (j = 0; j < NCHAN; j++)
++              adap->params.tp.tx_modq[j] = j;
+-      setup_memwin(adap);
++      adap->flags |= FW_OK;
+       return 0;
+       /*
+-       * If a command timed out or failed with EIO FW does not operate within
+-       * its spec or something catastrophic happened to HW/FW, stop issuing
+-       * commands.
++       * Something bad happened.  If a command timed out or failed with EIO
++       * FW does not operate within its spec or something catastrophic
++       * happened to HW/FW, stop issuing commands.
+        */
+-bye:  if (ret != -ETIMEDOUT && ret != -EIO)
+-              t4_fw_bye(adap, adap->fn);
++bye:
++      if (ret != -ETIMEDOUT && ret != -EIO)
++              t4_fw_bye(adap, adap->mbox);
+       return ret;
+ }
+@@ -3814,7 +4191,9 @@ static int __devinit init_one(struct pci_dev *pdev,
+       err = t4_prep_adapter(adapter);
+       if (err)
+               goto out_unmap_bar;
++      setup_memwin(adapter);
+       err = adap_init0(adapter);
++      setup_memwin_rdma(adapter);
+       if (err)
+               goto out_unmap_bar;
+@@ -3956,8 +4335,11 @@ static void __devexit remove_one(struct pci_dev *pdev)
+ {
+       struct adapter *adapter = pci_get_drvdata(pdev);
++#ifdef CONFIG_PCI_IOV
+       pci_disable_sriov(pdev);
++#endif
++
+       if (adapter) {
+               int i;
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+index d79980c..1b899fe 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+@@ -100,6 +100,8 @@ struct tid_info {
+       unsigned int nftids;
+       unsigned int ftid_base;
++      unsigned int aftid_base;
++      unsigned int aftid_end;
+       spinlock_t atid_lock ____cacheline_aligned_in_smp;
+       union aopen_entry *afree;
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+index 259d0dc..419432d 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+@@ -492,8 +492,9 @@ int t4_seeprom_wp(struct adapter *adapter, bool enable)
+  *
+  *    Reads card parameters stored in VPD EEPROM.
+  */
+-static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
++int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
+ {
++      u32 cclk_param, cclk_val;
+       int i, ret;
+       int ec, sn;
+       u8 vpd[VPD_LEN], csum;
+@@ -555,6 +556,19 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
+       i = pci_vpd_info_field_size(vpd + sn - PCI_VPD_INFO_FLD_HDR_SIZE);
+       memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN));
+       strim(p->sn);
++
++      /*
++       * Ask firmware for the Core Clock since it knows how to translate the
++       * Reference Clock ('V2') VPD field into a Core Clock value ...
++       */
++      cclk_param = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
++                    FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_CCLK));
++      ret = t4_query_params(adapter, adapter->mbox, 0, 0,
++                            1, &cclk_param, &cclk_val);
++      if (ret)
++              return ret;
++      p->cclk = cclk_val;
++
+       return 0;
+ }
+@@ -855,6 +869,77 @@ static int t4_flash_erase_sectors(struct adapter *adapter, int start, int end)
+ }
+ /**
++ *    t4_flash_cfg_addr - return the address of the flash configuration file
++ *    @adapter: the adapter
++ *
++ *    Return the address within the flash where the Firmware Configuration
++ *    File is stored.
++ */
++unsigned int t4_flash_cfg_addr(struct adapter *adapter)
++{
++      if (adapter->params.sf_size == 0x100000)
++              return FLASH_FPGA_CFG_START;
++      else
++              return FLASH_CFG_START;
++}
++
++/**
++ *    t4_load_cfg - download config file
++ *    @adap: the adapter
++ *    @cfg_data: the cfg text file to write
++ *    @size: text file size
++ *
++ *    Write the supplied config text file to the card's serial flash.
++ */
++int t4_load_cfg(struct adapter *adap, const u8 *cfg_data, unsigned int size)
++{
++      int ret, i, n;
++      unsigned int addr;
++      unsigned int flash_cfg_start_sec;
++      unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
++
++      addr = t4_flash_cfg_addr(adap);
++      flash_cfg_start_sec = addr / SF_SEC_SIZE;
++
++      if (size > FLASH_CFG_MAX_SIZE) {
++              dev_err(adap->pdev_dev, "cfg file too large, max is %u bytes\n",
++                      FLASH_CFG_MAX_SIZE);
++              return -EFBIG;
++      }
++
++      i = DIV_ROUND_UP(FLASH_CFG_MAX_SIZE,    /* # of sectors spanned */
++                       sf_sec_size);
++      ret = t4_flash_erase_sectors(adap, flash_cfg_start_sec,
++                                   flash_cfg_start_sec + i - 1);
++      /*
++       * If size == 0 then we're simply erasing the FLASH sectors associated
++       * with the on-adapter Firmware Configuration File.
++       */
++      if (ret || size == 0)
++              goto out;
++
++      /* this will write to the flash up to SF_PAGE_SIZE at a time */
++      for (i = 0; i < size; i += SF_PAGE_SIZE) {
++              if ((size - i) <  SF_PAGE_SIZE)
++                      n = size - i;
++              else
++                      n = SF_PAGE_SIZE;
++              ret = t4_write_flash(adap, addr, n, cfg_data);
++              if (ret)
++                      goto out;
++
++              addr += SF_PAGE_SIZE;
++              cfg_data += SF_PAGE_SIZE;
++      }
++
++out:
++      if (ret)
++              dev_err(adap->pdev_dev, "config file %s failed %d\n",
++                      (size == 0 ? "clear" : "download"), ret);
++      return ret;
++}
++
++/**
+  *    t4_load_fw - download firmware
+  *    @adap: the adapter
+  *    @fw_data: the firmware image to write
+@@ -1854,6 +1939,23 @@ void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log)
+ }
+ /**
++ *    t4_tp_wr_bits_indirect - set/clear bits in an indirect TP register
++ *    @adap: the adapter
++ *    @addr: the indirect TP register address
++ *    @mask: specifies the field within the register to modify
++ *    @val: new value for the field
++ *
++ *    Sets a field of an indirect TP register to the given value.
++ */
++void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr,
++                          unsigned int mask, unsigned int val)
++{
++      t4_write_reg(adap, TP_PIO_ADDR, addr);
++      val |= t4_read_reg(adap, TP_PIO_DATA) & ~mask;
++      t4_write_reg(adap, TP_PIO_DATA, val);
++}
++
++/**
+  *    init_cong_ctrl - initialize congestion control parameters
+  *    @a: the alpha values for congestion control
+  *    @b: the beta values for congestion control
+@@ -2137,9 +2239,9 @@ int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
+       struct fw_ldst_cmd c;
+       memset(&c, 0, sizeof(c));
+-      c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
+-                          F_FW_CMD_WRITE |
+-                          V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FIRMWARE));
++      c.op_to_addrspace = htonl(FW_CMD_OP(FW_LDST_CMD) | FW_CMD_REQUEST |
++                          FW_CMD_WRITE |
++                          FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FIRMWARE));
+       c.cycles_to_len16 = htonl(FW_LEN16(c));
+       c.u.addrval.addr = htonl(addr);
+       c.u.addrval.val = htonl(val);
+@@ -2239,39 +2341,129 @@ int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
+ }
+ /**
+- *    t4_fw_hello - establish communication with FW
+- *    @adap: the adapter
+- *    @mbox: mailbox to use for the FW command
+- *    @evt_mbox: mailbox to receive async FW events
+- *    @master: specifies the caller's willingness to be the device master
+- *    @state: returns the current device state
++ *      t4_fw_hello - establish communication with FW
++ *      @adap: the adapter
++ *      @mbox: mailbox to use for the FW command
++ *      @evt_mbox: mailbox to receive async FW events
++ *      @master: specifies the caller's willingness to be the device master
++ *    @state: returns the current device state (if non-NULL)
+  *
+- *    Issues a command to establish communication with FW.
++ *    Issues a command to establish communication with FW.  Returns either
++ *    an error (negative integer) or the mailbox of the Master PF.
+  */
+ int t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox,
+               enum dev_master master, enum dev_state *state)
+ {
+       int ret;
+       struct fw_hello_cmd c;
++      u32 v;
++      unsigned int master_mbox;
++      int retries = FW_CMD_HELLO_RETRIES;
++retry:
++      memset(&c, 0, sizeof(c));
+       INIT_CMD(c, HELLO, WRITE);
+       c.err_to_mbasyncnot = htonl(
+               FW_HELLO_CMD_MASTERDIS(master == MASTER_CANT) |
+               FW_HELLO_CMD_MASTERFORCE(master == MASTER_MUST) |
+-              FW_HELLO_CMD_MBMASTER(master == MASTER_MUST ? mbox : 0xff) |
+-              FW_HELLO_CMD_MBASYNCNOT(evt_mbox));
++              FW_HELLO_CMD_MBMASTER(master == MASTER_MUST ? mbox :
++                                    FW_HELLO_CMD_MBMASTER_MASK) |
++              FW_HELLO_CMD_MBASYNCNOT(evt_mbox) |
++              FW_HELLO_CMD_STAGE(fw_hello_cmd_stage_os) |
++              FW_HELLO_CMD_CLEARINIT);
++      /*
++       * Issue the HELLO command to the firmware.  If it's not successful
++       * but indicates that we got a "busy" or "timeout" condition, retry
++       * the HELLO until we exhaust our retry limit.
++       */
+       ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
+-      if (ret == 0 && state) {
+-              u32 v = ntohl(c.err_to_mbasyncnot);
+-              if (v & FW_HELLO_CMD_INIT)
+-                      *state = DEV_STATE_INIT;
+-              else if (v & FW_HELLO_CMD_ERR)
++      if (ret < 0) {
++              if ((ret == -EBUSY || ret == -ETIMEDOUT) && retries-- > 0)
++                      goto retry;
++              return ret;
++      }
++
++      v = ntohl(c.err_to_mbasyncnot);
++      master_mbox = FW_HELLO_CMD_MBMASTER_GET(v);
++      if (state) {
++              if (v & FW_HELLO_CMD_ERR)
+                       *state = DEV_STATE_ERR;
++              else if (v & FW_HELLO_CMD_INIT)
++                      *state = DEV_STATE_INIT;
+               else
+                       *state = DEV_STATE_UNINIT;
+       }
+-      return ret;
++
++      /*
++       * If we're not the Master PF then we need to wait around for the
++       * Master PF Driver to finish setting up the adapter.
++       *
++       * Note that we also do this wait if we're a non-Master-capable PF and
++       * there is no current Master PF; a Master PF may show up momentarily
++       * and we wouldn't want to fail pointlessly.  (This can happen when an
++       * OS loads lots of different drivers rapidly at the same time).  In
++       * this case, the Master PF returned by the firmware will be
++       * FW_PCIE_FW_MASTER_MASK so the test below will work ...
++       */
++      if ((v & (FW_HELLO_CMD_ERR|FW_HELLO_CMD_INIT)) == 0 &&
++          master_mbox != mbox) {
++              int waiting = FW_CMD_HELLO_TIMEOUT;
++
++              /*
++               * Wait for the firmware to either indicate an error or
++               * initialized state.  If we see either of these we bail out
++               * and report the issue to the caller.  If we exhaust the
++               * "hello timeout" and we haven't exhausted our retries, try
++               * again.  Otherwise bail with a timeout error.
++               */
++              for (;;) {
++                      u32 pcie_fw;
++
++                      msleep(50);
++                      waiting -= 50;
++
++                      /*
++                       * If neither Error nor Initialialized are indicated
++                       * by the firmware keep waiting till we exaust our
++                       * timeout ... and then retry if we haven't exhausted
++                       * our retries ...
++                       */
++                      pcie_fw = t4_read_reg(adap, MA_PCIE_FW);
++                      if (!(pcie_fw & (FW_PCIE_FW_ERR|FW_PCIE_FW_INIT))) {
++                              if (waiting <= 0) {
++                                      if (retries-- > 0)
++                                              goto retry;
++
++                                      return -ETIMEDOUT;
++                              }
++                              continue;
++                      }
++
++                      /*
++                       * We either have an Error or Initialized condition
++                       * report errors preferentially.
++                       */
++                      if (state) {
++                              if (pcie_fw & FW_PCIE_FW_ERR)
++                                      *state = DEV_STATE_ERR;
++                              else if (pcie_fw & FW_PCIE_FW_INIT)
++                                      *state = DEV_STATE_INIT;
++                      }
++
++                      /*
++                       * If we arrived before a Master PF was selected and
++                       * there's not a valid Master PF, grab its identity
++                       * for our caller.
++                       */
++                      if (master_mbox == FW_PCIE_FW_MASTER_MASK &&
++                          (pcie_fw & FW_PCIE_FW_MASTER_VLD))
++                              master_mbox = FW_PCIE_FW_MASTER_GET(pcie_fw);
++                      break;
++              }
++      }
++
++      return master_mbox;
+ }
+ /**
+@@ -2323,6 +2515,163 @@ int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset)
+ }
+ /**
++ *    t4_fw_config_file - setup an adapter via a Configuration File
++ *    @adap: the adapter
++ *    @mbox: mailbox to use for the FW command
++ *    @mtype: the memory type where the Configuration File is located
++ *    @maddr: the memory address where the Configuration File is located
++ *    @finiver: return value for CF [fini] version
++ *    @finicsum: return value for CF [fini] checksum
++ *    @cfcsum: return value for CF computed checksum
++ *
++ *    Issue a command to get the firmware to process the Configuration
++ *    File located at the specified mtype/maddress.  If the Configuration
++ *    File is processed successfully and return value pointers are
++ *    provided, the Configuration File "[fini] section version and
++ *    checksum values will be returned along with the computed checksum.
++ *    It's up to the caller to decide how it wants to respond to the
++ *    checksums not matching but it recommended that a prominant warning
++ *    be emitted in order to help people rapidly identify changed or
++ *    corrupted Configuration Files.
++ *
++ *    Also note that it's possible to modify things like "niccaps",
++ *    "toecaps",etc. between processing the Configuration File and telling
++ *    the firmware to use the new configuration.  Callers which want to
++ *    do this will need to "hand-roll" their own CAPS_CONFIGS commands for
++ *    Configuration Files if they want to do this.
++ */
++int t4_fw_config_file(struct adapter *adap, unsigned int mbox,
++                    unsigned int mtype, unsigned int maddr,
++                    u32 *finiver, u32 *finicsum, u32 *cfcsum)
++{
++      struct fw_caps_config_cmd caps_cmd;
++      int ret;
++
++      /*
++       * Tell the firmware to process the indicated Configuration File.
++       * If there are no errors and the caller has provided return value
++       * pointers for the [fini] section version, checksum and computed
++       * checksum, pass those back to the caller.
++       */
++      memset(&caps_cmd, 0, sizeof(caps_cmd));
++      caps_cmd.op_to_write =
++              htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
++                    FW_CMD_REQUEST |
++                    FW_CMD_READ);
++      caps_cmd.retval_len16 =
++              htonl(FW_CAPS_CONFIG_CMD_CFVALID |
++                    FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) |
++                    FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(maddr >> 16) |
++                    FW_LEN16(caps_cmd));
++      ret = t4_wr_mbox(adap, mbox, &caps_cmd, sizeof(caps_cmd), &caps_cmd);
++      if (ret < 0)
++              return ret;
++
++      if (finiver)
++              *finiver = ntohl(caps_cmd.finiver);
++      if (finicsum)
++              *finicsum = ntohl(caps_cmd.finicsum);
++      if (cfcsum)
++              *cfcsum = ntohl(caps_cmd.cfcsum);
++
++      /*
++       * And now tell the firmware to use the configuration we just loaded.
++       */
++      caps_cmd.op_to_write =
++              htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
++                    FW_CMD_REQUEST |
++                    FW_CMD_WRITE);
++      caps_cmd.retval_len16 = htonl(FW_LEN16(caps_cmd));
++      return t4_wr_mbox(adap, mbox, &caps_cmd, sizeof(caps_cmd), NULL);
++}
++
++/**
++ *    t4_fixup_host_params - fix up host-dependent parameters
++ *    @adap: the adapter
++ *    @page_size: the host's Base Page Size
++ *    @cache_line_size: the host's Cache Line Size
++ *
++ *    Various registers in T4 contain values which are dependent on the
++ *    host's Base Page and Cache Line Sizes.  This function will fix all of
++ *    those registers with the appropriate values as passed in ...
++ */
++int t4_fixup_host_params(struct adapter *adap, unsigned int page_size,
++                       unsigned int cache_line_size)
++{
++      unsigned int page_shift = fls(page_size) - 1;
++      unsigned int sge_hps = page_shift - 10;
++      unsigned int stat_len = cache_line_size > 64 ? 128 : 64;
++      unsigned int fl_align = cache_line_size < 32 ? 32 : cache_line_size;
++      unsigned int fl_align_log = fls(fl_align) - 1;
++
++      t4_write_reg(adap, SGE_HOST_PAGE_SIZE,
++                   HOSTPAGESIZEPF0(sge_hps) |
++                   HOSTPAGESIZEPF1(sge_hps) |
++                   HOSTPAGESIZEPF2(sge_hps) |
++                   HOSTPAGESIZEPF3(sge_hps) |
++                   HOSTPAGESIZEPF4(sge_hps) |
++                   HOSTPAGESIZEPF5(sge_hps) |
++                   HOSTPAGESIZEPF6(sge_hps) |
++                   HOSTPAGESIZEPF7(sge_hps));
++
++      t4_set_reg_field(adap, SGE_CONTROL,
++                       INGPADBOUNDARY(INGPADBOUNDARY_MASK) |
++                       EGRSTATUSPAGESIZE_MASK,
++                       INGPADBOUNDARY(fl_align_log - 5) |
++                       EGRSTATUSPAGESIZE(stat_len != 64));
++
++      /*
++       * Adjust various SGE Free List Host Buffer Sizes.
++       *
++       * This is something of a crock since we're using fixed indices into
++       * the array which are also known by the sge.c code and the T4
++       * Firmware Configuration File.  We need to come up with a much better
++       * approach to managing this array.  For now, the first four entries
++       * are:
++       *
++       *   0: Host Page Size
++       *   1: 64KB
++       *   2: Buffer size corresponding to 1500 byte MTU (unpacked mode)
++       *   3: Buffer size corresponding to 9000 byte MTU (unpacked mode)
++       *
++       * For the single-MTU buffers in unpacked mode we need to include
++       * space for the SGE Control Packet Shift, 14 byte Ethernet header,
++       * possible 4 byte VLAN tag, all rounded up to the next Ingress Packet
++       * Padding boundry.  All of these are accommodated in the Factory
++       * Default Firmware Configuration File but we need to adjust it for
++       * this host's cache line size.
++       */
++      t4_write_reg(adap, SGE_FL_BUFFER_SIZE0, page_size);
++      t4_write_reg(adap, SGE_FL_BUFFER_SIZE2,
++                   (t4_read_reg(adap, SGE_FL_BUFFER_SIZE2) + fl_align-1)
++                   & ~(fl_align-1));
++      t4_write_reg(adap, SGE_FL_BUFFER_SIZE3,
++                   (t4_read_reg(adap, SGE_FL_BUFFER_SIZE3) + fl_align-1)
++                   & ~(fl_align-1));
++
++      t4_write_reg(adap, ULP_RX_TDDP_PSZ, HPZ0(page_shift - 12));
++
++      return 0;
++}
++
++/**
++ *    t4_fw_initialize - ask FW to initialize the device
++ *    @adap: the adapter
++ *    @mbox: mailbox to use for the FW command
++ *
++ *    Issues a command to FW to partially initialize the device.  This
++ *    performs initialization that generally doesn't depend on user input.
++ */
++int t4_fw_initialize(struct adapter *adap, unsigned int mbox)
++{
++      struct fw_initialize_cmd c;
++
++      memset(&c, 0, sizeof(c));
++      INIT_CMD(c, INITIALIZE, WRITE);
++      return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
++}
++
++/**
+  *    t4_query_params - query FW or device parameters
+  *    @adap: the adapter
+  *    @mbox: mailbox to use for the FW command
+@@ -2974,10 +3323,6 @@ int __devinit t4_prep_adapter(struct adapter *adapter)
+               return ret;
+       }
+-      ret = get_vpd_params(adapter, &adapter->params.vpd);
+-      if (ret < 0)
+-              return ret;
+-
+       init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
+       /*
+@@ -2985,6 +3330,7 @@ int __devinit t4_prep_adapter(struct adapter *adapter)
+        */
+       adapter->params.nports = 1;
+       adapter->params.portvec = 1;
++      adapter->params.vpd.cclk = 50000;
+       return 0;
+ }
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+index 2767ca6..779b23f 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+@@ -115,6 +115,35 @@
+ #define  GLOBALENABLE           0x00000001U
+ #define SGE_HOST_PAGE_SIZE 0x100c
++
++#define  HOSTPAGESIZEPF7_MASK   0x0000000fU
++#define  HOSTPAGESIZEPF7_SHIFT  28
++#define  HOSTPAGESIZEPF7(x)     ((x) << HOSTPAGESIZEPF7_SHIFT)
++
++#define  HOSTPAGESIZEPF6_MASK   0x0000000fU
++#define  HOSTPAGESIZEPF6_SHIFT  24
++#define  HOSTPAGESIZEPF6(x)     ((x) << HOSTPAGESIZEPF6_SHIFT)
++
++#define  HOSTPAGESIZEPF5_MASK   0x0000000fU
++#define  HOSTPAGESIZEPF5_SHIFT  20
++#define  HOSTPAGESIZEPF5(x)     ((x) << HOSTPAGESIZEPF5_SHIFT)
++
++#define  HOSTPAGESIZEPF4_MASK   0x0000000fU
++#define  HOSTPAGESIZEPF4_SHIFT  16
++#define  HOSTPAGESIZEPF4(x)     ((x) << HOSTPAGESIZEPF4_SHIFT)
++
++#define  HOSTPAGESIZEPF3_MASK   0x0000000fU
++#define  HOSTPAGESIZEPF3_SHIFT  12
++#define  HOSTPAGESIZEPF3(x)     ((x) << HOSTPAGESIZEPF3_SHIFT)
++
++#define  HOSTPAGESIZEPF2_MASK   0x0000000fU
++#define  HOSTPAGESIZEPF2_SHIFT  8
++#define  HOSTPAGESIZEPF2(x)     ((x) << HOSTPAGESIZEPF2_SHIFT)
++
++#define  HOSTPAGESIZEPF1_MASK   0x0000000fU
++#define  HOSTPAGESIZEPF1_SHIFT  4
++#define  HOSTPAGESIZEPF1(x)     ((x) << HOSTPAGESIZEPF1_SHIFT)
++
+ #define  HOSTPAGESIZEPF0_MASK   0x0000000fU
+ #define  HOSTPAGESIZEPF0_SHIFT  0
+ #define  HOSTPAGESIZEPF0(x)     ((x) << HOSTPAGESIZEPF0_SHIFT)
+@@ -162,6 +191,8 @@
+ #define SGE_INT_ENABLE3 0x1040
+ #define SGE_FL_BUFFER_SIZE0 0x1044
+ #define SGE_FL_BUFFER_SIZE1 0x1048
++#define SGE_FL_BUFFER_SIZE2 0x104c
++#define SGE_FL_BUFFER_SIZE3 0x1050
+ #define SGE_INGRESS_RX_THRESHOLD 0x10a0
+ #define  THRESHOLD_0_MASK   0x3f000000U
+ #define  THRESHOLD_0_SHIFT  24
+@@ -367,7 +398,7 @@
+ #define  MEM_WRAP_CLIENT_NUM_MASK   0x0000000fU
+ #define  MEM_WRAP_CLIENT_NUM_SHIFT  0
+ #define  MEM_WRAP_CLIENT_NUM_GET(x) (((x) & MEM_WRAP_CLIENT_NUM_MASK) >> MEM_WRAP_CLIENT_NUM_SHIFT)
+-
++#define MA_PCIE_FW 0x30b8
+ #define MA_PARITY_ERROR_STATUS 0x77f4
+ #define EDC_0_BASE_ADDR 0x7900
+@@ -469,6 +500,10 @@
+ #define  TIMERRESOLUTION_MASK   0x00ff0000U
+ #define  TIMERRESOLUTION_SHIFT  16
+ #define  TIMERRESOLUTION_GET(x) (((x) & TIMERRESOLUTION_MASK) >> TIMERRESOLUTION_SHIFT)
++#define  DELAYEDACKRESOLUTION_MASK 0x000000ffU
++#define  DELAYEDACKRESOLUTION_SHIFT     0
++#define  DELAYEDACKRESOLUTION_GET(x) \
++      (((x) & DELAYEDACKRESOLUTION_MASK) >> DELAYEDACKRESOLUTION_SHIFT)
+ #define TP_SHIFT_CNT 0x7dc0
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+index 94e3484..3f85019 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+@@ -155,6 +155,17 @@ struct fw_eth_tx_pkt_vm_wr {
+ #define FW_CMD_MAX_TIMEOUT 3000
++/*
++ * If a host driver does a HELLO and discovers that there's already a MASTER
++ * selected, we may have to wait for that MASTER to finish issuing RESET,
++ * configuration and INITIALIZE commands.  Also, there's a possibility that
++ * our own HELLO may get lost if it happens right as the MASTER is issuign a
++ * RESET command, so we need to be willing to make a few retries of our HELLO.
++ */
++#define FW_CMD_HELLO_TIMEOUT  (3 * FW_CMD_MAX_TIMEOUT)
++#define FW_CMD_HELLO_RETRIES  3
++
++
+ enum fw_cmd_opcodes {
+       FW_LDST_CMD                    = 0x01,
+       FW_RESET_CMD                   = 0x03,
+@@ -307,6 +318,10 @@ struct fw_reset_cmd {
+       __be32 r3;
+ };
++enum fw_hellow_cmd {
++      fw_hello_cmd_stage_os           = 0x0
++};
++
+ struct fw_hello_cmd {
+       __be32 op_to_write;
+       __be32 retval_len16;
+@@ -315,8 +330,14 @@ struct fw_hello_cmd {
+ #define FW_HELLO_CMD_INIT         (1U << 30)
+ #define FW_HELLO_CMD_MASTERDIS(x)   ((x) << 29)
+ #define FW_HELLO_CMD_MASTERFORCE(x) ((x) << 28)
+-#define FW_HELLO_CMD_MBMASTER(x)    ((x) << 24)
++#define FW_HELLO_CMD_MBMASTER_MASK   0xfU
++#define FW_HELLO_CMD_MBMASTER_SHIFT  24
++#define FW_HELLO_CMD_MBMASTER(x)     ((x) << FW_HELLO_CMD_MBMASTER_SHIFT)
++#define FW_HELLO_CMD_MBMASTER_GET(x) \
++      (((x) >> FW_HELLO_CMD_MBMASTER_SHIFT) & FW_HELLO_CMD_MBMASTER_MASK)
+ #define FW_HELLO_CMD_MBASYNCNOT(x)  ((x) << 20)
++#define FW_HELLO_CMD_STAGE(x)       ((x) << 17)
++#define FW_HELLO_CMD_CLEARINIT      (1U << 16)
+       __be32 fwrev;
+ };
+@@ -1654,18 +1675,4 @@ struct fw_hdr {
+ #define FW_HDR_FW_VER_MICRO_GET(x) (((x) >> 8) & 0xff)
+ #define FW_HDR_FW_VER_BUILD_GET(x) (((x) >> 0) & 0xff)
+-#define S_FW_CMD_OP 24
+-#define V_FW_CMD_OP(x) ((x) << S_FW_CMD_OP)
+-
+-#define S_FW_CMD_REQUEST 23
+-#define V_FW_CMD_REQUEST(x) ((x) << S_FW_CMD_REQUEST)
+-#define F_FW_CMD_REQUEST V_FW_CMD_REQUEST(1U)
+-
+-#define S_FW_CMD_WRITE 21
+-#define V_FW_CMD_WRITE(x) ((x) << S_FW_CMD_WRITE)
+-#define F_FW_CMD_WRITE V_FW_CMD_WRITE(1U)
+-
+-#define S_FW_LDST_CMD_ADDRSPACE 0
+-#define V_FW_LDST_CMD_ADDRSPACE(x) ((x) << S_FW_LDST_CMD_ADDRSPACE)
+-
+ #endif /* _T4FW_INTERFACE_H_ */
+-- 
+1.7.1
+
diff --git a/linux-next-cherry-picks/0006-cxgb4-Add-support-for-T4-hardwired-driver-configurat.patch b/linux-next-cherry-picks/0006-cxgb4-Add-support-for-T4-hardwired-driver-configurat.patch
new file mode 100644 (file)
index 0000000..1f6aee4
--- /dev/null
@@ -0,0 +1,651 @@
+From 13ee15d396da78079918c5be7510ea1847393d4c Mon Sep 17 00:00:00 2001
+From: Vipul Pandya <vipul@chelsio.com>
+Date: Wed, 26 Sep 2012 02:39:40 +0000
+Subject: [PATCH 4/6] cxgb4: Add support for T4 hardwired driver configuration settings
+
+In case if user defined configuration file at /lib/firmware/cxgb4/t4-config.txt
+location and also factory default configuration file written to FLASH are not
+present then driver will use hardwired configuration settings.
+
+Signed-off-by: Jay Hernandez <jay@chelsio.com>
+Signed-off-by: Vipul Pandya <vipul@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h      |    4 +
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c |  390 +++++++++++++++++++++--
+ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c      |   22 ++
+ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h    |   56 ++++
+ drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h   |    2 +
+ 5 files changed, 442 insertions(+), 32 deletions(-)
+
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+index 777cbb4..6827ce3 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -318,6 +318,7 @@ enum {                                 /* adapter flags */
+       USING_MSI          = (1 << 1),
+       USING_MSIX         = (1 << 2),
+       FW_OK              = (1 << 4),
++      RSS_TNLALLLOOKUP   = (1 << 5),
+       USING_SOFT_PARAMS  = (1 << 6),
+       MASTER_PF          = (1 << 7),
+       FW_OFLD_CONN       = (1 << 9),
+@@ -677,6 +678,9 @@ static inline int t4_wr_mbox_ns(struct adapter *adap, int mbox, const void *cmd,
+       return t4_wr_mbox_meat(adap, mbox, cmd, size, rpl, false);
+ }
++void t4_write_indirect(struct adapter *adap, unsigned int addr_reg,
++                     unsigned int data_reg, const u32 *vals,
++                     unsigned int nregs, unsigned int start_idx);
+ void t4_intr_enable(struct adapter *adapter);
+ void t4_intr_disable(struct adapter *adapter);
+ int t4_slow_intr_handler(struct adapter *adapter);
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+index cb3e663..b9cd08d 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -78,28 +78,45 @@
+  */
+ #define MAX_SGE_TIMERVAL 200U
+-#ifdef CONFIG_PCI_IOV
+-/*
+- * Virtual Function provisioning constants.  We need two extra Ingress Queues
+- * with Interrupt capability to serve as the VF's Firmware Event Queue and
+- * Forwarded Interrupt Queue (when using MSI mode) -- neither will have Free
+- * Lists associated with them).  For each Ethernet/Control Egress Queue and
+- * for each Free List, we need an Egress Context.
+- */
+ enum {
++      /*
++       * Physical Function provisioning constants.
++       */
++      PFRES_NVI = 4,                  /* # of Virtual Interfaces */
++      PFRES_NETHCTRL = 128,           /* # of EQs used for ETH or CTRL Qs */
++      PFRES_NIQFLINT = 128,           /* # of ingress Qs/w Free List(s)/intr
++                                       */
++      PFRES_NEQ = 256,                /* # of egress queues */
++      PFRES_NIQ = 0,                  /* # of ingress queues */
++      PFRES_TC = 0,                   /* PCI-E traffic class */
++      PFRES_NEXACTF = 128,            /* # of exact MPS filters */
++
++      PFRES_R_CAPS = FW_CMD_CAP_PF,
++      PFRES_WX_CAPS = FW_CMD_CAP_PF,
++
++#ifdef CONFIG_PCI_IOV
++      /*
++       * Virtual Function provisioning constants.  We need two extra Ingress
++       * Queues with Interrupt capability to serve as the VF's Firmware
++       * Event Queue and Forwarded Interrupt Queue (when using MSI mode) --
++       * neither will have Free Lists associated with them).  For each
++       * Ethernet/Control Egress Queue and for each Free List, we need an
++       * Egress Context.
++       */
+       VFRES_NPORTS = 1,               /* # of "ports" per VF */
+       VFRES_NQSETS = 2,               /* # of "Queue Sets" per VF */
+       VFRES_NVI = VFRES_NPORTS,       /* # of Virtual Interfaces */
+       VFRES_NETHCTRL = VFRES_NQSETS,  /* # of EQs used for ETH or CTRL Qs */
+       VFRES_NIQFLINT = VFRES_NQSETS+2,/* # of ingress Qs/w Free List(s)/intr */
+-      VFRES_NIQ = 0,                  /* # of non-fl/int ingress queues */
+       VFRES_NEQ = VFRES_NQSETS*2,     /* # of egress queues */
++      VFRES_NIQ = 0,                  /* # of non-fl/int ingress queues */
+       VFRES_TC = 0,                   /* PCI-E traffic class */
+       VFRES_NEXACTF = 16,             /* # of exact MPS filters */
+       VFRES_R_CAPS = FW_CMD_CAP_DMAQ|FW_CMD_CAP_VF|FW_CMD_CAP_PORT,
+       VFRES_WX_CAPS = FW_CMD_CAP_DMAQ|FW_CMD_CAP_VF,
++#endif
+ };
+ /*
+@@ -146,7 +163,6 @@ static unsigned int pfvfres_pmask(struct adapter *adapter,
+       }
+       /*NOTREACHED*/
+ }
+-#endif
+ enum {
+       MAX_TXQ_ENTRIES      = 16384,
+@@ -213,6 +229,17 @@ static uint force_init;
+ module_param(force_init, uint, 0644);
+ MODULE_PARM_DESC(force_init, "Forcibly become Master PF and initialize adapter");
++/*
++ * Normally if the firmware we connect to has Configuration File support, we
++ * use that and only fall back to the old Driver-based initialization if the
++ * Configuration File fails for some reason.  If force_old_init is set, then
++ * we'll always use the old Driver-based initialization sequence.
++ */
++static uint force_old_init;
++
++module_param(force_old_init, uint, 0644);
++MODULE_PARM_DESC(force_old_init, "Force old initialization sequence");
++
+ static int dflt_msg_enable = DFLT_MSG_ENABLE;
+ module_param(dflt_msg_enable, int, 0644);
+@@ -274,6 +301,30 @@ module_param_array(num_vf, uint, NULL, 0644);
+ MODULE_PARM_DESC(num_vf, "number of VFs for each of PFs 0-3");
+ #endif
++/*
++ * The filter TCAM has a fixed portion and a variable portion.  The fixed
++ * portion can match on source/destination IP IPv4/IPv6 addresses and TCP/UDP
++ * ports.  The variable portion is 36 bits which can include things like Exact
++ * Match MAC Index (9 bits), Ether Type (16 bits), IP Protocol (8 bits),
++ * [Inner] VLAN Tag (17 bits), etc. which, if all were somehow selected, would
++ * far exceed the 36-bit budget for this "compressed" header portion of the
++ * filter.  Thus, we have a scarce resource which must be carefully managed.
++ *
++ * By default we set this up to mostly match the set of filter matching
++ * capabilities of T3 but with accommodations for some of T4's more
++ * interesting features:
++ *
++ *   { IP Fragment (1), MPS Match Type (3), IP Protocol (8),
++ *     [Inner] VLAN (17), Port (3), FCoE (1) }
++ */
++enum {
++      TP_VLAN_PRI_MAP_DEFAULT = HW_TPL_FR_MT_PR_IV_P_FC,
++      TP_VLAN_PRI_MAP_FIRST = FCOE_SHIFT,
++      TP_VLAN_PRI_MAP_LAST = FRAGMENTATION_SHIFT,
++};
++
++static unsigned int tp_vlan_pri_map = TP_VLAN_PRI_MAP_DEFAULT;
++
+ static struct dentry *cxgb4_debugfs_root;
+ static LIST_HEAD(adapter_list);
+@@ -3410,6 +3461,262 @@ bye:
+ }
+ /*
++ * Attempt to initialize the adapter via hard-coded, driver supplied
++ * parameters ...
++ */
++static int adap_init0_no_config(struct adapter *adapter, int reset)
++{
++      struct sge *s = &adapter->sge;
++      struct fw_caps_config_cmd caps_cmd;
++      u32 v;
++      int i, ret;
++
++      /*
++       * Reset device if necessary
++       */
++      if (reset) {
++              ret = t4_fw_reset(adapter, adapter->mbox,
++                                PIORSTMODE | PIORST);
++              if (ret < 0)
++                      goto bye;
++      }
++
++      /*
++       * Get device capabilities and select which we'll be using.
++       */
++      memset(&caps_cmd, 0, sizeof(caps_cmd));
++      caps_cmd.op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
++                                   FW_CMD_REQUEST | FW_CMD_READ);
++      caps_cmd.retval_len16 = htonl(FW_LEN16(caps_cmd));
++      ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
++                       &caps_cmd);
++      if (ret < 0)
++              goto bye;
++
++#ifndef CONFIG_CHELSIO_T4_OFFLOAD
++      /*
++       * If we're a pure NIC driver then disable all offloading facilities.
++       * This will allow the firmware to optimize aspects of the hardware
++       * configuration which will result in improved performance.
++       */
++      caps_cmd.ofldcaps = 0;
++      caps_cmd.iscsicaps = 0;
++      caps_cmd.rdmacaps = 0;
++      caps_cmd.fcoecaps = 0;
++#endif
++
++      if (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_VM)) {
++              if (!vf_acls)
++                      caps_cmd.niccaps ^= htons(FW_CAPS_CONFIG_NIC_VM);
++              else
++                      caps_cmd.niccaps = htons(FW_CAPS_CONFIG_NIC_VM);
++      } else if (vf_acls) {
++              dev_err(adapter->pdev_dev, "virtualization ACLs not supported");
++              goto bye;
++      }
++      caps_cmd.op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
++                            FW_CMD_REQUEST | FW_CMD_WRITE);
++      ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
++                       NULL);
++      if (ret < 0)
++              goto bye;
++
++      /*
++       * Tweak configuration based on system architecture, module
++       * parameters, etc.
++       */
++      ret = adap_init0_tweaks(adapter);
++      if (ret < 0)
++              goto bye;
++
++      /*
++       * Select RSS Global Mode we want to use.  We use "Basic Virtual"
++       * mode which maps each Virtual Interface to its own section of
++       * the RSS Table and we turn on all map and hash enables ...
++       */
++      adapter->flags |= RSS_TNLALLLOOKUP;
++      ret = t4_config_glbl_rss(adapter, adapter->mbox,
++                               FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL,
++                               FW_RSS_GLB_CONFIG_CMD_TNLMAPEN |
++                               FW_RSS_GLB_CONFIG_CMD_HASHTOEPLITZ |
++                               ((adapter->flags & RSS_TNLALLLOOKUP) ?
++                                      FW_RSS_GLB_CONFIG_CMD_TNLALLLKP : 0));
++      if (ret < 0)
++              goto bye;
++
++      /*
++       * Set up our own fundamental resource provisioning ...
++       */
++      ret = t4_cfg_pfvf(adapter, adapter->mbox, adapter->fn, 0,
++                        PFRES_NEQ, PFRES_NETHCTRL,
++                        PFRES_NIQFLINT, PFRES_NIQ,
++                        PFRES_TC, PFRES_NVI,
++                        FW_PFVF_CMD_CMASK_MASK,
++                        pfvfres_pmask(adapter, adapter->fn, 0),
++                        PFRES_NEXACTF,
++                        PFRES_R_CAPS, PFRES_WX_CAPS);
++      if (ret < 0)
++              goto bye;
++
++      /*
++       * Perform low level SGE initialization.  We need to do this before we
++       * send the firmware the INITIALIZE command because that will cause
++       * any other PF Drivers which are waiting for the Master
++       * Initialization to proceed forward.
++       */
++      for (i = 0; i < SGE_NTIMERS - 1; i++)
++              s->timer_val[i] = min(intr_holdoff[i], MAX_SGE_TIMERVAL);
++      s->timer_val[SGE_NTIMERS - 1] = MAX_SGE_TIMERVAL;
++      s->counter_val[0] = 1;
++      for (i = 1; i < SGE_NCOUNTERS; i++)
++              s->counter_val[i] = min(intr_cnt[i - 1],
++                                      THRESHOLD_0_GET(THRESHOLD_0_MASK));
++      t4_sge_init(adapter);
++
++#ifdef CONFIG_PCI_IOV
++      /*
++       * Provision resource limits for Virtual Functions.  We currently
++       * grant them all the same static resource limits except for the Port
++       * Access Rights Mask which we're assigning based on the PF.  All of
++       * the static provisioning stuff for both the PF and VF really needs
++       * to be managed in a persistent manner for each device which the
++       * firmware controls.
++       */
++      {
++              int pf, vf;
++
++              for (pf = 0; pf < ARRAY_SIZE(num_vf); pf++) {
++                      if (num_vf[pf] <= 0)
++                              continue;
++
++                      /* VF numbering starts at 1! */
++                      for (vf = 1; vf <= num_vf[pf]; vf++) {
++                              ret = t4_cfg_pfvf(adapter, adapter->mbox,
++                                                pf, vf,
++                                                VFRES_NEQ, VFRES_NETHCTRL,
++                                                VFRES_NIQFLINT, VFRES_NIQ,
++                                                VFRES_TC, VFRES_NVI,
++                                                FW_PFVF_CMD_CMASK_GET(
++                                                FW_PFVF_CMD_CMASK_MASK),
++                                                pfvfres_pmask(
++                                                adapter, pf, vf),
++                                                VFRES_NEXACTF,
++                                                VFRES_R_CAPS, VFRES_WX_CAPS);
++                              if (ret < 0)
++                                      dev_warn(adapter->pdev_dev,
++                                               "failed to "\
++                                               "provision pf/vf=%d/%d; "
++                                               "err=%d\n", pf, vf, ret);
++                      }
++              }
++      }
++#endif
++
++      /*
++       * Set up the default filter mode.  Later we'll want to implement this
++       * via a firmware command, etc. ...  This needs to be done before the
++       * firmare initialization command ...  If the selected set of fields
++       * isn't equal to the default value, we'll need to make sure that the
++       * field selections will fit in the 36-bit budget.
++       */
++      if (tp_vlan_pri_map != TP_VLAN_PRI_MAP_DEFAULT) {
++              int i, bits = 0;
++
++              for (i = TP_VLAN_PRI_MAP_FIRST; i <= TP_VLAN_PRI_MAP_LAST; i++)
++                      switch (tp_vlan_pri_map & (1 << i)) {
++                      case 0:
++                              /* compressed filter field not enabled */
++                              break;
++                      case FCOE_MASK:
++                              bits +=  1;
++                              break;
++                      case PORT_MASK:
++                              bits +=  3;
++                              break;
++                      case VNIC_ID_MASK:
++                              bits += 17;
++                              break;
++                      case VLAN_MASK:
++                              bits += 17;
++                              break;
++                      case TOS_MASK:
++                              bits +=  8;
++                              break;
++                      case PROTOCOL_MASK:
++                              bits +=  8;
++                              break;
++                      case ETHERTYPE_MASK:
++                              bits += 16;
++                              break;
++                      case MACMATCH_MASK:
++                              bits +=  9;
++                              break;
++                      case MPSHITTYPE_MASK:
++                              bits +=  3;
++                              break;
++                      case FRAGMENTATION_MASK:
++                              bits +=  1;
++                              break;
++                      }
++
++              if (bits > 36) {
++                      dev_err(adapter->pdev_dev,
++                              "tp_vlan_pri_map=%#x needs %d bits > 36;"\
++                              " using %#x\n", tp_vlan_pri_map, bits,
++                              TP_VLAN_PRI_MAP_DEFAULT);
++                      tp_vlan_pri_map = TP_VLAN_PRI_MAP_DEFAULT;
++              }
++      }
++      v = tp_vlan_pri_map;
++      t4_write_indirect(adapter, TP_PIO_ADDR, TP_PIO_DATA,
++                        &v, 1, TP_VLAN_PRI_MAP);
++
++      /*
++       * We need Five Tuple Lookup mode to be set in TP_GLOBAL_CONFIG order
++       * to support any of the compressed filter fields above.  Newer
++       * versions of the firmware do this automatically but it doesn't hurt
++       * to set it here.  Meanwhile, we do _not_ need to set Lookup Every
++       * Packet in TP_INGRESS_CONFIG to support matching non-TCP packets
++       * since the firmware automatically turns this on and off when we have
++       * a non-zero number of filters active (since it does have a
++       * performance impact).
++       */
++      if (tp_vlan_pri_map)
++              t4_set_reg_field(adapter, TP_GLOBAL_CONFIG,
++                               FIVETUPLELOOKUP_MASK,
++                               FIVETUPLELOOKUP_MASK);
++
++      /*
++       * Tweak some settings.
++       */
++      t4_write_reg(adapter, TP_SHIFT_CNT, SYNSHIFTMAX(6) |
++                   RXTSHIFTMAXR1(4) | RXTSHIFTMAXR2(15) |
++                   PERSHIFTBACKOFFMAX(8) | PERSHIFTMAX(8) |
++                   KEEPALIVEMAXR1(4) | KEEPALIVEMAXR2(9));
++
++      /*
++       * Get basic stuff going by issuing the Firmware Initialize command.
++       * Note that this _must_ be after all PFVF commands ...
++       */
++      ret = t4_fw_initialize(adapter, adapter->mbox);
++      if (ret < 0)
++              goto bye;
++
++      /*
++       * Return successfully!
++       */
++      dev_info(adapter->pdev_dev, "Successfully configured using built-in "\
++               "driver parameters\n");
++      return 0;
++
++      /*
++       * Something bad happened.  Return the error ...
++       */
++bye:
++      return ret;
++}
++
++/*
+  * Phase 0 of initialization: contact FW, obtain config, perform basic init.
+  */
+ static int adap_init0(struct adapter *adap)
+@@ -3474,7 +3781,9 @@ static int adap_init0(struct adapter *adap)
+               goto bye;
+       /*
+-       * Find out what ports are available to us.
++       * Find out what ports are available to us.  Note that we need to do
++       * this before calling adap_init0_no_config() since it needs nports
++       * and portvec ...
+        */
+       v =
+           FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
+@@ -3500,35 +3809,52 @@ static int adap_init0(struct adapter *adap)
+       } else {
+               dev_info(adap->pdev_dev, "Coming up as MASTER: "\
+                        "Initializing adapter\n");
+-              /*
+-               * Find out whether we're dealing with a version of
+-               * the firmware which has configuration file support.
+-               */
+-              params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
+-                           FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_CF));
+-              ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 1,
+-                                    params, val);
+               /*
+                * If the firmware doesn't support Configuration
+                * Files warn user and exit,
+                */
+               if (ret < 0)
+-                      dev_warn(adap->pdev_dev, "Firmware doesn't support "\
++                      dev_warn(adap->pdev_dev, "Firmware doesn't support "
+                                "configuration file.\n");
++              if (force_old_init)
++                      ret = adap_init0_no_config(adap, reset);
+               else {
+                       /*
+-                       * The firmware provides us with a memory
+-                       * buffer where we can load a Configuration
+-                       * File from the host if we want to override
+-                       * the Configuration File in flash.
++                       * Find out whether we're dealing with a version of
++                       * the firmware which has configuration file support.
+                        */
++                      params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
++                                   FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_CF));
++                      ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 1,
++                                            params, val);
+-                      ret = adap_init0_config(adap, reset);
+-                      if (ret == -ENOENT) {
+-                              dev_info(adap->pdev_dev,
+-                                  "No Configuration File present "
+-                                  "on adapter.\n");
++                      /*
++                       * If the firmware doesn't support Configuration
++                       * Files, use the old Driver-based, hard-wired
++                       * initialization.  Otherwise, try using the
++                       * Configuration File support and fall back to the
++                       * Driver-based initialization if there's no
++                       * Configuration File found.
++                       */
++                      if (ret < 0)
++                              ret = adap_init0_no_config(adap, reset);
++                      else {
++                              /*
++                               * The firmware provides us with a memory
++                               * buffer where we can load a Configuration
++                               * File from the host if we want to override
++                               * the Configuration File in flash.
++                               */
++
++                              ret = adap_init0_config(adap, reset);
++                              if (ret == -ENOENT) {
++                                      dev_info(adap->pdev_dev,
++                                          "No Configuration File present "
++                                          "on adapter.  Using hard-wired "
++                                          "configuration parameters.\n");
++                                      ret = adap_init0_no_config(adap, reset);
++                              }
+                       }
+               }
+               if (ret < 0) {
+@@ -3601,14 +3927,14 @@ static int adap_init0(struct adapter *adap)
+        */
+       memset(&caps_cmd, 0, sizeof(caps_cmd));
+       caps_cmd.op_to_write = htonl(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
+-                                   F_FW_CMD_REQUEST | F_FW_CMD_READ);
+-      caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
++                                   FW_CMD_REQUEST | FW_CMD_READ);
++      caps_cmd.retval_len16 = htonl(FW_LEN16(caps_cmd));
+       ret = t4_wr_mbox(adap, adap->mbox, &caps_cmd, sizeof(caps_cmd),
+                        &caps_cmd);
+       if (ret < 0)
+               goto bye;
+-      if (caps_cmd.toecaps) {
++      if (caps_cmd.ofldcaps) {
+               /* query offload-related parameters */
+               params[0] = FW_PARAM_DEV(NTID);
+               params[1] = FW_PARAM_PFVF(SERVER_START);
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+index 419432d..61f002d 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+@@ -120,6 +120,28 @@ static void t4_read_indirect(struct adapter *adap, unsigned int addr_reg,
+       }
+ }
++/**
++ *    t4_write_indirect - write indirectly addressed registers
++ *    @adap: the adapter
++ *    @addr_reg: register holding the indirect addresses
++ *    @data_reg: register holding the value for the indirect registers
++ *    @vals: values to write
++ *    @nregs: how many indirect registers to write
++ *    @start_idx: address of first indirect register to write
++ *
++ *    Writes a sequential block of registers that are accessed indirectly
++ *    through an address/data register pair.
++ */
++void t4_write_indirect(struct adapter *adap, unsigned int addr_reg,
++                     unsigned int data_reg, const u32 *vals,
++                     unsigned int nregs, unsigned int start_idx)
++{
++      while (nregs--) {
++              t4_write_reg(adap, addr_reg, start_idx++);
++              t4_write_reg(adap, data_reg, *vals++);
++      }
++}
++
+ /*
+  * Get the reply to a mailbox command and store it in @rpl in big-endian order.
+  */
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+index 779b23f..732c6da 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+@@ -491,6 +491,13 @@
+ #define  VLANEXTENABLE_MASK  0x0000f000U
+ #define  VLANEXTENABLE_SHIFT 12
++#define TP_GLOBAL_CONFIG 0x7d08
++#define  FIVETUPLELOOKUP_SHIFT  17
++#define  FIVETUPLELOOKUP_MASK   0x00060000U
++#define  FIVETUPLELOOKUP(x)     ((x) << FIVETUPLELOOKUP_SHIFT)
++#define  FIVETUPLELOOKUP_GET(x) (((x) & FIVETUPLELOOKUP_MASK) >> \
++                              FIVETUPLELOOKUP_SHIFT)
++
+ #define TP_PARA_REG2 0x7d68
+ #define  MAXRXDATA_MASK    0xffff0000U
+ #define  MAXRXDATA_SHIFT   16
+@@ -506,6 +513,41 @@
+       (((x) & DELAYEDACKRESOLUTION_MASK) >> DELAYEDACKRESOLUTION_SHIFT)
+ #define TP_SHIFT_CNT 0x7dc0
++#define  SYNSHIFTMAX_SHIFT         24
++#define  SYNSHIFTMAX_MASK          0xff000000U
++#define  SYNSHIFTMAX(x)            ((x) << SYNSHIFTMAX_SHIFT)
++#define  SYNSHIFTMAX_GET(x)        (((x) & SYNSHIFTMAX_MASK) >> \
++                                 SYNSHIFTMAX_SHIFT)
++#define  RXTSHIFTMAXR1_SHIFT       20
++#define  RXTSHIFTMAXR1_MASK        0x00f00000U
++#define  RXTSHIFTMAXR1(x)          ((x) << RXTSHIFTMAXR1_SHIFT)
++#define  RXTSHIFTMAXR1_GET(x)      (((x) & RXTSHIFTMAXR1_MASK) >> \
++                                 RXTSHIFTMAXR1_SHIFT)
++#define  RXTSHIFTMAXR2_SHIFT       16
++#define  RXTSHIFTMAXR2_MASK        0x000f0000U
++#define  RXTSHIFTMAXR2(x)          ((x) << RXTSHIFTMAXR2_SHIFT)
++#define  RXTSHIFTMAXR2_GET(x)      (((x) & RXTSHIFTMAXR2_MASK) >> \
++                                 RXTSHIFTMAXR2_SHIFT)
++#define  PERSHIFTBACKOFFMAX_SHIFT  12
++#define  PERSHIFTBACKOFFMAX_MASK   0x0000f000U
++#define  PERSHIFTBACKOFFMAX(x)     ((x) << PERSHIFTBACKOFFMAX_SHIFT)
++#define  PERSHIFTBACKOFFMAX_GET(x) (((x) & PERSHIFTBACKOFFMAX_MASK) >> \
++                                 PERSHIFTBACKOFFMAX_SHIFT)
++#define  PERSHIFTMAX_SHIFT         8
++#define  PERSHIFTMAX_MASK          0x00000f00U
++#define  PERSHIFTMAX(x)            ((x) << PERSHIFTMAX_SHIFT)
++#define  PERSHIFTMAX_GET(x)        (((x) & PERSHIFTMAX_MASK) >> \
++                                 PERSHIFTMAX_SHIFT)
++#define  KEEPALIVEMAXR1_SHIFT      4
++#define  KEEPALIVEMAXR1_MASK       0x000000f0U
++#define  KEEPALIVEMAXR1(x)         ((x) << KEEPALIVEMAXR1_SHIFT)
++#define  KEEPALIVEMAXR1_GET(x)     (((x) & KEEPALIVEMAXR1_MASK) >> \
++                                 KEEPALIVEMAXR1_SHIFT)
++#define KEEPALIVEMAXR2_SHIFT       0
++#define KEEPALIVEMAXR2_MASK        0x0000000fU
++#define KEEPALIVEMAXR2(x)          ((x) << KEEPALIVEMAXR2_SHIFT)
++#define KEEPALIVEMAXR2_GET(x)      (((x) & KEEPALIVEMAXR2_MASK) >> \
++                                 KEEPALIVEMAXR2_SHIFT)
+ #define TP_CCTRL_TABLE 0x7ddc
+ #define TP_MTU_TABLE 0x7de4
+@@ -539,6 +581,20 @@
+ #define TP_INT_CAUSE 0x7e74
+ #define  FLMTXFLSTEMPTY 0x40000000U
++#define TP_VLAN_PRI_MAP 0x140
++#define  FRAGMENTATION_SHIFT 9
++#define  FRAGMENTATION_MASK  0x00000200U
++#define  MPSHITTYPE_MASK     0x00000100U
++#define  MACMATCH_MASK       0x00000080U
++#define  ETHERTYPE_MASK      0x00000040U
++#define  PROTOCOL_MASK       0x00000020U
++#define  TOS_MASK            0x00000010U
++#define  VLAN_MASK           0x00000008U
++#define  VNIC_ID_MASK        0x00000004U
++#define  PORT_MASK           0x00000002U
++#define  FCOE_SHIFT          0
++#define  FCOE_MASK           0x00000001U
++
+ #define TP_INGRESS_CONFIG 0x141
+ #define  VNIC                0x00000800U
+ #define  CSUM_HAS_PSEUDO_HDR 0x00000400U
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+index 3f85019..b1d5561 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+@@ -79,6 +79,8 @@ struct fw_wr_hdr {
+ #define FW_WR_FLOWID(x)       ((x) << 8)
+ #define FW_WR_LEN16(x)        ((x) << 0)
++#define HW_TPL_FR_MT_PR_IV_P_FC         0X32B
++
+ struct fw_ulptx_wr {
+       __be32 op_to_compl;
+       __be32 flowid_len16;
+-- 
+1.7.1
+
diff --git a/linux-next-cherry-picks/0007-cxgb4-Inform-caller-if-driver-didn-t-upgrade-firmwar.patch b/linux-next-cherry-picks/0007-cxgb4-Inform-caller-if-driver-didn-t-upgrade-firmwar.patch
new file mode 100644 (file)
index 0000000..1c6ba3c
--- /dev/null
@@ -0,0 +1,39 @@
+From 1648a22b16ab05bd99dd8e2f33ca80bbcea60031 Mon Sep 17 00:00:00 2001
+From: Vipul Pandya <vipul@chelsio.com>
+Date: Wed, 26 Sep 2012 02:39:41 +0000
+Subject: [PATCH 5/6] cxgb4: Inform caller if driver didn't upgrade firmware
+
+If a card had already been initialized, on reloading cxgb4 driver firmware
+required an upgrade but the upgrade did not happen. In that case a mailbox
+timeout would occur during T4 configuration file stuff. The fix is to let the
+caller know the firmware was not upgraded so a reset would be issued before
+starting the T4 config stuff.
+
+Signed-off-by: Jay Hernandez <jay@chelsio.com>
+Signed-off-by: Vipul Pandya <vipul@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c |    6 ++++++
+ 1 files changed, 6 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+index b9cd08d..a3f866d 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -933,7 +933,13 @@ static int upgrade_fw(struct adapter *adap)
+               if (!ret)
+                       dev_info(dev, "firmware upgraded to version %pI4 from "
+                                FW_FNAME "\n", &hdr->fw_ver);
++      } else {
++              /*
++               * Tell our caller that we didn't upgrade the firmware.
++               */
++              ret = -EINVAL;
+       }
++
+ out:  release_firmware(fw);
+       return ret;
+ }
+-- 
+1.7.1
+
diff --git a/linux-next-cherry-picks/0008-cxgb4-Don-t-attempt-to-upgrade-T4-firmware-when-cxgb.patch b/linux-next-cherry-picks/0008-cxgb4-Don-t-attempt-to-upgrade-T4-firmware-when-cxgb.patch
new file mode 100644 (file)
index 0000000..8f5803a
--- /dev/null
@@ -0,0 +1,323 @@
+From 26f7cbc0a5a42d8cc0c7725d10317089a8215f97 Mon Sep 17 00:00:00 2001
+From: Vipul Pandya <vipul@chelsio.com>
+Date: Wed, 26 Sep 2012 02:39:42 +0000
+Subject: [PATCH 6/6] cxgb4: Don't attempt to upgrade T4 firmware when cxgb4 will end up as a slave
+
+This patch adds a new common code routine to upgrade an adapter's
+firmware.  This routine handles all of the complexities of working with the
+the existing adapter firmware in order to quiesce the adapter and uP, etc.
+For an automatic upgrade it will send a HELLO command to check if cxgb4
+want/can upgrade firmware, i.e. if cxgb4 is MASTER and has newer firmware
+that it wants to load and call the new common code routine t4_fw_upgrade.
+Note that it should not issue a RESET command after a successful firmware
+upgrade.
+
+Signed-off-by: Jay Hernandez <jay@chelsio.com>
+Signed-off-by: Vipul Pandya <vipul@chelsio.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h      |    4 +
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c |   14 ++-
+ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c      |  171 +++++++++++++++++++++++
+ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h    |    3 +
+ drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h   |   19 +++-
+ 5 files changed, 206 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+index 6827ce3..745a1f5 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -726,6 +726,10 @@ int t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox,
+ int t4_fw_bye(struct adapter *adap, unsigned int mbox);
+ int t4_early_init(struct adapter *adap, unsigned int mbox);
+ int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset);
++int t4_fw_halt(struct adapter *adap, unsigned int mbox, int force);
++int t4_fw_restart(struct adapter *adap, unsigned int mbox, int reset);
++int t4_fw_upgrade(struct adapter *adap, unsigned int mbox,
++                const u8 *fw_data, unsigned int size, int force);
+ int t4_fw_config_file(struct adapter *adap, unsigned int mbox,
+                     unsigned int mtype, unsigned int maddr,
+                     u32 *finiver, u32 *finicsum, u32 *cfcsum);
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+index a3f866d..94b7846 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -929,10 +929,18 @@ static int upgrade_fw(struct adapter *adap)
+        */
+       if (FW_HDR_FW_VER_MAJOR_GET(adap->params.fw_vers) != FW_VERSION_MAJOR ||
+           vers > adap->params.fw_vers) {
+-              ret = -t4_load_fw(adap, fw->data, fw->size);
++              dev_info(dev, "upgrading firmware ...\n");
++              ret = t4_fw_upgrade(adap, adap->mbox, fw->data, fw->size,
++                                  /*force=*/false);
+               if (!ret)
+-                      dev_info(dev, "firmware upgraded to version %pI4 from "
+-                               FW_FNAME "\n", &hdr->fw_ver);
++                      dev_info(dev, "firmware successfully upgraded to "
++                               FW_FNAME " (%d.%d.%d.%d)\n",
++                               FW_HDR_FW_VER_MAJOR_GET(vers),
++                               FW_HDR_FW_VER_MINOR_GET(vers),
++                               FW_HDR_FW_VER_MICRO_GET(vers),
++                               FW_HDR_FW_VER_BUILD_GET(vers));
++              else
++                      dev_err(dev, "firmware upgrade failed! err=%d\n", -ret);
+       } else {
+               /*
+                * Tell our caller that we didn't upgrade the firmware.
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+index 61f002d..ab732b3 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+@@ -2537,6 +2537,177 @@ int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset)
+ }
+ /**
++ *    t4_fw_halt - issue a reset/halt to FW and put uP into RESET
++ *    @adap: the adapter
++ *    @mbox: mailbox to use for the FW RESET command (if desired)
++ *    @force: force uP into RESET even if FW RESET command fails
++ *
++ *    Issues a RESET command to firmware (if desired) with a HALT indication
++ *    and then puts the microprocessor into RESET state.  The RESET command
++ *    will only be issued if a legitimate mailbox is provided (mbox <=
++ *    FW_PCIE_FW_MASTER_MASK).
++ *
++ *    This is generally used in order for the host to safely manipulate the
++ *    adapter without fear of conflicting with whatever the firmware might
++ *    be doing.  The only way out of this state is to RESTART the firmware
++ *    ...
++ */
++int t4_fw_halt(struct adapter *adap, unsigned int mbox, int force)
++{
++      int ret = 0;
++
++      /*
++       * If a legitimate mailbox is provided, issue a RESET command
++       * with a HALT indication.
++       */
++      if (mbox <= FW_PCIE_FW_MASTER_MASK) {
++              struct fw_reset_cmd c;
++
++              memset(&c, 0, sizeof(c));
++              INIT_CMD(c, RESET, WRITE);
++              c.val = htonl(PIORST | PIORSTMODE);
++              c.halt_pkd = htonl(FW_RESET_CMD_HALT(1U));
++              ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
++      }
++
++      /*
++       * Normally we won't complete the operation if the firmware RESET
++       * command fails but if our caller insists we'll go ahead and put the
++       * uP into RESET.  This can be useful if the firmware is hung or even
++       * missing ...  We'll have to take the risk of putting the uP into
++       * RESET without the cooperation of firmware in that case.
++       *
++       * We also force the firmware's HALT flag to be on in case we bypassed
++       * the firmware RESET command above or we're dealing with old firmware
++       * which doesn't have the HALT capability.  This will serve as a flag
++       * for the incoming firmware to know that it's coming out of a HALT
++       * rather than a RESET ... if it's new enough to understand that ...
++       */
++      if (ret == 0 || force) {
++              t4_set_reg_field(adap, CIM_BOOT_CFG, UPCRST, UPCRST);
++              t4_set_reg_field(adap, PCIE_FW, FW_PCIE_FW_HALT,
++                               FW_PCIE_FW_HALT);
++      }
++
++      /*
++       * And we always return the result of the firmware RESET command
++       * even when we force the uP into RESET ...
++       */
++      return ret;
++}
++
++/**
++ *    t4_fw_restart - restart the firmware by taking the uP out of RESET
++ *    @adap: the adapter
++ *    @reset: if we want to do a RESET to restart things
++ *
++ *    Restart firmware previously halted by t4_fw_halt().  On successful
++ *    return the previous PF Master remains as the new PF Master and there
++ *    is no need to issue a new HELLO command, etc.
++ *
++ *    We do this in two ways:
++ *
++ *     1. If we're dealing with newer firmware we'll simply want to take
++ *        the chip's microprocessor out of RESET.  This will cause the
++ *        firmware to start up from its start vector.  And then we'll loop
++ *        until the firmware indicates it's started again (PCIE_FW.HALT
++ *        reset to 0) or we timeout.
++ *
++ *     2. If we're dealing with older firmware then we'll need to RESET
++ *        the chip since older firmware won't recognize the PCIE_FW.HALT
++ *        flag and automatically RESET itself on startup.
++ */
++int t4_fw_restart(struct adapter *adap, unsigned int mbox, int reset)
++{
++      if (reset) {
++              /*
++               * Since we're directing the RESET instead of the firmware
++               * doing it automatically, we need to clear the PCIE_FW.HALT
++               * bit.
++               */
++              t4_set_reg_field(adap, PCIE_FW, FW_PCIE_FW_HALT, 0);
++
++              /*
++               * If we've been given a valid mailbox, first try to get the
++               * firmware to do the RESET.  If that works, great and we can
++               * return success.  Otherwise, if we haven't been given a
++               * valid mailbox or the RESET command failed, fall back to
++               * hitting the chip with a hammer.
++               */
++              if (mbox <= FW_PCIE_FW_MASTER_MASK) {
++                      t4_set_reg_field(adap, CIM_BOOT_CFG, UPCRST, 0);
++                      msleep(100);
++                      if (t4_fw_reset(adap, mbox,
++                                      PIORST | PIORSTMODE) == 0)
++                              return 0;
++              }
++
++              t4_write_reg(adap, PL_RST, PIORST | PIORSTMODE);
++              msleep(2000);
++      } else {
++              int ms;
++
++              t4_set_reg_field(adap, CIM_BOOT_CFG, UPCRST, 0);
++              for (ms = 0; ms < FW_CMD_MAX_TIMEOUT; ) {
++                      if (!(t4_read_reg(adap, PCIE_FW) & FW_PCIE_FW_HALT))
++                              return 0;
++                      msleep(100);
++                      ms += 100;
++              }
++              return -ETIMEDOUT;
++      }
++      return 0;
++}
++
++/**
++ *    t4_fw_upgrade - perform all of the steps necessary to upgrade FW
++ *    @adap: the adapter
++ *    @mbox: mailbox to use for the FW RESET command (if desired)
++ *    @fw_data: the firmware image to write
++ *    @size: image size
++ *    @force: force upgrade even if firmware doesn't cooperate
++ *
++ *    Perform all of the steps necessary for upgrading an adapter's
++ *    firmware image.  Normally this requires the cooperation of the
++ *    existing firmware in order to halt all existing activities
++ *    but if an invalid mailbox token is passed in we skip that step
++ *    (though we'll still put the adapter microprocessor into RESET in
++ *    that case).
++ *
++ *    On successful return the new firmware will have been loaded and
++ *    the adapter will have been fully RESET losing all previous setup
++ *    state.  On unsuccessful return the adapter may be completely hosed ...
++ *    positive errno indicates that the adapter is ~probably~ intact, a
++ *    negative errno indicates that things are looking bad ...
++ */
++int t4_fw_upgrade(struct adapter *adap, unsigned int mbox,
++                const u8 *fw_data, unsigned int size, int force)
++{
++      const struct fw_hdr *fw_hdr = (const struct fw_hdr *)fw_data;
++      int reset, ret;
++
++      ret = t4_fw_halt(adap, mbox, force);
++      if (ret < 0 && !force)
++              return ret;
++
++      ret = t4_load_fw(adap, fw_data, size);
++      if (ret < 0)
++              return ret;
++
++      /*
++       * Older versions of the firmware don't understand the new
++       * PCIE_FW.HALT flag and so won't know to perform a RESET when they
++       * restart.  So for newly loaded older firmware we'll have to do the
++       * RESET for it so it starts up on a clean slate.  We can tell if
++       * the newly loaded firmware will handle this right by checking
++       * its header flags to see if it advertises the capability.
++       */
++      reset = ((ntohl(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0);
++      return t4_fw_restart(adap, mbox, reset);
++}
++
++
++/**
+  *    t4_fw_config_file - setup an adapter via a Configuration File
+  *    @adap: the adapter
+  *    @mbox: mailbox to use for the FW command
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+index 732c6da..a1a8b57 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+@@ -321,6 +321,8 @@
+ #define  WINDOW(x)       ((x) << WINDOW_SHIFT)
+ #define PCIE_MEM_ACCESS_OFFSET 0x306c
++#define PCIE_FW 0x30b8
++
+ #define PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS 0x5908
+ #define  RNPP 0x80000000U
+ #define  RPCP 0x20000000U
+@@ -419,6 +421,7 @@
+ #define CIM_BOOT_CFG 0x7b00
+ #define  BOOTADDR_MASK 0xffffff00U
++#define  UPCRST        0x1U
+ #define CIM_PF_MAILBOX_DATA 0x240
+ #define CIM_PF_MAILBOX_CTRL 0x280
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+index b1d5561..a636463 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+@@ -317,9 +317,15 @@ struct fw_reset_cmd {
+       __be32 op_to_write;
+       __be32 retval_len16;
+       __be32 val;
+-      __be32 r3;
++      __be32 halt_pkd;
+ };
++#define FW_RESET_CMD_HALT_SHIFT    31
++#define FW_RESET_CMD_HALT_MASK     0x1
++#define FW_RESET_CMD_HALT(x)       ((x) << FW_RESET_CMD_HALT_SHIFT)
++#define FW_RESET_CMD_HALT_GET(x)  \
++      (((x) >> FW_RESET_CMD_HALT_SHIFT) & FW_RESET_CMD_HALT_MASK)
++
+ enum fw_hellow_cmd {
+       fw_hello_cmd_stage_os           = 0x0
+ };
+@@ -1648,6 +1654,7 @@ struct fw_debug_cmd {
+ #define FW_PCIE_FW_ERR           (1U << 31)
+ #define FW_PCIE_FW_INIT          (1U << 30)
++#define FW_PCIE_FW_HALT          (1U << 29)
+ #define FW_PCIE_FW_MASTER_VLD    (1U << 15)
+ #define FW_PCIE_FW_MASTER_MASK   0x7
+ #define FW_PCIE_FW_MASTER_SHIFT  12
+@@ -1669,7 +1676,11 @@ struct fw_hdr {
+       u8 intfver_iscsi;
+       u8 intfver_fcoe;
+       u8 reserved2;
+-      __be32  reserved3[27];
++      __u32   reserved3;
++      __u32   reserved4;
++      __u32   reserved5;
++      __be32  flags;
++      __be32  reserved6[23];
+ };
+ #define FW_HDR_FW_VER_MAJOR_GET(x) (((x) >> 24) & 0xff)
+@@ -1677,4 +1688,8 @@ struct fw_hdr {
+ #define FW_HDR_FW_VER_MICRO_GET(x) (((x) >> 8) & 0xff)
+ #define FW_HDR_FW_VER_BUILD_GET(x) (((x) >> 0) & 0xff)
++enum fw_hdr_flags {
++      FW_HDR_FLAGS_RESET_HALT = 0x00000001,
++};
++
+ #endif /* _T4FW_INTERFACE_H_ */
+-- 
+1.7.1
+