]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
cxgb4: program pci completion timeout
[mirror_ubuntu-artful-kernel.git] / drivers / net / ethernet / chelsio / cxgb4 / t4_hw.c
index 7b92f0f862050a9eb1f9703f0945b4d5f41656dd..efd0aa1a224e799f0c5a38a5447795f1b25abb30 100644 (file)
@@ -150,7 +150,12 @@ void t4_write_indirect(struct adapter *adap, unsigned int addr_reg,
  */
 void t4_hw_pci_read_cfg4(struct adapter *adap, int reg, u32 *val)
 {
-       u32 req = ENABLE_F | FUNCTION_V(adap->fn) | REGISTER_V(reg);
+       u32 req = FUNCTION_V(adap->pf) | REGISTER_V(reg);
+
+       if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5)
+               req |= ENABLE_F;
+       else
+               req |= T6_ENABLE_F;
 
        if (is_t4(adap->params.chip))
                req |= LOCALCFG_F;
@@ -381,9 +386,8 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
        /* Offset into the region of memory which is being accessed
         * MEM_EDC0 = 0
         * MEM_EDC1 = 1
-        * MEM_MC   = 2 -- T4
-        * MEM_MC0  = 2 -- For T5
-        * MEM_MC1  = 3 -- For T5
+        * MEM_MC   = 2 -- MEM_MC for chips with only 1 memory controller
+        * MEM_MC1  = 3 -- for chips with 2 memory controllers (e.g. T5)
         */
        edc_size  = EDRAM0_SIZE_G(t4_read_reg(adap, MA_EDRAM0_BAR_A));
        if (mtype != MEM_MC1)
@@ -412,7 +416,7 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
        mem_base = PCIEOFST_G(mem_reg) << PCIEOFST_SHIFT_X;
        if (is_t4(adap->params.chip))
                mem_base -= adap->t4_bar0;
-       win_pf = is_t4(adap->params.chip) ? 0 : PFNUM_V(adap->fn);
+       win_pf = is_t4(adap->params.chip) ? 0 : PFNUM_V(adap->pf);
 
        /* Calculate our initial PCI-E Memory Window Position and Offset into
         * that Window.
@@ -547,7 +551,7 @@ u32 t4_read_pcie_cfg4(struct adapter *adap, int reg)
        ldst_cmd.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst_cmd));
        ldst_cmd.u.pcie.select_naccess = FW_LDST_CMD_NACCESS_V(1);
        ldst_cmd.u.pcie.ctrl_to_fn =
-               (FW_LDST_CMD_LC_F | FW_LDST_CMD_FN_V(adap->fn));
+               (FW_LDST_CMD_LC_F | FW_LDST_CMD_FN_V(adap->pf));
        ldst_cmd.u.pcie.r = reg;
 
        /* If the LDST Command succeeds, return the result, otherwise
@@ -634,6 +638,7 @@ unsigned int t4_get_regs_len(struct adapter *adapter)
                return T4_REGMAP_SIZE;
 
        case CHELSIO_T5:
+       case CHELSIO_T6:
                return T5_REGMAP_SIZE;
        }
 
@@ -1316,6 +1321,344 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
                0x51300, 0x51308,
        };
 
+       static const unsigned int t6_reg_ranges[] = {
+               0x1008, 0x114c,
+               0x1180, 0x11b4,
+               0x11fc, 0x1250,
+               0x1280, 0x133c,
+               0x1800, 0x18fc,
+               0x3000, 0x302c,
+               0x3060, 0x30d8,
+               0x30e0, 0x30fc,
+               0x3140, 0x357c,
+               0x35a8, 0x35cc,
+               0x35ec, 0x35ec,
+               0x3600, 0x5624,
+               0x56cc, 0x575c,
+               0x580c, 0x5814,
+               0x5890, 0x58bc,
+               0x5940, 0x595c,
+               0x5980, 0x598c,
+               0x59b0, 0x59dc,
+               0x59fc, 0x5a18,
+               0x5a60, 0x5a6c,
+               0x5a80, 0x5a9c,
+               0x5b94, 0x5bfc,
+               0x5c10, 0x5ec0,
+               0x5ec8, 0x5ec8,
+               0x6000, 0x6040,
+               0x6058, 0x6154,
+               0x7700, 0x7798,
+               0x77c0, 0x7880,
+               0x78cc, 0x78fc,
+               0x7b00, 0x7c54,
+               0x7d00, 0x7efc,
+               0x8dc0, 0x8de0,
+               0x8df8, 0x8e84,
+               0x8ea0, 0x8f88,
+               0x8fb8, 0x911c,
+               0x9400, 0x9470,
+               0x9600, 0x971c,
+               0x9800, 0x9808,
+               0x9820, 0x983c,
+               0x9850, 0x9864,
+               0x9c00, 0x9c6c,
+               0x9c80, 0x9cec,
+               0x9d00, 0x9d6c,
+               0x9d80, 0x9dec,
+               0x9e00, 0x9e6c,
+               0x9e80, 0x9eec,
+               0x9f00, 0x9f6c,
+               0x9f80, 0xa020,
+               0xd004, 0xd03c,
+               0xdfc0, 0xdfe0,
+               0xe000, 0xf008,
+               0x11000, 0x11014,
+               0x11048, 0x11110,
+               0x11118, 0x1117c,
+               0x11190, 0x11260,
+               0x11300, 0x1130c,
+               0x12000, 0x1205c,
+               0x19040, 0x1906c,
+               0x19078, 0x19080,
+               0x1908c, 0x19124,
+               0x19150, 0x191b0,
+               0x191d0, 0x191e8,
+               0x19238, 0x192b8,
+               0x193f8, 0x19474,
+               0x19490, 0x194cc,
+               0x194f0, 0x194f8,
+               0x19c00, 0x19c80,
+               0x19c94, 0x19cbc,
+               0x19ce4, 0x19d28,
+               0x19d50, 0x19d78,
+               0x19d94, 0x19dc8,
+               0x19df0, 0x19e10,
+               0x19e50, 0x19e6c,
+               0x19ea0, 0x19f34,
+               0x19f40, 0x19f50,
+               0x19f90, 0x19fac,
+               0x19fc4, 0x19fe4,
+               0x1a000, 0x1a06c,
+               0x1a0b0, 0x1a120,
+               0x1a128, 0x1a138,
+               0x1a190, 0x1a1c4,
+               0x1a1fc, 0x1a1fc,
+               0x1e008, 0x1e00c,
+               0x1e040, 0x1e04c,
+               0x1e284, 0x1e290,
+               0x1e2c0, 0x1e2c0,
+               0x1e2e0, 0x1e2e0,
+               0x1e300, 0x1e384,
+               0x1e3c0, 0x1e3c8,
+               0x1e408, 0x1e40c,
+               0x1e440, 0x1e44c,
+               0x1e684, 0x1e690,
+               0x1e6c0, 0x1e6c0,
+               0x1e6e0, 0x1e6e0,
+               0x1e700, 0x1e784,
+               0x1e7c0, 0x1e7c8,
+               0x1e808, 0x1e80c,
+               0x1e840, 0x1e84c,
+               0x1ea84, 0x1ea90,
+               0x1eac0, 0x1eac0,
+               0x1eae0, 0x1eae0,
+               0x1eb00, 0x1eb84,
+               0x1ebc0, 0x1ebc8,
+               0x1ec08, 0x1ec0c,
+               0x1ec40, 0x1ec4c,
+               0x1ee84, 0x1ee90,
+               0x1eec0, 0x1eec0,
+               0x1eee0, 0x1eee0,
+               0x1ef00, 0x1ef84,
+               0x1efc0, 0x1efc8,
+               0x1f008, 0x1f00c,
+               0x1f040, 0x1f04c,
+               0x1f284, 0x1f290,
+               0x1f2c0, 0x1f2c0,
+               0x1f2e0, 0x1f2e0,
+               0x1f300, 0x1f384,
+               0x1f3c0, 0x1f3c8,
+               0x1f408, 0x1f40c,
+               0x1f440, 0x1f44c,
+               0x1f684, 0x1f690,
+               0x1f6c0, 0x1f6c0,
+               0x1f6e0, 0x1f6e0,
+               0x1f700, 0x1f784,
+               0x1f7c0, 0x1f7c8,
+               0x1f808, 0x1f80c,
+               0x1f840, 0x1f84c,
+               0x1fa84, 0x1fa90,
+               0x1fac0, 0x1fac0,
+               0x1fae0, 0x1fae0,
+               0x1fb00, 0x1fb84,
+               0x1fbc0, 0x1fbc8,
+               0x1fc08, 0x1fc0c,
+               0x1fc40, 0x1fc4c,
+               0x1fe84, 0x1fe90,
+               0x1fec0, 0x1fec0,
+               0x1fee0, 0x1fee0,
+               0x1ff00, 0x1ff84,
+               0x1ffc0, 0x1ffc8,
+               0x30000, 0x30070,
+               0x30100, 0x3015c,
+               0x30190, 0x301d0,
+               0x30200, 0x30318,
+               0x30400, 0x3052c,
+               0x30540, 0x3061c,
+               0x30800, 0x3088c,
+               0x308c0, 0x30908,
+               0x30910, 0x309b8,
+               0x30a00, 0x30a04,
+               0x30a0c, 0x30a2c,
+               0x30a44, 0x30a50,
+               0x30a74, 0x30c24,
+               0x30d00, 0x30d3c,
+               0x30d44, 0x30d7c,
+               0x30de0, 0x30de0,
+               0x30e00, 0x30ed4,
+               0x30f00, 0x30fa4,
+               0x30fc0, 0x30fc4,
+               0x31000, 0x31004,
+               0x31080, 0x310fc,
+               0x31208, 0x31220,
+               0x3123c, 0x31254,
+               0x31300, 0x31300,
+               0x31308, 0x3131c,
+               0x31338, 0x3133c,
+               0x31380, 0x31380,
+               0x31388, 0x313a8,
+               0x313b4, 0x313b4,
+               0x31400, 0x31420,
+               0x31438, 0x3143c,
+               0x31480, 0x31480,
+               0x314a8, 0x314a8,
+               0x314b0, 0x314b4,
+               0x314c8, 0x314d4,
+               0x31a40, 0x31a4c,
+               0x31af0, 0x31b20,
+               0x31b38, 0x31b3c,
+               0x31b80, 0x31b80,
+               0x31ba8, 0x31ba8,
+               0x31bb0, 0x31bb4,
+               0x31bc8, 0x31bd4,
+               0x32140, 0x3218c,
+               0x321f0, 0x32200,
+               0x32218, 0x32218,
+               0x32400, 0x32400,
+               0x32408, 0x3241c,
+               0x32618, 0x32620,
+               0x32664, 0x32664,
+               0x326a8, 0x326a8,
+               0x326ec, 0x326ec,
+               0x32a00, 0x32abc,
+               0x32b00, 0x32b78,
+               0x32c00, 0x32c00,
+               0x32c08, 0x32c3c,
+               0x32e00, 0x32e2c,
+               0x32f00, 0x32f2c,
+               0x33000, 0x330ac,
+               0x330c0, 0x331ac,
+               0x331c0, 0x332c4,
+               0x332e4, 0x333c4,
+               0x333e4, 0x334ac,
+               0x334c0, 0x335ac,
+               0x335c0, 0x336c4,
+               0x336e4, 0x337c4,
+               0x337e4, 0x337fc,
+               0x33814, 0x33814,
+               0x33854, 0x33868,
+               0x33880, 0x3388c,
+               0x338c0, 0x338d0,
+               0x338e8, 0x338ec,
+               0x33900, 0x339ac,
+               0x339c0, 0x33ac4,
+               0x33ae4, 0x33b10,
+               0x33b24, 0x33b50,
+               0x33bf0, 0x33c10,
+               0x33c24, 0x33c50,
+               0x33cf0, 0x33cfc,
+               0x34000, 0x34070,
+               0x34100, 0x3415c,
+               0x34190, 0x341d0,
+               0x34200, 0x34318,
+               0x34400, 0x3452c,
+               0x34540, 0x3461c,
+               0x34800, 0x3488c,
+               0x348c0, 0x34908,
+               0x34910, 0x349b8,
+               0x34a00, 0x34a04,
+               0x34a0c, 0x34a2c,
+               0x34a44, 0x34a50,
+               0x34a74, 0x34c24,
+               0x34d00, 0x34d3c,
+               0x34d44, 0x34d7c,
+               0x34de0, 0x34de0,
+               0x34e00, 0x34ed4,
+               0x34f00, 0x34fa4,
+               0x34fc0, 0x34fc4,
+               0x35000, 0x35004,
+               0x35080, 0x350fc,
+               0x35208, 0x35220,
+               0x3523c, 0x35254,
+               0x35300, 0x35300,
+               0x35308, 0x3531c,
+               0x35338, 0x3533c,
+               0x35380, 0x35380,
+               0x35388, 0x353a8,
+               0x353b4, 0x353b4,
+               0x35400, 0x35420,
+               0x35438, 0x3543c,
+               0x35480, 0x35480,
+               0x354a8, 0x354a8,
+               0x354b0, 0x354b4,
+               0x354c8, 0x354d4,
+               0x35a40, 0x35a4c,
+               0x35af0, 0x35b20,
+               0x35b38, 0x35b3c,
+               0x35b80, 0x35b80,
+               0x35ba8, 0x35ba8,
+               0x35bb0, 0x35bb4,
+               0x35bc8, 0x35bd4,
+               0x36140, 0x3618c,
+               0x361f0, 0x36200,
+               0x36218, 0x36218,
+               0x36400, 0x36400,
+               0x36408, 0x3641c,
+               0x36618, 0x36620,
+               0x36664, 0x36664,
+               0x366a8, 0x366a8,
+               0x366ec, 0x366ec,
+               0x36a00, 0x36abc,
+               0x36b00, 0x36b78,
+               0x36c00, 0x36c00,
+               0x36c08, 0x36c3c,
+               0x36e00, 0x36e2c,
+               0x36f00, 0x36f2c,
+               0x37000, 0x370ac,
+               0x370c0, 0x371ac,
+               0x371c0, 0x372c4,
+               0x372e4, 0x373c4,
+               0x373e4, 0x374ac,
+               0x374c0, 0x375ac,
+               0x375c0, 0x376c4,
+               0x376e4, 0x377c4,
+               0x377e4, 0x377fc,
+               0x37814, 0x37814,
+               0x37854, 0x37868,
+               0x37880, 0x3788c,
+               0x378c0, 0x378d0,
+               0x378e8, 0x378ec,
+               0x37900, 0x379ac,
+               0x379c0, 0x37ac4,
+               0x37ae4, 0x37b10,
+               0x37b24, 0x37b50,
+               0x37bf0, 0x37c10,
+               0x37c24, 0x37c50,
+               0x37cf0, 0x37cfc,
+               0x40040, 0x40040,
+               0x40080, 0x40084,
+               0x40100, 0x40100,
+               0x40140, 0x401bc,
+               0x40200, 0x40214,
+               0x40228, 0x40228,
+               0x40240, 0x40258,
+               0x40280, 0x40280,
+               0x40304, 0x40304,
+               0x40330, 0x4033c,
+               0x41304, 0x413dc,
+               0x41400, 0x4141c,
+               0x41480, 0x414d0,
+               0x44000, 0x4407c,
+               0x440c0, 0x4427c,
+               0x442c0, 0x4447c,
+               0x444c0, 0x4467c,
+               0x446c0, 0x4487c,
+               0x448c0, 0x44a7c,
+               0x44ac0, 0x44c7c,
+               0x44cc0, 0x44e7c,
+               0x44ec0, 0x4507c,
+               0x450c0, 0x451fc,
+               0x45800, 0x45868,
+               0x45880, 0x45884,
+               0x458a0, 0x458b0,
+               0x45a00, 0x45a68,
+               0x45a80, 0x45a84,
+               0x45aa0, 0x45ab0,
+               0x460c0, 0x460e4,
+               0x47000, 0x4708c,
+               0x47200, 0x47250,
+               0x47400, 0x47420,
+               0x47600, 0x47618,
+               0x47800, 0x4782c,
+               0x50000, 0x500cc,
+               0x50400, 0x50400,
+               0x50800, 0x508cc,
+               0x50c00, 0x50c00,
+               0x51000, 0x510b0,
+               0x51300, 0x51324,
+       };
+
        u32 *buf_end = (u32 *)((char *)buf + buf_size);
        const unsigned int *reg_ranges;
        int reg_ranges_size, range;
@@ -1335,6 +1678,11 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
                reg_ranges_size = ARRAY_SIZE(t5_reg_ranges);
                break;
 
+       case CHELSIO_T6:
+               reg_ranges = t6_reg_ranges;
+               reg_ranges_size = ARRAY_SIZE(t6_reg_ranges);
+               break;
+
        default:
                dev_err(adap->pdev_dev,
                        "Unsupported chip version %d\n", chip_version);
@@ -1381,17 +1729,16 @@ int t4_seeprom_wp(struct adapter *adapter, bool enable)
 }
 
 /**
- *     get_vpd_params - read VPD parameters from VPD EEPROM
+ *     t4_get_raw_vpd_params - read VPD parameters from VPD EEPROM
  *     @adapter: adapter to read
  *     @p: where to store the parameters
  *
  *     Reads card parameters stored in VPD EEPROM.
  */
-int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
+int t4_get_raw_vpd_params(struct adapter *adapter, struct vpd_params *p)
 {
-       u32 cclk_param, cclk_val;
-       int i, ret, addr;
-       int ec, sn, pn;
+       int i, ret = 0, addr;
+       int ec, sn, pn, na;
        u8 *vpd, csum;
        unsigned int vpdr_len, kw_offset, id_len;
 
@@ -1399,6 +1746,9 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
        if (!vpd)
                return -ENOMEM;
 
+       /* Card information normally starts at VPD_BASE but early cards had
+        * it at 0.
+        */
        ret = pci_read_vpd(adapter->pdev, VPD_BASE, sizeof(u32), vpd);
        if (ret < 0)
                goto out;
@@ -1464,6 +1814,7 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
        FIND_VPD_KW(ec, "EC");
        FIND_VPD_KW(sn, "SN");
        FIND_VPD_KW(pn, "PN");
+       FIND_VPD_KW(na, "NA");
 #undef FIND_VPD_KW
 
        memcpy(p->id, vpd + PCI_VPD_LRDT_TAG_SIZE, id_len);
@@ -1476,18 +1827,42 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
        i = pci_vpd_info_field_size(vpd + pn - PCI_VPD_INFO_FLD_HDR_SIZE);
        memcpy(p->pn, vpd + pn, min(i, PN_LEN));
        strim(p->pn);
+       memcpy(p->na, vpd + na, min(i, MACADDR_LEN));
+       strim((char *)p->na);
 
-       /*
-        * Ask firmware for the Core Clock since it knows how to translate the
+out:
+       vfree(vpd);
+       return ret;
+}
+
+/**
+ *     t4_get_vpd_params - read VPD parameters & retrieve Core Clock
+ *     @adapter: adapter to read
+ *     @p: where to store the parameters
+ *
+ *     Reads card parameters stored in VPD EEPROM and retrieves the Core
+ *     Clock.  This can only be called after a connection to the firmware
+ *     is established.
+ */
+int t4_get_vpd_params(struct adapter *adapter, struct vpd_params *p)
+{
+       u32 cclk_param, cclk_val;
+       int ret;
+
+       /* Grab the raw VPD parameters.
+        */
+       ret = t4_get_raw_vpd_params(adapter, p);
+       if (ret)
+               return ret;
+
+       /* 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_V(FW_PARAMS_MNEM_DEV) |
                      FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CCLK));
-       ret = t4_query_params(adapter, adapter->mbox, 0, 0,
+       ret = t4_query_params(adapter, adapter->mbox, adapter->pf, 0,
                              1, &cclk_param, &cclk_val);
 
-out:
-       vfree(vpd);
        if (ret)
                return ret;
        p->cclk = cclk_val;
@@ -1948,7 +2323,8 @@ static bool t4_fw_matches_chip(const struct adapter *adap,
         * which will keep us "honest" in the future ...
         */
        if ((is_t4(adap->params.chip) && hdr->chip == FW_HDR_CHIP_T4) ||
-           (is_t5(adap->params.chip) && hdr->chip == FW_HDR_CHIP_T5))
+           (is_t5(adap->params.chip) && hdr->chip == FW_HDR_CHIP_T5) ||
+           (is_t6(adap->params.chip) && hdr->chip == FW_HDR_CHIP_T6))
                return true;
 
        dev_err(adap->pdev_dev,
@@ -2062,7 +2438,7 @@ int t4_phy_fw_ver(struct adapter *adap, int *phy_fw_ver)
                 FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PHYFW) |
                 FW_PARAMS_PARAM_Y_V(adap->params.portvec) |
                 FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_PHYFW_VERSION));
-       ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 1,
+       ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1,
                              &param, &val);
        if (ret < 0)
                return ret;
@@ -2134,7 +2510,7 @@ int t4_load_phy_fw(struct adapter *adap,
                 FW_PARAMS_PARAM_Y_V(adap->params.portvec) |
                 FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_PHYFW_DOWNLOAD));
        val = phy_fw_size;
-       ret = t4_query_params_rw(adap, adap->mbox, adap->fn, 0, 1,
+       ret = t4_query_params_rw(adap, adap->mbox, adap->pf, 0, 1,
                                 &param, &val, 1);
        if (ret < 0)
                return ret;
@@ -2163,7 +2539,7 @@ int t4_load_phy_fw(struct adapter *adap,
                 FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PHYFW) |
                 FW_PARAMS_PARAM_Y_V(adap->params.portvec) |
                 FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_PHYFW_DOWNLOAD));
-       ret = t4_set_params_timeout(adap, adap->mbox, adap->fn, 0, 1,
+       ret = t4_set_params_timeout(adap, adap->mbox, adap->pf, 0, 1,
                                    &param, &val, 30000);
 
        /* If we have version number support, then check to see that the new
@@ -2199,7 +2575,7 @@ int t4_fwcache(struct adapter *adap, enum fw_params_param_dev_fwcache op)
        c.op_to_vfn =
                cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) |
                            FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
-                           FW_PARAMS_CMD_PFN_V(adap->fn) |
+                           FW_PARAMS_CMD_PFN_V(adap->pf) |
                            FW_PARAMS_CMD_VFN_V(0));
        c.retval_len16 = cpu_to_be32(FW_LEN16(c));
        c.param[0].mnem =
@@ -2230,7 +2606,7 @@ void t4_ulprx_read_la(struct adapter *adap, u32 *la_buf)
                     FW_PORT_CAP_ANEG)
 
 /**
- *     t4_link_start - apply link configuration to MAC/PHY
+ *     t4_link_l1cfg - apply link configuration to MAC/PHY
  *     @phy: the PHY to setup
  *     @mac: the MAC to setup
  *     @lc: the requested link configuration
@@ -2242,7 +2618,7 @@ void t4_ulprx_read_la(struct adapter *adap, u32 *la_buf)
  *     - If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
  *       otherwise do it later based on the outcome of auto-negotiation.
  */
-int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port,
+int t4_link_l1cfg(struct adapter *adap, unsigned int mbox, unsigned int port,
                  struct link_config *lc)
 {
        struct fw_port_cmd c;
@@ -2488,6 +2864,7 @@ static void tp_intr_handler(struct adapter *adapter)
 static void sge_intr_handler(struct adapter *adapter)
 {
        u64 v;
+       u32 err;
 
        static const struct intr_info sge_intr_info[] = {
                { ERR_CPL_EXCEED_IQE_SIZE_F,
@@ -2496,8 +2873,6 @@ static void sge_intr_handler(struct adapter *adapter)
                  "SGE GTS CIDX increment too large", -1, 0 },
                { ERR_CPL_OPCODE_0_F, "SGE received 0-length CPL", -1, 0 },
                { DBFIFO_LP_INT_F, NULL, -1, 0, t4_db_full },
-               { DBFIFO_HP_INT_F, NULL, -1, 0, t4_db_full },
-               { ERR_DROPPED_DB_F, NULL, -1, 0, t4_db_dropped },
                { ERR_DATA_CPL_ON_HIGH_QID1_F | ERR_DATA_CPL_ON_HIGH_QID0_F,
                  "SGE IQID > 1023 received CPL for FL", -1, 0 },
                { ERR_BAD_DB_PIDX3_F, "SGE DBP 3 pidx increment too large", -1,
@@ -2510,13 +2885,19 @@ static void sge_intr_handler(struct adapter *adapter)
                  0 },
                { ERR_ING_CTXT_PRIO_F,
                  "SGE too many priority ingress contexts", -1, 0 },
-               { ERR_EGR_CTXT_PRIO_F,
-                 "SGE too many priority egress contexts", -1, 0 },
                { INGRESS_SIZE_ERR_F, "SGE illegal ingress QID", -1, 0 },
                { EGRESS_SIZE_ERR_F, "SGE illegal egress QID", -1, 0 },
                { 0 }
        };
 
+       static struct intr_info t4t5_sge_intr_info[] = {
+               { ERR_DROPPED_DB_F, NULL, -1, 0, t4_db_dropped },
+               { DBFIFO_HP_INT_F, NULL, -1, 0, t4_db_full },
+               { ERR_EGR_CTXT_PRIO_F,
+                 "SGE too many priority egress contexts", -1, 0 },
+               { 0 }
+       };
+
        v = (u64)t4_read_reg(adapter, SGE_INT_CAUSE1_A) |
                ((u64)t4_read_reg(adapter, SGE_INT_CAUSE2_A) << 32);
        if (v) {
@@ -2526,8 +2907,23 @@ static void sge_intr_handler(struct adapter *adapter)
                t4_write_reg(adapter, SGE_INT_CAUSE2_A, v >> 32);
        }
 
-       if (t4_handle_intr_status(adapter, SGE_INT_CAUSE3_A, sge_intr_info) ||
-           v != 0)
+       v |= t4_handle_intr_status(adapter, SGE_INT_CAUSE3_A, sge_intr_info);
+       if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5)
+               v |= t4_handle_intr_status(adapter, SGE_INT_CAUSE3_A,
+                                          t4t5_sge_intr_info);
+
+       err = t4_read_reg(adapter, SGE_ERROR_STATS_A);
+       if (err & ERROR_QID_VALID_F) {
+               dev_err(adapter->pdev_dev, "SGE error for queue %u\n",
+                       ERROR_QID_G(err));
+               if (err & UNCAPTURED_ERROR_F)
+                       dev_err(adapter->pdev_dev,
+                               "SGE UNCAPTURED_ERROR set (clearing)\n");
+               t4_write_reg(adapter, SGE_ERROR_STATS_A, ERROR_QID_VALID_F |
+                            UNCAPTURED_ERROR_F);
+       }
+
+       if (v != 0)
                t4_fatal_err(adapter);
 }
 
@@ -2700,6 +3096,7 @@ static void cplsw_intr_handler(struct adapter *adapter)
  */
 static void le_intr_handler(struct adapter *adap)
 {
+       enum chip_type chip = CHELSIO_CHIP_VERSION(adap->params.chip);
        static const struct intr_info le_intr_info[] = {
                { LIPMISS_F, "LE LIP miss", -1, 0 },
                { LIP0_F, "LE 0 LIP error", -1, 0 },
@@ -2709,7 +3106,18 @@ static void le_intr_handler(struct adapter *adap)
                { 0 }
        };
 
-       if (t4_handle_intr_status(adap, LE_DB_INT_CAUSE_A, le_intr_info))
+       static struct intr_info t6_le_intr_info[] = {
+               { T6_LIPMISS_F, "LE LIP miss", -1, 0 },
+               { T6_LIP0_F, "LE 0 LIP error", -1, 0 },
+               { TCAMINTPERR_F, "LE parity error", -1, 1 },
+               { T6_UNKNOWNCMD_F, "LE unknown command", -1, 1 },
+               { SSRAMINTPERR_F, "LE request queue parity error", -1, 1 },
+               { 0 }
+       };
+
+       if (t4_handle_intr_status(adap, LE_DB_INT_CAUSE_A,
+                                 (chip <= CHELSIO_T5) ?
+                                 le_intr_info : t6_le_intr_info))
                t4_fatal_err(adap);
 }
 
@@ -2978,7 +3386,7 @@ int t4_slow_intr_handler(struct adapter *adapter)
                pcie_intr_handler(adapter);
        if (cause & MC_F)
                mem_intr_handler(adapter, MEM_MC);
-       if (!is_t4(adapter->params.chip) && (cause & MC1_S))
+       if (is_t5(adapter->params.chip) && (cause & MC1_F))
                mem_intr_handler(adapter, MEM_MC1);
        if (cause & EDC0_F)
                mem_intr_handler(adapter, MEM_EDC0);
@@ -3024,17 +3432,18 @@ int t4_slow_intr_handler(struct adapter *adapter)
  */
 void t4_intr_enable(struct adapter *adapter)
 {
+       u32 val = 0;
        u32 pf = SOURCEPF_G(t4_read_reg(adapter, PL_WHOAMI_A));
 
+       if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5)
+               val = ERR_DROPPED_DB_F | ERR_EGR_CTXT_PRIO_F | DBFIFO_HP_INT_F;
        t4_write_reg(adapter, SGE_INT_ENABLE3_A, ERR_CPL_EXCEED_IQE_SIZE_F |
                     ERR_INVALID_CIDX_INC_F | ERR_CPL_OPCODE_0_F |
-                    ERR_DROPPED_DB_F | ERR_DATA_CPL_ON_HIGH_QID1_F |
+                    ERR_DATA_CPL_ON_HIGH_QID1_F | INGRESS_SIZE_ERR_F |
                     ERR_DATA_CPL_ON_HIGH_QID0_F | ERR_BAD_DB_PIDX3_F |
                     ERR_BAD_DB_PIDX2_F | ERR_BAD_DB_PIDX1_F |
                     ERR_BAD_DB_PIDX0_F | ERR_ING_CTXT_PRIO_F |
-                    ERR_EGR_CTXT_PRIO_F | INGRESS_SIZE_ERR_F |
-                    DBFIFO_HP_INT_F | DBFIFO_LP_INT_F |
-                    EGRESS_SIZE_ERR_F);
+                    DBFIFO_LP_INT_F | EGRESS_SIZE_ERR_F | val);
        t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE_A), PF_INTR_MASK);
        t4_set_reg_field(adapter, PL_INT_MAP0_A, 0, 1 << pf);
 }
@@ -3248,11 +3657,29 @@ void t4_read_rss_key(struct adapter *adap, u32 *key)
  */
 void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx)
 {
+       u8 rss_key_addr_cnt = 16;
+       u32 vrt = t4_read_reg(adap, TP_RSS_CONFIG_VRT_A);
+
+       /* T6 and later: for KeyMode 3 (per-vf and per-vf scramble),
+        * allows access to key addresses 16-63 by using KeyWrAddrX
+        * as index[5:4](upper 2) into key table
+        */
+       if ((CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) &&
+           (vrt & KEYEXTEND_F) && (KEYMODE_G(vrt) == 3))
+               rss_key_addr_cnt = 32;
+
        t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, key, 10,
                          TP_RSS_SECRET_KEY0_A);
-       if (idx >= 0 && idx < 16)
-               t4_write_reg(adap, TP_RSS_CONFIG_VRT_A,
-                            KEYWRADDR_V(idx) | KEYWREN_F);
+
+       if (idx >= 0 && idx < rss_key_addr_cnt) {
+               if (rss_key_addr_cnt > 16)
+                       t4_write_reg(adap, TP_RSS_CONFIG_VRT_A,
+                                    KEYWRADDRX_V(idx >> 4) |
+                                    T6_VFWRADDR_V(idx) | KEYWREN_F);
+               else
+                       t4_write_reg(adap, TP_RSS_CONFIG_VRT_A,
+                                    KEYWRADDR_V(idx) | KEYWREN_F);
+       }
 }
 
 /**
@@ -3286,8 +3713,13 @@ void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index,
 {
        u32 vrt, mask, data;
 
-       mask = VFWRADDR_V(VFWRADDR_M);
-       data = VFWRADDR_V(index);
+       if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5) {
+               mask = VFWRADDR_V(VFWRADDR_M);
+               data = VFWRADDR_V(index);
+       } else {
+                mask =  T6_VFWRADDR_V(T6_VFWRADDR_M);
+                data = T6_VFWRADDR_V(index);
+       }
 
        /* Request that the index'th VF Table values be read into VFL/VFH.
         */
@@ -3355,24 +3787,148 @@ void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
        if (v4) {
                t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, val,
                                 ARRAY_SIZE(val), TP_MIB_TCP_OUT_RST_A);
-               v4->tcpOutRsts = STAT(OUT_RST);
-               v4->tcpInSegs  = STAT64(IN_SEG);
-               v4->tcpOutSegs = STAT64(OUT_SEG);
-               v4->tcpRetransSegs = STAT64(RXT_SEG);
+               v4->tcp_out_rsts = STAT(OUT_RST);
+               v4->tcp_in_segs  = STAT64(IN_SEG);
+               v4->tcp_out_segs = STAT64(OUT_SEG);
+               v4->tcp_retrans_segs = STAT64(RXT_SEG);
        }
        if (v6) {
                t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, val,
                                 ARRAY_SIZE(val), TP_MIB_TCP_V6OUT_RST_A);
-               v6->tcpOutRsts = STAT(OUT_RST);
-               v6->tcpInSegs  = STAT64(IN_SEG);
-               v6->tcpOutSegs = STAT64(OUT_SEG);
-               v6->tcpRetransSegs = STAT64(RXT_SEG);
+               v6->tcp_out_rsts = STAT(OUT_RST);
+               v6->tcp_in_segs  = STAT64(IN_SEG);
+               v6->tcp_out_segs = STAT64(OUT_SEG);
+               v6->tcp_retrans_segs = STAT64(RXT_SEG);
        }
 #undef STAT64
 #undef STAT
 #undef STAT_IDX
 }
 
+/**
+ *     t4_tp_get_err_stats - read TP's error MIB counters
+ *     @adap: the adapter
+ *     @st: holds the counter values
+ *
+ *     Returns the values of TP's error counters.
+ */
+void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st)
+{
+       /* T6 and later has 2 channels */
+       if (adap->params.arch.nchan == NCHAN) {
+               t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+                                st->mac_in_errs, 12, TP_MIB_MAC_IN_ERR_0_A);
+               t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+                                st->tnl_cong_drops, 8,
+                                TP_MIB_TNL_CNG_DROP_0_A);
+               t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+                                st->tnl_tx_drops, 4,
+                                TP_MIB_TNL_DROP_0_A);
+               t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+                                st->ofld_vlan_drops, 4,
+                                TP_MIB_OFD_VLN_DROP_0_A);
+               t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+                                st->tcp6_in_errs, 4,
+                                TP_MIB_TCP_V6IN_ERR_0_A);
+       } else {
+               t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+                                st->mac_in_errs, 2, TP_MIB_MAC_IN_ERR_0_A);
+               t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+                                st->hdr_in_errs, 2, TP_MIB_HDR_IN_ERR_0_A);
+               t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+                                st->tcp_in_errs, 2, TP_MIB_TCP_IN_ERR_0_A);
+               t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+                                st->tnl_cong_drops, 2,
+                                TP_MIB_TNL_CNG_DROP_0_A);
+               t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+                                st->ofld_chan_drops, 2,
+                                TP_MIB_OFD_CHN_DROP_0_A);
+               t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+                                st->tnl_tx_drops, 2, TP_MIB_TNL_DROP_0_A);
+               t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+                                st->ofld_vlan_drops, 2,
+                                TP_MIB_OFD_VLN_DROP_0_A);
+               t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+                                st->tcp6_in_errs, 2, TP_MIB_TCP_V6IN_ERR_0_A);
+       }
+       t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A,
+                        &st->ofld_no_neigh, 2, TP_MIB_OFD_ARP_DROP_A);
+}
+
+/**
+ *     t4_tp_get_cpl_stats - read TP's CPL MIB counters
+ *     @adap: the adapter
+ *     @st: holds the counter values
+ *
+ *     Returns the values of TP's CPL counters.
+ */
+void t4_tp_get_cpl_stats(struct adapter *adap, struct tp_cpl_stats *st)
+{
+       /* T6 and later has 2 channels */
+       if (adap->params.arch.nchan == NCHAN) {
+               t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->req,
+                                8, TP_MIB_CPL_IN_REQ_0_A);
+       } else {
+               t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->req,
+                                2, TP_MIB_CPL_IN_REQ_0_A);
+               t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->rsp,
+                                2, TP_MIB_CPL_OUT_RSP_0_A);
+       }
+}
+
+/**
+ *     t4_tp_get_rdma_stats - read TP's RDMA MIB counters
+ *     @adap: the adapter
+ *     @st: holds the counter values
+ *
+ *     Returns the values of TP's RDMA counters.
+ */
+void t4_tp_get_rdma_stats(struct adapter *adap, struct tp_rdma_stats *st)
+{
+       t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, &st->rqe_dfr_pkt,
+                        2, TP_MIB_RQE_DFR_PKT_A);
+}
+
+/**
+ *     t4_get_fcoe_stats - read TP's FCoE MIB counters for a port
+ *     @adap: the adapter
+ *     @idx: the port index
+ *     @st: holds the counter values
+ *
+ *     Returns the values of TP's FCoE counters for the selected port.
+ */
+void t4_get_fcoe_stats(struct adapter *adap, unsigned int idx,
+                      struct tp_fcoe_stats *st)
+{
+       u32 val[2];
+
+       t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, &st->frames_ddp,
+                        1, TP_MIB_FCOE_DDP_0_A + idx);
+       t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, &st->frames_drop,
+                        1, TP_MIB_FCOE_DROP_0_A + idx);
+       t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, val,
+                        2, TP_MIB_FCOE_BYTE_0_HI_A + 2 * idx);
+       st->octets_ddp = ((u64)val[0] << 32) | val[1];
+}
+
+/**
+ *     t4_get_usm_stats - read TP's non-TCP DDP MIB counters
+ *     @adap: the adapter
+ *     @st: holds the counter values
+ *
+ *     Returns the values of TP's counters for non-TCP directly-placed packets.
+ */
+void t4_get_usm_stats(struct adapter *adap, struct tp_usm_stats *st)
+{
+       u32 val[4];
+
+       t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, val, 4,
+                        TP_MIB_USM_PKTS_A);
+       st->frames = val[0];
+       st->drops = val[1];
+       st->octets = ((u64)val[2] << 32) | val[3];
+}
+
 /**
  *     t4_read_mtu_tbl - returns the values in the HW path MTU table
  *     @adap: the adapter
@@ -3629,6 +4185,28 @@ const char *t4_get_port_type_description(enum fw_port_type port_type)
        return "UNKNOWN";
 }
 
+/**
+ *      t4_get_port_stats_offset - collect port stats relative to a previous
+ *                                 snapshot
+ *      @adap: The adapter
+ *      @idx: The port
+ *      @stats: Current stats to fill
+ *      @offset: Previous stats snapshot
+ */
+void t4_get_port_stats_offset(struct adapter *adap, int idx,
+                             struct port_stats *stats,
+                             struct port_stats *offset)
+{
+       u64 *s, *o;
+       int i;
+
+       t4_get_port_stats(adap, idx, stats);
+       for (i = 0, s = (u64 *)stats, o = (u64 *)offset;
+                       i < (sizeof(struct port_stats) / sizeof(u64));
+                       i++, s++, o++)
+               *s -= *o;
+}
+
 /**
  *     t4_get_port_stats - collect port statistics
  *     @adap: the adapter
@@ -3713,103 +4291,51 @@ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
 }
 
 /**
- *     t4_wol_magic_enable - enable/disable magic packet WoL
+ *     t4_get_lb_stats - collect loopback port statistics
  *     @adap: the adapter
- *     @port: the physical port index
- *     @addr: MAC address expected in magic packets, %NULL to disable
- *
- *     Enables/disables magic packet wake-on-LAN for the selected port.
- */
-void t4_wol_magic_enable(struct adapter *adap, unsigned int port,
-                        const u8 *addr)
-{
-       u32 mag_id_reg_l, mag_id_reg_h, port_cfg_reg;
-
-       if (is_t4(adap->params.chip)) {
-               mag_id_reg_l = PORT_REG(port, XGMAC_PORT_MAGIC_MACID_LO);
-               mag_id_reg_h = PORT_REG(port, XGMAC_PORT_MAGIC_MACID_HI);
-               port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2_A);
-       } else {
-               mag_id_reg_l = T5_PORT_REG(port, MAC_PORT_MAGIC_MACID_LO);
-               mag_id_reg_h = T5_PORT_REG(port, MAC_PORT_MAGIC_MACID_HI);
-               port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2_A);
-       }
-
-       if (addr) {
-               t4_write_reg(adap, mag_id_reg_l,
-                            (addr[2] << 24) | (addr[3] << 16) |
-                            (addr[4] << 8) | addr[5]);
-               t4_write_reg(adap, mag_id_reg_h,
-                            (addr[0] << 8) | addr[1]);
-       }
-       t4_set_reg_field(adap, port_cfg_reg, MAGICEN_F,
-                        addr ? MAGICEN_F : 0);
-}
-
-/**
- *     t4_wol_pat_enable - enable/disable pattern-based WoL
- *     @adap: the adapter
- *     @port: the physical port index
- *     @map: bitmap of which HW pattern filters to set
- *     @mask0: byte mask for bytes 0-63 of a packet
- *     @mask1: byte mask for bytes 64-127 of a packet
- *     @crc: Ethernet CRC for selected bytes
- *     @enable: enable/disable switch
+ *     @idx: the loopback port index
+ *     @p: the stats structure to fill
  *
- *     Sets the pattern filters indicated in @map to mask out the bytes
- *     specified in @mask0/@mask1 in received packets and compare the CRC of
- *     the resulting packet against @crc.  If @enable is %true pattern-based
- *     WoL is enabled, otherwise disabled.
+ *     Return HW statistics for the given loopback port.
  */
-int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
-                     u64 mask0, u64 mask1, unsigned int crc, bool enable)
+void t4_get_lb_stats(struct adapter *adap, int idx, struct lb_port_stats *p)
 {
-       int i;
-       u32 port_cfg_reg;
-
-       if (is_t4(adap->params.chip))
-               port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2_A);
-       else
-               port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2_A);
-
-       if (!enable) {
-               t4_set_reg_field(adap, port_cfg_reg, PATEN_F, 0);
-               return 0;
-       }
-       if (map > 0xff)
-               return -EINVAL;
+       u32 bgmap = t4_get_mps_bg_map(adap, idx);
 
-#define EPIO_REG(name) \
+#define GET_STAT(name) \
+       t4_read_reg64(adap, \
        (is_t4(adap->params.chip) ? \
-        PORT_REG(port, XGMAC_PORT_EPIO_##name##_A) : \
-        T5_PORT_REG(port, MAC_PORT_EPIO_##name##_A))
+       PORT_REG(idx, MPS_PORT_STAT_LB_PORT_##name##_L) : \
+       T5_PORT_REG(idx, MPS_PORT_STAT_LB_PORT_##name##_L)))
+#define GET_STAT_COM(name) t4_read_reg64(adap, MPS_STAT_##name##_L)
 
-       t4_write_reg(adap, EPIO_REG(DATA1), mask0 >> 32);
-       t4_write_reg(adap, EPIO_REG(DATA2), mask1);
-       t4_write_reg(adap, EPIO_REG(DATA3), mask1 >> 32);
+       p->octets           = GET_STAT(BYTES);
+       p->frames           = GET_STAT(FRAMES);
+       p->bcast_frames     = GET_STAT(BCAST);
+       p->mcast_frames     = GET_STAT(MCAST);
+       p->ucast_frames     = GET_STAT(UCAST);
+       p->error_frames     = GET_STAT(ERROR);
+
+       p->frames_64        = GET_STAT(64B);
+       p->frames_65_127    = GET_STAT(65B_127B);
+       p->frames_128_255   = GET_STAT(128B_255B);
+       p->frames_256_511   = GET_STAT(256B_511B);
+       p->frames_512_1023  = GET_STAT(512B_1023B);
+       p->frames_1024_1518 = GET_STAT(1024B_1518B);
+       p->frames_1519_max  = GET_STAT(1519B_MAX);
+       p->drop             = GET_STAT(DROP_FRAMES);
+
+       p->ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_DROP_FRAME) : 0;
+       p->ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_DROP_FRAME) : 0;
+       p->ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_LB_DROP_FRAME) : 0;
+       p->ovflow3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_LB_DROP_FRAME) : 0;
+       p->trunc0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_TRUNC_FRAME) : 0;
+       p->trunc1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_TRUNC_FRAME) : 0;
+       p->trunc2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_LB_TRUNC_FRAME) : 0;
+       p->trunc3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_LB_TRUNC_FRAME) : 0;
 
-       for (i = 0; i < NWOL_PAT; i++, map >>= 1) {
-               if (!(map & 1))
-                       continue;
-
-               /* write byte masks */
-               t4_write_reg(adap, EPIO_REG(DATA0), mask0);
-               t4_write_reg(adap, EPIO_REG(OP), ADDRESS_V(i) | EPIOWR_F);
-               t4_read_reg(adap, EPIO_REG(OP));                /* flush */
-               if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY_F)
-                       return -ETIMEDOUT;
-
-               /* write CRC */
-               t4_write_reg(adap, EPIO_REG(DATA0), crc);
-               t4_write_reg(adap, EPIO_REG(OP), ADDRESS_V(i + 32) | EPIOWR_F);
-               t4_read_reg(adap, EPIO_REG(OP));                /* flush */
-               if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY_F)
-                       return -ETIMEDOUT;
-       }
-#undef EPIO_REG
-
-       t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2_A), 0, PATEN_F);
-       return 0;
+#undef GET_STAT
+#undef GET_STAT_COM
 }
 
 /*     t4_mk_filtdelwr - create a delete filter WR
@@ -4030,6 +4556,32 @@ void t4_sge_decode_idma_state(struct adapter *adapter, int state)
                        sge_regs[i], t4_read_reg(adapter, sge_regs[i]));
 }
 
+/**
+ *      t4_sge_ctxt_flush - flush the SGE context cache
+ *      @adap: the adapter
+ *      @mbox: mailbox to use for the FW command
+ *
+ *      Issues a FW command through the given mailbox to flush the
+ *      SGE context cache.
+ */
+int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox)
+{
+       int ret;
+       u32 ldst_addrspace;
+       struct fw_ldst_cmd c;
+
+       memset(&c, 0, sizeof(c));
+       ldst_addrspace = FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_SGE_EGRC);
+       c.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) |
+                                       FW_CMD_REQUEST_F | FW_CMD_READ_F |
+                                       ldst_addrspace);
+       c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c));
+       c.u.idctxt.msg_ctxtflush = cpu_to_be32(FW_LDST_CMD_CTXTFLUSH_F);
+
+       ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
+       return ret;
+}
+
 /**
  *      t4_fw_hello - establish communication with FW
  *      @adap: the adapter
@@ -4726,6 +5278,33 @@ int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port,
        return FW_VI_CMD_VIID_G(be16_to_cpu(c.type_viid));
 }
 
+/**
+ *     t4_free_vi - free a virtual interface
+ *     @adap: the adapter
+ *     @mbox: mailbox to use for the FW command
+ *     @pf: the PF owning the VI
+ *     @vf: the VF owning the VI
+ *     @viid: virtual interface identifiler
+ *
+ *     Free a previously allocated virtual interface.
+ */
+int t4_free_vi(struct adapter *adap, unsigned int mbox, unsigned int pf,
+              unsigned int vf, unsigned int viid)
+{
+       struct fw_vi_cmd c;
+
+       memset(&c, 0, sizeof(c));
+       c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_VI_CMD) |
+                                 FW_CMD_REQUEST_F |
+                                 FW_CMD_EXEC_F |
+                                 FW_VI_CMD_PFN_V(pf) |
+                                 FW_VI_CMD_VFN_V(vf));
+       c.alloc_to_len16 = cpu_to_be32(FW_VI_CMD_FREE_F | FW_LEN16(c));
+       c.type_viid = cpu_to_be16(FW_VI_CMD_VIID_V(viid));
+
+       return t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
+}
+
 /**
  *     t4_set_rxmode - set Rx properties of a virtual interface
  *     @adap: the adapter
@@ -4798,45 +5377,71 @@ int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox,
                      unsigned int viid, bool free, unsigned int naddr,
                      const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok)
 {
-       int i, ret;
+       int offset, ret = 0;
        struct fw_vi_mac_cmd c;
-       struct fw_vi_mac_exact *p;
-       unsigned int max_naddr = is_t4(adap->params.chip) ?
-                                      NUM_MPS_CLS_SRAM_L_INSTANCES :
-                                      NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
+       unsigned int nfilters = 0;
+       unsigned int max_naddr = adap->params.arch.mps_tcam_size;
+       unsigned int rem = naddr;
 
-       if (naddr > 7)
+       if (naddr > max_naddr)
                return -EINVAL;
 
-       memset(&c, 0, sizeof(c));
-       c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) |
-                                  FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
-                                  (free ? FW_CMD_EXEC_F : 0) |
-                                  FW_VI_MAC_CMD_VIID_V(viid));
-       c.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_FREEMACS_V(free) |
-                                         FW_CMD_LEN16_V((naddr + 2) / 2));
-
-       for (i = 0, p = c.u.exact; i < naddr; i++, p++) {
-               p->valid_to_idx =
-                       cpu_to_be16(FW_VI_MAC_CMD_VALID_F |
-                                   FW_VI_MAC_CMD_IDX_V(FW_VI_MAC_ADD_MAC));
-               memcpy(p->macaddr, addr[i], sizeof(p->macaddr));
-       }
+       for (offset = 0; offset < naddr ; /**/) {
+               unsigned int fw_naddr = (rem < ARRAY_SIZE(c.u.exact) ?
+                                        rem : ARRAY_SIZE(c.u.exact));
+               size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
+                                                    u.exact[fw_naddr]), 16);
+               struct fw_vi_mac_exact *p;
+               int i;
 
-       ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok);
-       if (ret)
-               return ret;
+               memset(&c, 0, sizeof(c));
+               c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) |
+                                          FW_CMD_REQUEST_F |
+                                          FW_CMD_WRITE_F |
+                                          FW_CMD_EXEC_V(free) |
+                                          FW_VI_MAC_CMD_VIID_V(viid));
+               c.freemacs_to_len16 =
+                       cpu_to_be32(FW_VI_MAC_CMD_FREEMACS_V(free) |
+                                   FW_CMD_LEN16_V(len16));
+
+               for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) {
+                       p->valid_to_idx =
+                               cpu_to_be16(FW_VI_MAC_CMD_VALID_F |
+                                           FW_VI_MAC_CMD_IDX_V(
+                                                   FW_VI_MAC_ADD_MAC));
+                       memcpy(p->macaddr, addr[offset + i],
+                              sizeof(p->macaddr));
+               }
+
+               /* It's okay if we run out of space in our MAC address arena.
+                * Some of the addresses we submit may get stored so we need
+                * to run through the reply to see what the results were ...
+                */
+               ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok);
+               if (ret && ret != -FW_ENOMEM)
+                       break;
 
-       for (i = 0, p = c.u.exact; i < naddr; i++, p++) {
-               u16 index = FW_VI_MAC_CMD_IDX_G(be16_to_cpu(p->valid_to_idx));
+               for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) {
+                       u16 index = FW_VI_MAC_CMD_IDX_G(
+                                       be16_to_cpu(p->valid_to_idx));
+
+                       if (idx)
+                               idx[offset + i] = (index >= max_naddr ?
+                                                  0xffff : index);
+                       if (index < max_naddr)
+                               nfilters++;
+                       else if (hash)
+                               *hash |= (1ULL <<
+                                         hash_mac_addr(addr[offset + i]));
+               }
 
-               if (idx)
-                       idx[i] = index >= max_naddr ? 0xffff : index;
-               if (index < max_naddr)
-                       ret++;
-               else if (hash)
-                       *hash |= (1ULL << hash_mac_addr(addr[i]));
+               free = false;
+               offset += fw_naddr;
+               rem -= fw_naddr;
        }
+
+       if (ret == 0 || ret == -FW_ENOMEM)
+               ret = nfilters;
        return ret;
 }
 
@@ -4865,9 +5470,7 @@ int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid,
        int ret, mode;
        struct fw_vi_mac_cmd c;
        struct fw_vi_mac_exact *p = c.u.exact;
-       unsigned int max_mac_addr = is_t4(adap->params.chip) ?
-                                   NUM_MPS_CLS_SRAM_L_INSTANCES :
-                                   NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
+       unsigned int max_mac_addr = adap->params.arch.mps_tcam_size;
 
        if (idx < 0)                             /* new allocation */
                idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC;
@@ -5244,6 +5847,22 @@ static int get_flash_params(struct adapter *adap)
        return 0;
 }
 
+static void set_pcie_completion_timeout(struct adapter *adapter, u8 range)
+{
+       u16 val;
+       u32 pcie_cap;
+
+       pcie_cap = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+       if (pcie_cap) {
+               pci_read_config_word(adapter->pdev,
+                                    pcie_cap + PCI_EXP_DEVCTL2, &val);
+               val &= ~PCI_EXP_DEVCTL2_COMP_TIMEOUT;
+               val |= range;
+               pci_write_config_word(adapter->pdev,
+                                     pcie_cap + PCI_EXP_DEVCTL2, val);
+       }
+}
+
 /**
  *     t4_prep_adapter - prepare SW and HW for operation
  *     @adapter: the adapter
@@ -5276,9 +5895,30 @@ int t4_prep_adapter(struct adapter *adapter)
        switch (ver) {
        case CHELSIO_T4:
                adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T4, pl_rev);
+               adapter->params.arch.sge_fl_db = DBPRIO_F;
+               adapter->params.arch.mps_tcam_size =
+                                NUM_MPS_CLS_SRAM_L_INSTANCES;
+               adapter->params.arch.mps_rplc_size = 128;
+               adapter->params.arch.nchan = NCHAN;
+               adapter->params.arch.vfcount = 128;
                break;
        case CHELSIO_T5:
                adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T5, pl_rev);
+               adapter->params.arch.sge_fl_db = DBPRIO_F | DBTYPE_F;
+               adapter->params.arch.mps_tcam_size =
+                                NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
+               adapter->params.arch.mps_rplc_size = 128;
+               adapter->params.arch.nchan = NCHAN;
+               adapter->params.arch.vfcount = 128;
+               break;
+       case CHELSIO_T6:
+               adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T6, pl_rev);
+               adapter->params.arch.sge_fl_db = 0;
+               adapter->params.arch.mps_tcam_size =
+                                NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
+               adapter->params.arch.mps_rplc_size = 256;
+               adapter->params.arch.nchan = 2;
+               adapter->params.arch.vfcount = 256;
                break;
        default:
                dev_err(adapter->pdev_dev, "Device %d is not supported\n",
@@ -5295,11 +5935,14 @@ int t4_prep_adapter(struct adapter *adapter)
        adapter->params.nports = 1;
        adapter->params.portvec = 1;
        adapter->params.vpd.cclk = 50000;
+
+       /* Set pci completion timeout value to 4 seconds. */
+       set_pcie_completion_timeout(adapter, 0xd);
        return 0;
 }
 
 /**
- *     cxgb4_t4_bar2_sge_qregs - return BAR2 SGE Queue register information
+ *     t4_bar2_sge_qregs - return BAR2 SGE Queue register information
  *     @adapter: the adapter
  *     @qid: the Queue ID
  *     @qtype: the Ingress or Egress type for @qid
@@ -5323,7 +5966,7 @@ int t4_prep_adapter(struct adapter *adapter)
  *     Write Combining Doorbell Buffer. If the BAR2 Queue ID is not 0,
  *     then these "Inferred Queue ID" register may not be used.
  */
-int cxgb4_t4_bar2_sge_qregs(struct adapter *adapter,
+int t4_bar2_sge_qregs(struct adapter *adapter,
                      unsigned int qid,
                      enum t4_bar2_qtype qtype,
                      u64 *pbar2_qoffset,
@@ -5457,13 +6100,13 @@ int t4_init_sge_params(struct adapter *adapter)
         */
        hps = t4_read_reg(adapter, SGE_HOST_PAGE_SIZE_A);
        s_hps = (HOSTPAGESIZEPF0_S +
-                (HOSTPAGESIZEPF1_S - HOSTPAGESIZEPF0_S) * adapter->fn);
+                (HOSTPAGESIZEPF1_S - HOSTPAGESIZEPF0_S) * adapter->pf);
        sge_params->hps = ((hps >> s_hps) & HOSTPAGESIZEPF0_M);
 
        /* Extract the SGE Egress and Ingess Queues Per Page for our PF.
         */
        s_qpp = (QUEUESPERPAGEPF0_S +
-               (QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) * adapter->fn);
+               (QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) * adapter->pf);
        qpp = t4_read_reg(adapter, SGE_EGRESS_QUEUES_PER_PAGE_PF_A);
        sge_params->eq_qpp = ((qpp >> s_qpp) & QUEUESPERPAGEPF0_M);
        qpp = t4_read_reg(adapter, SGE_INGRESS_QUEUES_PER_PAGE_PF_A);