Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/net/ethernet/broadcom/bnxt/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 155 kB image not shown  

Quelle  bnxt_ethtool.c   Sprache: C

 
/* Broadcom NetXtreme-C/E network driver.
 *
 * Copyright (c) 2014-2016 Broadcom Corporation
 * Copyright (c) 2016-2017 Broadcom Limited
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 */


#include <linux/bitops.h>
#include <linux/ctype.h>
#include <linux/stringify.h>
#include <linux/ethtool.h>
#include <linux/ethtool_netlink.h>
#include <linux/linkmode.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/etherdevice.h>
#include <linux/crc32.h>
#include <linux/firmware.h>
#include <linux/utsname.h>
#include <linux/time.h>
#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 <linux/bnxt/hsi.h>
#include "bnxt.h"
#include "bnxt_hwrm.h"
#include "bnxt_ulp.h"
#include "bnxt_xdp.h"
#include "bnxt_ptp.h"
#include "bnxt_ethtool.h"
#include "bnxt_nvm_defs.h" /* NVRAM content constant and structure defs */
#include "bnxt_fw_hdr.h" /* Firmware hdr constant and structure defs */
#include "bnxt_coredump.h"

#define BNXT_NVM_ERR_MSG(dev, extack, msg)   \
 do {       \
  if (extack)     \
   NL_SET_ERR_MSG_MOD(extack, msg); \
  netdev_err(dev, "%s\n", msg);   \
 } while (0)

static u32 bnxt_get_msglevel(struct net_device *dev)
{
 struct bnxt *bp = netdev_priv(dev);

 return bp->msg_enable;
}

static void bnxt_set_msglevel(struct net_device *dev, u32 value)
{
 struct bnxt *bp = netdev_priv(dev);

 bp->msg_enable = value;
}

static int bnxt_get_coalesce(struct net_device *dev,
        struct ethtool_coalesce *coal,
        struct kernel_ethtool_coalesce *kernel_coal,
        struct netlink_ext_ack *extack)
{
 struct bnxt *bp = netdev_priv(dev);
 struct bnxt_coal *hw_coal;
 u16 mult;

 memset(coal, 0, sizeof(*coal));

 coal->use_adaptive_rx_coalesce = bp->flags & BNXT_FLAG_DIM;

 hw_coal = &bp->rx_coal;
 mult = hw_coal->bufs_per_record;
 coal->rx_coalesce_usecs = hw_coal->coal_ticks;
 coal->rx_max_coalesced_frames = hw_coal->coal_bufs / mult;
 coal->rx_coalesce_usecs_irq = hw_coal->coal_ticks_irq;
 coal->rx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult;
 if (hw_coal->flags &
     RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET)
  kernel_coal->use_cqe_mode_rx = true;

 hw_coal = &bp->tx_coal;
 mult = hw_coal->bufs_per_record;
 coal->tx_coalesce_usecs = hw_coal->coal_ticks;
 coal->tx_max_coalesced_frames = hw_coal->coal_bufs / mult;
 coal->tx_coalesce_usecs_irq = hw_coal->coal_ticks_irq;
 coal->tx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult;
 if (hw_coal->flags &
     RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET)
  kernel_coal->use_cqe_mode_tx = true;

 coal->stats_block_coalesce_usecs = bp->stats_coal_ticks;

 return 0;
}

static int bnxt_set_coalesce(struct net_device *dev,
        struct ethtool_coalesce *coal,
        struct kernel_ethtool_coalesce *kernel_coal,
        struct netlink_ext_ack *extack)
{
 struct bnxt *bp = netdev_priv(dev);
 bool update_stats = false;
 struct bnxt_coal *hw_coal;
 int rc = 0;
 u16 mult;

 if (coal->use_adaptive_rx_coalesce) {
  bp->flags |= BNXT_FLAG_DIM;
 } else {
  if (bp->flags & BNXT_FLAG_DIM) {
   bp->flags &= ~(BNXT_FLAG_DIM);
   goto reset_coalesce;
  }
 }

 if ((kernel_coal->use_cqe_mode_rx || kernel_coal->use_cqe_mode_tx) &&
     !(bp->coal_cap.cmpl_params &
       RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_TIMER_RESET))
  return -EOPNOTSUPP;

 hw_coal = &bp->rx_coal;
 mult = hw_coal->bufs_per_record;
 hw_coal->coal_ticks = coal->rx_coalesce_usecs;
 hw_coal->coal_bufs = coal->rx_max_coalesced_frames * mult;
 hw_coal->coal_ticks_irq = coal->rx_coalesce_usecs_irq;
 hw_coal->coal_bufs_irq = coal->rx_max_coalesced_frames_irq * mult;
 hw_coal->flags &=
  ~RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET;
 if (kernel_coal->use_cqe_mode_rx)
  hw_coal->flags |=
   RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET;

 hw_coal = &bp->tx_coal;
 mult = hw_coal->bufs_per_record;
 hw_coal->coal_ticks = coal->tx_coalesce_usecs;
 hw_coal->coal_bufs = coal->tx_max_coalesced_frames * mult;
 hw_coal->coal_ticks_irq = coal->tx_coalesce_usecs_irq;
 hw_coal->coal_bufs_irq = coal->tx_max_coalesced_frames_irq * mult;
 hw_coal->flags &=
  ~RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET;
 if (kernel_coal->use_cqe_mode_tx)
  hw_coal->flags |=
   RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET;

 if (bp->stats_coal_ticks != coal->stats_block_coalesce_usecs) {
  u32 stats_ticks = coal->stats_block_coalesce_usecs;

  /* Allow 0, which means disable. */
  if (stats_ticks)
   stats_ticks = clamp_t(u32, stats_ticks,
           BNXT_MIN_STATS_COAL_TICKS,
           BNXT_MAX_STATS_COAL_TICKS);
  stats_ticks = rounddown(stats_ticks, BNXT_MIN_STATS_COAL_TICKS);
  bp->stats_coal_ticks = stats_ticks;
  if (bp->stats_coal_ticks)
   bp->current_interval =
    bp->stats_coal_ticks * HZ / 1000000;
  else
   bp->current_interval = BNXT_TIMER_INTERVAL;
  update_stats = true;
 }

reset_coalesce:
 if (test_bit(BNXT_STATE_OPEN, &bp->state)) {
  if (update_stats) {
   bnxt_close_nic(bp, truefalse);
   rc = bnxt_open_nic(bp, truefalse);
  } else {
   rc = bnxt_hwrm_set_coal(bp);
  }
 }

 return rc;
}

static const char * const bnxt_ring_rx_stats_str[] = {
 "rx_ucast_packets",
 "rx_mcast_packets",
 "rx_bcast_packets",
 "rx_discards",
 "rx_errors",
 "rx_ucast_bytes",
 "rx_mcast_bytes",
 "rx_bcast_bytes",
};

static const char * const bnxt_ring_tx_stats_str[] = {
 "tx_ucast_packets",
 "tx_mcast_packets",
 "tx_bcast_packets",
 "tx_errors",
 "tx_discards",
 "tx_ucast_bytes",
 "tx_mcast_bytes",
 "tx_bcast_bytes",
};

static const char * const bnxt_ring_tpa_stats_str[] = {
 "tpa_packets",
 "tpa_bytes",
 "tpa_events",
 "tpa_aborts",
};

static const char * const bnxt_ring_tpa2_stats_str[] = {
 "rx_tpa_eligible_pkt",
 "rx_tpa_eligible_bytes",
 "rx_tpa_pkt",
 "rx_tpa_bytes",
 "rx_tpa_errors",
 "rx_tpa_events",
};

static const char * const bnxt_rx_sw_stats_str[] = {
 "rx_l4_csum_errors",
 "rx_resets",
 "rx_buf_errors",
};

static const char * const bnxt_cmn_sw_stats_str[] = {
 "missed_irqs",
};

#define BNXT_RX_STATS_ENTRY(counter) \
 { BNXT_RX_STATS_OFFSET(counter), __stringify(counter) }

#define BNXT_TX_STATS_ENTRY(counter) \
 { BNXT_TX_STATS_OFFSET(counter), __stringify(counter) }

#define BNXT_RX_STATS_EXT_ENTRY(counter) \
 { BNXT_RX_STATS_EXT_OFFSET(counter), __stringify(counter) }

#define BNXT_TX_STATS_EXT_ENTRY(counter) \
 { BNXT_TX_STATS_EXT_OFFSET(counter), __stringify(counter) }

#define BNXT_RX_STATS_EXT_PFC_ENTRY(n)    \
 BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_duration_us), \
 BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_transitions)

#define BNXT_TX_STATS_EXT_PFC_ENTRY(n)    \
 BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_duration_us), \
 BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_transitions)

#define BNXT_RX_STATS_EXT_PFC_ENTRIES    \
 BNXT_RX_STATS_EXT_PFC_ENTRY(0),    \
 BNXT_RX_STATS_EXT_PFC_ENTRY(1),    \
 BNXT_RX_STATS_EXT_PFC_ENTRY(2),    \
 BNXT_RX_STATS_EXT_PFC_ENTRY(3),    \
 BNXT_RX_STATS_EXT_PFC_ENTRY(4),    \
 BNXT_RX_STATS_EXT_PFC_ENTRY(5),    \
 BNXT_RX_STATS_EXT_PFC_ENTRY(6),    \
 BNXT_RX_STATS_EXT_PFC_ENTRY(7)

#define BNXT_TX_STATS_EXT_PFC_ENTRIES    \
 BNXT_TX_STATS_EXT_PFC_ENTRY(0),    \
 BNXT_TX_STATS_EXT_PFC_ENTRY(1),    \
 BNXT_TX_STATS_EXT_PFC_ENTRY(2),    \
 BNXT_TX_STATS_EXT_PFC_ENTRY(3),    \
 BNXT_TX_STATS_EXT_PFC_ENTRY(4),    \
 BNXT_TX_STATS_EXT_PFC_ENTRY(5),    \
 BNXT_TX_STATS_EXT_PFC_ENTRY(6),    \
 BNXT_TX_STATS_EXT_PFC_ENTRY(7)

#define BNXT_RX_STATS_EXT_COS_ENTRY(n)    \
 BNXT_RX_STATS_EXT_ENTRY(rx_bytes_cos##n),  \
 BNXT_RX_STATS_EXT_ENTRY(rx_packets_cos##n)

#define BNXT_TX_STATS_EXT_COS_ENTRY(n)    \
 BNXT_TX_STATS_EXT_ENTRY(tx_bytes_cos##n),  \
 BNXT_TX_STATS_EXT_ENTRY(tx_packets_cos##n)

#define BNXT_RX_STATS_EXT_COS_ENTRIES    \
 BNXT_RX_STATS_EXT_COS_ENTRY(0),    \
 BNXT_RX_STATS_EXT_COS_ENTRY(1),    \
 BNXT_RX_STATS_EXT_COS_ENTRY(2),    \
 BNXT_RX_STATS_EXT_COS_ENTRY(3),    \
 BNXT_RX_STATS_EXT_COS_ENTRY(4),    \
 BNXT_RX_STATS_EXT_COS_ENTRY(5),    \
 BNXT_RX_STATS_EXT_COS_ENTRY(6),    \
 BNXT_RX_STATS_EXT_COS_ENTRY(7)    \

#define BNXT_TX_STATS_EXT_COS_ENTRIES    \
 BNXT_TX_STATS_EXT_COS_ENTRY(0),    \
 BNXT_TX_STATS_EXT_COS_ENTRY(1),    \
 BNXT_TX_STATS_EXT_COS_ENTRY(2),    \
 BNXT_TX_STATS_EXT_COS_ENTRY(3),    \
 BNXT_TX_STATS_EXT_COS_ENTRY(4),    \
 BNXT_TX_STATS_EXT_COS_ENTRY(5),    \
 BNXT_TX_STATS_EXT_COS_ENTRY(6),    \
 BNXT_TX_STATS_EXT_COS_ENTRY(7)    \

#define BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(n)   \
 BNXT_RX_STATS_EXT_ENTRY(rx_discard_bytes_cos##n), \
 BNXT_RX_STATS_EXT_ENTRY(rx_discard_packets_cos##n)

#define BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES    \
 BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(0),    \
 BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(1),    \
 BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(2),    \
 BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(3),    \
 BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(4),    \
 BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(5),    \
 BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(6),    \
 BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(7)

#define BNXT_RX_STATS_PRI_ENTRY(counter, n)  \
 { BNXT_RX_STATS_EXT_OFFSET(counter##_cos0), \
   __stringify(counter##_pri##n) }

#define BNXT_TX_STATS_PRI_ENTRY(counter, n)  \
 { BNXT_TX_STATS_EXT_OFFSET(counter##_cos0), \
   __stringify(counter##_pri##n) }

#define BNXT_RX_STATS_PRI_ENTRIES(counter)  \
 BNXT_RX_STATS_PRI_ENTRY(counter, 0),  \
 BNXT_RX_STATS_PRI_ENTRY(counter, 1),  \
 BNXT_RX_STATS_PRI_ENTRY(counter, 2),  \
 BNXT_RX_STATS_PRI_ENTRY(counter, 3),  \
 BNXT_RX_STATS_PRI_ENTRY(counter, 4),  \
 BNXT_RX_STATS_PRI_ENTRY(counter, 5),  \
 BNXT_RX_STATS_PRI_ENTRY(counter, 6),  \
 BNXT_RX_STATS_PRI_ENTRY(counter, 7)

#define BNXT_TX_STATS_PRI_ENTRIES(counter)  \
 BNXT_TX_STATS_PRI_ENTRY(counter, 0),  \
 BNXT_TX_STATS_PRI_ENTRY(counter, 1),  \
 BNXT_TX_STATS_PRI_ENTRY(counter, 2),  \
 BNXT_TX_STATS_PRI_ENTRY(counter, 3),  \
 BNXT_TX_STATS_PRI_ENTRY(counter, 4),  \
 BNXT_TX_STATS_PRI_ENTRY(counter, 5),  \
 BNXT_TX_STATS_PRI_ENTRY(counter, 6),  \
 BNXT_TX_STATS_PRI_ENTRY(counter, 7)

enum {
 RX_TOTAL_DISCARDS,
 TX_TOTAL_DISCARDS,
 RX_NETPOLL_DISCARDS,
};

static const char *const bnxt_ring_err_stats_arr[] = {
 "rx_total_l4_csum_errors",
 "rx_total_resets",
 "rx_total_buf_errors",
 "rx_total_oom_discards",
 "rx_total_netpoll_discards",
 "rx_total_ring_discards",
 "tx_total_resets",
 "tx_total_ring_discards",
 "total_missed_irqs",
};

#define NUM_RING_RX_SW_STATS  ARRAY_SIZE(bnxt_rx_sw_stats_str)
#define NUM_RING_CMN_SW_STATS  ARRAY_SIZE(bnxt_cmn_sw_stats_str)
#define NUM_RING_RX_HW_STATS  ARRAY_SIZE(bnxt_ring_rx_stats_str)
#define NUM_RING_TX_HW_STATS  ARRAY_SIZE(bnxt_ring_tx_stats_str)

static const struct {
 long offset;
 char string[ETH_GSTRING_LEN];
} bnxt_port_stats_arr[] = {
 BNXT_RX_STATS_ENTRY(rx_64b_frames),
 BNXT_RX_STATS_ENTRY(rx_65b_127b_frames),
 BNXT_RX_STATS_ENTRY(rx_128b_255b_frames),
 BNXT_RX_STATS_ENTRY(rx_256b_511b_frames),
 BNXT_RX_STATS_ENTRY(rx_512b_1023b_frames),
 BNXT_RX_STATS_ENTRY(rx_1024b_1518b_frames),
 BNXT_RX_STATS_ENTRY(rx_good_vlan_frames),
 BNXT_RX_STATS_ENTRY(rx_1519b_2047b_frames),
 BNXT_RX_STATS_ENTRY(rx_2048b_4095b_frames),
 BNXT_RX_STATS_ENTRY(rx_4096b_9216b_frames),
 BNXT_RX_STATS_ENTRY(rx_9217b_16383b_frames),
 BNXT_RX_STATS_ENTRY(rx_total_frames),
 BNXT_RX_STATS_ENTRY(rx_ucast_frames),
 BNXT_RX_STATS_ENTRY(rx_mcast_frames),
 BNXT_RX_STATS_ENTRY(rx_bcast_frames),
 BNXT_RX_STATS_ENTRY(rx_fcs_err_frames),
 BNXT_RX_STATS_ENTRY(rx_ctrl_frames),
 BNXT_RX_STATS_ENTRY(rx_pause_frames),
 BNXT_RX_STATS_ENTRY(rx_pfc_frames),
 BNXT_RX_STATS_ENTRY(rx_align_err_frames),
 BNXT_RX_STATS_ENTRY(rx_ovrsz_frames),
 BNXT_RX_STATS_ENTRY(rx_jbr_frames),
 BNXT_RX_STATS_ENTRY(rx_mtu_err_frames),
 BNXT_RX_STATS_ENTRY(rx_tagged_frames),
 BNXT_RX_STATS_ENTRY(rx_double_tagged_frames),
 BNXT_RX_STATS_ENTRY(rx_good_frames),
 BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri0),
 BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri1),
 BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri2),
 BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri3),
 BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri4),
 BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri5),
 BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri6),
 BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri7),
 BNXT_RX_STATS_ENTRY(rx_undrsz_frames),
 BNXT_RX_STATS_ENTRY(rx_eee_lpi_events),
 BNXT_RX_STATS_ENTRY(rx_eee_lpi_duration),
 BNXT_RX_STATS_ENTRY(rx_bytes),
 BNXT_RX_STATS_ENTRY(rx_runt_bytes),
 BNXT_RX_STATS_ENTRY(rx_runt_frames),
 BNXT_RX_STATS_ENTRY(rx_stat_discard),
 BNXT_RX_STATS_ENTRY(rx_stat_err),

 BNXT_TX_STATS_ENTRY(tx_64b_frames),
 BNXT_TX_STATS_ENTRY(tx_65b_127b_frames),
 BNXT_TX_STATS_ENTRY(tx_128b_255b_frames),
 BNXT_TX_STATS_ENTRY(tx_256b_511b_frames),
 BNXT_TX_STATS_ENTRY(tx_512b_1023b_frames),
 BNXT_TX_STATS_ENTRY(tx_1024b_1518b_frames),
 BNXT_TX_STATS_ENTRY(tx_good_vlan_frames),
 BNXT_TX_STATS_ENTRY(tx_1519b_2047b_frames),
 BNXT_TX_STATS_ENTRY(tx_2048b_4095b_frames),
 BNXT_TX_STATS_ENTRY(tx_4096b_9216b_frames),
 BNXT_TX_STATS_ENTRY(tx_9217b_16383b_frames),
 BNXT_TX_STATS_ENTRY(tx_good_frames),
 BNXT_TX_STATS_ENTRY(tx_total_frames),
 BNXT_TX_STATS_ENTRY(tx_ucast_frames),
 BNXT_TX_STATS_ENTRY(tx_mcast_frames),
 BNXT_TX_STATS_ENTRY(tx_bcast_frames),
 BNXT_TX_STATS_ENTRY(tx_pause_frames),
 BNXT_TX_STATS_ENTRY(tx_pfc_frames),
 BNXT_TX_STATS_ENTRY(tx_jabber_frames),
 BNXT_TX_STATS_ENTRY(tx_fcs_err_frames),
 BNXT_TX_STATS_ENTRY(tx_err),
 BNXT_TX_STATS_ENTRY(tx_fifo_underruns),
 BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri0),
 BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri1),
 BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri2),
 BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri3),
 BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri4),
 BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri5),
 BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri6),
 BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri7),
 BNXT_TX_STATS_ENTRY(tx_eee_lpi_events),
 BNXT_TX_STATS_ENTRY(tx_eee_lpi_duration),
 BNXT_TX_STATS_ENTRY(tx_total_collisions),
 BNXT_TX_STATS_ENTRY(tx_bytes),
 BNXT_TX_STATS_ENTRY(tx_xthol_frames),
 BNXT_TX_STATS_ENTRY(tx_stat_discard),
 BNXT_TX_STATS_ENTRY(tx_stat_error),
};

static const struct {
 long offset;
 char string[ETH_GSTRING_LEN];
} bnxt_port_stats_ext_arr[] = {
 BNXT_RX_STATS_EXT_ENTRY(link_down_events),
 BNXT_RX_STATS_EXT_ENTRY(continuous_pause_events),
 BNXT_RX_STATS_EXT_ENTRY(resume_pause_events),
 BNXT_RX_STATS_EXT_ENTRY(continuous_roce_pause_events),
 BNXT_RX_STATS_EXT_ENTRY(resume_roce_pause_events),
 BNXT_RX_STATS_EXT_COS_ENTRIES,
 BNXT_RX_STATS_EXT_PFC_ENTRIES,
 BNXT_RX_STATS_EXT_ENTRY(rx_bits),
 BNXT_RX_STATS_EXT_ENTRY(rx_buffer_passed_threshold),
 BNXT_RX_STATS_EXT_ENTRY(rx_pcs_symbol_err),
 BNXT_RX_STATS_EXT_ENTRY(rx_corrected_bits),
 BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES,
 BNXT_RX_STATS_EXT_ENTRY(rx_fec_corrected_blocks),
 BNXT_RX_STATS_EXT_ENTRY(rx_fec_uncorrectable_blocks),
 BNXT_RX_STATS_EXT_ENTRY(rx_filter_miss),
};

static const struct {
 long offset;
 char string[ETH_GSTRING_LEN];
} bnxt_tx_port_stats_ext_arr[] = {
 BNXT_TX_STATS_EXT_COS_ENTRIES,
 BNXT_TX_STATS_EXT_PFC_ENTRIES,
};

static const struct {
 long base_off;
 char string[ETH_GSTRING_LEN];
} bnxt_rx_bytes_pri_arr[] = {
 BNXT_RX_STATS_PRI_ENTRIES(rx_bytes),
};

static const struct {
 long base_off;
 char string[ETH_GSTRING_LEN];
} bnxt_rx_pkts_pri_arr[] = {
 BNXT_RX_STATS_PRI_ENTRIES(rx_packets),
};

static const struct {
 long base_off;
 char string[ETH_GSTRING_LEN];
} bnxt_tx_bytes_pri_arr[] = {
 BNXT_TX_STATS_PRI_ENTRIES(tx_bytes),
};

static const struct {
 long base_off;
 char string[ETH_GSTRING_LEN];
} bnxt_tx_pkts_pri_arr[] = {
 BNXT_TX_STATS_PRI_ENTRIES(tx_packets),
};

#define BNXT_NUM_RING_ERR_STATS ARRAY_SIZE(bnxt_ring_err_stats_arr)
#define BNXT_NUM_PORT_STATS ARRAY_SIZE(bnxt_port_stats_arr)
#define BNXT_NUM_STATS_PRI   \
 (ARRAY_SIZE(bnxt_rx_bytes_pri_arr) + \
  ARRAY_SIZE(bnxt_rx_pkts_pri_arr) + \
  ARRAY_SIZE(bnxt_tx_bytes_pri_arr) + \
  ARRAY_SIZE(bnxt_tx_pkts_pri_arr))

static int bnxt_get_num_tpa_ring_stats(struct bnxt *bp)
{
 if (BNXT_SUPPORTS_TPA(bp)) {
  if (bp->max_tpa_v2) {
   if (BNXT_CHIP_P5(bp))
    return BNXT_NUM_TPA_RING_STATS_P5;
   return BNXT_NUM_TPA_RING_STATS_P7;
  }
  return BNXT_NUM_TPA_RING_STATS;
 }
 return 0;
}

static int bnxt_get_num_ring_stats(struct bnxt *bp)
{
 int rx, tx, cmn;

 rx = NUM_RING_RX_HW_STATS + NUM_RING_RX_SW_STATS +
      bnxt_get_num_tpa_ring_stats(bp);
 tx = NUM_RING_TX_HW_STATS;
 cmn = NUM_RING_CMN_SW_STATS;
 return rx * bp->rx_nr_rings +
        tx * (bp->tx_nr_rings_xdp + bp->tx_nr_rings_per_tc) +
        cmn * bp->cp_nr_rings;
}

static int bnxt_get_num_stats(struct bnxt *bp)
{
 int num_stats = bnxt_get_num_ring_stats(bp);
 int len;

 num_stats += BNXT_NUM_RING_ERR_STATS;

 if (bp->flags & BNXT_FLAG_PORT_STATS)
  num_stats += BNXT_NUM_PORT_STATS;

 if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) {
  len = min_t(int, bp->fw_rx_stats_ext_size,
       ARRAY_SIZE(bnxt_port_stats_ext_arr));
  num_stats += len;
  len = min_t(int, bp->fw_tx_stats_ext_size,
       ARRAY_SIZE(bnxt_tx_port_stats_ext_arr));
  num_stats += len;
  if (bp->pri2cos_valid)
   num_stats += BNXT_NUM_STATS_PRI;
 }

 return num_stats;
}

static int bnxt_get_sset_count(struct net_device *dev, int sset)
{
 struct bnxt *bp = netdev_priv(dev);

 switch (sset) {
 case ETH_SS_STATS:
  return bnxt_get_num_stats(bp);
 case ETH_SS_TEST:
  if (!bp->num_tests)
   return -EOPNOTSUPP;
  return bp->num_tests;
 default:
  return -EOPNOTSUPP;
 }
}

static bool is_rx_ring(struct bnxt *bp, int ring_num)
{
 return ring_num < bp->rx_nr_rings;
}

static bool is_tx_ring(struct bnxt *bp, int ring_num)
{
 int tx_base = 0;

 if (!(bp->flags & BNXT_FLAG_SHARED_RINGS))
  tx_base = bp->rx_nr_rings;

 if (ring_num >= tx_base && ring_num < (tx_base + bp->tx_nr_rings))
  return true;
 return false;
}

static void bnxt_get_ethtool_stats(struct net_device *dev,
       struct ethtool_stats *stats, u64 *buf)
{
 struct bnxt_total_ring_err_stats ring_err_stats = {0};
 struct bnxt *bp = netdev_priv(dev);
 u64 *curr, *prev;
 u32 tpa_stats;
 u32 i, j = 0;

 if (!bp->bnapi) {
  j += bnxt_get_num_ring_stats(bp);
  goto skip_ring_stats;
 }

 tpa_stats = bnxt_get_num_tpa_ring_stats(bp);
 for (i = 0; i < bp->cp_nr_rings; i++) {
  struct bnxt_napi *bnapi = bp->bnapi[i];
  struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
  u64 *sw_stats = cpr->stats.sw_stats;
  u64 *sw;
  int k;

  if (is_rx_ring(bp, i)) {
   for (k = 0; k < NUM_RING_RX_HW_STATS; j++, k++)
    buf[j] = sw_stats[k];
  }
  if (is_tx_ring(bp, i)) {
   k = NUM_RING_RX_HW_STATS;
   for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS;
          j++, k++)
    buf[j] = sw_stats[k];
  }
  if (!tpa_stats || !is_rx_ring(bp, i))
   goto skip_tpa_ring_stats;

  k = NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS;
  for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS +
      tpa_stats; j++, k++)
   buf[j] = sw_stats[k];

skip_tpa_ring_stats:
  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;
  for (k = 0; k < NUM_RING_CMN_SW_STATS; j++, k++)
   buf[j] = sw[k];
 }

 bnxt_get_ring_err_stats(bp, &ring_err_stats);

skip_ring_stats:
 curr = &ring_err_stats.rx_total_l4_csum_errors;
 prev = &bp->ring_err_stats_prev.rx_total_l4_csum_errors;
 for (i = 0; i < BNXT_NUM_RING_ERR_STATS; i++, j++, curr++, prev++)
  buf[j] = *curr + *prev;

 if (bp->flags & BNXT_FLAG_PORT_STATS) {
  u64 *port_stats = bp->port_stats.sw_stats;

  for (i = 0; i < BNXT_NUM_PORT_STATS; i++, j++)
   buf[j] = *(port_stats + bnxt_port_stats_arr[i].offset);
 }
 if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) {
  u64 *rx_port_stats_ext = bp->rx_port_stats_ext.sw_stats;
  u64 *tx_port_stats_ext = bp->tx_port_stats_ext.sw_stats;
  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++, j++) {
   buf[j] = *(rx_port_stats_ext +
       bnxt_port_stats_ext_arr[i].offset);
  }
  len = min_t(u32, bp->fw_tx_stats_ext_size,
       ARRAY_SIZE(bnxt_tx_port_stats_ext_arr));
  for (i = 0; i < len; i++, j++) {
   buf[j] = *(tx_port_stats_ext +
       bnxt_tx_port_stats_ext_arr[i].offset);
  }
  if (bp->pri2cos_valid) {
   for (i = 0; i < 8; i++, j++) {
    long n = bnxt_rx_bytes_pri_arr[i].base_off +
      bp->pri2cos_idx[i];

    buf[j] = *(rx_port_stats_ext + n);
   }
   for (i = 0; i < 8; i++, j++) {
    long n = bnxt_rx_pkts_pri_arr[i].base_off +
      bp->pri2cos_idx[i];

    buf[j] = *(rx_port_stats_ext + n);
   }
   for (i = 0; i < 8; i++, j++) {
    long n = bnxt_tx_bytes_pri_arr[i].base_off +
      bp->pri2cos_idx[i];

    buf[j] = *(tx_port_stats_ext + n);
   }
   for (i = 0; i < 8; i++, j++) {
    long n = bnxt_tx_pkts_pri_arr[i].base_off +
      bp->pri2cos_idx[i];

    buf[j] = *(tx_port_stats_ext + n);
   }
  }
 }
}

static void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
{
 struct bnxt *bp = netdev_priv(dev);
 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))
    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))
    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)
    for (j = 0; j < num_str; j++) {
     str = bnxt_ring_tpa2_stats_str[j];
     ethtool_sprintf(&buf, "[%d]: %s", i,
       str);
    }
   else
    for (j = 0; j < num_str; j++) {
     str = bnxt_ring_tpa_stats_str[j];
     ethtool_sprintf(&buf, "[%d]: %s", i,
       str);
    }
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++)
   ethtool_puts(&buf, bnxt_ring_err_stats_arr[i]);

  if (bp->flags & BNXT_FLAG_PORT_STATS)
   for (i = 0; i < BNXT_NUM_PORT_STATS; i++) {
    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++) {
    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++) {
    str = bnxt_tx_port_stats_ext_arr[i].string;
    ethtool_puts(&buf, str);
   }

   if (bp->pri2cos_valid) {
    for (i = 0; i < 8; i++) {
     str = bnxt_rx_bytes_pri_arr[i].string;
     ethtool_puts(&buf, str);
    }

    for (i = 0; i < 8; i++) {
     str = bnxt_rx_pkts_pri_arr[i].string;
     ethtool_puts(&buf, str);
    }

    for (i = 0; i < 8; i++) {
     str = bnxt_tx_bytes_pri_arr[i].string;
     ethtool_puts(&buf, str);
    }

    for (i = 0; i < 8; i++) {
     str = bnxt_tx_pkts_pri_arr[i].string;
     ethtool_puts(&buf, str);
    }
   }
  }
  break;
 case ETH_SS_TEST:
  if (bp->num_tests)
   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",
      stringset);
  break;
 }
}

static void bnxt_get_ringparam(struct net_device *dev,
          struct ethtool_ringparam *ering,
          struct kernel_ethtool_ringparam *kernel_ering,
          struct netlink_ext_ack *extack)
{
 struct bnxt *bp = netdev_priv(dev);

 if (bp->flags & BNXT_FLAG_AGG_RINGS) {
  ering->rx_max_pending = BNXT_MAX_RX_DESC_CNT_JUM_ENA;
  ering->rx_jumbo_max_pending = BNXT_MAX_RX_JUM_DESC_CNT;
  kernel_ering->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_ENABLED;
 } else {
  ering->rx_max_pending = BNXT_MAX_RX_DESC_CNT;
  ering->rx_jumbo_max_pending = 0;
  kernel_ering->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_DISABLED;
 }
 ering->tx_max_pending = BNXT_MAX_TX_DESC_CNT;

 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,
         struct ethtool_ringparam *ering,
         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, falsefalse);

 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);

 if (netif_running(dev))
  return bnxt_open_nic(bp, falsefalse);

 return 0;
}

static void bnxt_get_channels(struct net_device *dev,
         struct ethtool_channels *channel)
{
 struct bnxt *bp = netdev_priv(dev);
 struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
 int max_rx_rings, max_tx_rings, tcs;
 int max_tx_sch_inputs, tx_grps;

 /* Get the most up-to-date max_tx_sch_inputs. */
 if (netif_running(dev) && BNXT_NEW_RM(bp))
  bnxt_hwrm_func_resc_qcaps(bp, false);
 max_tx_sch_inputs = hw_resc->max_tx_sch_inputs;

 bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, true);
 if (max_tx_sch_inputs)
  max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs);

 tcs = bp->num_tc;
 tx_grps = max(tcs, 1);
 if (bp->tx_nr_rings_xdp)
  tx_grps++;
 max_tx_rings /= tx_grps;
 channel->max_combined = min_t(int, max_rx_rings, max_tx_rings);

 if (bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, false)) {
  max_rx_rings = 0;
  max_tx_rings = 0;
 }
 if (max_tx_sch_inputs)
  max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs);

 if (tcs > 1)
  max_tx_rings /= tcs;

 channel->max_rx = max_rx_rings;
 channel->max_tx = max_tx_rings;
 channel->max_other = 0;
 if (bp->flags & BNXT_FLAG_SHARED_RINGS) {
  channel->combined_count = bp->rx_nr_rings;
  if (BNXT_CHIP_TYPE_NITRO_A0(bp))
   channel->combined_count--;
 } else {
  if (!BNXT_CHIP_TYPE_NITRO_A0(bp)) {
   channel->rx_count = bp->rx_nr_rings;
   channel->tx_count = bp->tx_nr_rings_per_tc;
  }
 }
}

static int bnxt_set_channels(struct net_device *dev,
        struct ethtool_channels *channel)
{
 struct bnxt *bp = netdev_priv(dev);
 int req_tx_rings, req_rx_rings, tcs;
 bool sh = false;
 int tx_xdp = 0;
 int rc = 0;
 int tx_cp;

 if (channel->other_count)
  return -EINVAL;

 if (!channel->combined_count &&
     (!channel->rx_count || !channel->tx_count))
  return -EINVAL;

 if (channel->combined_count &&
     (channel->rx_count || channel->tx_count))
  return -EINVAL;

 if (BNXT_CHIP_TYPE_NITRO_A0(bp) && (channel->rx_count ||
         channel->tx_count))
  return -EINVAL;

 if (channel->combined_count)
  sh = true;

 tcs = bp->num_tc;

 req_tx_rings = sh ? channel->combined_count : channel->tx_count;
 req_rx_rings = sh ? channel->combined_count : channel->rx_count;
 if (bp->tx_nr_rings_xdp) {
  if (!sh) {
   netdev_err(dev, "Only combined mode supported when XDP is enabled.\n");
   return -EINVAL;
  }
  tx_xdp = req_rx_rings;
 }

 if (bnxt_get_nr_rss_ctxs(bp, req_rx_rings) !=
     bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings) &&
     netif_is_rxfh_configured(dev)) {
  netdev_warn(dev, "RSS table size change required, RSS table entries must be default to proceed\n");
  return -EINVAL;
 }

 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
 * before PF unload
 */

  }
  bnxt_close_nic(bp, truefalse);
 }

 if (sh) {
  bp->flags |= BNXT_FLAG_SHARED_RINGS;
  bp->rx_nr_rings = channel->combined_count;
  bp->tx_nr_rings_per_tc = channel->combined_count;
 } else {
  bp->flags &= ~BNXT_FLAG_SHARED_RINGS;
  bp->rx_nr_rings = channel->rx_count;
  bp->tx_nr_rings_per_tc = channel->tx_count;
 }
 bp->tx_nr_rings_xdp = tx_xdp;
 bp->tx_nr_rings = bp->tx_nr_rings_per_tc + tx_xdp;
 if (tcs > 1)
  bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs + tx_xdp;

 tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings);
 bp->cp_nr_rings = sh ? max_t(int, tx_cp, bp->rx_nr_rings) :
          tx_cp + bp->rx_nr_rings;

 /* After changing number of rx channels, update NTUPLE feature. */
 netdev_update_features(dev);
 if (netif_running(dev)) {
  rc = bnxt_open_nic(bp, truefalse);
  if ((!rc) && BNXT_PF(bp)) {
   /* TODO CHIMP_FW: Send message to all VF's
 * to renable
 */

  }
 } else {
  rc = bnxt_reserve_rings(bp, true);
 }

 return rc;
}

static u32 bnxt_get_all_fltr_ids_rcu(struct bnxt *bp, struct hlist_head tbl[],
         int tbl_size, u32 *ids, u32 start,
         u32 id_cnt)
{
 int i, j = start;

 if (j >= id_cnt)
  return j;
 for (i = 0; i < tbl_size; i++) {
  struct hlist_head *head;
  struct bnxt_filter_base *fltr;

  head = &tbl[i];
  hlist_for_each_entry_rcu(fltr, head, hash) {
   if (!fltr->flags ||
       test_bit(BNXT_FLTR_FW_DELETED, &fltr->state))
    continue;
   ids[j++] = fltr->sw_id;
   if (j == id_cnt)
    return j;
  }
 }
 return j;
}

static struct bnxt_filter_base *bnxt_get_one_fltr_rcu(struct bnxt *bp,
            struct hlist_head tbl[],
            int tbl_size, u32 id)
{
 int i;

 for (i = 0; i < tbl_size; i++) {
  struct hlist_head *head;
  struct bnxt_filter_base *fltr;

  head = &tbl[i];
  hlist_for_each_entry_rcu(fltr, head, hash) {
   if (fltr->flags && fltr->sw_id == id)
    return fltr;
  }
 }
 return NULL;
}

static int bnxt_grxclsrlall(struct bnxt *bp, struct ethtool_rxnfc *cmd,
       u32 *rule_locs)
{
 u32 count;

 cmd->data = bp->ntp_fltr_count;
 rcu_read_lock();
 count = bnxt_get_all_fltr_ids_rcu(bp, bp->l2_fltr_hash_tbl,
       BNXT_L2_FLTR_HASH_SIZE, rule_locs, 0,
       cmd->rule_cnt);
 cmd->rule_cnt = bnxt_get_all_fltr_ids_rcu(bp, bp->ntp_fltr_hash_tbl,
        BNXT_NTP_FLTR_HASH_SIZE,
        rule_locs, count,
        cmd->rule_cnt);
 rcu_read_unlock();

 return 0;
}

static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd)
{
 struct ethtool_rx_flow_spec *fs =
  (struct ethtool_rx_flow_spec *)&cmd->fs;
 struct bnxt_filter_base *fltr_base;
 struct bnxt_ntuple_filter *fltr;
 struct bnxt_flow_masks *fmasks;
 struct flow_keys *fkeys;
 int rc = -EINVAL;

 if (fs->location >= bp->max_fltr)
  return rc;

 rcu_read_lock();
 fltr_base = bnxt_get_one_fltr_rcu(bp, bp->l2_fltr_hash_tbl,
       BNXT_L2_FLTR_HASH_SIZE,
       fs->location);
 if (fltr_base) {
  struct ethhdr *h_ether = &fs->h_u.ether_spec;
  struct ethhdr *m_ether = &fs->m_u.ether_spec;
  struct bnxt_l2_filter *l2_fltr;
  struct bnxt_l2_key *l2_key;

  l2_fltr = container_of(fltr_base, struct bnxt_l2_filter, base);
  l2_key = &l2_fltr->l2_key;
  fs->flow_type = ETHER_FLOW;
  ether_addr_copy(h_ether->h_dest, l2_key->dst_mac_addr);
  eth_broadcast_addr(m_ether->h_dest);
  if (l2_key->vlan) {
   struct ethtool_flow_ext *m_ext = &fs->m_ext;
   struct ethtool_flow_ext *h_ext = &fs->h_ext;

   fs->flow_type |= FLOW_EXT;
   m_ext->vlan_tci = htons(0xfff);
   h_ext->vlan_tci = htons(l2_key->vlan);
  }
  if (fltr_base->flags & BNXT_ACT_RING_DST)
   fs->ring_cookie = fltr_base->rxq;
  if (fltr_base->flags & BNXT_ACT_FUNC_DST)
   fs->ring_cookie = (u64)(fltr_base->vf_idx + 1) <<
       ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF;
  rcu_read_unlock();
  return 0;
 }
 fltr_base = bnxt_get_one_fltr_rcu(bp, bp->ntp_fltr_hash_tbl,
       BNXT_NTP_FLTR_HASH_SIZE,
       fs->location);
 if (!fltr_base) {
  rcu_read_unlock();
  return rc;
 }
 fltr = container_of(fltr_base, struct bnxt_ntuple_filter, base);

 fkeys = &fltr->fkeys;
 fmasks = &fltr->fmasks;
 if (fkeys->basic.n_proto == htons(ETH_P_IP)) {
  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;
   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;
  } else if (fkeys->basic.ip_proto == IPPROTO_UDP) {
   fs->flow_type = UDP_V4_FLOW;
  } else {
   goto fltr_err;
  }

  fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src;
  fs->m_u.tcp_ip4_spec.ip4src = fmasks->addrs.v4addrs.src;
  fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst;
  fs->m_u.tcp_ip4_spec.ip4dst = fmasks->addrs.v4addrs.dst;
  if (fs->flow_type == TCP_V4_FLOW ||
      fs->flow_type == UDP_V4_FLOW) {
   fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src;
   fs->m_u.tcp_ip4_spec.psrc = fmasks->ports.src;
   fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst;
   fs->m_u.tcp_ip4_spec.pdst = fmasks->ports.dst;
  }
 } else {
  if (fkeys->basic.ip_proto == BNXT_IP_PROTO_WILDCARD) {
   fs->flow_type = IPV6_USER_FLOW;
   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;
  } else if (fkeys->basic.ip_proto == IPPROTO_UDP) {
   fs->flow_type = UDP_V6_FLOW;
  } else {
   goto fltr_err;
  }

  *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] =
   fkeys->addrs.v6addrs.src;
  *(struct in6_addr *)&fs->m_u.tcp_ip6_spec.ip6src[0] =
   fmasks->addrs.v6addrs.src;
  *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6dst[0] =
   fkeys->addrs.v6addrs.dst;
  *(struct in6_addr *)&fs->m_u.tcp_ip6_spec.ip6dst[0] =
   fmasks->addrs.v6addrs.dst;
  if (fs->flow_type == TCP_V6_FLOW ||
      fs->flow_type == UDP_V6_FLOW) {
   fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src;
   fs->m_u.tcp_ip6_spec.psrc = fmasks->ports.src;
   fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst;
   fs->m_u.tcp_ip6_spec.pdst = fmasks->ports.dst;
  }
 }

 if (fltr->base.flags & BNXT_ACT_DROP) {
  fs->ring_cookie = RX_CLS_FLOW_DISC;
 } 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:
 rcu_read_unlock();

 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)
{
 u32 ring = ethtool_get_flow_spec_ring(fs->ring_cookie);
 u8 vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie);
 struct ethhdr *h_ether = &fs->h_u.ether_spec;
 struct ethhdr *m_ether = &fs->m_u.ether_spec;
 struct bnxt_l2_filter *fltr;
 struct bnxt_l2_key key;
 u16 vnic_id;
 u8 flags;
 int rc;

 if (BNXT_CHIP_P5_PLUS(bp))
  return -EOPNOTSUPP;

 if (!is_broadcast_ether_addr(m_ether->h_dest))
  return -EINVAL;
 ether_addr_copy(key.dst_mac_addr, h_ether->h_dest);
 key.vlan = 0;
 if (fs->flow_type & FLOW_EXT) {
  struct ethtool_flow_ext *m_ext = &fs->m_ext;
  struct ethtool_flow_ext *h_ext = &fs->h_ext;

  if (m_ext->vlan_tci != htons(0xfff) || !h_ext->vlan_tci)
   return -EINVAL;
  key.vlan = ntohs(h_ext->vlan_tci);
 }

 if (vf) {
  flags = BNXT_ACT_FUNC_DST;
  vnic_id = 0xffff;
  vf--;
 } else {
  flags = BNXT_ACT_RING_DST;
  vnic_id = bp->vnic_info[ring + 1].fw_vnic_id;
 }
 fltr = bnxt_alloc_new_l2_filter(bp, &key, flags);
 if (IS_ERR(fltr))
  return PTR_ERR(fltr);

 fltr->base.fw_vnic_id = vnic_id;
 fltr->base.rxq = ring;
 fltr->base.vf_idx = vf;
 rc = bnxt_hwrm_l2_filter_alloc(bp, fltr);
 if (rc)
  bnxt_del_l2_filter(bp, fltr);
 else
  fs->location = fltr->base.sw_id;
 return rc;
}

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 ||
     (mproto && (mproto != BNXT_IP_PROTO_FULL_MASK || sproto != IPPROTO_ICMP)))
  return false;
 return true;
}

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 ||
     (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_rxnfc *cmd)
{
 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;
 struct flow_keys *fkeys;
 u32 idx, ring;
 int rc;
 u8 vf;

 if (!bp->vnic_info)
  return -EAGAIN;

 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) {
  if (!bnxt_verify_ntuple_ip4_flow(&fs->h_u.usr_ip4_spec,
       &fs->m_u.usr_ip4_spec))
   return -EOPNOTSUPP;
 }

 if (flow_type == IPV6_USER_FLOW) {
  if (!bnxt_verify_ntuple_ip6_flow(&fs->h_u.usr_ip6_spec,
       &fs->m_u.usr_ip6_spec))
   return -EOPNOTSUPP;
 }

 new_fltr = kzalloc(sizeof(*new_fltr), GFP_KERNEL);
 if (!new_fltr)
  return -ENOMEM;

 l2_fltr = bp->vnic_info[BNXT_VNIC_DEFAULT].l2_filters[0];
 atomic_inc(&l2_fltr->refcnt);
 new_fltr->l2_fltr = l2_fltr;
 fmasks = &new_fltr->fmasks;
 fkeys = &new_fltr->fkeys;

 rc = -EOPNOTSUPP;
 switch (flow_type) {
 case IP_USER_FLOW: {
  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_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;
  fkeys->addrs.v4addrs.dst = ip_spec->ip4dst;
  fmasks->addrs.v4addrs.dst = ip_mask->ip4dst;
  break;
 }
 case TCP_V4_FLOW:
 case UDP_V4_FLOW: {
  struct ethtool_tcpip4_spec *ip_spec = &fs->h_u.tcp_ip4_spec;
  struct ethtool_tcpip4_spec *ip_mask = &fs->m_u.tcp_ip4_spec;

  fkeys->basic.ip_proto = IPPROTO_TCP;
  if (flow_type == UDP_V4_FLOW)
   fkeys->basic.ip_proto = IPPROTO_UDP;
  fkeys->basic.n_proto = htons(ETH_P_IP);
  fkeys->addrs.v4addrs.src = ip_spec->ip4src;
  fmasks->addrs.v4addrs.src = ip_mask->ip4src;
  fkeys->addrs.v4addrs.dst = ip_spec->ip4dst;
  fmasks->addrs.v4addrs.dst = ip_mask->ip4dst;
  fkeys->ports.src = ip_spec->psrc;
  fmasks->ports.src = ip_mask->psrc;
  fkeys->ports.dst = ip_spec->pdst;
  fmasks->ports.dst = ip_mask->pdst;
  break;
 }
 case IPV6_USER_FLOW: {
  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_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;
  fkeys->addrs.v6addrs.dst = *(struct in6_addr *)&ip_spec->ip6dst;
  fmasks->addrs.v6addrs.dst = *(struct in6_addr *)&ip_mask->ip6dst;
  break;
 }
 case TCP_V6_FLOW:
 case UDP_V6_FLOW: {
  struct ethtool_tcpip6_spec *ip_spec = &fs->h_u.tcp_ip6_spec;
  struct ethtool_tcpip6_spec *ip_mask = &fs->m_u.tcp_ip6_spec;

  fkeys->basic.ip_proto = IPPROTO_TCP;
  if (flow_type == UDP_V6_FLOW)
   fkeys->basic.ip_proto = IPPROTO_UDP;
  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;
  fkeys->addrs.v6addrs.dst = *(struct in6_addr *)&ip_spec->ip6dst;
  fmasks->addrs.v6addrs.dst = *(struct in6_addr *)&ip_mask->ip6dst;
  fkeys->ports.src = ip_spec->psrc;
  fmasks->ports.src = ip_mask->psrc;
  fkeys->ports.dst = ip_spec->pdst;
  fmasks->ports.dst = ip_mask->pdst;
  break;
 }
 default:
  rc = -EOPNOTSUPP;
  goto ntuple_err;
 }
 if (!memcmp(&BNXT_FLOW_MASK_NONE, fmasks, sizeof(*fmasks)))
  goto ntuple_err;

 idx = bnxt_get_ntp_filter_idx(bp, fkeys, NULL);
 rcu_read_lock();
 fltr = bnxt_lookup_ntp_filter_from_idx(bp, new_fltr, idx);
 if (fltr) {
  rcu_read_unlock();
  rc = -EEXIST;
  goto ntuple_err;
 }
 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
  new_fltr->base.rxq = ring;
 __set_bit(BNXT_FLTR_VALID, &new_fltr->base.state);
 rc = bnxt_insert_ntp_filter(bp, new_fltr, idx);
 if (!rc) {
  rc = bnxt_hwrm_cfa_ntuple_filter_alloc(bp, new_fltr);
  if (rc) {
   bnxt_del_ntp_filter(bp, new_fltr);
   return rc;
  }
  fs->location = new_fltr->base.sw_id;
  return 0;
 }

ntuple_err:
 atomic_dec(&l2_fltr->refcnt);
 kfree(new_fltr);
 return rc;
}

static int bnxt_srxclsrlins(struct bnxt *bp, struct ethtool_rxnfc *cmd)
{
 struct ethtool_rx_flow_spec *fs = &cmd->fs;
 u32 ring, flow_type;
 int rc;
 u8 vf;

 if (!netif_running(bp->dev))
  return -EAGAIN;
 if (!(bp->flags & BNXT_FLAG_RFS))
  return -EPERM;
 if (fs->location != RX_CLS_LOC_ANY)
  return -EINVAL;

 flow_type = fs->flow_type;
 if ((flow_type == IP_USER_FLOW ||
      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)
  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, cmd);

 ring = ethtool_get_flow_spec_ring(fs->ring_cookie);
 vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie);
 if (BNXT_VF(bp) && vf)
  return -EINVAL;
 if (BNXT_PF(bp) && vf > bp->pf.active_vfs)
  return -EINVAL;
 if (!vf && ring >= bp->rx_nr_rings)
  return -EINVAL;

 if (flow_type == ETHER_FLOW)
  rc = bnxt_add_l2_cls_rule(bp, fs);
 else
  rc = bnxt_add_ntuple_cls_rule(bp, cmd);
 return rc;
}

static int bnxt_srxclsrldel(struct bnxt *bp, struct ethtool_rxnfc *cmd)
{
 struct ethtool_rx_flow_spec *fs = &cmd->fs;
 struct bnxt_filter_base *fltr_base;
 struct bnxt_ntuple_filter *fltr;
 u32 id = fs->location;

 rcu_read_lock();
 fltr_base = bnxt_get_one_fltr_rcu(bp, bp->l2_fltr_hash_tbl,
       BNXT_L2_FLTR_HASH_SIZE, id);
 if (fltr_base) {
  struct bnxt_l2_filter *l2_fltr;

  l2_fltr = container_of(fltr_base, struct bnxt_l2_filter, base);
  rcu_read_unlock();
  bnxt_hwrm_l2_filter_free(bp, l2_fltr);
  bnxt_del_l2_filter(bp, l2_fltr);
  return 0;
 }
 fltr_base = bnxt_get_one_fltr_rcu(bp, bp->ntp_fltr_hash_tbl,
       BNXT_NTP_FLTR_HASH_SIZE, id);
 if (!fltr_base) {
  rcu_read_unlock();
  return -ENOENT;
 }

 fltr = container_of(fltr_base, struct bnxt_ntuple_filter, base);
 if (!(fltr->base.flags & BNXT_ACT_NO_AGING)) {
  rcu_read_unlock();
  return -EINVAL;
 }
 rcu_read_unlock();
 bnxt_hwrm_cfa_ntuple_filter_free(bp, fltr);
 bnxt_del_ntp_filter(bp, fltr);
 return 0;
}

static u64 get_ethtool_ipv4_rss(struct bnxt *bp)
{
 if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4)
  return RXH_IP_SRC | RXH_IP_DST;
 return 0;
}

static u64 get_ethtool_ipv6_rss(struct bnxt *bp)
{
 if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6)
  return RXH_IP_SRC | RXH_IP_DST;
 return 0;
}

static int bnxt_get_rxfh_fields(struct net_device *dev,
    struct ethtool_rxfh_fields *cmd)
{
 struct bnxt *bp = netdev_priv(dev);

 cmd->data = 0;
 switch (cmd->flow_type) {
 case TCP_V4_FLOW:
  if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4)
   cmd->data |= RXH_IP_SRC | RXH_IP_DST |
         RXH_L4_B_0_1 | RXH_L4_B_2_3;
  cmd->data |= get_ethtool_ipv4_rss(bp);
  break;
 case UDP_V4_FLOW:
  if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4)
   cmd->data |= RXH_IP_SRC | RXH_IP_DST |
         RXH_L4_B_0_1 | RXH_L4_B_2_3;
  fallthrough;
 case AH_ESP_V4_FLOW:
  if (bp->rss_hash_cfg &
      (VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV4 |
       VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV4))
   cmd->data |= RXH_IP_SRC | RXH_IP_DST |
         RXH_L4_B_0_1 | RXH_L4_B_2_3;
  fallthrough;
 case SCTP_V4_FLOW:
 case AH_V4_FLOW:
 case ESP_V4_FLOW:
 case IPV4_FLOW:
  cmd->data |= get_ethtool_ipv4_rss(bp);
  break;

 case TCP_V6_FLOW:
  if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6)
   cmd->data |= RXH_IP_SRC | RXH_IP_DST |
         RXH_L4_B_0_1 | RXH_L4_B_2_3;
  cmd->data |= get_ethtool_ipv6_rss(bp);
  break;
 case UDP_V6_FLOW:
  if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6)
   cmd->data |= RXH_IP_SRC | RXH_IP_DST |
         RXH_L4_B_0_1 | RXH_L4_B_2_3;
  fallthrough;
 case AH_ESP_V6_FLOW:
  if (bp->rss_hash_cfg &
      (VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV6 |
       VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV6))
   cmd->data |= RXH_IP_SRC | RXH_IP_DST |
         RXH_L4_B_0_1 | RXH_L4_B_2_3;
  fallthrough;
 case SCTP_V6_FLOW:
 case AH_V6_FLOW:
 case ESP_V6_FLOW:
 case IPV6_FLOW:
  cmd->data |= get_ethtool_ipv6_rss(bp);
  break;
 }
 return 0;
}

#define RXH_4TUPLE (RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3)
#define RXH_2TUPLE (RXH_IP_SRC | RXH_IP_DST)

static int bnxt_set_rxfh_fields(struct net_device *dev,
    const struct ethtool_rxfh_fields *cmd,
    struct netlink_ext_ack *extack)
{
 struct bnxt *bp = netdev_priv(dev);
 int tuple, rc = 0;
 u32 rss_hash_cfg;

 rss_hash_cfg = bp->rss_hash_cfg;

 if (cmd->data == RXH_4TUPLE)
  tuple = 4;
 else if (cmd->data == RXH_2TUPLE)
  tuple = 2;
 else if (!cmd->data)
  tuple = 0;
 else
  return -EINVAL;

 if (cmd->flow_type == TCP_V4_FLOW) {
  rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4;
  if (tuple == 4)
   rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4;
 } else if (cmd->flow_type == UDP_V4_FLOW) {
  if (tuple == 4 && !(bp->rss_cap & BNXT_RSS_CAP_UDP_RSS_CAP))
   return -EINVAL;
  rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4;
  if (tuple == 4)
   rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4;
 } else if (cmd->flow_type == TCP_V6_FLOW) {
  rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6;
  if (tuple == 4)
   rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6;
 } else if (cmd->flow_type == UDP_V6_FLOW) {
  if (tuple == 4 && !(bp->rss_cap & BNXT_RSS_CAP_UDP_RSS_CAP))
   return -EINVAL;
  rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
  if (tuple == 4)
   rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
 } else if (cmd->flow_type == AH_ESP_V4_FLOW) {
  if (tuple == 4 && (!(bp->rss_cap & BNXT_RSS_CAP_AH_V4_RSS_CAP) ||
       !(bp->rss_cap & BNXT_RSS_CAP_ESP_V4_RSS_CAP)))
   return -EINVAL;
  rss_hash_cfg &= ~(VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV4 |
      VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV4);
  if (tuple == 4)
   rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV4 |
     VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV4;
 } else if (cmd->flow_type == AH_ESP_V6_FLOW) {
  if (tuple == 4 && (!(bp->rss_cap & BNXT_RSS_CAP_AH_V6_RSS_CAP) ||
       !(bp->rss_cap & BNXT_RSS_CAP_ESP_V6_RSS_CAP)))
   return -EINVAL;
  rss_hash_cfg &= ~(VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV6 |
      VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV6);
  if (tuple == 4)
   rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV6 |
     VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV6;
 } else if (tuple == 4) {
  return -EINVAL;
 }

 switch (cmd->flow_type) {
 case TCP_V4_FLOW:
 case UDP_V4_FLOW:
 case SCTP_V4_FLOW:
 case AH_ESP_V4_FLOW:
 case AH_V4_FLOW:
 case ESP_V4_FLOW:
 case IPV4_FLOW:
  if (tuple == 2)
   rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4;
  else if (!tuple)
   rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4;
  break;

 case TCP_V6_FLOW:
 case UDP_V6_FLOW:
 case SCTP_V6_FLOW:
 case AH_ESP_V6_FLOW:
 case AH_V6_FLOW:
 case ESP_V6_FLOW:
 case IPV6_FLOW:
  if (tuple == 2)
   rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6;
  else if (!tuple)
   rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6;
  break;
 }

 if (bp->rss_hash_cfg == rss_hash_cfg)
  return 0;

 if (bp->rss_cap & BNXT_RSS_CAP_RSS_HASH_TYPE_DELTA)
  bp->rss_hash_delta = bp->rss_hash_cfg ^ rss_hash_cfg;
 bp->rss_hash_cfg = rss_hash_cfg;
 if (netif_running(bp->dev)) {
  bnxt_close_nic(bp, falsefalse);
  rc = bnxt_open_nic(bp, falsefalse);
 }
 return rc;
}

static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
     u32 *rule_locs)
{
 struct bnxt *bp = netdev_priv(dev);
 int rc = 0;

 switch (cmd->cmd) {
 case ETHTOOL_GRXRINGS:
  cmd->data = bp->rx_nr_rings;
  break;

 case ETHTOOL_GRXCLSRLCNT:
  cmd->rule_cnt = bp->ntp_fltr_count;
  cmd->data = bp->max_fltr | RX_CLS_LOC_SPECIAL;
  break;

 case ETHTOOL_GRXCLSRLALL:
  rc = bnxt_grxclsrlall(bp, cmd, (u32 *)rule_locs);
  break;

 case ETHTOOL_GRXCLSRULE:
  rc = bnxt_grxclsrule(bp, cmd);
  break;

 default:
  rc = -EOPNOTSUPP;
  break;
 }

 return rc;
}

static int bnxt_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
{
 struct bnxt *bp = netdev_priv(dev);
 int rc;

 switch (cmd->cmd) {
 case ETHTOOL_SRXCLSRLINS:
  rc = bnxt_srxclsrlins(bp, cmd);
  break;

 case ETHTOOL_SRXCLSRLDEL:
  rc = bnxt_srxclsrldel(bp, cmd);
  break;

 default:
  rc = -EOPNOTSUPP;
  break;
 }
 return rc;
}

u32 bnxt_get_rxfh_indir_size(struct net_device *dev)
{
 struct bnxt *bp = netdev_priv(dev);

 if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
  return bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings) *
         BNXT_RSS_TABLE_ENTRIES_P5;
 return HW_HASH_INDEX_SIZE;
}

static u32 bnxt_get_rxfh_key_size(struct net_device *dev)
{
 return HW_HASH_KEY_SIZE;
}

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;

 rxfh->hfunc = ETH_RSS_HASH_TOP;

 if (!bp->vnic_info)
  return 0;

 vnic = &bp->vnic_info[BNXT_VNIC_DEFAULT];
 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] = indir_tbl[i];
 }

 if (rxfh->key && vnic->rss_hash_key)
  memcpy(rxfh->key, vnic->rss_hash_key, HW_HASH_KEY_SIZE);

 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)
{
 struct bnxt *bp = netdev_priv(dev);
 int rc = 0;

 if (rxfh->hfunc && rxfh->hfunc != ETH_RSS_HASH_TOP)
  return -EOPNOTSUPP;

 bnxt_modify_rss(bp, NULL, NULL, rxfh);

 if (netif_running(bp->dev)) {
  bnxt_close_nic(bp, falsefalse);
  rc = bnxt_open_nic(bp, falsefalse);
 }
 return rc;
}

static void bnxt_get_drvinfo(struct net_device *dev,
        struct ethtool_drvinfo *info)
{
 struct bnxt *bp = netdev_priv(dev);

 strscpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
 strscpy(info->fw_version, bp->fw_ver_str, sizeof(info->fw_version));
 strscpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
 info->n_stats = bnxt_get_num_stats(bp);
 info->testinfo_len = bp->num_tests;
 /* TODO CHIMP_FW: eeprom dump details */
 info->eedump_len = 0;
 /* TODO CHIMP FW: reg dump details */
 info->regdump_len = 0;
}

static int bnxt_get_regs_len(struct net_device *dev)
{
 struct bnxt *bp = netdev_priv(dev);
 int reg_len;

 if (!BNXT_PF(bp))
  return -EOPNOTSUPP;

 reg_len = BNXT_PXP_REG_LEN;

 if (bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED)
  reg_len += sizeof(struct pcie_ctx_hw_stats);

 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)
{
 struct pcie_ctx_hw_stats *hw_pcie_stats;
 struct hwrm_pcie_qstats_input *req;
 struct bnxt *bp = netdev_priv(dev);
 dma_addr_t hw_pcie_stats_addr;
 int rc;

 regs->version = 0;
 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;

 if (hwrm_req_init(bp, req, HWRM_PCIE_QSTATS))
  return;

 hw_pcie_stats = hwrm_req_dma_slice(bp, req, sizeof(*hw_pcie_stats),
        &hw_pcie_stats_addr);
 if (!hw_pcie_stats) {
  hwrm_req_drop(bp, req);
  return;
 }

 regs->version = 1;
 hwrm_req_hold(bp, req); /* hold on to slice */
 req->pcie_stat_size = cpu_to_le16(sizeof(*hw_pcie_stats));
 req->pcie_stat_host_addr = cpu_to_le64(hw_pcie_stats_addr);
 rc = hwrm_req_send(bp, req);
 if (!rc) {
  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);
}

static void bnxt_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
 struct bnxt *bp = netdev_priv(dev);

 wol->supported = 0;
 wol->wolopts = 0;
 memset(&wol->sopass, 0, sizeof(wol->sopass));
 if (bp->flags & BNXT_FLAG_WOL_CAP) {
  wol->supported = WAKE_MAGIC;
  if (bp->wol)
   wol->wolopts = WAKE_MAGIC;
 }
}

static int bnxt_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
 struct bnxt *bp = netdev_priv(dev);

 if (wol->wolopts & ~WAKE_MAGIC)
  return -EINVAL;

 if (wol->wolopts & WAKE_MAGIC) {
  if (!(bp->flags & BNXT_FLAG_WOL_CAP))
   return -EINVAL;
  if (!bp->wol) {
   if (bnxt_hwrm_alloc_wol_fltr(bp))
    return -EBUSY;
   bp->wol = 1;
  }
 } else {
  if (bp->wol) {
   if (bnxt_hwrm_free_wol_fltr(bp))
    return -EBUSY;
   bp->wol = 0;
  }
 }
 return 0;
}

/* TODO: support 25GB, 40GB, 50GB with different cable type */
void _bnxt_fw_to_linkmode(unsigned long *mode, u16 fw_speeds)
{
 linkmode_zero(mode);

 if (fw_speeds & BNXT_LINK_SPEED_MSK_100MB)
  linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, mode);
 if (fw_speeds & BNXT_LINK_SPEED_MSK_1GB)
  linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, mode);
 if (fw_speeds & BNXT_LINK_SPEED_MSK_2_5GB)
  linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, mode);
 if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB)
  linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, mode);
 if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB)
  linkmode_set_bit(ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, mode);
}

enum bnxt_media_type {
 BNXT_MEDIA_UNKNOWN = 0,
 BNXT_MEDIA_TP,
 BNXT_MEDIA_CR,
 BNXT_MEDIA_SR,
 BNXT_MEDIA_LR_ER_FR,
 BNXT_MEDIA_KR,
 BNXT_MEDIA_KX,
 BNXT_MEDIA_X,
 __BNXT_MEDIA_END,
};

static const enum bnxt_media_type bnxt_phy_types[] = {
 [PORT_PHY_QCFG_RESP_PHY_TYPE_BASECR] = BNXT_MEDIA_CR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_BASEKR4] =  BNXT_MEDIA_KR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_BASELR] = BNXT_MEDIA_LR_ER_FR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_BASESR] = BNXT_MEDIA_SR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_BASEKR2] = BNXT_MEDIA_KR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_BASEKX] = BNXT_MEDIA_KX,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_BASEKR] = BNXT_MEDIA_KR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_BASET] = BNXT_MEDIA_TP,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_BASETE] = BNXT_MEDIA_TP,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_25G_BASECR_CA_L] = BNXT_MEDIA_CR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_25G_BASECR_CA_S] = BNXT_MEDIA_CR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_25G_BASECR_CA_N] = BNXT_MEDIA_CR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_25G_BASESR] = BNXT_MEDIA_SR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASECR4] = BNXT_MEDIA_CR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR4] = BNXT_MEDIA_SR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR4] = BNXT_MEDIA_LR_ER_FR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER4] = BNXT_MEDIA_LR_ER_FR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR10] = BNXT_MEDIA_SR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_40G_BASECR4] = BNXT_MEDIA_CR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_40G_BASESR4] = BNXT_MEDIA_SR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_40G_BASELR4] = BNXT_MEDIA_LR_ER_FR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_40G_BASEER4] = BNXT_MEDIA_LR_ER_FR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_40G_ACTIVE_CABLE] = BNXT_MEDIA_SR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_1G_BASET] = BNXT_MEDIA_TP,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_1G_BASESX] = BNXT_MEDIA_X,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_1G_BASECX] = BNXT_MEDIA_X,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASECR4] = BNXT_MEDIA_CR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASESR4] = BNXT_MEDIA_SR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASELR4] = BNXT_MEDIA_LR_ER_FR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER4] = BNXT_MEDIA_LR_ER_FR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASECR] = BNXT_MEDIA_CR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASESR] = BNXT_MEDIA_SR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASELR] = BNXT_MEDIA_LR_ER_FR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASEER] = BNXT_MEDIA_LR_ER_FR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASECR2] = BNXT_MEDIA_CR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR2] = BNXT_MEDIA_SR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR2] = BNXT_MEDIA_LR_ER_FR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER2] = BNXT_MEDIA_LR_ER_FR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASECR] = BNXT_MEDIA_CR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR] = BNXT_MEDIA_SR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR] = BNXT_MEDIA_LR_ER_FR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER] = BNXT_MEDIA_LR_ER_FR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASECR2] = BNXT_MEDIA_CR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASESR2] = BNXT_MEDIA_SR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASELR2] = BNXT_MEDIA_LR_ER_FR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER2] = BNXT_MEDIA_LR_ER_FR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASECR8] = BNXT_MEDIA_CR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASESR8] = BNXT_MEDIA_SR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASELR8] = BNXT_MEDIA_LR_ER_FR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER8] = BNXT_MEDIA_LR_ER_FR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASECR4] = BNXT_MEDIA_CR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASESR4] = BNXT_MEDIA_SR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASELR4] = BNXT_MEDIA_LR_ER_FR,
 [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER4] = BNXT_MEDIA_LR_ER_FR,
};

static enum bnxt_media_type
bnxt_get_media(struct bnxt_link_info *link_info)
{
 switch (link_info->media_type) {
 case PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP:
  return BNXT_MEDIA_TP;
 case PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC:
  return BNXT_MEDIA_CR;
 default:
  if (link_info->phy_type < ARRAY_SIZE(bnxt_phy_types))
   return bnxt_phy_types[link_info->phy_type];
  return BNXT_MEDIA_UNKNOWN;
 }
}

enum bnxt_link_speed_indices {
 BNXT_LINK_SPEED_UNKNOWN = 0,
 BNXT_LINK_SPEED_100MB_IDX,
 BNXT_LINK_SPEED_1GB_IDX,
 BNXT_LINK_SPEED_10GB_IDX,
 BNXT_LINK_SPEED_25GB_IDX,
 BNXT_LINK_SPEED_40GB_IDX,
 BNXT_LINK_SPEED_50GB_IDX,
 BNXT_LINK_SPEED_100GB_IDX,
 BNXT_LINK_SPEED_200GB_IDX,
 BNXT_LINK_SPEED_400GB_IDX,
 __BNXT_LINK_SPEED_END
};

static enum bnxt_link_speed_indices bnxt_fw_speed_idx(u16 speed)
{
 switch (speed) {
 case BNXT_LINK_SPEED_100MB: return BNXT_LINK_SPEED_100MB_IDX;
 case BNXT_LINK_SPEED_1GB: return BNXT_LINK_SPEED_1GB_IDX;
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=100 H=90 G=95

¤ Dauer der Verarbeitung: 0.10 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.