diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 1f4b9b30b9ed0..944f2cbc1795c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -66,6 +66,7 @@ enum { SERNUM_LEN = 24, /* Serial # length */ EC_LEN = 16, /* E/C length */ ID_LEN = 16, /* ID length */ + PN_LEN = 16, /* Part Number length */ }; enum { @@ -254,6 +255,7 @@ struct vpd_params { u8 ec[EC_LEN + 1]; u8 sn[SERNUM_LEN + 1]; u8 id[ID_LEN + 1]; + u8 pn[PN_LEN + 1]; }; struct pci_params { @@ -306,6 +308,7 @@ struct adapter_params { unsigned char bypass; unsigned int ofldq_wr_cred; + bool ulptx_memwrite_dsgl; /* use of T5 DSGL allowed */ }; #include "t4fw_api.h" @@ -957,7 +960,7 @@ int t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *parity); int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *parity); - +const char *t4_get_port_type_description(enum fw_port_type port_type); 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, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index bd0321d8b6123..4660f55e292bb 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -254,6 +254,8 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = { CH_DEVICE(0x5011, 4), CH_DEVICE(0x5012, 4), CH_DEVICE(0x5013, 4), + CH_DEVICE(0x5014, 4), + CH_DEVICE(0x5015, 4), CH_DEVICE(0x5401, 4), CH_DEVICE(0x5402, 4), CH_DEVICE(0x5403, 4), @@ -273,6 +275,8 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = { CH_DEVICE(0x5411, 4), CH_DEVICE(0x5412, 4), CH_DEVICE(0x5413, 4), + CH_DEVICE(0x5414, 4), + CH_DEVICE(0x5415, 4), { 0, } }; @@ -432,6 +436,9 @@ static void link_report(struct net_device *dev) case SPEED_100: s = "100Mbps"; break; + case 40000: /* Need a SPEED_40000 in ethtool.h */ + s = "40Gbps"; + break; } netdev_info(dev, "link up, %s, full-duplex, %s PAUSE\n", s, @@ -2061,7 +2068,7 @@ static void get_regs(struct net_device *dev, struct ethtool_regs *regs, 0x40200, 0x40298, 0x402ac, 0x4033c, 0x403f8, 0x403fc, - 0x41300, 0x413c4, + 0x41304, 0x413c4, 0x41400, 0x4141c, 0x41480, 0x414d0, 0x44000, 0x44078, @@ -2089,7 +2096,7 @@ static void get_regs(struct net_device *dev, struct ethtool_regs *regs, 0x48200, 0x48298, 0x482ac, 0x4833c, 0x483f8, 0x483fc, - 0x49300, 0x493c4, + 0x49304, 0x493c4, 0x49400, 0x4941c, 0x49480, 0x494d0, 0x4c000, 0x4c078, @@ -2199,6 +2206,8 @@ static unsigned int from_fw_linkcaps(unsigned int type, unsigned int caps) else if (type == FW_PORT_TYPE_FIBER_XFI || type == FW_PORT_TYPE_FIBER_XAUI || type == FW_PORT_TYPE_SFP) v |= SUPPORTED_FIBRE; + else if (type == FW_PORT_TYPE_BP40_BA) + v |= SUPPORTED_40000baseSR4_Full; if (caps & FW_PORT_CAP_ANEG) v |= SUPPORTED_Autoneg; @@ -2215,6 +2224,8 @@ static unsigned int to_fw_linkcaps(unsigned int caps) v |= FW_PORT_CAP_SPEED_1G; if (caps & ADVERTISED_10000baseT_Full) v |= FW_PORT_CAP_SPEED_10G; + if (caps & ADVERTISED_40000baseSR4_Full) + v |= FW_PORT_CAP_SPEED_40G; return v; } @@ -2269,6 +2280,8 @@ static unsigned int speed_to_caps(int speed) return FW_PORT_CAP_SPEED_1G; if (speed == SPEED_10000) return FW_PORT_CAP_SPEED_10G; + if (speed == 40000) /* Need SPEED_40000 in ethtool.h */ + return FW_PORT_CAP_SPEED_40G; return 0; } @@ -2296,8 +2309,10 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (cmd->autoneg == AUTONEG_DISABLE) { cap = speed_to_caps(speed); - if (!(lc->supported & cap) || (speed == SPEED_1000) || - (speed == SPEED_10000)) + if (!(lc->supported & cap) || + (speed == SPEED_1000) || + (speed == SPEED_10000) || + (speed == 40000)) return -EINVAL; lc->requested_speed = cap; lc->advertising = 0; @@ -3765,6 +3780,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld) lli.dbfifo_int_thresh = dbfifo_int_thresh; lli.sge_pktshift = adap->sge.pktshift; lli.enable_fw_ofld_conn = adap->flags & FW_OFLD_CONN; + lli.ulptx_memwrite_dsgl = adap->params.ulptx_memwrite_dsgl; handle = ulds[uld].add(&lli); if (IS_ERR(handle)) { @@ -5369,6 +5385,21 @@ static int adap_init0(struct adapter *adap) val[0] = 1; (void) t4_set_params(adap, adap->mbox, adap->fn, 0, 1, params, val); + /* + * Find out whether we're allowed to use the T5+ ULPTX MEMWRITE DSGL + * capability. Earlier versions of the firmware didn't have the + * ULPTX_MEMWRITE_DSGL so we'll interpret a query failure as no + * permission to use ULPTX MEMWRITE DSGL. + */ + if (is_t4(adap->params.chip)) { + adap->params.ulptx_memwrite_dsgl = false; + } else { + params[0] = FW_PARAM_DEV(ULPTX_MEMWRITE_DSGL); + ret = t4_query_params(adap, adap->mbox, adap->fn, 0, + 1, params, val); + adap->params.ulptx_memwrite_dsgl = (ret == 0 && val[0] != 0); + } + /* * Get device capabilities so we can determine what resources we need * to manage. @@ -5603,9 +5634,10 @@ static const struct pci_error_handlers cxgb4_eeh = { .resume = eeh_resume, }; -static inline bool is_10g_port(const struct link_config *lc) +static inline bool is_x_10g_port(const struct link_config *lc) { - return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0; + return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0 || + (lc->supported & FW_PORT_CAP_SPEED_40G) != 0; } static inline void init_rspq(struct sge_rspq *q, u8 timer_idx, u8 pkt_cnt_idx, @@ -5629,7 +5661,7 @@ static void cfg_queues(struct adapter *adap) int i, q10g = 0, n10g = 0, qidx = 0; for_each_port(adap, i) - n10g += is_10g_port(&adap2pinfo(adap, i)->link_cfg); + n10g += is_x_10g_port(&adap2pinfo(adap, i)->link_cfg); /* * We default to 1 queue per non-10G port and up to # of cores queues @@ -5644,7 +5676,7 @@ static void cfg_queues(struct adapter *adap) struct port_info *pi = adap2pinfo(adap, i); pi->first_qset = qidx; - pi->nqsets = is_10g_port(&pi->link_cfg) ? q10g : 1; + pi->nqsets = is_x_10g_port(&pi->link_cfg) ? q10g : 1; qidx += pi->nqsets; } @@ -5799,11 +5831,6 @@ static int init_rss(struct adapter *adap) static void print_port_info(const struct net_device *dev) { - static const char *base[] = { - "R XFI", "R XAUI", "T SGMII", "T XFI", "T XAUI", "KX4", "CX4", - "KX", "KR", "R SFP+", "KR/KX", "KR/KX/KX4" - }; - char buf[80]; char *bufp = buf; const char *spd = ""; @@ -5821,9 +5848,11 @@ static void print_port_info(const struct net_device *dev) bufp += sprintf(bufp, "1000/"); if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G) bufp += sprintf(bufp, "10G/"); + if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_40G) + bufp += sprintf(bufp, "40G/"); if (bufp != buf) --bufp; - sprintf(bufp, "BASE-%s", base[pi->port_type]); + sprintf(bufp, "BASE-%s", t4_get_port_type_description(pi->port_type)); netdev_info(dev, "Chelsio %s rev %d %s %sNIC PCIe x%d%s%s\n", adap->params.vpd.id, @@ -5831,8 +5860,8 @@ static void print_port_info(const struct net_device *dev) is_offload(adap) ? "R" : "", adap->params.pci.width, spd, (adap->flags & USING_MSIX) ? " MSI-X" : (adap->flags & USING_MSI) ? " MSI" : ""); - netdev_info(dev, "S/N: %s, E/C: %s\n", - adap->params.vpd.sn, adap->params.vpd.ec); + netdev_info(dev, "S/N: %s, P/N: %s\n", + adap->params.vpd.sn, adap->params.vpd.pn); } static void enable_pcie_relaxed_ordering(struct pci_dev *dev) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index 4dd0a82533e44..e274a047528fc 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -253,6 +253,7 @@ struct cxgb4_lld_info { /* packet data */ bool enable_fw_ofld_conn; /* Enable connection through fw */ /* WR */ + bool ulptx_memwrite_dsgl; /* use of T5 DSGL allowed */ }; struct cxgb4_uld_info { diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 47ffa64fcf19e..af76b25bb6064 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -706,11 +706,17 @@ static inline unsigned int flits_to_desc(unsigned int n) * @skb: the packet * * Returns whether an Ethernet packet is small enough to fit as - * immediate data. + * immediate data. Return value corresponds to headroom required. */ static inline int is_eth_imm(const struct sk_buff *skb) { - return skb->len <= MAX_IMM_TX_PKT_LEN - sizeof(struct cpl_tx_pkt); + int hdrlen = skb_shinfo(skb)->gso_size ? + sizeof(struct cpl_tx_pkt_lso_core) : 0; + + hdrlen += sizeof(struct cpl_tx_pkt); + if (skb->len <= MAX_IMM_TX_PKT_LEN - hdrlen) + return hdrlen; + return 0; } /** @@ -723,9 +729,10 @@ static inline int is_eth_imm(const struct sk_buff *skb) static inline unsigned int calc_tx_flits(const struct sk_buff *skb) { unsigned int flits; + int hdrlen = is_eth_imm(skb); - if (is_eth_imm(skb)) - return DIV_ROUND_UP(skb->len + sizeof(struct cpl_tx_pkt), 8); + if (hdrlen) + return DIV_ROUND_UP(skb->len + hdrlen, sizeof(__be64)); flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 4; if (skb_shinfo(skb)->gso_size) @@ -971,6 +978,7 @@ static inline void txq_advance(struct sge_txq *q, unsigned int n) */ netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev) { + int len; u32 wr_mid; u64 cntrl, *end; int qidx, credits; @@ -982,6 +990,7 @@ netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev) struct cpl_tx_pkt_core *cpl; const struct skb_shared_info *ssi; dma_addr_t addr[MAX_SKB_FRAGS + 1]; + bool immediate = false; /* * The chip min packet length is 10 octets but play safe and reject @@ -1011,7 +1020,10 @@ out_free: dev_kfree_skb(skb); return NETDEV_TX_BUSY; } - if (!is_eth_imm(skb) && + if (is_eth_imm(skb)) + immediate = true; + + if (!immediate && unlikely(map_skb(adap->pdev_dev, skb, addr) < 0)) { q->mapping_err++; goto out_free; @@ -1028,6 +1040,8 @@ out_free: dev_kfree_skb(skb); wr->r3 = cpu_to_be64(0); end = (u64 *)wr + flits; + len = immediate ? skb->len : 0; + len += sizeof(*cpl); ssi = skb_shinfo(skb); if (ssi->gso_size) { struct cpl_tx_pkt_lso *lso = (void *)wr; @@ -1035,8 +1049,9 @@ out_free: dev_kfree_skb(skb); int l3hdr_len = skb_network_header_len(skb); int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN; + len += sizeof(*lso); wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) | - FW_WR_IMMDLEN(sizeof(*lso))); + FW_WR_IMMDLEN(len)); lso->c.lso_ctrl = htonl(LSO_OPCODE(CPL_TX_PKT_LSO) | LSO_FIRST_SLICE | LSO_LAST_SLICE | LSO_IPV6(v6) | @@ -1054,9 +1069,6 @@ out_free: dev_kfree_skb(skb); q->tso++; q->tx_cso += ssi->gso_segs; } else { - int len; - - len = is_eth_imm(skb) ? skb->len + sizeof(*cpl) : sizeof(*cpl); wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) | FW_WR_IMMDLEN(len)); cpl = (void *)(wr + 1); @@ -1078,7 +1090,7 @@ out_free: dev_kfree_skb(skb); cpl->len = htons(skb->len); cpl->ctrl1 = cpu_to_be64(cntrl); - if (is_eth_imm(skb)) { + if (immediate) { inline_tx_skb(skb, &q->q, cpl + 1); dev_kfree_skb(skb); } else { @@ -1467,8 +1479,12 @@ static inline int ofld_send(struct adapter *adap, struct sk_buff *skb) { unsigned int idx = skb_txq(skb); - if (unlikely(is_ctrl_pkt(skb))) + if (unlikely(is_ctrl_pkt(skb))) { + /* Single ctrl queue is a requirement for LE workaround path */ + if (adap->tids.nsftids) + idx = 0; return ctrl_xmit(&adap->sge.ctrlq[idx], skb); + } return ofld_xmit(&adap->sge.ofldtxq[idx], skb); } diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 2c109343d5708..7ae756defc95f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -573,7 +573,7 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p) { u32 cclk_param, cclk_val; int i, ret, addr; - int ec, sn; + int ec, sn, pn; u8 *vpd, csum; unsigned int vpdr_len, kw_offset, id_len; @@ -638,6 +638,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"); #undef FIND_VPD_KW memcpy(p->id, vpd + PCI_VPD_LRDT_TAG_SIZE, id_len); @@ -647,6 +648,8 @@ 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); + memcpy(p->pn, vpd + pn, min(i, PN_LEN)); + strim(p->pn); /* * Ask firmware for the Core Clock since it knows how to translate the @@ -1155,7 +1158,8 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size) } #define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\ - FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_ANEG) + FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G | \ + FW_PORT_CAP_ANEG) /** * t4_link_start - apply link configuration to MAC/PHY @@ -2246,6 +2250,36 @@ static unsigned int get_mps_bg_map(struct adapter *adap, int idx) return 1 << idx; } +/** + * t4_get_port_type_description - return Port Type string description + * @port_type: firmware Port Type enumeration + */ +const char *t4_get_port_type_description(enum fw_port_type port_type) +{ + static const char *const port_type_description[] = { + "R XFI", + "R XAUI", + "T SGMII", + "T XFI", + "T XAUI", + "KX4", + "CX4", + "KX", + "KR", + "R SFP+", + "KR/KX", + "KR/KX/KX4", + "R QSFP_10G", + "", + "R QSFP", + "R BP40_BA", + }; + + if (port_type < ARRAY_SIZE(port_type_description)) + return port_type_description[port_type]; + return "UNKNOWN"; +} + /** * t4_get_port_stats - collect port statistics * @adap: the adapter @@ -3538,6 +3572,8 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl) speed = SPEED_1000; else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G)) speed = SPEED_10000; + else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_40G)) + speed = 40000; /* Need SPEED_40000 in ethtool.h */ if (link_ok != lc->link_ok || speed != lc->speed || fc != lc->fc) { /* something changed */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 74fea74ce0aa2..9cc973fbcf267 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -932,6 +932,7 @@ enum fw_params_param_dev { FW_PARAMS_PARAM_DEV_FWREV = 0x0B, FW_PARAMS_PARAM_DEV_TPREV = 0x0C, FW_PARAMS_PARAM_DEV_CF = 0x0D, + FW_PARAMS_PARAM_DEV_ULPTX_MEMWRITE_DSGL = 0x17, }; /* @@ -1742,6 +1743,9 @@ enum fw_port_type { FW_PORT_TYPE_SFP, FW_PORT_TYPE_BP_AP, FW_PORT_TYPE_BP4_AP, + FW_PORT_TYPE_QSFP_10G, + FW_PORT_TYPE_QSFP, + FW_PORT_TYPE_BP40_BA, FW_PORT_TYPE_NONE = FW_PORT_CMD_PTYPE_MASK };