--- /dev/null
+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
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+