ethdev: separate driver APIs
[dpdk.git] / drivers / net / cxgbe / base / t4_hw.c
index 05bf1e8..56f38c8 100644 (file)
 #include <rte_atomic.h>
 #include <rte_branch_prediction.h>
 #include <rte_memory.h>
-#include <rte_memzone.h>
 #include <rte_tailq.h>
 #include <rte_eal.h>
 #include <rte_alarm.h>
 #include <rte_ether.h>
-#include <rte_ethdev.h>
-#include <rte_atomic.h>
+#include <rte_ethdev_driver.h>
 #include <rte_malloc.h>
 #include <rte_random.h>
 #include <rte_dev.h>
@@ -57,7 +55,8 @@
 #include "t4_regs_values.h"
 #include "t4fw_interface.h"
 
-static void init_link_config(struct link_config *lc, unsigned int caps);
+static void init_link_config(struct link_config *lc, unsigned int pcaps,
+                            unsigned int acaps);
 
 /**
  * t4_read_mtu_tbl - returns the values in the HW path MTU table
@@ -403,6 +402,7 @@ int t4_wr_mbox_meat_timeout(struct adapter *adap, int mbox,
                        t4_os_atomic_list_del(&entry, &adap->mbox_list,
                                              &adap->mbox_lock);
                        t4_report_fw_error(adap);
+                       free(temp);
                        return (pcie_fw & F_PCIE_FW_ERR) ? -ENXIO : -EBUSY;
                }
 
@@ -446,6 +446,7 @@ int t4_wr_mbox_meat_timeout(struct adapter *adap, int mbox,
                                                         &adap->mbox_list,
                                                         &adap->mbox_lock));
                t4_report_fw_error(adap);
+               free(temp);
                return (v == X_MBOWNER_FW ? -EBUSY : -ETIMEDOUT);
        }
 
@@ -546,6 +547,7 @@ int t4_wr_mbox_meat_timeout(struct adapter *adap, int mbox,
                        T4_OS_MBOX_LOCKING(
                                t4_os_atomic_list_del(&entry, &adap->mbox_list,
                                                      &adap->mbox_lock));
+                       free(temp);
                        return -G_FW_CMD_RETVAL((int)res);
                }
        }
@@ -2495,6 +2497,43 @@ int t4_read_flash(struct adapter *adapter, unsigned int addr,
        return 0;
 }
 
+/**
+ * t4_get_exprom_version - return the Expansion ROM version (if any)
+ * @adapter: the adapter
+ * @vers: where to place the version
+ *
+ * Reads the Expansion ROM header from FLASH and returns the version
+ * number (if present) through the @vers return value pointer.  We return
+ * this in the Firmware Version Format since it's convenient.  Return
+ * 0 on success, -ENOENT if no Expansion ROM is present.
+ */
+static int t4_get_exprom_version(struct adapter *adapter, u32 *vers)
+{
+       struct exprom_header {
+               unsigned char hdr_arr[16];      /* must start with 0x55aa */
+               unsigned char hdr_ver[4];       /* Expansion ROM version */
+       } *hdr;
+       u32 exprom_header_buf[DIV_ROUND_UP(sizeof(struct exprom_header),
+                                          sizeof(u32))];
+       int ret;
+
+       ret = t4_read_flash(adapter, FLASH_EXP_ROM_START,
+                           ARRAY_SIZE(exprom_header_buf),
+                           exprom_header_buf, 0);
+       if (ret)
+               return ret;
+
+       hdr = (struct exprom_header *)exprom_header_buf;
+       if (hdr->hdr_arr[0] != 0x55 || hdr->hdr_arr[1] != 0xaa)
+               return -ENOENT;
+
+       *vers = (V_FW_HDR_FW_VER_MAJOR(hdr->hdr_ver[0]) |
+                V_FW_HDR_FW_VER_MINOR(hdr->hdr_ver[1]) |
+                V_FW_HDR_FW_VER_MICRO(hdr->hdr_ver[2]) |
+                V_FW_HDR_FW_VER_BUILD(hdr->hdr_ver[3]));
+       return 0;
+}
+
 /**
  * t4_get_fw_version - read the firmware version
  * @adapter: the adapter
@@ -2502,12 +2541,26 @@ int t4_read_flash(struct adapter *adapter, unsigned int addr,
  *
  * Reads the FW version from flash.
  */
-int t4_get_fw_version(struct adapter *adapter, u32 *vers)
+static int t4_get_fw_version(struct adapter *adapter, u32 *vers)
 {
        return t4_read_flash(adapter, FLASH_FW_START +
                             offsetof(struct fw_hdr, fw_ver), 1, vers, 0);
 }
 
+/**
+ *     t4_get_bs_version - read the firmware bootstrap version
+ *     @adapter: the adapter
+ *     @vers: where to place the version
+ *
+ *     Reads the FW Bootstrap version from flash.
+ */
+static int t4_get_bs_version(struct adapter *adapter, u32 *vers)
+{
+       return t4_read_flash(adapter, FLASH_FWBOOTSTRAP_START +
+                            offsetof(struct fw_hdr, fw_ver), 1,
+                            vers, 0);
+}
+
 /**
  * t4_get_tp_version - read the TP microcode version
  * @adapter: the adapter
@@ -2515,13 +2568,108 @@ int t4_get_fw_version(struct adapter *adapter, u32 *vers)
  *
  * Reads the TP microcode version from flash.
  */
-int t4_get_tp_version(struct adapter *adapter, u32 *vers)
+static int t4_get_tp_version(struct adapter *adapter, u32 *vers)
 {
        return t4_read_flash(adapter, FLASH_FW_START +
                             offsetof(struct fw_hdr, tp_microcode_ver),
                             1, vers, 0);
 }
 
+/**
+ * t4_get_version_info - extract various chip/firmware version information
+ * @adapter: the adapter
+ *
+ * Reads various chip/firmware version numbers and stores them into the
+ * adapter Adapter Parameters structure.  If any of the efforts fails
+ * the first failure will be returned, but all of the version numbers
+ * will be read.
+ */
+int t4_get_version_info(struct adapter *adapter)
+{
+       int ret = 0;
+
+#define FIRST_RET(__getvinfo) \
+       do { \
+               int __ret = __getvinfo; \
+               if (__ret && !ret) \
+                       ret = __ret; \
+       } while (0)
+
+       FIRST_RET(t4_get_fw_version(adapter, &adapter->params.fw_vers));
+       FIRST_RET(t4_get_bs_version(adapter, &adapter->params.bs_vers));
+       FIRST_RET(t4_get_tp_version(adapter, &adapter->params.tp_vers));
+       FIRST_RET(t4_get_exprom_version(adapter, &adapter->params.er_vers));
+
+#undef FIRST_RET
+
+       return ret;
+}
+
+/**
+ * t4_dump_version_info - dump all of the adapter configuration IDs
+ * @adapter: the adapter
+ *
+ * Dumps all of the various bits of adapter configuration version/revision
+ * IDs information.  This is typically called at some point after
+ * t4_get_version_info() has been called.
+ */
+void t4_dump_version_info(struct adapter *adapter)
+{
+       /**
+        * Device information.
+        */
+       dev_info(adapter, "Chelsio rev %d\n",
+                CHELSIO_CHIP_RELEASE(adapter->params.chip));
+
+       /**
+        * Firmware Version.
+        */
+       if (!adapter->params.fw_vers)
+               dev_warn(adapter, "No firmware loaded\n");
+       else
+               dev_info(adapter, "Firmware version: %u.%u.%u.%u\n",
+                        G_FW_HDR_FW_VER_MAJOR(adapter->params.fw_vers),
+                        G_FW_HDR_FW_VER_MINOR(adapter->params.fw_vers),
+                        G_FW_HDR_FW_VER_MICRO(adapter->params.fw_vers),
+                        G_FW_HDR_FW_VER_BUILD(adapter->params.fw_vers));
+
+       /**
+        * Bootstrap Firmware Version.
+        */
+       if (!adapter->params.bs_vers)
+               dev_warn(adapter, "No bootstrap loaded\n");
+       else
+               dev_info(adapter, "Bootstrap version: %u.%u.%u.%u\n",
+                        G_FW_HDR_FW_VER_MAJOR(adapter->params.bs_vers),
+                        G_FW_HDR_FW_VER_MINOR(adapter->params.bs_vers),
+                        G_FW_HDR_FW_VER_MICRO(adapter->params.bs_vers),
+                        G_FW_HDR_FW_VER_BUILD(adapter->params.bs_vers));
+
+       /**
+        * TP Microcode Version.
+        */
+       if (!adapter->params.tp_vers)
+               dev_warn(adapter, "No TP Microcode loaded\n");
+       else
+               dev_info(adapter, "TP Microcode version: %u.%u.%u.%u\n",
+                        G_FW_HDR_FW_VER_MAJOR(adapter->params.tp_vers),
+                        G_FW_HDR_FW_VER_MINOR(adapter->params.tp_vers),
+                        G_FW_HDR_FW_VER_MICRO(adapter->params.tp_vers),
+                        G_FW_HDR_FW_VER_BUILD(adapter->params.tp_vers));
+
+       /**
+        * Expansion ROM version.
+        */
+       if (!adapter->params.er_vers)
+               dev_info(adapter, "No Expansion ROM loaded\n");
+       else
+               dev_info(adapter, "Expansion ROM version: %u.%u.%u.%u\n",
+                        G_FW_HDR_FW_VER_MAJOR(adapter->params.er_vers),
+                        G_FW_HDR_FW_VER_MINOR(adapter->params.er_vers),
+                        G_FW_HDR_FW_VER_MICRO(adapter->params.er_vers),
+                        G_FW_HDR_FW_VER_BUILD(adapter->params.er_vers));
+}
+
 #define ADVERT_MASK (V_FW_PORT_CAP_SPEED(M_FW_PORT_CAP_SPEED) | \
                     FW_PORT_CAP_ANEG)
 
@@ -2542,14 +2690,24 @@ int t4_link_l1cfg(struct adapter *adap, unsigned int mbox, unsigned int port,
                  struct link_config *lc)
 {
        struct fw_port_cmd c;
-       unsigned int fc = 0, mdi = V_FW_PORT_CAP_MDI(FW_PORT_CAP_MDI_AUTO);
+       unsigned int mdi = V_FW_PORT_CAP_MDI(FW_PORT_CAP_MDI_AUTO);
+       unsigned int fc, fec;
 
        lc->link_ok = 0;
+       fc = 0;
        if (lc->requested_fc & PAUSE_RX)
                fc |= FW_PORT_CAP_FC_RX;
        if (lc->requested_fc & PAUSE_TX)
                fc |= FW_PORT_CAP_FC_TX;
 
+       fec = 0;
+       if (lc->requested_fec & FEC_RS)
+               fec |= FW_PORT_CAP_FEC_RS;
+       if (lc->requested_fec & FEC_BASER_RS)
+               fec |= FW_PORT_CAP_FEC_BASER_RS;
+       if (lc->requested_fec & FEC_RESERVED)
+               fec |= FW_PORT_CAP_FEC_RESERVED;
+
        memset(&c, 0, sizeof(c));
        c.op_to_portid = cpu_to_be32(V_FW_CMD_OP(FW_PORT_CMD) |
                                     F_FW_CMD_REQUEST | F_FW_CMD_EXEC |
@@ -2560,13 +2718,16 @@ int t4_link_l1cfg(struct adapter *adap, unsigned int mbox, unsigned int port,
 
        if (!(lc->supported & FW_PORT_CAP_ANEG)) {
                c.u.l1cfg.rcap = cpu_to_be32((lc->supported & ADVERT_MASK) |
-                                            fc);
-               lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+                                            fc | fec);
+               lc->fc = lc->requested_fc & ~PAUSE_AUTONEG;
+               lc->fec = lc->requested_fec;
        } else if (lc->autoneg == AUTONEG_DISABLE) {
-               c.u.l1cfg.rcap = cpu_to_be32(lc->requested_speed | fc | mdi);
-               lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+               c.u.l1cfg.rcap = cpu_to_be32(lc->requested_speed | fc |
+                                            fec | mdi);
+               lc->fc = lc->requested_fc & ~PAUSE_AUTONEG;
+               lc->fec = lc->requested_fec;
        } else {
-               c.u.l1cfg.rcap = cpu_to_be32(lc->advertising | fc | mdi);
+               c.u.l1cfg.rcap = cpu_to_be32(lc->advertising | fc | fec | mdi);
        }
 
        return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
@@ -2684,21 +2845,90 @@ const char *t4_get_port_type_description(enum fw_port_type port_type)
 /**
  * t4_get_mps_bg_map - return the buffer groups associated with a port
  * @adap: the adapter
- * @idx: the port index
+ * @pidx: the port index
  *
  * Returns a bitmap indicating which MPS buffer groups are associated
  * with the given port.  Bit i is set if buffer group i is used by the
  * port.
  */
-unsigned int t4_get_mps_bg_map(struct adapter *adap, int idx)
+unsigned int t4_get_mps_bg_map(struct adapter *adap, unsigned int pidx)
 {
-       u32 n = G_NUMPORTS(t4_read_reg(adap, A_MPS_CMN_CTL));
+       unsigned int chip_version = CHELSIO_CHIP_VERSION(adap->params.chip);
+       unsigned int nports = 1 << G_NUMPORTS(t4_read_reg(adap,
+                                                         A_MPS_CMN_CTL));
+
+       if (pidx >= nports) {
+               dev_warn(adap, "MPS Port Index %d >= Nports %d\n",
+                        pidx, nports);
+               return 0;
+       }
+
+       switch (chip_version) {
+       case CHELSIO_T4:
+       case CHELSIO_T5:
+               switch (nports) {
+               case 1: return 0xf;
+               case 2: return 3 << (2 * pidx);
+               case 4: return 1 << pidx;
+               }
+               break;
 
-       if (n == 0)
-               return idx == 0 ? 0xf : 0;
-       if (n == 1)
-               return idx < 2 ? (3 << (2 * idx)) : 0;
-       return 1 << idx;
+       case CHELSIO_T6:
+               switch (nports) {
+               case 2: return 1 << (2 * pidx);
+               }
+               break;
+       }
+
+       dev_err(adap, "Need MPS Buffer Group Map for Chip %0x, Nports %d\n",
+               chip_version, nports);
+       return 0;
+}
+
+/**
+ * t4_get_tp_ch_map - return TP ingress channels associated with a port
+ * @adapter: the adapter
+ * @pidx: the port index
+ *
+ * Returns a bitmap indicating which TP Ingress Channels are associated with
+ * a given Port.  Bit i is set if TP Ingress Channel i is used by the Port.
+ */
+unsigned int t4_get_tp_ch_map(struct adapter *adapter, unsigned int pidx)
+{
+       unsigned int chip_version = CHELSIO_CHIP_VERSION(adapter->params.chip);
+       unsigned int nports = 1 << G_NUMPORTS(t4_read_reg(adapter,
+                                                         A_MPS_CMN_CTL));
+
+       if (pidx >= nports) {
+               dev_warn(adap, "TP Port Index %d >= Nports %d\n",
+                        pidx, nports);
+               return 0;
+       }
+
+       switch (chip_version) {
+       case CHELSIO_T4:
+       case CHELSIO_T5:
+               /* Note that this happens to be the same values as the MPS
+                * Buffer Group Map for these Chips.  But we replicate the code
+                * here because they're really separate concepts.
+                */
+               switch (nports) {
+               case 1: return 0xf;
+               case 2: return 3 << (2 * pidx);
+               case 4: return 1 << pidx;
+               }
+               break;
+
+       case CHELSIO_T6:
+               switch (nports) {
+               case 2: return 1 << pidx;
+               }
+               break;
+       }
+
+       dev_err(adapter, "Need TP Channel Map for Chip %0x, Nports %d\n",
+               chip_version, nports);
+       return 0;
 }
 
 /**
@@ -2712,6 +2942,7 @@ unsigned int t4_get_mps_bg_map(struct adapter *adap, int idx)
 void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
 {
        u32 bgmap = t4_get_mps_bg_map(adap, idx);
+       u32 stat_ctl = t4_read_reg(adap, A_MPS_STAT_CTL);
 
 #define GET_STAT(name) \
        t4_read_reg64(adap, \
@@ -2744,6 +2975,15 @@ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
        p->tx_ppp6             = GET_STAT(TX_PORT_PPP6);
        p->tx_ppp7             = GET_STAT(TX_PORT_PPP7);
 
+       if (CHELSIO_CHIP_VERSION(adap->params.chip) >= CHELSIO_T5) {
+               if (stat_ctl & F_COUNTPAUSESTATTX) {
+                       p->tx_frames -= p->tx_pause;
+                       p->tx_octets -= p->tx_pause * 64;
+               }
+               if (stat_ctl & F_COUNTPAUSEMCTX)
+                       p->tx_mcast_frames -= p->tx_pause;
+       }
+
        p->rx_octets           = GET_STAT(RX_PORT_BYTES);
        p->rx_frames           = GET_STAT(RX_PORT_FRAMES);
        p->rx_bcast_frames     = GET_STAT(RX_PORT_BCAST);
@@ -2771,6 +3011,16 @@ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
        p->rx_ppp5             = GET_STAT(RX_PORT_PPP5);
        p->rx_ppp6             = GET_STAT(RX_PORT_PPP6);
        p->rx_ppp7             = GET_STAT(RX_PORT_PPP7);
+
+       if (CHELSIO_CHIP_VERSION(adap->params.chip) >= CHELSIO_T5) {
+               if (stat_ctl & F_COUNTPAUSESTATRX) {
+                       p->rx_frames -= p->rx_pause;
+                       p->rx_octets -= p->rx_pause * 64;
+               }
+               if (stat_ctl & F_COUNTPAUSEMCRX)
+                       p->rx_mcast_frames -= p->rx_pause;
+       }
+
        p->rx_ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_DROP_FRAME) : 0;
        p->rx_ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_DROP_FRAME) : 0;
        p->rx_ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_DROP_FRAME) : 0;
@@ -3128,6 +3378,49 @@ int t4_fw_restart(struct adapter *adap, unsigned int mbox, int reset)
        return 0;
 }
 
+/**
+ * t4_fl_pkt_align - return the fl packet alignment
+ * @adap: the adapter
+ *
+ * T4 has a single field to specify the packing and padding boundary.
+ * T5 onwards has separate fields for this and hence the alignment for
+ * next packet offset is maximum of these two.
+ */
+int t4_fl_pkt_align(struct adapter *adap)
+{
+       u32 sge_control, sge_control2;
+       unsigned int ingpadboundary, ingpackboundary, fl_align, ingpad_shift;
+
+       sge_control = t4_read_reg(adap, A_SGE_CONTROL);
+
+       /* T4 uses a single control field to specify both the PCIe Padding and
+        * Packing Boundary.  T5 introduced the ability to specify these
+        * separately.  The actual Ingress Packet Data alignment boundary
+        * within Packed Buffer Mode is the maximum of these two
+        * specifications.
+        */
+       if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5)
+               ingpad_shift = X_INGPADBOUNDARY_SHIFT;
+       else
+               ingpad_shift = X_T6_INGPADBOUNDARY_SHIFT;
+
+       ingpadboundary = 1 << (G_INGPADBOUNDARY(sge_control) + ingpad_shift);
+
+       fl_align = ingpadboundary;
+       if (!is_t4(adap->params.chip)) {
+               sge_control2 = t4_read_reg(adap, A_SGE_CONTROL2);
+               ingpackboundary = G_INGPACKBOUNDARY(sge_control2);
+               if (ingpackboundary == X_INGPACKBOUNDARY_16B)
+                       ingpackboundary = 16;
+               else
+                       ingpackboundary = 1 << (ingpackboundary +
+                                       X_INGPACKBOUNDARY_SHIFT);
+
+               fl_align = max(ingpadboundary, ingpackboundary);
+       }
+       return fl_align;
+}
+
 /**
  * t4_fixup_host_params_compat - fix up host-dependent parameters
  * @adap: the adapter
@@ -3173,6 +3466,10 @@ int t4_fixup_host_params_compat(struct adapter *adap,
                                                  X_INGPADBOUNDARY_SHIFT) |
                                V_EGRSTATUSPAGESIZE(stat_len != 64));
        else {
+               unsigned int pack_align;
+               unsigned int ingpad, ingpack;
+               unsigned int pcie_cap;
+
                /*
                 * T5 introduced the separation of the Free List Padding and
                 * Packing Boundaries.  Thus, we can select a smaller Padding
@@ -3186,12 +3483,34 @@ int t4_fixup_host_params_compat(struct adapter *adap,
                 * Size (the minimum unit of transfer to/from Memory).  If we
                 * have a Padding Boundary which is smaller than the Memory
                 * Line Size, that'll involve a Read-Modify-Write cycle on the
-                * Memory Controller which is never good.  For T5 the smallest
-                * Padding Boundary which we can select is 32 bytes which is
-                * larger than any known Memory Controller Line Size so we'll
-                * use that.
+                * Memory Controller which is never good.
                 */
 
+               /* We want the Packing Boundary to be based on the Cache Line
+                * Size in order to help avoid False Sharing performance
+                * issues between CPUs, etc.  We also want the Packing
+                * Boundary to incorporate the PCI-E Maximum Payload Size.  We
+                * get best performance when the Packing Boundary is a
+                * multiple of the Maximum Payload Size.
+                */
+               pack_align = fl_align;
+               pcie_cap = t4_os_find_pci_capability(adap, PCI_CAP_ID_EXP);
+               if (pcie_cap) {
+                       unsigned int mps, mps_log;
+                       u16 devctl;
+
+                       /* The PCIe Device Control Maximum Payload Size field
+                        * [bits 7:5] encodes sizes as powers of 2 starting at
+                        * 128 bytes.
+                        */
+                       t4_os_pci_read_cfg2(adap, pcie_cap + PCI_EXP_DEVCTL,
+                                           &devctl);
+                       mps_log = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5) + 7;
+                       mps = 1 << mps_log;
+                       if (mps > pack_align)
+                               pack_align = mps;
+               }
+
                /*
                 * N.B. T5 has a different interpretation of the "0" value for
                 * the Packing Boundary.  This corresponds to 16 bytes instead
@@ -3200,19 +3519,36 @@ int t4_fixup_host_params_compat(struct adapter *adap,
                 * on the other hand, if we wanted 32 bytes, the best we can
                 * really do is 64 bytes ...
                 */
-               if (fl_align <= 32) {
+               if (pack_align <= 16) {
+                       ingpack = X_INGPACKBOUNDARY_16B;
+                       fl_align = 16;
+               } else if (pack_align == 32) {
+                       ingpack = X_INGPACKBOUNDARY_64B;
                        fl_align = 64;
-                       fl_align_log = 6;
+               } else {
+                       unsigned int pack_align_log = cxgbe_fls(pack_align) - 1;
+
+                       ingpack = pack_align_log - X_INGPACKBOUNDARY_SHIFT;
+                       fl_align = pack_align;
                }
+
+               /* Use the smallest Ingress Padding which isn't smaller than
+                * the Memory Controller Read/Write Size.  We'll take that as
+                * being 8 bytes since we don't know of any system with a
+                * wider Memory Controller Bus Width.
+                */
+               if (is_t5(adap->params.chip))
+                       ingpad = X_INGPADBOUNDARY_32B;
+               else
+                       ingpad = X_T6_INGPADBOUNDARY_8B;
                t4_set_reg_field(adap, A_SGE_CONTROL,
                                 V_INGPADBOUNDARY(M_INGPADBOUNDARY) |
                                 F_EGRSTATUSPAGESIZE,
-                                V_INGPADBOUNDARY(X_INGPCIEBOUNDARY_32B) |
+                                V_INGPADBOUNDARY(ingpad) |
                                 V_EGRSTATUSPAGESIZE(stat_len != 64));
                t4_set_reg_field(adap, A_SGE_CONTROL2,
                                 V_INGPACKBOUNDARY(M_INGPACKBOUNDARY),
-                                V_INGPACKBOUNDARY(fl_align_log -
-                                                  X_INGPACKBOUNDARY_SHIFT));
+                                V_INGPACKBOUNDARY(ingpack));
        }
 
        /*
@@ -3831,19 +4167,37 @@ void t4_reset_link_config(struct adapter *adap, int idx)
 /**
  * init_link_config - initialize a link's SW state
  * @lc: structure holding the link state
- * @caps: link capabilities
+ * @pcaps: link Port Capabilities
+ * @acaps: link current Advertised Port Capabilities
  *
  * Initializes the SW state maintained for each link, including the link's
  * capabilities and default speed/flow-control/autonegotiation settings.
  */
-static void init_link_config(struct link_config *lc,
-                            unsigned int caps)
+static void init_link_config(struct link_config *lc, unsigned int pcaps,
+                            unsigned int acaps)
 {
-       lc->supported = caps;
+       unsigned int fec;
+
+       lc->supported = pcaps;
        lc->requested_speed = 0;
        lc->speed = 0;
        lc->requested_fc = 0;
        lc->fc = 0;
+
+       /**
+        * For Forward Error Control, we default to whatever the Firmware
+        * tells us the Link is currently advertising.
+        */
+       fec = 0;
+       if (acaps & FW_PORT_CAP_FEC_RS)
+               fec |= FEC_RS;
+       if (acaps & FW_PORT_CAP_FEC_BASER_RS)
+               fec |= FEC_BASER_RS;
+       if (acaps & FW_PORT_CAP_FEC_RESERVED)
+               fec |= FEC_RESERVED;
+       lc->requested_fec = fec;
+       lc->fec = fec;
+
        if (lc->supported & FW_PORT_CAP_ANEG) {
                lc->advertising = lc->supported & ADVERT_MASK;
                lc->autoneg = AUTONEG_ENABLE;
@@ -4261,6 +4615,14 @@ int t4_init_tp_params(struct adapter *adap)
                         &adap->params.tp.ingress_config, 1,
                         A_TP_INGRESS_CONFIG);
 
+       /* For T6, cache the adapter's compressed error vector
+        * and passing outer header info for encapsulated packets.
+        */
+       if (CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) {
+               v = t4_read_reg(adap, A_TP_OUT_CONFIG);
+               adap->params.tp.rx_pkt_encap = (v & F_CRXPKTENC) ? 1 : 0;
+       }
+
        /*
         * Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field
         * shift positions of several elements of the Compressed Filter Tuple
@@ -4399,7 +4761,8 @@ int t4_port_init(struct adapter *adap, int mbox, int pf, int vf)
                p->port_type = G_FW_PORT_CMD_PTYPE(ret);
                p->mod_type = FW_PORT_MOD_TYPE_NA;
 
-               init_link_config(&p->link_cfg, be16_to_cpu(c.u.info.pcap));
+               init_link_config(&p->link_cfg, be16_to_cpu(c.u.info.pcap),
+                                be16_to_cpu(c.u.info.acap));
                j++;
        }
        return 0;