diff options
Diffstat (limited to 'drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c')
-rw-r--r-- | drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 728 |
1 files changed, 574 insertions, 154 deletions
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 1d240a27455a..f5d490bf997e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -24,6 +24,7 @@ #include <linux/ptp_clock_kernel.h> #include <linux/net_tstamp.h> #include <linux/timecounter.h> +#include <net/netdev_queues.h> #include <net/netlink.h> #include "bnxt_hsi.h" #include "bnxt.h" @@ -631,13 +632,13 @@ static void bnxt_get_ethtool_stats(struct net_device *dev, buf[j] = sw_stats[k]; skip_tpa_ring_stats: - sw = (u64 *)&cpr->sw_stats.rx; + sw = (u64 *)&cpr->sw_stats->rx; if (is_rx_ring(bp, i)) { for (k = 0; k < NUM_RING_RX_SW_STATS; j++, k++) buf[j] = sw[k]; } - sw = (u64 *)&cpr->sw_stats.cmn; + sw = (u64 *)&cpr->sw_stats->cmn; for (k = 0; k < NUM_RING_CMN_SW_STATS; j++, k++) buf[j] = sw[k]; } @@ -705,112 +706,105 @@ skip_ring_stats: static void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf) { struct bnxt *bp = netdev_priv(dev); - static const char * const *str; u32 i, j, num_str; + const char *str; switch (stringset) { case ETH_SS_STATS: for (i = 0; i < bp->cp_nr_rings; i++) { - if (is_rx_ring(bp, i)) { - num_str = NUM_RING_RX_HW_STATS; - for (j = 0; j < num_str; j++) { - sprintf(buf, "[%d]: %s", i, - bnxt_ring_rx_stats_str[j]); - buf += ETH_GSTRING_LEN; + if (is_rx_ring(bp, i)) + for (j = 0; j < NUM_RING_RX_HW_STATS; j++) { + str = bnxt_ring_rx_stats_str[j]; + ethtool_sprintf(&buf, "[%d]: %s", i, + str); } - } - if (is_tx_ring(bp, i)) { - num_str = NUM_RING_TX_HW_STATS; - for (j = 0; j < num_str; j++) { - sprintf(buf, "[%d]: %s", i, - bnxt_ring_tx_stats_str[j]); - buf += ETH_GSTRING_LEN; + if (is_tx_ring(bp, i)) + for (j = 0; j < NUM_RING_TX_HW_STATS; j++) { + str = bnxt_ring_tx_stats_str[j]; + ethtool_sprintf(&buf, "[%d]: %s", i, + str); } - } num_str = bnxt_get_num_tpa_ring_stats(bp); if (!num_str || !is_rx_ring(bp, i)) goto skip_tpa_stats; if (bp->max_tpa_v2) - str = bnxt_ring_tpa2_stats_str; + for (j = 0; j < num_str; j++) { + str = bnxt_ring_tpa2_stats_str[j]; + ethtool_sprintf(&buf, "[%d]: %s", i, + str); + } else - str = bnxt_ring_tpa_stats_str; - - for (j = 0; j < num_str; j++) { - sprintf(buf, "[%d]: %s", i, str[j]); - buf += ETH_GSTRING_LEN; - } -skip_tpa_stats: - if (is_rx_ring(bp, i)) { - num_str = NUM_RING_RX_SW_STATS; for (j = 0; j < num_str; j++) { - sprintf(buf, "[%d]: %s", i, - bnxt_rx_sw_stats_str[j]); - buf += ETH_GSTRING_LEN; + str = bnxt_ring_tpa_stats_str[j]; + ethtool_sprintf(&buf, "[%d]: %s", i, + str); } - } - num_str = NUM_RING_CMN_SW_STATS; - for (j = 0; j < num_str; j++) { - sprintf(buf, "[%d]: %s", i, - bnxt_cmn_sw_stats_str[j]); - buf += ETH_GSTRING_LEN; +skip_tpa_stats: + if (is_rx_ring(bp, i)) + for (j = 0; j < NUM_RING_RX_SW_STATS; j++) { + str = bnxt_rx_sw_stats_str[j]; + ethtool_sprintf(&buf, "[%d]: %s", i, + str); + } + for (j = 0; j < NUM_RING_CMN_SW_STATS; j++) { + str = bnxt_cmn_sw_stats_str[j]; + ethtool_sprintf(&buf, "[%d]: %s", i, str); } } - for (i = 0; i < BNXT_NUM_RING_ERR_STATS; i++) { - strscpy(buf, bnxt_ring_err_stats_arr[i], ETH_GSTRING_LEN); - buf += ETH_GSTRING_LEN; - } + for (i = 0; i < BNXT_NUM_RING_ERR_STATS; i++) + ethtool_puts(&buf, bnxt_ring_err_stats_arr[i]); - if (bp->flags & BNXT_FLAG_PORT_STATS) { + if (bp->flags & BNXT_FLAG_PORT_STATS) for (i = 0; i < BNXT_NUM_PORT_STATS; i++) { - strcpy(buf, bnxt_port_stats_arr[i].string); - buf += ETH_GSTRING_LEN; + str = bnxt_port_stats_arr[i].string; + ethtool_puts(&buf, str); } - } + if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { u32 len; len = min_t(u32, bp->fw_rx_stats_ext_size, ARRAY_SIZE(bnxt_port_stats_ext_arr)); for (i = 0; i < len; i++) { - strcpy(buf, bnxt_port_stats_ext_arr[i].string); - buf += ETH_GSTRING_LEN; + str = bnxt_port_stats_ext_arr[i].string; + ethtool_puts(&buf, str); } + len = min_t(u32, bp->fw_tx_stats_ext_size, ARRAY_SIZE(bnxt_tx_port_stats_ext_arr)); for (i = 0; i < len; i++) { - strcpy(buf, - bnxt_tx_port_stats_ext_arr[i].string); - buf += ETH_GSTRING_LEN; + str = bnxt_tx_port_stats_ext_arr[i].string; + ethtool_puts(&buf, str); } + if (bp->pri2cos_valid) { for (i = 0; i < 8; i++) { - strcpy(buf, - bnxt_rx_bytes_pri_arr[i].string); - buf += ETH_GSTRING_LEN; + str = bnxt_rx_bytes_pri_arr[i].string; + ethtool_puts(&buf, str); } + for (i = 0; i < 8; i++) { - strcpy(buf, - bnxt_rx_pkts_pri_arr[i].string); - buf += ETH_GSTRING_LEN; + str = bnxt_rx_pkts_pri_arr[i].string; + ethtool_puts(&buf, str); } + for (i = 0; i < 8; i++) { - strcpy(buf, - bnxt_tx_bytes_pri_arr[i].string); - buf += ETH_GSTRING_LEN; + str = bnxt_tx_bytes_pri_arr[i].string; + ethtool_puts(&buf, str); } + for (i = 0; i < 8; i++) { - strcpy(buf, - bnxt_tx_pkts_pri_arr[i].string); - buf += ETH_GSTRING_LEN; + str = bnxt_tx_pkts_pri_arr[i].string; + ethtool_puts(&buf, str); } } } break; case ETH_SS_TEST: if (bp->num_tests) - memcpy(buf, bp->test_info->string, - bp->num_tests * ETH_GSTRING_LEN); + for (i = 0; i < bp->num_tests; i++) + ethtool_puts(&buf, bp->test_info->string[i]); break; default: netdev_err(bp->dev, "bnxt_get_strings invalid request %x\n", @@ -840,6 +834,8 @@ static void bnxt_get_ringparam(struct net_device *dev, ering->rx_pending = bp->rx_ring_size; ering->rx_jumbo_pending = bp->rx_agg_ring_size; ering->tx_pending = bp->tx_ring_size; + + kernel_ering->hds_thresh_max = BNXT_HDS_THRESHOLD_MAX; } static int bnxt_set_ringparam(struct net_device *dev, @@ -847,16 +843,35 @@ static int bnxt_set_ringparam(struct net_device *dev, struct kernel_ethtool_ringparam *kernel_ering, struct netlink_ext_ack *extack) { + u8 tcp_data_split = kernel_ering->tcp_data_split; struct bnxt *bp = netdev_priv(dev); + u8 hds_config_mod; if ((ering->rx_pending > BNXT_MAX_RX_DESC_CNT) || (ering->tx_pending > BNXT_MAX_TX_DESC_CNT) || (ering->tx_pending < BNXT_MIN_TX_DESC_CNT)) return -EINVAL; + hds_config_mod = tcp_data_split != dev->cfg->hds_config; + if (tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_DISABLED && hds_config_mod) + return -EINVAL; + + if (tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_ENABLED && + hds_config_mod && BNXT_RX_PAGE_MODE(bp)) { + NL_SET_ERR_MSG_MOD(extack, "tcp-data-split is disallowed when XDP is attached"); + return -EINVAL; + } + if (netif_running(dev)) bnxt_close_nic(bp, false, false); + if (hds_config_mod) { + if (tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_ENABLED) + bp->flags |= BNXT_FLAG_HDS; + else if (tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_UNKNOWN) + bp->flags &= ~BNXT_FLAG_HDS; + } + bp->rx_ring_size = ering->rx_pending; bp->tx_ring_size = ering->tx_pending; bnxt_set_ring_params(bp); @@ -955,11 +970,6 @@ static int bnxt_set_channels(struct net_device *dev, } tx_xdp = req_rx_rings; } - rc = bnxt_check_rings(bp, req_tx_rings, req_rx_rings, sh, tcs, tx_xdp); - if (rc) { - netdev_warn(dev, "Unable to allocate the requested rings\n"); - return rc; - } if (bnxt_get_nr_rss_ctxs(bp, req_rx_rings) != bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings) && @@ -968,7 +978,12 @@ static int bnxt_set_channels(struct net_device *dev, return -EINVAL; } - bnxt_clear_usr_fltrs(bp, true); + rc = bnxt_check_rings(bp, req_tx_rings, req_rx_rings, sh, tcs, tx_xdp); + if (rc) { + netdev_warn(dev, "Unable to allocate the requested rings\n"); + return rc; + } + if (netif_running(dev)) { if (BNXT_PF(bp)) { /* TODO CHIMP_FW: Send message to all VF's @@ -1131,14 +1146,15 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) fkeys = &fltr->fkeys; fmasks = &fltr->fmasks; if (fkeys->basic.n_proto == htons(ETH_P_IP)) { - if (fkeys->basic.ip_proto == IPPROTO_ICMP || - fkeys->basic.ip_proto == IPPROTO_RAW) { + if (fkeys->basic.ip_proto == BNXT_IP_PROTO_WILDCARD) { fs->flow_type = IP_USER_FLOW; fs->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4; - if (fkeys->basic.ip_proto == IPPROTO_ICMP) - fs->h_u.usr_ip4_spec.proto = IPPROTO_ICMP; - else - fs->h_u.usr_ip4_spec.proto = IPPROTO_RAW; + fs->h_u.usr_ip4_spec.proto = BNXT_IP_PROTO_WILDCARD; + fs->m_u.usr_ip4_spec.proto = 0; + } else if (fkeys->basic.ip_proto == IPPROTO_ICMP) { + fs->flow_type = IP_USER_FLOW; + fs->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4; + fs->h_u.usr_ip4_spec.proto = IPPROTO_ICMP; fs->m_u.usr_ip4_spec.proto = BNXT_IP_PROTO_FULL_MASK; } else if (fkeys->basic.ip_proto == IPPROTO_TCP) { fs->flow_type = TCP_V4_FLOW; @@ -1160,13 +1176,13 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) fs->m_u.tcp_ip4_spec.pdst = fmasks->ports.dst; } } else { - if (fkeys->basic.ip_proto == IPPROTO_ICMPV6 || - fkeys->basic.ip_proto == IPPROTO_RAW) { + if (fkeys->basic.ip_proto == BNXT_IP_PROTO_WILDCARD) { fs->flow_type = IPV6_USER_FLOW; - if (fkeys->basic.ip_proto == IPPROTO_ICMPV6) - fs->h_u.usr_ip6_spec.l4_proto = IPPROTO_ICMPV6; - else - fs->h_u.usr_ip6_spec.l4_proto = IPPROTO_RAW; + fs->h_u.usr_ip6_spec.l4_proto = BNXT_IP_PROTO_WILDCARD; + fs->m_u.usr_ip6_spec.l4_proto = 0; + } else if (fkeys->basic.ip_proto == IPPROTO_ICMPV6) { + fs->flow_type = IPV6_USER_FLOW; + fs->h_u.usr_ip6_spec.l4_proto = IPPROTO_ICMPV6; fs->m_u.usr_ip6_spec.l4_proto = BNXT_IP_PROTO_FULL_MASK; } else if (fkeys->basic.ip_proto == IPPROTO_TCP) { fs->flow_type = TCP_V6_FLOW; @@ -1193,10 +1209,14 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) } } - if (fltr->base.flags & BNXT_ACT_DROP) + if (fltr->base.flags & BNXT_ACT_DROP) { fs->ring_cookie = RX_CLS_FLOW_DISC; - else + } else if (fltr->base.flags & BNXT_ACT_RSS_CTX) { + fs->flow_type |= FLOW_RSS; + cmd->rss_context = fltr->base.fw_vnic_id; + } else { fs->ring_cookie = fltr->base.rxq; + } rc = 0; fltr_err: @@ -1205,6 +1225,35 @@ fltr_err: return rc; } +static struct bnxt_rss_ctx *bnxt_get_rss_ctx_from_index(struct bnxt *bp, + u32 index) +{ + struct ethtool_rxfh_context *ctx; + + ctx = xa_load(&bp->dev->ethtool->rss_ctx, index); + if (!ctx) + return NULL; + return ethtool_rxfh_context_priv(ctx); +} + +static int bnxt_alloc_vnic_rss_table(struct bnxt *bp, + struct bnxt_vnic_info *vnic) +{ + int size = L1_CACHE_ALIGN(BNXT_MAX_RSS_TABLE_SIZE_P5); + + vnic->rss_table_size = size + HW_HASH_KEY_SIZE; + vnic->rss_table = dma_alloc_coherent(&bp->pdev->dev, + vnic->rss_table_size, + &vnic->rss_table_dma_addr, + GFP_KERNEL); + if (!vnic->rss_table) + return -ENOMEM; + + vnic->rss_hash_key = ((void *)vnic->rss_table) + size; + vnic->rss_hash_key_dma_addr = vnic->rss_table_dma_addr + size; + return 0; +} + static int bnxt_add_l2_cls_rule(struct bnxt *bp, struct ethtool_rx_flow_spec *fs) { @@ -1260,10 +1309,12 @@ static int bnxt_add_l2_cls_rule(struct bnxt *bp, static bool bnxt_verify_ntuple_ip4_flow(struct ethtool_usrip4_spec *ip_spec, struct ethtool_usrip4_spec *ip_mask) { + u8 mproto = ip_mask->proto; + u8 sproto = ip_spec->proto; + if (ip_mask->l4_4_bytes || ip_mask->tos || ip_spec->ip_ver != ETH_RX_NFC_IP4 || - ip_mask->proto != BNXT_IP_PROTO_FULL_MASK || - (ip_spec->proto != IPPROTO_RAW && ip_spec->proto != IPPROTO_ICMP)) + (mproto && (mproto != BNXT_IP_PROTO_FULL_MASK || sproto != IPPROTO_ICMP))) return false; return true; } @@ -1271,31 +1322,34 @@ static bool bnxt_verify_ntuple_ip4_flow(struct ethtool_usrip4_spec *ip_spec, static bool bnxt_verify_ntuple_ip6_flow(struct ethtool_usrip6_spec *ip_spec, struct ethtool_usrip6_spec *ip_mask) { + u8 mproto = ip_mask->l4_proto; + u8 sproto = ip_spec->l4_proto; + if (ip_mask->l4_4_bytes || ip_mask->tclass || - ip_mask->l4_proto != BNXT_IP_PROTO_FULL_MASK || - (ip_spec->l4_proto != IPPROTO_RAW && - ip_spec->l4_proto != IPPROTO_ICMPV6)) + (mproto && (mproto != BNXT_IP_PROTO_FULL_MASK || sproto != IPPROTO_ICMPV6))) return false; return true; } static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, - struct ethtool_rx_flow_spec *fs) + struct ethtool_rxnfc *cmd) { - u8 vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie); - u32 ring = ethtool_get_flow_spec_ring(fs->ring_cookie); + struct ethtool_rx_flow_spec *fs = &cmd->fs; struct bnxt_ntuple_filter *new_fltr, *fltr; + u32 flow_type = fs->flow_type & 0xff; struct bnxt_l2_filter *l2_fltr; struct bnxt_flow_masks *fmasks; - u32 flow_type = fs->flow_type; struct flow_keys *fkeys; - u32 idx; + u32 idx, ring; int rc; + u8 vf; if (!bp->vnic_info) return -EAGAIN; - if ((flow_type & (FLOW_MAC_EXT | FLOW_EXT)) || vf) + vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie); + ring = ethtool_get_flow_spec_ring(fs->ring_cookie); + if ((fs->flow_type & (FLOW_MAC_EXT | FLOW_EXT)) || vf) return -EOPNOTSUPP; if (flow_type == IP_USER_FLOW) { @@ -1326,7 +1380,8 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, struct ethtool_usrip4_spec *ip_spec = &fs->h_u.usr_ip4_spec; struct ethtool_usrip4_spec *ip_mask = &fs->m_u.usr_ip4_spec; - fkeys->basic.ip_proto = ip_spec->proto; + fkeys->basic.ip_proto = ip_mask->proto ? ip_spec->proto + : BNXT_IP_PROTO_WILDCARD; fkeys->basic.n_proto = htons(ETH_P_IP); fkeys->addrs.v4addrs.src = ip_spec->ip4src; fmasks->addrs.v4addrs.src = ip_mask->ip4src; @@ -1357,7 +1412,8 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, struct ethtool_usrip6_spec *ip_spec = &fs->h_u.usr_ip6_spec; struct ethtool_usrip6_spec *ip_mask = &fs->m_u.usr_ip6_spec; - fkeys->basic.ip_proto = ip_spec->l4_proto; + fkeys->basic.ip_proto = ip_mask->l4_proto ? ip_spec->l4_proto + : BNXT_IP_PROTO_WILDCARD; fkeys->basic.n_proto = htons(ETH_P_IPV6); fkeys->addrs.v6addrs.src = *(struct in6_addr *)&ip_spec->ip6src; fmasks->addrs.v6addrs.src = *(struct in6_addr *)&ip_mask->ip6src; @@ -1403,6 +1459,19 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, rcu_read_unlock(); new_fltr->base.flags = BNXT_ACT_NO_AGING; + if (fs->flow_type & FLOW_RSS) { + struct bnxt_rss_ctx *rss_ctx; + + new_fltr->base.fw_vnic_id = 0; + new_fltr->base.flags |= BNXT_ACT_RSS_CTX; + rss_ctx = bnxt_get_rss_ctx_from_index(bp, cmd->rss_context); + if (rss_ctx) { + new_fltr->base.fw_vnic_id = rss_ctx->index; + } else { + rc = -EINVAL; + goto ntuple_err; + } + } if (fs->ring_cookie == RX_CLS_FLOW_DISC) new_fltr->base.flags |= BNXT_ACT_DROP; else @@ -1444,12 +1513,12 @@ static int bnxt_srxclsrlins(struct bnxt *bp, struct ethtool_rxnfc *cmd) flow_type == IPV6_USER_FLOW) && !(bp->fw_cap & BNXT_FW_CAP_CFA_NTUPLE_RX_EXT_IP_PROTO)) return -EOPNOTSUPP; - if (flow_type & (FLOW_MAC_EXT | FLOW_RSS)) + if (flow_type & FLOW_MAC_EXT) return -EINVAL; flow_type &= ~FLOW_EXT; if (fs->ring_cookie == RX_CLS_FLOW_DISC && flow_type != ETHER_FLOW) - return bnxt_add_ntuple_cls_rule(bp, fs); + return bnxt_add_ntuple_cls_rule(bp, cmd); ring = ethtool_get_flow_spec_ring(fs->ring_cookie); vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie); @@ -1463,7 +1532,7 @@ static int bnxt_srxclsrlins(struct bnxt *bp, struct ethtool_rxnfc *cmd) if (flow_type == ETHER_FLOW) rc = bnxt_add_l2_cls_rule(bp, fs); else - rc = bnxt_add_ntuple_cls_rule(bp, fs); + rc = bnxt_add_ntuple_cls_rule(bp, cmd); return rc; } @@ -1754,7 +1823,9 @@ static u32 bnxt_get_rxfh_key_size(struct net_device *dev) static int bnxt_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh) { + struct bnxt_rss_ctx *rss_ctx = NULL; struct bnxt *bp = netdev_priv(dev); + u32 *indir_tbl = bp->rss_indir_tbl; struct bnxt_vnic_info *vnic; u32 i, tbl_size; @@ -1764,10 +1835,21 @@ static int bnxt_get_rxfh(struct net_device *dev, return 0; vnic = &bp->vnic_info[BNXT_VNIC_DEFAULT]; - if (rxfh->indir && bp->rss_indir_tbl) { + if (rxfh->rss_context) { + struct ethtool_rxfh_context *ctx; + + ctx = xa_load(&bp->dev->ethtool->rss_ctx, rxfh->rss_context); + if (!ctx) + return -EINVAL; + indir_tbl = ethtool_rxfh_context_indir(ctx); + rss_ctx = ethtool_rxfh_context_priv(ctx); + vnic = &rss_ctx->vnic; + } + + if (rxfh->indir && indir_tbl) { tbl_size = bnxt_get_rxfh_indir_size(dev); for (i = 0; i < tbl_size; i++) - rxfh->indir[i] = bp->rss_indir_tbl[i]; + rxfh->indir[i] = indir_tbl[i]; } if (rxfh->key && vnic->rss_hash_key) @@ -1776,6 +1858,159 @@ static int bnxt_get_rxfh(struct net_device *dev, return 0; } +static void bnxt_modify_rss(struct bnxt *bp, struct ethtool_rxfh_context *ctx, + struct bnxt_rss_ctx *rss_ctx, + const struct ethtool_rxfh_param *rxfh) +{ + if (rxfh->key) { + if (rss_ctx) { + memcpy(rss_ctx->vnic.rss_hash_key, rxfh->key, + HW_HASH_KEY_SIZE); + } else { + memcpy(bp->rss_hash_key, rxfh->key, HW_HASH_KEY_SIZE); + bp->rss_hash_key_updated = true; + } + } + if (rxfh->indir) { + u32 i, pad, tbl_size = bnxt_get_rxfh_indir_size(bp->dev); + u32 *indir_tbl = bp->rss_indir_tbl; + + if (rss_ctx) + indir_tbl = ethtool_rxfh_context_indir(ctx); + for (i = 0; i < tbl_size; i++) + indir_tbl[i] = rxfh->indir[i]; + pad = bp->rss_indir_tbl_entries - tbl_size; + if (pad) + memset(&indir_tbl[i], 0, pad * sizeof(*indir_tbl)); + } +} + +static int bnxt_rxfh_context_check(struct bnxt *bp, + const struct ethtool_rxfh_param *rxfh, + struct netlink_ext_ack *extack) +{ + if (rxfh->hfunc && rxfh->hfunc != ETH_RSS_HASH_TOP) { + NL_SET_ERR_MSG_MOD(extack, "RSS hash function not supported"); + return -EOPNOTSUPP; + } + + if (!BNXT_SUPPORTS_MULTI_RSS_CTX(bp)) { + NL_SET_ERR_MSG_MOD(extack, "RSS contexts not supported"); + return -EOPNOTSUPP; + } + + if (!netif_running(bp->dev)) { + NL_SET_ERR_MSG_MOD(extack, "Unable to set RSS contexts when interface is down"); + return -EAGAIN; + } + + return 0; +} + +static int bnxt_create_rxfh_context(struct net_device *dev, + struct ethtool_rxfh_context *ctx, + const struct ethtool_rxfh_param *rxfh, + struct netlink_ext_ack *extack) +{ + struct bnxt *bp = netdev_priv(dev); + struct bnxt_rss_ctx *rss_ctx; + struct bnxt_vnic_info *vnic; + int rc; + + rc = bnxt_rxfh_context_check(bp, rxfh, extack); + if (rc) + return rc; + + if (bp->num_rss_ctx >= BNXT_MAX_ETH_RSS_CTX) { + NL_SET_ERR_MSG_FMT_MOD(extack, "Out of RSS contexts, maximum %u", + BNXT_MAX_ETH_RSS_CTX); + return -EINVAL; + } + + if (!bnxt_rfs_capable(bp, true)) { + NL_SET_ERR_MSG_MOD(extack, "Out hardware resources"); + return -ENOMEM; + } + + rss_ctx = ethtool_rxfh_context_priv(ctx); + + bp->num_rss_ctx++; + + vnic = &rss_ctx->vnic; + vnic->rss_ctx = ctx; + vnic->flags |= BNXT_VNIC_RSSCTX_FLAG; + vnic->vnic_id = BNXT_VNIC_ID_INVALID; + rc = bnxt_alloc_vnic_rss_table(bp, vnic); + if (rc) + goto out; + + /* Populate defaults in the context */ + bnxt_set_dflt_rss_indir_tbl(bp, ctx); + ctx->hfunc = ETH_RSS_HASH_TOP; + memcpy(vnic->rss_hash_key, bp->rss_hash_key, HW_HASH_KEY_SIZE); + memcpy(ethtool_rxfh_context_key(ctx), + bp->rss_hash_key, HW_HASH_KEY_SIZE); + + rc = bnxt_hwrm_vnic_alloc(bp, vnic, 0, bp->rx_nr_rings); + if (rc) { + NL_SET_ERR_MSG_MOD(extack, "Unable to allocate VNIC"); + goto out; + } + + rc = bnxt_hwrm_vnic_set_tpa(bp, vnic, bp->flags & BNXT_FLAG_TPA); + if (rc) { + NL_SET_ERR_MSG_MOD(extack, "Unable to setup TPA"); + goto out; + } + bnxt_modify_rss(bp, ctx, rss_ctx, rxfh); + + rc = __bnxt_setup_vnic_p5(bp, vnic); + if (rc) { + NL_SET_ERR_MSG_MOD(extack, "Unable to setup TPA"); + goto out; + } + + rss_ctx->index = rxfh->rss_context; + return 0; +out: + bnxt_del_one_rss_ctx(bp, rss_ctx, true); + return rc; +} + +static int bnxt_modify_rxfh_context(struct net_device *dev, + struct ethtool_rxfh_context *ctx, + const struct ethtool_rxfh_param *rxfh, + struct netlink_ext_ack *extack) +{ + struct bnxt *bp = netdev_priv(dev); + struct bnxt_rss_ctx *rss_ctx; + int rc; + + rc = bnxt_rxfh_context_check(bp, rxfh, extack); + if (rc) + return rc; + + rss_ctx = ethtool_rxfh_context_priv(ctx); + + bnxt_modify_rss(bp, ctx, rss_ctx, rxfh); + + return bnxt_hwrm_vnic_rss_cfg_p5(bp, &rss_ctx->vnic); +} + +static int bnxt_remove_rxfh_context(struct net_device *dev, + struct ethtool_rxfh_context *ctx, + u32 rss_context, + struct netlink_ext_ack *extack) +{ + struct bnxt *bp = netdev_priv(dev); + struct bnxt_rss_ctx *rss_ctx; + + rss_ctx = ethtool_rxfh_context_priv(ctx); + + bnxt_del_one_rss_ctx(bp, rss_ctx, true); + return 0; +} + static int bnxt_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh, struct netlink_ext_ack *extack) @@ -1786,21 +2021,8 @@ static int bnxt_set_rxfh(struct net_device *dev, if (rxfh->hfunc && rxfh->hfunc != ETH_RSS_HASH_TOP) return -EOPNOTSUPP; - if (rxfh->key) { - memcpy(bp->rss_hash_key, rxfh->key, HW_HASH_KEY_SIZE); - bp->rss_hash_key_updated = true; - } - - if (rxfh->indir) { - u32 i, pad, tbl_size = bnxt_get_rxfh_indir_size(dev); + bnxt_modify_rss(bp, NULL, NULL, rxfh); - for (i = 0; i < tbl_size; i++) - bp->rss_indir_tbl[i] = rxfh->indir[i]; - pad = bp->rss_indir_tbl_entries - tbl_size; - if (pad) - memset(&bp->rss_indir_tbl[i], 0, pad * sizeof(u16)); - } - bnxt_clear_usr_fltrs(bp, false); if (netif_running(bp->dev)) { bnxt_close_nic(bp, false, false); rc = bnxt_open_nic(bp, false, false); @@ -1840,6 +2062,17 @@ static int bnxt_get_regs_len(struct net_device *dev) return reg_len; } +#define BNXT_PCIE_32B_ENTRY(start, end) \ + { offsetof(struct pcie_ctx_hw_stats, start), \ + offsetof(struct pcie_ctx_hw_stats, end) } + +static const struct { + u16 start; + u16 end; +} bnxt_pcie_32b_entries[] = { + BNXT_PCIE_32B_ENTRY(pcie_ltssm_histogram[0], pcie_ltssm_histogram[3]), +}; + static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p) { @@ -1850,7 +2083,8 @@ static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, int rc; regs->version = 0; - bnxt_dbg_hwrm_rd_reg(bp, 0, BNXT_PXP_REG_LEN / 4, _p); + if (!(bp->fw_dbg_cap & DBG_QCAPS_RESP_FLAGS_REG_ACCESS_RESTRICTED)) + bnxt_dbg_hwrm_rd_reg(bp, 0, BNXT_PXP_REG_LEN / 4, _p); if (!(bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED)) return; @@ -1871,12 +2105,27 @@ static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, req->pcie_stat_host_addr = cpu_to_le64(hw_pcie_stats_addr); rc = hwrm_req_send(bp, req); if (!rc) { - __le64 *src = (__le64 *)hw_pcie_stats; - u64 *dst = (u64 *)(_p + BNXT_PXP_REG_LEN); - int i; - - for (i = 0; i < sizeof(*hw_pcie_stats) / sizeof(__le64); i++) - dst[i] = le64_to_cpu(src[i]); + u8 *dst = (u8 *)(_p + BNXT_PXP_REG_LEN); + u8 *src = (u8 *)hw_pcie_stats; + int i, j; + + for (i = 0, j = 0; i < sizeof(*hw_pcie_stats); ) { + if (i >= bnxt_pcie_32b_entries[j].start && + i <= bnxt_pcie_32b_entries[j].end) { + u32 *dst32 = (u32 *)(dst + i); + + *dst32 = le32_to_cpu(*(__le32 *)(src + i)); + i += 4; + if (i > bnxt_pcie_32b_entries[j].end && + j < ARRAY_SIZE(bnxt_pcie_32b_entries) - 1) + j++; + } else { + u64 *dst64 = (u64 *)(dst + i); + + *dst64 = le64_to_cpu(*(__le64 *)(src + i)); + i += 8; + } + } } hwrm_req_drop(bp, req); } @@ -2641,19 +2890,24 @@ static int bnxt_get_link_ksettings(struct net_device *dev, } base->port = PORT_NONE; - if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { + if (media == BNXT_MEDIA_TP) { base->port = PORT_TP; linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, lk_ksettings->link_modes.supported); linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, lk_ksettings->link_modes.advertising); + } else if (media == BNXT_MEDIA_KR) { + linkmode_set_bit(ETHTOOL_LINK_MODE_Backplane_BIT, + lk_ksettings->link_modes.supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_Backplane_BIT, + lk_ksettings->link_modes.advertising); } else { linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, lk_ksettings->link_modes.supported); linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, lk_ksettings->link_modes.advertising); - if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC) + if (media == BNXT_MEDIA_CR) base->port = PORT_DA; else base->port = PORT_FIBRE; @@ -3956,12 +4210,12 @@ err: static void bnxt_get_pkgver(struct net_device *dev) { struct bnxt *bp = netdev_priv(dev); - char buf[FW_VER_STR_LEN]; + char buf[FW_VER_STR_LEN - 5]; int len; if (!bnxt_get_pkginfo(dev, buf, sizeof(buf))) { len = strlen(bp->fw_ver_str); - snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len - 1, + snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len, "/pkg %s", buf); } } @@ -4122,6 +4376,45 @@ static int bnxt_get_eee(struct net_device *dev, struct ethtool_keee *edata) return 0; } +static int bnxt_set_tunable(struct net_device *dev, + const struct ethtool_tunable *tuna, + const void *data) +{ + struct bnxt *bp = netdev_priv(dev); + u32 rx_copybreak; + + switch (tuna->id) { + case ETHTOOL_RX_COPYBREAK: + rx_copybreak = *(u32 *)data; + if (rx_copybreak > BNXT_MAX_RX_COPYBREAK) + return -ERANGE; + if (rx_copybreak != bp->rx_copybreak) { + if (netif_running(dev)) + return -EBUSY; + bp->rx_copybreak = rx_copybreak; + } + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int bnxt_get_tunable(struct net_device *dev, + const struct ethtool_tunable *tuna, void *data) +{ + struct bnxt *bp = netdev_priv(dev); + + switch (tuna->id) { + case ETHTOOL_RX_COPYBREAK: + *(u32 *)data = bp->rx_copybreak; + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + static int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr, u16 page_number, u8 bank, u16 start_addr, u16 data_length, @@ -4170,6 +4463,9 @@ static int bnxt_get_module_info(struct net_device *dev, struct bnxt *bp = netdev_priv(dev); int rc; + if (BNXT_VF(bp) && !BNXT_VF_IS_TRUSTED(bp)) + return -EPERM; + /* No point in going further if phy status indicates * module is not inserted or if it is powered down or * if it is of type 10GBase-T @@ -4221,6 +4517,9 @@ static int bnxt_get_module_eeprom(struct net_device *dev, u16 start = eeprom->offset, length = eeprom->len; int rc = 0; + if (BNXT_VF(bp) && !BNXT_VF_IS_TRUSTED(bp)) + return -EPERM; + memset(data, 0, eeprom->len); /* Read A0 portion of the EEPROM */ @@ -4268,13 +4567,19 @@ static int bnxt_get_module_status(struct bnxt *bp, struct netlink_ext_ack *extac return -EINVAL; } -static int bnxt_get_module_eeprom_by_page(struct net_device *dev, - const struct ethtool_module_eeprom *page_data, - struct netlink_ext_ack *extack) +static int +bnxt_mod_eeprom_by_page_precheck(struct bnxt *bp, + const struct ethtool_module_eeprom *page_data, + struct netlink_ext_ack *extack) { - struct bnxt *bp = netdev_priv(dev); int rc; + if (BNXT_VF(bp) && !BNXT_VF_IS_TRUSTED(bp)) { + NL_SET_ERR_MSG_MOD(extack, + "Module read/write not permitted on untrusted VF"); + return -EPERM; + } + rc = bnxt_get_module_status(bp, extack); if (rc) return rc; @@ -4288,6 +4593,19 @@ static int bnxt_get_module_eeprom_by_page(struct net_device *dev, NL_SET_ERR_MSG_MOD(extack, "Firmware not capable for bank selection"); return -EINVAL; } + return 0; +} + +static int bnxt_get_module_eeprom_by_page(struct net_device *dev, + const struct ethtool_module_eeprom *page_data, + struct netlink_ext_ack *extack) +{ + struct bnxt *bp = netdev_priv(dev); + int rc; + + rc = bnxt_mod_eeprom_by_page_precheck(bp, page_data, extack); + if (rc) + return rc; rc = bnxt_read_sfp_module_eeprom_info(bp, page_data->i2c_address << 1, page_data->page, page_data->bank, @@ -4301,6 +4619,62 @@ static int bnxt_get_module_eeprom_by_page(struct net_device *dev, return page_data->length; } +static int bnxt_write_sfp_module_eeprom_info(struct bnxt *bp, + const struct ethtool_module_eeprom *page) +{ + struct hwrm_port_phy_i2c_write_input *req; + int bytes_written = 0; + int rc; + + rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_I2C_WRITE); + if (rc) + return rc; + + hwrm_req_hold(bp, req); + req->i2c_slave_addr = page->i2c_address << 1; + req->page_number = cpu_to_le16(page->page); + req->bank_number = page->bank; + req->port_id = cpu_to_le16(bp->pf.port_id); + req->enables = cpu_to_le32(PORT_PHY_I2C_WRITE_REQ_ENABLES_PAGE_OFFSET | + PORT_PHY_I2C_WRITE_REQ_ENABLES_BANK_NUMBER); + + while (bytes_written < page->length) { + u16 xfer_size; + + xfer_size = min_t(u16, page->length - bytes_written, + BNXT_MAX_PHY_I2C_RESP_SIZE); + req->page_offset = cpu_to_le16(page->offset + bytes_written); + req->data_length = xfer_size; + memcpy(req->data, page->data + bytes_written, xfer_size); + rc = hwrm_req_send(bp, req); + if (rc) + break; + bytes_written += xfer_size; + } + + hwrm_req_drop(bp, req); + return rc; +} + +static int bnxt_set_module_eeprom_by_page(struct net_device *dev, + const struct ethtool_module_eeprom *page_data, + struct netlink_ext_ack *extack) +{ + struct bnxt *bp = netdev_priv(dev); + int rc; + + rc = bnxt_mod_eeprom_by_page_precheck(bp, page_data, extack); + if (rc) + return rc; + + rc = bnxt_write_sfp_module_eeprom_info(bp, page_data); + if (rc) { + NL_SET_ERR_MSG_MOD(extack, "Module`s eeprom write failed"); + return rc; + } + return page_data->length; +} + static int bnxt_nway_reset(struct net_device *dev) { int rc = 0; @@ -4572,7 +4946,8 @@ static int bnxt_run_loopback(struct bnxt *bp) cpr = &rxr->bnapi->cp_ring; if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) cpr = rxr->rx_cpr; - pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh); + pkt_size = min(bp->dev->mtu + ETH_HLEN, max(BNXT_DEFAULT_RX_COPYBREAK, + bp->rx_copybreak)); skb = netdev_alloc_skb(bp->dev, pkt_size); if (!skb) return -ENOMEM; @@ -4641,7 +5016,15 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, if (!bp->num_tests || !BNXT_PF(bp)) return; + memset(buf, 0, sizeof(u64) * bp->num_tests); + if (etest->flags & ETH_TEST_FL_OFFLINE && + bnxt_ulp_registered(bp->edev)) { + etest->flags |= ETH_TEST_FL_FAILED; + netdev_warn(dev, "Offline tests cannot be run with RoCE driver loaded\n"); + return; + } + if (!netif_running(dev)) { etest->flags |= ETH_TEST_FL_FAILED; return; @@ -4671,45 +5054,51 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, if (!offline) { bnxt_run_fw_tests(bp, test_mask, &test_results); } else { - bnxt_ulp_stop(bp); bnxt_close_nic(bp, true, false); bnxt_run_fw_tests(bp, test_mask, &test_results); - buf[BNXT_MACLPBK_TEST_IDX] = 1; - bnxt_hwrm_mac_loopback(bp, true); - msleep(250); rc = bnxt_half_open_nic(bp); if (rc) { - bnxt_hwrm_mac_loopback(bp, false); etest->flags |= ETH_TEST_FL_FAILED; - bnxt_ulp_start(bp, rc); return; } + buf[BNXT_MACLPBK_TEST_IDX] = 1; + if (bp->mac_flags & BNXT_MAC_FL_NO_MAC_LPBK) + goto skip_mac_loopback; + + bnxt_hwrm_mac_loopback(bp, true); + msleep(250); if (bnxt_run_loopback(bp)) etest->flags |= ETH_TEST_FL_FAILED; else buf[BNXT_MACLPBK_TEST_IDX] = 0; bnxt_hwrm_mac_loopback(bp, false); +skip_mac_loopback: + buf[BNXT_PHYLPBK_TEST_IDX] = 1; + if (bp->phy_flags & BNXT_PHY_FL_NO_PHY_LPBK) + goto skip_phy_loopback; + bnxt_hwrm_phy_loopback(bp, true, false); msleep(1000); - if (bnxt_run_loopback(bp)) { - buf[BNXT_PHYLPBK_TEST_IDX] = 1; + if (bnxt_run_loopback(bp)) etest->flags |= ETH_TEST_FL_FAILED; - } + else + buf[BNXT_PHYLPBK_TEST_IDX] = 0; +skip_phy_loopback: + buf[BNXT_EXTLPBK_TEST_IDX] = 1; if (do_ext_lpbk) { etest->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE; bnxt_hwrm_phy_loopback(bp, true, true); msleep(1000); - if (bnxt_run_loopback(bp)) { - buf[BNXT_EXTLPBK_TEST_IDX] = 1; + if (bnxt_run_loopback(bp)) etest->flags |= ETH_TEST_FL_FAILED; - } + else + buf[BNXT_EXTLPBK_TEST_IDX] = 0; } bnxt_hwrm_phy_loopback(bp, false, false); bnxt_half_close_nic(bp); rc = bnxt_open_nic(bp, true, true); - bnxt_ulp_start(bp, rc); } if (rc || bnxt_test_irq(bp)) { buf[BNXT_IRQ_TEST_IDX] = 1; @@ -4783,14 +5172,22 @@ static int bnxt_set_dump(struct net_device *dev, struct ethtool_dump *dump) { struct bnxt *bp = netdev_priv(dev); - if (dump->flag > BNXT_DUMP_CRASH) { - netdev_info(dev, "Supports only Live(0) and Crash(1) dumps.\n"); + if (dump->flag > BNXT_DUMP_LIVE_WITH_CTX_L1_CACHE) { + netdev_info(dev, + "Supports only Live(0), Crash(1), Driver(2), Live with cached context(3) dumps.\n"); return -EINVAL; } - if (!IS_ENABLED(CONFIG_TEE_BNXT_FW) && dump->flag == BNXT_DUMP_CRASH) { - netdev_info(dev, "Cannot collect crash dump as TEE_BNXT_FW config option is not enabled.\n"); - return -EOPNOTSUPP; + if (dump->flag == BNXT_DUMP_CRASH) { + if (bp->fw_dbg_cap & DBG_QCAPS_RESP_FLAGS_CRASHDUMP_SOC_DDR && + (!IS_ENABLED(CONFIG_TEE_BNXT_FW))) { + netdev_info(dev, + "Cannot collect crash dump as TEE_BNXT_FW config option is not enabled.\n"); + return -EOPNOTSUPP; + } else if (!(bp->fw_dbg_cap & DBG_QCAPS_RESP_FLAGS_CRASHDUMP_HOST_DDR)) { + netdev_info(dev, "Crash dump collection from host memory is not supported on this interface.\n"); + return -EOPNOTSUPP; + } } bp->dump_flag = dump->flag; @@ -4829,17 +5226,14 @@ static int bnxt_get_dump_data(struct net_device *dev, struct ethtool_dump *dump, } static int bnxt_get_ts_info(struct net_device *dev, - struct ethtool_ts_info *info) + struct kernel_ethtool_ts_info *info) { struct bnxt *bp = netdev_priv(dev); struct bnxt_ptp_cfg *ptp; ptp = bp->ptp_cfg; - info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | - SOF_TIMESTAMPING_RX_SOFTWARE | - SOF_TIMESTAMPING_SOFTWARE; + info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE; - info->phc_index = -1; if (!ptp) return 0; @@ -5049,6 +5443,19 @@ static void bnxt_get_rmon_stats(struct net_device *dev, *ranges = bnxt_rmon_ranges; } +static void bnxt_get_ptp_stats(struct net_device *dev, + struct ethtool_ts_stats *ts_stats) +{ + struct bnxt *bp = netdev_priv(dev); + struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; + + if (ptp) { + ts_stats->pkts = ptp->stats.ts_pkts; + ts_stats->lost = ptp->stats.ts_lost; + ts_stats->err = atomic64_read(&ptp->stats.ts_err); + } +} + static void bnxt_get_link_ext_stats(struct net_device *dev, struct ethtool_link_ext_stats *stats) { @@ -5071,6 +5478,10 @@ void bnxt_ethtool_free(struct bnxt *bp) const struct ethtool_ops bnxt_ethtool_ops = { .cap_link_lanes_supported = 1, + .rxfh_per_ctx_key = 1, + .rxfh_max_num_contexts = BNXT_MAX_ETH_RSS_CTX + 1, + .rxfh_indir_space = BNXT_MAX_RSS_TABLE_ENTRIES_P5, + .rxfh_priv_size = sizeof(struct bnxt_rss_ctx), .supported_coalesce_params = ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_MAX_FRAMES | ETHTOOL_COALESCE_USECS_IRQ | @@ -5078,6 +5489,8 @@ const struct ethtool_ops bnxt_ethtool_ops = { ETHTOOL_COALESCE_STATS_BLOCK_USECS | ETHTOOL_COALESCE_USE_ADAPTIVE_RX | ETHTOOL_COALESCE_USE_CQE, + .supported_ring_params = ETHTOOL_RING_USE_TCP_DATA_SPLIT | + ETHTOOL_RING_USE_HDS_THRS, .get_link_ksettings = bnxt_get_link_ksettings, .set_link_ksettings = bnxt_set_link_ksettings, .get_fec_stats = bnxt_get_fec_stats, @@ -5108,6 +5521,9 @@ const struct ethtool_ops bnxt_ethtool_ops = { .get_rxfh_key_size = bnxt_get_rxfh_key_size, .get_rxfh = bnxt_get_rxfh, .set_rxfh = bnxt_set_rxfh, + .create_rxfh_context = bnxt_create_rxfh_context, + .modify_rxfh_context = bnxt_modify_rxfh_context, + .remove_rxfh_context = bnxt_remove_rxfh_context, .flash_device = bnxt_flash_device, .get_eeprom_len = bnxt_get_eeprom_len, .get_eeprom = bnxt_get_eeprom, @@ -5116,9 +5532,12 @@ const struct ethtool_ops bnxt_ethtool_ops = { .get_link_ext_stats = bnxt_get_link_ext_stats, .get_eee = bnxt_get_eee, .set_eee = bnxt_set_eee, + .get_tunable = bnxt_get_tunable, + .set_tunable = bnxt_set_tunable, .get_module_info = bnxt_get_module_info, .get_module_eeprom = bnxt_get_module_eeprom, .get_module_eeprom_by_page = bnxt_get_module_eeprom_by_page, + .set_module_eeprom_by_page = bnxt_set_module_eeprom_by_page, .nway_reset = bnxt_nway_reset, .set_phys_id = bnxt_set_phys_id, .self_test = bnxt_self_test, @@ -5131,4 +5550,5 @@ const struct ethtool_ops bnxt_ethtool_ops = { .get_eth_mac_stats = bnxt_get_eth_mac_stats, .get_eth_ctrl_stats = bnxt_get_eth_ctrl_stats, .get_rmon_stats = bnxt_get_rmon_stats, + .get_ts_stats = bnxt_get_ptp_stats, }; |